Skip to content

quiche: implement QuicMemSlice#6400

Merged
mattklein123 merged 73 commits intoenvoyproxy:masterfrom
danzh2010:memslice2
May 30, 2019
Merged

quiche: implement QuicMemSlice#6400
mattklein123 merged 73 commits intoenvoyproxy:masterfrom
danzh2010:memslice2

Conversation

@danzh2010
Copy link
Copy Markdown
Contributor

@danzh2010 danzh2010 commented Mar 27, 2019

Add QuicMemSliceImpl, QuicMemSliceSpanImpl, QuicMemSliceStorageImpl, QuicTestMemSliceVectorImpl using Envoy::Buffer;
Add several quic core targets into quiche.BUILD file to compile some quic objects including quic_types.h which is needed in QuicMemSliceSpan and quic_utils.h which is needed in QuicTestMemSliceVectorImpl;

Risk Level: low, not in use
Testing: tested impl's with quic_mem_slice_test.cc, quic_mem_slice_span_test.cc, quic_mem_slice_storage_test.cc from quiche.
Part of #2557

Signed-off-by: Dan Zhang <danzh@google.com>
Signed-off-by: Dan Zhang <danzh@google.com>
Signed-off-by: Dan Zhang <danzh@google.com>
Signed-off-by: Dan Zhang <danzh@google.com>
Signed-off-by: Dan Zhang <danzh@google.com>
Signed-off-by: Dan Zhang <danzh@google.com>
Signed-off-by: Dan Zhang <danzh@google.com>
@danzh2010
Copy link
Copy Markdown
Contributor Author

/assign @wu-bin

Signed-off-by: Dan Zhang <danzh@google.com>
Signed-off-by: Dan Zhang <danzh@google.com>
@danzh2010 danzh2010 changed the title quic-envoy: implement QuicMemSlice quiche: implement QuicMemSlice Mar 28, 2019
Copy link
Copy Markdown
Contributor

@wu-bin wu-bin left a comment

Choose a reason for hiding this comment

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

I only finished the BUILD files, will continue on the c++ files.

Comment thread bazel/external/quiche.BUILD Outdated
Comment thread bazel/external/quiche.BUILD Outdated
Comment thread bazel/external/quiche.BUILD
Comment thread bazel/external/quiche.BUILD
Comment thread bazel/external/quiche.BUILD
Comment thread source/extensions/quic_listeners/quiche/platform/BUILD Outdated
)

envoy_cc_library(
name = "quic_mem_slice_storage_impl_lib",
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

nit: quic_platform_mem_slice_storage_impl_lib

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

done

Comment thread source/extensions/quic_listeners/quiche/platform/BUILD Outdated
Comment thread source/extensions/quic_listeners/quiche/platform/BUILD Outdated
Comment thread source/extensions/quic_listeners/quiche/platform/BUILD
@htuch
Copy link
Copy Markdown
Member

htuch commented Mar 29, 2019

I think @jmarantz is an ideal reviewer for this, as he has been doing other detailed reviews around buffer implementation recently.

@htuch htuch requested review from jmarantz and removed request for alyssawilk, mattklein123, snowp and zuercher March 29, 2019 14:58
Signed-off-by: Dan Zhang <danzh@google.com>
Copy link
Copy Markdown
Contributor

@jmarantz jmarantz left a comment

Choose a reason for hiding this comment

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

flushing some comments. I haven't deeply looked at the interaction with buffers yet.

Comment thread source/common/common/stack_array.h Outdated
// NOLINT(namespace-envoy)

// This file is part of the QUICHE platform implementation, and is not to be
// consumed or referenced directly by other Envoy
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

unfinished sentence?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

completed it.

Comment thread source/extensions/quic_listeners/quiche/platform/quic_flags_impl.h Outdated

// Constructs a QuicMemSliceImpl by let |allocator| allocate a data buffer of
// |length|.
QuicMemSliceImpl(QuicBufferAllocator* allocator, size_t length)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Shall we go with Envoy style guide and use non-const refs for pointers which we can't allow to be null?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Since all the impl's are used by quic API's, it inevitably has to match the expectation of its callers, and thus following quic style guide.

allocator->New(length), length,
[allocator](const void* data, size_t, const Envoy::Buffer::BufferFragmentImpl* fragment) {
allocator->Delete(const_cast<char*>(static_cast<const char*>(data)));
delete fragment;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

i'm surprised this 'delete' compiles since it's passed as a const pointer.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

deleter can still be called for const object so that it can be destructed.

QuicMemSliceStorageImpl(QuicMemSliceStorageImpl&& other) = default;
QuicMemSliceStorageImpl& operator=(QuicMemSliceStorageImpl&& other) = default;

~QuicMemSliceStorageImpl() = default;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

not needed.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

removed.

Comment thread test/extensions/quic_listeners/quiche/platform/quic_platform_test.cc Outdated
// consumed or referenced directly by other Envoy code. It serves purely as a
// porting layer for QUICHE.

#include <stdint.h>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

#include <cstdint>

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

done

Signed-off-by: Dan Zhang <danzh@google.com>
Comment thread source/extensions/quic_listeners/quiche/platform/quic_flags_impl.h

inline void QuicPrintCommandLineFlagHelpImpl(const char* /*usage*/) {}

// porting layer for QUICHE.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Remove misplaced comment.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

done

#define QUIC_NOTREACHED_IMPL() NOT_REACHED_GCOVR_EXCL_LINE
#endif

#define DCHECK_GT(a, b) DCHECK(a > b)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Add parentheses to a and b to avoid problems with operator precedence:

#define DCHECK_GT(a, b) DCHECK((a) > (b))

Same below.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

done

// Constructs a QuicMemSliceImpl by let |allocator| allocate a data buffer of
// |length|.
QuicMemSliceImpl(QuicBufferAllocator* allocator, size_t length)
: length_(length), slice_(new Envoy::Buffer::OwnedImpl()) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This function seems too heavyweight, in theory it only needs to do one memory allocation(the lifetime of the memory is the same as QuicMemSliceImpl itself), but it currently does

  1. 2 allocations for slice_ (OwnedImpl + shared memory control block. Can change to std::make_shared to combine them)
  2. 1 allocation for fragment
  3. 1 allocation for the buffer itself (allocator->New)
  4. 1 allocation for the "UnownedSlice" object (inside the addBufferFragment call)

I think, without changing the overall approach in this PR, we can change the shared_ptr to a unique_ptr, which allows us to combine 1, 2 and 3 in one allocation(allocator->New(total size needed)). I suspect we'll want to change to approach in the future(i.e. replace Buffer instance in this class by a real slice object, which represents a continuous span of memory) to further optimize it, though.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I changed the class definition a bit:
Since mem slice doesn't need to share ownership of slice_ with other instance, slice_ doesn't need to be a shared_ptr.
Combined allocation of fragment and buffer itself.
Now there are only 2 allocations in this constructor.


// Constructs a QuicMemSliceImpl from a Buffer::Instance whose getRawSlices()
// returns only 1 slice.
QuicMemSliceImpl(std::shared_ptr<Envoy::Buffer::Instance> slice)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

(If we change slice_ to unique_ptr) slice should also be a unique_ptr.

Should this constructor be 'explicit', since it only has 1 arg?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

added explicit specifier.

Comment thread source/extensions/quic_listeners/quiche/platform/quic_mem_slice_impl.h Outdated
bool empty() const { return length() == 0; }

private:
size_t length_;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

It seems length_ is not needed because slice_ already has a length() method.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

removed


private:
size_t length_;
std::shared_ptr<Envoy::Buffer::Instance> slice_;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

See my previous comment; I think this can be simplified to a unique_ptr.

Also a nit: The term "slice" often implies a continuous span of memory, I'd prefer something like 'single_slice_buffer_' here.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Rename to single_slice_buffer_.

// TODO(danzh): investigate the cost of allocating one buffer per slice.
// If it turns out to be expensive, add a new function to free data in the middle in buffer
// interface and re-design QuicMemSliceImpl.
single_slice_buffer->move(buffer_, slice.len_);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

nit: DCHECK to make sure single_slice_buffer only has 1 slice?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

There is ASSERT in QuicMemSliceImpl() one line below. Skipped this temporary variable here and passed in buffer_ directly.

void* dst = allocator->New(slice_len);
QuicUtils::CopyToBuffer(iov, iov_count, io_offset, slice_len, static_cast<char*>(dst));
io_offset += slice_len;
auto fragment = new Envoy::Buffer::BufferFragmentImpl(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Similar here, the allocation of data and BufferFragment can be combined.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

done

Signed-off-by: Dan Zhang <danzh@google.com>
Comment thread bazel/external/quiche.BUILD
Comment thread source/common/buffer/buffer_impl.cc Outdated

OwnedImpl::OwnedImpl(OwnedImpl&& other)
: old_impl_(other.old_impl_), slices_(std::move(other.slices_)), length_(other.length_),
buffer_(std::move(other.buffer_)) {}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

add unit tests for these new ctors/assign-ops in buffer_impl_test.cc. we should definitely not be just testing them from quic only.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

done

# wrapping Envoy data type to QUIC data type.
#
# See a detailed description of QUIC platform API dependency model at:
# https://quiche.googlesource.com/quiche/+/refs/heads/master/quic/platform/api/README.md
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

btw this is excellent doc, thank you. Please render the dot diagram as a png also.

Comment thread source/extensions/quic_listeners/quiche/platform/BUILD
danzh1989 added 4 commits May 28, 2019 13:08
Signed-off-by: Dan Zhang <danzh@google.com>
Signed-off-by: Dan Zhang <danzh@google.com>
Signed-off-by: Dan Zhang <danzh@google.com>
Signed-off-by: Dan Zhang <danzh@google.com>
Comment thread bazel/external/quiche.BUILD
Comment thread test/common/buffer/owned_impl_test.cc Outdated
Signed-off-by: Dan Zhang <danzh@google.com>
jmarantz
jmarantz previously approved these changes May 29, 2019
Copy link
Copy Markdown
Contributor

@jmarantz jmarantz left a comment

Choose a reason for hiding this comment

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

Thanks for your patience while we worked through it! It's much simpler now.

Comment thread bazel/external/quiche.BUILD
# wrapping Envoy data type to QUIC data type.
#
# See a detailed description of QUIC platform API dependency model at:
# https://quiche.googlesource.com/quiche/+/refs/heads/master/quic/platform/api/README.md
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

What's the plan for fixing the diagram? Doesn't block this PR I suppose, but I am afraid if you don't do it someone will come along later and just delete the work you've done since it does not render as you intended.

Signed-off-by: Dan Zhang <danzh@google.com>
@danzh2010
Copy link
Copy Markdown
Contributor Author

/retest

@repokitteh-read-only
Copy link
Copy Markdown

🔨 rebuilding ci/circleci: tsan (failed build)

🐱

Caused by: a #6400 (comment) was created by @danzh2010.

see: more, trace.

@danzh2010
Copy link
Copy Markdown
Contributor Author

merged with master branch. PTAL!

jmarantz
jmarantz previously approved these changes May 29, 2019
Copy link
Copy Markdown
Contributor

@jmarantz jmarantz 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 Matt's gotta look at this next.

Copy link
Copy Markdown
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 from a skim. A couple of small questions. Thank you!

/wait

Comment thread source/common/buffer/buffer_impl.cc Outdated

OwnedImpl::OwnedImpl(OwnedImpl&& other) : OwnedImpl() { move(other); }

OwnedImpl& OwnedImpl::operator=(const OwnedImpl& other) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Having the copy constructor and copy assignment operators can potentially lead to unintentional copies through C++ magic, so I would prefer to not have them. Is it possible to hide these behind explicit methods so they are very intentional?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I brought up the previous discussion about why we added copy contractor. Please refer to that thread.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think the previous state was a strange explicit upcast which had more or less then same effect.

How about an explicit copyFrom() method instead, which you could call from the constructor body. Would that work?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Yes, +1 to an explicit method. I don't think we need the constructor/assignment overrides but could have explicit methods (possible static) which do what we need. you could also make these operators private, and then access them via public static factory methods.

/wait

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Buffer::Instance already has similar method: add(). I switch to that one.

Envoy::Buffer::RawSlice iovec;
uint64_t num_iov = single_slice_buffer_.reserve(length, &iovec, 1);
ASSERT(num_iov == 1);
// evbuffer may return a slice longer than needed, trim it to requested length.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

nit: we are moving away from evbuffer internally. I would rephrase the comment to say this is how Envoy's buffer implementation works, etc.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

done

Signed-off-by: Dan Zhang <danzh@google.com>
Signed-off-by: Dan Zhang <danzh@google.com>
Signed-off-by: Dan Zhang <danzh@google.com>
Copy link
Copy Markdown
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.

Nice, thanks!

@mattklein123 mattklein123 merged commit 0c48eff into envoyproxy:master May 30, 2019
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.

7 participants