| OLD | NEW |
| 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 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 180 int ClientSocketPoolBaseHelper::RequestSocketInternal( | 180 int ClientSocketPoolBaseHelper::RequestSocketInternal( |
| 181 const std::string& group_name, | 181 const std::string& group_name, |
| 182 const Request* request) { | 182 const Request* request) { |
| 183 DCHECK_GE(request->priority(), 0); | 183 DCHECK_GE(request->priority(), 0); |
| 184 CompletionCallback* const callback = request->callback(); | 184 CompletionCallback* const callback = request->callback(); |
| 185 CHECK(callback); | 185 CHECK(callback); |
| 186 ClientSocketHandle* const handle = request->handle(); | 186 ClientSocketHandle* const handle = request->handle(); |
| 187 CHECK(handle); | 187 CHECK(handle); |
| 188 Group& group = group_map_[group_name]; | 188 Group& group = group_map_[group_name]; |
| 189 | 189 |
| 190 // Can we make another active socket now? | |
| 191 if (ReachedMaxSocketsLimit() || | |
| 192 !group.HasAvailableSocketSlot(max_sockets_per_group_)) { | |
| 193 if (ReachedMaxSocketsLimit()) { | |
| 194 // We could check if we really have a stalled group here, but it requires | |
| 195 // a scan of all groups, so just flip a flag here, and do the check later. | |
| 196 may_have_stalled_group_ = true; | |
| 197 | |
| 198 request->net_log().AddEvent(NetLog::TYPE_SOCKET_POOL_STALLED_MAX_SOCKETS, | |
| 199 NULL); | |
| 200 } else { | |
| 201 request->net_log().AddEvent( | |
| 202 NetLog::TYPE_SOCKET_POOL_STALLED_MAX_SOCKETS_PER_GROUP, NULL); | |
| 203 } | |
| 204 return ERR_IO_PENDING; | |
| 205 } | |
| 206 | |
| 207 // Try to reuse a socket. | 190 // Try to reuse a socket. |
| 208 while (!group.idle_sockets.empty()) { | 191 while (!group.idle_sockets.empty()) { |
| 209 IdleSocket idle_socket = group.idle_sockets.back(); | 192 IdleSocket idle_socket = group.idle_sockets.back(); |
| 210 group.idle_sockets.pop_back(); | 193 group.idle_sockets.pop_back(); |
| 211 DecrementIdleCount(); | 194 DecrementIdleCount(); |
| 212 if (idle_socket.socket->IsConnectedAndIdle()) { | 195 if (idle_socket.socket->IsConnectedAndIdle()) { |
| 213 // We found one we can reuse! | 196 // We found one we can reuse! |
| 214 base::TimeDelta idle_time = | 197 base::TimeDelta idle_time = |
| 215 base::TimeTicks::Now() - idle_socket.start_time; | 198 base::TimeTicks::Now() - idle_socket.start_time; |
| 216 HandOutSocket( | 199 HandOutSocket( |
| 217 idle_socket.socket, idle_socket.used, handle, idle_time, &group, | 200 idle_socket.socket, idle_socket.used, handle, idle_time, &group, |
| 218 request->net_log()); | 201 request->net_log()); |
| 219 return OK; | 202 return OK; |
| 220 } | 203 } |
| 221 delete idle_socket.socket; | 204 delete idle_socket.socket; |
| 222 } | 205 } |
| 223 | 206 |
| 207 // Can we make another active socket now? |
| 208 if (!group.HasAvailableSocketSlot(max_sockets_per_group_)) { |
| 209 request->net_log().AddEvent( |
| 210 NetLog::TYPE_SOCKET_POOL_STALLED_MAX_SOCKETS_PER_GROUP, NULL); |
| 211 return ERR_IO_PENDING; |
| 212 } |
| 213 |
| 214 if (ReachedMaxSocketsLimit()) { |
| 215 if (idle_socket_count() > 0) { |
| 216 CloseOneIdleSocket(); |
| 217 } else { |
| 218 // We could check if we really have a stalled group here, but it requires |
| 219 // a scan of all groups, so just flip a flag here, and do the check later. |
| 220 may_have_stalled_group_ = true; |
| 221 request->net_log().AddEvent( |
| 222 NetLog::TYPE_SOCKET_POOL_STALLED_MAX_SOCKETS, NULL); |
| 223 return ERR_IO_PENDING; |
| 224 } |
| 225 } |
| 226 |
| 224 // See if we already have enough connect jobs or sockets that will be released | 227 // See if we already have enough connect jobs or sockets that will be released |
| 225 // soon. | 228 // soon. |
| 226 if (group.HasReleasingSockets()) { | 229 if (group.HasReleasingSockets()) { |
| 227 return ERR_IO_PENDING; | 230 return ERR_IO_PENDING; |
| 228 } | 231 } |
| 229 | 232 |
| 230 // We couldn't find a socket to reuse, so allocate and connect a new one. | 233 // We couldn't find a socket to reuse, so allocate and connect a new one. |
| 231 BoundNetLog job_net_log = BoundNetLog::Make( | 234 BoundNetLog job_net_log = BoundNetLog::Make( |
| 232 request->net_log().net_log(), NetLog::SOURCE_CONNECT_JOB); | 235 request->net_log().net_log(), NetLog::SOURCE_CONNECT_JOB); |
| 233 request->net_log().BeginEvent( | 236 request->net_log().BeginEvent( |
| (...skipping 261 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 495 // sure it doesn't get ridiculously high. | 498 // sure it doesn't get ridiculously high. |
| 496 | 499 |
| 497 int iterations = 0; | 500 int iterations = 0; |
| 498 while (num_releasing_sockets_ == 0) { | 501 while (num_releasing_sockets_ == 0) { |
| 499 CHECK_LT(iterations, 1000) << "Probably stuck in an infinite loop."; | 502 CHECK_LT(iterations, 1000) << "Probably stuck in an infinite loop."; |
| 500 std::string top_group_name; | 503 std::string top_group_name; |
| 501 Group* top_group = NULL; | 504 Group* top_group = NULL; |
| 502 int stalled_group_count = FindTopStalledGroup(&top_group, &top_group_name); | 505 int stalled_group_count = FindTopStalledGroup(&top_group, &top_group_name); |
| 503 if (stalled_group_count >= 1) { | 506 if (stalled_group_count >= 1) { |
| 504 if (ReachedMaxSocketsLimit()) { | 507 if (ReachedMaxSocketsLimit()) { |
| 505 // We can't activate more sockets since we're already at our global | 508 if (idle_socket_count() > 0) { |
| 506 // limit. | 509 CloseOneIdleSocket(); |
| 507 may_have_stalled_group_ = true; | 510 } else { |
| 508 return; | 511 // We can't activate more sockets since we're already at our global |
| 512 // limit. |
| 513 may_have_stalled_group_ = true; |
| 514 return; |
| 515 } |
| 509 } | 516 } |
| 510 | 517 |
| 511 ProcessPendingRequest(top_group_name, top_group); | 518 ProcessPendingRequest(top_group_name, top_group); |
| 512 } else { | 519 } else { |
| 513 may_have_stalled_group_ = false; | 520 may_have_stalled_group_ = false; |
| 514 return; | 521 return; |
| 515 } | 522 } |
| 516 | 523 |
| 517 iterations++; | 524 iterations++; |
| 518 } | 525 } |
| (...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 629 void ClientSocketPoolBaseHelper::OnAvailableSocketSlot( | 636 void ClientSocketPoolBaseHelper::OnAvailableSocketSlot( |
| 630 const std::string& group_name, Group* group) { | 637 const std::string& group_name, Group* group) { |
| 631 if (may_have_stalled_group_) { | 638 if (may_have_stalled_group_) { |
| 632 std::string top_group_name; | 639 std::string top_group_name; |
| 633 Group* top_group = NULL; | 640 Group* top_group = NULL; |
| 634 int stalled_group_count = FindTopStalledGroup(&top_group, &top_group_name); | 641 int stalled_group_count = FindTopStalledGroup(&top_group, &top_group_name); |
| 635 if (stalled_group_count == 0 || | 642 if (stalled_group_count == 0 || |
| 636 (stalled_group_count == 1 && top_group->num_releasing_sockets == 0)) { | 643 (stalled_group_count == 1 && top_group->num_releasing_sockets == 0)) { |
| 637 may_have_stalled_group_ = false; | 644 may_have_stalled_group_ = false; |
| 638 } | 645 } |
| 639 if (stalled_group_count >= 1) | 646 if (stalled_group_count >= 1) { |
| 647 CHECK_GE(1, idle_socket_count()); |
| 640 ProcessPendingRequest(top_group_name, top_group); | 648 ProcessPendingRequest(top_group_name, top_group); |
| 649 } |
| 641 } else if (!group->pending_requests.empty()) { | 650 } else if (!group->pending_requests.empty()) { |
| 642 ProcessPendingRequest(group_name, group); | 651 ProcessPendingRequest(group_name, group); |
| 643 // |group| may no longer be valid after this point. Be careful not to | 652 // |group| may no longer be valid after this point. Be careful not to |
| 644 // access it again. | 653 // access it again. |
| 645 } else if (group->IsEmpty()) { | 654 } else if (group->IsEmpty()) { |
| 646 // Delete |group| if no longer needed. |group| will no longer be valid. | 655 // Delete |group| if no longer needed. |group| will no longer be valid. |
| 647 group_map_.erase(group_name); | 656 group_map_.erase(group_name); |
| 648 } | 657 } |
| 649 } | 658 } |
| 650 | 659 |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 719 if (group.IsEmpty()) { | 728 if (group.IsEmpty()) { |
| 720 group_map_.erase(i++); | 729 group_map_.erase(i++); |
| 721 } else { | 730 } else { |
| 722 ++i; | 731 ++i; |
| 723 } | 732 } |
| 724 } | 733 } |
| 725 } | 734 } |
| 726 | 735 |
| 727 bool ClientSocketPoolBaseHelper::ReachedMaxSocketsLimit() const { | 736 bool ClientSocketPoolBaseHelper::ReachedMaxSocketsLimit() const { |
| 728 // Each connecting socket will eventually connect and be handed out. | 737 // Each connecting socket will eventually connect and be handed out. |
| 729 int total = handed_out_socket_count_ + connecting_socket_count_; | 738 int total = handed_out_socket_count_ + connecting_socket_count_ + |
| 739 idle_socket_count(); |
| 730 DCHECK_LE(total, max_sockets_); | 740 DCHECK_LE(total, max_sockets_); |
| 731 if (total < max_sockets_) | 741 if (total < max_sockets_) |
| 732 return false; | 742 return false; |
| 733 LOG(WARNING) << "ReachedMaxSocketsLimit: " << total << "/" << max_sockets_; | 743 LOG(WARNING) << "ReachedMaxSocketsLimit: " << total << "/" << max_sockets_; |
| 734 return true; | 744 return true; |
| 735 } | 745 } |
| 736 | 746 |
| 747 void ClientSocketPoolBaseHelper::CloseOneIdleSocket() { |
| 748 CHECK_GT(idle_socket_count(), 0); |
| 749 |
| 750 for (GroupMap::iterator i = group_map_.begin(); i != group_map_.end(); ++i) { |
| 751 Group& group = i->second; |
| 752 |
| 753 if (!group.idle_sockets.empty()) { |
| 754 std::deque<IdleSocket>::iterator j = group.idle_sockets.begin(); |
| 755 delete j->socket; |
| 756 group.idle_sockets.erase(j); |
| 757 DecrementIdleCount(); |
| 758 if (group.IsEmpty()) |
| 759 group_map_.erase(i); |
| 760 |
| 761 return; |
| 762 } |
| 763 } |
| 764 |
| 765 LOG(DFATAL) << "No idle socket found to close!."; |
| 766 } |
| 767 |
| 737 } // namespace internal | 768 } // namespace internal |
| 738 | 769 |
| 739 } // namespace net | 770 } // namespace net |
| OLD | NEW |