OLD | NEW |
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 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_SPDY_PRIORITY_FOREST_H_ | 5 #ifndef NET_SPDY_SPDY_PRIORITY_FOREST_H_ |
6 #define NET_SPDY_SPDY_PRIORITY_FOREST_H_ | 6 #define NET_SPDY_SPDY_PRIORITY_FOREST_H_ |
7 | 7 |
8 #include <map> | 8 #include <map> |
9 #include <set> | 9 #include <set> |
10 #include <vector> | 10 #include <vector> |
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
112 private: | 112 private: |
113 enum NodeType { ROOT_NODE, NONROOT_ORDERED, NONROOT_UNORDERED }; | 113 enum NodeType { ROOT_NODE, NONROOT_ORDERED, NONROOT_UNORDERED }; |
114 struct Node { | 114 struct Node { |
115 Node() : type(ROOT_NODE), flags(0), child() { | 115 Node() : type(ROOT_NODE), flags(0), child() { |
116 depends_on.priority = Priority(); | 116 depends_on.priority = Priority(); |
117 } | 117 } |
118 NodeType type; | 118 NodeType type; |
119 unsigned int flags; // bitfield of flags | 119 unsigned int flags; // bitfield of flags |
120 union { | 120 union { |
121 Priority priority; // used for root nodes | 121 Priority priority; // used for root nodes |
122 NodeId parent_id; // used for non-root nodes | 122 NodeId parent_id; // used for non-root nodes |
123 } depends_on; | 123 } depends_on; |
124 NodeId child; // node ID of child (or NodeId() for no child) | 124 NodeId child; // node ID of child (or NodeId() for no child) |
125 }; | 125 }; |
126 | 126 |
127 typedef base::hash_map<NodeId, Node> NodeMap; | 127 typedef base::hash_map<NodeId, Node> NodeMap; |
128 | 128 |
129 // Constants for the Node.flags bitset: | 129 // Constants for the Node.flags bitset: |
130 // kReadToRead: set for nodes that are ready for reading | 130 // kReadToRead: set for nodes that are ready for reading |
131 static const unsigned int kReadyToRead = (1 << 0); | 131 static const unsigned int kReadyToRead = (1 << 0); |
132 // kReadToWrite: set for nodes that are ready for writing | 132 // kReadToWrite: set for nodes that are ready for writing |
133 static const unsigned int kReadyToWrite = (1 << 1); | 133 static const unsigned int kReadyToWrite = (1 << 1); |
134 | 134 |
135 // Common code for IsMarkedReadyToRead and IsMarkedReadyToWrite. | 135 // Common code for IsMarkedReadyToRead and IsMarkedReadyToWrite. |
136 bool IsMarked(NodeId node_id, unsigned int flag) const; | 136 bool IsMarked(NodeId node_id, unsigned int flag) const; |
137 // Common code for MarkReadyToRead and MarkReadyToWrite. | 137 // Common code for MarkReadyToRead and MarkReadyToWrite. |
138 bool Mark(NodeId node_id, unsigned int flag); | 138 bool Mark(NodeId node_id, unsigned int flag); |
139 // Common code for MarkNoLongerReadyToRead and MarkNoLongerReadyToWrite. | 139 // Common code for MarkNoLongerReadyToRead and MarkNoLongerReadyToWrite. |
140 bool Unmark(NodeId node_id, unsigned int flag); | 140 bool Unmark(NodeId node_id, unsigned int flag); |
141 // Common code for NextNodeToRead and NextNodeToWrite; | 141 // Common code for NextNodeToRead and NextNodeToWrite; |
142 NodeId FirstMarkedNode(unsigned int flag); | 142 NodeId FirstMarkedNode(unsigned int flag); |
143 // Get the given node, or return NULL if it doesn't exist. | 143 // Get the given node, or return NULL if it doesn't exist. |
144 const Node* FindNode(NodeId node_id) const; | 144 const Node* FindNode(NodeId node_id) const; |
145 | 145 |
146 NodeMap all_nodes_; // maps from node IDs to Node objects | 146 NodeMap all_nodes_; // maps from node IDs to Node objects |
147 | 147 |
148 DISALLOW_COPY_AND_ASSIGN(SpdyPriorityForest); | 148 DISALLOW_COPY_AND_ASSIGN(SpdyPriorityForest); |
149 }; | 149 }; |
150 | 150 |
151 template <typename NodeId, typename Priority> | 151 template <typename NodeId, typename Priority> |
152 SpdyPriorityForest<NodeId, Priority>::SpdyPriorityForest() {} | 152 SpdyPriorityForest<NodeId, Priority>::SpdyPriorityForest() { |
| 153 } |
153 | 154 |
154 template <typename NodeId, typename Priority> | 155 template <typename NodeId, typename Priority> |
155 SpdyPriorityForest<NodeId, Priority>::~SpdyPriorityForest() {} | 156 SpdyPriorityForest<NodeId, Priority>::~SpdyPriorityForest() { |
| 157 } |
156 | 158 |
157 template <typename NodeId, typename Priority> | 159 template <typename NodeId, typename Priority> |
158 int SpdyPriorityForest<NodeId, Priority>::num_nodes() const { | 160 int SpdyPriorityForest<NodeId, Priority>::num_nodes() const { |
159 return all_nodes_.size(); | 161 return all_nodes_.size(); |
160 } | 162 } |
161 | 163 |
162 template <typename NodeId, typename Priority> | 164 template <typename NodeId, typename Priority> |
163 bool SpdyPriorityForest<NodeId, Priority>::NodeExists(NodeId node_id) const { | 165 bool SpdyPriorityForest<NodeId, Priority>::NodeExists(NodeId node_id) const { |
164 return all_nodes_.count(node_id) != 0; | 166 return all_nodes_.count(node_id) != 0; |
165 } | 167 } |
166 | 168 |
167 template <typename NodeId, typename Priority> | 169 template <typename NodeId, typename Priority> |
168 bool SpdyPriorityForest<NodeId, Priority>::AddRootNode( | 170 bool SpdyPriorityForest<NodeId, Priority>::AddRootNode(NodeId node_id, |
169 NodeId node_id, Priority priority) { | 171 Priority priority) { |
170 if (NodeExists(node_id)) { | 172 if (NodeExists(node_id)) { |
171 return false; | 173 return false; |
172 } | 174 } |
173 Node* new_node = &all_nodes_[node_id]; | 175 Node* new_node = &all_nodes_[node_id]; |
174 new_node->type = ROOT_NODE; | 176 new_node->type = ROOT_NODE; |
175 new_node->depends_on.priority = priority; | 177 new_node->depends_on.priority = priority; |
176 return true; | 178 return true; |
177 } | 179 } |
178 | 180 |
179 template <typename NodeId, typename Priority> | 181 template <typename NodeId, typename Priority> |
180 bool SpdyPriorityForest<NodeId, Priority>::AddNonRootNode( | 182 bool SpdyPriorityForest<NodeId, Priority>::AddNonRootNode(NodeId node_id, |
181 NodeId node_id, NodeId parent_id, bool unordered) { | 183 NodeId parent_id, |
| 184 bool unordered) { |
182 if (NodeExists(node_id) || !NodeExists(parent_id)) { | 185 if (NodeExists(node_id) || !NodeExists(parent_id)) { |
183 return false; | 186 return false; |
184 } | 187 } |
185 | 188 |
186 Node* parent = &all_nodes_[parent_id]; | 189 Node* parent = &all_nodes_[parent_id]; |
187 if (parent->child != NodeId()) { | 190 if (parent->child != NodeId()) { |
188 return false; | 191 return false; |
189 } | 192 } |
190 | 193 |
191 Node* new_node = &all_nodes_[node_id]; | 194 Node* new_node = &all_nodes_[node_id]; |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
267 NodeId SpdyPriorityForest<NodeId, Priority>::GetChild(NodeId node_id) const { | 270 NodeId SpdyPriorityForest<NodeId, Priority>::GetChild(NodeId node_id) const { |
268 const Node* node = FindNode(node_id); | 271 const Node* node = FindNode(node_id); |
269 if (node != NULL) { | 272 if (node != NULL) { |
270 return node->child; | 273 return node->child; |
271 } else { | 274 } else { |
272 return NodeId(); | 275 return NodeId(); |
273 } | 276 } |
274 } | 277 } |
275 | 278 |
276 template <typename NodeId, typename Priority> | 279 template <typename NodeId, typename Priority> |
277 bool SpdyPriorityForest<NodeId, Priority>::SetPriority( | 280 bool SpdyPriorityForest<NodeId, Priority>::SetPriority(NodeId node_id, |
278 NodeId node_id, Priority priority) { | 281 Priority priority) { |
279 if (!NodeExists(node_id)) { | 282 if (!NodeExists(node_id)) { |
280 return false; | 283 return false; |
281 } | 284 } |
282 | 285 |
283 Node* node = &all_nodes_[node_id]; | 286 Node* node = &all_nodes_[node_id]; |
284 // If this is not already a root node, we need to make it be a root node. | 287 // If this is not already a root node, we need to make it be a root node. |
285 if (node->type != ROOT_NODE) { | 288 if (node->type != ROOT_NODE) { |
286 DCHECK(NodeExists(node->depends_on.parent_id)); | 289 DCHECK(NodeExists(node->depends_on.parent_id)); |
287 Node* parent = &all_nodes_[node->depends_on.parent_id]; | 290 Node* parent = &all_nodes_[node->depends_on.parent_id]; |
288 parent->child = NodeId(); | 291 parent->child = NodeId(); |
289 node->type = ROOT_NODE; | 292 node->type = ROOT_NODE; |
290 } | 293 } |
291 | 294 |
292 node->depends_on.priority = priority; | 295 node->depends_on.priority = priority; |
293 return true; | 296 return true; |
294 } | 297 } |
295 | 298 |
296 template <typename NodeId, typename Priority> | 299 template <typename NodeId, typename Priority> |
297 bool SpdyPriorityForest<NodeId, Priority>::SetParent( | 300 bool SpdyPriorityForest<NodeId, Priority>::SetParent(NodeId node_id, |
298 NodeId node_id, NodeId parent_id, bool unordered) { | 301 NodeId parent_id, |
| 302 bool unordered) { |
299 if (!NodeExists(node_id) || !NodeExists(parent_id)) { | 303 if (!NodeExists(node_id) || !NodeExists(parent_id)) { |
300 return false; | 304 return false; |
301 } | 305 } |
302 | 306 |
303 Node* node = &all_nodes_[node_id]; | 307 Node* node = &all_nodes_[node_id]; |
304 Node* new_parent = &all_nodes_[parent_id]; | 308 Node* new_parent = &all_nodes_[parent_id]; |
305 // If the new parent is already the node's parent, all we have to do is | 309 // If the new parent is already the node's parent, all we have to do is |
306 // update the node type and we're done. | 310 // update the node type and we're done. |
307 if (new_parent->child == node_id) { | 311 if (new_parent->child == node_id) { |
308 node->type = (unordered ? NONROOT_UNORDERED : NONROOT_ORDERED); | 312 node->type = (unordered ? NONROOT_UNORDERED : NONROOT_ORDERED); |
309 return true; | 313 return true; |
310 } | 314 } |
311 // Otherwise, if the new parent already has a child, we fail. | 315 // Otherwise, if the new parent already has a child, we fail. |
312 if (new_parent->child != NodeId()) { | 316 if (new_parent->child != NodeId()) { |
313 return false; | 317 return false; |
314 } | 318 } |
315 | 319 |
316 // Next, make sure we won't create a cycle. | 320 // Next, make sure we won't create a cycle. |
317 if (node_id == parent_id) return false; | 321 if (node_id == parent_id) |
| 322 return false; |
318 Node* last = node; | 323 Node* last = node; |
319 NodeId last_id = node_id; | 324 NodeId last_id = node_id; |
320 while (last->child != NodeId()) { | 325 while (last->child != NodeId()) { |
321 if (last->child == parent_id) return false; | 326 if (last->child == parent_id) |
| 327 return false; |
322 last_id = last->child; | 328 last_id = last->child; |
323 DCHECK(NodeExists(last_id)); | 329 DCHECK(NodeExists(last_id)); |
324 last = &all_nodes_[last_id]; | 330 last = &all_nodes_[last_id]; |
325 } | 331 } |
326 | 332 |
327 // If the node is not a root, we need clear its old parent's child field | 333 // If the node is not a root, we need clear its old parent's child field |
328 // (unless the old parent is the same as the new parent). | 334 // (unless the old parent is the same as the new parent). |
329 if (node->type != ROOT_NODE) { | 335 if (node->type != ROOT_NODE) { |
330 const NodeId old_parent_id = node->depends_on.parent_id; | 336 const NodeId old_parent_id = node->depends_on.parent_id; |
331 DCHECK(NodeExists(old_parent_id)); | 337 DCHECK(NodeExists(old_parent_id)); |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
380 NodeId node_id) { | 386 NodeId node_id) { |
381 return Unmark(node_id, kReadyToWrite); | 387 return Unmark(node_id, kReadyToWrite); |
382 } | 388 } |
383 | 389 |
384 template <typename NodeId, typename Priority> | 390 template <typename NodeId, typename Priority> |
385 NodeId SpdyPriorityForest<NodeId, Priority>::NextNodeToWrite() { | 391 NodeId SpdyPriorityForest<NodeId, Priority>::NextNodeToWrite() { |
386 return FirstMarkedNode(kReadyToWrite); | 392 return FirstMarkedNode(kReadyToWrite); |
387 } | 393 } |
388 | 394 |
389 template <typename NodeId, typename Priority> | 395 template <typename NodeId, typename Priority> |
390 bool SpdyPriorityForest<NodeId, Priority>::IsMarked( | 396 bool SpdyPriorityForest<NodeId, Priority>::IsMarked(NodeId node_id, |
391 NodeId node_id, unsigned int flag) const { | 397 unsigned int flag) const { |
392 const Node* node = FindNode(node_id); | 398 const Node* node = FindNode(node_id); |
393 return node != NULL && (node->flags & flag) != 0; | 399 return node != NULL && (node->flags & flag) != 0; |
394 } | 400 } |
395 | 401 |
396 template <typename NodeId, typename Priority> | 402 template <typename NodeId, typename Priority> |
397 bool SpdyPriorityForest<NodeId, Priority>::Mark( | 403 bool SpdyPriorityForest<NodeId, Priority>::Mark(NodeId node_id, |
398 NodeId node_id, unsigned int flag) { | 404 unsigned int flag) { |
399 if (!NodeExists(node_id)) { | 405 if (!NodeExists(node_id)) { |
400 return false; | 406 return false; |
401 } | 407 } |
402 all_nodes_[node_id].flags |= flag; | 408 all_nodes_[node_id].flags |= flag; |
403 return true; | 409 return true; |
404 } | 410 } |
405 | 411 |
406 template <typename NodeId, typename Priority> | 412 template <typename NodeId, typename Priority> |
407 bool SpdyPriorityForest<NodeId, Priority>::Unmark( | 413 bool SpdyPriorityForest<NodeId, Priority>::Unmark(NodeId node_id, |
408 NodeId node_id, unsigned int flag) { | 414 unsigned int flag) { |
409 if (!NodeExists(node_id)) { | 415 if (!NodeExists(node_id)) { |
410 return false; | 416 return false; |
411 } | 417 } |
412 all_nodes_[node_id].flags &= ~flag; | 418 all_nodes_[node_id].flags &= ~flag; |
413 return true; | 419 return true; |
414 } | 420 } |
415 | 421 |
416 template <typename NodeId, typename Priority> | 422 template <typename NodeId, typename Priority> |
417 NodeId SpdyPriorityForest<NodeId, Priority>::FirstMarkedNode( | 423 NodeId SpdyPriorityForest<NodeId, Priority>::FirstMarkedNode( |
418 unsigned int flag) { | 424 unsigned int flag) { |
419 // TODO(mdsteele): This is an *incredibly* stupid brute force solution. | 425 // TODO(mdsteele): This is an *incredibly* stupid brute force solution. |
420 | 426 |
421 // Get all root nodes that have at least one marked child. | 427 // Get all root nodes that have at least one marked child. |
422 uint64 total_weight = 0; | 428 uint64 total_weight = 0; |
423 std::map<uint64, NodeId> roots; // maps cumulative weight to root node ID | 429 std::map<uint64, NodeId> roots; // maps cumulative weight to root node ID |
424 for (typename NodeMap::const_iterator iter = all_nodes_.begin(); | 430 for (typename NodeMap::const_iterator iter = all_nodes_.begin(); |
425 iter != all_nodes_.end(); ++iter) { | 431 iter != all_nodes_.end(); |
| 432 ++iter) { |
426 const NodeId root_id = iter->first; | 433 const NodeId root_id = iter->first; |
427 const Node& root = iter->second; | 434 const Node& root = iter->second; |
428 if (root.type == ROOT_NODE) { | 435 if (root.type == ROOT_NODE) { |
429 // See if there is at least one marked node in this root's chain. | 436 // See if there is at least one marked node in this root's chain. |
430 for (const Node* node = &root; ; node = &all_nodes_[node->child]) { | 437 for (const Node* node = &root;; node = &all_nodes_[node->child]) { |
431 if ((node->flags & flag) != 0) { | 438 if ((node->flags & flag) != 0) { |
432 total_weight += static_cast<uint64>(root.depends_on.priority); | 439 total_weight += static_cast<uint64>(root.depends_on.priority); |
433 roots[total_weight] = root_id; | 440 roots[total_weight] = root_id; |
434 break; | 441 break; |
435 } | 442 } |
436 if (node->child == NodeId()) { | 443 if (node->child == NodeId()) { |
437 break; | 444 break; |
438 } | 445 } |
439 DCHECK(NodeExists(node->child)); | 446 DCHECK(NodeExists(node->child)); |
440 } | 447 } |
(...skipping 19 matching lines...) Expand all Loading... |
460 while (true) { | 467 while (true) { |
461 DCHECK(NodeExists(node_id)); | 468 DCHECK(NodeExists(node_id)); |
462 Node* node = &all_nodes_[node_id]; | 469 Node* node = &all_nodes_[node_id]; |
463 if ((node->flags & flag) != 0) { | 470 if ((node->flags & flag) != 0) { |
464 // There might be more nodes that are ready and that are linked to this | 471 // There might be more nodes that are ready and that are linked to this |
465 // one in an unordered chain. Find all of them, then pick one randomly. | 472 // one in an unordered chain. Find all of them, then pick one randomly. |
466 std::vector<NodeId> group; | 473 std::vector<NodeId> group; |
467 group.push_back(node_id); | 474 group.push_back(node_id); |
468 for (Node* next = node; next->child != NodeId();) { | 475 for (Node* next = node; next->child != NodeId();) { |
469 DCHECK(NodeExists(next->child)); | 476 DCHECK(NodeExists(next->child)); |
470 Node *child = &all_nodes_[next->child]; | 477 Node* child = &all_nodes_[next->child]; |
471 DCHECK_NE(ROOT_NODE, child->type); | 478 DCHECK_NE(ROOT_NODE, child->type); |
472 if (child->type != NONROOT_UNORDERED) { | 479 if (child->type != NONROOT_UNORDERED) { |
473 break; | 480 break; |
474 } | 481 } |
475 if ((child->flags & flag) != 0) { | 482 if ((child->flags & flag) != 0) { |
476 group.push_back(next->child); | 483 group.push_back(next->child); |
477 } | 484 } |
478 next = child; | 485 next = child; |
479 } | 486 } |
480 return group[base::RandGenerator(group.size())]; | 487 return group[base::RandGenerator(group.size())]; |
481 } | 488 } |
482 node_id = node->child; | 489 node_id = node->child; |
483 } | 490 } |
484 } | 491 } |
485 | 492 |
486 template <typename NodeId, typename Priority> | 493 template <typename NodeId, typename Priority> |
487 const typename SpdyPriorityForest<NodeId, Priority>::Node* | 494 const typename SpdyPriorityForest<NodeId, Priority>::Node* |
488 SpdyPriorityForest<NodeId, Priority>::FindNode(NodeId node_id) const { | 495 SpdyPriorityForest<NodeId, Priority>::FindNode(NodeId node_id) const { |
489 typename NodeMap::const_iterator iter = all_nodes_.find(node_id); | 496 typename NodeMap::const_iterator iter = all_nodes_.find(node_id); |
490 if (iter == all_nodes_.end()) { | 497 if (iter == all_nodes_.end()) { |
491 return NULL; | 498 return NULL; |
492 } | 499 } |
493 return &iter->second; | 500 return &iter->second; |
494 } | 501 } |
495 | 502 |
496 template <typename NodeId, typename Priority> | 503 template <typename NodeId, typename Priority> |
497 bool SpdyPriorityForest<NodeId, Priority>::ValidateInvariantsForTests() const { | 504 bool SpdyPriorityForest<NodeId, Priority>::ValidateInvariantsForTests() const { |
498 for (typename NodeMap::const_iterator iter = all_nodes_.begin(); | 505 for (typename NodeMap::const_iterator iter = all_nodes_.begin(); |
499 iter != all_nodes_.end(); ++iter) { | 506 iter != all_nodes_.end(); |
| 507 ++iter) { |
500 const NodeId node_id = iter->first; | 508 const NodeId node_id = iter->first; |
501 const Node& node = iter->second; | 509 const Node& node = iter->second; |
502 if (node.type != ROOT_NODE && | 510 if (node.type != ROOT_NODE && |
503 (!NodeExists(node.depends_on.parent_id) || | 511 (!NodeExists(node.depends_on.parent_id) || |
504 GetChild(node.depends_on.parent_id) != node_id)) { | 512 GetChild(node.depends_on.parent_id) != node_id)) { |
505 return false; | 513 return false; |
506 } | 514 } |
507 if (node.child != NodeId()) { | 515 if (node.child != NodeId()) { |
508 if (!NodeExists(node.child) || node_id != GetParent(node.child)) { | 516 if (!NodeExists(node.child) || node_id != GetParent(node.child)) { |
509 return false; | 517 return false; |
510 } | 518 } |
511 } | 519 } |
512 | 520 |
513 NodeId child_id = node.child; | 521 NodeId child_id = node.child; |
514 int count = 0; | 522 int count = 0; |
515 while (child_id != NodeId()) { | 523 while (child_id != NodeId()) { |
516 if (count > num_nodes() || node_id == child_id) { | 524 if (count > num_nodes() || node_id == child_id) { |
517 return false; | 525 return false; |
518 } | 526 } |
519 child_id = GetChild(child_id); | 527 child_id = GetChild(child_id); |
520 ++count; | 528 ++count; |
521 } | 529 } |
522 } | 530 } |
523 return true; | 531 return true; |
524 } | 532 } |
525 | 533 |
526 } // namespace net | 534 } // namespace net |
527 | 535 |
528 #endif // NET_SPDY_SPDY_PRIORITY_FOREST_H_ | 536 #endif // NET_SPDY_SPDY_PRIORITY_FOREST_H_ |
OLD | NEW |