Remove unnecessary copy in QuicChaosProtector

When QuicChaosProtector was first written, QuicStreamSendBuffer did not allow out-of-order writes. To work around this, QuicChaosProtector copied out the entire crypto data in one go. Now that cl/712548578 has landed, QuicStreamSendBuffer allows out-of-order writes so this copy is no longer required. This CL removes that unnecessary copy.

Protected by FLAGS_quic_reloadable_flag_quic_chaos_protector_avoid_copy.

PiperOrigin-RevId: 712664648
diff --git a/quiche/common/quiche_feature_flags_list.h b/quiche/common/quiche_feature_flags_list.h
index 52a8c84..065699e 100755
--- a/quiche/common/quiche_feature_flags_list.h
+++ b/quiche/common/quiche_feature_flags_list.h
@@ -19,6 +19,7 @@
 QUICHE_FLAG(bool, quiche_reloadable_flag_quic_block_until_settings_received_copt, true, true, "If enabled and a BSUS connection is received, blocks server connections until SETTINGS frame is received.")
 QUICHE_FLAG(bool, quiche_reloadable_flag_quic_buffered_store_set_client_cid, false, true, "If true, QuicBufferedPacketStore will set client CID in packets it generates.")
 QUICHE_FLAG(bool, quiche_reloadable_flag_quic_can_send_ack_frequency, true, true, "If true, ack frequency frame can be sent from server to client.")
+QUICHE_FLAG(bool, quiche_reloadable_flag_quic_chaos_protector_avoid_copy, false, true, "When true, avoid unnecessary copy in QuicChaosProtector.")
 QUICHE_FLAG(bool, quiche_reloadable_flag_quic_conservative_bursts, false, false, "If true, set burst token to 2 in cwnd bootstrapping experiment.")
 QUICHE_FLAG(bool, quiche_reloadable_flag_quic_conservative_cwnd_and_pacing_gains, false, false, "If true, uses conservative cwnd gain and pacing gain when cwnd gets bootstrapped.")
 QUICHE_FLAG(bool, quiche_reloadable_flag_quic_default_enable_5rto_blackhole_detection2, true, true, "If true, default-enable 5RTO blachole detection.")
diff --git a/quiche/quic/core/quic_chaos_protector.cc b/quiche/quic/core/quic_chaos_protector.cc
index 8295730..f7a8bc2 100644
--- a/quiche/quic/core/quic_chaos_protector.cc
+++ b/quiche/quic/core/quic_chaos_protector.cc
@@ -24,6 +24,8 @@
 #include "quiche/quic/core/quic_stream_frame_data_producer.h"
 #include "quiche/quic/core/quic_types.h"
 #include "quiche/quic/platform/api/quic_bug_tracker.h"
+#include "quiche/quic/platform/api/quic_flag_utils.h"
+#include "quiche/quic/platform/api/quic_flags.h"
 #include "quiche/common/platform/api/quiche_logging.h"
 #include "quiche/common/simple_buffer_allocator.h"
 
@@ -228,10 +230,14 @@
 QuicChaosProtector::QuicChaosProtector(size_t packet_size,
                                        EncryptionLevel level,
                                        QuicFramer* framer, QuicRandom* random)
-    : packet_size_(packet_size),
+    : avoid_copy_(GetQuicReloadableFlag(quic_chaos_protector_avoid_copy)),
+      packet_size_(packet_size),
       level_(level),
       framer_(framer),
       random_(random) {
+  if (avoid_copy_) {
+    QUIC_RELOADABLE_FLAG_COUNT(quic_chaos_protector_avoid_copy);
+  }
   QUICHE_DCHECK_NE(framer_, nullptr);
   QUICHE_DCHECK_NE(framer_->data_producer(), nullptr);
   QUICHE_DCHECK_NE(random_, nullptr);
@@ -295,11 +301,13 @@
                   << header.packet_number;
     return std::nullopt;
   }
-  if (!CopyCryptoDataToLocalBuffer()) {
-    QUIC_DVLOG(1) << "Failed to copy crypto data to local buffer for initial "
-                     "packet number "
-                  << header.packet_number;
-    return std::nullopt;
+  if (!avoid_copy_) {
+    if (!CopyCryptoDataToLocalBuffer()) {
+      QUIC_DVLOG(1) << "Failed to copy crypto data to local buffer for initial "
+                       "packet number "
+                    << header.packet_number;
+      return std::nullopt;
+    }
   }
   SplitCryptoFrame();
   AddPingFrames();
@@ -321,6 +329,10 @@
                                          QuicStreamOffset offset,
                                          QuicByteCount data_length,
                                          QuicDataWriter* writer) {
+  if (avoid_copy_) {
+    QUIC_BUG(chaos avoid copy WriteCryptoData) << "This should never be called";
+    return false;
+  }
   if (level != level_) {
     QUIC_BUG(chaos bad level) << "Unexpected " << level << " != " << level_;
     return false;
@@ -341,6 +353,11 @@
 }
 
 bool QuicChaosProtector::CopyCryptoDataToLocalBuffer() {
+  if (avoid_copy_) {
+    QUIC_BUG(chaos avoid copy CopyCryptoDataToLocalBuffer)
+        << "This should never be called";
+    return false;
+  }
   size_t frame_size = QuicDataWriter::GetVarInt62Len(crypto_buffer_offset_) +
                       QuicDataWriter::GetVarInt62Len(crypto_data_length_) +
                       crypto_data_length_;
@@ -480,14 +497,18 @@
 
 std::optional<size_t> QuicChaosProtector::BuildPacket(
     const QuicPacketHeader& header, char* buffer) {
-  QuicStreamFrameDataProducer* original_data_producer =
-      framer_->data_producer();
-  framer_->set_data_producer(this);
+  QuicStreamFrameDataProducer* original_data_producer;
+  if (!avoid_copy_) {
+    original_data_producer = framer_->data_producer();
+    framer_->set_data_producer(this);
+  }
 
   size_t length =
       framer_->BuildDataPacket(header, frames_, buffer, packet_size_, level_);
 
-  framer_->set_data_producer(original_data_producer);
+  if (!avoid_copy_) {
+    framer_->set_data_producer(original_data_producer);
+  }
   if (length == 0) {
     QUIC_DVLOG(1) << "Failed to build data packet for initial packet number "
                   << header.packet_number;
diff --git a/quiche/quic/core/quic_chaos_protector.h b/quiche/quic/core/quic_chaos_protector.h
index 5dbb3ad..bed2d6f 100644
--- a/quiche/quic/core/quic_chaos_protector.h
+++ b/quiche/quic/core/quic_chaos_protector.h
@@ -154,6 +154,7 @@
   std::optional<size_t> BuildPacket(const QuicPacketHeader& header,
                                     char* buffer);
 
+  const bool avoid_copy_;  // Latched from quic_chaos_protector_avoid_copy flag.
   size_t packet_size_;
   std::unique_ptr<char[]> crypto_frame_buffer_;
   const char* crypto_data_buffer_ = nullptr;
diff --git a/quiche/quic/core/quic_chaos_protector_test.cc b/quiche/quic/core/quic_chaos_protector_test.cc
index b090916..6531c10 100644
--- a/quiche/quic/core/quic_chaos_protector_test.cc
+++ b/quiche/quic/core/quic_chaos_protector_test.cc
@@ -299,8 +299,10 @@
                        QuicByteCount data_length,
                        QuicDataWriter* writer) override {
     EXPECT_EQ(level, level);
-    EXPECT_EQ(offset, crypto_offset_);
-    EXPECT_EQ(data_length, crypto_data_length_);
+    if (!chaos_protector_->avoid_copy_) {
+      EXPECT_EQ(offset, crypto_offset_);
+      EXPECT_EQ(data_length, crypto_data_length_);
+    }
     for (QuicByteCount i = 0; i < data_length; i++) {
       EXPECT_TRUE(writer->WriteUInt8(static_cast<uint8_t>((offset + i) & 0xFF)))
           << i;