Internal change

PiperOrigin-RevId: 547813805
diff --git a/quiche/quic/core/batch_writer/quic_batch_writer_base.cc b/quiche/quic/core/batch_writer/quic_batch_writer_base.cc
index fae805f..666406f 100644
--- a/quiche/quic/core/batch_writer/quic_batch_writer_base.cc
+++ b/quiche/quic/core/batch_writer/quic_batch_writer_base.cc
@@ -62,6 +62,7 @@
 
   bool buffered = false;
   bool flush = can_batch_result.must_flush;
+  uint32_t packet_batch_id = 0;
 
   if (can_batch_result.can_batch) {
     QuicBatchWriterBuffer::PushResult push_result =
@@ -72,6 +73,7 @@
       buffered = true;
       // If there's no space left after the packet is buffered, force a flush.
       flush = flush || (batch_buffer_->GetNextWriteLocation() == nullptr);
+      packet_batch_id = push_result.batch_id;
     } else {
       // If there's no space without this packet, force a flush.
       flush = true;
@@ -93,9 +95,10 @@
 
   if (result.status != WRITE_STATUS_OK) {
     if (IsWriteBlockedStatus(result.status)) {
-      return WriteResult(
-          buffered ? WRITE_STATUS_BLOCKED_DATA_BUFFERED : WRITE_STATUS_BLOCKED,
-          result.error_code);
+      return WriteResult(buffered ? WRITE_STATUS_BLOCKED_DATA_BUFFERED
+                                  : WRITE_STATUS_BLOCKED,
+                         result.error_code)
+          .set_batch_id(packet_batch_id);
     }
 
     // Drop all packets, including the one being written.
@@ -116,6 +119,7 @@
                                          peer_address, options, params,
                                          release_time.actual_release_time);
     buffered = push_result.succeeded;
+    packet_batch_id = push_result.batch_id;
 
     // Since buffered_writes has been emptied, this write must have been
     // buffered successfully.
@@ -126,6 +130,7 @@
   }
 
   result.send_time_offset = release_time.release_time_offset;
+  result.batch_id = packet_batch_id;
   return result;
 }
 
diff --git a/quiche/quic/core/batch_writer/quic_batch_writer_buffer.cc b/quiche/quic/core/batch_writer/quic_batch_writer_buffer.cc
index d283e2b..6fa7059 100644
--- a/quiche/quic/core/batch_writer/quic_batch_writer_buffer.cc
+++ b/quiche/quic/core/batch_writer/quic_batch_writer_buffer.cc
@@ -82,6 +82,17 @@
   } else {
     // In place push, do nothing.
   }
+  if (buffered_writes_.empty()) {
+    // Starting a new batch.
+    ++batch_id_;
+
+    // |batch_id| is a 32-bit unsigned int that is possibly shared by a lot of
+    // QUIC connections(because writer can be shared), so wrap around happens,
+    // when it happens we skip id=0, which indicates "not batched".
+    if (batch_id_ == 0) {
+      ++batch_id_;
+    }
+  }
   buffered_writes_.emplace_back(
       next_write_location, buf_len, self_address, peer_address,
       options ? options->Clone() : std::unique_ptr<PerPacketOptions>(), params,
@@ -90,6 +101,7 @@
   QUICHE_DCHECK(Invariants());
 
   result.succeeded = true;
+  result.batch_id = batch_id_;
   return result;
 }
 
diff --git a/quiche/quic/core/batch_writer/quic_batch_writer_buffer.h b/quiche/quic/core/batch_writer/quic_batch_writer_buffer.h
index 62282a3..369ecff 100644
--- a/quiche/quic/core/batch_writer/quic_batch_writer_buffer.h
+++ b/quiche/quic/core/batch_writer/quic_batch_writer_buffer.h
@@ -38,6 +38,8 @@
     //    in-place push.
     // Only valid if |succeeded| is true.
     bool buffer_copied;
+    // The batch ID of the packet. Only valid if |succeeded|.
+    uint32_t batch_id = 0;
   };
 
   PushResult PushBufferedWrite(const char* buffer, size_t buf_len,
@@ -88,6 +90,11 @@
   const char* buffer_end() const { return buffer_ + sizeof(buffer_); }
   ABSL_CACHELINE_ALIGNED char buffer_[kBufferSize];
   quiche::QuicheCircularDeque<BufferedWrite> buffered_writes_;
+  // 0 if a batch has never started. Otherwise
+  // - If |buffered_writes_| is empty, this is the ID of the previous batch.
+  // - If |buffered_writes_| is not empty, this is the ID of the current batch.
+  // For debugging only.
+  uint32_t batch_id_ = 0;
 };
 
 }  // namespace quic
diff --git a/quiche/quic/core/batch_writer/quic_batch_writer_buffer_test.cc b/quiche/quic/core/batch_writer/quic_batch_writer_buffer_test.cc
index ffa88f0..747ff1f 100644
--- a/quiche/quic/core/batch_writer/quic_batch_writer_buffer_test.cc
+++ b/quiche/quic/core/batch_writer/quic_batch_writer_buffer_test.cc
@@ -278,6 +278,34 @@
                             nullptr, params);
 }
 
+TEST_F(QuicBatchWriterBufferTest, BatchID) {
+  const int kNumBufferedWrites = 10;
+  QuicPacketWriterParams params;
+  auto first_push_result = batch_buffer_->PushBufferedWrite(
+      packet_buffer_, kDefaultMaxPacketSize, self_addr_, peer_addr_, nullptr,
+      params, release_time_);
+  ASSERT_TRUE(first_push_result.succeeded);
+  ASSERT_NE(first_push_result.batch_id, 0);
+  for (int i = 1; i < kNumBufferedWrites; ++i) {
+    EXPECT_EQ(batch_buffer_
+                  ->PushBufferedWrite(packet_buffer_, kDefaultMaxPacketSize,
+                                      self_addr_, peer_addr_, nullptr, params,
+                                      release_time_)
+                  .batch_id,
+              first_push_result.batch_id);
+  }
+
+  batch_buffer_->PopBufferedWrite(kNumBufferedWrites);
+  EXPECT_TRUE(batch_buffer_->buffered_writes().empty());
+
+  EXPECT_NE(
+      batch_buffer_
+          ->PushBufferedWrite(packet_buffer_, kDefaultMaxPacketSize, self_addr_,
+                              peer_addr_, nullptr, params, release_time_)
+          .batch_id,
+      first_push_result.batch_id);
+}
+
 }  // namespace
 }  // namespace test
 }  // namespace quic
diff --git a/quiche/quic/core/quic_connection.cc b/quiche/quic/core/quic_connection.cc
index 0c29444..e95c8d1 100644
--- a/quiche/quic/core/quic_connection.cc
+++ b/quiche/quic/core/quic_connection.cc
@@ -3540,7 +3540,7 @@
           sent_packet_manager_.unacked_packets()
               .rbegin()
               ->retransmittable_frames,
-          packet->nonretransmittable_frames, packet_send_time);
+          packet->nonretransmittable_frames, packet_send_time, result.batch_id);
     }
   }
   if (packet->encryption_level == ENCRYPTION_HANDSHAKE) {
@@ -5020,6 +5020,8 @@
       packet->encrypted_buffer, packet->encrypted_length, self_address.host(),
       peer_address, writer, GetEcnCodepointToSend(peer_address));
 
+  const uint32_t writer_batch_id = result.batch_id;
+
   // If using a batch writer and the probing packet is buffered, flush it.
   if (writer->IsBatchMode() && result.status == WRITE_STATUS_OK &&
       result.bytes_written == 0) {
@@ -5051,7 +5053,7 @@
           sent_packet_manager_.unacked_packets()
               .rbegin()
               ->retransmittable_frames,
-          packet->nonretransmittable_frames, packet_send_time);
+          packet->nonretransmittable_frames, packet_send_time, writer_batch_id);
     }
   }
 
diff --git a/quiche/quic/core/quic_connection.h b/quiche/quic/core/quic_connection.h
index 6191fdd..cce16d0 100644
--- a/quiche/quic/core/quic_connection.h
+++ b/quiche/quic/core/quic_connection.h
@@ -281,7 +281,7 @@
                             EncryptionLevel /*encryption_level*/,
                             const QuicFrames& /*retransmittable_frames*/,
                             const QuicFrames& /*nonretransmittable_frames*/,
-                            QuicTime /*sent_time*/) {}
+                            QuicTime /*sent_time*/, uint32_t /*batch_id*/) {}
 
   // Called when a coalesced packet is successfully serialized.
   virtual void OnCoalescedPacketSent(
diff --git a/quiche/quic/core/quic_connection_test.cc b/quiche/quic/core/quic_connection_test.cc
index 12cea2f..d91c041 100644
--- a/quiche/quic/core/quic_connection_test.cc
+++ b/quiche/quic/core/quic_connection_test.cc
@@ -6984,10 +6984,10 @@
   MockQuicConnectionDebugVisitor debug_visitor;
   connection_.set_debug_visitor(&debug_visitor);
 
-  EXPECT_CALL(debug_visitor, OnPacketSent(_, _, _, _, _, _, _, _)).Times(1);
+  EXPECT_CALL(debug_visitor, OnPacketSent(_, _, _, _, _, _, _, _, _)).Times(1);
   connection_.SendStreamDataWithString(1, "foo", 0, NO_FIN);
 
-  EXPECT_CALL(debug_visitor, OnPacketSent(_, _, _, _, _, _, _, _)).Times(1);
+  EXPECT_CALL(debug_visitor, OnPacketSent(_, _, _, _, _, _, _, _, _)).Times(1);
   connection_.SendConnectivityProbingPacket(writer_.get(),
                                             connection_.peer_address());
 }
@@ -7114,7 +7114,7 @@
   CongestionBlockWrites();
   connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
   EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
-  EXPECT_CALL(debug_visitor, OnPacketSent(_, _, _, _, _, _, _, _)).Times(1);
+  EXPECT_CALL(debug_visitor, OnPacketSent(_, _, _, _, _, _, _, _, _)).Times(1);
   EXPECT_CALL(debug_visitor, OnPingSent()).Times(1);
   connection_.SendControlFrame(QuicFrame(QuicPingFrame(1)));
   EXPECT_FALSE(connection_.HasQueuedData());
@@ -7126,7 +7126,7 @@
 
   connection_.SetDefaultEncryptionLevel(ENCRYPTION_FORWARD_SECURE);
   EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
-  EXPECT_CALL(debug_visitor, OnPacketSent(_, _, _, _, _, _, _, _)).Times(1);
+  EXPECT_CALL(debug_visitor, OnPacketSent(_, _, _, _, _, _, _, _, _)).Times(1);
   EXPECT_EQ(0u, connection_.GetStats().blocked_frames_sent);
   connection_.SendControlFrame(QuicFrame(QuicBlockedFrame(1, 3, 0)));
   EXPECT_EQ(1u, connection_.GetStats().blocked_frames_sent);
@@ -7142,7 +7142,7 @@
   QuicBlockedFrame blocked(1, 3, 0);
 
   EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0);
-  EXPECT_CALL(debug_visitor, OnPacketSent(_, _, _, _, _, _, _, _)).Times(0);
+  EXPECT_CALL(debug_visitor, OnPacketSent(_, _, _, _, _, _, _, _, _)).Times(0);
   EXPECT_EQ(0u, connection_.GetStats().blocked_frames_sent);
   connection_.SendControlFrame(QuicFrame(blocked));
   EXPECT_EQ(0u, connection_.GetStats().blocked_frames_sent);
@@ -9907,7 +9907,7 @@
   }
   MockQuicConnectionDebugVisitor debug_visitor;
   connection_.set_debug_visitor(&debug_visitor);
-  EXPECT_CALL(debug_visitor, OnPacketSent(_, _, _, _, _, _, _, _)).Times(3);
+  EXPECT_CALL(debug_visitor, OnPacketSent(_, _, _, _, _, _, _, _, _)).Times(3);
   EXPECT_CALL(debug_visitor, OnCoalescedPacketSent(_, _)).Times(1);
   EXPECT_CALL(visitor_, OnHandshakePacketSent()).Times(1);
   {
@@ -15700,7 +15700,7 @@
   connection_.set_debug_visitor(&debug_visitor);
 
   uint64_t debug_visitor_sent_count = 0;
-  EXPECT_CALL(debug_visitor, OnPacketSent(_, _, _, _, _, _, _, _))
+  EXPECT_CALL(debug_visitor, OnPacketSent(_, _, _, _, _, _, _, _, _))
       .WillRepeatedly([&]() { debug_visitor_sent_count++; });
 
   EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(AnyNumber());
diff --git a/quiche/quic/core/quic_trace_visitor.cc b/quiche/quic/core/quic_trace_visitor.cc
index 388eebb..7906536 100644
--- a/quiche/quic/core/quic_trace_visitor.cc
+++ b/quiche/quic/core/quic_trace_visitor.cc
@@ -52,7 +52,8 @@
     QuicPacketNumber packet_number, QuicPacketLength packet_length,
     bool /*has_crypto_handshake*/, TransmissionType /*transmission_type*/,
     EncryptionLevel encryption_level, const QuicFrames& retransmittable_frames,
-    const QuicFrames& /*nonretransmittable_frames*/, QuicTime sent_time) {
+    const QuicFrames& /*nonretransmittable_frames*/, QuicTime sent_time,
+    uint32_t /*batch_id*/) {
   quic_trace::Event* event = trace_.add_events();
   event->set_event_type(quic_trace::PACKET_SENT);
   event->set_time_us(ConvertTimestampToRecordedFormat(sent_time));
diff --git a/quiche/quic/core/quic_trace_visitor.h b/quiche/quic/core/quic_trace_visitor.h
index 6a8c442..28e4d68 100644
--- a/quiche/quic/core/quic_trace_visitor.h
+++ b/quiche/quic/core/quic_trace_visitor.h
@@ -24,7 +24,7 @@
                     EncryptionLevel encryption_level,
                     const QuicFrames& retransmittable_frames,
                     const QuicFrames& nonretransmittable_frames,
-                    QuicTime sent_time) override;
+                    QuicTime sent_time, uint32_t batch_id) override;
 
   void OnIncomingAck(QuicPacketNumber ack_packet_number,
                      EncryptionLevel ack_decrypted_level,
diff --git a/quiche/quic/core/quic_types.h b/quiche/quic/core/quic_types.h
index 961e904..ae9a4fb 100644
--- a/quiche/quic/core/quic_types.h
+++ b/quiche/quic/core/quic_types.h
@@ -158,10 +158,19 @@
   QUIC_EXPORT_PRIVATE friend std::ostream& operator<<(std::ostream& os,
                                                       const WriteResult& s);
 
+  WriteResult& set_batch_id(uint32_t batch_id) {
+    this->batch_id = batch_id;
+    return *this;
+  }
+
   WriteStatus status;
   // Number of packets dropped as a result of this write.
   // Only used by batch writers. Otherwise always 0.
   uint16_t dropped_packets = 0;
+  // The batch id the packet being written belongs to. For debugging only.
+  // Only used by batch writers. Only valid if the packet being written started
+  // a new batch, or added to an existing batch.
+  uint32_t batch_id = 0;
   // The delta between a packet's ideal and actual send time:
   //     actual_send_time = ideal_send_time + send_time_offset
   //                      = (now + release_time_delay) + send_time_offset
diff --git a/quiche/quic/test_tools/quic_test_utils.h b/quiche/quic/test_tools/quic_test_utils.h
index 4a054f3..3d58222 100644
--- a/quiche/quic/test_tools/quic_test_utils.h
+++ b/quiche/quic/test_tools/quic_test_utils.h
@@ -1318,7 +1318,8 @@
 
   MOCK_METHOD(void, OnPacketSent,
               (QuicPacketNumber, QuicPacketLength, bool, TransmissionType,
-               EncryptionLevel, const QuicFrames&, const QuicFrames&, QuicTime),
+               EncryptionLevel, const QuicFrames&, const QuicFrames&, QuicTime,
+               uint32_t),
               (override));
 
   MOCK_METHOD(void, OnCoalescedPacketSent, (const QuicCoalescedPacket&, size_t),