Skip to content

Add TranscoderInputStreamImpl#1078

Merged
mattklein123 merged 16 commits intoenvoyproxy:masterfrom
lizan:grpc_transcoder_input_stream
Jun 21, 2017
Merged

Add TranscoderInputStreamImpl#1078
mattklein123 merged 16 commits intoenvoyproxy:masterfrom
lizan:grpc_transcoder_input_stream

Conversation

@lizan
Copy link
Member

@lizan lizan commented Jun 9, 2017

The class implements TranscoderInputStream from transcoding library,
take input from Envoy::Buffer, this also allows Envoy::Buffer to be used
as protobuf::io::ZeroCopyInputStream.

For #501

The class implements TranscoderInputStream from transcoding library,
take input from Envoy::Buffer, this also allows Envoy::Buffer to be used
as protobuf::io::ZeroCopyInputStream.

For envoyproxy#501
@lizan
Copy link
Member Author

lizan commented Jun 9, 2017

#1079 for the context how this is used.

@mattklein123
Copy link
Member

@lizan Can we make a note to use this here as well: https://github.com/lyft/envoy/blob/master/source/common/grpc/rpc_channel_impl.cc#L62

Doesn't need to be done in this PR if you don't want, but would like to do a follow up. Will catch up on reviews this weekend.

Copy link
Member

@htuch htuch left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is useful, but do we want to couple zero-copy with the transcoder? As @mattklein123 points out, this is useful in other places as well (including the active #1054 under review). Can we have a protobuf zero-copy Buffer subclass (or build this into Buffer), then use this here in the TranscoderInputStreamImply?


#include "common/buffer/buffer_impl.h"

#include "src/transcoder_input_stream.h"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you wire up the external deps for this PR? Ideally, the grpc_transcoder library doesn't live under the src prefix, but something more like grpc_transcoder/....

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, do you want to add mocks for the TranscoderInputStream interface?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

grpc-ecosystem/grpc-httpjson-transcoding#9 for prefix.

Probably not need mocks, just like buffers, it is hard to EXPECT how the input stream is used, so just using real impl should be fine.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

void Move(Buffer::Instance& instance);

// Mark the buffer is finished
void Finish() { finished_ = true; }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For all methods that are not inherited from external deps, please follow the Envoy convention and start methods with lower case as per the style guide.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

}

Buffer::RawSlice slice;
uint64_t num_slices = buffer_.getRawSlices(&slice, 1);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: const uint64_t num_slices = ...

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Buffer::RawSlice slice;
uint64_t num_slices = buffer_.getRawSlices(&slice, 1);

if (num_slices) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: if (num_slices > 0) {

bool TranscoderInputStreamImpl::Skip(int) { NOT_IMPLEMENTED; }

void TranscoderInputStreamImpl::BackUp(int count) {
GOOGLE_CHECK_GE(count, 0);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What are these macros? They aren't standard in the Envoy code base. Could we just use an ASSERT?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

GOOGLE_CHECK_LE(count, position_);

position_ -= count;
byte_count_ -= count;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since I don't have the interface, I can't tell the semantics of byte_count_, but I noticed it isn't decremented if (position != 0), so in the absence of Backup, it monotonically increases forever?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

https://developers.google.com/protocol-buffers/docs/reference/cpp/google.protobuf.io.zero_copy_stream#ZeroCopyInputStream

byte_count_ here is for ByteCount(), which

Returns the total number of bytes read since this object was created.

So yes it monotonically increases forever.

@lizan
Copy link
Member Author

lizan commented Jun 15, 2017

@htuch @mattklein123 refactored out ZeroCopyInputStreamImpl, and make AsyncClient and RpcChannel use it. PTAL.


class ZeroCopyInputStreamImpl : public virtual google::protobuf::io::ZeroCopyInputStream {
public:
// Create input stream with one buffer, and finish immediately
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if there is any easy way to do this, but in this case, it would be nice if we didn't have to allocate a new buffer on the stack, just to move into, and then operate. IMO we should be able to operate directly on the input buffer since it's non-const anyway. I would just put in a TODO here for a potential perf optimization.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems all usage are using InstancePtr, so just changed the signature with InstancePtr in this class.

// Create input stream with empty buffer
ZeroCopyInputStreamImpl() {}

virtual ~ZeroCopyInputStreamImpl() {}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: is this needed to compile? otherwise del

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

}

Buffer::RawSlice slice;
const uint64_t num_slices = buffer_.getRawSlices(&slice, 1);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See comment here: https://github.com/lyft/envoy/blob/master/include/envoy/buffer/buffer.h#L67 I think this can return a slice that has no data in it. Just make sure the code below correctly handled that case. I think you probably need to also check that slice.len_ > 0 but not sure.


bool ZeroCopyInputStreamImpl::Skip(int) { NOT_IMPLEMENTED; }

void ZeroCopyInputStreamImpl::BackUp(int count) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a little hazy on the proto buffer interfaces, but is this always safe? We are draining() above. Can we BackUp() into nothing? Or does that never happen. If so I would add a comment.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

The precondition of BackUp() doesn't allow them. so we're safe to draining. Added comments.

return true;
}

if (!finished_) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a little confused what happens here. If we return true here with no data, how does the proto code know to call Next() again without just going into a spin loop? Or is this only useful in the explicit transcoding case somehow? Again might need a few more comments for those not as familiar with proto interfaces.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is callers responsibility to maintain. Added comment. transcoding interface add BytesAvailable() to avoid this.

Copy link
Member

@mattklein123 mattklein123 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM pending small grammar nits and any @htuch comments.

// Preconditions for BackUp:
// - The last method called must have been Next().
// - count must be less than or equal to the size of the last buffer returned by Next().
// Due to preconditions above, it is save to just adjust position_ and byte_count_ here, and
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/save/safe

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

// - The last method called must have been Next().
// - count must be less than or equal to the size of the last buffer returned by Next().
// Due to preconditions above, it is save to just adjust position_ and byte_count_ here, and
// draining in Next().
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/draining/drain

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

// google::protobuf::io::ZeroCopyInputStream
// See
// https://developers.google.com/protocol-buffers/docs/reference/cpp/google.protobuf.io.zero_copy_stream#ZeroCopyInputStream
// for each methods details.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/each methods/method

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

// https://developers.google.com/protocol-buffers/docs/reference/cpp/google.protobuf.io.zero_copy_stream#ZeroCopyInputStream
// for each methods details.

// Note the Next() will return true with no data until next data available if the stream is not
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

// Note Next() will return true with no data until more data is available if the stream is not
// finished. It is the caller's responsibility to finish the stream or wrap with LimitingInputStream
// before passing to protobuf code to avoid a spin loop.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Copy link
Member

@htuch htuch left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, just some minor stuff.


namespace Buffer {

class ZeroCopyInputStreamImpl : public virtual google::protobuf::io::ZeroCopyInputStream {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is virtual needed here? Is this because google::protobuf::io::ZeroCopyInputStream isn't pure? Do have potential diamond inheritance with this?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, TranscoderInputStreamImpl inherits this class and TranscoderInputStream from transcoding library, which inherits ZeroCopyInputStream.


private:
bool finished_{false};
int64_t byte_count_{0};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be negative?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changed to uint

ZeroCopyInputStreamImpl stream_;

const void* data_;
int size_;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Prefer fixed size types in general in Envoy .

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

data_ and size_ are used to receive output from Next, so types here matches the interface.

mattklein123
mattklein123 previously approved these changes Jun 20, 2017
@mattklein123 mattklein123 merged commit f565599 into envoyproxy:master Jun 21, 2017
jpsim pushed a commit that referenced this pull request Nov 28, 2022
The most recent Envoy bump requires this: envoyproxy/envoy-mobile#1076

```
The new binary is 2.00 % different in size compared to main.
The new binary is 5790759 bytes.
The current size (5790759) is larger than the maximum size (5700000).
```

Signed-off-by: Michael Rebello <me@michaelrebello.com>
Signed-off-by: JP Simard <jp@jpsim.com>
jpsim pushed a commit that referenced this pull request Nov 29, 2022
The most recent Envoy bump requires this: envoyproxy/envoy-mobile#1076

```
The new binary is 2.00 % different in size compared to main.
The new binary is 5790759 bytes.
The current size (5790759) is larger than the maximum size (5700000).
```

Signed-off-by: Michael Rebello <me@michaelrebello.com>
Signed-off-by: JP Simard <jp@jpsim.com>
mathetake added a commit that referenced this pull request Mar 3, 2026
**Description**

This removes the unnecessary replace statement in go.mod.

Signed-off-by: Takeshi Yoneda <t.y.mathetake@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants