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

Side by Side Diff: net/socket/client_socket_pool_base.cc

Issue 149027: Limit total number of sockets in the system.... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: reorder Created 11 years, 5 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/socket/client_socket_pool_base.h ('k') | net/socket/client_socket_pool_base_unittest.cc » ('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/socket/client_socket_pool_base.h" 5 #include "net/socket/client_socket_pool_base.h"
6 6
7 #include "base/compiler_specific.h" 7 #include "base/compiler_specific.h"
8 #include "base/message_loop.h" 8 #include "base/message_loop.h"
9 #include "base/stl_util-inl.h" 9 #include "base/stl_util-inl.h"
10 #include "base/time.h" 10 #include "base/time.h"
(...skipping 29 matching lines...) Expand all
40 delegate_(delegate), 40 delegate_(delegate),
41 load_state_(LOAD_STATE_IDLE) { 41 load_state_(LOAD_STATE_IDLE) {
42 DCHECK(!group_name.empty()); 42 DCHECK(!group_name.empty());
43 DCHECK(key_handle); 43 DCHECK(key_handle);
44 DCHECK(delegate); 44 DCHECK(delegate);
45 } 45 }
46 46
47 ConnectJob::~ConnectJob() {} 47 ConnectJob::~ConnectJob() {}
48 48
49 ClientSocketPoolBase::ClientSocketPoolBase( 49 ClientSocketPoolBase::ClientSocketPoolBase(
50 int max_sockets,
50 int max_sockets_per_group, 51 int max_sockets_per_group,
51 ConnectJobFactory* connect_job_factory) 52 ConnectJobFactory* connect_job_factory)
52 : idle_socket_count_(0), 53 : idle_socket_count_(0),
54 connecting_socket_count_(0),
55 handed_out_socket_count_(0),
56 max_sockets_(max_sockets),
53 max_sockets_per_group_(max_sockets_per_group), 57 max_sockets_per_group_(max_sockets_per_group),
54 connect_job_factory_(connect_job_factory) {} 58 may_have_stalled_group_(false),
59 connect_job_factory_(connect_job_factory) {
60 DCHECK_LE(0, max_sockets_per_group);
61 DCHECK_LE(max_sockets_per_group, max_sockets);
62 }
55 63
56 ClientSocketPoolBase::~ClientSocketPoolBase() { 64 ClientSocketPoolBase::~ClientSocketPoolBase() {
57 if (g_late_binding) 65 if (g_late_binding)
58 CancelAllConnectJobs(); 66 CancelAllConnectJobs();
59 // Clean up any idle sockets. Assert that we have no remaining active 67 // Clean up any idle sockets. Assert that we have no remaining active
60 // sockets or pending requests. They should have all been cleaned up prior 68 // sockets or pending requests. They should have all been cleaned up prior
61 // to the manager being destroyed. 69 // to the manager being destroyed.
62 CloseIdleSockets(); 70 CloseIdleSockets();
63 DCHECK(group_map_.empty()); 71 DCHECK(group_map_.empty());
64 DCHECK(connect_job_map_.empty()); 72 DCHECK(connect_job_map_.empty());
(...skipping 17 matching lines...) Expand all
82 const HostResolver::RequestInfo& resolve_info, 90 const HostResolver::RequestInfo& resolve_info,
83 int priority, 91 int priority,
84 ClientSocketHandle* handle, 92 ClientSocketHandle* handle,
85 CompletionCallback* callback) { 93 CompletionCallback* callback) {
86 DCHECK(!resolve_info.hostname().empty()); 94 DCHECK(!resolve_info.hostname().empty());
87 DCHECK_GE(priority, 0); 95 DCHECK_GE(priority, 0);
88 DCHECK(callback); 96 DCHECK(callback);
89 Group& group = group_map_[group_name]; 97 Group& group = group_map_[group_name];
90 98
91 // Can we make another active socket now? 99 // Can we make another active socket now?
92 if (!group.HasAvailableSocketSlot(max_sockets_per_group_)) { 100 if (ReachedMaxSocketsLimit() ||
101 !group.HasAvailableSocketSlot(max_sockets_per_group_)) {
102 if (ReachedMaxSocketsLimit()) {
103 // We could check if we really have a stalled group here, but it requires
104 // a scan of all groups, so just flip a flag here, and do the check later.
105 may_have_stalled_group_ = true;
106 }
93 CHECK(callback); 107 CHECK(callback);
94 Request r(handle, callback, priority, resolve_info); 108 Request r(handle, callback, priority, resolve_info);
95 InsertRequestIntoQueue(r, &group.pending_requests); 109 InsertRequestIntoQueue(r, &group.pending_requests);
96 return ERR_IO_PENDING; 110 return ERR_IO_PENDING;
97 } 111 }
98 112
99 while (!group.idle_sockets.empty()) { 113 while (!group.idle_sockets.empty()) {
100 IdleSocket idle_socket = group.idle_sockets.back(); 114 IdleSocket idle_socket = group.idle_sockets.back();
101 group.idle_sockets.pop_back(); 115 group.idle_sockets.pop_back();
102 DecrementIdleCount(); 116 DecrementIdleCount();
(...skipping 10 matching lines...) Expand all
113 CHECK(callback); 127 CHECK(callback);
114 Request r(handle, callback, priority, resolve_info); 128 Request r(handle, callback, priority, resolve_info);
115 scoped_ptr<ConnectJob> connect_job( 129 scoped_ptr<ConnectJob> connect_job(
116 connect_job_factory_->NewConnectJob(group_name, r, this)); 130 connect_job_factory_->NewConnectJob(group_name, r, this));
117 131
118 int rv = connect_job->Connect(); 132 int rv = connect_job->Connect();
119 if (rv == OK) { 133 if (rv == OK) {
120 HandOutSocket(connect_job->ReleaseSocket(), false /* not reused */, 134 HandOutSocket(connect_job->ReleaseSocket(), false /* not reused */,
121 handle, &group); 135 handle, &group);
122 } else if (rv == ERR_IO_PENDING) { 136 } else if (rv == ERR_IO_PENDING) {
137 connecting_socket_count_++;
138
123 ConnectJob* job = connect_job.release(); 139 ConnectJob* job = connect_job.release();
124 if (g_late_binding) { 140 if (g_late_binding) {
125 CHECK(!ContainsKey(connect_job_map_, handle)); 141 CHECK(!ContainsKey(connect_job_map_, handle));
126 InsertRequestIntoQueue(r, &group.pending_requests); 142 InsertRequestIntoQueue(r, &group.pending_requests);
127 } else { 143 } else {
128 group.connecting_requests[handle] = r; 144 group.connecting_requests[handle] = r;
129 CHECK(!ContainsKey(connect_job_map_, handle)); 145 CHECK(!ContainsKey(connect_job_map_, handle));
130 connect_job_map_[handle] = job; 146 connect_job_map_[handle] = job;
131 } 147 }
132 group.jobs.insert(job); 148 group.jobs.insert(job);
(...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after
284 timer_.Stop(); 300 timer_.Stop();
285 } 301 }
286 302
287 void ClientSocketPoolBase::DoReleaseSocket(const std::string& group_name, 303 void ClientSocketPoolBase::DoReleaseSocket(const std::string& group_name,
288 ClientSocket* socket) { 304 ClientSocket* socket) {
289 GroupMap::iterator i = group_map_.find(group_name); 305 GroupMap::iterator i = group_map_.find(group_name);
290 CHECK(i != group_map_.end()); 306 CHECK(i != group_map_.end());
291 307
292 Group& group = i->second; 308 Group& group = i->second;
293 309
310 CHECK(handed_out_socket_count_ > 0);
311 handed_out_socket_count_--;
312
294 CHECK(group.active_socket_count > 0); 313 CHECK(group.active_socket_count > 0);
295 group.active_socket_count--; 314 group.active_socket_count--;
296 315
297 const bool can_reuse = socket->IsConnectedAndIdle(); 316 const bool can_reuse = socket->IsConnectedAndIdle();
298 if (can_reuse) { 317 if (can_reuse) {
299 AddIdleSocket(socket, true /* used socket */, &group); 318 AddIdleSocket(socket, true /* used socket */, &group);
300 } else { 319 } else {
301 delete socket; 320 delete socket;
302 } 321 }
303 322
304 OnAvailableSocketSlot(group_name, &group); 323 OnAvailableSocketSlot(group_name, &group);
305 } 324 }
306 325
326 // Search for the highest priority pending request, amongst the groups that
327 // are not at the |max_sockets_per_group_| limit. Note: for requests with
328 // the same priority, the winner is based on group hash ordering (and not
329 // insertion order).
330 int ClientSocketPoolBase::FindTopStalledGroup(Group** group,
331 std::string* group_name) {
332 Group* top_group = NULL;
333 const std::string* top_group_name = NULL;
334 int stalled_group_count = 0;
335 for (GroupMap::iterator i = group_map_.begin();
336 i != group_map_.end(); ++i) {
337 Group& group = i->second;
338 const RequestQueue& queue = group.pending_requests;
339 if (queue.empty())
340 continue;
341 bool has_slot = group.HasAvailableSocketSlot(max_sockets_per_group_);
342 if (has_slot)
343 stalled_group_count++;
344 bool has_higher_priority = !top_group ||
345 group.TopPendingPriority() > top_group->TopPendingPriority();
346 if (has_slot && has_higher_priority) {
347 top_group = &group;
348 top_group_name = &i->first;
349 }
350 }
351 if (top_group) {
352 *group = top_group;
353 *group_name = *top_group_name;
354 }
355 return stalled_group_count;
356 }
357
307 void ClientSocketPoolBase::OnConnectJobComplete(int result, ConnectJob* job) { 358 void ClientSocketPoolBase::OnConnectJobComplete(int result, ConnectJob* job) {
308 DCHECK_NE(ERR_IO_PENDING, result); 359 DCHECK_NE(ERR_IO_PENDING, result);
309 const std::string group_name = job->group_name(); 360 const std::string group_name = job->group_name();
310 GroupMap::iterator group_it = group_map_.find(group_name); 361 GroupMap::iterator group_it = group_map_.find(group_name);
311 CHECK(group_it != group_map_.end()); 362 CHECK(group_it != group_map_.end());
312 Group& group = group_it->second; 363 Group& group = group_it->second;
313 364
314 const ClientSocketHandle* const key_handle = job->key_handle(); 365 const ClientSocketHandle* const key_handle = job->key_handle();
315 scoped_ptr<ClientSocket> socket(job->ReleaseSocket()); 366 scoped_ptr<ClientSocket> socket(job->ReleaseSocket());
316 367
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
362 callback->Run(result); 413 callback->Run(result);
363 } 414 }
364 } 415 }
365 416
366 void ClientSocketPoolBase::EnableLateBindingOfSockets(bool enabled) { 417 void ClientSocketPoolBase::EnableLateBindingOfSockets(bool enabled) {
367 g_late_binding = enabled; 418 g_late_binding = enabled;
368 } 419 }
369 420
370 void ClientSocketPoolBase::RemoveConnectJob( 421 void ClientSocketPoolBase::RemoveConnectJob(
371 const ClientSocketHandle* handle, ConnectJob *job, Group* group) { 422 const ClientSocketHandle* handle, ConnectJob *job, Group* group) {
423 CHECK(connecting_socket_count_ > 0);
424 connecting_socket_count_--;
425
372 if (g_late_binding) { 426 if (g_late_binding) {
373 DCHECK(job); 427 DCHECK(job);
374 delete job; 428 delete job;
375 } else { 429 } else {
376 ConnectJobMap::iterator it = connect_job_map_.find(handle); 430 ConnectJobMap::iterator it = connect_job_map_.find(handle);
377 CHECK(it != connect_job_map_.end()); 431 CHECK(it != connect_job_map_.end());
378 job = it->second; 432 job = it->second;
379 delete job; 433 delete job;
380 connect_job_map_.erase(it); 434 connect_job_map_.erase(it);
381 group->connecting_requests.erase(handle); 435 group->connecting_requests.erase(handle);
(...skipping 10 matching lines...) Expand all
392 GroupMap::iterator it = group_map_.find(group_name); 446 GroupMap::iterator it = group_map_.find(group_name);
393 if (it != group_map_.end()) { 447 if (it != group_map_.end()) {
394 Group& group = it->second; 448 Group& group = it->second;
395 if (group.HasAvailableSocketSlot(max_sockets_per_group_)) 449 if (group.HasAvailableSocketSlot(max_sockets_per_group_))
396 OnAvailableSocketSlot(group_name, &group); 450 OnAvailableSocketSlot(group_name, &group);
397 } 451 }
398 } 452 }
399 453
400 void ClientSocketPoolBase::OnAvailableSocketSlot(const std::string& group_name, 454 void ClientSocketPoolBase::OnAvailableSocketSlot(const std::string& group_name,
401 Group* group) { 455 Group* group) {
402 if (!group->pending_requests.empty()) { 456 if (may_have_stalled_group_) {
457 std::string top_group_name;
458 Group* top_group;
459 int stalled_group_count = FindTopStalledGroup(&top_group, &top_group_name);
460 if (stalled_group_count <= 1)
461 may_have_stalled_group_ = false;
462 if (stalled_group_count >= 1)
463 ProcessPendingRequest(top_group_name, top_group);
464 } else if (!group->pending_requests.empty()) {
403 ProcessPendingRequest(group_name, group); 465 ProcessPendingRequest(group_name, group);
404 // |group| may no longer be valid after this point. Be careful not to 466 // |group| may no longer be valid after this point. Be careful not to
405 // access it again. 467 // access it again.
406 } else if (group->IsEmpty()) { 468 } else if (group->IsEmpty()) {
407 // Delete |group| if no longer needed. |group| will no longer be valid. 469 // Delete |group| if no longer needed. |group| will no longer be valid.
408 group_map_.erase(group_name); 470 group_map_.erase(group_name);
409 } 471 }
410 } 472 }
411 473
412 void ClientSocketPoolBase::ProcessPendingRequest(const std::string& group_name, 474 void ClientSocketPoolBase::ProcessPendingRequest(const std::string& group_name,
(...skipping 15 matching lines...) Expand all
428 } 490 }
429 491
430 void ClientSocketPoolBase::HandOutSocket( 492 void ClientSocketPoolBase::HandOutSocket(
431 ClientSocket* socket, 493 ClientSocket* socket,
432 bool reused, 494 bool reused,
433 ClientSocketHandle* handle, 495 ClientSocketHandle* handle,
434 Group* group) { 496 Group* group) {
435 DCHECK(socket); 497 DCHECK(socket);
436 handle->set_socket(socket); 498 handle->set_socket(socket);
437 handle->set_is_reused(reused); 499 handle->set_is_reused(reused);
500
501 handed_out_socket_count_++;
438 group->active_socket_count++; 502 group->active_socket_count++;
439 } 503 }
440 504
441 void ClientSocketPoolBase::AddIdleSocket( 505 void ClientSocketPoolBase::AddIdleSocket(
442 ClientSocket* socket, bool used, Group* group) { 506 ClientSocket* socket, bool used, Group* group) {
443 DCHECK(socket); 507 DCHECK(socket);
444 IdleSocket idle_socket; 508 IdleSocket idle_socket;
445 idle_socket.socket = socket; 509 idle_socket.socket = socket;
446 idle_socket.start_time = base::TimeTicks::Now(); 510 idle_socket.start_time = base::TimeTicks::Now();
447 idle_socket.used = used; 511 idle_socket.used = used;
(...skipping 10 matching lines...) Expand all
458 // Delete group if no longer needed. 522 // Delete group if no longer needed.
459 if (group.IsEmpty()) { 523 if (group.IsEmpty()) {
460 CHECK(group.pending_requests.empty()); 524 CHECK(group.pending_requests.empty());
461 group_map_.erase(i++); 525 group_map_.erase(i++);
462 } else { 526 } else {
463 ++i; 527 ++i;
464 } 528 }
465 } 529 }
466 } 530 }
467 531
532 bool ClientSocketPoolBase::ReachedMaxSocketsLimit() const {
533 // Each connecting socket will eventually connect and be handed out.
534 int total = handed_out_socket_count_ + connecting_socket_count_;
535 DCHECK_LE(total, max_sockets_);
536 return total == max_sockets_;
537 }
538
468 } // namespace net 539 } // namespace net
OLDNEW
« no previous file with comments | « net/socket/client_socket_pool_base.h ('k') | net/socket/client_socket_pool_base_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698