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