gfe-relnote: In QUIC bbr sender, fix calculation of bytes_lost when gfe2_reloadable_flag_quic_one_bw_sample_per_ack_event is on. Protected by v2 flag gfe2_reloadable_flag_quic_one_bw_sample_per_ack_event2. Also added a unit test to ensure bytes_lost is used to update recover window. PiperOrigin-RevId: 289101409 Change-Id: I17ff916303af25a3967fb0559bbc50ec4ace4122
diff --git a/quic/core/congestion_control/bandwidth_sampler.cc b/quic/core/congestion_control/bandwidth_sampler.cc index 21705a5..d4eeabe 100644 --- a/quic/core/congestion_control/bandwidth_sampler.cc +++ b/quic/core/congestion_control/bandwidth_sampler.cc
@@ -87,7 +87,7 @@ quic_bw_sampler_remove_packets_once_per_congestion_event2); } if (one_bw_sample_per_ack_event_) { - QUIC_RELOADABLE_FLAG_COUNT(quic_one_bw_sample_per_ack_event); + QUIC_RELOADABLE_FLAG_COUNT(quic_one_bw_sample_per_ack_event2); } }
diff --git a/quic/core/congestion_control/bandwidth_sampler.h b/quic/core/congestion_control/bandwidth_sampler.h index d93af36..df63fa5 100644 --- a/quic/core/congestion_control/bandwidth_sampler.h +++ b/quic/core/congestion_control/bandwidth_sampler.h
@@ -481,10 +481,10 @@ quic_bw_sampler_remove_packets_once_per_congestion_event2); // Latched value of quic_bw_sampler_remove_packets_once_per_congestion_event2 - // and quic_one_bw_sample_per_ack_event. + // and quic_one_bw_sample_per_ack_event2. const bool one_bw_sample_per_ack_event_ = remove_packets_once_per_congestion_event_ && - GetQuicReloadableFlag(quic_one_bw_sample_per_ack_event); + GetQuicReloadableFlag(quic_one_bw_sample_per_ack_event2); }; } // namespace quic
diff --git a/quic/core/congestion_control/bbr_sender.cc b/quic/core/congestion_control/bbr_sender.cc index f8d22db..f80d4ce 100644 --- a/quic/core/congestion_control/bbr_sender.cc +++ b/quic/core/congestion_control/bbr_sender.cc
@@ -443,8 +443,8 @@ if (!sample.sample_rtt.IsInfinite()) { min_rtt_expired = MaybeUpdateMinRtt(event_time, sample.sample_rtt); } + bytes_lost = sampler_.total_bytes_lost() - total_bytes_lost_before; if (mode_ == STARTUP) { - bytes_lost = sampler_.total_bytes_lost() - total_bytes_lost_before; if (stats_) { stats_->slowstart_packets_lost += lost_packets.size(); stats_->slowstart_bytes_lost += bytes_lost;
diff --git a/quic/core/congestion_control/bbr_sender_test.cc b/quic/core/congestion_control/bbr_sender_test.cc index ddb1077..2ff1f8a 100644 --- a/quic/core/congestion_control/bbr_sender_test.cc +++ b/quic/core/congestion_control/bbr_sender_test.cc
@@ -11,6 +11,7 @@ #include "net/third_party/quiche/src/quic/core/congestion_control/rtt_stats.h" #include "net/third_party/quiche/src/quic/core/quic_packets.h" +#include "net/third_party/quiche/src/quic/core/quic_types.h" #include "net/third_party/quiche/src/quic/core/quic_utils.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" @@ -377,6 +378,54 @@ EXPECT_FALSE(sender_->ExportDebugState().last_sample_is_app_limited); } +TEST_F(BbrSenderTest, RemoveBytesLostInRecovery) { + SetQuicReloadableFlag(quic_bbr_one_mss_conservation, false); + // Disable Ack Decimation on the receiver, because it can increase srtt. + QuicConnectionPeer::SetAckMode(receiver_.connection(), AckMode::TCP_ACKING); + CreateDefaultSetup(); + + DriveOutOfStartup(); + + // Drop a packet to enter recovery. + receiver_.DropNextIncomingPacket(); + ASSERT_TRUE( + simulator_.RunUntilOrTimeout([this]() { return sender_->InRecovery(); }, + QuicTime::Delta::FromSeconds(30))); + + QuicUnackedPacketMap* unacked_packets = + QuicSentPacketManagerPeer::GetUnackedPacketMap( + QuicConnectionPeer::GetSentPacketManager(bbr_sender_.connection())); + QuicPacketNumber largest_sent = + bbr_sender_.connection()->sent_packet_manager().GetLargestSentPacket(); + // least_inflight is the smallest inflight packet. + QuicPacketNumber least_inflight = + bbr_sender_.connection()->sent_packet_manager().GetLeastUnacked(); + while (!unacked_packets->GetTransmissionInfo(least_inflight).in_flight) { + ASSERT_LE(least_inflight, largest_sent); + least_inflight++; + } + QuicPacketLength least_inflight_packet_size = + unacked_packets->GetTransmissionInfo(least_inflight).bytes_sent; + QuicByteCount prior_recovery_window = + sender_->ExportDebugState().recovery_window; + QuicByteCount prior_inflight = unacked_packets->bytes_in_flight(); + QUIC_LOG(INFO) << "Recovery window:" << prior_recovery_window + << ", least_inflight_packet_size:" + << least_inflight_packet_size + << ", bytes_in_flight:" << prior_inflight; + ASSERT_GT(prior_recovery_window, least_inflight_packet_size); + + // Lose the least inflight packet and expect the recovery window to drop. + unacked_packets->RemoveFromInFlight(least_inflight); + LostPacketVector lost_packets; + lost_packets.emplace_back(least_inflight, least_inflight_packet_size); + sender_->OnCongestionEvent(false, prior_inflight, clock_->Now(), {}, + lost_packets); + EXPECT_EQ(sender_->ExportDebugState().recovery_window, + prior_inflight - least_inflight_packet_size); + EXPECT_LT(sender_->ExportDebugState().recovery_window, prior_recovery_window); +} + // Test a simple long data transfer with 2 rtts of aggregation. TEST_F(BbrSenderTest, SimpleTransfer2RTTAggregationBytes) { CreateDefaultSetup();