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();