Created and integrated QuicIntervalDeque class for index management. Improves code readability.
gfe-relnote: Integrated QuicIntervalDeque class into QuicStreamSendBuffer affecting the QUIC GFE path. Protected by --gfe2_reloadable_flag_quic_interval_deque
PiperOrigin-RevId: 286471930
Change-Id: Ida91b6c7d066d9710d06932c9f4726946bfbd430
diff --git a/quic/core/quic_stream_send_buffer.cc b/quic/core/quic_stream_send_buffer.cc
index 158afd8..2008cf2 100644
--- a/quic/core/quic_stream_send_buffer.cc
+++ b/quic/core/quic_stream_send_buffer.cc
@@ -35,13 +35,21 @@
BufferedSlice::~BufferedSlice() {}
+QuicInterval<std::size_t> BufferedSlice::interval() const {
+ const std::size_t length = slice.length();
+ return QuicInterval<std::size_t>(offset, offset + length);
+}
+
bool StreamPendingRetransmission::operator==(
const StreamPendingRetransmission& other) const {
return offset == other.offset && length == other.length;
}
QuicStreamSendBuffer::QuicStreamSendBuffer(QuicBufferAllocator* allocator)
- : stream_offset_(0),
+ // TODO(b/144690240): Remove this variable once quic_seeker is deprecated.
+ : interval_deque_active_(GetQuicReloadableFlag(quic_interval_deque)),
+ current_end_offset_(0),
+ stream_offset_(0),
allocator_(allocator),
stream_bytes_written_(0),
stream_bytes_outstanding_(0),
@@ -76,9 +84,20 @@
return;
}
size_t length = slice.length();
- buffered_slices_.emplace_back(std::move(slice), stream_offset_);
- if (write_index_ == -1) {
- write_index_ = buffered_slices_.size() - 1;
+ if (interval_deque_active_) {
+ QUIC_RELOADABLE_FLAG_COUNT_N(quic_interval_deque, 1, 5);
+ // Need to start the offsets at the right interval.
+ if (interval_deque_.Empty()) {
+ const QuicStreamOffset end = stream_offset_ + length;
+ current_end_offset_ = std::max(current_end_offset_, end);
+ }
+ BufferedSlice bs = BufferedSlice(std::move(slice), stream_offset_);
+ interval_deque_.PushBack(std::move(bs));
+ } else {
+ buffered_slices_.emplace_back(std::move(slice), stream_offset_);
+ if (write_index_ == -1) {
+ write_index_ = buffered_slices_.size() - 1;
+ }
}
stream_offset_ += length;
}
@@ -96,6 +115,38 @@
bool QuicStreamSendBuffer::WriteStreamData(QuicStreamOffset offset,
QuicByteCount data_length,
QuicDataWriter* writer) {
+ if (interval_deque_active_) {
+ QUIC_RELOADABLE_FLAG_COUNT_N(quic_interval_deque, 2, 5);
+ QUIC_BUG_IF(current_end_offset_ < offset)
+ << "Tried to write data out of sequence. last_offset_end:"
+ << current_end_offset_ << ", offset:" << offset;
+ // The iterator returned from |interval_deque_| will automatically advance
+ // the internal write index for the QuicIntervalDeque. The incrementing is
+ // done in operator++.
+ for (auto slice_it = interval_deque_.DataAt(offset);
+ slice_it != interval_deque_.DataEnd(); ++slice_it) {
+ if (data_length == 0 || offset < slice_it->offset) {
+ break;
+ }
+
+ QuicByteCount slice_offset = offset - slice_it->offset;
+ QuicByteCount available_bytes_in_slice =
+ slice_it->slice.length() - slice_offset;
+ QuicByteCount copy_length =
+ std::min(data_length, available_bytes_in_slice);
+ if (!writer->WriteBytes(slice_it->slice.data() + slice_offset,
+ copy_length)) {
+ QUIC_BUG << "Writer fails to write.";
+ return false;
+ }
+ offset += copy_length;
+ data_length -= copy_length;
+ const QuicStreamOffset new_end =
+ slice_it->offset + slice_it->slice.length();
+ current_end_offset_ = std::max(current_end_offset_, new_end);
+ }
+ return data_length == 0;
+ }
// TODO(renjietang): Remove this variable once quic_coalesce_stream_frames_2
// is deprecated.
bool write_index_hit = false;
@@ -164,7 +215,7 @@
}
} else if (write_index_hit &&
static_cast<size_t>(write_index_) == buffered_slices_.size()) {
- // Already write to the end off buffer.
+ // Already write to the end of buffer.
QUIC_DVLOG(2) << "Finish writing out all buffered data.";
write_index_ = -1;
}
@@ -264,6 +315,39 @@
bool QuicStreamSendBuffer::FreeMemSlices(QuicStreamOffset start,
QuicStreamOffset end) {
+ if (interval_deque_active_) {
+ QUIC_RELOADABLE_FLAG_COUNT_N(quic_interval_deque, 3, 5);
+ auto it = interval_deque_.DataBegin();
+ if (it == interval_deque_.DataEnd() || it->slice.empty()) {
+ QUIC_BUG << "Trying to ack stream data [" << start << ", " << end << "), "
+ << (it == interval_deque_.DataEnd()
+ ? "and there is no outstanding data."
+ : "and the first slice is empty.");
+ return false;
+ }
+ if (!it->interval().Contains(start)) {
+ // Slow path that not the earliest outstanding data gets acked.
+ it = std::lower_bound(interval_deque_.DataBegin(),
+ interval_deque_.DataEnd(), start, CompareOffset());
+ }
+ if (it == interval_deque_.DataEnd() || it->slice.empty()) {
+ QUIC_BUG << "Offset " << start << " with iterator offset: " << it->offset
+ << (it == interval_deque_.DataEnd()
+ ? " does not exist."
+ : " has already been acked.");
+ return false;
+ }
+ for (; it != interval_deque_.DataEnd(); ++it) {
+ if (it->offset >= end) {
+ break;
+ }
+ if (!it->slice.empty() &&
+ bytes_acked_.Contains(it->offset, it->offset + it->slice.length())) {
+ it->slice.Reset();
+ }
+ }
+ return true;
+ }
auto it = buffered_slices_.begin();
// Find it, such that buffered_slices_[it - 1].end < start <=
// buffered_slices_[it].end.
@@ -297,6 +381,19 @@
}
void QuicStreamSendBuffer::CleanUpBufferedSlices() {
+ if (interval_deque_active_) {
+ QUIC_RELOADABLE_FLAG_COUNT_N(quic_interval_deque, 4, 5);
+ while (!interval_deque_.Empty() &&
+ interval_deque_.DataBegin()->slice.empty()) {
+ QUIC_BUG_IF(interval_deque_.DataBegin()->offset > current_end_offset_)
+ << "Fail to pop front from interval_deque_. Front element contained "
+ "a slice whose data has not all be written. Front offset "
+ << interval_deque_.DataBegin()->offset << " length "
+ << interval_deque_.DataBegin()->slice.length();
+ interval_deque_.PopFront();
+ }
+ return;
+ }
while (!buffered_slices_.empty() && buffered_slices_.front().slice.empty()) {
// Remove data which stops waiting for acks. Please note, mem slices can
// be released out of order, but send buffer is cleaned up in order.
@@ -323,7 +420,12 @@
}
size_t QuicStreamSendBuffer::size() const {
- return buffered_slices_.size();
+ if (interval_deque_active_) {
+ QUIC_RELOADABLE_FLAG_COUNT_N(quic_interval_deque, 5, 5);
+ return interval_deque_.Size();
+ } else {
+ return buffered_slices_.size();
+ }
}
} // namespace quic