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 210 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
221 return ClientSocketPool::kMaxConnectRetryIntervalMs; | 221 return ClientSocketPool::kMaxConnectRetryIntervalMs; |
222 } | 222 } |
223 | 223 |
224 // ConnectJob::Delegate methods: | 224 // ConnectJob::Delegate methods: |
225 virtual void OnConnectJobComplete(int result, ConnectJob* job); | 225 virtual void OnConnectJobComplete(int result, ConnectJob* job); |
226 | 226 |
227 // NetworkChangeNotifier::Observer methods: | 227 // NetworkChangeNotifier::Observer methods: |
228 virtual void OnIPAddressChanged(); | 228 virtual void OnIPAddressChanged(); |
229 | 229 |
230 int NumConnectJobsInGroup(const std::string& group_name) const { | 230 int NumConnectJobsInGroup(const std::string& group_name) const { |
231 return group_map_.find(group_name)->second->jobs().size(); | 231 return group_map_.find(group_name)->second.jobs.size(); |
232 } | 232 } |
233 | 233 |
234 // Closes all idle sockets if |force| is true. Else, only closes idle | 234 // Closes all idle sockets if |force| is true. Else, only closes idle |
235 // sockets that timed out or can't be reused. Made public for testing. | 235 // sockets that timed out or can't be reused. Made public for testing. |
236 void CleanupIdleSockets(bool force); | 236 void CleanupIdleSockets(bool force); |
237 | 237 |
238 base::TimeDelta ConnectionTimeout() const { | 238 base::TimeDelta ConnectionTimeout() const { |
239 return connect_job_factory_->ConnectionTimeout(); | 239 return connect_job_factory_->ConnectionTimeout(); |
240 } | 240 } |
241 | 241 |
(...skipping 19 matching lines...) Expand all Loading... |
261 // socket for a new request. | 261 // socket for a new request. |
262 bool ShouldCleanup(base::TimeTicks now, base::TimeDelta timeout) const; | 262 bool ShouldCleanup(base::TimeTicks now, base::TimeDelta timeout) const; |
263 }; | 263 }; |
264 | 264 |
265 typedef std::deque<const Request*> RequestQueue; | 265 typedef std::deque<const Request*> RequestQueue; |
266 typedef std::map<const ClientSocketHandle*, const Request*> RequestMap; | 266 typedef std::map<const ClientSocketHandle*, const Request*> RequestMap; |
267 | 267 |
268 // A Group is allocated per group_name when there are idle sockets or pending | 268 // A Group is allocated per group_name when there are idle sockets or pending |
269 // requests. Otherwise, the Group object is removed from the map. | 269 // requests. Otherwise, the Group object is removed from the map. |
270 // |active_socket_count| tracks the number of sockets held by clients. | 270 // |active_socket_count| tracks the number of sockets held by clients. |
271 class Group { | 271 struct Group { |
272 public: | 272 Group() |
273 Group(); | 273 : active_socket_count(0), |
274 ~Group(); | 274 backup_job(NULL), |
| 275 backup_task(NULL) { |
| 276 } |
| 277 |
| 278 ~Group() { |
| 279 CleanupBackupJob(); |
| 280 } |
275 | 281 |
276 bool IsEmpty() const { | 282 bool IsEmpty() const { |
277 return active_socket_count_ == 0 && idle_sockets_.empty() && | 283 return active_socket_count == 0 && idle_sockets.empty() && jobs.empty() && |
278 jobs_.empty() && pending_requests_.empty(); | 284 pending_requests.empty(); |
279 } | 285 } |
280 | 286 |
281 bool HasAvailableSocketSlot(int max_sockets_per_group) const { | 287 bool HasAvailableSocketSlot(int max_sockets_per_group) const { |
282 return active_socket_count_ + static_cast<int>(jobs_.size()) < | 288 return active_socket_count + static_cast<int>(jobs.size()) < |
283 max_sockets_per_group; | 289 max_sockets_per_group; |
284 } | 290 } |
285 | 291 |
286 bool IsStalled(int max_sockets_per_group) const { | 292 bool IsStalled(int max_sockets_per_group) const { |
287 return HasAvailableSocketSlot(max_sockets_per_group) && | 293 return HasAvailableSocketSlot(max_sockets_per_group) && |
288 pending_requests_.size() > jobs_.size(); | 294 pending_requests.size() > jobs.size(); |
289 } | 295 } |
290 | 296 |
291 RequestPriority TopPendingPriority() const { | 297 RequestPriority TopPendingPriority() const { |
292 return pending_requests_.front()->priority(); | 298 return pending_requests.front()->priority(); |
293 } | 299 } |
294 | 300 |
295 bool HasBackupJob() const { return !method_factory_.empty(); } | |
296 | |
297 void CleanupBackupJob() { | 301 void CleanupBackupJob() { |
298 method_factory_.RevokeAll(); | 302 if (backup_job) { |
| 303 delete backup_job; |
| 304 backup_job = NULL; |
| 305 } |
| 306 if (backup_task) { |
| 307 backup_task->Cancel(); |
| 308 backup_task = NULL; |
| 309 } |
299 } | 310 } |
300 | 311 |
301 // Set a timer to create a backup socket if it takes too long to create one. | 312 std::deque<IdleSocket> idle_sockets; |
302 void StartBackupSocketTimer(const std::string& group_name, | 313 std::set<const ConnectJob*> jobs; |
303 ClientSocketPoolBaseHelper* pool); | 314 RequestQueue pending_requests; |
304 | 315 int active_socket_count; // number of active sockets used by clients |
305 // Called when the backup socket timer fires. | 316 // A backup job in case the connect for this group takes too long. |
306 void OnBackupSocketTimerFired( | 317 ConnectJob* backup_job; |
307 std::string group_name, | 318 CancelableTask* backup_task; |
308 ClientSocketPoolBaseHelper* pool); | |
309 | |
310 void AddJob(const ConnectJob* job) { jobs_.insert(job); } | |
311 void RemoveJob(const ConnectJob* job) { jobs_.erase(job); } | |
312 void RemoveAllJobs(); | |
313 | |
314 void IncrementActiveSocketCount() { active_socket_count_++; } | |
315 void DecrementActiveSocketCount() { active_socket_count_--; } | |
316 | |
317 const std::set<const ConnectJob*>& jobs() const { return jobs_; } | |
318 const std::deque<IdleSocket>& idle_sockets() const { return idle_sockets_; } | |
319 const RequestQueue& pending_requests() const { return pending_requests_; } | |
320 int active_socket_count() const { return active_socket_count_; } | |
321 RequestQueue* mutable_pending_requests() { return &pending_requests_; } | |
322 std::deque<IdleSocket>* mutable_idle_sockets() { return &idle_sockets_; } | |
323 | |
324 private: | |
325 std::deque<IdleSocket> idle_sockets_; | |
326 std::set<const ConnectJob*> jobs_; | |
327 RequestQueue pending_requests_; | |
328 int active_socket_count_; // number of active sockets used by clients | |
329 // A factory to pin the backup_job tasks. | |
330 ScopedRunnableMethodFactory<Group> method_factory_; | |
331 }; | 319 }; |
332 | 320 |
333 typedef std::map<std::string, Group*> GroupMap; | 321 typedef std::map<std::string, Group> GroupMap; |
334 | 322 |
335 typedef std::set<const ConnectJob*> ConnectJobSet; | 323 typedef std::set<const ConnectJob*> ConnectJobSet; |
336 | 324 |
337 struct CallbackResultPair { | 325 struct CallbackResultPair { |
338 CallbackResultPair() : callback(NULL), result(OK) {} | 326 CallbackResultPair() : callback(NULL), result(OK) {} |
339 CallbackResultPair(CompletionCallback* callback_in, int result_in) | 327 CallbackResultPair(CompletionCallback* callback_in, int result_in) |
340 : callback(callback_in), result(result_in) {} | 328 : callback(callback_in), result(result_in) {} |
341 | 329 |
342 CompletionCallback* callback; | 330 CompletionCallback* callback; |
343 int result; | 331 int result; |
344 }; | 332 }; |
345 | 333 |
346 typedef std::map<const ClientSocketHandle*, CallbackResultPair> | 334 typedef std::map<const ClientSocketHandle*, CallbackResultPair> |
347 PendingCallbackMap; | 335 PendingCallbackMap; |
348 | 336 |
349 ~ClientSocketPoolBaseHelper(); | 337 ~ClientSocketPoolBaseHelper(); |
350 | 338 |
351 static void InsertRequestIntoQueue(const Request* r, | 339 static void InsertRequestIntoQueue(const Request* r, |
352 RequestQueue* pending_requests); | 340 RequestQueue* pending_requests); |
353 static const Request* RemoveRequestFromQueue(RequestQueue::iterator it, | 341 static const Request* RemoveRequestFromQueue(RequestQueue::iterator it, |
354 RequestQueue* pending_requests); | 342 RequestQueue* pending_requests); |
355 | 343 |
356 Group* GetOrCreateGroup(const std::string& group_name); | |
357 void RemoveGroup(const std::string& group_name); | |
358 void RemoveGroup(GroupMap::iterator it); | |
359 | |
360 // Called when the number of idle sockets changes. | 344 // Called when the number of idle sockets changes. |
361 void IncrementIdleCount(); | 345 void IncrementIdleCount(); |
362 void DecrementIdleCount(); | 346 void DecrementIdleCount(); |
363 | 347 |
364 // Scans the group map for groups which have an available socket slot and | 348 // Scans the group map for groups which have an available socket slot and |
365 // at least one pending request. Returns true if any groups are stalled, and | 349 // at least one pending request. Returns true if any groups are stalled, and |
366 // if so, fills |group| and |group_name| with data of the stalled group | 350 // if so, fills |group| and |group_name| with data of the stalled group |
367 // having highest priority. | 351 // having highest priority. |
368 bool FindTopStalledGroup(Group** group, std::string* group_name); | 352 bool FindTopStalledGroup(Group** group, std::string* group_name); |
369 | 353 |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
403 bool ReachedMaxSocketsLimit() const; | 387 bool ReachedMaxSocketsLimit() const; |
404 | 388 |
405 // This is the internal implementation of RequestSocket(). It differs in that | 389 // This is the internal implementation of RequestSocket(). It differs in that |
406 // it does not handle logging into NetLog of the queueing status of | 390 // it does not handle logging into NetLog of the queueing status of |
407 // |request|. | 391 // |request|. |
408 int RequestSocketInternal(const std::string& group_name, | 392 int RequestSocketInternal(const std::string& group_name, |
409 const Request* request); | 393 const Request* request); |
410 | 394 |
411 // Assigns an idle socket for the group to the request. | 395 // Assigns an idle socket for the group to the request. |
412 // Returns |true| if an idle socket is available, false otherwise. | 396 // Returns |true| if an idle socket is available, false otherwise. |
413 bool AssignIdleSocketToGroup(const Request* request, Group* group); | 397 bool AssignIdleSocketToGroup(Group* group, const Request* request); |
414 | 398 |
415 static void LogBoundConnectJobToRequest( | 399 static void LogBoundConnectJobToRequest( |
416 const NetLog::Source& connect_job_source, const Request* request); | 400 const NetLog::Source& connect_job_source, const Request* request); |
417 | 401 |
| 402 // Set a timer to create a backup socket if it takes too long to create one. |
| 403 void StartBackupSocketTimer(const std::string& group_name); |
| 404 |
| 405 // Called when the backup socket timer fires. |
| 406 void OnBackupSocketTimerFired(const std::string& group_name); |
| 407 |
418 // Closes one idle socket. Picks the first one encountered. | 408 // Closes one idle socket. Picks the first one encountered. |
419 // TODO(willchan): Consider a better algorithm for doing this. Perhaps we | 409 // TODO(willchan): Consider a better algorithm for doing this. Perhaps we |
420 // should keep an ordered list of idle sockets, and close them in order. | 410 // should keep an ordered list of idle sockets, and close them in order. |
421 // Requires maintaining more state. It's not clear if it's worth it since | 411 // Requires maintaining more state. It's not clear if it's worth it since |
422 // I'm not sure if we hit this situation often. | 412 // I'm not sure if we hit this situation often. |
423 void CloseOneIdleSocket(); | 413 void CloseOneIdleSocket(); |
424 | 414 |
425 // Checks if there are stalled socket groups that should be notified | 415 // Checks if there are stalled socket groups that should be notified |
426 // for possible wakeup. | 416 // for possible wakeup. |
427 void CheckForStalledSocketGroups(); | 417 void CheckForStalledSocketGroups(); |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
466 | 456 |
467 // The time to wait until closing idle sockets. | 457 // The time to wait until closing idle sockets. |
468 const base::TimeDelta unused_idle_socket_timeout_; | 458 const base::TimeDelta unused_idle_socket_timeout_; |
469 const base::TimeDelta used_idle_socket_timeout_; | 459 const base::TimeDelta used_idle_socket_timeout_; |
470 | 460 |
471 const scoped_ptr<ConnectJobFactory> connect_job_factory_; | 461 const scoped_ptr<ConnectJobFactory> connect_job_factory_; |
472 | 462 |
473 // TODO(vandebo) Remove when backup jobs move to TCPClientSocketPool | 463 // TODO(vandebo) Remove when backup jobs move to TCPClientSocketPool |
474 bool backup_jobs_enabled_; | 464 bool backup_jobs_enabled_; |
475 | 465 |
| 466 // A factory to pin the backup_job tasks. |
| 467 ScopedRunnableMethodFactory<ClientSocketPoolBaseHelper> method_factory_; |
| 468 |
476 // A unique id for the pool. It gets incremented every time we Flush() the | 469 // A unique id for the pool. It gets incremented every time we Flush() the |
477 // pool. This is so that when sockets get released back to the pool, we can | 470 // pool. This is so that when sockets get released back to the pool, we can |
478 // make sure that they are discarded rather than reused. | 471 // make sure that they are discarded rather than reused. |
479 int pool_generation_number_; | 472 int pool_generation_number_; |
480 | 473 |
481 // Some parts of this class need to know if the destructor is running. | 474 // Some parts of this class need to know if the destructor is running. |
482 bool in_destructor_; | 475 bool in_destructor_; |
483 }; | 476 }; |
484 | 477 |
485 } // namespace internal | 478 } // namespace internal |
(...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
646 // ClientSocketPoolBase<T> reference to drop to zero. While we're deep | 639 // ClientSocketPoolBase<T> reference to drop to zero. While we're deep |
647 // in cleanup code, we'll often hold a reference to |self|. | 640 // in cleanup code, we'll often hold a reference to |self|. |
648 scoped_refptr<internal::ClientSocketPoolBaseHelper> helper_; | 641 scoped_refptr<internal::ClientSocketPoolBaseHelper> helper_; |
649 | 642 |
650 DISALLOW_COPY_AND_ASSIGN(ClientSocketPoolBase); | 643 DISALLOW_COPY_AND_ASSIGN(ClientSocketPoolBase); |
651 }; | 644 }; |
652 | 645 |
653 } // namespace net | 646 } // namespace net |
654 | 647 |
655 #endif // NET_SOCKET_CLIENT_SOCKET_POOL_BASE_H_ | 648 #endif // NET_SOCKET_CLIENT_SOCKET_POOL_BASE_H_ |
OLD | NEW |