gfe-relnote: In QUIC, when RTO fires and there is no packet to be RTOed, let connection send data. Protected by gfe2_reloadable_flag_quic_fix_rto_retransmission2 which replaces gfe2_reloadable_flag_quic_fix_rto_retransmission.

This fix only applies for version > 39.

PiperOrigin-RevId: 262347120
Change-Id: Ic164c2f9e7117c3f9af43f1f1a3e8b369d8a3052
diff --git a/quic/core/quic_connection.cc b/quic/core/quic_connection.cc
index a577bf1..ce60171 100644
--- a/quic/core/quic_connection.cc
+++ b/quic/core/quic_connection.cc
@@ -2469,12 +2469,12 @@
 
   if (sent_packet_manager_.fix_rto_retransmission()) {
     // Making sure at least one packet is created when retransmission timer
-    // fires in TLP, RTO or HANDSHAKE mode. It is possible that loss algorithm
-    // invokes timer based loss but the packet does not need to be
-    // retransmitted.
-    QUIC_BUG_IF(stats_.loss_timeout_count == previous_loss_timeout_count &&
-                packet_generator_.packet_number() ==
-                    previous_created_packet_number)
+    // fires in TLP. It is possible that loss algorithm invokes timer based loss
+    // but the packet does not need to be retransmitted. And no packets will be
+    // sent if timer fires in HANDSHAKE or RTO mode but writer is blocked.
+    QUIC_BUG_IF(packet_generator_.packet_number() ==
+                    previous_created_packet_number &&
+                stats_.tlp_count != previous_tlp_count)
         << "previous_crypto_retransmit_count: "
         << previous_crypto_retransmit_count
         << ", crypto_retransmit_count: " << stats_.crypto_retransmit_count
@@ -2487,7 +2487,8 @@
         << ", previous_created_packet_number: "
         << previous_created_packet_number
         << ", packet_number: " << packet_generator_.packet_number()
-        << ", session has data to write: " << visitor_->WillingAndAbleToWrite();
+        << ", session has data to write: " << visitor_->WillingAndAbleToWrite()
+        << ", writer is blocked: " << writer_->IsWriteBlocked();
   }
 
   // Ensure the retransmission alarm is always set if there are unacked packets
diff --git a/quic/core/quic_connection_test.cc b/quic/core/quic_connection_test.cc
index 39d2760..26c70f1 100644
--- a/quic/core/quic_connection_test.cc
+++ b/quic/core/quic_connection_test.cc
@@ -4159,25 +4159,25 @@
   // Simulate the retransmission alarm firing.
   clock_.AdvanceTime(DefaultRetransmissionTime());
   // RTO fires, but there is no packet to be RTOed.
-  if (GetQuicReloadableFlag(quic_fix_rto_retransmission)) {
+  if (GetQuicReloadableFlag(quic_fix_rto_retransmission2)) {
     EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
   } else {
     EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0);
   }
   connection_.GetRetransmissionAlarm()->Fire();
-  if (GetQuicReloadableFlag(quic_fix_rto_retransmission)) {
+  if (GetQuicReloadableFlag(quic_fix_rto_retransmission2)) {
     EXPECT_EQ(1u, writer_->rst_stream_frames().size());
   }
 
   EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(40);
   EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(20);
-  if (GetQuicReloadableFlag(quic_fix_rto_retransmission)) {
+  if (GetQuicReloadableFlag(quic_fix_rto_retransmission2)) {
     EXPECT_CALL(visitor_, WillingAndAbleToWrite())
         .WillRepeatedly(Return(false));
   } else {
     EXPECT_CALL(visitor_, WillingAndAbleToWrite()).WillRepeatedly(Return(true));
   }
-  if (GetQuicReloadableFlag(quic_fix_rto_retransmission)) {
+  if (GetQuicReloadableFlag(quic_fix_rto_retransmission2)) {
     EXPECT_CALL(visitor_, OnAckNeedsRetransmittableFrame()).Times(1);
   } else {
     // Since there is a buffered RST_STREAM, no retransmittable frame is bundled
@@ -8685,6 +8685,62 @@
   EXPECT_TRUE(connection_.connected());
 }
 
+// Regresstion test for b/138962304.
+TEST_P(QuicConnectionTest, RtoAndWriteBlocked) {
+  if (!QuicConnectionPeer::GetSentPacketManager(&connection_)
+           ->fix_rto_retransmission()) {
+    return;
+  }
+  EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet());
+
+  QuicStreamId stream_id = 2;
+  QuicPacketNumber last_data_packet;
+  SendStreamDataToPeer(stream_id, "foo", 0, NO_FIN, &last_data_packet);
+  EXPECT_TRUE(connection_.GetRetransmissionAlarm()->IsSet());
+
+  // Writer gets blocked.
+  writer_->SetWriteBlocked();
+
+  // Cancel the stream.
+  EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0);
+  EXPECT_CALL(visitor_, OnWriteBlocked()).Times(AtLeast(1));
+  SendRstStream(stream_id, QUIC_ERROR_PROCESSING_STREAM, 3);
+
+  // Retransmission timer fires in RTO mode.
+  connection_.GetRetransmissionAlarm()->Fire();
+  // Verify no packets get flushed when writer is blocked.
+  EXPECT_EQ(0u, connection_.NumQueuedPackets());
+}
+
+// Regresstion test for b/138962304.
+TEST_P(QuicConnectionTest, TlpAndWriteBlocked) {
+  if (!QuicConnectionPeer::GetSentPacketManager(&connection_)
+           ->fix_rto_retransmission()) {
+    return;
+  }
+  EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet());
+  connection_.SetMaxTailLossProbes(1);
+
+  QuicStreamId stream_id = 2;
+  QuicPacketNumber last_data_packet;
+  SendStreamDataToPeer(stream_id, "foo", 0, NO_FIN, &last_data_packet);
+  SendStreamDataToPeer(4, "foo", 0, NO_FIN, &last_data_packet);
+  EXPECT_TRUE(connection_.GetRetransmissionAlarm()->IsSet());
+
+  // Writer gets blocked.
+  writer_->SetWriteBlocked();
+
+  // Cancel stream 2.
+  EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0);
+  EXPECT_CALL(visitor_, OnWriteBlocked()).Times(AtLeast(1));
+  SendRstStream(stream_id, QUIC_ERROR_PROCESSING_STREAM, 3);
+
+  // Retransmission timer fires in TLP mode.
+  connection_.GetRetransmissionAlarm()->Fire();
+  // Verify one packets is forced flushed when writer is blocked.
+  EXPECT_EQ(1u, connection_.NumQueuedPackets());
+}
+
 }  // namespace
 }  // namespace test
 }  // namespace quic
diff --git a/quic/core/quic_sent_packet_manager.cc b/quic/core/quic_sent_packet_manager.cc
index 0542edb..43f530e 100644
--- a/quic/core/quic_sent_packet_manager.cc
+++ b/quic/core/quic_sent_packet_manager.cc
@@ -119,14 +119,10 @@
           GetQuicReloadableFlag(quic_loss_removes_from_inflight)),
       ignore_tlpr_if_no_pending_stream_data_(
           GetQuicReloadableFlag(quic_ignore_tlpr_if_no_pending_stream_data)),
-      fix_rto_retransmission_(
-          GetQuicReloadableFlag(quic_fix_rto_retransmission)) {
+      fix_rto_retransmission_(false) {
   if (loss_removes_from_inflight_) {
     QUIC_RELOADABLE_FLAG_COUNT(quic_loss_removes_from_inflight);
   }
-  if (fix_rto_retransmission_) {
-    QUIC_RELOADABLE_FLAG_COUNT(quic_fix_rto_retransmission);
-  }
   SetSendAlgorithm(congestion_control_type);
 }
 
@@ -1287,6 +1283,16 @@
   rtt_stats_.set_initial_rtt(std::max(min_rtt, std::min(max_rtt, rtt)));
 }
 
+void QuicSentPacketManager::SetSessionDecideWhatToWrite(
+    bool session_decides_what_to_write) {
+  if (GetQuicReloadableFlag(quic_fix_rto_retransmission2) &&
+      session_decides_what_to_write) {
+    fix_rto_retransmission_ = true;
+    QUIC_RELOADABLE_FLAG_COUNT(quic_fix_rto_retransmission2);
+  }
+  unacked_packets_.SetSessionDecideWhatToWrite(session_decides_what_to_write);
+}
+
 void QuicSentPacketManager::EnableMultiplePacketNumberSpacesSupport() {
   unacked_packets_.EnableMultiplePacketNumberSpacesSupport();
 }
diff --git a/quic/core/quic_sent_packet_manager.h b/quic/core/quic_sent_packet_manager.h
index 010181c..98eb33e 100644
--- a/quic/core/quic_sent_packet_manager.h
+++ b/quic/core/quic_sent_packet_manager.h
@@ -283,9 +283,7 @@
                           EncryptionLevel ack_decrypted_level);
 
   // Called to enable/disable letting session decide what to write.
-  void SetSessionDecideWhatToWrite(bool session_decides_what_to_write) {
-    unacked_packets_.SetSessionDecideWhatToWrite(session_decides_what_to_write);
-  }
+  void SetSessionDecideWhatToWrite(bool session_decides_what_to_write);
 
   void EnableMultiplePacketNumberSpacesSupport();
 
@@ -630,8 +628,9 @@
   // Latched value of quic_ignore_tlpr_if_no_pending_stream_data.
   const bool ignore_tlpr_if_no_pending_stream_data_;
 
-  // Latched value of quic_fix_rto_retransmission.
-  const bool fix_rto_retransmission_;
+  // Latched value of quic_fix_rto_retransmission2 and
+  // session_decides_what_to_write.
+  bool fix_rto_retransmission_;
 };
 
 }  // namespace quic
diff --git a/quic/core/quic_sent_packet_manager_test.cc b/quic/core/quic_sent_packet_manager_test.cc
index fe34851..e1ab409 100644
--- a/quic/core/quic_sent_packet_manager_test.cc
+++ b/quic/core/quic_sent_packet_manager_test.cc
@@ -2972,7 +2972,7 @@
   EXPECT_CALL(notifier_, RetransmitFrames(_, _)).Times(0);
   manager_.OnRetransmissionTimeout();
   EXPECT_EQ(2u, stats_.rto_count);
-  if (GetQuicReloadableFlag(quic_fix_rto_retransmission)) {
+  if (GetQuicReloadableFlag(quic_fix_rto_retransmission2)) {
     // Verify a credit is raised up.
     EXPECT_EQ(1u, manager_.pending_timer_transmission_count());
   } else {