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

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

Issue 176021: Control the amount of time to leave an unused socket idle before closing it. (Closed)
Patch Set: Address wtc's comments. Created 11 years, 3 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 | « no previous file | net/socket/client_socket_pool_base.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 // A ClientSocketPoolBase is used to restrict the number of sockets open at 5 // A ClientSocketPoolBase is used to restrict the number of sockets open at
6 // a time. It also maintains a list of idle persistent sockets for reuse. 6 // a time. It also maintains a list of idle persistent sockets for reuse.
7 // Subclasses of ClientSocketPool should compose ClientSocketPoolBase to handle 7 // Subclasses of ClientSocketPool should compose ClientSocketPoolBase to handle
8 // the core logic of (1) restricting the number of active (connected or 8 // the core logic of (1) restricting the number of active (connected or
9 // connecting) sockets per "group" (generally speaking, the hostname), (2) 9 // connecting) sockets per "group" (generally speaking, the hostname), (2)
10 // maintaining a per-group list of idle, persistent sockets for reuse, and (3) 10 // maintaining a per-group list of idle, persistent sockets for reuse, and (3)
(...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after
159 const Request& request, 159 const Request& request,
160 ConnectJob::Delegate* delegate, 160 ConnectJob::Delegate* delegate,
161 LoadLog* load_log) const = 0; 161 LoadLog* load_log) const = 0;
162 162
163 private: 163 private:
164 DISALLOW_COPY_AND_ASSIGN(ConnectJobFactory); 164 DISALLOW_COPY_AND_ASSIGN(ConnectJobFactory);
165 }; 165 };
166 166
167 ClientSocketPoolBaseHelper(int max_sockets, 167 ClientSocketPoolBaseHelper(int max_sockets,
168 int max_sockets_per_group, 168 int max_sockets_per_group,
169 base::TimeDelta unused_idle_socket_timeout,
170 base::TimeDelta used_idle_socket_timeout,
169 ConnectJobFactory* connect_job_factory); 171 ConnectJobFactory* connect_job_factory);
170 172
171 ~ClientSocketPoolBaseHelper(); 173 ~ClientSocketPoolBaseHelper();
172 174
173 // See ClientSocketPool::RequestSocket for documentation on this function. 175 // See ClientSocketPool::RequestSocket for documentation on this function.
174 // Note that |request| must be heap allocated. If ERR_IO_PENDING is returned, 176 // Note that |request| must be heap allocated. If ERR_IO_PENDING is returned,
175 // then ClientSocketPoolBaseHelper takes ownership of |request|. 177 // then ClientSocketPoolBaseHelper takes ownership of |request|.
176 int RequestSocket(const std::string& group_name, const Request* request); 178 int RequestSocket(const std::string& group_name, const Request* request);
177 179
178 // See ClientSocketPool::CancelRequest for documentation on this function. 180 // See ClientSocketPool::CancelRequest for documentation on this function.
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
210 // afterward and receive the socket from the job). 212 // afterward and receive the socket from the job).
211 static void EnableLateBindingOfSockets(bool enabled); 213 static void EnableLateBindingOfSockets(bool enabled);
212 214
213 // For testing. 215 // For testing.
214 bool may_have_stalled_group() const { return may_have_stalled_group_; } 216 bool may_have_stalled_group() const { return may_have_stalled_group_; }
215 217
216 int NumConnectJobsInGroup(const std::string& group_name) const { 218 int NumConnectJobsInGroup(const std::string& group_name) const {
217 return group_map_.find(group_name)->second.jobs.size(); 219 return group_map_.find(group_name)->second.jobs.size();
218 } 220 }
219 221
222 // Closes all idle sockets if |force| is true. Else, only closes idle
223 // sockets that timed out or can't be reused. Made public for testing.
224 void CleanupIdleSockets(bool force);
225
220 private: 226 private:
221 // Entry for a persistent socket which became idle at time |start_time|. 227 // Entry for a persistent socket which became idle at time |start_time|.
222 struct IdleSocket { 228 struct IdleSocket {
223 IdleSocket() : socket(NULL), used(false) {} 229 IdleSocket() : socket(NULL), used(false) {}
224 ClientSocket* socket; 230 ClientSocket* socket;
225 base::TimeTicks start_time; 231 base::TimeTicks start_time;
226 bool used; // Indicates whether or not the socket has been used yet. 232 bool used; // Indicates whether or not the socket has been used yet.
227 233
228 // An idle socket should be removed if it can't be reused, or has been idle 234 // An idle socket should be removed if it can't be reused, or has been idle
229 // for too long. |now| is the current time value (TimeTicks::Now()). 235 // for too long. |now| is the current time value (TimeTicks::Now()).
236 // |timeout| is the length of time to wait before timing out an idle socket.
230 // 237 //
231 // An idle socket can't be reused if it is disconnected or has received 238 // An idle socket can't be reused if it is disconnected or has received
232 // data unexpectedly (hence no longer idle). The unread data would be 239 // data unexpectedly (hence no longer idle). The unread data would be
233 // mistaken for the beginning of the next response if we were to reuse the 240 // mistaken for the beginning of the next response if we were to reuse the
234 // socket for a new request. 241 // socket for a new request.
235 bool ShouldCleanup(base::TimeTicks now) const; 242 bool ShouldCleanup(base::TimeTicks now, base::TimeDelta timeout) const;
236 }; 243 };
237 244
238 typedef std::deque<const Request*> RequestQueue; 245 typedef std::deque<const Request*> RequestQueue;
239 typedef std::map<const ClientSocketHandle*, const Request*> RequestMap; 246 typedef std::map<const ClientSocketHandle*, const Request*> RequestMap;
240 247
241 // A Group is allocated per group_name when there are idle sockets or pending 248 // A Group is allocated per group_name when there are idle sockets or pending
242 // requests. Otherwise, the Group object is removed from the map. 249 // requests. Otherwise, the Group object is removed from the map.
243 struct Group { 250 struct Group {
244 Group() : active_socket_count(0) {} 251 Group() : active_socket_count(0) {}
245 252
(...skipping 21 matching lines...) Expand all
267 typedef std::map<std::string, Group> GroupMap; 274 typedef std::map<std::string, Group> GroupMap;
268 275
269 typedef std::map<const ClientSocketHandle*, ConnectJob*> ConnectJobMap; 276 typedef std::map<const ClientSocketHandle*, ConnectJob*> ConnectJobMap;
270 typedef std::set<const ConnectJob*> ConnectJobSet; 277 typedef std::set<const ConnectJob*> ConnectJobSet;
271 278
272 static void InsertRequestIntoQueue(const Request* r, 279 static void InsertRequestIntoQueue(const Request* r,
273 RequestQueue* pending_requests); 280 RequestQueue* pending_requests);
274 static const Request* RemoveRequestFromQueue(RequestQueue::iterator it, 281 static const Request* RemoveRequestFromQueue(RequestQueue::iterator it,
275 RequestQueue* pending_requests); 282 RequestQueue* pending_requests);
276 283
277 // Closes all idle sockets if |force| is true. Else, only closes idle
278 // sockets that timed out or can't be reused.
279 void CleanupIdleSockets(bool force);
280
281 // Called when the number of idle sockets changes. 284 // Called when the number of idle sockets changes.
282 void IncrementIdleCount(); 285 void IncrementIdleCount();
283 void DecrementIdleCount(); 286 void DecrementIdleCount();
284 287
285 // Called via PostTask by ReleaseSocket. 288 // Called via PostTask by ReleaseSocket.
286 void DoReleaseSocket(const std::string& group_name, ClientSocket* socket); 289 void DoReleaseSocket(const std::string& group_name, ClientSocket* socket);
287 290
288 // Scans the group map for groups which have an available socket slot and 291 // Scans the group map for groups which have an available socket slot and
289 // at least one pending request. Returns number of groups found, and if found 292 // at least one pending request. Returns number of groups found, and if found
290 // at least one, fills |group| and |group_name| with data of the stalled group 293 // at least one, fills |group| and |group_name| with data of the stalled group
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
352 355
353 // Number of connected sockets we handed out across all groups. 356 // Number of connected sockets we handed out across all groups.
354 int handed_out_socket_count_; 357 int handed_out_socket_count_;
355 358
356 // The maximum total number of sockets. See ReachedMaxSocketsLimit. 359 // The maximum total number of sockets. See ReachedMaxSocketsLimit.
357 const int max_sockets_; 360 const int max_sockets_;
358 361
359 // The maximum number of sockets kept per group. 362 // The maximum number of sockets kept per group.
360 const int max_sockets_per_group_; 363 const int max_sockets_per_group_;
361 364
365 // The time to wait until closing idle sockets.
366 const base::TimeDelta unused_idle_socket_timeout_;
367 const base::TimeDelta used_idle_socket_timeout_;
368
362 // Until the maximum number of sockets limit is reached, a group can only 369 // Until the maximum number of sockets limit is reached, a group can only
363 // have pending requests if it exceeds the "max sockets per group" limit. 370 // have pending requests if it exceeds the "max sockets per group" limit.
364 // 371 //
365 // This means when a socket is released, the only pending requests that can 372 // This means when a socket is released, the only pending requests that can
366 // be started next belong to the same group. 373 // be started next belong to the same group.
367 // 374 //
368 // However once the |max_sockets_| limit is reached, this stops being true: 375 // However once the |max_sockets_| limit is reached, this stops being true:
369 // groups can now have pending requests without having first reached the 376 // groups can now have pending requests without having first reached the
370 // |max_sockets_per_group_| limit. So choosing the next request involves 377 // |max_sockets_per_group_| limit. So choosing the next request involves
371 // selecting the highest priority request across *all* groups. 378 // selecting the highest priority request across *all* groups.
372 // 379 //
373 // Since reaching the maximum number of sockets is an edge case, we make note 380 // Since reaching the maximum number of sockets is an edge case, we make note
374 // of when it happens, and thus avoid doing the slower "scan all groups" 381 // of when it happens, and thus avoid doing the slower "scan all groups"
375 // in the common case. 382 // in the common case.
376 bool may_have_stalled_group_; 383 bool may_have_stalled_group_;
377 384
378 const scoped_ptr<ConnectJobFactory> connect_job_factory_; 385 const scoped_ptr<ConnectJobFactory> connect_job_factory_;
379 386
380 // Controls whether or not we use late binding of sockets. 387 // Controls whether or not we use late binding of sockets.
381 static bool g_late_binding; 388 static bool g_late_binding;
382 389
383 }; 390 };
384 391
385 } // namespace internal 392 } // namespace internal
386 393
394 // The maximum duration, in seconds, to keep unused idle persistent sockets
395 // alive.
396 // TODO(willchan): Change this timeout after getting histogram data on how
397 // long it should be.
398 static const int kUnusedIdleSocketTimeout = 10;
399 // The maximum duration, in seconds, to keep used idle persistent sockets alive.
400 static const int kUsedIdleSocketTimeout = 300; // 5 minutes
401
387 template <typename SocketParams> 402 template <typename SocketParams>
388 class ClientSocketPoolBase { 403 class ClientSocketPoolBase {
389 public: 404 public:
390 class Request : public internal::ClientSocketPoolBaseHelper::Request { 405 class Request : public internal::ClientSocketPoolBaseHelper::Request {
391 public: 406 public:
392 Request(ClientSocketHandle* handle, 407 Request(ClientSocketHandle* handle,
393 CompletionCallback* callback, 408 CompletionCallback* callback,
394 int priority, 409 int priority,
395 const SocketParams& params, 410 const SocketParams& params,
396 LoadLog* load_log) 411 LoadLog* load_log)
(...skipping 15 matching lines...) Expand all
412 virtual ConnectJob* NewConnectJob( 427 virtual ConnectJob* NewConnectJob(
413 const std::string& group_name, 428 const std::string& group_name,
414 const Request& request, 429 const Request& request,
415 ConnectJob::Delegate* delegate, 430 ConnectJob::Delegate* delegate,
416 LoadLog* load_log) const = 0; 431 LoadLog* load_log) const = 0;
417 432
418 private: 433 private:
419 DISALLOW_COPY_AND_ASSIGN(ConnectJobFactory); 434 DISALLOW_COPY_AND_ASSIGN(ConnectJobFactory);
420 }; 435 };
421 436
437 // |max_sockets| is the maximum number of sockets to be maintained by this
438 // ClientSocketPool. |max_sockets_per_group| specifies the maximum number of
439 // sockets a "group" can have. |unused_idle_socket_timeout| specifies how
440 // long to leave an unused idle socket open before closing it.
441 // |used_idle_socket_timeout| specifies how long to leave a previously used
442 // idle socket open before closing it.
422 ClientSocketPoolBase(int max_sockets, 443 ClientSocketPoolBase(int max_sockets,
423 int max_sockets_per_group, 444 int max_sockets_per_group,
445 base::TimeDelta unused_idle_socket_timeout,
446 base::TimeDelta used_idle_socket_timeout,
424 ConnectJobFactory* connect_job_factory) 447 ConnectJobFactory* connect_job_factory)
425 : helper_(new internal::ClientSocketPoolBaseHelper( 448 : helper_(new internal::ClientSocketPoolBaseHelper(
426 max_sockets, max_sockets_per_group, 449 max_sockets, max_sockets_per_group,
450 unused_idle_socket_timeout, used_idle_socket_timeout,
427 new ConnectJobFactoryAdaptor(connect_job_factory))) {} 451 new ConnectJobFactoryAdaptor(connect_job_factory))) {}
428 452
429 ~ClientSocketPoolBase() {} 453 ~ClientSocketPoolBase() {}
430 454
431 // These member functions simply forward to ClientSocketPoolBaseHelper. 455 // These member functions simply forward to ClientSocketPoolBaseHelper.
432 456
433 // RequestSocket bundles up the parameters into a Request and then forwards to 457 // RequestSocket bundles up the parameters into a Request and then forwards to
434 // ClientSocketPoolBaseHelper::RequestSocket(). Note that the memory 458 // ClientSocketPoolBaseHelper::RequestSocket(). Note that the memory
435 // ownership is transferred in the asynchronous (ERR_IO_PENDING) case. 459 // ownership is transferred in the asynchronous (ERR_IO_PENDING) case.
436 int RequestSocket(const std::string& group_name, 460 int RequestSocket(const std::string& group_name,
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
478 502
479 // For testing. 503 // For testing.
480 bool may_have_stalled_group() const { 504 bool may_have_stalled_group() const {
481 return helper_->may_have_stalled_group(); 505 return helper_->may_have_stalled_group();
482 } 506 }
483 507
484 int NumConnectJobsInGroup(const std::string& group_name) const { 508 int NumConnectJobsInGroup(const std::string& group_name) const {
485 return helper_->NumConnectJobsInGroup(group_name); 509 return helper_->NumConnectJobsInGroup(group_name);
486 } 510 }
487 511
512 void CleanupIdleSockets(bool force) {
513 return helper_->CleanupIdleSockets(force);
514 }
515
488 private: 516 private:
489 // This adaptor class exists to bridge the 517 // This adaptor class exists to bridge the
490 // internal::ClientSocketPoolBaseHelper::ConnectJobFactory and 518 // internal::ClientSocketPoolBaseHelper::ConnectJobFactory and
491 // ClientSocketPoolBase::ConnectJobFactory types, allowing clients to use the 519 // ClientSocketPoolBase::ConnectJobFactory types, allowing clients to use the
492 // typesafe ClientSocketPoolBase::ConnectJobFactory, rather than having to 520 // typesafe ClientSocketPoolBase::ConnectJobFactory, rather than having to
493 // static_cast themselves. 521 // static_cast themselves.
494 class ConnectJobFactoryAdaptor 522 class ConnectJobFactoryAdaptor
495 : public internal::ClientSocketPoolBaseHelper::ConnectJobFactory { 523 : public internal::ClientSocketPoolBaseHelper::ConnectJobFactory {
496 public: 524 public:
497 typedef typename ClientSocketPoolBase<SocketParams>::ConnectJobFactory 525 typedef typename ClientSocketPoolBase<SocketParams>::ConnectJobFactory
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
529 // decoupled from socket connection jobs. A socket request may initiate a 557 // decoupled from socket connection jobs. A socket request may initiate a
530 // socket connection job, but there is no guarantee that that socket 558 // socket connection job, but there is no guarantee that that socket
531 // connection will service the request (for example, a released socket may 559 // connection will service the request (for example, a released socket may
532 // service the request sooner, or a higher priority request may come in 560 // service the request sooner, or a higher priority request may come in
533 // afterward and receive the socket from the job). 561 // afterward and receive the socket from the job).
534 void EnableLateBindingOfSockets(bool enabled); 562 void EnableLateBindingOfSockets(bool enabled);
535 563
536 } // namespace net 564 } // namespace net
537 565
538 #endif // NET_SOCKET_CLIENT_SOCKET_POOL_BASE_H_ 566 #endif // NET_SOCKET_CLIENT_SOCKET_POOL_BASE_H_
OLDNEW
« no previous file with comments | « no previous file | net/socket/client_socket_pool_base.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698