gfe-relnote: Add a connection option(1ACK) to send only one immediate ACK in QUIC after reordering, instead of 4.  Protected by gfe2_reloadable_flag_quic_one_immediate_ack

PiperOrigin-RevId: 290743392
Change-Id: I0c1a557d48f3b0b0c3e58c235d6c97dd79973c68
diff --git a/quic/core/crypto/crypto_protocol.h b/quic/core/crypto/crypto_protocol.h
index 9400a5e..70cd234 100644
--- a/quic/core/crypto/crypto_protocol.h
+++ b/quic/core/crypto/crypto_protocol.h
@@ -138,6 +138,7 @@
 const QuicTag kMAD3 = TAG('M', 'A', 'D', '3');   // No min RTO
 const QuicTag kMAD4 = TAG('M', 'A', 'D', '4');   // IETF style TLP
 const QuicTag kMAD5 = TAG('M', 'A', 'D', '5');   // IETF style TLP with 2x mult
+const QuicTag k1ACK = TAG('1', 'A', 'C', 'K');   // 1 fast ack for reordering
 const QuicTag kACD0 = TAG('A', 'D', 'D', '0');   // Disable ack decimation
 const QuicTag kACKD = TAG('A', 'C', 'K', 'D');   // Ack decimation style acking.
 const QuicTag kAKD2 = TAG('A', 'K', 'D', '2');   // Ack decimation tolerating
diff --git a/quic/core/quic_received_packet_manager.cc b/quic/core/quic_received_packet_manager.cc
index 9e33ea4..4333323 100644
--- a/quic/core/quic_received_packet_manager.cc
+++ b/quic/core/quic_received_packet_manager.cc
@@ -12,6 +12,7 @@
 #include "net/third_party/quiche/src/quic/core/crypto/crypto_protocol.h"
 #include "net/third_party/quiche/src/quic/core/quic_connection_stats.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_flags.h"
 #include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
 
 namespace quic {
@@ -50,6 +51,7 @@
       ack_decimation_delay_(kAckDecimationDelay),
       unlimited_ack_decimation_(false),
       fast_ack_after_quiescence_(false),
+      one_immediate_ack_(false),
       local_max_ack_delay_(
           QuicTime::Delta::FromMilliseconds(kDefaultDelayedAckTimeMs)),
       ack_timeout_(QuicTime::Zero()),
@@ -88,6 +90,11 @@
   if (config.HasClientSentConnectionOption(kACKQ, perspective)) {
     fast_ack_after_quiescence_ = true;
   }
+  if (GetQuicReloadableFlag(quic_one_immediate_ack) &&
+      config.HasClientSentConnectionOption(k1ACK, perspective)) {
+    QUIC_RELOADABLE_FLAG_COUNT(quic_one_immediate_ack);
+    one_immediate_ack_ = true;
+  }
 }
 
 void QuicReceivedPacketManager::RecordPacketReceived(
@@ -315,6 +322,9 @@
 }
 
 bool QuicReceivedPacketManager::HasNewMissingPackets() const {
+  if (one_immediate_ack_) {
+    return HasMissingPackets() && ack_frame_.packets.LastIntervalLength() == 1;
+  }
   return HasMissingPackets() &&
          ack_frame_.packets.LastIntervalLength() <= kMaxPacketsAfterNewMissing;
 }
diff --git a/quic/core/quic_received_packet_manager.h b/quic/core/quic_received_packet_manager.h
index 293b03c..92a9e2f 100644
--- a/quic/core/quic_received_packet_manager.h
+++ b/quic/core/quic_received_packet_manager.h
@@ -175,6 +175,8 @@
   // When true, use a 1ms delayed ack timer if it's been an SRTT since a packet
   // was received.
   bool fast_ack_after_quiescence_;
+  // When true, only send 1 immediate ACK when reordering is detected.
+  bool one_immediate_ack_;
 
   // The local node's maximum ack delay time. This is the maximum amount of
   // time to wait before sending an acknowledgement.
diff --git a/quic/core/quic_received_packet_manager_test.cc b/quic/core/quic_received_packet_manager_test.cc
index 7355847..bfdf338 100644
--- a/quic/core/quic_received_packet_manager_test.cc
+++ b/quic/core/quic_received_packet_manager_test.cc
@@ -31,6 +31,11 @@
     manager->fast_ack_after_quiescence_ = fast_ack_after_quiescence;
   }
 
+  static void SetOneImmediateAck(QuicReceivedPacketManager* manager,
+                                 bool one_immediate_ack) {
+    manager->one_immediate_ack_ = one_immediate_ack;
+  }
+
   static void SetAckDecimationDelay(QuicReceivedPacketManager* manager,
                                     float ack_decimation_delay) {
     manager->ack_decimation_delay_ = ack_decimation_delay;
@@ -247,6 +252,16 @@
   // Delayed ack is scheduled.
   CheckAckTimeout(clock_.ApproximateNow() + kDelayedAckTime);
 
+  RecordPacketReceipt(5, clock_.ApproximateNow());
+  MaybeUpdateAckTimeout(kInstigateAck, 5);
+  // Immediate ack is sent.
+  CheckAckTimeout(clock_.ApproximateNow());
+
+  RecordPacketReceipt(6, clock_.ApproximateNow());
+  MaybeUpdateAckTimeout(kInstigateAck, 6);
+  // Immediate ack is scheduled, because 4 is still missing.
+  CheckAckTimeout(clock_.ApproximateNow());
+
   RecordPacketReceipt(2, clock_.ApproximateNow());
   MaybeUpdateAckTimeout(kInstigateAck, 2);
   CheckAckTimeout(clock_.ApproximateNow());
@@ -256,10 +271,44 @@
   // Should ack immediately, since this fills the last hole.
   CheckAckTimeout(clock_.ApproximateNow());
 
-  RecordPacketReceipt(4, clock_.ApproximateNow());
-  MaybeUpdateAckTimeout(kInstigateAck, 4);
+  RecordPacketReceipt(7, clock_.ApproximateNow());
+  MaybeUpdateAckTimeout(kInstigateAck, 7);
+  // Immediate ack is scheduled, because 4 is still missing.
+  CheckAckTimeout(clock_.ApproximateNow());
+}
+
+TEST_P(QuicReceivedPacketManagerTest, OutOfOrderReceiptCausesAckSent1Ack) {
+  QuicReceivedPacketManagerPeer::SetOneImmediateAck(&received_manager_, true);
+  EXPECT_FALSE(HasPendingAck());
+
+  RecordPacketReceipt(3, clock_.ApproximateNow());
+  MaybeUpdateAckTimeout(kInstigateAck, 3);
   // Delayed ack is scheduled.
   CheckAckTimeout(clock_.ApproximateNow() + kDelayedAckTime);
+
+  RecordPacketReceipt(5, clock_.ApproximateNow());
+  MaybeUpdateAckTimeout(kInstigateAck, 5);
+  // Immediate ack is sent.
+  CheckAckTimeout(clock_.ApproximateNow());
+
+  RecordPacketReceipt(6, clock_.ApproximateNow());
+  MaybeUpdateAckTimeout(kInstigateAck, 6);
+  // Delayed ack is scheduled.
+  CheckAckTimeout(clock_.ApproximateNow() + kDelayedAckTime);
+
+  RecordPacketReceipt(2, clock_.ApproximateNow());
+  MaybeUpdateAckTimeout(kInstigateAck, 2);
+  CheckAckTimeout(clock_.ApproximateNow());
+
+  RecordPacketReceipt(1, clock_.ApproximateNow());
+  MaybeUpdateAckTimeout(kInstigateAck, 1);
+  // Should ack immediately, since this fills the last hole.
+  CheckAckTimeout(clock_.ApproximateNow());
+
+  RecordPacketReceipt(7, clock_.ApproximateNow());
+  MaybeUpdateAckTimeout(kInstigateAck, 7);
+  // Delayed ack is scheduled, even though 4 is still missing.
+  CheckAckTimeout(clock_.ApproximateNow() + kDelayedAckTime);
 }
 
 TEST_P(QuicReceivedPacketManagerTest, OutOfOrderAckReceiptCausesNoAck) {