in quic/congestion_control/Bbr.cpp [184:265]
void BbrCongestionController::onPacketAcked(
const AckEvent& ack,
uint64_t prevInflightBytes,
bool hasLoss) {
SCOPE_EXIT {
if (conn_.qLogger) {
conn_.qLogger->addCongestionMetricUpdate(
conn_.lossState.inflightBytes,
getCongestionWindow(),
kCongestionPacketAck,
bbrStateToString(state_),
bbrRecoveryStateToString(recoveryState_));
}
};
if (ack.implicit) {
// This is an implicit ACK during the handshake, we can't trust very
// much about it except the fact that it does ACK some bytes.
updateCwnd(ack.ackedBytes, 0);
return;
}
if (ack.rttSample && minRttSampler_) {
bool updated =
minRttSampler_->newRttSample(ack.rttSample.value(), ack.ackTime);
if (updated) {
appLimitedSinceProbeRtt_ = false;
}
}
bool newRoundTrip =
updateRoundTripCounter(ack.largestNewlyAckedPacketSentTime);
bool lastAckedPacketAppLimited =
ack.ackedPackets.empty() ? false : ack.largestNewlyAckedPacketAppLimited;
if (bandwidthSampler_) {
bandwidthSampler_->onPacketAcked(ack, roundTripCounter_);
}
if (inRecovery()) {
CHECK(endOfRecovery_.has_value());
if (newRoundTrip &&
recoveryState_ != BbrCongestionController::RecoveryState::GROWTH) {
recoveryState_ = BbrCongestionController::RecoveryState::GROWTH;
}
if (ack.largestNewlyAckedPacketSentTime > *endOfRecovery_) {
recoveryState_ = BbrCongestionController::RecoveryState::NOT_RECOVERY;
} else {
updateRecoveryWindowWithAck(ack.ackedBytes);
}
}
auto excessiveBytes = updateAckAggregation(ack);
// handleAckInProbeBw() needs to happen before we check exiting Startup and
// Drain and transitToProbeBw(). Otherwise, we may transitToProbeBw() first
// then immediately invoke a handleAckInProbeBw() to also transit to next
// ProbwBw pacing cycle.
if (state_ == BbrState::ProbeBw) {
handleAckInProbeBw(ack.ackTime, prevInflightBytes, hasLoss);
}
if (newRoundTrip && !lastAckedPacketAppLimited) {
detectBottleneckBandwidth(lastAckedPacketAppLimited);
}
if (shouldExitStartup()) {
transitToDrain();
}
if (shouldExitDrain()) {
transitToProbeBw(ack.ackTime);
}
if (shouldProbeRtt(ack.ackTime)) {
transitToProbeRtt();
}
exitingQuiescene_ = false;
if (state_ == BbrState::ProbeRtt && minRttSampler_) {
handleAckInProbeRtt(newRoundTrip, ack.ackTime);
}
updateCwnd(ack.ackedBytes, excessiveBytes);
updatePacing();
}