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

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

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