gfe-relnote: In QUIC, add connection option to enable IETF loss detection with both adaptive packet and adaptive time threshold. Protected by existing gfe2_reloadable_flag_quic_enable_ietf_loss_detection. PiperOrigin-RevId: 278375594 Change-Id: Ib3dd4aa9208ec367197ec46d5b401c0f390e6085
diff --git a/quic/core/congestion_control/general_loss_algorithm.cc b/quic/core/congestion_control/general_loss_algorithm.cc index 5f7115a..8798322 100644 --- a/quic/core/congestion_control/general_loss_algorithm.cc +++ b/quic/core/congestion_control/general_loss_algorithm.cc
@@ -32,6 +32,7 @@ : loss_detection_timeout_(QuicTime::Zero()), reordering_threshold_(kNumberOfNacksBeforeRetransmission), use_adaptive_reordering_threshold_(false), + use_adaptive_time_threshold_(false), least_in_flight_(1), packet_number_space_(NUM_PACKET_NUMBER_SPACES) { SetLossDetectionType(loss_type); @@ -190,7 +191,8 @@ QuicTime ack_receive_time, QuicPacketNumber packet_number, QuicPacketNumber previous_largest_acked) { - if (loss_type_ == kAdaptiveTime && reordering_shift_ > 0) { + if ((loss_type_ == kAdaptiveTime || use_adaptive_time_threshold_) && + reordering_shift_ > 0) { // Increase reordering fraction such that the packet would not have been // declared lost. QuicTime::Delta time_needed =
diff --git a/quic/core/congestion_control/general_loss_algorithm.h b/quic/core/congestion_control/general_loss_algorithm.h index d501cc6..fb85523 100644 --- a/quic/core/congestion_control/general_loss_algorithm.h +++ b/quic/core/congestion_control/general_loss_algorithm.h
@@ -70,6 +70,12 @@ use_adaptive_reordering_threshold_ = true; } + bool use_adaptive_time_threshold() const { + return use_adaptive_time_threshold_; + } + + void enable_adaptive_time_threshold() { use_adaptive_time_threshold_ = true; } + private: QuicTime loss_detection_timeout_; LossDetectionType loss_type_; @@ -81,6 +87,8 @@ QuicPacketCount reordering_threshold_; // If true, uses adaptive reordering threshold for loss detection. bool use_adaptive_reordering_threshold_; + // If true, uses adaptive time threshold for time based loss detection. + bool use_adaptive_time_threshold_; // The largest newly acked from the previous call to DetectLosses. QuicPacketNumber largest_previously_acked_; // The least in flight packet. Loss detection should start from this. Please
diff --git a/quic/core/congestion_control/general_loss_algorithm_test.cc b/quic/core/congestion_control/general_loss_algorithm_test.cc index 0c41f65..aaf9c7c 100644 --- a/quic/core/congestion_control/general_loss_algorithm_test.cc +++ b/quic/core/congestion_control/general_loss_algorithm_test.cc
@@ -520,6 +520,48 @@ EXPECT_EQ(1, loss_algorithm_.reordering_shift()); } +TEST_F(GeneralLossAlgorithmTest, IncreaseTimeThresholdUponSpuriousLoss) { + loss_algorithm_.SetLossDetectionType(kIetfLossDetection); + loss_algorithm_.enable_adaptive_time_threshold(); + loss_algorithm_.set_reordering_shift(kDefaultLossDelayShift); + EXPECT_EQ(kDefaultLossDelayShift, loss_algorithm_.reordering_shift()); + EXPECT_TRUE(loss_algorithm_.use_adaptive_time_threshold()); + const size_t kNumSentPackets = 10; + // Transmit 2 packets at 1/10th an RTT interval. + for (size_t i = 1; i <= kNumSentPackets; ++i) { + SendDataPacket(i); + clock_.AdvanceTime(0.1 * rtt_stats_.smoothed_rtt()); + } + EXPECT_EQ(QuicTime::Zero() + rtt_stats_.smoothed_rtt(), clock_.Now()); + AckedPacketVector packets_acked; + // Expect the timer to not be set. + EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout()); + // Packet 1 should not be lost until 1/4 RTTs pass. + unacked_packets_.RemoveFromInFlight(QuicPacketNumber(2)); + packets_acked.push_back(AckedPacket( + QuicPacketNumber(2), kMaxOutgoingPacketSize, QuicTime::Zero())); + VerifyLosses(2, packets_acked, std::vector<uint64_t>{}); + packets_acked.clear(); + // Expect the timer to be set to 1/4 RTT's in the future. + EXPECT_EQ(rtt_stats_.smoothed_rtt() * (1.0f / 4), + loss_algorithm_.GetLossTimeout() - clock_.Now()); + VerifyLosses(2, packets_acked, std::vector<uint64_t>{}); + clock_.AdvanceTime(rtt_stats_.smoothed_rtt() * (1.0f / 4)); + VerifyLosses(2, packets_acked, {1}); + EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout()); + // Retransmit packet 1 as 11 and 2 as 12. + SendDataPacket(11); + SendDataPacket(12); + + // Advance the time 1/4 RTT and indicate the loss was spurious. + // The new threshold should be 1/2 RTT. + clock_.AdvanceTime(rtt_stats_.smoothed_rtt() * (1.0f / 4)); + loss_algorithm_.SpuriousLossDetected(unacked_packets_, rtt_stats_, + clock_.Now(), QuicPacketNumber(1), + QuicPacketNumber(2)); + EXPECT_EQ(1, loss_algorithm_.reordering_shift()); +} + TEST_F(GeneralLossAlgorithmTest, IncreaseReorderingThresholdUponSpuriousLoss) { loss_algorithm_.enable_adaptive_reordering_threshold(); for (size_t i = 1; i <= 4; ++i) {
diff --git a/quic/core/congestion_control/uber_loss_algorithm.cc b/quic/core/congestion_control/uber_loss_algorithm.cc index 1aa10ff..4e7f07b 100644 --- a/quic/core/congestion_control/uber_loss_algorithm.cc +++ b/quic/core/congestion_control/uber_loss_algorithm.cc
@@ -93,4 +93,10 @@ } } +void UberLossAlgorithm::EnableAdaptiveTimeThreshold() { + for (int8_t i = INITIAL_DATA; i < NUM_PACKET_NUMBER_SPACES; ++i) { + general_loss_algorithms_[i].enable_adaptive_time_threshold(); + } +} + } // namespace quic
diff --git a/quic/core/congestion_control/uber_loss_algorithm.h b/quic/core/congestion_control/uber_loss_algorithm.h index a97fe08..f922bba 100644 --- a/quic/core/congestion_control/uber_loss_algorithm.h +++ b/quic/core/congestion_control/uber_loss_algorithm.h
@@ -54,6 +54,9 @@ // Enable adaptive reordering threshold of all packet number spaces. void EnableAdaptiveReorderingThreshold(); + // Enable adaptive time threshold of all packet number spaces. + void EnableAdaptiveTimeThreshold(); + private: friend class test::QuicSentPacketManagerPeer;
diff --git a/quic/core/crypto/crypto_protocol.h b/quic/core/crypto/crypto_protocol.h index 0aeb1f9..f09c595 100644 --- a/quic/core/crypto/crypto_protocol.h +++ b/quic/core/crypto/crypto_protocol.h
@@ -176,6 +176,11 @@ // with 1/4 RTT time threshold // and adaptive packet // threshold +const QuicTag kILD4 = TAG('I', 'L', 'D', '4'); // IETF style loss detection + // with both adaptive time + // threshold (default 1/4 RTT) + // and adaptive packet + // threshold // TODO(fayang): Remove this connection option when QUIC_VERSION_35, is removed // Since MAX_HEADER_LIST_SIZE settings frame is supported instead. const QuicTag kSMHL = TAG('S', 'M', 'H', 'L'); // Support MAX_HEADER_LIST_SIZE
diff --git a/quic/core/quic_sent_packet_manager.cc b/quic/core/quic_sent_packet_manager.cc index 5880ea9..f9ec1c0 100644 --- a/quic/core/quic_sent_packet_manager.cc +++ b/quic/core/quic_sent_packet_manager.cc
@@ -257,25 +257,32 @@ } if (GetQuicReloadableFlag(quic_enable_ietf_loss_detection)) { if (config.HasClientRequestedIndependentOption(kILD0, perspective)) { - QUIC_RELOADABLE_FLAG_COUNT_N(quic_enable_ietf_loss_detection, 1, 4); + QUIC_RELOADABLE_FLAG_COUNT_N(quic_enable_ietf_loss_detection, 1, 5); uber_loss_algorithm_.SetLossDetectionType(kIetfLossDetection); } if (config.HasClientRequestedIndependentOption(kILD1, perspective)) { - QUIC_RELOADABLE_FLAG_COUNT_N(quic_enable_ietf_loss_detection, 2, 4); + QUIC_RELOADABLE_FLAG_COUNT_N(quic_enable_ietf_loss_detection, 2, 5); uber_loss_algorithm_.SetLossDetectionType(kIetfLossDetection); uber_loss_algorithm_.SetReorderingShift(kDefaultLossDelayShift); } if (config.HasClientRequestedIndependentOption(kILD2, perspective)) { - QUIC_RELOADABLE_FLAG_COUNT_N(quic_enable_ietf_loss_detection, 3, 4); + QUIC_RELOADABLE_FLAG_COUNT_N(quic_enable_ietf_loss_detection, 3, 5); uber_loss_algorithm_.SetLossDetectionType(kIetfLossDetection); uber_loss_algorithm_.EnableAdaptiveReorderingThreshold(); } if (config.HasClientRequestedIndependentOption(kILD3, perspective)) { - QUIC_RELOADABLE_FLAG_COUNT_N(quic_enable_ietf_loss_detection, 4, 4); + QUIC_RELOADABLE_FLAG_COUNT_N(quic_enable_ietf_loss_detection, 4, 5); uber_loss_algorithm_.SetLossDetectionType(kIetfLossDetection); uber_loss_algorithm_.SetReorderingShift(kDefaultLossDelayShift); uber_loss_algorithm_.EnableAdaptiveReorderingThreshold(); } + if (config.HasClientRequestedIndependentOption(kILD4, perspective)) { + QUIC_RELOADABLE_FLAG_COUNT_N(quic_enable_ietf_loss_detection, 5, 5); + uber_loss_algorithm_.SetLossDetectionType(kIetfLossDetection); + uber_loss_algorithm_.SetReorderingShift(kDefaultLossDelayShift); + uber_loss_algorithm_.EnableAdaptiveReorderingThreshold(); + uber_loss_algorithm_.EnableAdaptiveTimeThreshold(); + } } if (config.HasClientSentConnectionOption(kCONH, perspective)) { conservative_handshake_retransmits_ = true;
diff --git a/quic/core/quic_sent_packet_manager_test.cc b/quic/core/quic_sent_packet_manager_test.cc index c9d70b9..b7ca395 100644 --- a/quic/core/quic_sent_packet_manager_test.cc +++ b/quic/core/quic_sent_packet_manager_test.cc
@@ -1851,6 +1851,35 @@ QuicSentPacketManagerPeer::AdaptiveReorderingThresholdEnabled(&manager_)); } +TEST_F(QuicSentPacketManagerTest, + NegotiateIetfLossDetectionAdaptiveReorderingAndTimeThreshold) { + SetQuicReloadableFlag(quic_enable_ietf_loss_detection, true); + EXPECT_EQ(kNack, QuicSentPacketManagerPeer::GetLossAlgorithm(&manager_) + ->GetLossDetectionType()); + EXPECT_FALSE( + QuicSentPacketManagerPeer::AdaptiveReorderingThresholdEnabled(&manager_)); + EXPECT_FALSE( + QuicSentPacketManagerPeer::AdaptiveTimeThresholdEnabled(&manager_)); + + QuicConfig config; + QuicTagVector options; + options.push_back(kILD4); + QuicConfigPeer::SetReceivedConnectionOptions(&config, options); + EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)); + EXPECT_CALL(*network_change_visitor_, OnCongestionChange()); + manager_.SetFromConfig(config); + + EXPECT_EQ(kIetfLossDetection, + QuicSentPacketManagerPeer::GetLossAlgorithm(&manager_) + ->GetLossDetectionType()); + EXPECT_EQ(kDefaultLossDelayShift, + QuicSentPacketManagerPeer::GetReorderingShift(&manager_)); + EXPECT_TRUE( + QuicSentPacketManagerPeer::AdaptiveReorderingThresholdEnabled(&manager_)); + EXPECT_TRUE( + QuicSentPacketManagerPeer::AdaptiveTimeThresholdEnabled(&manager_)); +} + TEST_F(QuicSentPacketManagerTest, NegotiateCongestionControlFromOptions) { QuicConfig config; QuicTagVector options;
diff --git a/quic/test_tools/quic_sent_packet_manager_peer.cc b/quic/test_tools/quic_sent_packet_manager_peer.cc index 7b3977e..cd8297a 100644 --- a/quic/test_tools/quic_sent_packet_manager_peer.cc +++ b/quic/test_tools/quic_sent_packet_manager_peer.cc
@@ -214,5 +214,12 @@ .use_adaptive_reordering_threshold(); } +// static +bool QuicSentPacketManagerPeer::AdaptiveTimeThresholdEnabled( + QuicSentPacketManager* sent_packet_manager) { + return sent_packet_manager->uber_loss_algorithm_.general_loss_algorithms_[0] + .use_adaptive_time_threshold(); +} + } // namespace test } // namespace quic
diff --git a/quic/test_tools/quic_sent_packet_manager_peer.h b/quic/test_tools/quic_sent_packet_manager_peer.h index 6be8b46..3927189 100644 --- a/quic/test_tools/quic_sent_packet_manager_peer.h +++ b/quic/test_tools/quic_sent_packet_manager_peer.h
@@ -98,6 +98,9 @@ static bool AdaptiveReorderingThresholdEnabled( QuicSentPacketManager* sent_packet_manager); + + static bool AdaptiveTimeThresholdEnabled( + QuicSentPacketManager* sent_packet_manager); }; } // namespace test