Let lossdetectioninterface::detectlosses to return a detectionstats which includes the max sequence reordering observed from acked packets. protected by existing flag --gfe2_reloadable_flag_quic_enable_loss_detection_experiment_at_gfe.
The previous change, cl/309076773, used number of reordered _incoming_ packets to decide whether to send feedback to reordering_threshold_session. This CL changed it to use maximum reordering from _acked_ packets instead.
PiperOrigin-RevId: 311210547
Change-Id: I1e1d4d5f842ee7036f23c3832ee3ece8ab38a497
diff --git a/quic/core/congestion_control/general_loss_algorithm.cc b/quic/core/congestion_control/general_loss_algorithm.cc
index 1e67db6..f00045e 100644
--- a/quic/core/congestion_control/general_loss_algorithm.cc
+++ b/quic/core/congestion_control/general_loss_algorithm.cc
@@ -23,13 +23,15 @@
packet_number_space_(NUM_PACKET_NUMBER_SPACES) {}
// Uses nack counts to decide when packets are lost.
-void GeneralLossAlgorithm::DetectLosses(
+LossDetectionInterface::DetectionStats GeneralLossAlgorithm::DetectLosses(
const QuicUnackedPacketMap& unacked_packets,
QuicTime time,
const RttStats& rtt_stats,
QuicPacketNumber largest_newly_acked,
const AckedPacketVector& packets_acked,
LostPacketVector* packets_lost) {
+ DetectionStats detection_stats;
+
loss_detection_timeout_ = QuicTime::Zero();
if (!packets_acked.empty() && least_in_flight_.IsInitialized() &&
packets_acked.front().packet_number == least_in_flight_) {
@@ -40,7 +42,7 @@
// do not use this optimization if largest_newly_acked is not the largest
// packet in packets_acked.
least_in_flight_ = largest_newly_acked + 1;
- return;
+ return detection_stats;
}
// There is hole in acked_packets, increment least_in_flight_ if possible.
for (const auto& acked : packets_acked) {
@@ -50,6 +52,7 @@
++least_in_flight_;
}
}
+
QuicTime::Delta max_rtt =
std::max(rtt_stats.previous_srtt(), rtt_stats.latest_rtt());
max_rtt = std::max(kAlarmGranularity, max_rtt);
@@ -77,9 +80,17 @@
// Skip packets of different packet number space.
continue;
}
+
if (!it->in_flight) {
continue;
}
+
+ if (largest_newly_acked - packet_number >
+ detection_stats.sent_packets_max_sequence_reordering) {
+ detection_stats.sent_packets_max_sequence_reordering =
+ largest_newly_acked - packet_number;
+ }
+
// Packet threshold loss detection.
// Skip packet threshold loss detection if largest_newly_acked is a runt.
const bool skip_packet_threshold_detection =
@@ -108,6 +119,8 @@
// There is no in flight packet.
least_in_flight_ = largest_newly_acked + 1;
}
+
+ return detection_stats;
}
QuicTime GeneralLossAlgorithm::GetLossTimeout() const {
diff --git a/quic/core/congestion_control/general_loss_algorithm.h b/quic/core/congestion_control/general_loss_algorithm.h
index b9e5d8e..ee8ba64 100644
--- a/quic/core/congestion_control/general_loss_algorithm.h
+++ b/quic/core/congestion_control/general_loss_algorithm.h
@@ -31,12 +31,12 @@
Perspective /*perspective*/) override {}
// Uses |largest_acked| and time to decide when packets are lost.
- void DetectLosses(const QuicUnackedPacketMap& unacked_packets,
- QuicTime time,
- const RttStats& rtt_stats,
- QuicPacketNumber largest_newly_acked,
- const AckedPacketVector& packets_acked,
- LostPacketVector* packets_lost) override;
+ DetectionStats DetectLosses(const QuicUnackedPacketMap& unacked_packets,
+ QuicTime time,
+ const RttStats& rtt_stats,
+ QuicPacketNumber largest_newly_acked,
+ const AckedPacketVector& packets_acked,
+ LostPacketVector* packets_lost) override;
// Returns a non-zero value when the early retransmit timer is active.
QuicTime GetLossTimeout() const override;
diff --git a/quic/core/congestion_control/general_loss_algorithm_test.cc b/quic/core/congestion_control/general_loss_algorithm_test.cc
index 7bef933..1a58ade 100644
--- a/quic/core/congestion_control/general_loss_algorithm_test.cc
+++ b/quic/core/congestion_control/general_loss_algorithm_test.cc
@@ -61,12 +61,25 @@
void VerifyLosses(uint64_t largest_newly_acked,
const AckedPacketVector& packets_acked,
const std::vector<uint64_t>& losses_expected) {
+ return VerifyLosses(largest_newly_acked, packets_acked, losses_expected,
+ quiche::QuicheOptional<QuicPacketCount>());
+ }
+
+ void VerifyLosses(uint64_t largest_newly_acked,
+ const AckedPacketVector& packets_acked,
+ const std::vector<uint64_t>& losses_expected,
+ quiche::QuicheOptional<QuicPacketCount>
+ max_sequence_reordering_expected) {
unacked_packets_.MaybeUpdateLargestAckedOfPacketNumberSpace(
APPLICATION_DATA, QuicPacketNumber(largest_newly_acked));
LostPacketVector lost_packets;
- loss_algorithm_.DetectLosses(unacked_packets_, clock_.Now(), rtt_stats_,
- QuicPacketNumber(largest_newly_acked),
- packets_acked, &lost_packets);
+ LossDetectionInterface::DetectionStats stats = loss_algorithm_.DetectLosses(
+ unacked_packets_, clock_.Now(), rtt_stats_,
+ QuicPacketNumber(largest_newly_acked), packets_acked, &lost_packets);
+ if (max_sequence_reordering_expected.has_value()) {
+ EXPECT_EQ(stats.sent_packets_max_sequence_reordering,
+ max_sequence_reordering_expected.value());
+ }
ASSERT_EQ(losses_expected.size(), lost_packets.size());
for (size_t i = 0; i < losses_expected.size(); ++i) {
EXPECT_EQ(lost_packets[i].packet_number,
@@ -91,19 +104,19 @@
unacked_packets_.RemoveFromInFlight(QuicPacketNumber(2));
packets_acked.push_back(AckedPacket(
QuicPacketNumber(2), kMaxOutgoingPacketSize, QuicTime::Zero()));
- VerifyLosses(2, packets_acked, std::vector<uint64_t>{});
+ VerifyLosses(2, packets_acked, std::vector<uint64_t>{}, 1);
packets_acked.clear();
// No loss on two acks.
unacked_packets_.RemoveFromInFlight(QuicPacketNumber(3));
packets_acked.push_back(AckedPacket(
QuicPacketNumber(3), kMaxOutgoingPacketSize, QuicTime::Zero()));
- VerifyLosses(3, packets_acked, std::vector<uint64_t>{});
+ VerifyLosses(3, packets_acked, std::vector<uint64_t>{}, 2);
packets_acked.clear();
// Loss on three acks.
unacked_packets_.RemoveFromInFlight(QuicPacketNumber(4));
packets_acked.push_back(AckedPacket(
QuicPacketNumber(4), kMaxOutgoingPacketSize, QuicTime::Zero()));
- VerifyLosses(4, packets_acked, {1});
+ VerifyLosses(4, packets_acked, {1}, 3);
EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
}
diff --git a/quic/core/congestion_control/loss_detection_interface.h b/quic/core/congestion_control/loss_detection_interface.h
index 2ed7952..8d91976 100644
--- a/quic/core/congestion_control/loss_detection_interface.h
+++ b/quic/core/congestion_control/loss_detection_interface.h
@@ -26,13 +26,19 @@
virtual void SetFromConfig(const QuicConfig& config,
Perspective perspective) = 0;
+ struct QUIC_NO_EXPORT DetectionStats {
+ // Maximum sequence reordering observed in newly acked packets.
+ QuicPacketCount sent_packets_max_sequence_reordering = 0;
+ };
+
// Called when a new ack arrives or the loss alarm fires.
- virtual void DetectLosses(const QuicUnackedPacketMap& unacked_packets,
- QuicTime time,
- const RttStats& rtt_stats,
- QuicPacketNumber largest_newly_acked,
- const AckedPacketVector& packets_acked,
- LostPacketVector* packets_lost) = 0;
+ virtual DetectionStats DetectLosses(
+ const QuicUnackedPacketMap& unacked_packets,
+ QuicTime time,
+ const RttStats& rtt_stats,
+ QuicPacketNumber largest_newly_acked,
+ const AckedPacketVector& packets_acked,
+ LostPacketVector* packets_lost) = 0;
// Get the time the LossDetectionAlgorithm wants to re-evaluate losses.
// Returns QuicTime::Zero if no alarm needs to be set.
diff --git a/quic/core/congestion_control/uber_loss_algorithm.cc b/quic/core/congestion_control/uber_loss_algorithm.cc
index 5059a81..0f294d6 100644
--- a/quic/core/congestion_control/uber_loss_algorithm.cc
+++ b/quic/core/congestion_control/uber_loss_algorithm.cc
@@ -27,13 +27,15 @@
}
}
-void UberLossAlgorithm::DetectLosses(
+LossDetectionInterface::DetectionStats UberLossAlgorithm::DetectLosses(
const QuicUnackedPacketMap& unacked_packets,
QuicTime time,
const RttStats& rtt_stats,
QuicPacketNumber /*largest_newly_acked*/,
const AckedPacketVector& packets_acked,
LostPacketVector* packets_lost) {
+ DetectionStats overall_stats;
+
for (int8_t i = INITIAL_DATA; i < NUM_PACKET_NUMBER_SPACES; ++i) {
const QuicPacketNumber largest_acked =
unacked_packets.GetLargestAckedOfPacketNumberSpace(
@@ -45,10 +47,16 @@
continue;
}
- general_loss_algorithms_[i].DetectLosses(unacked_packets, time, rtt_stats,
- largest_acked, packets_acked,
- packets_lost);
+ DetectionStats stats = general_loss_algorithms_[i].DetectLosses(
+ unacked_packets, time, rtt_stats, largest_acked, packets_acked,
+ packets_lost);
+
+ overall_stats.sent_packets_max_sequence_reordering =
+ std::max(overall_stats.sent_packets_max_sequence_reordering,
+ stats.sent_packets_max_sequence_reordering);
}
+
+ return overall_stats;
}
QuicTime UberLossAlgorithm::GetLossTimeout() const {
diff --git a/quic/core/congestion_control/uber_loss_algorithm.h b/quic/core/congestion_control/uber_loss_algorithm.h
index 1b1c1e8..86b6525 100644
--- a/quic/core/congestion_control/uber_loss_algorithm.h
+++ b/quic/core/congestion_control/uber_loss_algorithm.h
@@ -51,12 +51,12 @@
Perspective perspective) override;
// Detects lost packets.
- void DetectLosses(const QuicUnackedPacketMap& unacked_packets,
- QuicTime time,
- const RttStats& rtt_stats,
- QuicPacketNumber largest_newly_acked,
- const AckedPacketVector& packets_acked,
- LostPacketVector* packets_lost) override;
+ DetectionStats DetectLosses(const QuicUnackedPacketMap& unacked_packets,
+ QuicTime time,
+ const RttStats& rtt_stats,
+ QuicPacketNumber largest_newly_acked,
+ const AckedPacketVector& packets_acked,
+ LostPacketVector* packets_lost) override;
// Returns the earliest time the early retransmit timer should be active.
QuicTime GetLossTimeout() const override;
diff --git a/quic/core/congestion_control/uber_loss_algorithm_test.cc b/quic/core/congestion_control/uber_loss_algorithm_test.cc
index a3daf09..6fd949f 100644
--- a/quic/core/congestion_control/uber_loss_algorithm_test.cc
+++ b/quic/core/congestion_control/uber_loss_algorithm_test.cc
@@ -11,6 +11,7 @@
#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
#include "net/third_party/quiche/src/quic/test_tools/mock_clock.h"
#include "net/third_party/quiche/src/quic/test_tools/quic_unacked_packet_map_peer.h"
+#include "net/third_party/quiche/src/common/platform/api/quiche_optional.h"
namespace quic {
namespace test {
@@ -64,10 +65,23 @@
void VerifyLosses(uint64_t largest_newly_acked,
const AckedPacketVector& packets_acked,
const std::vector<uint64_t>& losses_expected) {
+ return VerifyLosses(largest_newly_acked, packets_acked, losses_expected,
+ quiche::QuicheOptional<QuicPacketCount>());
+ }
+
+ void VerifyLosses(uint64_t largest_newly_acked,
+ const AckedPacketVector& packets_acked,
+ const std::vector<uint64_t>& losses_expected,
+ quiche::QuicheOptional<QuicPacketCount>
+ max_sequence_reordering_expected) {
LostPacketVector lost_packets;
- loss_algorithm_.DetectLosses(*unacked_packets_, clock_.Now(), rtt_stats_,
- QuicPacketNumber(largest_newly_acked),
- packets_acked, &lost_packets);
+ LossDetectionInterface::DetectionStats stats = loss_algorithm_.DetectLosses(
+ *unacked_packets_, clock_.Now(), rtt_stats_,
+ QuicPacketNumber(largest_newly_acked), packets_acked, &lost_packets);
+ if (max_sequence_reordering_expected.has_value()) {
+ EXPECT_EQ(stats.sent_packets_max_sequence_reordering,
+ max_sequence_reordering_expected.value());
+ }
ASSERT_EQ(losses_expected.size(), lost_packets.size());
for (size_t i = 0; i < losses_expected.size(); ++i) {
EXPECT_EQ(lost_packets[i].packet_number,
@@ -98,7 +112,7 @@
unacked_packets_->MaybeUpdateLargestAckedOfPacketNumberSpace(
HANDSHAKE_DATA, QuicPacketNumber(4));
// Verify no packet is detected lost.
- VerifyLosses(4, packets_acked_, std::vector<uint64_t>{});
+ VerifyLosses(4, packets_acked_, std::vector<uint64_t>{}, 0);
EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
}
@@ -114,7 +128,7 @@
unacked_packets_->MaybeUpdateLargestAckedOfPacketNumberSpace(
APPLICATION_DATA, QuicPacketNumber(4));
// No packet loss by acking 4.
- VerifyLosses(4, packets_acked_, std::vector<uint64_t>{});
+ VerifyLosses(4, packets_acked_, std::vector<uint64_t>{}, 1);
EXPECT_EQ(clock_.Now() + 1.25 * rtt_stats_.smoothed_rtt(),
loss_algorithm_.GetLossTimeout());
@@ -122,14 +136,14 @@
AckPackets({6});
unacked_packets_->MaybeUpdateLargestAckedOfPacketNumberSpace(
APPLICATION_DATA, QuicPacketNumber(6));
- VerifyLosses(6, packets_acked_, std::vector<uint64_t>{3});
+ VerifyLosses(6, packets_acked_, std::vector<uint64_t>{3}, 3);
EXPECT_EQ(clock_.Now() + 1.25 * rtt_stats_.smoothed_rtt(),
loss_algorithm_.GetLossTimeout());
packets_acked_.clear();
clock_.AdvanceTime(1.25 * rtt_stats_.latest_rtt());
// Verify 5 will be early retransmitted.
- VerifyLosses(6, packets_acked_, {5});
+ VerifyLosses(6, packets_acked_, {5}, 1);
}
TEST_F(UberLossAlgorithmTest, ScenarioC) {
@@ -151,14 +165,14 @@
unacked_packets_->MaybeUpdateLargestAckedOfPacketNumberSpace(
HANDSHAKE_DATA, QuicPacketNumber(5));
// No packet loss by acking 5.
- VerifyLosses(5, packets_acked_, std::vector<uint64_t>{});
+ VerifyLosses(5, packets_acked_, std::vector<uint64_t>{}, 2);
EXPECT_EQ(clock_.Now() + 1.25 * rtt_stats_.smoothed_rtt(),
loss_algorithm_.GetLossTimeout());
packets_acked_.clear();
clock_.AdvanceTime(1.25 * rtt_stats_.latest_rtt());
// Verify 2 and 3 will be early retransmitted.
- VerifyLosses(5, packets_acked_, std::vector<uint64_t>{2, 3});
+ VerifyLosses(5, packets_acked_, std::vector<uint64_t>{2, 3}, 2);
}
// Regression test for b/133771183.
diff --git a/quic/core/quic_connection_stats.h b/quic/core/quic_connection_stats.h
index 911ea6d..3b0c85d 100644
--- a/quic/core/quic_connection_stats.h
+++ b/quic/core/quic_connection_stats.h
@@ -102,6 +102,9 @@
// Maximum reordering observed in microseconds
int64_t max_time_reordering_us = 0;
+ // Maximum sequence reordering observed from acked packets.
+ QuicPacketCount sent_packets_max_sequence_reordering = 0;
+
// The following stats are used only in TcpCubicSender.
// The number of loss events from TCP's perspective. Each loss event includes
// one or more lost packets.
diff --git a/quic/core/quic_connection_test.cc b/quic/core/quic_connection_test.cc
index e9165b2..ffe43c6 100644
--- a/quic/core/quic_connection_test.cc
+++ b/quic/core/quic_connection_test.cc
@@ -2853,7 +2853,8 @@
LostPacketVector lost_packets;
lost_packets.push_back(LostPacket(original, kMaxOutgoingPacketSize));
EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _, _))
- .WillOnce(SetArgPointee<5>(lost_packets));
+ .WillOnce(DoAll(SetArgPointee<5>(lost_packets),
+ Return(LossDetectionInterface::DetectionStats())));
EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
QuicPacketNumber retransmission;
// Packet 1 is short header for IETF QUIC because the encryption level
@@ -3573,7 +3574,8 @@
lost_packets.push_back(
LostPacket(QuicPacketNumber(2), kMaxOutgoingPacketSize));
EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _, _))
- .WillOnce(SetArgPointee<5>(lost_packets));
+ .WillOnce(DoAll(SetArgPointee<5>(lost_packets),
+ Return(LossDetectionInterface::DetectionStats())));
EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
EXPECT_FALSE(QuicPacketCreatorPeer::SendVersionInPacket(creator_));
@@ -3655,7 +3657,8 @@
LostPacketVector lost_packets;
lost_packets.push_back(LostPacket(last_packet - 1, kMaxOutgoingPacketSize));
EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _, _))
- .WillOnce(SetArgPointee<5>(lost_packets));
+ .WillOnce(DoAll(SetArgPointee<5>(lost_packets),
+ Return(LossDetectionInterface::DetectionStats())));
EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(AtLeast(1));
ProcessAckPacket(&nack_two);
@@ -3775,7 +3778,8 @@
LostPacketVector lost_packets;
lost_packets.push_back(LostPacket(last_packet - 1, kMaxOutgoingPacketSize));
EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _, _))
- .WillOnce(SetArgPointee<5>(lost_packets));
+ .WillOnce(DoAll(SetArgPointee<5>(lost_packets),
+ Return(LossDetectionInterface::DetectionStats())));
EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0);
ProcessAckPacket(&ack);
@@ -3814,7 +3818,8 @@
lost_packets.push_back(
LostPacket(QuicPacketNumber(2), kMaxOutgoingPacketSize));
EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _, _))
- .WillOnce(SetArgPointee<5>(lost_packets));
+ .WillOnce(DoAll(SetArgPointee<5>(lost_packets),
+ Return(LossDetectionInterface::DetectionStats())));
EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, QuicPacketNumber(4), _, _))
.Times(1);
@@ -3851,7 +3856,8 @@
LostPacketVector lost_packets;
lost_packets.push_back(LostPacket(original, kMaxOutgoingPacketSize));
EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _, _))
- .WillOnce(SetArgPointee<5>(lost_packets));
+ .WillOnce(DoAll(SetArgPointee<5>(lost_packets),
+ Return(LossDetectionInterface::DetectionStats())));
EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
// Packet 1 is short header for IETF QUIC because the encryption level
// switched to ENCRYPTION_FORWARD_SECURE in SendStreamDataToPeer.
@@ -4068,7 +4074,8 @@
LostPacket(QuicPacketNumber(i), kMaxOutgoingPacketSize));
}
EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _, _))
- .WillOnce(SetArgPointee<5>(lost_packets));
+ .WillOnce(DoAll(SetArgPointee<5>(lost_packets),
+ Return(LossDetectionInterface::DetectionStats())));
EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
ProcessAckPacket(&nack);
@@ -7156,7 +7163,8 @@
lost_packets.push_back(
LostPacket(QuicPacketNumber(1), kMaxOutgoingPacketSize));
EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _, _))
- .WillOnce(SetArgPointee<5>(lost_packets));
+ .WillOnce(DoAll(SetArgPointee<5>(lost_packets),
+ Return(LossDetectionInterface::DetectionStats())));
EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
ProcessAckPacket(&ack);
size_t padding_frame_count = writer_->padding_frames().size();
@@ -7501,7 +7509,8 @@
lost_packets.push_back(
LostPacket(QuicPacketNumber(3), kMaxOutgoingPacketSize));
EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _, _, _))
- .WillOnce(SetArgPointee<5>(lost_packets));
+ .WillOnce(DoAll(SetArgPointee<5>(lost_packets),
+ Return(LossDetectionInterface::DetectionStats())));
EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _, _));
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
ProcessAckPacket(&nack_three);
diff --git a/quic/core/quic_sent_packet_manager.cc b/quic/core/quic_sent_packet_manager.cc
index 0523b3c..5c99279 100644
--- a/quic/core/quic_sent_packet_manager.cc
+++ b/quic/core/quic_sent_packet_manager.cc
@@ -934,9 +934,17 @@
packets_acked_.back().packet_number);
largest_newly_acked_ = packets_acked_.back().packet_number;
}
- loss_algorithm_->DetectLosses(unacked_packets_, time, rtt_stats_,
- largest_newly_acked_, packets_acked_,
- &packets_lost_);
+ LossDetectionInterface::DetectionStats detection_stats =
+ loss_algorithm_->DetectLosses(unacked_packets_, time, rtt_stats_,
+ largest_newly_acked_, packets_acked_,
+ &packets_lost_);
+
+ if (detection_stats.sent_packets_max_sequence_reordering >
+ stats_->sent_packets_max_sequence_reordering) {
+ stats_->sent_packets_max_sequence_reordering =
+ detection_stats.sent_packets_max_sequence_reordering;
+ }
+
for (const LostPacket& packet : packets_lost_) {
QuicTransmissionInfo* info =
unacked_packets_.GetMutableTransmissionInfo(packet.packet_number);
diff --git a/quic/core/quic_sent_packet_manager_test.cc b/quic/core/quic_sent_packet_manager_test.cc
index 9d62bb6..e11f16e 100644
--- a/quic/core/quic_sent_packet_manager_test.cc
+++ b/quic/core/quic_sent_packet_manager_test.cc
@@ -622,6 +622,7 @@
EXPECT_EQ(1u, stats_.packets_spuriously_retransmitted);
EXPECT_EQ(1u, stats_.packets_lost);
EXPECT_LT(QuicTime::Delta::Zero(), stats_.total_loss_detection_time);
+ EXPECT_LE(1u, stats_.sent_packets_max_sequence_reordering);
}
TEST_F(QuicSentPacketManagerTest, AckOriginalTransmission) {