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

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

Issue 3171017: Only create the backup ConnectJob when it is needed. (Closed) Base URL: http://src.chromium.org/git/chromium.git
Patch Set: Address mbelshe's comments. Created 10 years, 4 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_base.h ('k') | no next file » | 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 #include "net/socket/client_socket_pool_base.h" 5 #include "net/socket/client_socket_pool_base.h"
6 6
7 #include "base/compiler_specific.h" 7 #include "base/compiler_specific.h"
8 #include "base/format_macros.h" 8 #include "base/format_macros.h"
9 #include "base/message_loop.h" 9 #include "base/message_loop.h"
10 #include "base/stats_counters.h" 10 #include "base/stats_counters.h"
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after
131 ConnectJobFactory* connect_job_factory) 131 ConnectJobFactory* connect_job_factory)
132 : idle_socket_count_(0), 132 : idle_socket_count_(0),
133 connecting_socket_count_(0), 133 connecting_socket_count_(0),
134 handed_out_socket_count_(0), 134 handed_out_socket_count_(0),
135 max_sockets_(max_sockets), 135 max_sockets_(max_sockets),
136 max_sockets_per_group_(max_sockets_per_group), 136 max_sockets_per_group_(max_sockets_per_group),
137 unused_idle_socket_timeout_(unused_idle_socket_timeout), 137 unused_idle_socket_timeout_(unused_idle_socket_timeout),
138 used_idle_socket_timeout_(used_idle_socket_timeout), 138 used_idle_socket_timeout_(used_idle_socket_timeout),
139 connect_job_factory_(connect_job_factory), 139 connect_job_factory_(connect_job_factory),
140 backup_jobs_enabled_(false), 140 backup_jobs_enabled_(false),
141 ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)),
142 pool_generation_number_(0), 141 pool_generation_number_(0),
143 in_destructor_(false) { 142 in_destructor_(false) {
144 DCHECK_LE(0, max_sockets_per_group); 143 DCHECK_LE(0, max_sockets_per_group);
145 DCHECK_LE(max_sockets_per_group, max_sockets); 144 DCHECK_LE(max_sockets_per_group, max_sockets);
146 145
147 NetworkChangeNotifier::AddObserver(this); 146 NetworkChangeNotifier::AddObserver(this);
148 } 147 }
149 148
150 ClientSocketPoolBaseHelper::~ClientSocketPoolBaseHelper() { 149 ClientSocketPoolBaseHelper::~ClientSocketPoolBaseHelper() {
151 in_destructor_ = true; 150 in_destructor_ = true;
(...skipping 29 matching lines...) Expand all
181 RequestQueue::iterator it, RequestQueue* pending_requests) { 180 RequestQueue::iterator it, RequestQueue* pending_requests) {
182 const Request* req = *it; 181 const Request* req = *it;
183 pending_requests->erase(it); 182 pending_requests->erase(it);
184 return req; 183 return req;
185 } 184 }
186 185
187 int ClientSocketPoolBaseHelper::RequestSocket( 186 int ClientSocketPoolBaseHelper::RequestSocket(
188 const std::string& group_name, 187 const std::string& group_name,
189 const Request* request) { 188 const Request* request) {
190 request->net_log().BeginEvent(NetLog::TYPE_SOCKET_POOL, NULL); 189 request->net_log().BeginEvent(NetLog::TYPE_SOCKET_POOL, NULL);
191 Group& group = group_map_[group_name]; 190 Group* group = GetOrCreateGroup(group_name);
192 191
193 int rv = RequestSocketInternal(group_name, request); 192 int rv = RequestSocketInternal(group_name, request);
194 if (rv != ERR_IO_PENDING) { 193 if (rv != ERR_IO_PENDING) {
195 request->net_log().EndEvent(NetLog::TYPE_SOCKET_POOL, NULL); 194 request->net_log().EndEvent(NetLog::TYPE_SOCKET_POOL, NULL);
196 CHECK(!request->handle()->is_initialized()); 195 CHECK(!request->handle()->is_initialized());
197 delete request; 196 delete request;
198 } else { 197 } else {
199 InsertRequestIntoQueue(request, &group.pending_requests); 198 InsertRequestIntoQueue(request, group->mutable_pending_requests());
200 } 199 }
201 return rv; 200 return rv;
202 } 201 }
203 202
204 int ClientSocketPoolBaseHelper::RequestSocketInternal( 203 int ClientSocketPoolBaseHelper::RequestSocketInternal(
205 const std::string& group_name, 204 const std::string& group_name,
206 const Request* request) { 205 const Request* request) {
207 DCHECK_GE(request->priority(), 0); 206 DCHECK_GE(request->priority(), 0);
208 CompletionCallback* const callback = request->callback(); 207 CompletionCallback* const callback = request->callback();
209 CHECK(callback); 208 CHECK(callback);
210 ClientSocketHandle* const handle = request->handle(); 209 ClientSocketHandle* const handle = request->handle();
211 CHECK(handle); 210 CHECK(handle);
212 Group& group = group_map_[group_name]; 211 Group* group = GetOrCreateGroup(group_name);
213 212
214 // Try to reuse a socket. 213 // Try to reuse a socket.
215 if (AssignIdleSocketToGroup(&group, request)) 214 if (AssignIdleSocketToGroup(request, group))
216 return OK; 215 return OK;
217 216
218 // Can we make another active socket now? 217 // Can we make another active socket now?
219 if (!group.HasAvailableSocketSlot(max_sockets_per_group_)) { 218 if (!group->HasAvailableSocketSlot(max_sockets_per_group_)) {
220 request->net_log().AddEvent( 219 request->net_log().AddEvent(
221 NetLog::TYPE_SOCKET_POOL_STALLED_MAX_SOCKETS_PER_GROUP, NULL); 220 NetLog::TYPE_SOCKET_POOL_STALLED_MAX_SOCKETS_PER_GROUP, NULL);
222 return ERR_IO_PENDING; 221 return ERR_IO_PENDING;
223 } 222 }
224 223
225 if (ReachedMaxSocketsLimit()) { 224 if (ReachedMaxSocketsLimit()) {
226 if (idle_socket_count() > 0) { 225 if (idle_socket_count() > 0) {
227 CloseOneIdleSocket(); 226 CloseOneIdleSocket();
228 } else { 227 } else {
229 // We could check if we really have a stalled group here, but it requires 228 // We could check if we really have a stalled group here, but it requires
230 // a scan of all groups, so just flip a flag here, and do the check later. 229 // a scan of all groups, so just flip a flag here, and do the check later.
231 request->net_log().AddEvent( 230 request->net_log().AddEvent(
232 NetLog::TYPE_SOCKET_POOL_STALLED_MAX_SOCKETS, NULL); 231 NetLog::TYPE_SOCKET_POOL_STALLED_MAX_SOCKETS, NULL);
233 return ERR_IO_PENDING; 232 return ERR_IO_PENDING;
234 } 233 }
235 } 234 }
236 235
237 // We couldn't find a socket to reuse, so allocate and connect a new one. 236 // We couldn't find a socket to reuse, so allocate and connect a new one.
238 scoped_ptr<ConnectJob> connect_job( 237 scoped_ptr<ConnectJob> connect_job(
239 connect_job_factory_->NewConnectJob(group_name, *request, this)); 238 connect_job_factory_->NewConnectJob(group_name, *request, this));
240 239
241 int rv = connect_job->Connect(); 240 int rv = connect_job->Connect();
242 if (rv == OK) { 241 if (rv == OK) {
243 LogBoundConnectJobToRequest(connect_job->net_log().source(), request); 242 LogBoundConnectJobToRequest(connect_job->net_log().source(), request);
244 HandOutSocket(connect_job->ReleaseSocket(), false /* not reused */, 243 HandOutSocket(connect_job->ReleaseSocket(), false /* not reused */,
245 handle, base::TimeDelta(), &group, request->net_log()); 244 handle, base::TimeDelta(), group, request->net_log());
246 } else if (rv == ERR_IO_PENDING) { 245 } else if (rv == ERR_IO_PENDING) {
247 // If we don't have any sockets in this group, set a timer for potentially 246 // If we don't have any sockets in this group, set a timer for potentially
248 // creating a new one. If the SYN is lost, this backup socket may complete 247 // creating a new one. If the SYN is lost, this backup socket may complete
249 // before the slow socket, improving end user latency. 248 // before the slow socket, improving end user latency.
250 if (group.IsEmpty() && !group.backup_job && backup_jobs_enabled_) { 249 if (group->IsEmpty() && !group->HasBackupJob() && backup_jobs_enabled_)
251 group.backup_job = connect_job_factory_->NewConnectJob(group_name, 250 group->StartBackupSocketTimer(group_name, this);
252 *request,
253 this);
254 StartBackupSocketTimer(group_name);
255 }
256 251
257 connecting_socket_count_++; 252 connecting_socket_count_++;
258 253
259 ConnectJob* job = connect_job.release(); 254 group->AddJob(connect_job.release());
260 group.jobs.insert(job);
261 } else { 255 } else {
262 LogBoundConnectJobToRequest(connect_job->net_log().source(), request); 256 LogBoundConnectJobToRequest(connect_job->net_log().source(), request);
263 connect_job->GetAdditionalErrorState(handle); 257 connect_job->GetAdditionalErrorState(handle);
264 ClientSocket* error_socket = connect_job->ReleaseSocket(); 258 ClientSocket* error_socket = connect_job->ReleaseSocket();
265 if (error_socket) { 259 if (error_socket) {
266 HandOutSocket(error_socket, false /* not reused */, handle, 260 HandOutSocket(error_socket, false /* not reused */, handle,
267 base::TimeDelta(), &group, request->net_log()); 261 base::TimeDelta(), group, request->net_log());
268 } else if (group.IsEmpty()) { 262 } else if (group->IsEmpty()) {
269 group_map_.erase(group_name); 263 RemoveGroup(group_name);
270 } 264 }
271 } 265 }
272 266
273 return rv; 267 return rv;
274 } 268 }
275 269
276 bool ClientSocketPoolBaseHelper::AssignIdleSocketToGroup( 270 bool ClientSocketPoolBaseHelper::AssignIdleSocketToGroup(
277 Group* group, const Request* request) { 271 const Request* request, Group* group) {
278 // Iterate through the list of idle sockets until we find one or exhaust 272 // Iterate through the list of idle sockets until we find one or exhaust
279 // the list. 273 // the list.
280 while (!group->idle_sockets.empty()) { 274 while (!group->idle_sockets().empty()) {
281 IdleSocket idle_socket = group->idle_sockets.back(); 275 IdleSocket idle_socket = group->idle_sockets().back();
282 group->idle_sockets.pop_back(); 276 group->mutable_idle_sockets()->pop_back();
283 DecrementIdleCount(); 277 DecrementIdleCount();
284 if (idle_socket.socket->IsConnectedAndIdle()) { 278 if (idle_socket.socket->IsConnectedAndIdle()) {
285 // We found one we can reuse! 279 // We found one we can reuse!
286 base::TimeDelta idle_time = 280 base::TimeDelta idle_time =
287 base::TimeTicks::Now() - idle_socket.start_time; 281 base::TimeTicks::Now() - idle_socket.start_time;
288 HandOutSocket( 282 HandOutSocket(
289 idle_socket.socket, idle_socket.used, request->handle(), idle_time, 283 idle_socket.socket, idle_socket.used, request->handle(), idle_time,
290 group, request->net_log()); 284 group, request->net_log());
291 return true; 285 return true;
292 } 286 }
293 delete idle_socket.socket; 287 delete idle_socket.socket;
294 } 288 }
295 return false; 289 return false;
296 } 290 }
297 291
298 // static 292 // static
299 void ClientSocketPoolBaseHelper::LogBoundConnectJobToRequest( 293 void ClientSocketPoolBaseHelper::LogBoundConnectJobToRequest(
300 const NetLog::Source& connect_job_source, const Request* request) { 294 const NetLog::Source& connect_job_source, const Request* request) {
301 request->net_log().AddEvent( 295 request->net_log().AddEvent(
302 NetLog::TYPE_SOCKET_POOL_BOUND_TO_CONNECT_JOB, 296 NetLog::TYPE_SOCKET_POOL_BOUND_TO_CONNECT_JOB,
303 new NetLogSourceParameter("source_dependency", connect_job_source)); 297 new NetLogSourceParameter("source_dependency", connect_job_source));
304 } 298 }
305 299
306 void ClientSocketPoolBaseHelper::StartBackupSocketTimer(
307 const std::string& group_name) {
308 CHECK(ContainsKey(group_map_, group_name));
309 Group& group = group_map_[group_name];
310
311 // Only allow one timer pending to create a backup socket.
312 if (group.backup_task)
313 return;
314
315 group.backup_task = method_factory_.NewRunnableMethod(
316 &ClientSocketPoolBaseHelper::OnBackupSocketTimerFired, group_name);
317 MessageLoop::current()->PostDelayedTask(FROM_HERE, group.backup_task,
318 ConnectRetryIntervalMs());
319 }
320
321 void ClientSocketPoolBaseHelper::OnBackupSocketTimerFired(
322 const std::string& group_name) {
323 CHECK(ContainsKey(group_map_, group_name));
324
325 Group& group = group_map_[group_name];
326
327 CHECK(group.backup_task);
328 group.backup_task = NULL;
329
330 CHECK(group.backup_job);
331
332 // If there are no more jobs pending, there is no work to do.
333 // If we've done our cleanups correctly, this should not happen.
334 if (group.jobs.empty()) {
335 NOTREACHED();
336 return;
337 }
338
339 // If our backup job is waiting on DNS, or if we can't create any sockets
340 // right now due to limits, just reset the timer.
341 if (ReachedMaxSocketsLimit() ||
342 !group.HasAvailableSocketSlot(max_sockets_per_group_) ||
343 (*group.jobs.begin())->GetLoadState() == LOAD_STATE_RESOLVING_HOST) {
344 StartBackupSocketTimer(group_name);
345 return;
346 }
347
348 group.backup_job->net_log().AddEvent(NetLog::TYPE_SOCKET_BACKUP_CREATED,
349 NULL);
350 SIMPLE_STATS_COUNTER("socket.backup_created");
351 int rv = group.backup_job->Connect();
352 connecting_socket_count_++;
353 group.jobs.insert(group.backup_job);
354 ConnectJob* job = group.backup_job;
355 group.backup_job = NULL;
356 if (rv != ERR_IO_PENDING)
357 OnConnectJobComplete(rv, job);
358 }
359
360 void ClientSocketPoolBaseHelper::CancelRequest( 300 void ClientSocketPoolBaseHelper::CancelRequest(
361 const std::string& group_name, ClientSocketHandle* handle) { 301 const std::string& group_name, ClientSocketHandle* handle) {
362 PendingCallbackMap::iterator callback_it = pending_callback_map_.find(handle); 302 PendingCallbackMap::iterator callback_it = pending_callback_map_.find(handle);
363 if (callback_it != pending_callback_map_.end()) { 303 if (callback_it != pending_callback_map_.end()) {
364 int result = callback_it->second.result; 304 int result = callback_it->second.result;
365 pending_callback_map_.erase(callback_it); 305 pending_callback_map_.erase(callback_it);
366 ClientSocket* socket = handle->release_socket(); 306 ClientSocket* socket = handle->release_socket();
367 if (socket) { 307 if (socket) {
368 if (result != OK) 308 if (result != OK)
369 socket->Disconnect(); 309 socket->Disconnect();
370 ReleaseSocket(handle->group_name(), socket, handle->id()); 310 ReleaseSocket(handle->group_name(), socket, handle->id());
371 } 311 }
372 return; 312 return;
373 } 313 }
374 314
375 CHECK(ContainsKey(group_map_, group_name)); 315 CHECK(ContainsKey(group_map_, group_name));
376 316
377 Group& group = group_map_[group_name]; 317 Group* group = GetOrCreateGroup(group_name);
378 318
379 // Search pending_requests for matching handle. 319 // Search pending_requests for matching handle.
380 RequestQueue::iterator it = group.pending_requests.begin(); 320 RequestQueue::iterator it = group->mutable_pending_requests()->begin();
381 for (; it != group.pending_requests.end(); ++it) { 321 for (; it != group->pending_requests().end(); ++it) {
382 if ((*it)->handle() == handle) { 322 if ((*it)->handle() == handle) {
383 const Request* req = RemoveRequestFromQueue(it, &group.pending_requests); 323 const Request* req =
324 RemoveRequestFromQueue(it, group->mutable_pending_requests());
384 req->net_log().AddEvent(NetLog::TYPE_CANCELLED, NULL); 325 req->net_log().AddEvent(NetLog::TYPE_CANCELLED, NULL);
385 req->net_log().EndEvent(NetLog::TYPE_SOCKET_POOL, NULL); 326 req->net_log().EndEvent(NetLog::TYPE_SOCKET_POOL, NULL);
386 delete req; 327 delete req;
387 328
388 // We let the job run, unless we're at the socket limit. 329 // We let the job run, unless we're at the socket limit.
389 if (group.jobs.size() && ReachedMaxSocketsLimit()) { 330 if (group->jobs().size() && ReachedMaxSocketsLimit()) {
390 RemoveConnectJob(*group.jobs.begin(), &group); 331 RemoveConnectJob(*group->jobs().begin(), group);
391 CheckForStalledSocketGroups(); 332 CheckForStalledSocketGroups();
392 } 333 }
393 break; 334 break;
394 } 335 }
395 } 336 }
396 } 337 }
397 338
398 void ClientSocketPoolBaseHelper::CloseIdleSockets() { 339 void ClientSocketPoolBaseHelper::CloseIdleSockets() {
399 CleanupIdleSockets(true); 340 CleanupIdleSockets(true);
400 } 341 }
401 342
402 int ClientSocketPoolBaseHelper::IdleSocketCountInGroup( 343 int ClientSocketPoolBaseHelper::IdleSocketCountInGroup(
403 const std::string& group_name) const { 344 const std::string& group_name) const {
404 GroupMap::const_iterator i = group_map_.find(group_name); 345 GroupMap::const_iterator i = group_map_.find(group_name);
405 CHECK(i != group_map_.end()); 346 CHECK(i != group_map_.end());
406 347
407 return i->second.idle_sockets.size(); 348 return i->second->idle_sockets().size();
408 } 349 }
409 350
410 LoadState ClientSocketPoolBaseHelper::GetLoadState( 351 LoadState ClientSocketPoolBaseHelper::GetLoadState(
411 const std::string& group_name, 352 const std::string& group_name,
412 const ClientSocketHandle* handle) const { 353 const ClientSocketHandle* handle) const {
413 if (ContainsKey(pending_callback_map_, handle)) 354 if (ContainsKey(pending_callback_map_, handle))
414 return LOAD_STATE_CONNECTING; 355 return LOAD_STATE_CONNECTING;
415 356
416 if (!ContainsKey(group_map_, group_name)) { 357 if (!ContainsKey(group_map_, group_name)) {
417 NOTREACHED() << "ClientSocketPool does not contain group: " << group_name 358 NOTREACHED() << "ClientSocketPool does not contain group: " << group_name
418 << " for handle: " << handle; 359 << " for handle: " << handle;
419 return LOAD_STATE_IDLE; 360 return LOAD_STATE_IDLE;
420 } 361 }
421 362
422 // Can't use operator[] since it is non-const. 363 // Can't use operator[] since it is non-const.
423 const Group& group = group_map_.find(group_name)->second; 364 const Group& group = *group_map_.find(group_name)->second;
424 365
425 // Search pending_requests for matching handle. 366 // Search pending_requests for matching handle.
426 RequestQueue::const_iterator it = group.pending_requests.begin(); 367 RequestQueue::const_iterator it = group.pending_requests().begin();
427 for (size_t i = 0; it != group.pending_requests.end(); ++it, ++i) { 368 for (size_t i = 0; it != group.pending_requests().end(); ++it, ++i) {
428 if ((*it)->handle() == handle) { 369 if ((*it)->handle() == handle) {
429 if (i < group.jobs.size()) { 370 if (i < group.jobs().size()) {
430 LoadState max_state = LOAD_STATE_IDLE; 371 LoadState max_state = LOAD_STATE_IDLE;
431 for (ConnectJobSet::const_iterator job_it = group.jobs.begin(); 372 for (ConnectJobSet::const_iterator job_it = group.jobs().begin();
432 job_it != group.jobs.end(); ++job_it) { 373 job_it != group.jobs().end(); ++job_it) {
433 max_state = std::max(max_state, (*job_it)->GetLoadState()); 374 max_state = std::max(max_state, (*job_it)->GetLoadState());
434 } 375 }
435 return max_state; 376 return max_state;
436 } else { 377 } else {
437 // TODO(wtc): Add a state for being on the wait list. 378 // TODO(wtc): Add a state for being on the wait list.
438 // See http://www.crbug.com/5077. 379 // See http://www.crbug.com/5077.
439 return LOAD_STATE_IDLE; 380 return LOAD_STATE_IDLE;
440 } 381 }
441 } 382 }
442 } 383 }
(...skipping 21 matching lines...) Expand all
464 scoped_refptr<ClientSocketPoolBaseHelper> protect_this; 405 scoped_refptr<ClientSocketPoolBaseHelper> protect_this;
465 if (!in_destructor_) 406 if (!in_destructor_)
466 protect_this = this; 407 protect_this = this;
467 408
468 // Current time value. Retrieving it once at the function start rather than 409 // Current time value. Retrieving it once at the function start rather than
469 // inside the inner loop, since it shouldn't change by any meaningful amount. 410 // inside the inner loop, since it shouldn't change by any meaningful amount.
470 base::TimeTicks now = base::TimeTicks::Now(); 411 base::TimeTicks now = base::TimeTicks::Now();
471 412
472 GroupMap::iterator i = group_map_.begin(); 413 GroupMap::iterator i = group_map_.begin();
473 while (i != group_map_.end()) { 414 while (i != group_map_.end()) {
474 Group& group = i->second; 415 Group* group = i->second;
475 416
476 std::deque<IdleSocket>::iterator j = group.idle_sockets.begin(); 417 std::deque<IdleSocket>::iterator j = group->mutable_idle_sockets()->begin();
477 while (j != group.idle_sockets.end()) { 418 while (j != group->idle_sockets().end()) {
478 base::TimeDelta timeout = 419 base::TimeDelta timeout =
479 j->used ? used_idle_socket_timeout_ : unused_idle_socket_timeout_; 420 j->used ? used_idle_socket_timeout_ : unused_idle_socket_timeout_;
480 if (force || j->ShouldCleanup(now, timeout)) { 421 if (force || j->ShouldCleanup(now, timeout)) {
481 delete j->socket; 422 delete j->socket;
482 j = group.idle_sockets.erase(j); 423 j = group->mutable_idle_sockets()->erase(j);
483 DecrementIdleCount(); 424 DecrementIdleCount();
484 } else { 425 } else {
485 ++j; 426 ++j;
486 } 427 }
487 } 428 }
488 429
489 // Delete group if no longer needed. 430 // Delete group if no longer needed.
490 if (group.IsEmpty()) { 431 if (group->IsEmpty()) {
491 group_map_.erase(i++); 432 RemoveGroup(i++);
492 } else { 433 } else {
493 ++i; 434 ++i;
494 } 435 }
495 } 436 }
496 } 437 }
497 438
439 ClientSocketPoolBaseHelper::Group* ClientSocketPoolBaseHelper::GetOrCreateGroup(
440 const std::string& group_name) {
441 GroupMap::iterator it = group_map_.find(group_name);
442 if (it != group_map_.end())
443 return it->second;
444 Group* group = new Group;
445 group_map_[group_name] = group;
446 return group;
447 }
448
449 void ClientSocketPoolBaseHelper::RemoveGroup(const std::string& group_name) {
450 GroupMap::iterator it = group_map_.find(group_name);
451 CHECK(it != group_map_.end());
452
453 RemoveGroup(it);
454 }
455
456 void ClientSocketPoolBaseHelper::RemoveGroup(GroupMap::iterator it) {
457 delete it->second;
458 group_map_.erase(it);
459 }
460
498 void ClientSocketPoolBaseHelper::IncrementIdleCount() { 461 void ClientSocketPoolBaseHelper::IncrementIdleCount() {
499 if (++idle_socket_count_ == 1) 462 if (++idle_socket_count_ == 1)
500 timer_.Start(TimeDelta::FromSeconds(kCleanupInterval), this, 463 timer_.Start(TimeDelta::FromSeconds(kCleanupInterval), this,
501 &ClientSocketPoolBaseHelper::OnCleanupTimerFired); 464 &ClientSocketPoolBaseHelper::OnCleanupTimerFired);
502 } 465 }
503 466
504 void ClientSocketPoolBaseHelper::DecrementIdleCount() { 467 void ClientSocketPoolBaseHelper::DecrementIdleCount() {
505 if (--idle_socket_count_ == 0) 468 if (--idle_socket_count_ == 0)
506 timer_.Stop(); 469 timer_.Stop();
507 } 470 }
508 471
509 void ClientSocketPoolBaseHelper::ReleaseSocket(const std::string& group_name, 472 void ClientSocketPoolBaseHelper::ReleaseSocket(const std::string& group_name,
510 ClientSocket* socket, 473 ClientSocket* socket,
511 int id) { 474 int id) {
512 GroupMap::iterator i = group_map_.find(group_name); 475 GroupMap::iterator i = group_map_.find(group_name);
513 CHECK(i != group_map_.end()); 476 CHECK(i != group_map_.end());
514 477
515 Group& group = i->second; 478 Group* group = i->second;
516 479
517 CHECK_GT(handed_out_socket_count_, 0); 480 CHECK_GT(handed_out_socket_count_, 0);
518 handed_out_socket_count_--; 481 handed_out_socket_count_--;
519 482
520 CHECK_GT(group.active_socket_count, 0); 483 CHECK_GT(group->active_socket_count(), 0);
521 group.active_socket_count--; 484 group->DecrementActiveSocketCount();
522 485
523 const bool can_reuse = socket->IsConnectedAndIdle() && 486 const bool can_reuse = socket->IsConnectedAndIdle() &&
524 id == pool_generation_number_; 487 id == pool_generation_number_;
525 if (can_reuse) { 488 if (can_reuse) {
526 // Add it to the idle list. 489 // Add it to the idle list.
527 AddIdleSocket(socket, true /* used socket */, &group); 490 AddIdleSocket(socket, true /* used socket */, group);
528 OnAvailableSocketSlot(group_name, &group); 491 OnAvailableSocketSlot(group_name, group);
529 } else { 492 } else {
530 delete socket; 493 delete socket;
531 } 494 }
532 495
533 CheckForStalledSocketGroups(); 496 CheckForStalledSocketGroups();
534 } 497 }
535 498
536 void ClientSocketPoolBaseHelper::CheckForStalledSocketGroups() { 499 void ClientSocketPoolBaseHelper::CheckForStalledSocketGroups() {
537 // If we have idle sockets, see if we can give one to the top-stalled group. 500 // If we have idle sockets, see if we can give one to the top-stalled group.
538 std::string top_group_name; 501 std::string top_group_name;
(...skipping 22 matching lines...) Expand all
561 // are not at the |max_sockets_per_group_| limit. Note: for requests with 524 // are not at the |max_sockets_per_group_| limit. Note: for requests with
562 // the same priority, the winner is based on group hash ordering (and not 525 // the same priority, the winner is based on group hash ordering (and not
563 // insertion order). 526 // insertion order).
564 bool ClientSocketPoolBaseHelper::FindTopStalledGroup(Group** group, 527 bool ClientSocketPoolBaseHelper::FindTopStalledGroup(Group** group,
565 std::string* group_name) { 528 std::string* group_name) {
566 Group* top_group = NULL; 529 Group* top_group = NULL;
567 const std::string* top_group_name = NULL; 530 const std::string* top_group_name = NULL;
568 bool has_stalled_group = false; 531 bool has_stalled_group = false;
569 for (GroupMap::iterator i = group_map_.begin(); 532 for (GroupMap::iterator i = group_map_.begin();
570 i != group_map_.end(); ++i) { 533 i != group_map_.end(); ++i) {
571 Group& group = i->second; 534 Group* curr_group = i->second;
572 const RequestQueue& queue = group.pending_requests; 535 const RequestQueue& queue = curr_group->pending_requests();
573 if (queue.empty()) 536 if (queue.empty())
574 continue; 537 continue;
575 if (group.IsStalled(max_sockets_per_group_)) { 538 if (curr_group->IsStalled(max_sockets_per_group_)) {
576 has_stalled_group = true; 539 has_stalled_group = true;
577 bool has_higher_priority = !top_group || 540 bool has_higher_priority = !top_group ||
578 group.TopPendingPriority() < top_group->TopPendingPriority(); 541 curr_group->TopPendingPriority() < top_group->TopPendingPriority();
579 if (has_higher_priority) { 542 if (has_higher_priority) {
580 top_group = &group; 543 top_group = curr_group;
581 top_group_name = &i->first; 544 top_group_name = &i->first;
582 } 545 }
583 } 546 }
584 } 547 }
585 548
586 if (top_group) { 549 if (top_group) {
587 *group = top_group; 550 *group = top_group;
588 *group_name = *top_group_name; 551 *group_name = *top_group_name;
589 } 552 }
590 return has_stalled_group; 553 return has_stalled_group;
591 } 554 }
592 555
593 void ClientSocketPoolBaseHelper::OnConnectJobComplete( 556 void ClientSocketPoolBaseHelper::OnConnectJobComplete(
594 int result, ConnectJob* job) { 557 int result, ConnectJob* job) {
595 DCHECK_NE(ERR_IO_PENDING, result); 558 DCHECK_NE(ERR_IO_PENDING, result);
596 const std::string group_name = job->group_name(); 559 const std::string group_name = job->group_name();
597 GroupMap::iterator group_it = group_map_.find(group_name); 560 GroupMap::iterator group_it = group_map_.find(group_name);
598 CHECK(group_it != group_map_.end()); 561 CHECK(group_it != group_map_.end());
599 Group& group = group_it->second; 562 Group* group = group_it->second;
600 563
601 scoped_ptr<ClientSocket> socket(job->ReleaseSocket()); 564 scoped_ptr<ClientSocket> socket(job->ReleaseSocket());
602 565
603 BoundNetLog job_log = job->net_log(); 566 BoundNetLog job_log = job->net_log();
604 567
605 if (result == OK) { 568 if (result == OK) {
606 DCHECK(socket.get()); 569 DCHECK(socket.get());
607 RemoveConnectJob(job, &group); 570 RemoveConnectJob(job, group);
608 if (!group.pending_requests.empty()) { 571 if (!group->pending_requests().empty()) {
609 scoped_ptr<const Request> r(RemoveRequestFromQueue( 572 scoped_ptr<const Request> r(RemoveRequestFromQueue(
610 group.pending_requests.begin(), &group.pending_requests)); 573 group->mutable_pending_requests()->begin(),
574 group->mutable_pending_requests()));
611 LogBoundConnectJobToRequest(job_log.source(), r.get()); 575 LogBoundConnectJobToRequest(job_log.source(), r.get());
612 HandOutSocket( 576 HandOutSocket(
613 socket.release(), false /* unused socket */, r->handle(), 577 socket.release(), false /* unused socket */, r->handle(),
614 base::TimeDelta(), &group, r->net_log()); 578 base::TimeDelta(), group, r->net_log());
615 r->net_log().EndEvent(NetLog::TYPE_SOCKET_POOL, NULL); 579 r->net_log().EndEvent(NetLog::TYPE_SOCKET_POOL, NULL);
616 InvokeUserCallbackLater(r->handle(), r->callback(), result); 580 InvokeUserCallbackLater(r->handle(), r->callback(), result);
617 } else { 581 } else {
618 AddIdleSocket(socket.release(), false /* unused socket */, &group); 582 AddIdleSocket(socket.release(), false /* unused socket */, group);
619 OnAvailableSocketSlot(group_name, &group); 583 OnAvailableSocketSlot(group_name, group);
620 CheckForStalledSocketGroups(); 584 CheckForStalledSocketGroups();
621 } 585 }
622 } else { 586 } else {
623 // If we got a socket, it must contain error information so pass that 587 // If we got a socket, it must contain error information so pass that
624 // up so that the caller can retrieve it. 588 // up so that the caller can retrieve it.
625 bool handed_out_socket = false; 589 bool handed_out_socket = false;
626 if (!group.pending_requests.empty()) { 590 if (!group->pending_requests().empty()) {
627 scoped_ptr<const Request> r(RemoveRequestFromQueue( 591 scoped_ptr<const Request> r(RemoveRequestFromQueue(
628 group.pending_requests.begin(), &group.pending_requests)); 592 group->mutable_pending_requests()->begin(),
593 group->mutable_pending_requests()));
629 LogBoundConnectJobToRequest(job_log.source(), r.get()); 594 LogBoundConnectJobToRequest(job_log.source(), r.get());
630 job->GetAdditionalErrorState(r->handle()); 595 job->GetAdditionalErrorState(r->handle());
631 RemoveConnectJob(job, &group); 596 RemoveConnectJob(job, group);
632 if (socket.get()) { 597 if (socket.get()) {
633 handed_out_socket = true; 598 handed_out_socket = true;
634 HandOutSocket(socket.release(), false /* unused socket */, r->handle(), 599 HandOutSocket(socket.release(), false /* unused socket */, r->handle(),
635 base::TimeDelta(), &group, r->net_log()); 600 base::TimeDelta(), group, r->net_log());
636 } 601 }
637 r->net_log().EndEvent(NetLog::TYPE_SOCKET_POOL, 602 r->net_log().EndEvent(NetLog::TYPE_SOCKET_POOL,
638 new NetLogIntegerParameter("net_error", result)); 603 new NetLogIntegerParameter("net_error", result));
639 InvokeUserCallbackLater(r->handle(), r->callback(), result); 604 InvokeUserCallbackLater(r->handle(), r->callback(), result);
640 } else { 605 } else {
641 RemoveConnectJob(job, &group); 606 RemoveConnectJob(job, group);
642 } 607 }
643 if (!handed_out_socket) { 608 if (!handed_out_socket) {
644 OnAvailableSocketSlot(group_name, &group); 609 OnAvailableSocketSlot(group_name, group);
645 CheckForStalledSocketGroups(); 610 CheckForStalledSocketGroups();
646 } 611 }
647 } 612 }
648 } 613 }
649 614
650 void ClientSocketPoolBaseHelper::OnIPAddressChanged() { 615 void ClientSocketPoolBaseHelper::OnIPAddressChanged() {
651 Flush(); 616 Flush();
652 } 617 }
653 618
654 void ClientSocketPoolBaseHelper::Flush() { 619 void ClientSocketPoolBaseHelper::Flush() {
655 pool_generation_number_++; 620 pool_generation_number_++;
656 CloseIdleSockets(); 621 CloseIdleSockets();
657 } 622 }
658 623
659 void ClientSocketPoolBaseHelper::RemoveConnectJob(const ConnectJob* job, 624 void ClientSocketPoolBaseHelper::RemoveConnectJob(const ConnectJob* job,
660 Group* group) { 625 Group* group) {
661 CHECK_GT(connecting_socket_count_, 0); 626 CHECK_GT(connecting_socket_count_, 0);
662 connecting_socket_count_--; 627 connecting_socket_count_--;
663 628
664 DCHECK(group); 629 DCHECK(group);
665 DCHECK(ContainsKey(group->jobs, job)); 630 DCHECK(ContainsKey(group->jobs(), job));
666 group->jobs.erase(job); 631 group->RemoveJob(job);
667 632
668 // If we've got no more jobs for this group, then we no longer need a 633 // If we've got no more jobs for this group, then we no longer need a
669 // backup job either. 634 // backup job either.
670 if (group->jobs.empty()) 635 if (group->jobs().empty())
671 group->CleanupBackupJob(); 636 group->CleanupBackupJob();
672 637
673 DCHECK(job); 638 DCHECK(job);
674 delete job; 639 delete job;
675 } 640 }
676 641
677 void ClientSocketPoolBaseHelper::OnAvailableSocketSlot( 642 void ClientSocketPoolBaseHelper::OnAvailableSocketSlot(
678 const std::string& group_name, Group* group) { 643 const std::string& group_name, Group* group) {
679 if (!group->pending_requests.empty()) 644 if (!group->pending_requests().empty())
680 ProcessPendingRequest(group_name, group); 645 ProcessPendingRequest(group_name, group);
681 646
682 if (group->IsEmpty()) 647 if (group->IsEmpty())
683 group_map_.erase(group_name); 648 RemoveGroup(group_name);
684 } 649 }
685 650
686 void ClientSocketPoolBaseHelper::ProcessPendingRequest( 651 void ClientSocketPoolBaseHelper::ProcessPendingRequest(
687 const std::string& group_name, Group* group) { 652 const std::string& group_name, Group* group) {
688 int rv = RequestSocketInternal(group_name, 653 int rv = RequestSocketInternal(group_name,
689 *group->pending_requests.begin()); 654 *group->pending_requests().begin());
690 if (rv != ERR_IO_PENDING) { 655 if (rv != ERR_IO_PENDING) {
691 scoped_ptr<const Request> request(RemoveRequestFromQueue( 656 scoped_ptr<const Request> request(RemoveRequestFromQueue(
692 group->pending_requests.begin(), &group->pending_requests)); 657 group->mutable_pending_requests()->begin(),
658 group->mutable_pending_requests()));
693 659
694 scoped_refptr<NetLog::EventParameters> params; 660 scoped_refptr<NetLog::EventParameters> params;
695 if (rv != OK) 661 if (rv != OK)
696 params = new NetLogIntegerParameter("net_error", rv); 662 params = new NetLogIntegerParameter("net_error", rv);
697 request->net_log().EndEvent(NetLog::TYPE_SOCKET_POOL, params); 663 request->net_log().EndEvent(NetLog::TYPE_SOCKET_POOL, params);
698 InvokeUserCallbackLater( 664 InvokeUserCallbackLater(
699 request->handle(), request->callback(), rv); 665 request->handle(), request->callback(), rv);
700 } 666 }
701 } 667 }
702 668
(...skipping 15 matching lines...) Expand all
718 NetLog::TYPE_SOCKET_POOL_REUSED_AN_EXISTING_SOCKET, 684 NetLog::TYPE_SOCKET_POOL_REUSED_AN_EXISTING_SOCKET,
719 new NetLogIntegerParameter( 685 new NetLogIntegerParameter(
720 "idle_ms", static_cast<int>(idle_time.InMilliseconds()))); 686 "idle_ms", static_cast<int>(idle_time.InMilliseconds())));
721 } 687 }
722 688
723 net_log.AddEvent(NetLog::TYPE_SOCKET_POOL_BOUND_TO_SOCKET, 689 net_log.AddEvent(NetLog::TYPE_SOCKET_POOL_BOUND_TO_SOCKET,
724 new NetLogSourceParameter( 690 new NetLogSourceParameter(
725 "source_dependency", socket->NetLog().source())); 691 "source_dependency", socket->NetLog().source()));
726 692
727 handed_out_socket_count_++; 693 handed_out_socket_count_++;
728 group->active_socket_count++; 694 group->IncrementActiveSocketCount();
729 } 695 }
730 696
731 void ClientSocketPoolBaseHelper::AddIdleSocket( 697 void ClientSocketPoolBaseHelper::AddIdleSocket(
732 ClientSocket* socket, bool used, Group* group) { 698 ClientSocket* socket, bool used, Group* group) {
733 DCHECK(socket); 699 DCHECK(socket);
734 IdleSocket idle_socket; 700 IdleSocket idle_socket;
735 idle_socket.socket = socket; 701 idle_socket.socket = socket;
736 idle_socket.start_time = base::TimeTicks::Now(); 702 idle_socket.start_time = base::TimeTicks::Now();
737 idle_socket.used = used; 703 idle_socket.used = used;
738 704
739 group->idle_sockets.push_back(idle_socket); 705 group->mutable_idle_sockets()->push_back(idle_socket);
740 IncrementIdleCount(); 706 IncrementIdleCount();
741 } 707 }
742 708
743 void ClientSocketPoolBaseHelper::CancelAllConnectJobs() { 709 void ClientSocketPoolBaseHelper::CancelAllConnectJobs() {
744 for (GroupMap::iterator i = group_map_.begin(); i != group_map_.end();) { 710 for (GroupMap::iterator i = group_map_.begin(); i != group_map_.end(); ++i) {
745 Group& group = i->second; 711 Group* group = i->second;
746 connecting_socket_count_ -= group.jobs.size(); 712 connecting_socket_count_ -= group->jobs().size();
747 STLDeleteElements(&group.jobs); 713 group->RemoveAllJobs();
748
749 if (group.backup_task) {
750 group.backup_task->Cancel();
751 group.backup_task = NULL;
752 }
753 714
754 // Delete group if no longer needed. 715 // Delete group if no longer needed.
755 if (group.IsEmpty()) { 716 if (group->IsEmpty()) {
756 group_map_.erase(i++); 717 RemoveGroup(i);
757 } else {
758 ++i;
759 } 718 }
760 } 719 }
761 } 720 }
762 721
763 bool ClientSocketPoolBaseHelper::ReachedMaxSocketsLimit() const { 722 bool ClientSocketPoolBaseHelper::ReachedMaxSocketsLimit() const {
764 // Each connecting socket will eventually connect and be handed out. 723 // Each connecting socket will eventually connect and be handed out.
765 int total = handed_out_socket_count_ + connecting_socket_count_ + 724 int total = handed_out_socket_count_ + connecting_socket_count_ +
766 idle_socket_count(); 725 idle_socket_count();
767 DCHECK_LE(total, max_sockets_); 726 DCHECK_LE(total, max_sockets_);
768 if (total < max_sockets_) 727 if (total < max_sockets_)
769 return false; 728 return false;
770 LOG(WARNING) << "ReachedMaxSocketsLimit: " << total << "/" << max_sockets_; 729 LOG(WARNING) << "ReachedMaxSocketsLimit: " << total << "/" << max_sockets_;
771 return true; 730 return true;
772 } 731 }
773 732
774 void ClientSocketPoolBaseHelper::CloseOneIdleSocket() { 733 void ClientSocketPoolBaseHelper::CloseOneIdleSocket() {
775 CHECK_GT(idle_socket_count(), 0); 734 CHECK_GT(idle_socket_count(), 0);
776 735
777 for (GroupMap::iterator i = group_map_.begin(); i != group_map_.end(); ++i) { 736 for (GroupMap::iterator i = group_map_.begin(); i != group_map_.end(); ++i) {
778 Group& group = i->second; 737 Group* group = i->second;
779 738
780 if (!group.idle_sockets.empty()) { 739 if (!group->idle_sockets().empty()) {
781 std::deque<IdleSocket>::iterator j = group.idle_sockets.begin(); 740 std::deque<IdleSocket>::iterator j =
741 group->mutable_idle_sockets()->begin();
782 delete j->socket; 742 delete j->socket;
783 group.idle_sockets.erase(j); 743 group->mutable_idle_sockets()->erase(j);
784 DecrementIdleCount(); 744 DecrementIdleCount();
785 if (group.IsEmpty()) 745 if (group->IsEmpty())
786 group_map_.erase(i); 746 RemoveGroup(i);
787 747
788 return; 748 return;
789 } 749 }
790 } 750 }
791 751
792 LOG(DFATAL) << "No idle socket found to close!."; 752 LOG(DFATAL) << "No idle socket found to close!.";
793 } 753 }
794 754
795 void ClientSocketPoolBaseHelper::InvokeUserCallbackLater( 755 void ClientSocketPoolBaseHelper::InvokeUserCallbackLater(
796 ClientSocketHandle* handle, CompletionCallback* callback, int rv) { 756 ClientSocketHandle* handle, CompletionCallback* callback, int rv) {
(...skipping 15 matching lines...) Expand all
812 if (it == pending_callback_map_.end()) 772 if (it == pending_callback_map_.end())
813 return; 773 return;
814 774
815 CHECK(!handle->is_initialized()); 775 CHECK(!handle->is_initialized());
816 CompletionCallback* callback = it->second.callback; 776 CompletionCallback* callback = it->second.callback;
817 int result = it->second.result; 777 int result = it->second.result;
818 pending_callback_map_.erase(it); 778 pending_callback_map_.erase(it);
819 callback->Run(result); 779 callback->Run(result);
820 } 780 }
821 781
782 ClientSocketPoolBaseHelper::Group::Group()
783 : active_socket_count_(0),
784 ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) {}
785
786 ClientSocketPoolBaseHelper::Group::~Group() {
787 CleanupBackupJob();
788 }
789
790 void ClientSocketPoolBaseHelper::Group::StartBackupSocketTimer(
791 const std::string& group_name,
792 ClientSocketPoolBaseHelper* pool) {
793 // Only allow one timer pending to create a backup socket.
794 if (!method_factory_.empty())
795 return;
796
797 MessageLoop::current()->PostDelayedTask(
798 FROM_HERE,
799 method_factory_.NewRunnableMethod(
800 &Group::OnBackupSocketTimerFired, group_name, pool),
801 pool->ConnectRetryIntervalMs());
802 }
803
804 void ClientSocketPoolBaseHelper::Group::OnBackupSocketTimerFired(
805 std::string group_name,
806 ClientSocketPoolBaseHelper* pool) {
807 // If there are no more jobs pending, there is no work to do.
808 // If we've done our cleanups correctly, this should not happen.
809 if (jobs_.empty()) {
810 NOTREACHED();
811 return;
812 }
813
814 // If our backup job is waiting on DNS, or if we can't create any sockets
815 // right now due to limits, just reset the timer.
816 if (pool->ReachedMaxSocketsLimit() ||
817 !HasAvailableSocketSlot(pool->max_sockets_per_group_) ||
818 (*jobs_.begin())->GetLoadState() == LOAD_STATE_RESOLVING_HOST) {
819 StartBackupSocketTimer(group_name, pool);
820 return;
821 }
822
823 ConnectJob* backup_job = pool->connect_job_factory_->NewConnectJob(
824 group_name, **pending_requests_.begin(), pool);
825 backup_job->net_log().AddEvent(NetLog::TYPE_SOCKET_BACKUP_CREATED, NULL);
826 SIMPLE_STATS_COUNTER("socket.backup_created");
827 int rv = backup_job->Connect();
828 pool->connecting_socket_count_++;
829 AddJob(backup_job);
830 if (rv != ERR_IO_PENDING)
831 pool->OnConnectJobComplete(rv, backup_job);
832 }
833
834 void ClientSocketPoolBaseHelper::Group::RemoveAllJobs() {
835 // Delete active jobs.
836 STLDeleteElements(&jobs_);
837
838 // Cancel pending backup job.
839 method_factory_.RevokeAll();
840 }
841
822 } // namespace internal 842 } // namespace internal
823 843
824 } // namespace net 844 } // namespace net
OLDNEW
« no previous file with comments | « net/socket/client_socket_pool_base.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698