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) {