gfe-relnote: (n/a) When QUIC switches from BbrSender to Bbr2Sender, let Bbr2Sender copy the bandwidth sampler states from BbrSender. Protected by --gfe2_reloadable_flag_quic_bbr_copy_sampler_state_from_v1_to_v2. PiperOrigin-RevId: 303846658 Change-Id: I37d88015801392608d87140213d01db02d01209f
diff --git a/quic/core/congestion_control/bandwidth_sampler.cc b/quic/core/congestion_control/bandwidth_sampler.cc index c78c6b7..c929e8b 100644 --- a/quic/core/congestion_control/bandwidth_sampler.cc +++ b/quic/core/congestion_control/bandwidth_sampler.cc
@@ -95,6 +95,29 @@ total_bytes_acked_after_last_ack_event_(0), overestimate_avoidance_(false) {} +BandwidthSampler::BandwidthSampler(const BandwidthSampler& other) + : total_bytes_sent_(other.total_bytes_sent_), + total_bytes_acked_(other.total_bytes_acked_), + total_bytes_lost_(other.total_bytes_lost_), + total_bytes_neutered_(other.total_bytes_neutered_), + total_bytes_sent_at_last_acked_packet_( + other.total_bytes_sent_at_last_acked_packet_), + last_acked_packet_sent_time_(other.last_acked_packet_sent_time_), + last_acked_packet_ack_time_(other.last_acked_packet_ack_time_), + last_sent_packet_(other.last_sent_packet_), + started_as_app_limited_(other.started_as_app_limited_), + is_app_limited_(other.is_app_limited_), + end_of_app_limited_phase_(other.end_of_app_limited_phase_), + connection_state_map_(other.connection_state_map_), + recent_ack_points_(other.recent_ack_points_), + a0_candidates_(other.a0_candidates_), + max_tracked_packets_(other.max_tracked_packets_), + unacked_packet_map_(other.unacked_packet_map_), + max_ack_height_tracker_(other.max_ack_height_tracker_), + total_bytes_acked_after_last_ack_event_( + other.total_bytes_acked_after_last_ack_event_), + overestimate_avoidance_(other.overestimate_avoidance_) {} + void BandwidthSampler::EnableOverestimateAvoidance() { if (overestimate_avoidance_) { return;
diff --git a/quic/core/congestion_control/bandwidth_sampler.h b/quic/core/congestion_control/bandwidth_sampler.h index 2f00d62..b3c0736 100644 --- a/quic/core/congestion_control/bandwidth_sampler.h +++ b/quic/core/congestion_control/bandwidth_sampler.h
@@ -304,6 +304,10 @@ public: BandwidthSampler(const QuicUnackedPacketMap* unacked_packet_map, QuicRoundTripCount max_height_tracker_window_length); + + // Copy states from |other|. This is useful when changing send algorithms in + // the middle of a connection. + BandwidthSampler(const BandwidthSampler& other); ~BandwidthSampler() override; void OnPacketSent(QuicTime sent_time,
diff --git a/quic/core/congestion_control/bbr2_misc.cc b/quic/core/congestion_control/bbr2_misc.cc index 626540a..5a30467 100644 --- a/quic/core/congestion_control/bbr2_misc.cc +++ b/quic/core/congestion_control/bbr2_misc.cc
@@ -55,9 +55,19 @@ QuicTime::Delta initial_rtt, QuicTime initial_rtt_timestamp, float cwnd_gain, - float pacing_gain) + float pacing_gain, + const BandwidthSampler* old_sampler) : params_(params), - bandwidth_sampler_(nullptr, params->initial_max_ack_height_filter_window), + bandwidth_sampler_([](QuicRoundTripCount max_height_tracker_window_length, + const BandwidthSampler* old_sampler) { + if (GetQuicReloadableFlag(quic_bbr_copy_sampler_state_from_v1_to_v2) && + old_sampler != nullptr) { + QUIC_RELOADABLE_FLAG_COUNT(quic_bbr_copy_sampler_state_from_v1_to_v2); + return BandwidthSampler(*old_sampler); + } + return BandwidthSampler(/*unacked_packet_map=*/nullptr, + max_height_tracker_window_length); + }(params->initial_max_ack_height_filter_window, old_sampler)), min_rtt_filter_(initial_rtt, initial_rtt_timestamp), cwnd_gain_(cwnd_gain), pacing_gain_(pacing_gain) {}
diff --git a/quic/core/congestion_control/bbr2_misc.h b/quic/core/congestion_control/bbr2_misc.h index b8ba702..63a11e1 100644 --- a/quic/core/congestion_control/bbr2_misc.h +++ b/quic/core/congestion_control/bbr2_misc.h
@@ -299,7 +299,8 @@ QuicTime::Delta initial_rtt, QuicTime initial_rtt_timestamp, float cwnd_gain, - float pacing_gain); + float pacing_gain, + const BandwidthSampler* old_sampler); void OnPacketSent(QuicTime sent_time, QuicByteCount bytes_in_flight,
diff --git a/quic/core/congestion_control/bbr2_sender.cc b/quic/core/congestion_control/bbr2_sender.cc index c975aec..4d79443 100644 --- a/quic/core/congestion_control/bbr2_sender.cc +++ b/quic/core/congestion_control/bbr2_sender.cc
@@ -58,7 +58,8 @@ QuicPacketCount initial_cwnd_in_packets, QuicPacketCount max_cwnd_in_packets, QuicRandom* random, - QuicConnectionStats* stats) + QuicConnectionStats* stats, + BbrSender* old_sender) : mode_(Bbr2Mode::STARTUP), rtt_stats_(rtt_stats), unacked_packets_(unacked_packets), @@ -70,7 +71,8 @@ rtt_stats->SmoothedOrInitialRtt(), rtt_stats->last_update_time(), /*cwnd_gain=*/1.0, - /*pacing_gain=*/kInitialPacingGain), + /*pacing_gain=*/kInitialPacingGain, + old_sender ? &old_sender->sampler_ : nullptr), initial_cwnd_( cwnd_limits().ApplyLimits(initial_cwnd_in_packets * kDefaultTCPMSS)), cwnd_(initial_cwnd_),
diff --git a/quic/core/congestion_control/bbr2_sender.h b/quic/core/congestion_control/bbr2_sender.h index f865e27..d68a6a1 100644 --- a/quic/core/congestion_control/bbr2_sender.h +++ b/quic/core/congestion_control/bbr2_sender.h
@@ -13,6 +13,7 @@ #include "net/third_party/quiche/src/quic/core/congestion_control/bbr2_probe_bw.h" #include "net/third_party/quiche/src/quic/core/congestion_control/bbr2_probe_rtt.h" #include "net/third_party/quiche/src/quic/core/congestion_control/bbr2_startup.h" +#include "net/third_party/quiche/src/quic/core/congestion_control/bbr_sender.h" #include "net/third_party/quiche/src/quic/core/congestion_control/rtt_stats.h" #include "net/third_party/quiche/src/quic/core/congestion_control/send_algorithm_interface.h" #include "net/third_party/quiche/src/quic/core/congestion_control/windowed_filter.h" @@ -31,7 +32,8 @@ QuicPacketCount initial_cwnd_in_packets, QuicPacketCount max_cwnd_in_packets, QuicRandom* random, - QuicConnectionStats* stats); + QuicConnectionStats* stats, + BbrSender* old_sender); ~Bbr2Sender() override = default;
diff --git a/quic/core/congestion_control/bbr2_simulator_test.cc b/quic/core/congestion_control/bbr2_simulator_test.cc index 6f3829c..949b283 100644 --- a/quic/core/congestion_control/bbr2_simulator_test.cc +++ b/quic/core/congestion_control/bbr2_simulator_test.cc
@@ -172,7 +172,7 @@ "Sender", Perspective::IS_SERVER, TestConnectionId(42)) { - sender_ = SetupBbr2Sender(&sender_endpoint_); + sender_ = SetupBbr2Sender(&sender_endpoint_, /*old_sender=*/nullptr); } ~Bbr2DefaultTopologyTest() { @@ -192,14 +192,15 @@ QuicConnectionPeer::GetSentPacketManager(connection)); } - Bbr2Sender* SetupBbr2Sender(simulator::QuicEndpoint* endpoint) { + Bbr2Sender* SetupBbr2Sender(simulator::QuicEndpoint* endpoint, + BbrSender* old_sender) { // Ownership of the sender will be overtaken by the endpoint. Bbr2Sender* sender = new Bbr2Sender( endpoint->connection()->clock()->Now(), endpoint->connection()->sent_packet_manager().GetRttStats(), GetUnackedMap(endpoint->connection()), kDefaultInitialCwndPackets, GetQuicFlag(FLAGS_quic_max_congestion_window), &random_, - QuicConnectionPeer::GetStats(endpoint->connection())); + QuicConnectionPeer::GetStats(endpoint->connection()), old_sender); QuicConnectionPeer::SetSendAlgorithm(endpoint->connection(), sender); endpoint->RecordTrace(); return sender; @@ -936,6 +937,90 @@ } } +// Regression test for http://shortn/_Jt1QWtshAM. +TEST_F(Bbr2DefaultTopologyTest, SwitchToBbr2MidConnection) { + if (!GetQuicReloadableFlag(quic_bbr_copy_sampler_state_from_v1_to_v2)) { + return; + } + QuicTime now = QuicTime::Zero(); + BbrSender old_sender(sender_connection()->clock()->Now(), + sender_connection()->sent_packet_manager().GetRttStats(), + GetUnackedMap(sender_connection()), + kDefaultInitialCwndPackets, + GetQuicFlag(FLAGS_quic_max_congestion_window), &random_, + QuicConnectionPeer::GetStats(sender_connection())); + + QuicPacketNumber next_packet_number(1); + + // Send packets 1-4. + while (next_packet_number < QuicPacketNumber(5)) { + now = now + QuicTime::Delta::FromMilliseconds(10); + + old_sender.OnPacketSent(now, /*bytes_in_flight=*/0, next_packet_number++, + /*bytes=*/1350, HAS_RETRANSMITTABLE_DATA); + } + + // Switch from |old_sender| to |sender_|. + sender_ = SetupBbr2Sender(&sender_endpoint_, &old_sender); + + // Send packets 5-7. + now = now + QuicTime::Delta::FromMilliseconds(10); + sender_->OnPacketSent(now, /*bytes_in_flight=*/1350, next_packet_number++, + /*bytes=*/23, NO_RETRANSMITTABLE_DATA); + + now = now + QuicTime::Delta::FromMilliseconds(10); + sender_->OnPacketSent(now, /*bytes_in_flight=*/1350, next_packet_number++, + /*bytes=*/767, HAS_RETRANSMITTABLE_DATA); + + QuicByteCount bytes_in_flight = 767; + while (next_packet_number < QuicPacketNumber(30)) { + now = now + QuicTime::Delta::FromMilliseconds(10); + bytes_in_flight += 1350; + sender_->OnPacketSent(now, bytes_in_flight, next_packet_number++, + /*bytes=*/1350, HAS_RETRANSMITTABLE_DATA); + } + + // Ack 1 & 2. + AckedPacketVector acked = { + AckedPacket(QuicPacketNumber(1), /*bytes_acked=*/0, QuicTime::Zero()), + AckedPacket(QuicPacketNumber(2), /*bytes_acked=*/0, QuicTime::Zero()), + }; + now = now + QuicTime::Delta::FromMilliseconds(2000); + sender_->OnCongestionEvent(true, bytes_in_flight, now, acked, {}); + + // Send 30-41. + while (next_packet_number < QuicPacketNumber(42)) { + now = now + QuicTime::Delta::FromMilliseconds(10); + bytes_in_flight += 1350; + sender_->OnPacketSent(now, bytes_in_flight, next_packet_number++, + /*bytes=*/1350, HAS_RETRANSMITTABLE_DATA); + } + + // Ack 3. + acked = { + AckedPacket(QuicPacketNumber(3), /*bytes_acked=*/0, QuicTime::Zero()), + }; + now = now + QuicTime::Delta::FromMilliseconds(2000); + sender_->OnCongestionEvent(true, bytes_in_flight, now, acked, {}); + + // Send 42. + now = now + QuicTime::Delta::FromMilliseconds(10); + bytes_in_flight += 1350; + sender_->OnPacketSent(now, bytes_in_flight, next_packet_number++, + /*bytes=*/1350, HAS_RETRANSMITTABLE_DATA); + + // Ack 4-7. + acked = { + AckedPacket(QuicPacketNumber(4), /*bytes_acked=*/0, QuicTime::Zero()), + AckedPacket(QuicPacketNumber(5), /*bytes_acked=*/0, QuicTime::Zero()), + AckedPacket(QuicPacketNumber(6), /*bytes_acked=*/767, QuicTime::Zero()), + AckedPacket(QuicPacketNumber(7), /*bytes_acked=*/1350, QuicTime::Zero()), + }; + now = now + QuicTime::Delta::FromMilliseconds(2000); + sender_->OnCongestionEvent(true, bytes_in_flight, now, acked, {}); + EXPECT_FALSE(sender_->BandwidthEstimate().IsZero()); +} + // All Bbr2MultiSenderTests uses the following network topology: // // Sender 0 (A Bbr2Sender) @@ -1049,7 +1134,7 @@ QuicConnectionPeer::GetSentPacketManager(endpoint->connection())), kDefaultInitialCwndPackets, GetQuicFlag(FLAGS_quic_max_congestion_window), &random_, - QuicConnectionPeer::GetStats(endpoint->connection())); + QuicConnectionPeer::GetStats(endpoint->connection()), nullptr); QuicConnectionPeer::SetSendAlgorithm(endpoint->connection(), sender); endpoint->RecordTrace(); return sender;
diff --git a/quic/core/congestion_control/bbr_sender.h b/quic/core/congestion_control/bbr_sender.h index 4b42600..7aa4f69 100644 --- a/quic/core/congestion_control/bbr_sender.h +++ b/quic/core/congestion_control/bbr_sender.h
@@ -171,6 +171,9 @@ DebugState ExportDebugState() const; private: + // For switching send algorithm mid connection. + friend class Bbr2Sender; + typedef WindowedFilter<QuicBandwidth, MaxFilter<QuicBandwidth>, QuicRoundTripCount,
diff --git a/quic/core/congestion_control/send_algorithm_interface.cc b/quic/core/congestion_control/send_algorithm_interface.cc index 26c0976..d7b2eca 100644 --- a/quic/core/congestion_control/send_algorithm_interface.cc +++ b/quic/core/congestion_control/send_algorithm_interface.cc
@@ -26,7 +26,8 @@ CongestionControlType congestion_control_type, QuicRandom* random, QuicConnectionStats* stats, - QuicPacketCount initial_congestion_window) { + QuicPacketCount initial_congestion_window, + SendAlgorithmInterface* old_send_algorithm) { QuicPacketCount max_congestion_window = GetQuicFlag(FLAGS_quic_max_congestion_window); switch (congestion_control_type) { @@ -36,9 +37,13 @@ initial_congestion_window, max_congestion_window, random, stats); case kBBRv2: - return new Bbr2Sender(clock->ApproximateNow(), rtt_stats, unacked_packets, - initial_congestion_window, max_congestion_window, - random, stats); + return new Bbr2Sender( + clock->ApproximateNow(), rtt_stats, unacked_packets, + initial_congestion_window, max_congestion_window, random, stats, + old_send_algorithm && + old_send_algorithm->GetCongestionControlType() == kBBR + ? static_cast<BbrSender*>(old_send_algorithm) + : nullptr); case kPCC: if (GetQuicReloadableFlag(quic_enable_pcc3)) { return CreatePccSender(clock, rtt_stats, unacked_packets, random, stats,
diff --git a/quic/core/congestion_control/send_algorithm_interface.h b/quic/core/congestion_control/send_algorithm_interface.h index b242951..2bfc2df 100644 --- a/quic/core/congestion_control/send_algorithm_interface.h +++ b/quic/core/congestion_control/send_algorithm_interface.h
@@ -78,7 +78,8 @@ CongestionControlType type, QuicRandom* random, QuicConnectionStats* stats, - QuicPacketCount initial_congestion_window); + QuicPacketCount initial_congestion_window, + SendAlgorithmInterface* old_send_algorithm); virtual ~SendAlgorithmInterface() {}
diff --git a/quic/core/congestion_control/send_algorithm_test.cc b/quic/core/congestion_control/send_algorithm_test.cc index 150ac1a..9937cf8 100644 --- a/quic/core/congestion_control/send_algorithm_test.cc +++ b/quic/core/congestion_control/send_algorithm_test.cc
@@ -171,7 +171,7 @@ QuicConnectionPeer::GetSentPacketManager( quic_sender_.connection())), GetParam().congestion_control_type, &random_, &stats_, - kInitialCongestionWindowPackets); + kInitialCongestionWindowPackets, nullptr); quic_sender_.RecordTrace(); QuicConnectionPeer::SetSendAlgorithm(quic_sender_.connection(), sender_);
diff --git a/quic/core/congestion_control/tcp_cubic_sender_bytes_test.cc b/quic/core/congestion_control/tcp_cubic_sender_bytes_test.cc index 04c0e8a..13a253b 100644 --- a/quic/core/congestion_control/tcp_cubic_sender_bytes_test.cc +++ b/quic/core/congestion_control/tcp_cubic_sender_bytes_test.cc
@@ -786,7 +786,7 @@ QuicConnectionStats stats; std::unique_ptr<SendAlgorithmInterface> sender(SendAlgorithmInterface::Create( &clock_, &rtt_stats, /*unacked_packets=*/nullptr, kCubicBytes, - QuicRandom::GetInstance(), &stats, kInitialCongestionWindow)); + QuicRandom::GetInstance(), &stats, kInitialCongestionWindow, nullptr)); AckedPacketVector acked_packets; LostPacketVector missing_packets;
diff --git a/quic/core/quic_sent_packet_manager.cc b/quic/core/quic_sent_packet_manager.cc index aeec09c..0de1dad 100644 --- a/quic/core/quic_sent_packet_manager.cc +++ b/quic/core/quic_sent_packet_manager.cc
@@ -1237,7 +1237,7 @@ SetSendAlgorithm(SendAlgorithmInterface::Create( clock_, &rtt_stats_, &unacked_packets_, congestion_control_type, random_, - stats_, initial_congestion_window_)); + stats_, initial_congestion_window_, send_algorithm_.get())); } void QuicSentPacketManager::SetSendAlgorithm(