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

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

Issue 2994003: Refactor how ClientSocketPoolBaseHelper avoids re-entrancy. (Closed) Base URL: http://src.chromium.org/git/chromium.git
Patch Set: Merge. Created 10 years, 5 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 | « net/socket/client_socket_pool.h ('k') | 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) 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
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
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
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
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
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
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
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_
OLDNEW
« no previous file with comments | « net/socket/client_socket_pool.h ('k') | net/socket/client_socket_pool_base.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698