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 |