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