Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

quiche: fix QuicMemSliceStorageImplTest and add quiche tests into CIs #10287

Closed
wants to merge 12 commits into from

Conversation

danzh2010
Copy link
Contributor

QuicMemSliceStorageImpl is implemented with Envoy::Buffer::OwnedImpl which has a recent change in its move() implementation. The changed behavior is that move() will merge small slices into the last slice to avoid a lot of fragments. This breaks our assumption that move() between 2 buffers should keep the slices in their original form. As a result, it fails our QUICHE test QuicMemSliceStorageImplTest.MultipleIovInMultipleSlice in which we test building a QuicMemSliceStorage with max slice length 4 bytes.

[ RUN ] QuicMemSliceStorageImplTest.MultipleIovInMultipleSlice
bazel-out/k8-fastbuild/bin/external/com_googlesource_quiche/quiche/quic/platform/api/quic_mem_slice_storage_test.cc:56: Failure
Expected equality of these values:
"aaaa"
Which is: 0x3fd160
span.GetData(0)
Which is: "aaaabbbb"

Because the max slices length for this test is small enough for the Envoy buffer to merge them, QuicMemSliceStorage ends up doesn't honor the max_slice_len passed to its constructor. This could lead the slices in QuicStreamSendBuffer to become larger than QUIC expects.

This PR changes the implementation of QuicMemSliceStorageImpl and QuicMemSliceSpanImpl to work with this new Envoy Buffer behavior:
QuicMemSliceStorageImpl is changes to keep a vector of QuicMemSliceImpl instead of a Envoy buffer.
QuicMemSliceSpanImpl has a handle to a Envoy Buffer as before and the other handle to Span of QuicMemSliceImpl to work with the new implementation of QuicMemSliceStorageImpl.

Risk Level: low
Testing: existing tests pass

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
Contributor Author

/assign @wu-bin for platform impl change
/assign @lizan for do_ci.sh change

@repokitteh-read-only
Copy link

neither of for, platform, impl, change can be assigned to this issue.

🐱

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

see: more, trace.

@repokitteh-read-only
Copy link

🙀 Error while processing event:

evaluation error
error: function _rk_error error: path contains forbidden characters
🐱

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

see: more, trace.

@danzh2010
Copy link
Contributor Author

/assign @wu-bin @lizan

@danzh2010
Copy link
Contributor Author

/retest

@repokitteh-read-only
Copy link

🔨 rebuilding ci/circleci: coverage (failed build)

🐱

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

see: more, trace.

Copy link
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.

basically looks good but I was hoping @antoniovicente could take a look as I think he's been thinking more about the buffers code.

if (buffer_ != nullptr) {
return buffer_->length();
} else {
size_t len = 0;
Copy link
Contributor

Choose a reason for hiding this comment

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

if we are returning a QuicByteCount rather than size_t should we use that for the accumulation?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

good point!


private:
// Either |buffer_| or |span_| is used to point to the mem slices.
Copy link
Contributor

Choose a reason for hiding this comment

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

line 69 above assumes that they can't both be populated, but it's a little ambiguous from this comment. Can you clarify in this comment?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

ci/do_ci.sh Outdated
@@ -92,7 +92,7 @@ if [[ $# -gt 1 ]]; then
shift
TEST_TARGETS=$*
else
TEST_TARGETS=//test/...
TEST_TARGETS="//test/... $(bazel query ${BAZEL_QUERY_OPTIONS} "attr('size', 'small', '@com_googlesource_quiche//:all')" | grep "^@com_googlesource_quiche")"
Copy link
Contributor

Choose a reason for hiding this comment

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

Why only run small quiche tests?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I changed to check a new tag 'test_included'. We want to run QUICHE tests selectively because we may add a test target quic_end_to_end_test which is can be ran manually in case of need.

Comment on lines +14 to +20
if (buffer_ != nullptr) {
uint64_t num_slices = buffer_->getRawSlices(nullptr, 0);
ASSERT(num_slices > index);
absl::FixedArray<Envoy::Buffer::RawSlice> slices(num_slices);
buffer_->getRawSlices(slices.begin(), num_slices);
return {reinterpret_cast<char*>(slices[index].mem_), slices[index].len_};
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we store a absl::FixedArray<Envoy::Buffer::RawSlice> as a member variable, and convert the slices in Envoy::Buffer::Instance and absl::Span<QuicMemSliceImpl> to the FixedArray? It seems to me that QuicMemSliceSpanImpl never owns a buffer, so making that change will result in a much smaller implementation.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We don't have a way to convert a RawSlice to QuicMemSliceImpl which is used in ConsumeFunction. RawSlice have no control over the memory but QuicMemSliceImpl does.

Copy link
Contributor

Choose a reason for hiding this comment

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

I'm confused, I think in ConsumeAll, we are already converting a RawSlice to a QuicMemSlice?

    absl::FixedArray<Envoy::Buffer::RawSlice> slices(num_slices);
    buffer_->getRawSlices(slices.begin(), num_slices);
    for (auto& slice : slices) {
      if (slice.len_ == 0) {
        continue;
      }
      // Move each slice into a stand-alone 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.
      consume(QuicMemSlice(QuicMemSliceImpl(*buffer_, slice.len_)));
      saved_length += slice.len_;
    }

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We can transfer the ownership of memory from Envoy Buffer to QuicMemSlice, but not from RawSlice to QuicMemSlice. My understanding is that QuicMemSliceSpan needs to have a handle to the owner of the memory.

Comment on lines +27 to +30
for (auto& mem_slice : other.mem_slices_) {
Envoy::Buffer::OwnedImpl buffer;
buffer.add(mem_slice.data(), mem_slice.length());
mem_slices_.emplace_back(buffer, mem_slice.length());
Copy link
Contributor

Choose a reason for hiding this comment

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

I think making copies is fine since it is only needed in tests, but worth adding a comment.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is copy assignment, making copy is expected. And yes, this is only used in QUICHE tests.

Copy link
Contributor

Choose a reason for hiding this comment

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

Fair enough.

Comment on lines +33 to +35
quic::QuicUniqueBufferPtr buffer = quic::MakeUniqueBuffer(allocator, slice_len);
QuicUtils::CopyToBuffer(iov, iov_count, io_offset, slice_len, buffer.get());
mem_slices_.emplace_back(std::move(buffer), slice_len);
Copy link
Contributor

Choose a reason for hiding this comment

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

Looks much better than before. Thanks!

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
Contributor Author

ping?

@danzh2010
Copy link
Contributor Author

Discussed with @wu-bin offline. The current QuicMemSlice API is not very straight forward for user. And there might be better API for it together with QuicMemSliceSpan and QuicMemSliceStorage. We want to try the upstream improvement first before fixing this failure. So I will close this PR for now and resurrect it once we get some conclusion about the best approach.

@danzh2010 danzh2010 closed this Mar 11, 2020
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.

5 participants