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 |