| 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 // 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 170 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 181 base::TimeDelta used_idle_socket_timeout, | 181 base::TimeDelta used_idle_socket_timeout, |
| 182 ConnectJobFactory* connect_job_factory); | 182 ConnectJobFactory* connect_job_factory); |
| 183 | 183 |
| 184 // See ClientSocketPool::RequestSocket for documentation on this function. | 184 // See ClientSocketPool::RequestSocket for documentation on this function. |
| 185 // ClientSocketPoolBaseHelper takes ownership of |request|, which must be | 185 // ClientSocketPoolBaseHelper takes ownership of |request|, which must be |
| 186 // heap allocated. | 186 // heap allocated. |
| 187 int RequestSocket(const std::string& group_name, const Request* request); | 187 int RequestSocket(const std::string& group_name, const Request* request); |
| 188 | 188 |
| 189 // See ClientSocketPool::CancelRequest for documentation on this function. | 189 // See ClientSocketPool::CancelRequest for documentation on this function. |
| 190 void CancelRequest(const std::string& group_name, | 190 void CancelRequest(const std::string& group_name, |
| 191 const ClientSocketHandle* handle); | 191 ClientSocketHandle* handle); |
| 192 | 192 |
| 193 // See ClientSocketPool::ReleaseSocket for documentation on this function. | 193 // See ClientSocketPool::ReleaseSocket for documentation on this function. |
| 194 void ReleaseSocket(const std::string& group_name, | 194 void ReleaseSocket(const std::string& group_name, |
| 195 ClientSocket* socket, | 195 ClientSocket* socket, |
| 196 int id); | 196 int id); |
| 197 | 197 |
| 198 // See ClientSocketPool::Flush for documentation on this function. | 198 // See ClientSocketPool::Flush for documentation on this function. |
| 199 void Flush(); | 199 void Flush(); |
| 200 | 200 |
| 201 // See ClientSocketPool::CloseIdleSockets for documentation on this function. | 201 // See ClientSocketPool::CloseIdleSockets for documentation on this function. |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 236 | 236 |
| 237 base::TimeDelta ConnectionTimeout() const { | 237 base::TimeDelta ConnectionTimeout() const { |
| 238 return connect_job_factory_->ConnectionTimeout(); | 238 return connect_job_factory_->ConnectionTimeout(); |
| 239 } | 239 } |
| 240 | 240 |
| 241 void EnableBackupJobs() { backup_jobs_enabled_ = true; } | 241 void EnableBackupJobs() { backup_jobs_enabled_ = true; } |
| 242 | 242 |
| 243 private: | 243 private: |
| 244 friend class base::RefCounted<ClientSocketPoolBaseHelper>; | 244 friend class base::RefCounted<ClientSocketPoolBaseHelper>; |
| 245 | 245 |
| 246 ~ClientSocketPoolBaseHelper(); | |
| 247 | |
| 248 // Entry for a persistent socket which became idle at time |start_time|. | 246 // Entry for a persistent socket which became idle at time |start_time|. |
| 249 struct IdleSocket { | 247 struct IdleSocket { |
| 250 IdleSocket() : socket(NULL), used(false) {} | 248 IdleSocket() : socket(NULL), used(false) {} |
| 251 ClientSocket* socket; | 249 ClientSocket* socket; |
| 252 base::TimeTicks start_time; | 250 base::TimeTicks start_time; |
| 253 bool used; // Indicates whether or not the socket has been used yet. | 251 bool used; // Indicates whether or not the socket has been used yet. |
| 254 | 252 |
| 255 // An idle socket should be removed if it can't be reused, or has been idle | 253 // An idle socket should be removed if it can't be reused, or has been idle |
| 256 // for too long. |now| is the current time value (TimeTicks::Now()). | 254 // for too long. |now| is the current time value (TimeTicks::Now()). |
| 257 // |timeout| is the length of time to wait before timing out an idle socket. | 255 // |timeout| is the length of time to wait before timing out an idle socket. |
| (...skipping 25 matching lines...) Expand all Loading... |
| 283 bool IsEmpty() const { | 281 bool IsEmpty() const { |
| 284 return active_socket_count == 0 && idle_sockets.empty() && jobs.empty() && | 282 return active_socket_count == 0 && idle_sockets.empty() && jobs.empty() && |
| 285 pending_requests.empty(); | 283 pending_requests.empty(); |
| 286 } | 284 } |
| 287 | 285 |
| 288 bool HasAvailableSocketSlot(int max_sockets_per_group) const { | 286 bool HasAvailableSocketSlot(int max_sockets_per_group) const { |
| 289 return active_socket_count + static_cast<int>(jobs.size()) < | 287 return active_socket_count + static_cast<int>(jobs.size()) < |
| 290 max_sockets_per_group; | 288 max_sockets_per_group; |
| 291 } | 289 } |
| 292 | 290 |
| 291 bool IsStalled(int max_sockets_per_group) const { |
| 292 return HasAvailableSocketSlot(max_sockets_per_group) && |
| 293 pending_requests.size() > jobs.size(); |
| 294 } |
| 295 |
| 293 RequestPriority TopPendingPriority() const { | 296 RequestPriority TopPendingPriority() const { |
| 294 return pending_requests.front()->priority(); | 297 return pending_requests.front()->priority(); |
| 295 } | 298 } |
| 296 | 299 |
| 297 void CleanupBackupJob() { | 300 void CleanupBackupJob() { |
| 298 if (backup_job) { | 301 if (backup_job) { |
| 299 delete backup_job; | 302 delete backup_job; |
| 300 backup_job = NULL; | 303 backup_job = NULL; |
| 301 } | 304 } |
| 302 if (backup_task) { | 305 if (backup_task) { |
| 303 backup_task->Cancel(); | 306 backup_task->Cancel(); |
| 304 backup_task = NULL; | 307 backup_task = NULL; |
| 305 } | 308 } |
| 306 } | 309 } |
| 307 | 310 |
| 308 std::deque<IdleSocket> idle_sockets; | 311 std::deque<IdleSocket> idle_sockets; |
| 309 std::set<const ConnectJob*> jobs; | 312 std::set<const ConnectJob*> jobs; |
| 310 RequestQueue pending_requests; | 313 RequestQueue pending_requests; |
| 311 int active_socket_count; // number of active sockets used by clients | 314 int active_socket_count; // number of active sockets used by clients |
| 312 // A backup job in case the connect for this group takes too long. | 315 // A backup job in case the connect for this group takes too long. |
| 313 ConnectJob* backup_job; | 316 ConnectJob* backup_job; |
| 314 CancelableTask* backup_task; | 317 CancelableTask* backup_task; |
| 315 }; | 318 }; |
| 316 | 319 |
| 317 typedef std::map<std::string, Group> GroupMap; | 320 typedef std::map<std::string, Group> GroupMap; |
| 318 | 321 |
| 319 typedef std::set<const ConnectJob*> ConnectJobSet; | 322 typedef std::set<const ConnectJob*> ConnectJobSet; |
| 320 | 323 |
| 324 struct CallbackResultPair { |
| 325 CallbackResultPair() : callback(NULL), result(OK) {} |
| 326 CallbackResultPair(CompletionCallback* callback_in, int result_in) |
| 327 : callback(callback_in), result(result_in) {} |
| 328 |
| 329 CompletionCallback* callback; |
| 330 int result; |
| 331 }; |
| 332 |
| 333 typedef std::map<const ClientSocketHandle*, CallbackResultPair> |
| 334 PendingCallbackMap; |
| 335 |
| 336 ~ClientSocketPoolBaseHelper(); |
| 337 |
| 321 static void InsertRequestIntoQueue(const Request* r, | 338 static void InsertRequestIntoQueue(const Request* r, |
| 322 RequestQueue* pending_requests); | 339 RequestQueue* pending_requests); |
| 323 static const Request* RemoveRequestFromQueue(RequestQueue::iterator it, | 340 static const Request* RemoveRequestFromQueue(RequestQueue::iterator it, |
| 324 RequestQueue* pending_requests); | 341 RequestQueue* pending_requests); |
| 325 | 342 |
| 326 // Called when the number of idle sockets changes. | 343 // Called when the number of idle sockets changes. |
| 327 void IncrementIdleCount(); | 344 void IncrementIdleCount(); |
| 328 void DecrementIdleCount(); | 345 void DecrementIdleCount(); |
| 329 | 346 |
| 330 // Scans the group map for groups which have an available socket slot and | 347 // Scans the group map for groups which have an available socket slot and |
| 331 // at least one pending request. Returns number of groups found, and if found | 348 // at least one pending request. Returns true if any groups are stalled, and |
| 332 // at least one, fills |group| and |group_name| with data of the stalled group | 349 // if so, fills |group| and |group_name| with data of the stalled group |
| 333 // having highest priority. | 350 // having highest priority. |
| 334 int FindTopStalledGroup(Group** group, std::string* group_name); | 351 bool FindTopStalledGroup(Group** group, std::string* group_name); |
| 335 | 352 |
| 336 // Called when timer_ fires. This method scans the idle sockets removing | 353 // Called when timer_ fires. This method scans the idle sockets removing |
| 337 // sockets that timed out or can't be reused. | 354 // sockets that timed out or can't be reused. |
| 338 void OnCleanupTimerFired() { | 355 void OnCleanupTimerFired() { |
| 339 CleanupIdleSockets(false); | 356 CleanupIdleSockets(false); |
| 340 } | 357 } |
| 341 | 358 |
| 342 // Removes |job| from |connect_job_set_|. Also updates |group| if non-NULL. | 359 // Removes |job| from |connect_job_set_|. Also updates |group| if non-NULL. |
| 343 void RemoveConnectJob(const ConnectJob* job, Group* group); | 360 void RemoveConnectJob(const ConnectJob* job, Group* group); |
| 344 | 361 |
| 345 // Might delete the Group from |group_map_|. | 362 // Tries to see if we can handle any more requests for |group|. |
| 346 // If |was_at_socket_limit|, will also check for idle sockets to assign | 363 void OnAvailableSocketSlot(const std::string& group_name, Group* group); |
| 347 // to any stalled groups. | |
| 348 void OnAvailableSocketSlot(const std::string& group_name, | |
| 349 bool was_at_socket_limit); | |
| 350 | 364 |
| 351 // Process a pending socket request for a group. | 365 // Process a pending socket request for a group. |
| 352 // If |was_at_socket_limit|, will also check for idle sockets to assign | 366 void ProcessPendingRequest(const std::string& group_name, Group* group); |
| 353 // to any stalled groups. | |
| 354 void ProcessPendingRequest(const std::string& group_name, | |
| 355 bool was_at_socket_limit); | |
| 356 | 367 |
| 357 // Assigns |socket| to |handle| and updates |group|'s counters appropriately. | 368 // Assigns |socket| to |handle| and updates |group|'s counters appropriately. |
| 358 void HandOutSocket(ClientSocket* socket, | 369 void HandOutSocket(ClientSocket* socket, |
| 359 bool reused, | 370 bool reused, |
| 360 ClientSocketHandle* handle, | 371 ClientSocketHandle* handle, |
| 361 base::TimeDelta time_idle, | 372 base::TimeDelta time_idle, |
| 362 Group* group, | 373 Group* group, |
| 363 const BoundNetLog& net_log); | 374 const BoundNetLog& net_log); |
| 364 | 375 |
| 365 // Adds |socket| to the list of idle sockets for |group|. |used| indicates | 376 // Adds |socket| to the list of idle sockets for |group|. |used| indicates |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 397 // TODO(willchan): Consider a better algorithm for doing this. Perhaps we | 408 // TODO(willchan): Consider a better algorithm for doing this. Perhaps we |
| 398 // should keep an ordered list of idle sockets, and close them in order. | 409 // should keep an ordered list of idle sockets, and close them in order. |
| 399 // Requires maintaining more state. It's not clear if it's worth it since | 410 // Requires maintaining more state. It's not clear if it's worth it since |
| 400 // I'm not sure if we hit this situation often. | 411 // I'm not sure if we hit this situation often. |
| 401 void CloseOneIdleSocket(); | 412 void CloseOneIdleSocket(); |
| 402 | 413 |
| 403 // Checks if there are stalled socket groups that should be notified | 414 // Checks if there are stalled socket groups that should be notified |
| 404 // for possible wakeup. | 415 // for possible wakeup. |
| 405 void CheckForStalledSocketGroups(); | 416 void CheckForStalledSocketGroups(); |
| 406 | 417 |
| 407 // Returns true if we might have a stalled group. | 418 // Posts a task to call InvokeUserCallback() on the next iteration through the |
| 408 bool MayHaveStalledGroups(); | 419 // current message loop. Inserts |callback| into |pending_callback_map_|, |
| 420 // keyed by |handle|. |
| 421 void InvokeUserCallbackLater( |
| 422 ClientSocketHandle* handle, CompletionCallback* callback, int rv); |
| 423 |
| 424 // Invokes the user callback for |handle|. By the time this task has run, |
| 425 // it's possible that the request has been cancelled, so |handle| may not |
| 426 // exist in |pending_callback_map_|. We look up the callback and result code |
| 427 // in |pending_callback_map_|. |
| 428 void InvokeUserCallback(ClientSocketHandle* handle); |
| 409 | 429 |
| 410 GroupMap group_map_; | 430 GroupMap group_map_; |
| 411 | 431 |
| 432 // Map of the ClientSocketHandles for which we have a pending Task to invoke a |
| 433 // callback. This is necessary since, before we invoke said callback, it's |
| 434 // possible that the request is cancelled. |
| 435 PendingCallbackMap pending_callback_map_; |
| 436 |
| 412 // Timer used to periodically prune idle sockets that timed out or can't be | 437 // Timer used to periodically prune idle sockets that timed out or can't be |
| 413 // reused. | 438 // reused. |
| 414 base::RepeatingTimer<ClientSocketPoolBaseHelper> timer_; | 439 base::RepeatingTimer<ClientSocketPoolBaseHelper> timer_; |
| 415 | 440 |
| 416 // The total number of idle sockets in the system. | 441 // The total number of idle sockets in the system. |
| 417 int idle_socket_count_; | 442 int idle_socket_count_; |
| 418 | 443 |
| 419 // Number of connecting sockets across all groups. | 444 // Number of connecting sockets across all groups. |
| 420 int connecting_socket_count_; | 445 int connecting_socket_count_; |
| 421 | 446 |
| (...skipping 15 matching lines...) Expand all Loading... |
| 437 // TODO(vandebo) Remove when backup jobs move to TCPClientSocketPool | 462 // TODO(vandebo) Remove when backup jobs move to TCPClientSocketPool |
| 438 bool backup_jobs_enabled_; | 463 bool backup_jobs_enabled_; |
| 439 | 464 |
| 440 // A factory to pin the backup_job tasks. | 465 // A factory to pin the backup_job tasks. |
| 441 ScopedRunnableMethodFactory<ClientSocketPoolBaseHelper> method_factory_; | 466 ScopedRunnableMethodFactory<ClientSocketPoolBaseHelper> method_factory_; |
| 442 | 467 |
| 443 // A unique id for the pool. It gets incremented every time we Flush() the | 468 // A unique id for the pool. It gets incremented every time we Flush() the |
| 444 // pool. This is so that when sockets get released back to the pool, we can | 469 // pool. This is so that when sockets get released back to the pool, we can |
| 445 // make sure that they are discarded rather than reused. | 470 // make sure that they are discarded rather than reused. |
| 446 int pool_generation_number_; | 471 int pool_generation_number_; |
| 447 | |
| 448 // The count of stalled groups the last time we checked. | |
| 449 int last_stalled_group_count_; | |
| 450 }; | 472 }; |
| 451 | 473 |
| 452 } // namespace internal | 474 } // namespace internal |
| 453 | 475 |
| 454 // The maximum duration, in seconds, to keep used idle persistent sockets alive. | 476 // The maximum duration, in seconds, to keep used idle persistent sockets alive. |
| 455 static const int kUsedIdleSocketTimeout = 300; // 5 minutes | 477 static const int kUsedIdleSocketTimeout = 300; // 5 minutes |
| 456 | 478 |
| 457 template <typename SocketParams> | 479 template <typename SocketParams> |
| 458 class ClientSocketPoolBase { | 480 class ClientSocketPoolBase { |
| 459 public: | 481 public: |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 520 const scoped_refptr<SocketParams>& params, | 542 const scoped_refptr<SocketParams>& params, |
| 521 RequestPriority priority, | 543 RequestPriority priority, |
| 522 ClientSocketHandle* handle, | 544 ClientSocketHandle* handle, |
| 523 CompletionCallback* callback, | 545 CompletionCallback* callback, |
| 524 const BoundNetLog& net_log) { | 546 const BoundNetLog& net_log) { |
| 525 Request* request = new Request(handle, callback, priority, params, net_log); | 547 Request* request = new Request(handle, callback, priority, params, net_log); |
| 526 return helper_->RequestSocket(group_name, request); | 548 return helper_->RequestSocket(group_name, request); |
| 527 } | 549 } |
| 528 | 550 |
| 529 void CancelRequest(const std::string& group_name, | 551 void CancelRequest(const std::string& group_name, |
| 530 const ClientSocketHandle* handle) { | 552 ClientSocketHandle* handle) { |
| 531 return helper_->CancelRequest(group_name, handle); | 553 return helper_->CancelRequest(group_name, handle); |
| 532 } | 554 } |
| 533 | 555 |
| 534 void ReleaseSocket(const std::string& group_name, ClientSocket* socket, | 556 void ReleaseSocket(const std::string& group_name, ClientSocket* socket, |
| 535 int id) { | 557 int id) { |
| 536 return helper_->ReleaseSocket(group_name, socket, id); | 558 return helper_->ReleaseSocket(group_name, socket, id); |
| 537 } | 559 } |
| 538 | 560 |
| 539 void CloseIdleSockets() { return helper_->CloseIdleSockets(); } | 561 void CloseIdleSockets() { return helper_->CloseIdleSockets(); } |
| 540 | 562 |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 614 // ClientSocketPoolBase<T> reference to drop to zero. While we're deep | 636 // ClientSocketPoolBase<T> reference to drop to zero. While we're deep |
| 615 // in cleanup code, we'll often hold a reference to |self|. | 637 // in cleanup code, we'll often hold a reference to |self|. |
| 616 scoped_refptr<internal::ClientSocketPoolBaseHelper> helper_; | 638 scoped_refptr<internal::ClientSocketPoolBaseHelper> helper_; |
| 617 | 639 |
| 618 DISALLOW_COPY_AND_ASSIGN(ClientSocketPoolBase); | 640 DISALLOW_COPY_AND_ASSIGN(ClientSocketPoolBase); |
| 619 }; | 641 }; |
| 620 | 642 |
| 621 } // namespace net | 643 } // namespace net |
| 622 | 644 |
| 623 #endif // NET_SOCKET_CLIENT_SOCKET_POOL_BASE_H_ | 645 #endif // NET_SOCKET_CLIENT_SOCKET_POOL_BASE_H_ |
| OLD | NEW |