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(