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

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

Issue 989523005: Avoid duplicates in SPDY's write blocked list. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Use hash_map. Created 5 years, 9 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
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 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_WRITE_BLOCKED_LIST_H_ 5 #ifndef NET_SPDY_WRITE_BLOCKED_LIST_H_
6 #define NET_SPDY_WRITE_BLOCKED_LIST_H_ 6 #define NET_SPDY_WRITE_BLOCKED_LIST_H_
7 7
8 #include <algorithm> 8 #include <algorithm>
9 #include <deque> 9 #include <deque>
10 10
11 #include "base/containers/hash_tables.h"
11 #include "base/logging.h" 12 #include "base/logging.h"
12 #include "net/spdy/spdy_protocol.h" 13 #include "net/spdy/spdy_protocol.h"
13 14
14 namespace { 15 namespace {
15 class WriteBlockedListPeer; 16 class WriteBlockedListPeer;
16 } 17 }
17 18
18 namespace net { 19 namespace net {
19 20
20 const int kHighestPriority = 0; 21 const int kHighestPriority = 0;
21 const int kLowestPriority = 7; 22 const int kLowestPriority = 7;
22 23
23 template <typename IdType> 24 template <typename IdType>
24 class WriteBlockedList { 25 class WriteBlockedList {
25 public: 26 public:
26 // 0(1) size lookup. 0(1) insert at front or back. 27 // 0(1) size lookup. 0(1) insert at front or back.
27 typedef std::deque<IdType> BlockedList; 28 typedef std::deque<IdType> BlockedList;
28 typedef typename BlockedList::iterator iterator; 29 typedef typename BlockedList::iterator iterator;
29 30
31 explicit WriteBlockedList(bool use_stream_to_priority_map)
32 : use_stream_to_priority_(use_stream_to_priority_map) {}
33
30 static SpdyPriority ClampPriority(SpdyPriority priority) { 34 static SpdyPriority ClampPriority(SpdyPriority priority) {
31 if (priority < kHighestPriority) { 35 if (priority < kHighestPriority) {
32 LOG(DFATAL) << "Invalid priority: " << static_cast<int>(priority); 36 LOG(DFATAL) << "Invalid priority: " << static_cast<int>(priority);
33 return kHighestPriority; 37 return kHighestPriority;
34 } 38 }
35 if (priority > kLowestPriority) { 39 if (priority > kLowestPriority) {
36 LOG(DFATAL) << "Invalid priority: " << static_cast<int>(priority); 40 LOG(DFATAL) << "Invalid priority: " << static_cast<int>(priority);
37 return kLowestPriority; 41 return kLowestPriority;
38 } 42 }
39 return priority; 43 return priority;
40 } 44 }
41 45
42 // Returns the priority of the highest priority list with sessions on it. 46 // Returns the priority of the highest priority list with sessions on it.
43 SpdyPriority GetHighestPriorityWriteBlockedList() const { 47 SpdyPriority GetHighestPriorityWriteBlockedList() const {
44 for (SpdyPriority i = 0; i <= kLowestPriority; ++i) { 48 for (SpdyPriority i = 0; i <= kLowestPriority; ++i) {
45 if (write_blocked_lists_[i].size() > 0) 49 if (write_blocked_lists_[i].size() > 0)
46 return i; 50 return i;
47 } 51 }
48 LOG(DFATAL) << "No blocked streams"; 52 LOG(DFATAL) << "No blocked streams";
49 return kHighestPriority; 53 return kHighestPriority;
50 } 54 }
51 55
52 IdType PopFront(SpdyPriority priority) { 56 IdType PopFront(SpdyPriority priority) {
53 priority = ClampPriority(priority); 57 priority = ClampPriority(priority);
54 DCHECK(!write_blocked_lists_[priority].empty()); 58 DCHECK(!write_blocked_lists_[priority].empty());
55 IdType stream_id = write_blocked_lists_[priority].front(); 59 IdType stream_id = write_blocked_lists_[priority].front();
56 write_blocked_lists_[priority].pop_front(); 60 write_blocked_lists_[priority].pop_front();
61 if (use_stream_to_priority_) {
62 stream_to_priority_.erase(stream_id);
63 }
57 return stream_id; 64 return stream_id;
58 } 65 }
59 66
60 bool HasWriteBlockedStreamsGreaterThanPriority(SpdyPriority priority) const { 67 bool HasWriteBlockedStreamsGreaterThanPriority(SpdyPriority priority) const {
61 priority = ClampPriority(priority); 68 priority = ClampPriority(priority);
62 for (SpdyPriority i = kHighestPriority; i < priority; ++i) { 69 for (SpdyPriority i = kHighestPriority; i < priority; ++i) {
63 if (!write_blocked_lists_[i].empty()) { 70 if (!write_blocked_lists_[i].empty()) {
64 return true; 71 return true;
65 } 72 }
66 } 73 }
67 return false; 74 return false;
68 } 75 }
69 76
70 bool HasWriteBlockedStreams() const { 77 bool HasWriteBlockedStreams() const {
71 for (SpdyPriority i = kHighestPriority; i <= kLowestPriority; ++i) { 78 for (SpdyPriority i = kHighestPriority; i <= kLowestPriority; ++i) {
72 if (!write_blocked_lists_[i].empty()) { 79 if (!write_blocked_lists_[i].empty()) {
73 return true; 80 return true;
74 } 81 }
75 } 82 }
76 return false; 83 return false;
77 } 84 }
78 85
79 void PushBack(IdType stream_id, SpdyPriority priority) { 86 void PushBack(IdType stream_id, SpdyPriority priority) {
80 write_blocked_lists_[ClampPriority(priority)].push_back(stream_id); 87 priority = ClampPriority(priority);
88 DVLOG(2) << "Adding stream " << stream_id << " at priority "
89 << static_cast<int>(priority);
90 bool should_insert_stream = true;
91 if (use_stream_to_priority_) {
92 typename StreamToPriorityMap::iterator iter =
93 stream_to_priority_.find(stream_id);
94 if (iter != stream_to_priority_.end()) {
95 DVLOG(1) << "Stream " << stream_id << " already in write blocked list.";
96 if (iter->second == priority) {
97 // The stream is already in the write blocked list for the priority.
98 should_insert_stream = false;
99 } else {
100 // The stream is in a write blocked list for a different priority.
101 bool removed =
102 RemoveStreamFromWriteBlockedList(stream_id, iter->second);
103 DCHECK(removed);
104 }
105 }
106 if (should_insert_stream) {
107 stream_to_priority_[stream_id] = priority;
108 write_blocked_lists_[priority].push_back(stream_id);
109 }
110 } else {
111 write_blocked_lists_[priority].push_back(stream_id);
112 }
81 } 113 }
82 114
83 bool RemoveStreamFromWriteBlockedList(IdType stream_id, 115 bool RemoveStreamFromWriteBlockedList(IdType stream_id,
84 SpdyPriority priority) { 116 SpdyPriority priority) {
117 if (use_stream_to_priority_) {
118 typename StreamToPriorityMap::iterator iter =
119 stream_to_priority_.find(stream_id);
120 if (iter == stream_to_priority_.end()) {
121 // The stream is not present in the write blocked list.
122 return false;
123 } else if (iter->second == priority) {
124 stream_to_priority_.erase(iter);
125 } else {
126 // The stream is not present at the specified priority level.
127 return false;
128 }
129 }
85 // We shouldn't really add a stream_id to a list multiple times, 130 // We shouldn't really add a stream_id to a list multiple times,
86 // but under some conditions it does happen. Doing a check in PushBack 131 // but under some conditions it does happen. Doing a check in PushBack
87 // would be too costly, so instead we check here to eliminate duplicates. 132 // would be too costly, so instead we check here to eliminate duplicates.
88 bool found = false; 133 bool found = false;
89 iterator it = std::find(write_blocked_lists_[priority].begin(), 134 iterator it = std::find(write_blocked_lists_[priority].begin(),
90 write_blocked_lists_[priority].end(), 135 write_blocked_lists_[priority].end(),
91 stream_id); 136 stream_id);
92 while (it != write_blocked_lists_[priority].end()) { 137 while (it != write_blocked_lists_[priority].end()) {
93 found = true; 138 found = true;
94 iterator next_it = write_blocked_lists_[priority].erase(it); 139 iterator next_it = write_blocked_lists_[priority].erase(it);
(...skipping 15 matching lines...) Expand all
110 } 155 }
111 156
112 size_t NumBlockedStreams() const { 157 size_t NumBlockedStreams() const {
113 size_t num_blocked_streams = 0; 158 size_t num_blocked_streams = 0;
114 for (SpdyPriority i = kHighestPriority; i <= kLowestPriority; ++i) { 159 for (SpdyPriority i = kHighestPriority; i <= kLowestPriority; ++i) {
115 num_blocked_streams += write_blocked_lists_[i].size(); 160 num_blocked_streams += write_blocked_lists_[i].size();
116 } 161 }
117 return num_blocked_streams; 162 return num_blocked_streams;
118 } 163 }
119 164
165 bool avoids_inserting_duplicates() const { return use_stream_to_priority_; }
166
120 private: 167 private:
121 friend WriteBlockedListPeer; 168 friend WriteBlockedListPeer;
169
170 typedef base::hash_map<IdType, SpdyPriority> StreamToPriorityMap;
171
122 BlockedList write_blocked_lists_[kLowestPriority + 1]; 172 BlockedList write_blocked_lists_[kLowestPriority + 1];
173 StreamToPriorityMap stream_to_priority_;
174 bool use_stream_to_priority_;
123 }; 175 };
124 176
125 } // namespace net 177 } // namespace net
126 178
127 #endif // NET_SPDY_WRITE_BLOCKED_LIST_H_ 179 #endif // NET_SPDY_WRITE_BLOCKED_LIST_H_
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698