blob: 269858f405618c0f06133362b5a164a670f4ee89 [file] [log] [blame]
QUICHE teama6ef0a62019-03-07 20:34:33 -05001// Copyright (c) 2017 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#ifndef QUICHE_QUIC_CORE_PACKET_NUMBER_INDEXED_QUEUE_H_
6#define QUICHE_QUIC_CORE_PACKET_NUMBER_INDEXED_QUEUE_H_
7
8#include "net/third_party/quiche/src/quic/core/quic_constants.h"
wub254545c2019-04-04 13:56:52 -07009#include "net/third_party/quiche/src/quic/core/quic_packet_number.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050010#include "net/third_party/quiche/src/quic/core/quic_types.h"
11#include "net/third_party/quiche/src/quic/platform/api/quic_bug_tracker.h"
12#include "net/third_party/quiche/src/quic/platform/api/quic_containers.h"
13
14namespace quic {
15
16// PacketNumberIndexedQueue is a queue of mostly continuous numbered entries
17// which supports the following operations:
18// - adding elements to the end of the queue, or at some point past the end
19// - removing elements in any order
20// - retrieving elements
21// If all elements are inserted in order, all of the operations above are
22// amortized O(1) time.
23//
24// Internally, the data structure is a deque where each element is marked as
25// present or not. The deque starts at the lowest present index. Whenever an
26// element is removed, it's marked as not present, and the front of the deque is
27// cleared of elements that are not present.
28//
29// The tail of the queue is not cleared due to the assumption of entries being
30// inserted in order, though removing all elements of the queue will return it
31// to its initial state.
32//
33// Note that this data structure is inherently hazardous, since an addition of
34// just two entries will cause it to consume all of the memory available.
35// Because of that, it is not a general-purpose container and should not be used
36// as one.
wuba545ca12019-12-11 19:27:43 -080037// TODO(wub): Update the comments when deprecating
38// --quic_bw_sampler_remove_packets_once_per_congestion_event.
QUICHE teama6ef0a62019-03-07 20:34:33 -050039template <typename T>
dschinazie2116422019-10-29 11:54:26 -070040class QUIC_NO_EXPORT PacketNumberIndexedQueue {
QUICHE teama6ef0a62019-03-07 20:34:33 -050041 public:
42 PacketNumberIndexedQueue() : number_of_present_entries_(0) {}
43
44 // Retrieve the entry associated with the packet number. Returns the pointer
45 // to the entry in case of success, or nullptr if the entry does not exist.
46 T* GetEntry(QuicPacketNumber packet_number);
47 const T* GetEntry(QuicPacketNumber packet_number) const;
48
49 // Inserts data associated |packet_number| into (or past) the end of the
50 // queue, filling up the missing intermediate entries as necessary. Returns
51 // true if the element has been inserted successfully, false if it was already
52 // in the queue or inserted out of order.
53 template <typename... Args>
54 bool Emplace(QuicPacketNumber packet_number, Args&&... args);
55
56 // Removes data associated with |packet_number| and frees the slots in the
57 // queue as necessary.
58 bool Remove(QuicPacketNumber packet_number);
59
wub254545c2019-04-04 13:56:52 -070060 // Same as above, but if an entry is present in the queue, also call f(entry)
61 // before removing it.
62 template <typename Function>
63 bool Remove(QuicPacketNumber packet_number, Function f);
64
wuba545ca12019-12-11 19:27:43 -080065 // Remove up to, but not including |packet_number|.
66 void RemoveUpTo(QuicPacketNumber packet_number);
67
QUICHE teama6ef0a62019-03-07 20:34:33 -050068 bool IsEmpty() const { return number_of_present_entries_ == 0; }
69
70 // Returns the number of entries in the queue.
71 size_t number_of_present_entries() const {
72 return number_of_present_entries_;
73 }
74
75 // Returns the number of entries allocated in the underlying deque. This is
76 // proportional to the memory usage of the queue.
77 size_t entry_slots_used() const { return entries_.size(); }
78
79 // Packet number of the first entry in the queue.
80 QuicPacketNumber first_packet() const { return first_packet_; }
81
82 // Packet number of the last entry ever inserted in the queue. Note that the
83 // entry in question may have already been removed. Zero if the queue is
84 // empty.
85 QuicPacketNumber last_packet() const {
86 if (IsEmpty()) {
87 return QuicPacketNumber();
88 }
89 return first_packet_ + entries_.size() - 1;
90 }
91
92 private:
93 // Wrapper around T used to mark whether the entry is actually in the map.
dschinazie2116422019-10-29 11:54:26 -070094 struct QUIC_NO_EXPORT EntryWrapper : T {
wuba545ca12019-12-11 19:27:43 -080095 // NOTE(wub): When quic_bw_sampler_remove_packets_once_per_congestion_event
96 // is enabled, |present| is false if and only if this is a placeholder entry
97 // for holes in the parent's |entries|.
QUICHE teama6ef0a62019-03-07 20:34:33 -050098 bool present;
99
100 EntryWrapper() : present(false) {}
101
102 template <typename... Args>
103 explicit EntryWrapper(Args&&... args)
104 : T(std::forward<Args>(args)...), present(true) {}
105 };
106
107 // Cleans up unused slots in the front after removing an element.
108 void Cleanup();
109
110 const EntryWrapper* GetEntryWrapper(QuicPacketNumber offset) const;
111 EntryWrapper* GetEntryWrapper(QuicPacketNumber offset) {
112 const auto* const_this = this;
113 return const_cast<EntryWrapper*>(const_this->GetEntryWrapper(offset));
114 }
115
116 QuicDeque<EntryWrapper> entries_;
wuba545ca12019-12-11 19:27:43 -0800117 // NOTE(wub): When --quic_bw_sampler_remove_packets_once_per_congestion_event
118 // is enabled, |number_of_present_entries_| only represents number of holes,
119 // which does not include number of acked or lost packets.
QUICHE teama6ef0a62019-03-07 20:34:33 -0500120 size_t number_of_present_entries_;
121 QuicPacketNumber first_packet_;
122};
123
124template <typename T>
125T* PacketNumberIndexedQueue<T>::GetEntry(QuicPacketNumber packet_number) {
126 EntryWrapper* entry = GetEntryWrapper(packet_number);
127 if (entry == nullptr) {
128 return nullptr;
129 }
130 return entry;
131}
132
133template <typename T>
134const T* PacketNumberIndexedQueue<T>::GetEntry(
135 QuicPacketNumber packet_number) const {
136 const EntryWrapper* entry = GetEntryWrapper(packet_number);
137 if (entry == nullptr) {
138 return nullptr;
139 }
140 return entry;
141}
142
143template <typename T>
144template <typename... Args>
145bool PacketNumberIndexedQueue<T>::Emplace(QuicPacketNumber packet_number,
146 Args&&... args) {
147 if (!packet_number.IsInitialized()) {
148 QUIC_BUG << "Try to insert an uninitialized packet number";
149 return false;
150 }
151
152 if (IsEmpty()) {
153 DCHECK(entries_.empty());
154 DCHECK(!first_packet_.IsInitialized());
155
156 entries_.emplace_back(std::forward<Args>(args)...);
157 number_of_present_entries_ = 1;
158 first_packet_ = packet_number;
159 return true;
160 }
161
162 // Do not allow insertion out-of-order.
163 if (packet_number <= last_packet()) {
164 return false;
165 }
166
167 // Handle potentially missing elements.
168 size_t offset = packet_number - first_packet_;
169 if (offset > entries_.size()) {
170 entries_.resize(offset);
171 }
172
173 number_of_present_entries_++;
174 entries_.emplace_back(std::forward<Args>(args)...);
175 DCHECK_EQ(packet_number, last_packet());
176 return true;
177}
178
179template <typename T>
180bool PacketNumberIndexedQueue<T>::Remove(QuicPacketNumber packet_number) {
wub254545c2019-04-04 13:56:52 -0700181 return Remove(packet_number, [](const T&) {});
182}
183
184template <typename T>
185template <typename Function>
186bool PacketNumberIndexedQueue<T>::Remove(QuicPacketNumber packet_number,
187 Function f) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500188 EntryWrapper* entry = GetEntryWrapper(packet_number);
189 if (entry == nullptr) {
190 return false;
191 }
wub254545c2019-04-04 13:56:52 -0700192 f(*static_cast<const T*>(entry));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500193 entry->present = false;
194 number_of_present_entries_--;
195
196 if (packet_number == first_packet()) {
197 Cleanup();
198 }
199 return true;
200}
201
202template <typename T>
wuba545ca12019-12-11 19:27:43 -0800203void PacketNumberIndexedQueue<T>::RemoveUpTo(QuicPacketNumber packet_number) {
204 while (!entries_.empty() && first_packet_.IsInitialized() &&
205 first_packet_ < packet_number) {
206 if (entries_.front().present) {
207 number_of_present_entries_--;
208 }
209 entries_.pop_front();
210 first_packet_++;
211 }
212 if (entries_.empty()) {
213 first_packet_.Clear();
214 }
215}
216
217template <typename T>
QUICHE teama6ef0a62019-03-07 20:34:33 -0500218void PacketNumberIndexedQueue<T>::Cleanup() {
219 while (!entries_.empty() && !entries_.front().present) {
220 entries_.pop_front();
221 first_packet_++;
222 }
223 if (entries_.empty()) {
224 first_packet_.Clear();
225 }
226}
227
228template <typename T>
229auto PacketNumberIndexedQueue<T>::GetEntryWrapper(
230 QuicPacketNumber packet_number) const -> const EntryWrapper* {
231 if (!packet_number.IsInitialized() || IsEmpty() ||
232 packet_number < first_packet_) {
233 return nullptr;
234 }
235
236 uint64_t offset = packet_number - first_packet_;
237 if (offset >= entries_.size()) {
238 return nullptr;
239 }
240
241 const EntryWrapper* entry = &entries_[offset];
242 if (!entry->present) {
243 return nullptr;
244 }
245
246 return entry;
247}
248
249} // namespace quic
250
251#endif // QUICHE_QUIC_CORE_PACKET_NUMBER_INDEXED_QUEUE_H_