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

Side by Side Diff: net/base/client_socket_pool.cc

Issue 62181: Add a bound on the total number of active sockets in ClientSocketPool.... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: do a gclient sync to update files Created 11 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 | Annotate | Revision Log
« no previous file with comments | « net/base/client_socket_pool.h ('k') | net/http/http_network_session.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2006-2008 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 #include "net/base/client_socket_pool.h" 5 #include "net/base/client_socket_pool.h"
6 6
7 #include "base/message_loop.h" 7 #include "base/message_loop.h"
8 #include "net/base/client_socket.h" 8 #include "net/base/client_socket.h"
9 #include "net/base/client_socket_handle.h" 9 #include "net/base/client_socket_handle.h"
10 #include "net/base/net_errors.h" 10 #include "net/base/net_errors.h"
(...skipping 10 matching lines...) Expand all
21 // some conditions. See http://crbug.com/4606. 21 // some conditions. See http://crbug.com/4606.
22 const int kCleanupInterval = 10; // DO NOT INCREASE THIS TIMEOUT. 22 const int kCleanupInterval = 10; // DO NOT INCREASE THIS TIMEOUT.
23 23
24 // The maximum duration, in seconds, to keep idle persistent sockets alive. 24 // The maximum duration, in seconds, to keep idle persistent sockets alive.
25 const int kIdleTimeout = 300; // 5 minutes. 25 const int kIdleTimeout = 300; // 5 minutes.
26 26
27 } // namespace 27 } // namespace
28 28
29 namespace net { 29 namespace net {
30 30
31 ClientSocketPool::ClientSocketPool(int max_sockets_per_group) 31 ClientSocketPool::ClientSocketPool(int max_sockets_per_group, int max_sockets)
32 : idle_socket_count_(0), 32 : idle_socket_count_(0),
33 max_sockets_per_group_(max_sockets_per_group) { 33 active_socket_count_(0),
34 max_sockets_per_group_(max_sockets_per_group),
35 max_sockets_(max_sockets),
36 may_have_stalled_group_(false) {
37 DCHECK(max_sockets_per_group <= max_sockets);
34 } 38 }
35 39
36 ClientSocketPool::~ClientSocketPool() { 40 ClientSocketPool::~ClientSocketPool() {
37 // Clean up any idle sockets. Assert that we have no remaining active 41 // Clean up any idle sockets. Assert that we have no remaining active
38 // sockets or pending requests. They should have all been cleaned up prior 42 // sockets or pending requests. They should have all been cleaned up prior
39 // to the manager being destroyed. 43 // to the manager being destroyed.
40 CloseIdleSockets(); 44 CloseIdleSockets();
41 DCHECK(group_map_.empty()); 45 DCHECK(group_map_.empty());
42 } 46 }
43 47
44 // InsertRequestIntoQueue inserts the request into the queue based on 48 // InsertRequestIntoQueue inserts the request into the queue based on
45 // priority. Highest priorities are closest to the front. Older requests are 49 // priority. Highest priorities are closest to the front. Older requests are
46 // prioritized over requests of equal priority. 50 // prioritized over requests of equal priority.
47 // 51 //
48 // static 52 // static
49 void ClientSocketPool::InsertRequestIntoQueue(const Request& r, 53 void ClientSocketPool::InsertRequestIntoQueue(const Request& r,
50 RequestQueue* pending_requests) { 54 RequestQueue* pending_requests) {
51 RequestQueue::iterator it = pending_requests->begin(); 55 RequestQueue::iterator it = pending_requests->begin();
52 while (it != pending_requests->end() && r.priority <= it->priority) 56 while (it != pending_requests->end() && r.priority <= it->priority)
53 ++it; 57 ++it;
54 pending_requests->insert(it, r); 58 pending_requests->insert(it, r);
55 } 59 }
56 60
57 int ClientSocketPool::RequestSocket(ClientSocketHandle* handle, 61 int ClientSocketPool::RequestSocket(ClientSocketHandle* handle,
58 int priority, 62 int priority,
59 CompletionCallback* callback) { 63 CompletionCallback* callback) {
60 Group& group = group_map_[handle->group_name_]; 64 Group& group = group_map_[handle->group_name_];
61 65
62 // Can we make another active socket now? 66 // Can we make another active socket now?
63 if (group.active_socket_count == max_sockets_per_group_) { 67 bool has_max_sockets = (active_socket_count_ == max_sockets_);
68 if (group.active_socket_count == max_sockets_per_group_ || has_max_sockets) {
69 may_have_stalled_group_ |= has_max_sockets;
64 Request r; 70 Request r;
65 r.handle = handle; 71 r.handle = handle;
66 DCHECK(callback); 72 DCHECK(callback);
67 r.callback = callback; 73 r.callback = callback;
68 r.priority = priority; 74 r.priority = priority;
69 InsertRequestIntoQueue(r, &group.pending_requests); 75 InsertRequestIntoQueue(r, &group.pending_requests);
70 return ERR_IO_PENDING; 76 return ERR_IO_PENDING;
71 } 77 }
72 78
73 // OK, we are going to activate one. 79 // OK, we are going to activate one.
74 group.active_socket_count++; 80 group.active_socket_count++;
81 active_socket_count_++;
75 82
76 // Use idle sockets in LIFO order because they're more likely to be 83 // Use idle sockets in LIFO order because they're more likely to be
77 // still reusable. 84 // still reusable.
78 while (!group.idle_sockets.empty()) { 85 while (!group.idle_sockets.empty()) {
79 IdleSocket idle_socket = group.idle_sockets.back(); 86 IdleSocket idle_socket = group.idle_sockets.back();
80 group.idle_sockets.pop_back(); 87 group.idle_sockets.pop_back();
81 DecrementIdleCount(); 88 DecrementIdleCount();
82 if ((*idle_socket.ptr)->IsConnectedAndIdle()) { 89 if ((*idle_socket.ptr)->IsConnectedAndIdle()) {
83 // We found one we can reuse! 90 // We found one we can reuse!
84 handle->socket_ = idle_socket.ptr; 91 handle->socket_ = idle_socket.ptr;
85 return OK; 92 return OK;
86 } 93 }
87 delete idle_socket.ptr; 94 delete idle_socket.ptr;
88 } 95 }
89 96
90 handle->socket_ = new ClientSocketPtr(); 97 handle->socket_ = new ClientSocketPtr();
91 return OK; 98 return OK;
92 } 99 }
93 100
94 void ClientSocketPool::CancelRequest(ClientSocketHandle* handle) { 101 void ClientSocketPool::CancelRequest(ClientSocketHandle* handle) {
95 Group& group = group_map_[handle->group_name_]; 102 GroupMap::iterator i = group_map_.find(handle->group_name_);
96 103 DCHECK(i != group_map_.end());
97 // In order for us to be canceling a pending request, we must have active 104 Group& group = i->second;
98 // sockets equaling the limit. NOTE: The correctness of the code doesn't
99 // require this assertion.
100 DCHECK(group.active_socket_count == max_sockets_per_group_);
101 105
102 // Search pending_requests for matching handle. 106 // Search pending_requests for matching handle.
103 std::deque<Request>::iterator it = group.pending_requests.begin(); 107 std::deque<Request>::iterator it = group.pending_requests.begin();
104 for (; it != group.pending_requests.end(); ++it) { 108 for (; it != group.pending_requests.end(); ++it) {
105 if (it->handle == handle) { 109 if (it->handle == handle) {
106 group.pending_requests.erase(it); 110 group.pending_requests.erase(it);
107 break; 111 break;
108 } 112 }
109 } 113 }
114
115 // Delete group if no longer needed.
116 if (group.empty())
117 group_map_.erase(i);
110 } 118 }
111 119
112 void ClientSocketPool::ReleaseSocket(ClientSocketHandle* handle) { 120 void ClientSocketPool::ReleaseSocket(ClientSocketHandle* handle) {
113 // Run this asynchronously to allow the caller to finish before we let 121 // Run this asynchronously to allow the caller to finish before we let
114 // another to begin doing work. This also avoids nasty recursion issues. 122 // another to begin doing work. This also avoids nasty recursion issues.
115 // NOTE: We cannot refer to the handle argument after this method returns. 123 // NOTE: We cannot refer to the handle argument after this method returns.
116 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod( 124 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
117 this, &ClientSocketPool::DoReleaseSocket, handle->group_name_, 125 this, &ClientSocketPool::DoReleaseSocket, handle->group_name_,
118 handle->socket_)); 126 handle->socket_));
119 } 127 }
(...skipping 25 matching lines...) Expand all
145 if (force || j->ShouldCleanup(now)) { 153 if (force || j->ShouldCleanup(now)) {
146 delete j->ptr; 154 delete j->ptr;
147 j = group.idle_sockets.erase(j); 155 j = group.idle_sockets.erase(j);
148 DecrementIdleCount(); 156 DecrementIdleCount();
149 } else { 157 } else {
150 ++j; 158 ++j;
151 } 159 }
152 } 160 }
153 161
154 // Delete group if no longer needed. 162 // Delete group if no longer needed.
155 if (group.active_socket_count == 0 && group.idle_sockets.empty()) { 163 if (group.empty()) {
156 DCHECK(group.pending_requests.empty());
157 group_map_.erase(i++); 164 group_map_.erase(i++);
158 } else { 165 } else {
159 ++i; 166 ++i;
160 } 167 }
161 } 168 }
162 } 169 }
163 170
164 void ClientSocketPool::IncrementIdleCount() { 171 void ClientSocketPool::IncrementIdleCount() {
165 if (++idle_socket_count_ == 1) 172 if (++idle_socket_count_ == 1)
166 timer_.Start(TimeDelta::FromSeconds(kCleanupInterval), this, 173 timer_.Start(TimeDelta::FromSeconds(kCleanupInterval), this,
167 &ClientSocketPool::OnCleanupTimerFired); 174 &ClientSocketPool::OnCleanupTimerFired);
168 } 175 }
169 176
170 void ClientSocketPool::DecrementIdleCount() { 177 void ClientSocketPool::DecrementIdleCount() {
171 if (--idle_socket_count_ == 0) 178 if (--idle_socket_count_ == 0)
172 timer_.Stop(); 179 timer_.Stop();
173 } 180 }
174 181
175 void ClientSocketPool::DoReleaseSocket(const std::string& group_name, 182 void ClientSocketPool::DoReleaseSocket(const std::string& group_name,
176 ClientSocketPtr* ptr) { 183 ClientSocketPtr* ptr) {
177 GroupMap::iterator i = group_map_.find(group_name); 184 GroupMap::iterator i = group_map_.find(group_name);
178 DCHECK(i != group_map_.end()); 185 DCHECK(i != group_map_.end());
179 186
180 Group& group = i->second; 187 Group& group = i->second;
181 188
182 DCHECK(group.active_socket_count > 0); 189 DCHECK(group.active_socket_count > 0);
190 DCHECK(active_socket_count_ > 0);
191
183 group.active_socket_count--; 192 group.active_socket_count--;
193 active_socket_count_--;
184 194
185 bool can_reuse = ptr->get() && (*ptr)->IsConnectedAndIdle(); 195 bool can_reuse = ptr->get() && (*ptr)->IsConnectedAndIdle();
186 if (can_reuse) { 196 if (can_reuse) {
187 IdleSocket idle_socket; 197 IdleSocket idle_socket;
188 idle_socket.ptr = ptr; 198 idle_socket.ptr = ptr;
189 idle_socket.start_time = base::TimeTicks::Now(); 199 idle_socket.start_time = base::TimeTicks::Now();
190 200
191 group.idle_sockets.push_back(idle_socket); 201 group.idle_sockets.push_back(idle_socket);
192 IncrementIdleCount(); 202 IncrementIdleCount();
193 } else { 203 } else {
194 delete ptr; 204 delete ptr;
195 } 205 }
196 206
197 // Process one pending request. 207 // Process one pending request.
198 if (!group.pending_requests.empty()) { 208 if (may_have_stalled_group_) {
199 Request r = group.pending_requests.front(); 209 // The highest priority pending request may belong to another group, so
200 group.pending_requests.pop_front(); 210 // check all of them. Worst-case this takes |max_sockets_| iterations.
201 int rv = RequestSocket(r.handle, r.priority, NULL); 211 if (Group* top_group = FindTopStalledGroup())
202 DCHECK(rv == OK); 212 StartPendingRequestForGroup(top_group);
203 r.callback->Run(rv); 213
204 return; 214 // Check if there are any stalled groups left.
215 if (!FindTopStalledGroup())
216 may_have_stalled_group_ = false;
217
218 } else if (!group.pending_requests.empty()) {
219 // Otherwise just dequeue the first pending request of |group|.
220 StartPendingRequestForGroup(&group);
205 } 221 }
206 222
207 // Delete group if no longer needed. 223 // Delete group if no longer needed.
208 if (group.active_socket_count == 0 && group.idle_sockets.empty()) { 224 if (group.empty())
209 DCHECK(group.pending_requests.empty());
210 group_map_.erase(i); 225 group_map_.erase(i);
226 }
227
228 void ClientSocketPool::StartPendingRequestForGroup(Group* group) {
229 Request r = group->pending_requests.front();
230 group->pending_requests.pop_front();
231 int rv = RequestSocket(r.handle, r.priority, NULL);
232 DCHECK(rv == OK);
233 r.callback->Run(rv);
234 }
235
236 // Search for the highest priority pending request, amongst the groups that
237 // are not at the |max_sockets_per_group_| limit. Note: for requests with
238 // the same priority, the winner is based on group hash ordering (and not
239 // insertion order).
240 ClientSocketPool::Group* ClientSocketPool::FindTopStalledGroup() {
241 Group* top_group = NULL;
242 for (GroupMap::iterator i = group_map_.begin(); i != group_map_.end(); ++i) {
243 Group* group = &i->second;
244 const RequestQueue& queue = group->pending_requests;
245 if (group->active_socket_count < max_sockets_per_group_ &&
246 !queue.empty() && (top_group == NULL || queue.front().priority >
247 top_group->pending_requests.front().priority)) {
248 top_group = group;
249 }
211 } 250 }
251 return top_group;
212 } 252 }
213 253
214 } // namespace net 254 } // namespace net
OLDNEW
« no previous file with comments | « net/base/client_socket_pool.h ('k') | net/http/http_network_session.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698