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
3 // found in the LICENSE file.
5 #include "net/quic/quic_unacked_packet_map.h"
7 #include "base/logging.h"
8 #include "base/stl_util.h"
9 #include "net/quic/quic_ack_notifier_manager.h"
10 #include "net/quic/quic_connection_stats.h"
11 #include "net/quic/quic_flags.h"
12 #include "net/quic/quic_utils_chromium.h"
18 QuicUnackedPacketMap::QuicUnackedPacketMap(
19 AckNotifierManager
* ack_notifier_manager
)
20 : largest_sent_packet_(0),
24 pending_crypto_packet_count_(0),
25 ack_notifier_manager_(ack_notifier_manager
) {
28 QuicUnackedPacketMap::~QuicUnackedPacketMap() {
29 QuicPacketSequenceNumber index
= least_unacked_
;
30 for (UnackedPacketMap::iterator it
= unacked_packets_
.begin();
31 it
!= unacked_packets_
.end(); ++it
, ++index
) {
32 delete it
->retransmittable_frames
;
33 // Only delete all_transmissions once, for the newest packet.
34 if (it
->all_transmissions
!= nullptr &&
35 index
== *it
->all_transmissions
->rbegin()) {
36 delete it
->all_transmissions
;
41 void QuicUnackedPacketMap::AddSentPacket(
42 const SerializedPacket
& packet
,
43 QuicPacketSequenceNumber old_sequence_number
,
44 TransmissionType transmission_type
,
46 QuicByteCount bytes_sent
,
48 QuicPacketSequenceNumber sequence_number
= packet
.sequence_number
;
49 LOG_IF(DFATAL
, largest_sent_packet_
> sequence_number
);
50 DCHECK_GE(sequence_number
, least_unacked_
+ unacked_packets_
.size());
51 while (least_unacked_
+ unacked_packets_
.size() < sequence_number
) {
52 unacked_packets_
.push_back(TransmissionInfo());
53 unacked_packets_
.back().is_unackable
= true;
56 TransmissionInfo
info(packet
.retransmittable_frames
,
57 packet
.sequence_number_length
, transmission_type
,
58 sent_time
, bytes_sent
, packet
.is_fec_packet
);
59 if (old_sequence_number
== 0) {
60 if (packet
.retransmittable_frames
!= nullptr &&
61 packet
.retransmittable_frames
->HasCryptoHandshake() == IS_HANDSHAKE
) {
62 ++pending_crypto_packet_count_
;
65 TransferRetransmissionInfo(
66 old_sequence_number
, sequence_number
, transmission_type
, &info
);
69 largest_sent_packet_
= sequence_number
;
71 bytes_in_flight_
+= bytes_sent
;
72 info
.in_flight
= true;
74 unacked_packets_
.push_back(info
);
77 void QuicUnackedPacketMap::RemoveObsoletePackets() {
78 while (!unacked_packets_
.empty()) {
79 if (!IsPacketUseless(least_unacked_
, unacked_packets_
.front())) {
86 void QuicUnackedPacketMap::TransferRetransmissionInfo(
87 QuicPacketSequenceNumber old_sequence_number
,
88 QuicPacketSequenceNumber new_sequence_number
,
89 TransmissionType transmission_type
,
90 TransmissionInfo
* info
) {
91 if (old_sequence_number
< least_unacked_
||
92 old_sequence_number
> largest_sent_packet_
) {
93 LOG(DFATAL
) << "Old TransmissionInfo no longer exists for:"
94 << old_sequence_number
<< " least_unacked:" << least_unacked_
95 << " largest_sent:" << largest_sent_packet_
;
98 DCHECK_GE(new_sequence_number
, least_unacked_
+ unacked_packets_
.size());
99 DCHECK_NE(NOT_RETRANSMISSION
, transmission_type
);
101 TransmissionInfo
* transmission_info
=
102 &unacked_packets_
.at(old_sequence_number
- least_unacked_
);
103 RetransmittableFrames
* frames
= transmission_info
->retransmittable_frames
;
104 transmission_info
->retransmittable_frames
= nullptr;
105 LOG_IF(DFATAL
, frames
== nullptr)
106 << "Attempt to retransmit packet with no "
107 << "retransmittable frames: " << old_sequence_number
;
109 // Only keep one transmission older than largest observed, because only the
110 // most recent is expected to possibly be a spurious retransmission.
111 while (transmission_info
->all_transmissions
!= nullptr &&
112 transmission_info
->all_transmissions
->size() > 1 &&
113 *(++transmission_info
->all_transmissions
->begin()) <
115 QuicPacketSequenceNumber old_transmission
=
116 *transmission_info
->all_transmissions
->begin();
117 TransmissionInfo
* old_info
=
118 &unacked_packets_
[old_transmission
- least_unacked_
];
119 // Don't remove old packets if they're still in flight.
120 if (old_info
->in_flight
) {
123 old_info
->all_transmissions
->pop_front();
124 // This will cause the packet be removed in RemoveObsoletePackets.
125 old_info
->all_transmissions
= nullptr;
127 // Don't link old transmissions to new ones when version or
128 // encryption changes.
129 if (transmission_type
== ALL_INITIAL_RETRANSMISSION
||
130 transmission_type
== ALL_UNACKED_RETRANSMISSION
) {
131 RemoveAckability(transmission_info
);
133 if (transmission_info
->all_transmissions
== nullptr) {
134 transmission_info
->all_transmissions
= new SequenceNumberList();
135 transmission_info
->all_transmissions
->push_back(old_sequence_number
);
137 transmission_info
->all_transmissions
->push_back(new_sequence_number
);
139 info
->retransmittable_frames
= frames
;
140 info
->all_transmissions
= transmission_info
->all_transmissions
;
141 // Proactively remove obsolete packets so the least unacked can be raised.
142 RemoveObsoletePackets();
145 void QuicUnackedPacketMap::ClearAllPreviousRetransmissions() {
146 while (!unacked_packets_
.empty() && least_unacked_
< largest_observed_
) {
147 // If this packet is in flight, or has retransmittable data, then there is
148 // no point in clearing out any further packets, because they would not
149 // affect the high water mark.
150 TransmissionInfo
* info
= &unacked_packets_
.front();
151 if (info
->in_flight
|| info
->retransmittable_frames
!= nullptr) {
155 if (info
->all_transmissions
!= nullptr) {
156 if (info
->all_transmissions
->size() < 2) {
157 LOG(DFATAL
) << "all_transmissions must be nullptr or have multiple "
158 << "elements. size:" << info
->all_transmissions
->size();
159 delete info
->all_transmissions
;
160 info
->all_transmissions
= nullptr;
162 LOG_IF(DFATAL
, info
->all_transmissions
->front() != least_unacked_
)
163 << "The first element of all transmissions should be least unacked:"
164 << least_unacked_
<< " but is:" << info
->all_transmissions
->front();
165 info
->all_transmissions
->pop_front();
166 if (info
->all_transmissions
->size() == 1) {
167 // Set the newer transmission's 'all_transmissions' entry to nullptr.
168 QuicPacketSequenceNumber new_transmission
=
169 info
->all_transmissions
->front();
170 TransmissionInfo
* new_info
=
171 &unacked_packets_
.at(new_transmission
- least_unacked_
);
172 delete new_info
->all_transmissions
;
173 new_info
->all_transmissions
= nullptr;
181 bool QuicUnackedPacketMap::HasRetransmittableFrames(
182 QuicPacketSequenceNumber sequence_number
) const {
183 DCHECK_GE(sequence_number
, least_unacked_
);
184 DCHECK_LT(sequence_number
, least_unacked_
+ unacked_packets_
.size());
185 return unacked_packets_
[sequence_number
- least_unacked_
]
186 .retransmittable_frames
!= nullptr;
189 void QuicUnackedPacketMap::NackPacket(QuicPacketSequenceNumber sequence_number
,
190 QuicPacketCount min_nacks
) {
191 DCHECK_GE(sequence_number
, least_unacked_
);
192 DCHECK_LT(sequence_number
, least_unacked_
+ unacked_packets_
.size());
193 unacked_packets_
[sequence_number
- least_unacked_
].nack_count
=
195 unacked_packets_
[sequence_number
- least_unacked_
].nack_count
);
198 void QuicUnackedPacketMap::RemoveRetransmittability(
199 QuicPacketSequenceNumber sequence_number
) {
200 DCHECK_GE(sequence_number
, least_unacked_
);
201 DCHECK_LT(sequence_number
, least_unacked_
+ unacked_packets_
.size());
202 TransmissionInfo
* info
= &unacked_packets_
[sequence_number
- least_unacked_
];
203 SequenceNumberList
* all_transmissions
= info
->all_transmissions
;
204 if (all_transmissions
== nullptr) {
205 MaybeRemoveRetransmittableFrames(info
);
208 // TODO(ianswett): Consider adding a check to ensure there are retransmittable
209 // frames associated with this packet.
210 for (QuicPacketSequenceNumber sequence_number
: *all_transmissions
) {
211 TransmissionInfo
* transmission_info
=
212 &unacked_packets_
[sequence_number
- least_unacked_
];
213 MaybeRemoveRetransmittableFrames(transmission_info
);
214 transmission_info
->all_transmissions
= nullptr;
216 delete all_transmissions
;
219 void QuicUnackedPacketMap::RemoveAckability(TransmissionInfo
* info
) {
220 DCHECK(info
->retransmittable_frames
== nullptr);
221 info
->is_unackable
= true;
222 SequenceNumberList
* all_transmissions
= info
->all_transmissions
;
223 if (all_transmissions
== nullptr) {
226 for (QuicPacketSequenceNumber sequence_number
: *all_transmissions
) {
227 TransmissionInfo
* transmission_info
=
228 &unacked_packets_
[sequence_number
- least_unacked_
];
229 transmission_info
->all_transmissions
= nullptr;
230 transmission_info
->is_unackable
= true;
232 delete all_transmissions
;
235 void QuicUnackedPacketMap::MaybeRemoveRetransmittableFrames(
236 TransmissionInfo
* transmission_info
) {
237 if (transmission_info
->retransmittable_frames
== nullptr) {
240 if (transmission_info
->retransmittable_frames
->HasCryptoHandshake() ==
242 --pending_crypto_packet_count_
;
244 delete transmission_info
->retransmittable_frames
;
245 transmission_info
->retransmittable_frames
= nullptr;
248 void QuicUnackedPacketMap::IncreaseLargestObserved(
249 QuicPacketSequenceNumber largest_observed
) {
250 DCHECK_LE(largest_observed_
, largest_observed
);
251 largest_observed_
= largest_observed
;
254 bool QuicUnackedPacketMap::IsPacketUsefulForMeasuringRtt(
255 QuicPacketSequenceNumber sequence_number
,
256 const TransmissionInfo
& info
) const {
257 // Packet can be used for RTT measurement if it may yet be acked as the
258 // largest observed packet by the receiver.
259 return !info
.is_unackable
&& sequence_number
> largest_observed_
;
262 bool QuicUnackedPacketMap::IsPacketUsefulForCongestionControl(
263 const TransmissionInfo
& info
) const {
264 // Packet contributes to congestion control if it is considered inflight.
265 return info
.in_flight
;
268 bool QuicUnackedPacketMap::IsPacketUsefulForRetransmittableData(
269 const TransmissionInfo
& info
) const {
270 // Packet may have retransmittable frames, or the data may have been
271 // retransmitted with a new sequence number.
272 return info
.retransmittable_frames
!= nullptr ||
273 info
.all_transmissions
!= nullptr;
276 bool QuicUnackedPacketMap::IsPacketUseless(
277 QuicPacketSequenceNumber sequence_number
,
278 const TransmissionInfo
& info
) const {
279 return !IsPacketUsefulForMeasuringRtt(sequence_number
, info
) &&
280 !IsPacketUsefulForCongestionControl(info
) &&
281 !IsPacketUsefulForRetransmittableData(info
);
284 bool QuicUnackedPacketMap::IsUnacked(
285 QuicPacketSequenceNumber sequence_number
) const {
286 if (sequence_number
< least_unacked_
||
287 sequence_number
>= least_unacked_
+ unacked_packets_
.size()) {
290 return !IsPacketUseless(sequence_number
,
291 unacked_packets_
[sequence_number
- least_unacked_
]);
294 void QuicUnackedPacketMap::RemoveFromInFlight(
295 QuicPacketSequenceNumber sequence_number
) {
296 DCHECK_GE(sequence_number
, least_unacked_
);
297 DCHECK_LT(sequence_number
, least_unacked_
+ unacked_packets_
.size());
298 TransmissionInfo
* info
= &unacked_packets_
[sequence_number
- least_unacked_
];
299 if (info
->in_flight
) {
300 LOG_IF(DFATAL
, bytes_in_flight_
< info
->bytes_sent
);
301 bytes_in_flight_
-= info
->bytes_sent
;
302 info
->in_flight
= false;
306 void QuicUnackedPacketMap::CancelRetransmissionsForStream(
307 QuicStreamId stream_id
) {
308 QuicPacketSequenceNumber sequence_number
= least_unacked_
;
309 for (UnackedPacketMap::const_iterator it
= unacked_packets_
.begin();
310 it
!= unacked_packets_
.end(); ++it
, ++sequence_number
) {
311 RetransmittableFrames
* retransmittable_frames
= it
->retransmittable_frames
;
312 if (retransmittable_frames
== nullptr) {
315 retransmittable_frames
->RemoveFramesForStream(stream_id
);
316 if (retransmittable_frames
->frames().empty()) {
317 RemoveRetransmittability(sequence_number
);
322 bool QuicUnackedPacketMap::HasUnackedPackets() const {
323 return !unacked_packets_
.empty();
326 bool QuicUnackedPacketMap::HasInFlightPackets() const {
327 return bytes_in_flight_
> 0;
330 const TransmissionInfo
& QuicUnackedPacketMap::GetTransmissionInfo(
331 QuicPacketSequenceNumber sequence_number
) const {
332 return unacked_packets_
[sequence_number
- least_unacked_
];
335 QuicTime
QuicUnackedPacketMap::GetLastPacketSentTime() const {
336 UnackedPacketMap::const_reverse_iterator it
= unacked_packets_
.rbegin();
337 while (it
!= unacked_packets_
.rend()) {
339 LOG_IF(DFATAL
, it
->sent_time
== QuicTime::Zero())
340 << "Sent time can never be zero for a packet in flight.";
341 return it
->sent_time
;
345 LOG(DFATAL
) << "GetLastPacketSentTime requires in flight packets.";
346 return QuicTime::Zero();
349 size_t QuicUnackedPacketMap::GetNumUnackedPacketsDebugOnly() const {
350 size_t unacked_packet_count
= 0;
351 QuicPacketSequenceNumber sequence_number
= least_unacked_
;
352 for (UnackedPacketMap::const_iterator it
= unacked_packets_
.begin();
353 it
!= unacked_packets_
.end(); ++it
, ++sequence_number
) {
354 if (!IsPacketUseless(sequence_number
, *it
)) {
355 ++unacked_packet_count
;
358 return unacked_packet_count
;
361 bool QuicUnackedPacketMap::HasMultipleInFlightPackets() const {
362 size_t num_in_flight
= 0;
363 for (UnackedPacketMap::const_reverse_iterator it
= unacked_packets_
.rbegin();
364 it
!= unacked_packets_
.rend(); ++it
) {
368 if (num_in_flight
> 1) {
375 bool QuicUnackedPacketMap::HasPendingCryptoPackets() const {
376 return pending_crypto_packet_count_
> 0;
379 bool QuicUnackedPacketMap::HasUnackedRetransmittableFrames() const {
380 for (UnackedPacketMap::const_reverse_iterator it
=
381 unacked_packets_
.rbegin(); it
!= unacked_packets_
.rend(); ++it
) {
382 if (it
->in_flight
&& it
->retransmittable_frames
) {
389 QuicPacketSequenceNumber
QuicUnackedPacketMap::GetLeastUnacked() const {
390 return least_unacked_
;
393 void QuicUnackedPacketMap::PopLeastUnacked() {
394 ack_notifier_manager_
->OnPacketRemoved(least_unacked_
);
396 unacked_packets_
.pop_front();