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