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

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

Issue 8340012: Close idle connections / SPDY sessions when needed. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: OVERRIDE Created 9 years, 1 month 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
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 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 <math.h> 7 #include <math.h>
8 #include "base/compiler_specific.h" 8 #include "base/compiler_specific.h"
9 #include "base/format_macros.h" 9 #include "base/format_macros.h"
10 #include "base/logging.h" 10 #include "base/logging.h"
(...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after
195 } 195 }
196 196
197 ClientSocketPoolBaseHelper::~ClientSocketPoolBaseHelper() { 197 ClientSocketPoolBaseHelper::~ClientSocketPoolBaseHelper() {
198 // Clean up any idle sockets and pending connect jobs. Assert that we have no 198 // Clean up any idle sockets and pending connect jobs. Assert that we have no
199 // remaining active sockets or pending requests. They should have all been 199 // remaining active sockets or pending requests. They should have all been
200 // cleaned up prior to |this| being destroyed. 200 // cleaned up prior to |this| being destroyed.
201 Flush(); 201 Flush();
202 DCHECK(group_map_.empty()); 202 DCHECK(group_map_.empty());
203 DCHECK(pending_callback_map_.empty()); 203 DCHECK(pending_callback_map_.empty());
204 DCHECK_EQ(0, connecting_socket_count_); 204 DCHECK_EQ(0, connecting_socket_count_);
205 DCHECK(higher_layer_pools_.empty());
205 206
206 NetworkChangeNotifier::RemoveIPAddressObserver(this); 207 NetworkChangeNotifier::RemoveIPAddressObserver(this);
207 } 208 }
208 209
209 // InsertRequestIntoQueue inserts the request into the queue based on 210 // InsertRequestIntoQueue inserts the request into the queue based on
210 // priority. Highest priorities are closest to the front. Older requests are 211 // priority. Highest priorities are closest to the front. Older requests are
211 // prioritized over requests of equal priority. 212 // prioritized over requests of equal priority.
212 // 213 //
213 // static 214 // static
214 void ClientSocketPoolBaseHelper::InsertRequestIntoQueue( 215 void ClientSocketPoolBaseHelper::InsertRequestIntoQueue(
215 const Request* r, RequestQueue* pending_requests) { 216 const Request* r, RequestQueue* pending_requests) {
216 RequestQueue::iterator it = pending_requests->begin(); 217 RequestQueue::iterator it = pending_requests->begin();
217 while (it != pending_requests->end() && r->priority() >= (*it)->priority()) 218 while (it != pending_requests->end() && r->priority() >= (*it)->priority())
218 ++it; 219 ++it;
219 pending_requests->insert(it, r); 220 pending_requests->insert(it, r);
220 } 221 }
221 222
222 // static 223 // static
223 const ClientSocketPoolBaseHelper::Request* 224 const ClientSocketPoolBaseHelper::Request*
224 ClientSocketPoolBaseHelper::RemoveRequestFromQueue( 225 ClientSocketPoolBaseHelper::RemoveRequestFromQueue(
225 const RequestQueue::iterator& it, Group* group) { 226 const RequestQueue::iterator& it, Group* group) {
226 const Request* req = *it; 227 const Request* req = *it;
227 group->mutable_pending_requests()->erase(it); 228 group->mutable_pending_requests()->erase(it);
228 // If there are no more requests, we kill the backup timer. 229 // If there are no more requests, we kill the backup timer.
229 if (group->pending_requests().empty()) 230 if (group->pending_requests().empty())
230 group->CleanupBackupJob(); 231 group->CleanupBackupJob();
231 return req; 232 return req;
232 } 233 }
233 234
235 void ClientSocketPoolBaseHelper::AddLayeredPool(LayeredPool* pool) {
236 CHECK(pool);
237 CHECK(!ContainsKey(higher_layer_pools_, pool));
238 higher_layer_pools_.insert(pool);
239 }
240
241 void ClientSocketPoolBaseHelper::RemoveLayeredPool(LayeredPool* pool) {
242 CHECK(pool);
243 CHECK(ContainsKey(higher_layer_pools_, pool));
244 higher_layer_pools_.erase(pool);
245 }
246
234 int ClientSocketPoolBaseHelper::RequestSocket( 247 int ClientSocketPoolBaseHelper::RequestSocket(
235 const std::string& group_name, 248 const std::string& group_name,
236 const Request* request) { 249 const Request* request) {
237 CHECK(request->callback()); 250 CHECK(request->callback());
238 CHECK(request->handle()); 251 CHECK(request->handle());
239 252
240 request->net_log().BeginEvent(NetLog::TYPE_SOCKET_POOL, NULL); 253 request->net_log().BeginEvent(NetLog::TYPE_SOCKET_POOL, NULL);
241 Group* group = GetOrCreateGroup(group_name); 254 Group* group = GetOrCreateGroup(group_name);
242 255
243 int rv = RequestSocketInternal(group_name, request); 256 int rv = RequestSocketInternal(group_name, request);
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
314 if (AssignIdleSocketToGroup(request, group)) 327 if (AssignIdleSocketToGroup(request, group))
315 return OK; 328 return OK;
316 } 329 }
317 330
318 if (!preconnecting && group->TryToUsePreconnectConnectJob()) 331 if (!preconnecting && group->TryToUsePreconnectConnectJob())
319 return ERR_IO_PENDING; 332 return ERR_IO_PENDING;
320 333
321 // Can we make another active socket now? 334 // Can we make another active socket now?
322 if (!group->HasAvailableSocketSlot(max_sockets_per_group_) && 335 if (!group->HasAvailableSocketSlot(max_sockets_per_group_) &&
323 !request->ignore_limits()) { 336 !request->ignore_limits()) {
337 // TODO(willchan): Consider whether or not we need to close a socket in a
338 // higher layered group. I don't think this makes sense since we would just
339 // reuse that socket then if we needed one and wouldn't make it down to this
340 // layer.
324 request->net_log().AddEvent( 341 request->net_log().AddEvent(
325 NetLog::TYPE_SOCKET_POOL_STALLED_MAX_SOCKETS_PER_GROUP, NULL); 342 NetLog::TYPE_SOCKET_POOL_STALLED_MAX_SOCKETS_PER_GROUP, NULL);
326 return ERR_IO_PENDING; 343 return ERR_IO_PENDING;
327 } 344 }
328 345
329 if (ReachedMaxSocketsLimit() && !request->ignore_limits()) { 346 if (ReachedMaxSocketsLimit() && !request->ignore_limits()) {
330 if (idle_socket_count() > 0) { 347 if (idle_socket_count() > 0) {
348 // There's an idle socket in this pool. Either that's because there's
349 // still one in this group, but we got here due to preconnecting bypassing
350 // idle sockets, or because there's an idle socket in another group.
331 bool closed = CloseOneIdleSocketExceptInGroup(group); 351 bool closed = CloseOneIdleSocketExceptInGroup(group);
332 if (preconnecting && !closed) 352 if (preconnecting && !closed)
333 return ERR_PRECONNECT_MAX_SOCKET_LIMIT; 353 return ERR_PRECONNECT_MAX_SOCKET_LIMIT;
334 } else { 354 } else if (!CloseOneIdleConnectionInLayeredPool()) {
mmenke 2011/10/27 18:52:37 Is this guaranteed to result in ReachedMaxSocketsL
willchan no longer on Chromium 2011/11/08 22:26:13 Sorry, I don't grok. Which path do you mean? Also
mmenke 2011/11/08 22:41:04 So you have a request with ignore_limits() set to
willchan no longer on Chromium 2011/11/15 18:44:06 GREAT catch. I'm impressed you caught this given y
335 // We could check if we really have a stalled group here, but it requires 355 // We could check if we really have a stalled group here, but it requires
336 // a scan of all groups, so just flip a flag here, and do the check later. 356 // a scan of all groups, so just flip a flag here, and do the check later.
337 request->net_log().AddEvent( 357 request->net_log().AddEvent(
338 NetLog::TYPE_SOCKET_POOL_STALLED_MAX_SOCKETS, NULL); 358 NetLog::TYPE_SOCKET_POOL_STALLED_MAX_SOCKETS, NULL);
339 return ERR_IO_PENDING; 359 return ERR_IO_PENDING;
340 } 360 }
341 } 361 }
342 362
343 // We couldn't find a socket to reuse, so allocate and connect a new one. 363 // We couldn't find a socket to reuse, and there's space to allocate one,
364 // so allocate and connect a new one.
344 scoped_ptr<ConnectJob> connect_job( 365 scoped_ptr<ConnectJob> connect_job(
345 connect_job_factory_->NewConnectJob(group_name, *request, this)); 366 connect_job_factory_->NewConnectJob(group_name, *request, this));
346 367
347 connect_job->Initialize(preconnecting); 368 connect_job->Initialize(preconnecting);
348 int rv = connect_job->Connect(); 369 int rv = connect_job->Connect();
349 if (rv == OK) { 370 if (rv == OK) {
350 LogBoundConnectJobToRequest(connect_job->net_log().source(), request); 371 LogBoundConnectJobToRequest(connect_job->net_log().source(), request);
351 if (!preconnecting) { 372 if (!preconnecting) {
352 HandOutSocket(connect_job->ReleaseSocket(), false /* not reused */, 373 HandOutSocket(connect_job->ReleaseSocket(), false /* not reused */,
353 handle, base::TimeDelta(), group, request->net_log()); 374 handle, base::TimeDelta(), group, request->net_log());
(...skipping 400 matching lines...) Expand 10 before | Expand all | Expand 10 after
754 // its limit, may be left with other stalled groups that could be 775 // its limit, may be left with other stalled groups that could be
755 // woken. This isn't optimal, but there is no starvation, so to avoid 776 // woken. This isn't optimal, but there is no starvation, so to avoid
756 // the looping we leave it at this. 777 // the looping we leave it at this.
757 OnAvailableSocketSlot(top_group_name, top_group); 778 OnAvailableSocketSlot(top_group_name, top_group);
758 } 779 }
759 780
760 // Search for the highest priority pending request, amongst the groups that 781 // Search for the highest priority pending request, amongst the groups that
761 // are not at the |max_sockets_per_group_| limit. Note: for requests with 782 // are not at the |max_sockets_per_group_| limit. Note: for requests with
762 // the same priority, the winner is based on group hash ordering (and not 783 // the same priority, the winner is based on group hash ordering (and not
763 // insertion order). 784 // insertion order).
764 bool ClientSocketPoolBaseHelper::FindTopStalledGroup(Group** group, 785 bool ClientSocketPoolBaseHelper::FindTopStalledGroup(
765 std::string* group_name) { 786 Group** group,
787 std::string* group_name) const {
788 CHECK((group && group_name) || (!group && !group_name));
766 Group* top_group = NULL; 789 Group* top_group = NULL;
767 const std::string* top_group_name = NULL; 790 const std::string* top_group_name = NULL;
768 bool has_stalled_group = false; 791 bool has_stalled_group = false;
769 for (GroupMap::iterator i = group_map_.begin(); 792 for (GroupMap::const_iterator i = group_map_.begin();
770 i != group_map_.end(); ++i) { 793 i != group_map_.end(); ++i) {
771 Group* curr_group = i->second; 794 Group* curr_group = i->second;
772 const RequestQueue& queue = curr_group->pending_requests(); 795 const RequestQueue& queue = curr_group->pending_requests();
773 if (queue.empty()) 796 if (queue.empty())
774 continue; 797 continue;
775 if (curr_group->IsStalled(max_sockets_per_group_)) { 798 if (curr_group->IsStalled(max_sockets_per_group_)) {
799 if (!group)
800 return true;
776 has_stalled_group = true; 801 has_stalled_group = true;
777 bool has_higher_priority = !top_group || 802 bool has_higher_priority = !top_group ||
778 curr_group->TopPendingPriority() < top_group->TopPendingPriority(); 803 curr_group->TopPendingPriority() < top_group->TopPendingPriority();
779 if (has_higher_priority) { 804 if (has_higher_priority) {
780 top_group = curr_group; 805 top_group = curr_group;
781 top_group_name = &i->first; 806 top_group_name = &i->first;
782 } 807 }
783 } 808 }
784 } 809 }
785 810
786 if (top_group) { 811 if (top_group) {
812 CHECK(group);
787 *group = top_group; 813 *group = top_group;
788 *group_name = *top_group_name; 814 *group_name = *top_group_name;
815 } else {
816 CHECK(!has_stalled_group);
789 } 817 }
790 return has_stalled_group; 818 return has_stalled_group;
791 } 819 }
792 820
793 void ClientSocketPoolBaseHelper::OnConnectJobComplete( 821 void ClientSocketPoolBaseHelper::OnConnectJobComplete(
794 int result, ConnectJob* job) { 822 int result, ConnectJob* job) {
795 DCHECK_NE(ERR_IO_PENDING, result); 823 DCHECK_NE(ERR_IO_PENDING, result);
796 const std::string group_name = job->group_name(); 824 const std::string group_name = job->group_name();
797 GroupMap::iterator group_it = group_map_.find(group_name); 825 GroupMap::iterator group_it = group_map_.find(group_name);
798 CHECK(group_it != group_map_.end()); 826 CHECK(group_it != group_map_.end());
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
851 Flush(); 879 Flush();
852 } 880 }
853 881
854 void ClientSocketPoolBaseHelper::Flush() { 882 void ClientSocketPoolBaseHelper::Flush() {
855 pool_generation_number_++; 883 pool_generation_number_++;
856 CancelAllConnectJobs(); 884 CancelAllConnectJobs();
857 CloseIdleSockets(); 885 CloseIdleSockets();
858 AbortAllRequests(); 886 AbortAllRequests();
859 } 887 }
860 888
889 bool ClientSocketPoolBaseHelper::IsStalled() const {
890 CHECK_LE(handed_out_socket_count_ + connecting_socket_count_, max_sockets_);
mmenke 2011/10/27 18:52:37 Given that requests have an "ignore_limits" flag,
willchan no longer on Chromium 2011/11/08 22:26:13 Good point!
891 if ((handed_out_socket_count_ + connecting_socket_count_) != max_sockets_)
892 return false;
893 for (GroupMap::const_iterator it = group_map_.begin();
894 it != group_map_.end(); it++) {
895 if (it->second->IsStalled(max_sockets_per_group_))
896 return true;
897 }
898 return false;
899 }
900
861 void ClientSocketPoolBaseHelper::RemoveConnectJob(ConnectJob* job, 901 void ClientSocketPoolBaseHelper::RemoveConnectJob(ConnectJob* job,
862 Group* group) { 902 Group* group) {
863 CHECK_GT(connecting_socket_count_, 0); 903 CHECK_GT(connecting_socket_count_, 0);
864 connecting_socket_count_--; 904 connecting_socket_count_--;
865 905
866 DCHECK(group); 906 DCHECK(group);
867 DCHECK(ContainsKey(group->jobs(), job)); 907 DCHECK(ContainsKey(group->jobs(), job));
868 group->RemoveJob(job); 908 group->RemoveJob(job);
869 909
870 // If we've got no more jobs for this group, then we no longer need a 910 // If we've got no more jobs for this group, then we no longer need a
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after
988 // Each connecting socket will eventually connect and be handed out. 1028 // Each connecting socket will eventually connect and be handed out.
989 int total = handed_out_socket_count_ + connecting_socket_count_ + 1029 int total = handed_out_socket_count_ + connecting_socket_count_ +
990 idle_socket_count(); 1030 idle_socket_count();
991 // There can be more sockets than the limit since some requests can ignore 1031 // There can be more sockets than the limit since some requests can ignore
992 // the limit 1032 // the limit
993 if (total < max_sockets_) 1033 if (total < max_sockets_)
994 return false; 1034 return false;
995 return true; 1035 return true;
996 } 1036 }
997 1037
998 void ClientSocketPoolBaseHelper::CloseOneIdleSocket() { 1038 bool ClientSocketPoolBaseHelper::CloseOneIdleSocket() {
999 CloseOneIdleSocketExceptInGroup(NULL); 1039 if (idle_socket_count() == 0)
1040 return false;
1041 return CloseOneIdleSocketExceptInGroup(NULL);
1000 } 1042 }
1001 1043
1002 bool ClientSocketPoolBaseHelper::CloseOneIdleSocketExceptInGroup( 1044 bool ClientSocketPoolBaseHelper::CloseOneIdleSocketExceptInGroup(
1003 const Group* exception_group) { 1045 const Group* exception_group) {
1004 CHECK_GT(idle_socket_count(), 0); 1046 CHECK_GT(idle_socket_count(), 0);
1005 1047
1006 for (GroupMap::iterator i = group_map_.begin(); i != group_map_.end(); ++i) { 1048 for (GroupMap::iterator i = group_map_.begin(); i != group_map_.end(); ++i) {
1007 Group* group = i->second; 1049 Group* group = i->second;
1008 if (exception_group == group) 1050 if (exception_group == group)
1009 continue; 1051 continue;
1010 std::list<IdleSocket>* idle_sockets = group->mutable_idle_sockets(); 1052 std::list<IdleSocket>* idle_sockets = group->mutable_idle_sockets();
1011 1053
1012 if (!idle_sockets->empty()) { 1054 if (!idle_sockets->empty()) {
1013 delete idle_sockets->front().socket; 1055 delete idle_sockets->front().socket;
1014 idle_sockets->pop_front(); 1056 idle_sockets->pop_front();
1015 DecrementIdleCount(); 1057 DecrementIdleCount();
1016 if (group->IsEmpty()) 1058 if (group->IsEmpty())
1017 RemoveGroup(i); 1059 RemoveGroup(i);
1018 1060
1019 return true; 1061 return true;
1020 } 1062 }
1021 } 1063 }
1022 1064
1023 if (!exception_group)
1024 LOG(DFATAL) << "No idle socket found to close!.";
1025
1026 return false; 1065 return false;
1027 } 1066 }
1028 1067
1068 bool ClientSocketPoolBaseHelper::CloseOneIdleConnectionInLayeredPool() {
1069 // This pool doesn't have any idle sockets. It's possible that a pool at a
1070 // higher layer is holding one of this sockets active, but it's actually idle.
1071 // Query the higher layers.
1072 for (std::set<LayeredPool*>::const_iterator it =
1073 higher_layer_pools_.begin(); it != higher_layer_pools_.end(); ++it) {
mmenke 2011/10/27 18:52:37 nit: Looks to me like higher_layer_pools_.begin()
willchan no longer on Chromium 2011/11/08 22:26:13 Done.
1074 if ((*it)->CloseOneIdleConnection())
1075 return true;
1076 }
1077 return false;
1078 }
1079
1029 void ClientSocketPoolBaseHelper::InvokeUserCallbackLater( 1080 void ClientSocketPoolBaseHelper::InvokeUserCallbackLater(
1030 ClientSocketHandle* handle, OldCompletionCallback* callback, int rv) { 1081 ClientSocketHandle* handle, OldCompletionCallback* callback, int rv) {
1031 CHECK(!ContainsKey(pending_callback_map_, handle)); 1082 CHECK(!ContainsKey(pending_callback_map_, handle));
1032 pending_callback_map_[handle] = CallbackResultPair(callback, rv); 1083 pending_callback_map_[handle] = CallbackResultPair(callback, rv);
1033 MessageLoop::current()->PostTask( 1084 MessageLoop::current()->PostTask(
1034 FROM_HERE, 1085 FROM_HERE,
1035 method_factory_.NewRunnableMethod( 1086 method_factory_.NewRunnableMethod(
1036 &ClientSocketPoolBaseHelper::InvokeUserCallback, 1087 &ClientSocketPoolBaseHelper::InvokeUserCallback,
1037 handle)); 1088 handle));
1038 } 1089 }
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after
1123 // Delete active jobs. 1174 // Delete active jobs.
1124 STLDeleteElements(&jobs_); 1175 STLDeleteElements(&jobs_);
1125 1176
1126 // Cancel pending backup job. 1177 // Cancel pending backup job.
1127 method_factory_.RevokeAll(); 1178 method_factory_.RevokeAll();
1128 } 1179 }
1129 1180
1130 } // namespace internal 1181 } // namespace internal
1131 1182
1132 } // namespace net 1183 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698