Always send the earliest ack in quicconnection::sendallpendingacks. protected by gfe2_reloadable_flag_quic_always_send_earliest_ack. PiperOrigin-RevId: 313445668 Change-Id: Ibb17ff261f40d9da52f5e5e043e496daac6829ea
diff --git a/quic/core/quic_connection.cc b/quic/core/quic_connection.cc index d39aa1e..36dea57 100644 --- a/quic/core/quic_connection.cc +++ b/quic/core/quic_connection.cc
@@ -4001,21 +4001,27 @@ DCHECK(SupportsMultiplePacketNumberSpaces()); QUIC_DVLOG(1) << ENDPOINT << "Trying to send all pending ACKs"; ack_alarm_->Cancel(); + const QuicTime earliest_ack_timeout = + uber_received_packet_manager_.GetEarliestAckTimeout(); + QUIC_BUG_IF(!earliest_ack_timeout.IsInitialized()); // Latches current encryption level. const EncryptionLevel current_encryption_level = encryption_level_; for (int8_t i = INITIAL_DATA; i <= APPLICATION_DATA; ++i) { const QuicTime ack_timeout = uber_received_packet_manager_.GetAckTimeout( static_cast<PacketNumberSpace>(i)); - if (!ack_timeout.IsInitialized() || - ack_timeout > clock_->ApproximateNow()) { + if (!ack_timeout.IsInitialized()) { continue; } - if (!framer_.HasEncrypterOfEncryptionLevel( - QuicUtils::GetEncryptionLevel(static_cast<PacketNumberSpace>(i)))) { - QUIC_BUG << ENDPOINT << "Cannot send ACKs for packet number space " - << PacketNumberSpaceToString(static_cast<PacketNumberSpace>(i)) - << " without corresponding encrypter"; - continue; + if (ack_timeout > clock_->ApproximateNow()) { + if (!GetQuicReloadableFlag(quic_always_send_earliest_ack)) { + continue; + } + QUIC_RELOADABLE_FLAG_COUNT(quic_always_send_earliest_ack); + if (ack_timeout > earliest_ack_timeout) { + // Always send the earliest ACK to make forward progress in case alarm + // fires early. + continue; + } } QUIC_DVLOG(1) << ENDPOINT << "Sending ACK of packet number space " << PacketNumberSpaceToString(
diff --git a/quic/core/quic_connection_test.cc b/quic/core/quic_connection_test.cc index 714db95..a9e25f0 100644 --- a/quic/core/quic_connection_test.cc +++ b/quic/core/quic_connection_test.cc
@@ -10715,6 +10715,52 @@ } } +TEST_P(QuicConnectionTest, AckAlarmFiresEarly) { + if (!connection_.SupportsMultiplePacketNumberSpaces()) { + return; + } + EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); + if (QuicVersionUsesCryptoFrames(connection_.transport_version())) { + EXPECT_CALL(visitor_, OnCryptoFrame(_)).Times(AnyNumber()); + } + EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AnyNumber()); + use_tagging_decrypter(); + // Receives packet 1000 in initial data. + ProcessCryptoPacketAtLevel(1000, ENCRYPTION_INITIAL); + EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); + + peer_framer_.SetEncrypter(ENCRYPTION_ZERO_RTT, + std::make_unique<TaggingEncrypter>(0x02)); + SetDecrypter(ENCRYPTION_ZERO_RTT, + std::make_unique<StrictTaggingDecrypter>(0x02)); + connection_.SetEncrypter(ENCRYPTION_INITIAL, + std::make_unique<TaggingEncrypter>(0x02)); + // Receives packet 1000 in application data. + ProcessDataPacketAtLevel(1000, false, ENCRYPTION_ZERO_RTT); + EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); + // Verify ACK deadline does not change. + EXPECT_EQ(clock_.ApproximateNow() + kAlarmGranularity, + connection_.GetAckAlarm()->deadline()); + + // Ack alarm fires early. + if (GetQuicReloadableFlag(quic_always_send_earliest_ack)) { + // Verify the earliest ACK is flushed. + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1); + } else { + EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0); + } + connection_.GetAckAlarm()->Fire(); + EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); + if (GetQuicReloadableFlag(quic_always_send_earliest_ack)) { + EXPECT_EQ(clock_.ApproximateNow() + DefaultDelayedAckTime(), + connection_.GetAckAlarm()->deadline()); + } else { + // No forward progress has been made. + EXPECT_EQ(clock_.ApproximateNow() + kAlarmGranularity, + connection_.GetAckAlarm()->deadline()); + } +} + } // namespace } // namespace test } // namespace quic