| OLD | NEW |
| (Empty) |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "net/quic/congestion_control/general_loss_algorithm.h" | |
| 6 | |
| 7 #include "net/quic/congestion_control/rtt_stats.h" | |
| 8 #include "net/quic/quic_bug_tracker.h" | |
| 9 #include "net/quic/quic_flags.h" | |
| 10 #include "net/quic/quic_protocol.h" | |
| 11 | |
| 12 namespace net { | |
| 13 | |
| 14 namespace { | |
| 15 | |
| 16 // The minimum delay before a packet will be considered lost, | |
| 17 // regardless of SRTT. Half of the minimum TLP, since the loss algorithm only | |
| 18 // triggers when a nack has been receieved for the packet. | |
| 19 static const size_t kMinLossDelayMs = 5; | |
| 20 | |
| 21 // Default fraction of an RTT the algorithm waits before determining a packet is | |
| 22 // lost due to early retransmission by time based loss detection. | |
| 23 static const int kDefaultLossDelayShift = 2; | |
| 24 // Default fraction of an RTT when doing adaptive loss detection. | |
| 25 static const int kDefaultAdaptiveLossDelayShift = 4; | |
| 26 | |
| 27 } // namespace | |
| 28 | |
| 29 GeneralLossAlgorithm::GeneralLossAlgorithm() | |
| 30 : loss_type_(kNack), | |
| 31 loss_detection_timeout_(QuicTime::Zero()), | |
| 32 largest_sent_on_spurious_retransmit_(0), | |
| 33 reordering_shift_(kDefaultLossDelayShift) {} | |
| 34 | |
| 35 GeneralLossAlgorithm::GeneralLossAlgorithm(LossDetectionType loss_type) | |
| 36 : loss_type_(loss_type), | |
| 37 loss_detection_timeout_(QuicTime::Zero()), | |
| 38 largest_sent_on_spurious_retransmit_(0), | |
| 39 reordering_shift_(loss_type == kAdaptiveTime | |
| 40 ? kDefaultAdaptiveLossDelayShift | |
| 41 : kDefaultLossDelayShift) {} | |
| 42 | |
| 43 LossDetectionType GeneralLossAlgorithm::GetLossDetectionType() const { | |
| 44 return loss_type_; | |
| 45 } | |
| 46 | |
| 47 void GeneralLossAlgorithm::SetLossDetectionType(LossDetectionType loss_type) { | |
| 48 loss_type_ = loss_type; | |
| 49 if (loss_type_ == kAdaptiveTime) { | |
| 50 reordering_shift_ = kDefaultAdaptiveLossDelayShift; | |
| 51 } | |
| 52 } | |
| 53 | |
| 54 // Uses nack counts to decide when packets are lost. | |
| 55 void GeneralLossAlgorithm::DetectLosses( | |
| 56 const QuicUnackedPacketMap& unacked_packets, | |
| 57 QuicTime time, | |
| 58 const RttStats& rtt_stats, | |
| 59 QuicPacketNumber largest_newly_acked, | |
| 60 SendAlgorithmInterface::CongestionVector* packets_lost) { | |
| 61 QuicPacketNumber largest_observed = unacked_packets.largest_observed(); | |
| 62 if (FLAGS_quic_loss_recovery_use_largest_acked) { | |
| 63 largest_observed = largest_newly_acked; | |
| 64 } | |
| 65 loss_detection_timeout_ = QuicTime::Zero(); | |
| 66 QuicTime::Delta max_rtt = | |
| 67 std::max(rtt_stats.previous_srtt(), rtt_stats.latest_rtt()); | |
| 68 QuicTime::Delta loss_delay = | |
| 69 std::max(QuicTime::Delta::FromMilliseconds(kMinLossDelayMs), | |
| 70 max_rtt + (max_rtt >> reordering_shift_)); | |
| 71 QuicPacketNumber packet_number = unacked_packets.GetLeastUnacked(); | |
| 72 for (QuicUnackedPacketMap::const_iterator it = unacked_packets.begin(); | |
| 73 it != unacked_packets.end() && packet_number <= largest_observed; | |
| 74 ++it, ++packet_number) { | |
| 75 if (!it->in_flight) { | |
| 76 continue; | |
| 77 } | |
| 78 | |
| 79 if (loss_type_ == kNack) { | |
| 80 // FACK based loss detection. | |
| 81 if (largest_observed - packet_number >= | |
| 82 kNumberOfNacksBeforeRetransmission) { | |
| 83 packets_lost->push_back(std::make_pair(packet_number, it->bytes_sent)); | |
| 84 continue; | |
| 85 } | |
| 86 } | |
| 87 | |
| 88 // Only early retransmit(RFC5827) when the last packet gets acked and | |
| 89 // there are retransmittable packets in flight. | |
| 90 // This also implements a timer-protected variant of FACK. | |
| 91 if ((!it->retransmittable_frames.empty() && | |
| 92 unacked_packets.largest_sent_packet() == largest_observed) || | |
| 93 (loss_type_ == kTime || loss_type_ == kAdaptiveTime)) { | |
| 94 QuicTime when_lost = it->sent_time + loss_delay; | |
| 95 if (time < when_lost) { | |
| 96 loss_detection_timeout_ = when_lost; | |
| 97 break; | |
| 98 } | |
| 99 packets_lost->push_back(std::make_pair(packet_number, it->bytes_sent)); | |
| 100 continue; | |
| 101 } | |
| 102 | |
| 103 // NACK-based loss detection allows for a max reordering window of 1 RTT. | |
| 104 if (it->sent_time + rtt_stats.smoothed_rtt() < | |
| 105 unacked_packets.GetTransmissionInfo(largest_observed).sent_time) { | |
| 106 packets_lost->push_back(std::make_pair(packet_number, it->bytes_sent)); | |
| 107 continue; | |
| 108 } | |
| 109 } | |
| 110 } | |
| 111 | |
| 112 QuicTime GeneralLossAlgorithm::GetLossTimeout() const { | |
| 113 return loss_detection_timeout_; | |
| 114 } | |
| 115 | |
| 116 void GeneralLossAlgorithm::SpuriousRetransmitDetected( | |
| 117 const QuicUnackedPacketMap& unacked_packets, | |
| 118 QuicTime time, | |
| 119 const RttStats& rtt_stats, | |
| 120 QuicPacketNumber spurious_retransmission) { | |
| 121 if (loss_type_ != kAdaptiveTime || reordering_shift_ == 0) { | |
| 122 return; | |
| 123 } | |
| 124 if (spurious_retransmission <= largest_sent_on_spurious_retransmit_) { | |
| 125 return; | |
| 126 } | |
| 127 largest_sent_on_spurious_retransmit_ = unacked_packets.largest_sent_packet(); | |
| 128 // Calculate the extra time needed so this wouldn't have been declared lost. | |
| 129 // Extra time needed is based on how long it's been since the spurious | |
| 130 // retransmission was sent, because the SRTT and latest RTT may have changed. | |
| 131 QuicTime::Delta extra_time_needed = | |
| 132 time - | |
| 133 unacked_packets.GetTransmissionInfo(spurious_retransmission).sent_time; | |
| 134 // Increase the reordering fraction until enough time would be allowed. | |
| 135 QuicTime::Delta max_rtt = | |
| 136 std::max(rtt_stats.previous_srtt(), rtt_stats.latest_rtt()); | |
| 137 QuicTime::Delta proposed_extra_time(QuicTime::Delta::Zero()); | |
| 138 do { | |
| 139 proposed_extra_time = max_rtt >> reordering_shift_; | |
| 140 --reordering_shift_; | |
| 141 } while (proposed_extra_time < extra_time_needed && reordering_shift_ > 0); | |
| 142 } | |
| 143 | |
| 144 } // namespace net | |
| OLD | NEW |