OLD | NEW |
---|---|
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 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 #ifndef NET_SPDY_HTTP2_WRITE_SCHEDULER_H_ | 5 #ifndef NET_SPDY_HTTP2_WRITE_SCHEDULER_H_ |
6 #define NET_SPDY_HTTP2_WRITE_SCHEDULER_H_ | 6 #define NET_SPDY_HTTP2_WRITE_SCHEDULER_H_ |
7 | 7 |
8 #include <stdint.h> | 8 #include <stdint.h> |
9 | 9 |
10 #include <algorithm> | 10 #include <algorithm> |
11 #include <cmath> | 11 #include <cmath> |
12 #include <deque> | 12 #include <deque> |
13 #include <map> | 13 #include <map> |
14 #include <memory> | 14 #include <memory> |
15 #include <queue> | 15 #include <queue> |
16 #include <set> | 16 #include <set> |
17 #include <tuple> | 17 #include <tuple> |
18 #include <unordered_map> | 18 #include <unordered_map> |
19 #include <utility> | 19 #include <utility> |
20 #include <vector> | 20 #include <vector> |
21 | 21 |
22 #include "base/containers/linked_list.h" | 22 #include "base/containers/linked_list.h" |
23 #include "base/logging.h" | 23 #include "base/logging.h" |
24 #include "base/macros.h" | 24 #include "base/macros.h" |
25 #include "base/memory/ptr_util.h" | |
25 #include "base/stl_util.h" | 26 #include "base/stl_util.h" |
cbentzel
2016/08/29 18:48:01
Do you know if this can be removed as part of this
Avi (use Gerrit)
2016/08/29 19:12:17
Missed it. Yes, it can.
| |
26 #include "net/spdy/spdy_bug_tracker.h" | 27 #include "net/spdy/spdy_bug_tracker.h" |
27 #include "net/spdy/spdy_protocol.h" | 28 #include "net/spdy/spdy_protocol.h" |
28 #include "net/spdy/write_scheduler.h" | 29 #include "net/spdy/write_scheduler.h" |
29 | 30 |
30 namespace net { | 31 namespace net { |
31 | 32 |
32 namespace test { | 33 namespace test { |
33 template <typename StreamIdType> | 34 template <typename StreamIdType> |
34 class Http2PriorityWriteSchedulerPeer; | 35 class Http2PriorityWriteSchedulerPeer; |
35 } | 36 } |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
74 size_t NumReadyStreams() const override; | 75 size_t NumReadyStreams() const override; |
75 | 76 |
76 // Return the number of streams currently in the tree. | 77 // Return the number of streams currently in the tree. |
77 int num_streams() const; | 78 int num_streams() const; |
78 | 79 |
79 private: | 80 private: |
80 friend class test::Http2PriorityWriteSchedulerPeer<StreamIdType>; | 81 friend class test::Http2PriorityWriteSchedulerPeer<StreamIdType>; |
81 | 82 |
82 struct StreamInfo; | 83 struct StreamInfo; |
83 using StreamInfoVector = std::vector<StreamInfo*>; | 84 using StreamInfoVector = std::vector<StreamInfo*>; |
84 using StreamInfoMap = std::unordered_map<StreamIdType, StreamInfo*>; | |
85 | 85 |
86 struct StreamInfo : public base::LinkNode<StreamInfo> { | 86 struct StreamInfo : public base::LinkNode<StreamInfo> { |
87 // ID for this stream. | 87 // ID for this stream. |
88 StreamIdType id; | 88 StreamIdType id; |
89 // StreamInfo for parent stream. | 89 // StreamInfo for parent stream. |
90 StreamInfo* parent = nullptr; | 90 StreamInfo* parent = nullptr; |
91 // Weights can range between 1 and 256 (inclusive). | 91 // Weights can range between 1 and 256 (inclusive). |
92 int weight = kHttp2DefaultStreamWeight; | 92 int weight = kHttp2DefaultStreamWeight; |
93 // The total weight of this stream's direct descendants. | 93 // The total weight of this stream's direct descendants. |
94 int total_child_weights = 0; | 94 int total_child_weights = 0; |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
160 // Unless there are bugs, this should always return true. | 160 // Unless there are bugs, this should always return true. |
161 bool ValidateInvariantsForTests() const; | 161 bool ValidateInvariantsForTests() const; |
162 | 162 |
163 // Returns true if the parent stream has the given stream in its children. | 163 // Returns true if the parent stream has the given stream in its children. |
164 bool StreamHasChild(const StreamInfo& parent_info, | 164 bool StreamHasChild(const StreamInfo& parent_info, |
165 const StreamInfo* child_info) const; | 165 const StreamInfo* child_info) const; |
166 | 166 |
167 // Pointee owned by all_stream_infos_. | 167 // Pointee owned by all_stream_infos_. |
168 StreamInfo* root_stream_info_; | 168 StreamInfo* root_stream_info_; |
169 // Maps from stream IDs to StreamInfo objects. | 169 // Maps from stream IDs to StreamInfo objects. |
170 StreamInfoMap all_stream_infos_; | 170 std::unordered_map<StreamIdType, std::unique_ptr<StreamInfo>> |
171 base::STLValueDeleter<StreamInfoMap> all_stream_infos_deleter_; | 171 all_stream_infos_; |
172 // Queue containing all ready streams, ordered with streams of higher | 172 // Queue containing all ready streams, ordered with streams of higher |
173 // priority before streams of lower priority, and, among streams of equal | 173 // priority before streams of lower priority, and, among streams of equal |
174 // priority, streams with lower ordinal before those with higher | 174 // priority, streams with lower ordinal before those with higher |
175 // ordinal. Note that not all streams in scheduling_queue_ are eligible to be | 175 // ordinal. Note that not all streams in scheduling_queue_ are eligible to be |
176 // picked as the next stream: some may have ancestor stream(s) that are ready | 176 // picked as the next stream: some may have ancestor stream(s) that are ready |
177 // and unblocked. In these situations the occluded child streams are left in | 177 // and unblocked. In these situations the occluded child streams are left in |
178 // the queue, to reduce churn. | 178 // the queue, to reduce churn. |
179 base::LinkedList<StreamInfo> scheduling_queue_; | 179 base::LinkedList<StreamInfo> scheduling_queue_; |
180 // Ordinal value to assign to next node inserted into scheduling_queue_ when | 180 // Ordinal value to assign to next node inserted into scheduling_queue_ when |
181 // |add_to_front == true|. Decremented after each assignment. | 181 // |add_to_front == true|. Decremented after each assignment. |
182 int64_t head_ordinal_ = -1; | 182 int64_t head_ordinal_ = -1; |
183 // Ordinal value to assign to next node inserted into scheduling_queue_ when | 183 // Ordinal value to assign to next node inserted into scheduling_queue_ when |
184 // |add_to_front == false|. Incremented after each assignment. | 184 // |add_to_front == false|. Incremented after each assignment. |
185 int64_t tail_ordinal_ = 0; | 185 int64_t tail_ordinal_ = 0; |
186 | 186 |
187 DISALLOW_COPY_AND_ASSIGN(Http2PriorityWriteScheduler); | 187 DISALLOW_COPY_AND_ASSIGN(Http2PriorityWriteScheduler); |
188 }; | 188 }; |
189 | 189 |
190 template <typename StreamIdType> | 190 template <typename StreamIdType> |
191 Http2PriorityWriteScheduler<StreamIdType>::Http2PriorityWriteScheduler() | 191 Http2PriorityWriteScheduler<StreamIdType>::Http2PriorityWriteScheduler() { |
192 : all_stream_infos_deleter_(&all_stream_infos_) { | 192 std::unique_ptr<StreamInfo> root_stream_info = base::MakeUnique<StreamInfo>(); |
193 root_stream_info_ = new StreamInfo(); | 193 root_stream_info_ = root_stream_info.get(); |
194 root_stream_info_->id = kHttp2RootStreamId; | 194 root_stream_info->id = kHttp2RootStreamId; |
195 root_stream_info_->weight = kHttp2DefaultStreamWeight; | 195 root_stream_info->weight = kHttp2DefaultStreamWeight; |
196 root_stream_info_->parent = nullptr; | 196 root_stream_info->parent = nullptr; |
197 root_stream_info_->priority = 1.0; | 197 root_stream_info->priority = 1.0; |
198 root_stream_info_->ready = false; | 198 root_stream_info->ready = false; |
199 all_stream_infos_[kHttp2RootStreamId] = root_stream_info_; | 199 all_stream_infos_[kHttp2RootStreamId] = std::move(root_stream_info); |
200 } | 200 } |
201 | 201 |
202 template <typename StreamIdType> | 202 template <typename StreamIdType> |
203 int Http2PriorityWriteScheduler<StreamIdType>::num_streams() const { | 203 int Http2PriorityWriteScheduler<StreamIdType>::num_streams() const { |
204 return all_stream_infos_.size(); | 204 return all_stream_infos_.size(); |
205 } | 205 } |
206 | 206 |
207 template <typename StreamIdType> | 207 template <typename StreamIdType> |
208 bool Http2PriorityWriteScheduler<StreamIdType>::StreamRegistered( | 208 bool Http2PriorityWriteScheduler<StreamIdType>::StreamRegistered( |
209 StreamIdType stream_id) const { | 209 StreamIdType stream_id) const { |
(...skipping 12 matching lines...) Expand all Loading... | |
222 return; | 222 return; |
223 } | 223 } |
224 | 224 |
225 StreamInfo* parent = FindStream(precedence.parent_id()); | 225 StreamInfo* parent = FindStream(precedence.parent_id()); |
226 if (parent == nullptr) { | 226 if (parent == nullptr) { |
227 // parent_id may legitimately not be registered yet--see b/15676312. | 227 // parent_id may legitimately not be registered yet--see b/15676312. |
228 DVLOG(1) << "Parent stream " << precedence.parent_id() << " not registered"; | 228 DVLOG(1) << "Parent stream " << precedence.parent_id() << " not registered"; |
229 parent = root_stream_info_; | 229 parent = root_stream_info_; |
230 } | 230 } |
231 | 231 |
232 StreamInfo* new_stream_info = new StreamInfo; | 232 std::unique_ptr<StreamInfo> new_stream_info = base::MakeUnique<StreamInfo>(); |
233 new_stream_info->id = stream_id; | 233 StreamInfo* new_stream_info_ptr = new_stream_info.get(); |
234 new_stream_info->weight = precedence.weight(); | 234 new_stream_info_ptr->id = stream_id; |
235 new_stream_info->parent = parent; | 235 new_stream_info_ptr->weight = precedence.weight(); |
236 all_stream_infos_[stream_id] = new_stream_info; | 236 new_stream_info_ptr->parent = parent; |
237 all_stream_infos_[stream_id] = std::move(new_stream_info); | |
237 if (precedence.is_exclusive()) { | 238 if (precedence.is_exclusive()) { |
238 // Move the parent's current children below the new stream. | 239 // Move the parent's current children below the new stream. |
239 using std::swap; | 240 using std::swap; |
240 swap(new_stream_info->children, parent->children); | 241 swap(new_stream_info_ptr->children, parent->children); |
cbentzel
2016/08/29 18:48:01
This might just be me - but seems a little strange
Avi (use Gerrit)
2016/08/29 19:12:17
I wasn't sure if the order mattered, especially if
cbentzel
2016/08/29 19:19:19
Agreed. I don't know that area of code well, addin
| |
241 new_stream_info->total_child_weights = parent->total_child_weights; | 242 new_stream_info_ptr->total_child_weights = parent->total_child_weights; |
242 // Update each child's parent. | 243 // Update each child's parent. |
243 for (StreamInfo* child : new_stream_info->children) { | 244 for (StreamInfo* child : new_stream_info_ptr->children) { |
244 child->parent = new_stream_info; | 245 child->parent = new_stream_info_ptr; |
245 } | 246 } |
246 // Clear parent's old child data. | 247 // Clear parent's old child data. |
247 DCHECK(parent->children.empty()); | 248 DCHECK(parent->children.empty()); |
248 parent->total_child_weights = 0; | 249 parent->total_child_weights = 0; |
249 } | 250 } |
250 // Add new stream to parent. | 251 // Add new stream to parent. |
251 parent->children.push_back(new_stream_info); | 252 parent->children.push_back(new_stream_info_ptr); |
252 parent->total_child_weights += precedence.weight(); | 253 parent->total_child_weights += precedence.weight(); |
253 | 254 |
254 // Update all priorities under parent, since addition of a stream affects | 255 // Update all priorities under parent, since addition of a stream affects |
255 // sibling priorities as well. | 256 // sibling priorities as well. |
256 UpdatePrioritiesUnder(parent); | 257 UpdatePrioritiesUnder(parent); |
257 | 258 |
258 // Stream starts with ready == false, so no need to schedule it yet. | 259 // Stream starts with ready == false, so no need to schedule it yet. |
259 DCHECK(!new_stream_info->ready); | 260 DCHECK(!new_stream_info_ptr->ready); |
260 } | 261 } |
261 | 262 |
262 template <typename StreamIdType> | 263 template <typename StreamIdType> |
263 void Http2PriorityWriteScheduler<StreamIdType>::UnregisterStream( | 264 void Http2PriorityWriteScheduler<StreamIdType>::UnregisterStream( |
264 StreamIdType stream_id) { | 265 StreamIdType stream_id) { |
265 if (stream_id == kHttp2RootStreamId) { | 266 if (stream_id == kHttp2RootStreamId) { |
266 SPDY_BUG << "Cannot unregister root stream"; | 267 SPDY_BUG << "Cannot unregister root stream"; |
267 return; | 268 return; |
268 } | 269 } |
269 // Remove the stream from table. | 270 // Remove the stream from table. |
270 typename StreamInfoMap::iterator it = all_stream_infos_.find(stream_id); | 271 auto it = all_stream_infos_.find(stream_id); |
271 if (it == all_stream_infos_.end()) { | 272 if (it == all_stream_infos_.end()) { |
272 SPDY_BUG << "Stream " << stream_id << " not registered"; | 273 SPDY_BUG << "Stream " << stream_id << " not registered"; |
273 return; | 274 return; |
274 } | 275 } |
275 std::unique_ptr<StreamInfo> stream_info(std::move(it->second)); | 276 std::unique_ptr<StreamInfo> stream_info(std::move(it->second)); |
276 all_stream_infos_.erase(it); | 277 all_stream_infos_.erase(it); |
277 // If ready (and hence scheduled), unschedule. | 278 // If ready (and hence scheduled), unschedule. |
278 if (stream_info->ready) { | 279 if (stream_info->ready) { |
279 Unschedule(stream_info.get()); | 280 Unschedule(stream_info.get()); |
280 } | 281 } |
(...skipping 287 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
568 return true; | 569 return true; |
569 } | 570 } |
570 } | 571 } |
571 return false; | 572 return false; |
572 } | 573 } |
573 | 574 |
574 template <typename StreamIdType> | 575 template <typename StreamIdType> |
575 const typename Http2PriorityWriteScheduler<StreamIdType>::StreamInfo* | 576 const typename Http2PriorityWriteScheduler<StreamIdType>::StreamInfo* |
576 Http2PriorityWriteScheduler<StreamIdType>::FindStream( | 577 Http2PriorityWriteScheduler<StreamIdType>::FindStream( |
577 StreamIdType stream_id) const { | 578 StreamIdType stream_id) const { |
578 typename StreamInfoMap::const_iterator it = all_stream_infos_.find(stream_id); | 579 auto it = all_stream_infos_.find(stream_id); |
579 return it == all_stream_infos_.end() ? nullptr : it->second; | 580 return it == all_stream_infos_.end() ? nullptr : it->second.get(); |
580 } | 581 } |
581 | 582 |
582 template <typename StreamIdType> | 583 template <typename StreamIdType> |
583 typename Http2PriorityWriteScheduler<StreamIdType>::StreamInfo* | 584 typename Http2PriorityWriteScheduler<StreamIdType>::StreamInfo* |
584 Http2PriorityWriteScheduler<StreamIdType>::FindStream(StreamIdType stream_id) { | 585 Http2PriorityWriteScheduler<StreamIdType>::FindStream(StreamIdType stream_id) { |
585 typename StreamInfoMap::iterator it = all_stream_infos_.find(stream_id); | 586 auto it = all_stream_infos_.find(stream_id); |
586 return it == all_stream_infos_.end() ? nullptr : it->second; | 587 return it == all_stream_infos_.end() ? nullptr : it->second.get(); |
587 } | 588 } |
588 | 589 |
589 template <typename StreamIdType> | 590 template <typename StreamIdType> |
590 void Http2PriorityWriteScheduler<StreamIdType>::UpdatePrioritiesUnder( | 591 void Http2PriorityWriteScheduler<StreamIdType>::UpdatePrioritiesUnder( |
591 StreamInfo* stream_info) { | 592 StreamInfo* stream_info) { |
592 for (StreamInfo* child : stream_info->children) { | 593 for (StreamInfo* child : stream_info->children) { |
593 child->priority = stream_info->priority * | 594 child->priority = stream_info->priority * |
594 (static_cast<float>(child->weight) / | 595 (static_cast<float>(child->weight) / |
595 static_cast<float>(stream_info->total_child_weights)); | 596 static_cast<float>(stream_info->total_child_weights)); |
596 if (child->ready) { | 597 if (child->ready) { |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
680 template <typename StreamIdType> | 681 template <typename StreamIdType> |
681 bool Http2PriorityWriteScheduler<StreamIdType>::ValidateInvariantsForTests() | 682 bool Http2PriorityWriteScheduler<StreamIdType>::ValidateInvariantsForTests() |
682 const { | 683 const { |
683 int total_streams = 0; | 684 int total_streams = 0; |
684 int streams_visited = 0; | 685 int streams_visited = 0; |
685 // Iterate through all streams in the map. | 686 // Iterate through all streams in the map. |
686 for (const auto& kv : all_stream_infos_) { | 687 for (const auto& kv : all_stream_infos_) { |
687 ++total_streams; | 688 ++total_streams; |
688 ++streams_visited; | 689 ++streams_visited; |
689 StreamIdType stream_id = kv.first; | 690 StreamIdType stream_id = kv.first; |
690 const StreamInfo& stream_info = *kv.second; | 691 const StreamInfo& stream_info = *kv.second.get(); |
691 | 692 |
692 // Verify each StreamInfo mapped under the proper stream ID. | 693 // Verify each StreamInfo mapped under the proper stream ID. |
693 if (stream_id != stream_info.id) { | 694 if (stream_id != stream_info.id) { |
694 DLOG(INFO) << "Stream ID " << stream_id << " maps to StreamInfo with ID " | 695 DLOG(INFO) << "Stream ID " << stream_id << " maps to StreamInfo with ID " |
695 << stream_info.id; | 696 << stream_info.id; |
696 return false; | 697 return false; |
697 } | 698 } |
698 | 699 |
699 // All streams except the root should have a parent, and should appear in | 700 // All streams except the root should have a parent, and should appear in |
700 // the children of that parent. | 701 // the children of that parent. |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
740 } | 741 } |
741 // Validate the validation function; we should have visited each stream twice | 742 // Validate the validation function; we should have visited each stream twice |
742 // (except for the root) | 743 // (except for the root) |
743 DCHECK(streams_visited == 2 * num_streams() - 1); | 744 DCHECK(streams_visited == 2 * num_streams() - 1); |
744 return true; | 745 return true; |
745 } | 746 } |
746 | 747 |
747 } // namespace net | 748 } // namespace net |
748 | 749 |
749 #endif // NET_SPDY_HTTP2_WRITE_SCHEDULER_H_ | 750 #endif // NET_SPDY_HTTP2_WRITE_SCHEDULER_H_ |
OLD | NEW |