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(