You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by ma...@apache.org on 2017/12/21 06:02:58 UTC

[trafficserver] branch quic-latest updated: Update loss detection logic to draft-08

This is an automated email from the ASF dual-hosted git repository.

maskit pushed a commit to branch quic-latest
in repository https://gitbox.apache.org/repos/asf/trafficserver.git


The following commit(s) were added to refs/heads/quic-latest by this push:
     new ad7d9eb  Update loss detection logic to draft-08
ad7d9eb is described below

commit ad7d9eb2859974acb1d3add8c7a6fc3816a42c17
Author: Masakazu Kitajo <ma...@apache.org>
AuthorDate: Thu Dec 21 15:02:15 2017 +0900

    Update loss detection logic to draft-08
---
 iocore/net/quic/QUICCongestionController.cc |   9 +-
 iocore/net/quic/QUICCongestionController.h  |   5 +-
 iocore/net/quic/QUICLossDetector.cc         | 337 ++++++++++++++++------------
 iocore/net/quic/QUICLossDetector.h          |  27 +--
 4 files changed, 212 insertions(+), 166 deletions(-)

diff --git a/iocore/net/quic/QUICCongestionController.cc b/iocore/net/quic/QUICCongestionController.cc
index 96c2b55..3ce8e76 100644
--- a/iocore/net/quic/QUICCongestionController.cc
+++ b/iocore/net/quic/QUICCongestionController.cc
@@ -51,12 +51,12 @@ QUICCongestionController::handle_frame(std::shared_ptr<const QUICFrame> frame)
 }
 
 void
-QUICCongestionController::on_packet_sent()
+QUICCongestionController::on_packet_sent(size_t sent_bytes)
 {
 }
 
 void
-QUICCongestionController::on_packet_acked()
+QUICCongestionController::on_packet_acked(QUICPacketNumber acked_packet_number)
 {
 }
 
@@ -66,6 +66,11 @@ QUICCongestionController::on_packets_lost(std::set<QUICPacketNumber> packets)
 }
 
 void
+QUICCongestionController::on_retransmission_timeout_verified()
+{
+}
+
+void
 QUICCongestionController::on_rto_verified()
 {
 }
diff --git a/iocore/net/quic/QUICCongestionController.h b/iocore/net/quic/QUICCongestionController.h
index 1f76343..79cb96a 100644
--- a/iocore/net/quic/QUICCongestionController.h
+++ b/iocore/net/quic/QUICCongestionController.h
@@ -35,10 +35,11 @@ public:
   virtual std::vector<QUICFrameType> interests() override;
   virtual QUICErrorUPtr handle_frame(std::shared_ptr<const QUICFrame>) override;
 
-  void on_packet_sent();
-  void on_packet_acked();
+  void on_packet_sent(size_t sent_bytes);
+  void on_packet_acked(QUICPacketNumber acked_packet_number);
   virtual void on_packets_lost(std::set<QUICPacketNumber> packets);
   void on_rto_verified();
+  void on_retransmission_timeout_verified();
 
 private:
 };
diff --git a/iocore/net/quic/QUICLossDetector.cc b/iocore/net/quic/QUICLossDetector.cc
index f162221..7edd181 100644
--- a/iocore/net/quic/QUICLossDetector.cc
+++ b/iocore/net/quic/QUICLossDetector.cc
@@ -28,6 +28,17 @@
 #define QUICLDDebug(fmt, ...) \
   Debug("quic_loss_detector", "[%" PRIx64 "] " fmt, static_cast<uint64_t>(this->_connection_id), ##__VA_ARGS__)
 
+// 3.4.1.  Constants of interest (draft-08)
+// Keep the order as the same as the spec so that we can see the difference easily.
+constexpr static uint32_t MAX_TLPS               = 2;
+constexpr static uint32_t REORDERING_THRESHOLD   = 3;
+constexpr static double TIME_REORDERING_FRACTION = 1 / 8;
+constexpr static ink_hrtime MIN_TLP_TIMEOUT      = HRTIME_MSECONDS(10);
+constexpr static ink_hrtime MIN_RTO_TIMEOUT      = HRTIME_MSECONDS(200);
+// This is defined on the spec but not used
+// constexpr static ink_hrtime DELAYED_ACK_TIMEOUT  = HRTIME_MSECONDS(25);
+constexpr static ink_hrtime DEFAULT_INITIAL_RTT = HRTIME_MSECONDS(100);
+
 QUICLossDetector::QUICLossDetector(QUICPacketTransmitter *transmitter, QUICCongestionController *cc)
   : _transmitter(transmitter), _cc(cc)
 {
@@ -35,9 +46,9 @@ QUICLossDetector::QUICLossDetector(QUICPacketTransmitter *transmitter, QUICConge
 
   if (this->_time_loss_detection) {
     this->_reordering_threshold     = UINT32_MAX;
-    this->_time_reordering_fraction = this->_TIME_REORDERING_FRACTION;
+    this->_time_reordering_fraction = TIME_REORDERING_FRACTION;
   } else {
-    this->_reordering_threshold     = this->_REORDERING_THRESHOLD;
+    this->_reordering_threshold     = REORDERING_THRESHOLD;
     this->_time_reordering_fraction = INFINITY;
   }
 
@@ -103,46 +114,6 @@ QUICLossDetector::largest_acked_packet_number()
 }
 
 void
-QUICLossDetector::_detect_lost_packets(QUICPacketNumber largest_acked_packet_number)
-{
-  SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread());
-  this->_loss_time = 0;
-  std::set<QUICPacketNumber> lost_packets;
-  uint32_t delay_until_lost = UINT32_MAX;
-
-  if (this->_time_reordering_fraction != INFINITY) {
-    delay_until_lost = (1 + this->_time_reordering_fraction) * std::max(this->_latest_rtt, this->_smoothed_rtt);
-  } else if (largest_acked_packet_number == this->_largest_sent_packet) {
-    // Early retransmit alarm.
-    delay_until_lost = 9 / 8 * std::max(this->_latest_rtt, this->_smoothed_rtt);
-  }
-  for (auto &unacked : this->_sent_packets) {
-    if (unacked.first >= largest_acked_packet_number) {
-      break;
-    }
-    ink_hrtime time_since_sent = Thread::get_hrtime() - unacked.second->time;
-    uint64_t packet_delta      = largest_acked_packet_number - unacked.second->packet_number;
-    if (time_since_sent > delay_until_lost) {
-      lost_packets.insert(unacked.first);
-    } else if (packet_delta > this->_reordering_threshold) {
-      lost_packets.insert(unacked.first);
-    } else if (this->_loss_time == 0 && delay_until_lost != INFINITY) {
-      this->_loss_time = Thread::get_hrtime() + delay_until_lost - time_since_sent;
-    }
-  }
-
-  // Inform the congestion controller of lost packets and
-  // lets it decide whether to retransmit immediately.
-  if (!lost_packets.empty()) {
-    this->_cc->on_packets_lost(lost_packets);
-    for (auto packet_number : lost_packets) {
-      this->_decrement_packet_count(packet_number);
-      this->_sent_packets.erase(packet_number);
-    }
-  }
-}
-
-void
 QUICLossDetector::on_packet_sent(QUICPacketUPtr packet)
 {
   if (this->_connection_id == 0) {
@@ -152,34 +123,30 @@ QUICLossDetector::on_packet_sent(QUICPacketUPtr packet)
   bool is_handshake   = false;
   QUICPacketType type = packet->type();
 
-  // XXX: Should QUICPacketType::SERVER_STATELESS_RETRY be included?
   if (type == QUICPacketType::INITIAL || type == QUICPacketType::HANDSHAKE) {
     is_handshake = true;
   }
 
   QUICPacketNumber packet_number = packet->packet_number();
-  bool is_retransmittable        = packet->is_retransmittable();
+  bool is_ack_only               = !packet->is_retransmittable();
   size_t sent_bytes              = packet->size();
-  return this->_on_packet_sent(packet_number, is_retransmittable, is_handshake, sent_bytes, std::move(packet));
+  return this->_on_packet_sent(packet_number, is_ack_only, is_handshake, sent_bytes, std::move(packet));
 }
 
 void
-QUICLossDetector::_on_packet_sent(QUICPacketNumber packet_number, bool is_retransmittable, bool is_handshake, size_t sent_bytes,
+QUICLossDetector::_on_packet_sent(QUICPacketNumber packet_number, bool is_ack_only, bool is_handshake, size_t sent_bytes,
                                   QUICPacketUPtr packet)
 {
   SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread());
-  this->_largest_sent_packet      = packet_number;
   this->_time_of_last_sent_packet = Thread::get_hrtime();
+  this->_largest_sent_packet      = packet_number;
   // FIXME Should we really keep actual packet object?
 
-  std::unique_ptr<PacketInfo> packet_info(new PacketInfo(
-    {packet_number, this->_time_of_last_sent_packet, is_retransmittable, is_handshake, sent_bytes, std::move(packet)}));
-  this->_sent_packets.insert(std::pair<QUICPacketNumber, std::unique_ptr<PacketInfo>>(packet_number, std::move(packet_info)));
-  if (is_handshake) {
-    ++this->_handshake_outstanding;
-  }
-  if (is_retransmittable) {
-    ++this->_retransmittable_outstanding;
+  std::unique_ptr<PacketInfo> packet_info(
+    new PacketInfo({packet_number, this->_time_of_last_sent_packet, is_ack_only, is_handshake, sent_bytes, std::move(packet)}));
+  this->_add_to_sent_packet_list(packet_number, std::move(packet_info));
+  if (!is_ack_only) {
+    this->_cc->on_packet_sent(sent_bytes);
     this->_set_loss_detection_alarm();
   }
 }
@@ -194,10 +161,7 @@ QUICLossDetector::_on_ack_received(const std::shared_ptr<const QUICAckFrame> &ac
   if (pi != this->_sent_packets.end()) {
     this->_latest_rtt = Thread::get_hrtime() - pi->second->time;
     // _latest_rtt is nanosecond but ack_frame->ack_delay is millisecond
-    if (this->_latest_rtt > static_cast<ink_hrtime>(HRTIME_MSECONDS(ack_frame->ack_delay()))) {
-      this->_latest_rtt -= HRTIME_MSECONDS(ack_frame->ack_delay());
-    }
-    this->_update_rtt(this->_latest_rtt);
+    this->_update_rtt(this->_latest_rtt, HRTIME_MSECONDS(ack_frame->ack_delay()), ack_frame->largest_acknowledged());
   }
 
   QUICLDDebug("Unacked packets %lu (retransmittable %u, includes %u handshake packets)", this->_sent_packets.size(),
@@ -220,69 +184,19 @@ QUICLossDetector::_on_ack_received(const std::shared_ptr<const QUICAckFrame> &ac
 }
 
 void
-QUICLossDetector::_on_packet_acked(QUICPacketNumber acked_packet_number)
+QUICLossDetector::_update_rtt(ink_hrtime latest_rtt, ink_hrtime ack_delay, QUICPacketNumber largest_acked)
 {
-  SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread());
-  QUICLDDebug("Packet number %" PRIu64 " has been acked", acked_packet_number);
-  // If a packet sent prior to RTO was acked, then the RTO
-  // was spurious.  Otherwise, inform congestion control.
-  if (this->_rto_count > 0 && acked_packet_number > this->_largest_sent_before_rto) {
-    // TODO cc->on_retransmission_timeout_verified();
-  }
-  this->_handshake_count = 0;
-  this->_tlp_count       = 0;
-  this->_rto_count       = 0;
-  this->_decrement_packet_count(acked_packet_number);
-  this->_sent_packets.erase(acked_packet_number);
-}
-
-void
-QUICLossDetector::_decrement_packet_count(QUICPacketNumber packet_number)
-{
-  SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread());
-  auto ite = this->_sent_packets.find(packet_number);
-  if (ite != this->_sent_packets.end()) {
-    if (ite->second->handshake) {
-      --this->_handshake_outstanding;
-    }
-    if (ite->second->retransmittable) {
-      --this->_retransmittable_outstanding;
+  // min_rtt ignores ack delay.
+  this->_min_rtt = std::min(this->_min_rtt, latest_rtt);
+  // Adjust for ack delay if it's plausible.
+  if (latest_rtt - this->_min_rtt > ack_delay) {
+    latest_rtt -= ack_delay;
+    // Only save into max ack delay if it's used for rtt calculation and is not ack only.
+    auto pi = this->_sent_packets.find(largest_acked);
+    if (pi != this->_sent_packets.end() && !pi->second->ack_only) {
+      this->_max_ack_delay = std::max(this->_max_ack_delay, ack_delay);
     }
   }
-}
-
-void
-QUICLossDetector::_on_loss_detection_alarm()
-{
-  if (this->_handshake_outstanding) {
-    // Handshake retransmission alarm.
-    this->_retransmit_handshake_packets();
-    this->_handshake_count++;
-  } else if (this->_loss_time != 0) {
-    // Early retransmit or Time Loss Detection
-    this->_detect_lost_packets(this->_largest_acked_packet);
-  } else if (this->_tlp_count < this->_MAX_TLPS) {
-    // Tail Loss Probe.
-    QUICLDDebug("TLP");
-    this->_send_one_packet();
-    this->_tlp_count++;
-  } else {
-    // RTO.
-    if (this->_rto_count == 0) {
-      this->_largest_sent_before_rto = this->_largest_sent_packet;
-    }
-    QUICLDDebug("RTO");
-    this->_send_two_packets();
-    this->_rto_count++;
-  }
-  QUICLDDebug("Unacked packets %lu (retransmittable %u, includes %u handshake packets)", this->_sent_packets.size(),
-              this->_retransmittable_outstanding.load(), this->_handshake_outstanding.load());
-  this->_set_loss_detection_alarm();
-}
-
-void
-QUICLossDetector::_update_rtt(ink_hrtime latest_rtt)
-{
   // Based on {{RFC6298}}.
   if (this->_smoothed_rtt == 0) {
     this->_smoothed_rtt = latest_rtt;
@@ -294,10 +208,29 @@ QUICLossDetector::_update_rtt(ink_hrtime latest_rtt)
 }
 
 void
+QUICLossDetector::_on_packet_acked(QUICPacketNumber acked_packet_number)
+{
+  SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread());
+  QUICLDDebug("Packet number %" PRIu64 " has been acked", acked_packet_number);
+  this->_cc->on_packet_acked(acked_packet_number);
+  // If a packet sent prior to RTO was acked, then the RTO
+  // was spurious.  Otherwise, inform congestion control.
+  if (this->_rto_count > 0 && acked_packet_number > this->_largest_sent_before_rto) {
+    this->_cc->on_retransmission_timeout_verified();
+  }
+  this->_handshake_count = 0;
+  this->_tlp_count       = 0;
+  this->_rto_count       = 0;
+  this->_remove_from_sent_packet_list(acked_packet_number);
+}
+
+void
 QUICLossDetector::_set_loss_detection_alarm()
 {
   ink_hrtime alarm_duration;
-  if (!this->_retransmittable_outstanding && this->_loss_detection_alarm) {
+  // Don't arm the alarm if there are no packets with
+  // retransmittable data in flight.
+  if (this->_retransmittable_outstanding == 0 && this->_loss_detection_alarm) {
     this->_loss_detection_alarm_at = 0;
     this->_loss_detection_alarm->cancel();
     this->_loss_detection_alarm = nullptr;
@@ -307,30 +240,25 @@ QUICLossDetector::_set_loss_detection_alarm()
   if (this->_handshake_outstanding) {
     // Handshake retransmission alarm.
     if (this->_smoothed_rtt == 0) {
-      alarm_duration = 2 * this->_DEFAULT_INITIAL_RTT;
+      alarm_duration = 2 * DEFAULT_INITIAL_RTT;
     } else {
       alarm_duration = 2 * this->_smoothed_rtt;
     }
-    alarm_duration = std::max(alarm_duration, this->_MIN_TLP_TIMEOUT);
+    alarm_duration = std::max(alarm_duration, MIN_TLP_TIMEOUT);
     alarm_duration = alarm_duration * (1 << this->_handshake_count);
     QUICLDDebug("Handshake retransmission alarm will be set");
   } else if (this->_loss_time != 0) {
     // Early retransmit timer or time loss detection.
-    alarm_duration = this->_loss_time - Thread::get_hrtime();
+    alarm_duration = this->_loss_time - this->_time_of_last_sent_packet;
     QUICLDDebug("Early retransmit timer or time loss detection will be set");
-  } else if (this->_tlp_count < this->_MAX_TLPS) {
+  } else if (this->_tlp_count < MAX_TLPS) {
     // Tail Loss Probe
-    if (this->_retransmittable_outstanding) {
-      alarm_duration = 1.5 * this->_smoothed_rtt + this->_DELAYED_ACK_TIMEOUT;
-    } else {
-      alarm_duration = this->_MIN_TLP_TIMEOUT;
-    }
-    alarm_duration = std::max(alarm_duration, 2 * this->_smoothed_rtt);
+    alarm_duration = std::max(static_cast<ink_hrtime>(1.5 * this->_smoothed_rtt + this->_max_ack_delay), MIN_TLP_TIMEOUT);
     QUICLDDebug("TLP alarm will be set");
   } else {
     // RTO alarm
     alarm_duration = this->_smoothed_rtt + 4 * this->_rttvar;
-    alarm_duration = std::max(alarm_duration, this->_MIN_RTO_TIMEOUT);
+    alarm_duration = std::max(alarm_duration, MIN_RTO_TIMEOUT);
     alarm_duration = alarm_duration * (1 << this->_rto_count);
     QUICLDDebug("RTO alarm will be set");
   }
@@ -338,7 +266,7 @@ QUICLossDetector::_set_loss_detection_alarm()
   if (this->_loss_detection_alarm_at) {
     this->_loss_detection_alarm_at = std::min(this->_loss_detection_alarm_at, Thread::get_hrtime() + alarm_duration);
   } else {
-    this->_loss_detection_alarm_at = Thread::get_hrtime() + alarm_duration;
+    this->_loss_detection_alarm_at = this->_time_of_last_sent_packet + alarm_duration;
   }
   QUICLDDebug("Loss detection alarm has been set to %" PRId64, alarm_duration);
 
@@ -347,26 +275,77 @@ QUICLossDetector::_set_loss_detection_alarm()
   }
 }
 
-std::set<QUICPacketNumber>
-QUICLossDetector::_determine_newly_acked_packets(const QUICAckFrame &ack_frame)
+void
+QUICLossDetector::_on_loss_detection_alarm()
 {
-  std::set<QUICPacketNumber> packets;
-  QUICPacketNumber x = ack_frame.largest_acknowledged();
-  for (uint64_t i = 0; i <= ack_frame.ack_block_section()->first_ack_block_length(); ++i) {
-    packets.insert(x--);
+  if (this->_handshake_outstanding) {
+    // Handshake retransmission alarm.
+    this->_retransmit_handshake_packets();
+    this->_handshake_count++;
+  } else if (this->_loss_time != 0) {
+    // Early retransmit or Time Loss Detection
+    this->_detect_lost_packets(this->_largest_acked_packet);
+  } else if (this->_tlp_count < MAX_TLPS) {
+    // Tail Loss Probe.
+    QUICLDDebug("TLP");
+    this->_send_one_packet();
+    this->_tlp_count++;
+  } else {
+    // RTO.
+    if (this->_rto_count == 0) {
+      this->_largest_sent_before_rto = this->_largest_sent_packet;
+    }
+    QUICLDDebug("RTO");
+    this->_send_two_packets();
+    this->_rto_count++;
   }
-  for (auto &&block : *(ack_frame.ack_block_section())) {
-    for (uint64_t i = 0; i <= block.gap(); ++i) {
-      x--;
+  QUICLDDebug("Unacked packets %lu (retransmittable %u, includes %u handshake packets)", this->_sent_packets.size(),
+              this->_retransmittable_outstanding.load(), this->_handshake_outstanding.load());
+  this->_set_loss_detection_alarm();
+}
+
+void
+QUICLossDetector::_detect_lost_packets(QUICPacketNumber largest_acked_packet_number)
+{
+  SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread());
+  this->_loss_time = 0;
+  std::set<QUICPacketNumber> lost_packets;
+  double delay_until_lost = INFINITY;
+
+  if (this->_time_loss_detection) {
+    delay_until_lost = (1 + this->_time_reordering_fraction) * std::max(this->_latest_rtt, this->_smoothed_rtt);
+  } else if (largest_acked_packet_number == this->_largest_sent_packet) {
+    // Early retransmit alarm.
+    delay_until_lost = 5 / 4 * std::max(this->_latest_rtt, this->_smoothed_rtt);
+  }
+
+  for (auto &unacked : this->_sent_packets) {
+    if (unacked.first >= largest_acked_packet_number) {
+      break;
     }
-    for (uint64_t i = 0; i <= block.length(); ++i) {
-      packets.insert(x--);
+    ink_hrtime time_since_sent = Thread::get_hrtime() - unacked.second->time;
+    uint64_t packet_delta      = largest_acked_packet_number - unacked.second->packet_number;
+    if (time_since_sent > delay_until_lost) {
+      lost_packets.insert(unacked.first);
+    } else if (packet_delta > this->_reordering_threshold) {
+      lost_packets.insert(unacked.first);
+    } else if (this->_loss_time == 0 && delay_until_lost != INFINITY) {
+      this->_loss_time = Thread::get_hrtime() + delay_until_lost - time_since_sent;
     }
   }
 
-  return packets;
+  // Inform the congestion controller of lost packets and
+  // lets it decide whether to retransmit immediately.
+  if (!lost_packets.empty()) {
+    this->_cc->on_packets_lost(lost_packets);
+    for (auto packet_number : lost_packets) {
+      this->_remove_from_sent_packet_list(packet_number);
+    }
+  }
 }
 
+// ===== Functions below are used on the spec but there're no pseudo code  =====
+
 void
 QUICLossDetector::_retransmit_handshake_packets()
 {
@@ -383,9 +362,7 @@ QUICLossDetector::_retransmit_handshake_packets()
   }
 
   for (auto packet_number : retransmitted_handshake_packets) {
-    this->_sent_packets.erase(packet_number);
-    --this->_handshake_outstanding;
-    --this->_retransmittable_outstanding;
+    this->_remove_from_sent_packet_list(packet_number);
   }
 }
 
@@ -418,3 +395,69 @@ QUICLossDetector::_send_two_packets()
     this->_transmitter->transmit_packet();
   }
 }
+
+// ===== Functions below are helper functions =====
+
+std::set<QUICPacketNumber>
+QUICLossDetector::_determine_newly_acked_packets(const QUICAckFrame &ack_frame)
+{
+  std::set<QUICPacketNumber> packets;
+  QUICPacketNumber x = ack_frame.largest_acknowledged();
+  for (uint64_t i = 0; i <= ack_frame.ack_block_section()->first_ack_block_length(); ++i) {
+    packets.insert(x--);
+  }
+  for (auto &&block : *(ack_frame.ack_block_section())) {
+    for (uint64_t i = 0; i <= block.gap(); ++i) {
+      x--;
+    }
+    for (uint64_t i = 0; i <= block.length(); ++i) {
+      packets.insert(x--);
+    }
+  }
+
+  return packets;
+}
+
+void
+QUICLossDetector::_add_to_sent_packet_list(QUICPacketNumber packet_number, std::unique_ptr<PacketInfo> packet_info)
+{
+  SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread());
+
+  // Add to the list
+  this->_sent_packets.insert(std::pair<QUICPacketNumber, std::unique_ptr<PacketInfo>>(packet_number, std::move(packet_info)));
+
+  // Increment counters
+  auto ite = this->_sent_packets.find(packet_number);
+  if (ite != this->_sent_packets.end()) {
+    if (ite->second->handshake) {
+      ++this->_handshake_outstanding;
+      ink_assert(this->_handshake_outstanding.load() > 0);
+    }
+    if (!ite->second->ack_only) {
+      ++this->_retransmittable_outstanding;
+      ink_assert(this->_retransmittable_outstanding.load() > 0);
+    }
+  }
+}
+
+void
+QUICLossDetector::_remove_from_sent_packet_list(QUICPacketNumber packet_number)
+{
+  SCOPED_MUTEX_LOCK(lock, this->mutex, this_ethread());
+
+  // Decrement counters
+  auto ite = this->_sent_packets.find(packet_number);
+  if (ite != this->_sent_packets.end()) {
+    if (ite->second->handshake) {
+      ink_assert(this->_handshake_outstanding.load() > 0);
+      --this->_handshake_outstanding;
+    }
+    if (!ite->second->ack_only) {
+      ink_assert(this->_retransmittable_outstanding.load() > 0);
+      --this->_retransmittable_outstanding;
+    }
+  }
+
+  // Remove from the list
+  this->_sent_packets.erase(packet_number);
+}
diff --git a/iocore/net/quic/QUICLossDetector.h b/iocore/net/quic/QUICLossDetector.h
index ce2c629..e67598b 100644
--- a/iocore/net/quic/QUICLossDetector.h
+++ b/iocore/net/quic/QUICLossDetector.h
@@ -57,7 +57,7 @@ private:
   struct PacketInfo {
     QUICPacketNumber packet_number;
     ink_hrtime time;
-    bool retransmittable;
+    bool ack_only;
     bool handshake;
     size_t bytes;
     QUICPacketUPtr packet;
@@ -67,35 +67,32 @@ private:
 
   // TODO QUICCongestionController *cc = nullptr;
 
-  // 3.2.1.  Constants of interest
-  uint32_t _MAX_TLPS               = 2;
-  uint32_t _REORDERING_THRESHOLD   = 3;
-  double _TIME_REORDERING_FRACTION = 1 / 8;
-  ink_hrtime _MIN_TLP_TIMEOUT      = HRTIME_MSECONDS(10);
-  ink_hrtime _MIN_RTO_TIMEOUT      = HRTIME_MSECONDS(200);
-  ink_hrtime _DELAYED_ACK_TIMEOUT  = HRTIME_MSECONDS(25);
-  ink_hrtime _DEFAULT_INITIAL_RTT  = HRTIME_MSECONDS(100);
-
-  // 3.2.2.  Variables of interest
+  // 3.4.2.  Variables of interest (draft-08)
+  // Keep the order as the same as the spec so that we can see the difference easily.
   Action *_loss_detection_alarm        = nullptr;
   uint32_t _handshake_count            = 0;
   uint32_t _tlp_count                  = 0;
   uint32_t _rto_count                  = 0;
   uint32_t _largest_sent_before_rto    = 0;
+  ink_hrtime _time_of_last_sent_packet = 0;
   uint32_t _largest_sent_packet        = 0;
   uint32_t _largest_acked_packet       = 0;
-  ink_hrtime _time_of_last_sent_packet = 0;
   ink_hrtime _latest_rtt               = 0;
   ink_hrtime _smoothed_rtt             = 0;
   ink_hrtime _rttvar                   = 0;
+  ink_hrtime _min_rtt                  = 0;
+  ink_hrtime _max_ack_delay            = 0;
   uint32_t _reordering_threshold;
   double _time_reordering_fraction;
   ink_hrtime _loss_time = 0;
   std::map<QUICPacketNumber, std::unique_ptr<PacketInfo>> _sent_packets;
 
+  // These are not defined on the spec but expected to be count
+  // These counter have to be updated when inserting / erasing packets from _sent_packets with following functions.
   std::atomic<uint32_t> _handshake_outstanding;
   std::atomic<uint32_t> _retransmittable_outstanding;
-  void _decrement_packet_count(QUICPacketNumber packet_number);
+  void _add_to_sent_packet_list(QUICPacketNumber packet_number, std::unique_ptr<PacketInfo> packet_info);
+  void _remove_from_sent_packet_list(QUICPacketNumber packet_number);
 
   /*
    * Because this alarm will be reset on every packet transmission, to reduce number of events,
@@ -103,11 +100,11 @@ private:
    */
   ink_hrtime _loss_detection_alarm_at = 0;
 
-  void _on_packet_sent(QUICPacketNumber packet_number, bool is_retransmittable, bool is_handshake, size_t sent_bytes,
+  void _on_packet_sent(QUICPacketNumber packet_number, bool is_ack_only, bool is_handshake, size_t sent_bytes,
                        QUICPacketUPtr packet);
   void _on_ack_received(const std::shared_ptr<const QUICAckFrame> &ack_frame);
   void _on_packet_acked(QUICPacketNumber acked_packet_number);
-  void _update_rtt(ink_hrtime latest_rtt);
+  void _update_rtt(ink_hrtime latest_rtt, ink_hrtime ack_delay, QUICPacketNumber largest_acked);
   void _detect_lost_packets(QUICPacketNumber largest_acked);
   void _set_loss_detection_alarm();
   void _on_loss_detection_alarm();

-- 
To stop receiving notification emails like this one, please contact
['"commits@trafficserver.apache.org" <co...@trafficserver.apache.org>'].