Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(463)

Side by Side Diff: net/spdy/priority_write_scheduler.h

Issue 2832973003: Split net/spdy into core and chromium subdirectories. (Closed)
Patch Set: Fix some more build rules. Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « net/spdy/multiplexed_session.cc ('k') | net/spdy/priority_write_scheduler_test.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 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 #ifndef NET_SPDY_PRIORITY_WRITE_SCHEDULER_H_
6 #define NET_SPDY_PRIORITY_WRITE_SCHEDULER_H_
7
8 #include <stddef.h>
9 #include <stdint.h>
10
11 #include <algorithm>
12 #include <deque>
13 #include <tuple>
14 #include <unordered_map>
15 #include <utility>
16 #include <vector>
17
18 #include "base/logging.h"
19 #include "net/spdy/spdy_bug_tracker.h"
20 #include "net/spdy/spdy_protocol.h"
21 #include "net/spdy/write_scheduler.h"
22
23 namespace net {
24
25 namespace test {
26 template <typename StreamIdType>
27 class PriorityWriteSchedulerPeer;
28 }
29
30 // WriteScheduler implementation that manages the order in which streams are
31 // written using the SPDY priority scheme described at:
32 // https://www.chromium.org/spdy/spdy-protocol/spdy-protocol-draft3-1#TOC-2.3.3- Stream-priority
33 //
34 // Internally, PriorityWriteScheduler consists of 8 PriorityInfo objects, one
35 // for each priority value. Each PriorityInfo contains a list of streams of
36 // that priority that are ready to write, as well as a timestamp of the last
37 // I/O event that occurred for a stream of that priority.
38 template <typename StreamIdType>
39 class PriorityWriteScheduler : public WriteScheduler<StreamIdType> {
40 public:
41 using typename WriteScheduler<StreamIdType>::StreamPrecedenceType;
42
43 // Creates scheduler with no streams.
44 PriorityWriteScheduler() = default;
45
46 void RegisterStream(StreamIdType stream_id,
47 const StreamPrecedenceType& precedence) override {
48 SPDY_BUG_IF(!precedence.is_spdy3_priority()) << "Expected SPDY priority";
49
50 // parent_id not used here, but may as well validate it. However,
51 // parent_id may legitimately not be registered yet--see b/15676312.
52 StreamIdType parent_id = precedence.parent_id();
53 DVLOG_IF(1, parent_id != kHttp2RootStreamId && !StreamRegistered(parent_id))
54 << "Parent stream " << parent_id << " not registered";
55
56 if (stream_id == kHttp2RootStreamId) {
57 SPDY_BUG << "Stream " << kHttp2RootStreamId << " already registered";
58 return;
59 }
60 StreamInfo stream_info = {precedence.spdy3_priority(), stream_id, false};
61 bool inserted =
62 stream_infos_.insert(std::make_pair(stream_id, stream_info)).second;
63 SPDY_BUG_IF(!inserted) << "Stream " << stream_id << " already registered";
64 }
65
66 void UnregisterStream(StreamIdType stream_id) override {
67 auto it = stream_infos_.find(stream_id);
68 if (it == stream_infos_.end()) {
69 SPDY_BUG << "Stream " << stream_id << " not registered";
70 return;
71 }
72 StreamInfo& stream_info = it->second;
73 if (stream_info.ready) {
74 bool erased =
75 Erase(&priority_infos_[stream_info.priority].ready_list, stream_info);
76 DCHECK(erased);
77 }
78 stream_infos_.erase(it);
79 }
80
81 bool StreamRegistered(StreamIdType stream_id) const override {
82 return stream_infos_.find(stream_id) != stream_infos_.end();
83 }
84
85 StreamPrecedenceType GetStreamPrecedence(
86 StreamIdType stream_id) const override {
87 auto it = stream_infos_.find(stream_id);
88 if (it == stream_infos_.end()) {
89 DVLOG(1) << "Stream " << stream_id << " not registered";
90 return StreamPrecedenceType(kV3LowestPriority);
91 }
92 return StreamPrecedenceType(it->second.priority);
93 }
94
95 void UpdateStreamPrecedence(StreamIdType stream_id,
96 const StreamPrecedenceType& precedence) override {
97 SPDY_BUG_IF(!precedence.is_spdy3_priority()) << "Expected SPDY priority";
98
99 // parent_id not used here, but may as well validate it. However,
100 // parent_id may legitimately not be registered yet--see b/15676312.
101 StreamIdType parent_id = precedence.parent_id();
102 DVLOG_IF(1, parent_id != kHttp2RootStreamId && !StreamRegistered(parent_id))
103 << "Parent stream " << parent_id << " not registered";
104
105 auto it = stream_infos_.find(stream_id);
106 if (it == stream_infos_.end()) {
107 // TODO(mpw): add to stream_infos_ on demand--see b/15676312.
108 DVLOG(1) << "Stream " << stream_id << " not registered";
109 return;
110 }
111 StreamInfo& stream_info = it->second;
112 SpdyPriority new_priority = precedence.spdy3_priority();
113 if (stream_info.priority == new_priority) {
114 return;
115 }
116 if (stream_info.ready) {
117 bool erased =
118 Erase(&priority_infos_[stream_info.priority].ready_list, stream_info);
119 DCHECK(erased);
120 priority_infos_[new_priority].ready_list.push_back(&stream_info);
121 ++num_ready_streams_;
122 }
123 stream_info.priority = new_priority;
124 }
125
126 std::vector<StreamIdType> GetStreamChildren(
127 StreamIdType stream_id) const override {
128 return std::vector<StreamIdType>();
129 }
130
131 void RecordStreamEventTime(StreamIdType stream_id,
132 int64_t now_in_usec) override {
133 auto it = stream_infos_.find(stream_id);
134 if (it == stream_infos_.end()) {
135 SPDY_BUG << "Stream " << stream_id << " not registered";
136 return;
137 }
138 PriorityInfo& priority_info = priority_infos_[it->second.priority];
139 priority_info.last_event_time_usec =
140 std::max(priority_info.last_event_time_usec, now_in_usec);
141 }
142
143 int64_t GetLatestEventWithPrecedence(StreamIdType stream_id) const override {
144 auto it = stream_infos_.find(stream_id);
145 if (it == stream_infos_.end()) {
146 SPDY_BUG << "Stream " << stream_id << " not registered";
147 return 0;
148 }
149 int64_t last_event_time_usec = 0;
150 const StreamInfo& stream_info = it->second;
151 for (SpdyPriority p = kV3HighestPriority; p < stream_info.priority; ++p) {
152 last_event_time_usec = std::max(last_event_time_usec,
153 priority_infos_[p].last_event_time_usec);
154 }
155 return last_event_time_usec;
156 }
157
158 StreamIdType PopNextReadyStream() override {
159 return std::get<0>(PopNextReadyStreamAndPrecedence());
160 }
161
162 // Returns the next ready stream and its precedence.
163 std::tuple<StreamIdType, StreamPrecedenceType>
164 PopNextReadyStreamAndPrecedence() override {
165 for (SpdyPriority p = kV3HighestPriority; p <= kV3LowestPriority; ++p) {
166 ReadyList& ready_list = priority_infos_[p].ready_list;
167 if (!ready_list.empty()) {
168 StreamInfo* info = ready_list.front();
169 ready_list.pop_front();
170 --num_ready_streams_;
171
172 DCHECK(stream_infos_.find(info->stream_id) != stream_infos_.end());
173 info->ready = false;
174 return std::make_tuple(info->stream_id,
175 StreamPrecedenceType(info->priority));
176 }
177 }
178 SPDY_BUG << "No ready streams available";
179 return std::make_tuple(0, StreamPrecedenceType(kV3LowestPriority));
180 }
181
182 bool ShouldYield(StreamIdType stream_id) const override {
183 auto it = stream_infos_.find(stream_id);
184 if (it == stream_infos_.end()) {
185 SPDY_BUG << "Stream " << stream_id << " not registered";
186 return false;
187 }
188
189 // If there's a higher priority stream, this stream should yield.
190 const StreamInfo& stream_info = it->second;
191 for (SpdyPriority p = kV3HighestPriority; p < stream_info.priority; ++p) {
192 if (!priority_infos_[p].ready_list.empty()) {
193 return true;
194 }
195 }
196
197 // If this priority level is empty, or this stream is the next up, there's
198 // no need to yield.
199 const auto& ready_list = priority_infos_[it->second.priority].ready_list;
200 if (ready_list.empty() || ready_list.front()->stream_id == stream_id) {
201 return false;
202 }
203
204 // There are other streams in this priority level which take precedence.
205 // Yield.
206 return true;
207 }
208
209 void MarkStreamReady(StreamIdType stream_id, bool add_to_front) override {
210 auto it = stream_infos_.find(stream_id);
211 if (it == stream_infos_.end()) {
212 SPDY_BUG << "Stream " << stream_id << " not registered";
213 return;
214 }
215 StreamInfo& stream_info = it->second;
216 if (stream_info.ready) {
217 return;
218 }
219 ReadyList& ready_list = priority_infos_[stream_info.priority].ready_list;
220 if (add_to_front) {
221 ready_list.push_front(&stream_info);
222 } else {
223 ready_list.push_back(&stream_info);
224 }
225 ++num_ready_streams_;
226 stream_info.ready = true;
227 }
228
229 void MarkStreamNotReady(StreamIdType stream_id) override {
230 auto it = stream_infos_.find(stream_id);
231 if (it == stream_infos_.end()) {
232 SPDY_BUG << "Stream " << stream_id << " not registered";
233 return;
234 }
235 StreamInfo& stream_info = it->second;
236 if (!stream_info.ready) {
237 return;
238 }
239 bool erased =
240 Erase(&priority_infos_[stream_info.priority].ready_list, stream_info);
241 DCHECK(erased);
242 stream_info.ready = false;
243 }
244
245 // Returns true iff the number of ready streams is non-zero.
246 bool HasReadyStreams() const override { return num_ready_streams_ > 0; }
247
248 // Returns the number of ready streams.
249 size_t NumReadyStreams() const override { return num_ready_streams_; }
250
251 private:
252 friend class test::PriorityWriteSchedulerPeer<StreamIdType>;
253
254 // State kept for all registered streams. All ready streams have ready = true
255 // and should be present in priority_infos_[priority].ready_list.
256 struct StreamInfo {
257 SpdyPriority priority;
258 StreamIdType stream_id;
259 bool ready;
260 };
261
262 // 0(1) size lookup, 0(1) insert at front or back.
263 typedef std::deque<StreamInfo*> ReadyList;
264
265 // State kept for each priority level.
266 struct PriorityInfo {
267 // IDs of streams that are ready to write.
268 ReadyList ready_list;
269 // Time of latest write event for stream of this priority, in microseconds.
270 int64_t last_event_time_usec = 0;
271 };
272
273 typedef std::unordered_map<StreamIdType, StreamInfo> StreamInfoMap;
274
275 // Erases first occurrence (which should be the only one) of |info| in
276 // |ready_list|, returning true if found (and erased), or false otherwise.
277 // Decrements |num_ready_streams_| if an entry is erased.
278 bool Erase(ReadyList* ready_list, const StreamInfo& info) {
279 auto it = std::find(ready_list->begin(), ready_list->end(), &info);
280 if (it == ready_list->end()) {
281 return false;
282 }
283 ready_list->erase(it);
284 --num_ready_streams_;
285 return true;
286 }
287
288 // Number of ready streams.
289 size_t num_ready_streams_ = 0;
290 // Per-priority state, including ready lists.
291 PriorityInfo priority_infos_[kV3LowestPriority + 1];
292 // StreamInfos for all registered streams.
293 StreamInfoMap stream_infos_;
294 };
295
296 } // namespace net
297
298 #endif // NET_SPDY_PRIORITY_WRITE_SCHEDULER_H_
OLDNEW
« no previous file with comments | « net/spdy/multiplexed_session.cc ('k') | net/spdy/priority_write_scheduler_test.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698