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;