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

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

Issue 2050005: Reland 46757. (Closed) Base URL: http://src.chromium.org/git/chromium.git
Patch Set: Reduce large iteration check. Created 10 years, 7 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
« 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) 2010 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2010 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/format_macros.h" 8 #include "base/format_macros.h"
9 #include "base/message_loop.h" 9 #include "base/message_loop.h"
10 #include "base/stats_counters.h" 10 #include "base/stats_counters.h"
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after
110 ClientSocketPoolBaseHelper::ClientSocketPoolBaseHelper( 110 ClientSocketPoolBaseHelper::ClientSocketPoolBaseHelper(
111 int max_sockets, 111 int max_sockets,
112 int max_sockets_per_group, 112 int max_sockets_per_group,
113 base::TimeDelta unused_idle_socket_timeout, 113 base::TimeDelta unused_idle_socket_timeout,
114 base::TimeDelta used_idle_socket_timeout, 114 base::TimeDelta used_idle_socket_timeout,
115 ConnectJobFactory* connect_job_factory, 115 ConnectJobFactory* connect_job_factory,
116 NetworkChangeNotifier* network_change_notifier) 116 NetworkChangeNotifier* network_change_notifier)
117 : idle_socket_count_(0), 117 : idle_socket_count_(0),
118 connecting_socket_count_(0), 118 connecting_socket_count_(0),
119 handed_out_socket_count_(0), 119 handed_out_socket_count_(0),
120 num_releasing_sockets_(0),
120 max_sockets_(max_sockets), 121 max_sockets_(max_sockets),
121 max_sockets_per_group_(max_sockets_per_group), 122 max_sockets_per_group_(max_sockets_per_group),
122 unused_idle_socket_timeout_(unused_idle_socket_timeout), 123 unused_idle_socket_timeout_(unused_idle_socket_timeout),
123 used_idle_socket_timeout_(used_idle_socket_timeout), 124 used_idle_socket_timeout_(used_idle_socket_timeout),
124 may_have_stalled_group_(false), 125 may_have_stalled_group_(false),
125 connect_job_factory_(connect_job_factory), 126 connect_job_factory_(connect_job_factory),
126 network_change_notifier_(network_change_notifier), 127 network_change_notifier_(network_change_notifier),
127 backup_jobs_enabled_(false), 128 backup_jobs_enabled_(false),
128 ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) { 129 ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) {
129 DCHECK_LE(0, max_sockets_per_group); 130 DCHECK_LE(0, max_sockets_per_group);
(...skipping 221 matching lines...) Expand 10 before | Expand all | Expand 10 after
351 } 352 }
352 return; 353 return;
353 } 354 }
354 } 355 }
355 } 356 }
356 357
357 void ClientSocketPoolBaseHelper::ReleaseSocket(const std::string& group_name, 358 void ClientSocketPoolBaseHelper::ReleaseSocket(const std::string& group_name,
358 ClientSocket* socket) { 359 ClientSocket* socket) {
359 Group& group = group_map_[group_name]; 360 Group& group = group_map_[group_name];
360 group.num_releasing_sockets++; 361 group.num_releasing_sockets++;
362 num_releasing_sockets_++;
361 DCHECK_LE(group.num_releasing_sockets, group.active_socket_count); 363 DCHECK_LE(group.num_releasing_sockets, group.active_socket_count);
362 // Run this asynchronously to allow the caller to finish before we let 364 // Run this asynchronously to allow the caller to finish before we let
363 // another to begin doing work. This also avoids nasty recursion issues. 365 // another to begin doing work. This also avoids nasty recursion issues.
364 // NOTE: We cannot refer to the handle argument after this method returns. 366 // NOTE: We cannot refer to the handle argument after this method returns.
365 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod( 367 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
366 this, &ClientSocketPoolBaseHelper::DoReleaseSocket, group_name, socket)); 368 this, &ClientSocketPoolBaseHelper::DoReleaseSocket, group_name, socket));
367 } 369 }
368 370
369 void ClientSocketPoolBaseHelper::CloseIdleSockets() { 371 void ClientSocketPoolBaseHelper::CloseIdleSockets() {
370 CleanupIdleSockets(true); 372 CleanupIdleSockets(true);
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after
475 477
476 group.num_releasing_sockets--; 478 group.num_releasing_sockets--;
477 DCHECK_GE(group.num_releasing_sockets, 0); 479 DCHECK_GE(group.num_releasing_sockets, 0);
478 480
479 CHECK_GT(handed_out_socket_count_, 0); 481 CHECK_GT(handed_out_socket_count_, 0);
480 handed_out_socket_count_--; 482 handed_out_socket_count_--;
481 483
482 CHECK_GT(group.active_socket_count, 0); 484 CHECK_GT(group.active_socket_count, 0);
483 group.active_socket_count--; 485 group.active_socket_count--;
484 486
487 CHECK_GT(num_releasing_sockets_, 0);
488 num_releasing_sockets_--;
489
485 const bool can_reuse = socket->IsConnectedAndIdle(); 490 const bool can_reuse = socket->IsConnectedAndIdle();
486 if (can_reuse) { 491 if (can_reuse) {
487 AddIdleSocket(socket, true /* used socket */, &group); 492 AddIdleSocket(socket, true /* used socket */, &group);
488 } else { 493 } else {
489 delete socket; 494 delete socket;
490 } 495 }
491 496
492 OnAvailableSocketSlot(group_name, &group);
493
494 // If there are no more releasing sockets, then we might have to process 497 // If there are no more releasing sockets, then we might have to process
495 // multiple available socket slots, since we stalled their processing until 498 // multiple available socket slots, since we stalled their processing until
496 // all sockets have been released. 499 // all sockets have been released. Note that ProcessPendingRequest() will
497 i = group_map_.find(group_name); 500 // invoke user callbacks, so |num_releasing_sockets_| may change.
498 if (i == group_map_.end() || i->second.num_releasing_sockets > 0) 501 //
499 return; 502 // This code has been known to infinite loop. Set a counter and CHECK to make
503 // sure it doesn't get ridiculously high.
500 504
501 while (true) { 505 int iterations = 0;
502 // We can't activate more sockets since we're already at our global limit. 506 while (num_releasing_sockets_ == 0) {
503 if (ReachedMaxSocketsLimit()) 507 CHECK_LT(iterations, 1000) << "Probably stuck in an infinite loop.";
508 std::string top_group_name;
509 Group* top_group = NULL;
510 int stalled_group_count = FindTopStalledGroup(&top_group, &top_group_name);
511 if (stalled_group_count >= 1) {
512 if (ReachedMaxSocketsLimit()) {
513 // We can't activate more sockets since we're already at our global
514 // limit.
515 may_have_stalled_group_ = true;
516 return;
517 }
518
519 ProcessPendingRequest(top_group_name, top_group);
520 } else {
521 may_have_stalled_group_ = false;
504 return; 522 return;
523 }
505 524
506 // |group| might now be deleted. 525 iterations++;
507 i = group_map_.find(group_name);
508 if (i == group_map_.end())
509 return;
510
511 group = i->second;
512
513 // If we already have enough ConnectJobs to satisfy the pending requests,
514 // don't bother starting up more.
515 if (group.pending_requests.size() <= group.jobs.size())
516 return;
517
518 if (!group.HasAvailableSocketSlot(max_sockets_per_group_))
519 return;
520
521 OnAvailableSocketSlot(group_name, &group);
522 } 526 }
523 } 527 }
524 528
525 // Search for the highest priority pending request, amongst the groups that 529 // Search for the highest priority pending request, amongst the groups that
526 // are not at the |max_sockets_per_group_| limit. Note: for requests with 530 // are not at the |max_sockets_per_group_| limit. Note: for requests with
527 // the same priority, the winner is based on group hash ordering (and not 531 // the same priority, the winner is based on group hash ordering (and not
528 // insertion order). 532 // insertion order).
529 int ClientSocketPoolBaseHelper::FindTopStalledGroup(Group** group, 533 int ClientSocketPoolBaseHelper::FindTopStalledGroup(Group** group,
530 std::string* group_name) { 534 std::string* group_name) {
531 Group* top_group = NULL; 535 Group* top_group = NULL;
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after
633 OnAvailableSocketSlot(group_name, &group); 637 OnAvailableSocketSlot(group_name, &group);
634 } 638 }
635 } 639 }
636 640
637 void ClientSocketPoolBaseHelper::OnAvailableSocketSlot( 641 void ClientSocketPoolBaseHelper::OnAvailableSocketSlot(
638 const std::string& group_name, Group* group) { 642 const std::string& group_name, Group* group) {
639 if (may_have_stalled_group_) { 643 if (may_have_stalled_group_) {
640 std::string top_group_name; 644 std::string top_group_name;
641 Group* top_group = NULL; 645 Group* top_group = NULL;
642 int stalled_group_count = FindTopStalledGroup(&top_group, &top_group_name); 646 int stalled_group_count = FindTopStalledGroup(&top_group, &top_group_name);
643 if (stalled_group_count <= 1) 647 if (stalled_group_count == 0 ||
648 (stalled_group_count == 1 && top_group->num_releasing_sockets == 0)) {
644 may_have_stalled_group_ = false; 649 may_have_stalled_group_ = false;
650 }
645 if (stalled_group_count >= 1) 651 if (stalled_group_count >= 1)
646 ProcessPendingRequest(top_group_name, top_group); 652 ProcessPendingRequest(top_group_name, top_group);
647 } else if (!group->pending_requests.empty()) { 653 } else if (!group->pending_requests.empty()) {
648 ProcessPendingRequest(group_name, group); 654 ProcessPendingRequest(group_name, group);
649 // |group| may no longer be valid after this point. Be careful not to 655 // |group| may no longer be valid after this point. Be careful not to
650 // access it again. 656 // access it again.
651 } else if (group->IsEmpty()) { 657 } else if (group->IsEmpty()) {
652 // Delete |group| if no longer needed. |group| will no longer be valid. 658 // Delete |group| if no longer needed. |group| will no longer be valid.
653 group_map_.erase(group_name); 659 group_map_.erase(group_name);
654 } 660 }
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
736 DCHECK_LE(total, max_sockets_); 742 DCHECK_LE(total, max_sockets_);
737 if (total < max_sockets_) 743 if (total < max_sockets_)
738 return false; 744 return false;
739 LOG(WARNING) << "ReachedMaxSocketsLimit: " << total << "/" << max_sockets_; 745 LOG(WARNING) << "ReachedMaxSocketsLimit: " << total << "/" << max_sockets_;
740 return true; 746 return true;
741 } 747 }
742 748
743 } // namespace internal 749 } // namespace internal
744 750
745 } // namespace net 751 } // 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