void Copa::onPacketAcked()

in quic/congestion_control/Copa.cpp [147:287]


void Copa::onPacketAcked(const AckEvent& ack) {
  DCHECK(ack.largestNewlyAckedPacket.has_value());
  subtractAndCheckUnderflow(conn_.lossState.inflightBytes, ack.ackedBytes);
  minRTTFilter_.Update(
      conn_.lossState.lrtt,
      std::chrono::duration_cast<microseconds>(ack.ackTime.time_since_epoch())
          .count());
  auto rttMin = minRTTFilter_.GetBest();
  if (useRttStanding_) {
    standingRTTFilter_.SetWindowLength(conn_.lossState.srtt.count());
  } else {
    standingRTTFilter_.SetWindowLength(conn_.lossState.srtt.count() / 2);
  }
  standingRTTFilter_.Update(
      conn_.lossState.lrtt,
      std::chrono::duration_cast<microseconds>(ack.ackTime.time_since_epoch())
          .count());
  auto rttStandingMicroSec = standingRTTFilter_.GetBest().count();

  VLOG(10) << __func__ << "ack size=" << ack.ackedBytes
           << " num packets acked=" << ack.ackedBytes / conn_.udpSendPacketLen
           << " writable=" << getWritableBytes() << " cwnd=" << cwndBytes_
           << " inflight=" << conn_.lossState.inflightBytes
           << " rttMin=" << rttMin.count()
           << " sRTT=" << conn_.lossState.srtt.count()
           << " lRTT=" << conn_.lossState.lrtt.count()
           << " mRTT=" << conn_.lossState.mrtt.count()
           << " rttvar=" << conn_.lossState.rttvar.count()
           << " packetsBufferred="
           << conn_.flowControlState.sumCurStreamBufferLen
           << " packetsRetransmitted=" << conn_.lossState.rtxCount << " "
           << conn_;

  if (conn_.qLogger) {
    conn_.qLogger->addCongestionMetricUpdate(
        conn_.lossState.inflightBytes,
        getCongestionWindow(),
        kCongestionPacketAck);
  }

  if (rttStandingMicroSec < rttMin.count()) {
    VLOG(3) << __func__ << "delay negative, rttStanding=" << rttStandingMicroSec
            << " rttMin=" << rttMin.count() << " " << conn_;
    return;
  }

  uint64_t delayInMicroSec;
  if (useRttStanding_) {
    delayInMicroSec = rttStandingMicroSec - rttMin.count();
  } else {
    delayInMicroSec =
        duration_cast<microseconds>(conn_.lossState.lrtt - rttMin).count();
  }

  if (rttStandingMicroSec == 0) {
    VLOG(3) << __func__ << "rttStandingMicroSec zero, lrtt = "
            << conn_.lossState.lrtt.count() << " rttMin=" << rttMin.count()
            << " " << conn_;
    return;
  }

  VLOG(10) << __func__
           << " estimated queuing delay microsec =" << delayInMicroSec << " "
           << conn_;

  bool increaseCwnd = false;
  if (delayInMicroSec == 0) {
    // taking care of inf targetRate case here, this happens in beginning where
    // we do want to increase cwnd
    increaseCwnd = true;
  } else {
    auto targetRate = (1.0 * conn_.udpSendPacketLen * 1000000) /
        (deltaParam_ * delayInMicroSec);
    auto currentRate = (1.0 * cwndBytes_ * 1000000) / rttStandingMicroSec;

    VLOG(10) << __func__ << " estimated target rate=" << targetRate
             << " current rate=" << currentRate << " " << conn_;
    increaseCwnd = targetRate >= currentRate;
  }

  if (!(increaseCwnd && isSlowStart_)) {
    // Update direction except for the case where we are in slow start mode,
    checkAndUpdateDirection(ack.ackTime);
  }

  if (increaseCwnd) {
    if (isSlowStart_) {
      // When a flow starts, Copa performs slow-start where
      // cwnd doubles once per RTT until current rate exceeds target rate".
      if (!lastCwndDoubleTime_.has_value()) {
        lastCwndDoubleTime_ = ack.ackTime;
      } else if (
          ack.ackTime - lastCwndDoubleTime_.value() > conn_.lossState.srtt) {
        VLOG(10) << __func__ << " doubling cwnd per RTT from=" << cwndBytes_
                 << " due to slow start"
                 << " " << conn_;
        addAndCheckOverflow(cwndBytes_, cwndBytes_);
        lastCwndDoubleTime_ = ack.ackTime;
      }
    } else {
      if (velocityState_.direction != VelocityState::Direction::Up &&
          velocityState_.velocity > 1.0) {
        // if our current rate is much different than target, we double v every
        // RTT. That could result in a high v at some point in time. If we
        // detect a sudden direction change here, while v is still very high but
        // meant for opposite direction, we should reset it to 1.
        changeDirection(VelocityState::Direction::Up, ack.ackTime);
      }
      uint64_t addition = (ack.ackedPackets.size() * conn_.udpSendPacketLen *
                           conn_.udpSendPacketLen * velocityState_.velocity) /
          (deltaParam_ * cwndBytes_);
      VLOG(10) << __func__ << " increasing cwnd from=" << cwndBytes_ << " by "
               << addition << " " << conn_;
      addAndCheckOverflow(cwndBytes_, addition);
    }
  } else {
    if (velocityState_.direction != VelocityState::Direction::Down &&
        velocityState_.velocity > 1.0) {
      // if our current rate is much different than target, we double v every
      // RTT. That could result in a high v at some point in time. If we detect
      // a sudden direction change here, while v is still very high but meant
      // for opposite direction, we should reset it to 1.
      changeDirection(VelocityState::Direction::Down, ack.ackTime);
    }
    uint64_t reduction = (ack.ackedPackets.size() * conn_.udpSendPacketLen *
                          conn_.udpSendPacketLen * velocityState_.velocity) /
        (deltaParam_ * cwndBytes_);
    VLOG(10) << __func__ << " decreasing cwnd from=" << cwndBytes_ << " by "
             << reduction << " " << conn_;
    isSlowStart_ = false;
    subtractAndCheckUnderflow(
        cwndBytes_,
        std::min<uint64_t>(
            reduction,
            cwndBytes_ -
                conn_.transportSettings.minCwndInMss * conn_.udpSendPacketLen));
  }
  if (conn_.pacer) {
    conn_.pacer->refreshPacingRate(cwndBytes_ * 2, conn_.lossState.srtt);
  }
}