Provide absl::Span<QuicMemSlice> version of WriteMemSlices()
The goal is to eventually deprecate QuicMemSliceSpan, thus reducing the amount of platform code we need to carry around.
PiperOrigin-RevId: 378444535
diff --git a/quic/core/quic_stream.cc b/quic/core/quic_stream.cc
index 3f1b7d9..9744ed3 100644
--- a/quic/core/quic_stream.cc
+++ b/quic/core/quic_stream.cc
@@ -19,6 +19,7 @@
#include "quic/platform/api/quic_flag_utils.h"
#include "quic/platform/api/quic_flags.h"
#include "quic/platform/api/quic_logging.h"
+#include "quic/platform/api/quic_mem_slice.h"
using spdy::SpdyPriority;
@@ -759,6 +760,16 @@
}
QuicConsumedData QuicStream::WriteMemSlices(QuicMemSliceSpan span, bool fin) {
+ return WriteMemSlicesInner(MemSliceSpanWrapper(span), fin);
+}
+
+QuicConsumedData QuicStream::WriteMemSlices(absl::Span<QuicMemSlice> span,
+ bool fin) {
+ return WriteMemSlicesInner(MemSliceSpanWrapper(span), fin);
+}
+
+QuicConsumedData QuicStream::WriteMemSlicesInner(MemSliceSpanWrapper span,
+ bool fin) {
QuicConsumedData consumed_data(0, false);
if (span.empty() && !fin) {
QUIC_BUG(quic_bug_10586_6) << "span.empty() && !fin";
@@ -786,7 +797,7 @@
if (!span.empty()) {
// Buffer all data if buffered data size is below limit.
QuicStreamOffset offset = send_buffer_.stream_offset();
- consumed_data.bytes_consumed = send_buffer_.SaveMemSliceSpan(span);
+ consumed_data.bytes_consumed = span.SaveTo(send_buffer_);
if (offset > send_buffer_.stream_offset() ||
kMaxStreamLength < send_buffer_.stream_offset()) {
QUIC_BUG(quic_bug_10586_8) << "Write too many data via stream " << id_;
diff --git a/quic/core/quic_stream.h b/quic/core/quic_stream.h
index 6e6e623..ca20eb4 100644
--- a/quic/core/quic_stream.h
+++ b/quic/core/quic_stream.h
@@ -24,6 +24,7 @@
#include "absl/strings/string_view.h"
#include "absl/types/optional.h"
+#include "absl/types/span.h"
#include "quic/core/quic_flow_controller.h"
#include "quic/core/quic_packets.h"
#include "quic/core/quic_stream_send_buffer.h"
@@ -32,6 +33,7 @@
#include "quic/core/session_notifier_interface.h"
#include "quic/core/stream_delegate_interface.h"
#include "quic/platform/api/quic_export.h"
+#include "quic/platform/api/quic_mem_slice.h"
#include "quic/platform/api/quic_mem_slice_span.h"
#include "quic/platform/api/quic_reference_counted.h"
#include "spdy/core/spdy_protocol.h"
@@ -343,9 +345,13 @@
// succeeds.
bool MaybeSetTtl(QuicTime::Delta ttl);
- // Same as WritevData except data is provided in reference counted memory so
- // that data copy is avoided.
+ // Commits data into the stream write buffer, and potentially sends it over
+ // the wire. This method has all-or-nothing semantics: if the write buffer is
+ // not full, all of the memslices in |span| are moved into it; otherwise,
+ // nothing happens.
+ // TODO(vasilvv): deprecate and remove QuicMemSliceSpan version.
QuicConsumedData WriteMemSlices(QuicMemSliceSpan span, bool fin);
+ QuicConsumedData WriteMemSlices(absl::Span<QuicMemSlice> span, bool fin);
// Returns true if any stream data is lost (including fin) and needs to be
// retransmitted.
@@ -464,6 +470,26 @@
friend class test::QuicStreamPeer;
friend class QuicStreamUtils;
+ // Wraps around either QuicMemSliceSpan or absl::Span<QuicMemSlice>.
+ // TODO(vasilvv): delete this after QuicMemSliceSpan is gone.
+ class QUIC_EXPORT_PRIVATE MemSliceSpanWrapper {
+ public:
+ explicit MemSliceSpanWrapper(QuicMemSliceSpan span) : old_(span) {}
+ explicit MemSliceSpanWrapper(absl::Span<QuicMemSlice> span) : new_(span) {}
+
+ bool empty() { return old_.has_value() ? old_->empty() : new_.empty(); }
+ size_t SaveTo(QuicStreamSendBuffer& send_buffer) {
+ if (old_.has_value()) {
+ return send_buffer.SaveMemSliceSpan(*old_);
+ }
+ return send_buffer.SaveMemSliceSpan(new_);
+ }
+
+ private:
+ absl::optional<QuicMemSliceSpan> old_;
+ absl::Span<QuicMemSlice> new_;
+ };
+
QuicStream(QuicStreamId id,
QuicSession* session,
QuicStreamSequencer sequencer,
@@ -502,6 +528,8 @@
// Returns true if deadline_ has passed.
bool HasDeadlinePassed() const;
+ QuicConsumedData WriteMemSlicesInner(MemSliceSpanWrapper span, bool fin);
+
QuicStreamSequencer sequencer_;
QuicStreamId id_;
// Pointer to the owning QuicSession object.
diff --git a/quic/core/quic_stream_send_buffer.cc b/quic/core/quic_stream_send_buffer.cc
index 3b1b37b..1e32e54 100644
--- a/quic/core/quic_stream_send_buffer.cc
+++ b/quic/core/quic_stream_send_buffer.cc
@@ -12,6 +12,7 @@
#include "quic/platform/api/quic_flag_utils.h"
#include "quic/platform/api/quic_flags.h"
#include "quic/platform/api/quic_logging.h"
+#include "quic/platform/api/quic_mem_slice.h"
namespace quic {
@@ -96,6 +97,20 @@
[&](QuicMemSlice slice) { SaveMemSlice(std::move(slice)); });
}
+QuicByteCount QuicStreamSendBuffer::SaveMemSliceSpan(
+ absl::Span<QuicMemSlice> span) {
+ QuicByteCount total = 0;
+ for (QuicMemSlice& slice : span) {
+ if (slice.length() == 0) {
+ // Skip empty slices.
+ continue;
+ }
+ total += slice.length();
+ SaveMemSlice(std::move(slice));
+ }
+ return total;
+}
+
void QuicStreamSendBuffer::OnStreamDataConsumed(size_t bytes_consumed) {
stream_bytes_written_ += bytes_consumed;
stream_bytes_outstanding_ += bytes_consumed;
diff --git a/quic/core/quic_stream_send_buffer.h b/quic/core/quic_stream_send_buffer.h
index 4b23d3d..f91e476 100644
--- a/quic/core/quic_stream_send_buffer.h
+++ b/quic/core/quic_stream_send_buffer.h
@@ -5,6 +5,7 @@
#ifndef QUICHE_QUIC_CORE_QUIC_STREAM_SEND_BUFFER_H_
#define QUICHE_QUIC_CORE_QUIC_STREAM_SEND_BUFFER_H_
+#include "absl/types/span.h"
#include "quic/core/frames/quic_stream_frame.h"
#include "quic/core/quic_interval_deque.h"
#include "quic/core/quic_interval_set.h"
@@ -80,6 +81,7 @@
// Save all slices in |span| to send buffer. Return total bytes saved.
QuicByteCount SaveMemSliceSpan(QuicMemSliceSpan span);
+ QuicByteCount SaveMemSliceSpan(absl::Span<QuicMemSlice> span);
// Called when |bytes_consumed| bytes has been consumed by the stream.
void OnStreamDataConsumed(size_t bytes_consumed);
diff --git a/quic/core/quic_stream_test.cc b/quic/core/quic_stream_test.cc
index 2d3298b..e69b657 100644
--- a/quic/core/quic_stream_test.cc
+++ b/quic/core/quic_stream_test.cc
@@ -1178,14 +1178,17 @@
SetQuicFlag(FLAGS_quic_buffered_data_threshold, 100);
Initialize();
- char data[1024];
- std::vector<std::pair<char*, size_t>> buffers;
- buffers.push_back(std::make_pair(data, ABSL_ARRAYSIZE(data)));
- buffers.push_back(std::make_pair(data, ABSL_ARRAYSIZE(data)));
- QuicTestMemSliceVector vector1(buffers);
- QuicTestMemSliceVector vector2(buffers);
- QuicMemSliceSpan span1 = vector1.span();
- QuicMemSliceSpan span2 = vector2.span();
+ constexpr QuicByteCount kDataSize = 1024;
+ QuicBufferAllocator* allocator =
+ connection_->helper()->GetStreamSendBufferAllocator();
+ std::vector<QuicMemSlice> vector1;
+ vector1.push_back(QuicMemSlice(QuicBuffer(allocator, kDataSize)));
+ vector1.push_back(QuicMemSlice(QuicBuffer(allocator, kDataSize)));
+ std::vector<QuicMemSlice> vector2;
+ vector2.push_back(QuicMemSlice(QuicBuffer(allocator, kDataSize)));
+ vector2.push_back(QuicMemSlice(QuicBuffer(allocator, kDataSize)));
+ absl::Span<QuicMemSlice> span1(vector1);
+ absl::Span<QuicMemSlice> span2(vector2);
EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
.WillOnce(InvokeWithoutArgs([this]() {
@@ -1196,7 +1199,7 @@
QuicConsumedData consumed = stream_->WriteMemSlices(span1, false);
EXPECT_EQ(2048u, consumed.bytes_consumed);
EXPECT_FALSE(consumed.fin_consumed);
- EXPECT_EQ(2 * ABSL_ARRAYSIZE(data) - 100, stream_->BufferedDataBytes());
+ EXPECT_EQ(2 * kDataSize - 100, stream_->BufferedDataBytes());
EXPECT_FALSE(stream_->fin_buffered());
EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _)).Times(0);
@@ -1204,12 +1207,11 @@
consumed = stream_->WriteMemSlices(span2, true);
EXPECT_EQ(0u, consumed.bytes_consumed);
EXPECT_FALSE(consumed.fin_consumed);
- EXPECT_EQ(2 * ABSL_ARRAYSIZE(data) - 100, stream_->BufferedDataBytes());
+ EXPECT_EQ(2 * kDataSize - 100, stream_->BufferedDataBytes());
EXPECT_FALSE(stream_->fin_buffered());
QuicByteCount data_to_write =
- 2 * ABSL_ARRAYSIZE(data) - 100 -
- GetQuicFlag(FLAGS_quic_buffered_data_threshold) + 1;
+ 2 * kDataSize - 100 - GetQuicFlag(FLAGS_quic_buffered_data_threshold) + 1;
EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _))
.WillOnce(InvokeWithoutArgs([this, data_to_write]() {
return session_->ConsumeData(stream_->id(), data_to_write, 100u, NO_FIN,
@@ -1225,8 +1227,7 @@
consumed = stream_->WriteMemSlices(span2, true);
EXPECT_EQ(2048u, consumed.bytes_consumed);
EXPECT_TRUE(consumed.fin_consumed);
- EXPECT_EQ(2 * ABSL_ARRAYSIZE(data) +
- GetQuicFlag(FLAGS_quic_buffered_data_threshold) - 1,
+ EXPECT_EQ(2 * kDataSize + GetQuicFlag(FLAGS_quic_buffered_data_threshold) - 1,
stream_->BufferedDataBytes());
EXPECT_TRUE(stream_->fin_buffered());