OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "net/quic/quic_unacked_packet_map.h" | 5 #include "net/quic/quic_unacked_packet_map.h" |
6 | 6 |
7 #include "base/logging.h" | 7 #include "base/logging.h" |
8 #include "base/stl_util.h" | 8 #include "base/stl_util.h" |
9 #include "net/quic/quic_bug_tracker.h" | 9 #include "net/quic/quic_bug_tracker.h" |
10 #include "net/quic/quic_connection_stats.h" | 10 #include "net/quic/quic_connection_stats.h" |
11 #include "net/quic/quic_flags.h" | 11 #include "net/quic/quic_flags.h" |
12 #include "net/quic/quic_utils.h" | 12 #include "net/quic/quic_utils.h" |
13 #include "net/quic/quic_utils_chromium.h" | 13 #include "net/quic/quic_utils_chromium.h" |
14 | 14 |
15 using std::max; | 15 using std::max; |
16 | 16 |
17 namespace net { | 17 namespace net { |
18 | 18 |
19 QuicUnackedPacketMap::QuicUnackedPacketMap() | 19 QuicUnackedPacketMap::QuicUnackedPacketMap() |
20 : largest_sent_packet_(0), | 20 : largest_sent_packet_(0), |
21 largest_observed_(0), | 21 largest_observed_(0), |
22 least_unacked_(1), | 22 least_unacked_(1), |
23 bytes_in_flight_(0), | 23 bytes_in_flight_(0), |
24 pending_crypto_packet_count_(0), | 24 pending_crypto_packet_count_(0) {} |
25 track_single_retransmission_(FLAGS_quic_track_single_retransmission) {} | |
26 | 25 |
27 QuicUnackedPacketMap::~QuicUnackedPacketMap() { | 26 QuicUnackedPacketMap::~QuicUnackedPacketMap() { |
28 QuicPacketNumber index = least_unacked_; | 27 QuicPacketNumber index = least_unacked_; |
29 for (UnackedPacketMap::iterator it = unacked_packets_.begin(); | 28 for (UnackedPacketMap::iterator it = unacked_packets_.begin(); |
30 it != unacked_packets_.end(); ++it, ++index) { | 29 it != unacked_packets_.end(); ++it, ++index) { |
31 QuicUtils::DeleteFrames(&it->retransmittable_frames); | 30 QuicUtils::DeleteFrames(&it->retransmittable_frames); |
32 // Only delete all_transmissions once, for the newest packet. | |
33 if (it->all_transmissions != nullptr && | |
34 index == *it->all_transmissions->rbegin()) { | |
35 delete it->all_transmissions; | |
36 } | |
37 } | 31 } |
38 } | 32 } |
39 | 33 |
40 void QuicUnackedPacketMap::AddSentPacket(SerializedPacket* packet, | 34 void QuicUnackedPacketMap::AddSentPacket(SerializedPacket* packet, |
41 QuicPacketNumber old_packet_number, | 35 QuicPacketNumber old_packet_number, |
42 TransmissionType transmission_type, | 36 TransmissionType transmission_type, |
43 QuicTime sent_time, | 37 QuicTime sent_time, |
44 QuicByteCount bytes_sent, | 38 QuicByteCount bytes_sent, |
45 bool set_in_flight) { | 39 bool set_in_flight) { |
46 QuicPacketNumber packet_number = packet->packet_number; | 40 QuicPacketNumber packet_number = packet->packet_number; |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
122 info->has_crypto_handshake = transmission_info->has_crypto_handshake; | 116 info->has_crypto_handshake = transmission_info->has_crypto_handshake; |
123 transmission_info->has_crypto_handshake = false; | 117 transmission_info->has_crypto_handshake = false; |
124 info->needs_padding = transmission_info->needs_padding; | 118 info->needs_padding = transmission_info->needs_padding; |
125 | 119 |
126 // Transfer the AckListeners if any are present. | 120 // Transfer the AckListeners if any are present. |
127 info->ack_listeners.swap(transmission_info->ack_listeners); | 121 info->ack_listeners.swap(transmission_info->ack_listeners); |
128 QUIC_BUG_IF(frames == nullptr) | 122 QUIC_BUG_IF(frames == nullptr) |
129 << "Attempt to retransmit packet with no " | 123 << "Attempt to retransmit packet with no " |
130 << "retransmittable frames: " << old_packet_number; | 124 << "retransmittable frames: " << old_packet_number; |
131 | 125 |
132 // Only keep one transmission older than largest observed, because only the | |
133 // most recent is expected to possibly be a spurious retransmission. | |
134 if (!track_single_retransmission_) { | |
135 while (transmission_info->all_transmissions != nullptr && | |
136 transmission_info->all_transmissions->size() > 1 && | |
137 *(++transmission_info->all_transmissions->begin()) < | |
138 largest_observed_) { | |
139 QuicPacketNumber old_transmission = | |
140 *transmission_info->all_transmissions->begin(); | |
141 TransmissionInfo* old_info = | |
142 &unacked_packets_[old_transmission - least_unacked_]; | |
143 // Don't remove old packets if they're still in flight. | |
144 if (old_info->in_flight) { | |
145 break; | |
146 } | |
147 old_info->all_transmissions->pop_front(); | |
148 // This will cause the packet be removed in RemoveObsoletePackets. | |
149 old_info->all_transmissions = nullptr; | |
150 } | |
151 } | |
152 // Don't link old transmissions to new ones when version or | 126 // Don't link old transmissions to new ones when version or |
153 // encryption changes. | 127 // encryption changes. |
154 if (transmission_type == ALL_INITIAL_RETRANSMISSION || | 128 if (transmission_type == ALL_INITIAL_RETRANSMISSION || |
155 transmission_type == ALL_UNACKED_RETRANSMISSION) { | 129 transmission_type == ALL_UNACKED_RETRANSMISSION) { |
156 RemoveAckability(transmission_info); | 130 RemoveAckability(transmission_info); |
157 } else { | 131 } else { |
158 if (track_single_retransmission_) { | 132 transmission_info->retransmission = new_packet_number; |
159 transmission_info->retransmission = new_packet_number; | |
160 } else { | |
161 if (transmission_info->all_transmissions == nullptr) { | |
162 transmission_info->all_transmissions = new PacketNumberList(); | |
163 transmission_info->all_transmissions->push_back(old_packet_number); | |
164 } | |
165 transmission_info->all_transmissions->push_back(new_packet_number); | |
166 } | |
167 } | |
168 if (!track_single_retransmission_) { | |
169 info->all_transmissions = transmission_info->all_transmissions; | |
170 } | 133 } |
171 // Proactively remove obsolete packets so the least unacked can be raised. | 134 // Proactively remove obsolete packets so the least unacked can be raised. |
172 RemoveObsoletePackets(); | 135 RemoveObsoletePackets(); |
173 } | 136 } |
174 | 137 |
175 bool QuicUnackedPacketMap::HasRetransmittableFrames( | 138 bool QuicUnackedPacketMap::HasRetransmittableFrames( |
176 QuicPacketNumber packet_number) const { | 139 QuicPacketNumber packet_number) const { |
177 DCHECK_GE(packet_number, least_unacked_); | 140 DCHECK_GE(packet_number, least_unacked_); |
178 DCHECK_LT(packet_number, least_unacked_ + unacked_packets_.size()); | 141 DCHECK_LT(packet_number, least_unacked_ + unacked_packets_.size()); |
179 return !unacked_packets_[packet_number - least_unacked_] | 142 return !unacked_packets_[packet_number - least_unacked_] |
180 .retransmittable_frames.empty(); | 143 .retransmittable_frames.empty(); |
181 } | 144 } |
182 | 145 |
183 void QuicUnackedPacketMap::NackPacket(QuicPacketNumber packet_number, | 146 void QuicUnackedPacketMap::NackPacket(QuicPacketNumber packet_number, |
184 uint16_t min_nacks) { | 147 uint16_t min_nacks) { |
185 DCHECK_GE(packet_number, least_unacked_); | 148 DCHECK_GE(packet_number, least_unacked_); |
186 DCHECK_LT(packet_number, least_unacked_ + unacked_packets_.size()); | 149 DCHECK_LT(packet_number, least_unacked_ + unacked_packets_.size()); |
187 unacked_packets_[packet_number - least_unacked_].nack_count = max( | 150 unacked_packets_[packet_number - least_unacked_].nack_count = max( |
188 min_nacks, unacked_packets_[packet_number - least_unacked_].nack_count); | 151 min_nacks, unacked_packets_[packet_number - least_unacked_].nack_count); |
189 } | 152 } |
190 | 153 |
191 void QuicUnackedPacketMap::RemoveRetransmittability(TransmissionInfo* info) { | 154 void QuicUnackedPacketMap::RemoveRetransmittability(TransmissionInfo* info) { |
192 if (track_single_retransmission_) { | 155 while (info->retransmission != 0) { |
193 while (info->retransmission != 0) { | 156 const QuicPacketNumber retransmission = info->retransmission; |
194 const QuicPacketNumber retransmission = info->retransmission; | 157 info->retransmission = 0; |
195 info->retransmission = 0; | 158 info = &unacked_packets_[retransmission - least_unacked_]; |
196 info = &unacked_packets_[retransmission - least_unacked_]; | |
197 } | |
198 MaybeRemoveRetransmittableFrames(info); | |
199 return; | |
200 } | 159 } |
201 PacketNumberList* all_transmissions = info->all_transmissions; | 160 MaybeRemoveRetransmittableFrames(info); |
202 if (all_transmissions == nullptr) { | |
203 MaybeRemoveRetransmittableFrames(info); | |
204 return; | |
205 } | |
206 // TODO(ianswett): Consider adding a check to ensure there are retransmittable | |
207 // frames associated with this packet. | |
208 for (QuicPacketNumber packet_number : *all_transmissions) { | |
209 TransmissionInfo* transmission_info = | |
210 &unacked_packets_[packet_number - least_unacked_]; | |
211 MaybeRemoveRetransmittableFrames(transmission_info); | |
212 transmission_info->all_transmissions = nullptr; | |
213 } | |
214 delete all_transmissions; | |
215 } | 161 } |
216 | 162 |
217 void QuicUnackedPacketMap::RemoveRetransmittability( | 163 void QuicUnackedPacketMap::RemoveRetransmittability( |
218 QuicPacketNumber packet_number) { | 164 QuicPacketNumber packet_number) { |
219 DCHECK_GE(packet_number, least_unacked_); | 165 DCHECK_GE(packet_number, least_unacked_); |
220 DCHECK_LT(packet_number, least_unacked_ + unacked_packets_.size()); | 166 DCHECK_LT(packet_number, least_unacked_ + unacked_packets_.size()); |
221 TransmissionInfo* info = &unacked_packets_[packet_number - least_unacked_]; | 167 TransmissionInfo* info = &unacked_packets_[packet_number - least_unacked_]; |
222 RemoveRetransmittability(info); | 168 RemoveRetransmittability(info); |
223 } | 169 } |
224 | 170 |
225 void QuicUnackedPacketMap::RemoveAckability(TransmissionInfo* info) { | 171 void QuicUnackedPacketMap::RemoveAckability(TransmissionInfo* info) { |
226 DCHECK(info->retransmittable_frames.empty()); | 172 DCHECK(info->retransmittable_frames.empty()); |
| 173 DCHECK_EQ(0u, info->retransmission); |
227 info->is_unackable = true; | 174 info->is_unackable = true; |
228 if (track_single_retransmission_) { | |
229 DCHECK_EQ(0u, info->retransmission); | |
230 return; | |
231 } | |
232 PacketNumberList* all_transmissions = info->all_transmissions; | |
233 if (all_transmissions == nullptr) { | |
234 return; | |
235 } | |
236 for (QuicPacketNumber packet_number : *all_transmissions) { | |
237 TransmissionInfo* transmission_info = | |
238 &unacked_packets_[packet_number - least_unacked_]; | |
239 transmission_info->all_transmissions = nullptr; | |
240 transmission_info->is_unackable = true; | |
241 } | |
242 delete all_transmissions; | |
243 } | 175 } |
244 | 176 |
245 void QuicUnackedPacketMap::MaybeRemoveRetransmittableFrames( | 177 void QuicUnackedPacketMap::MaybeRemoveRetransmittableFrames( |
246 TransmissionInfo* transmission_info) { | 178 TransmissionInfo* transmission_info) { |
247 if (transmission_info->has_crypto_handshake) { | 179 if (transmission_info->has_crypto_handshake) { |
248 DCHECK(!transmission_info->retransmittable_frames.empty()); | 180 DCHECK(!transmission_info->retransmittable_frames.empty()); |
249 DCHECK_LT(0u, pending_crypto_packet_count_); | 181 DCHECK_LT(0u, pending_crypto_packet_count_); |
250 --pending_crypto_packet_count_; | 182 --pending_crypto_packet_count_; |
251 transmission_info->has_crypto_handshake = false; | 183 transmission_info->has_crypto_handshake = false; |
252 } | 184 } |
(...skipping 18 matching lines...) Expand all Loading... |
271 const TransmissionInfo& info) const { | 203 const TransmissionInfo& info) const { |
272 // Packet contributes to congestion control if it is considered inflight. | 204 // Packet contributes to congestion control if it is considered inflight. |
273 return info.in_flight; | 205 return info.in_flight; |
274 } | 206 } |
275 | 207 |
276 bool QuicUnackedPacketMap::IsPacketUsefulForRetransmittableData( | 208 bool QuicUnackedPacketMap::IsPacketUsefulForRetransmittableData( |
277 const TransmissionInfo& info) const { | 209 const TransmissionInfo& info) const { |
278 // Packet may have retransmittable frames, or the data may have been | 210 // Packet may have retransmittable frames, or the data may have been |
279 // retransmitted with a new packet number. | 211 // retransmitted with a new packet number. |
280 return !info.retransmittable_frames.empty() || | 212 return !info.retransmittable_frames.empty() || |
281 info.all_transmissions != nullptr || | |
282 // Allow for an extra 1 RTT before stopping to track old packets. | 213 // Allow for an extra 1 RTT before stopping to track old packets. |
283 info.retransmission > largest_observed_; | 214 info.retransmission > largest_observed_; |
284 } | 215 } |
285 | 216 |
286 bool QuicUnackedPacketMap::IsPacketUseless(QuicPacketNumber packet_number, | 217 bool QuicUnackedPacketMap::IsPacketUseless(QuicPacketNumber packet_number, |
287 const TransmissionInfo& info) const { | 218 const TransmissionInfo& info) const { |
288 return !IsPacketUsefulForMeasuringRtt(packet_number, info) && | 219 return !IsPacketUsefulForMeasuringRtt(packet_number, info) && |
289 !IsPacketUsefulForCongestionControl(info) && | 220 !IsPacketUsefulForCongestionControl(info) && |
290 !IsPacketUsefulForRetransmittableData(info); | 221 !IsPacketUsefulForRetransmittableData(info); |
291 } | 222 } |
(...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
421 } | 352 } |
422 } | 353 } |
423 return false; | 354 return false; |
424 } | 355 } |
425 | 356 |
426 QuicPacketNumber QuicUnackedPacketMap::GetLeastUnacked() const { | 357 QuicPacketNumber QuicUnackedPacketMap::GetLeastUnacked() const { |
427 return least_unacked_; | 358 return least_unacked_; |
428 } | 359 } |
429 | 360 |
430 } // namespace net | 361 } // namespace net |
OLD | NEW |