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 DCHECK_GE(old_sequence_number
, least_unacked_
);
92 DCHECK_LT(old_sequence_number
, least_unacked_
+ unacked_packets_
.size());
93 DCHECK_GE(new_sequence_number
, least_unacked_
+ unacked_packets_
.size());
94 DCHECK_NE(NOT_RETRANSMISSION
, transmission_type
);
96 TransmissionInfo
* transmission_info
=
97 &unacked_packets_
.at(old_sequence_number
- least_unacked_
);
98 RetransmittableFrames
* frames
= transmission_info
->retransmittable_frames
;
99 transmission_info
->retransmittable_frames
= nullptr;
100 LOG_IF(DFATAL
, frames
== nullptr)
101 << "Attempt to retransmit packet with no "
102 << "retransmittable frames: " << old_sequence_number
;
104 // Only keep one transmission older than largest observed, because only the
105 // most recent is expected to possibly be a spurious retransmission.
106 while (transmission_info
->all_transmissions
!= nullptr &&
107 transmission_info
->all_transmissions
->size() > 1 &&
108 *(++transmission_info
->all_transmissions
->begin()) <
110 QuicPacketSequenceNumber old_transmission
=
111 *transmission_info
->all_transmissions
->begin();
112 TransmissionInfo
* old_info
=
113 &unacked_packets_
[old_transmission
- least_unacked_
];
114 // Don't remove old packets if they're still in flight.
115 if (old_info
->in_flight
) {
118 old_info
->all_transmissions
->pop_front();
119 // This will cause the packet be removed in RemoveObsoletePackets.
120 old_info
->all_transmissions
= nullptr;
122 // Don't link old transmissions to new ones when version or
123 // encryption changes.
124 if (transmission_type
== ALL_INITIAL_RETRANSMISSION
||
125 transmission_type
== ALL_UNACKED_RETRANSMISSION
) {
126 RemoveAckability(transmission_info
);
128 if (transmission_info
->all_transmissions
== nullptr) {
129 transmission_info
->all_transmissions
= new SequenceNumberList();
130 transmission_info
->all_transmissions
->push_back(old_sequence_number
);
132 transmission_info
->all_transmissions
->push_back(new_sequence_number
);
134 info
->retransmittable_frames
= frames
;
135 info
->all_transmissions
= transmission_info
->all_transmissions
;
136 // Proactively remove obsolete packets so the least unacked can be raised.
137 RemoveObsoletePackets();
140 void QuicUnackedPacketMap::ClearAllPreviousRetransmissions() {
141 while (!unacked_packets_
.empty() && least_unacked_
< largest_observed_
) {
142 // If this packet is in flight, or has retransmittable data, then there is
143 // no point in clearing out any further packets, because they would not
144 // affect the high water mark.
145 TransmissionInfo
* info
= &unacked_packets_
.front();
146 if (info
->in_flight
|| info
->retransmittable_frames
!= nullptr) {
150 if (info
->all_transmissions
!= nullptr) {
151 if (info
->all_transmissions
->size() < 2) {
152 LOG(DFATAL
) << "all_transmissions must be nullptr or have multiple "
153 << "elements. size:" << info
->all_transmissions
->size();
154 delete info
->all_transmissions
;
156 info
->all_transmissions
->pop_front();
157 if (info
->all_transmissions
->size() == 1) {
158 // Set the newer transmission's 'all_transmissions' entry to nullptr.
159 QuicPacketSequenceNumber new_transmission
=
160 info
->all_transmissions
->front();
161 TransmissionInfo
* new_info
=
162 &unacked_packets_
.at(new_transmission
- least_unacked_
);
163 delete new_info
->all_transmissions
;
164 new_info
->all_transmissions
= nullptr;
172 bool QuicUnackedPacketMap::HasRetransmittableFrames(
173 QuicPacketSequenceNumber sequence_number
) const {
174 DCHECK_GE(sequence_number
, least_unacked_
);
175 DCHECK_LT(sequence_number
, least_unacked_
+ unacked_packets_
.size());
176 return unacked_packets_
[sequence_number
- least_unacked_
]
177 .retransmittable_frames
!= nullptr;
180 void QuicUnackedPacketMap::NackPacket(QuicPacketSequenceNumber sequence_number
,
181 QuicPacketCount min_nacks
) {
182 DCHECK_GE(sequence_number
, least_unacked_
);
183 DCHECK_LT(sequence_number
, least_unacked_
+ unacked_packets_
.size());
184 unacked_packets_
[sequence_number
- least_unacked_
].nack_count
=
186 unacked_packets_
[sequence_number
- least_unacked_
].nack_count
);
189 void QuicUnackedPacketMap::RemoveRetransmittability(
190 QuicPacketSequenceNumber sequence_number
) {
191 DCHECK_GE(sequence_number
, least_unacked_
);
192 DCHECK_LT(sequence_number
, least_unacked_
+ unacked_packets_
.size());
193 TransmissionInfo
* info
= &unacked_packets_
[sequence_number
- least_unacked_
];
194 SequenceNumberList
* all_transmissions
= info
->all_transmissions
;
195 if (all_transmissions
== nullptr) {
196 MaybeRemoveRetransmittableFrames(info
);
199 // TODO(ianswett): Consider adding a check to ensure there are retransmittable
200 // frames associated with this packet.
201 for (QuicPacketSequenceNumber sequence_number
: *all_transmissions
) {
202 TransmissionInfo
* transmission_info
=
203 &unacked_packets_
[sequence_number
- least_unacked_
];
204 MaybeRemoveRetransmittableFrames(transmission_info
);
205 transmission_info
->all_transmissions
= nullptr;
207 delete all_transmissions
;
210 void QuicUnackedPacketMap::RemoveAckability(TransmissionInfo
* info
) {
211 DCHECK(info
->retransmittable_frames
== nullptr);
212 info
->is_unackable
= true;
213 SequenceNumberList
* all_transmissions
= info
->all_transmissions
;
214 if (all_transmissions
== nullptr) {
217 for (QuicPacketSequenceNumber sequence_number
: *all_transmissions
) {
218 TransmissionInfo
* transmission_info
=
219 &unacked_packets_
[sequence_number
- least_unacked_
];
220 transmission_info
->all_transmissions
= nullptr;
221 transmission_info
->is_unackable
= true;
223 delete all_transmissions
;
226 void QuicUnackedPacketMap::MaybeRemoveRetransmittableFrames(
227 TransmissionInfo
* transmission_info
) {
228 if (transmission_info
->retransmittable_frames
!= nullptr) {
229 if (transmission_info
->retransmittable_frames
->HasCryptoHandshake()
231 --pending_crypto_packet_count_
;
233 delete transmission_info
->retransmittable_frames
;
234 transmission_info
->retransmittable_frames
= nullptr;
238 void QuicUnackedPacketMap::IncreaseLargestObserved(
239 QuicPacketSequenceNumber largest_observed
) {
240 DCHECK_LE(largest_observed_
, largest_observed
);
241 largest_observed_
= largest_observed
;
244 bool QuicUnackedPacketMap::IsPacketUsefulForMeasuringRtt(
245 QuicPacketSequenceNumber sequence_number
,
246 const TransmissionInfo
& info
) const {
247 // Packet can be used for RTT measurement if it may yet be acked as the
248 // largest observed packet by the receiver.
249 return !info
.is_unackable
&& sequence_number
> largest_observed_
;
252 bool QuicUnackedPacketMap::IsPacketUsefulForCongestionControl(
253 const TransmissionInfo
& info
) const {
254 // Packet contributes to congestion control if it is considered inflight.
255 return info
.in_flight
;
258 bool QuicUnackedPacketMap::IsPacketUsefulForRetransmittableData(
259 const TransmissionInfo
& info
) const {
260 // Packet may have retransmittable frames, or the data may have been
261 // retransmitted with a new sequence number.
262 return info
.retransmittable_frames
!= nullptr ||
263 info
.all_transmissions
!= nullptr;
266 bool QuicUnackedPacketMap::IsPacketUseless(
267 QuicPacketSequenceNumber sequence_number
,
268 const TransmissionInfo
& info
) const {
269 return !IsPacketUsefulForMeasuringRtt(sequence_number
, info
) &&
270 !IsPacketUsefulForCongestionControl(info
) &&
271 !IsPacketUsefulForRetransmittableData(info
);
274 bool QuicUnackedPacketMap::IsUnacked(
275 QuicPacketSequenceNumber sequence_number
) const {
276 if (sequence_number
< least_unacked_
||
277 sequence_number
>= least_unacked_
+ unacked_packets_
.size()) {
280 return !IsPacketUseless(sequence_number
,
281 unacked_packets_
[sequence_number
- least_unacked_
]);
284 void QuicUnackedPacketMap::RemoveFromInFlight(
285 QuicPacketSequenceNumber sequence_number
) {
286 DCHECK_GE(sequence_number
, least_unacked_
);
287 DCHECK_LT(sequence_number
, least_unacked_
+ unacked_packets_
.size());
288 TransmissionInfo
* info
= &unacked_packets_
[sequence_number
- least_unacked_
];
289 if (info
->in_flight
) {
290 LOG_IF(DFATAL
, bytes_in_flight_
< info
->bytes_sent
);
291 bytes_in_flight_
-= info
->bytes_sent
;
292 info
->in_flight
= false;
296 void QuicUnackedPacketMap::CancelRetransmissionsForStream(
297 QuicStreamId stream_id
) {
298 QuicPacketSequenceNumber sequence_number
= least_unacked_
;
299 for (UnackedPacketMap::const_iterator it
= unacked_packets_
.begin();
300 it
!= unacked_packets_
.end(); ++it
, ++sequence_number
) {
301 RetransmittableFrames
* retransmittable_frames
= it
->retransmittable_frames
;
302 if (!retransmittable_frames
) {
305 retransmittable_frames
->RemoveFramesForStream(stream_id
);
306 if (retransmittable_frames
->frames().empty()) {
307 RemoveRetransmittability(sequence_number
);
312 bool QuicUnackedPacketMap::HasUnackedPackets() const {
313 return !unacked_packets_
.empty();
316 bool QuicUnackedPacketMap::HasInFlightPackets() const {
317 return bytes_in_flight_
> 0;
320 const TransmissionInfo
& QuicUnackedPacketMap::GetTransmissionInfo(
321 QuicPacketSequenceNumber sequence_number
) const {
322 return unacked_packets_
[sequence_number
- least_unacked_
];
325 QuicTime
QuicUnackedPacketMap::GetLastPacketSentTime() const {
326 UnackedPacketMap::const_reverse_iterator it
= unacked_packets_
.rbegin();
327 while (it
!= unacked_packets_
.rend()) {
329 LOG_IF(DFATAL
, it
->sent_time
== QuicTime::Zero())
330 << "Sent time can never be zero for a packet in flight.";
331 return it
->sent_time
;
335 LOG(DFATAL
) << "GetLastPacketSentTime requires in flight packets.";
336 return QuicTime::Zero();
339 size_t QuicUnackedPacketMap::GetNumUnackedPacketsDebugOnly() const {
340 size_t unacked_packet_count
= 0;
341 QuicPacketSequenceNumber sequence_number
= least_unacked_
;
342 for (UnackedPacketMap::const_iterator it
= unacked_packets_
.begin();
343 it
!= unacked_packets_
.end(); ++it
, ++sequence_number
) {
344 if (!IsPacketUseless(sequence_number
, *it
)) {
345 ++unacked_packet_count
;
348 return unacked_packet_count
;
351 bool QuicUnackedPacketMap::HasMultipleInFlightPackets() const {
352 size_t num_in_flight
= 0;
353 for (UnackedPacketMap::const_reverse_iterator it
= unacked_packets_
.rbegin();
354 it
!= unacked_packets_
.rend(); ++it
) {
358 if (num_in_flight
> 1) {
365 bool QuicUnackedPacketMap::HasPendingCryptoPackets() const {
366 return pending_crypto_packet_count_
> 0;
369 bool QuicUnackedPacketMap::HasUnackedRetransmittableFrames() const {
370 for (UnackedPacketMap::const_reverse_iterator it
=
371 unacked_packets_
.rbegin(); it
!= unacked_packets_
.rend(); ++it
) {
372 if (it
->in_flight
&& it
->retransmittable_frames
) {
379 QuicPacketSequenceNumber
QuicUnackedPacketMap::GetLeastUnacked() const {
380 return least_unacked_
;
383 void QuicUnackedPacketMap::PopLeastUnacked() {
384 ack_notifier_manager_
->OnPacketRemoved(least_unacked_
);
386 unacked_packets_
.pop_front();