in neqo-transport/src/cc/classic_cc.rs [471:528]
fn detect_persistent_congestion<'a>(
&mut self,
first_rtt_sample_time: Option<Instant>,
prev_largest_acked_sent: Option<Instant>,
pto: Duration,
lost_packets: impl IntoIterator<Item = &'a SentPacket>,
now: Instant,
) -> bool {
if first_rtt_sample_time.is_none() {
return false;
}
let pc_period = pto * PERSISTENT_CONG_THRESH;
let mut last_pn = 1 << 62; // Impossibly large, but not enough to overflow.
let mut start = None;
// Look for the first lost packet after the previous largest acknowledged.
// Ignore packets that weren't ack-eliciting for the start of this range.
// Also, make sure to ignore any packets sent before we got an RTT estimate
// as we might not have sent PTO packets soon enough after those.
let cutoff = max(first_rtt_sample_time, prev_largest_acked_sent);
for p in lost_packets
.into_iter()
.skip_while(|p| Some(p.time_sent()) < cutoff)
{
if p.pn() != last_pn + 1 {
// Not a contiguous range of lost packets, start over.
start = None;
}
last_pn = p.pn();
if !p.cc_in_flight() {
// Not interesting, keep looking.
continue;
}
if let Some(t) = start {
let elapsed = p
.time_sent()
.checked_duration_since(t)
.expect("time is monotonic");
if elapsed > pc_period {
qinfo!("[{self}] persistent congestion");
self.congestion_window = self.cwnd_min();
self.acked_bytes = 0;
self.set_state(State::PersistentCongestion, now);
qlog::metrics_updated(
&self.qlog,
&[QlogMetric::CongestionWindow(self.congestion_window)],
now,
);
return true;
}
} else {
start = Some(p.time_sent());
}
}
false
}