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

Unified 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « net/socket/client_socket_pool_base.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: net/socket/client_socket_pool_base.cc
diff --git a/net/socket/client_socket_pool_base.cc b/net/socket/client_socket_pool_base.cc
index 334a9dc454a5833770fe5a7b75452b1fc10c56ba..c239c694ecaee75c3dc79d128cc8f5a29344c385 100644
--- a/net/socket/client_socket_pool_base.cc
+++ b/net/socket/client_socket_pool_base.cc
@@ -138,7 +138,6 @@ ClientSocketPoolBaseHelper::ClientSocketPoolBaseHelper(
used_idle_socket_timeout_(used_idle_socket_timeout),
connect_job_factory_(connect_job_factory),
backup_jobs_enabled_(false),
- ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)),
pool_generation_number_(0),
in_destructor_(false) {
DCHECK_LE(0, max_sockets_per_group);
@@ -188,7 +187,7 @@ int ClientSocketPoolBaseHelper::RequestSocket(
const std::string& group_name,
const Request* request) {
request->net_log().BeginEvent(NetLog::TYPE_SOCKET_POOL, NULL);
- Group& group = group_map_[group_name];
+ Group* group = GetOrCreateGroup(group_name);
int rv = RequestSocketInternal(group_name, request);
if (rv != ERR_IO_PENDING) {
@@ -196,7 +195,7 @@ int ClientSocketPoolBaseHelper::RequestSocket(
CHECK(!request->handle()->is_initialized());
delete request;
} else {
- InsertRequestIntoQueue(request, &group.pending_requests);
+ InsertRequestIntoQueue(request, group->mutable_pending_requests());
}
return rv;
}
@@ -209,14 +208,14 @@ int ClientSocketPoolBaseHelper::RequestSocketInternal(
CHECK(callback);
ClientSocketHandle* const handle = request->handle();
CHECK(handle);
- Group& group = group_map_[group_name];
+ Group* group = GetOrCreateGroup(group_name);
// Try to reuse a socket.
- if (AssignIdleSocketToGroup(&group, request))
+ if (AssignIdleSocketToGroup(request, group))
return OK;
// Can we make another active socket now?
- if (!group.HasAvailableSocketSlot(max_sockets_per_group_)) {
+ if (!group->HasAvailableSocketSlot(max_sockets_per_group_)) {
request->net_log().AddEvent(
NetLog::TYPE_SOCKET_POOL_STALLED_MAX_SOCKETS_PER_GROUP, NULL);
return ERR_IO_PENDING;
@@ -242,31 +241,26 @@ int ClientSocketPoolBaseHelper::RequestSocketInternal(
if (rv == OK) {
LogBoundConnectJobToRequest(connect_job->net_log().source(), request);
HandOutSocket(connect_job->ReleaseSocket(), false /* not reused */,
- handle, base::TimeDelta(), &group, request->net_log());
+ handle, base::TimeDelta(), group, request->net_log());
} else if (rv == ERR_IO_PENDING) {
// If we don't have any sockets in this group, set a timer for potentially
// creating a new one. If the SYN is lost, this backup socket may complete
// before the slow socket, improving end user latency.
- if (group.IsEmpty() && !group.backup_job && backup_jobs_enabled_) {
- group.backup_job = connect_job_factory_->NewConnectJob(group_name,
- *request,
- this);
- StartBackupSocketTimer(group_name);
- }
+ if (group->IsEmpty() && !group->HasBackupJob() && backup_jobs_enabled_)
+ group->StartBackupSocketTimer(group_name, this);
connecting_socket_count_++;
- ConnectJob* job = connect_job.release();
- group.jobs.insert(job);
+ group->AddJob(connect_job.release());
} else {
LogBoundConnectJobToRequest(connect_job->net_log().source(), request);
connect_job->GetAdditionalErrorState(handle);
ClientSocket* error_socket = connect_job->ReleaseSocket();
if (error_socket) {
HandOutSocket(error_socket, false /* not reused */, handle,
- base::TimeDelta(), &group, request->net_log());
- } else if (group.IsEmpty()) {
- group_map_.erase(group_name);
+ base::TimeDelta(), group, request->net_log());
+ } else if (group->IsEmpty()) {
+ RemoveGroup(group_name);
}
}
@@ -274,12 +268,12 @@ int ClientSocketPoolBaseHelper::RequestSocketInternal(
}
bool ClientSocketPoolBaseHelper::AssignIdleSocketToGroup(
- Group* group, const Request* request) {
+ const Request* request, Group* group) {
// Iterate through the list of idle sockets until we find one or exhaust
// the list.
- while (!group->idle_sockets.empty()) {
- IdleSocket idle_socket = group->idle_sockets.back();
- group->idle_sockets.pop_back();
+ while (!group->idle_sockets().empty()) {
+ IdleSocket idle_socket = group->idle_sockets().back();
+ group->mutable_idle_sockets()->pop_back();
DecrementIdleCount();
if (idle_socket.socket->IsConnectedAndIdle()) {
// We found one we can reuse!
@@ -303,60 +297,6 @@ void ClientSocketPoolBaseHelper::LogBoundConnectJobToRequest(
new NetLogSourceParameter("source_dependency", connect_job_source));
}
-void ClientSocketPoolBaseHelper::StartBackupSocketTimer(
- const std::string& group_name) {
- CHECK(ContainsKey(group_map_, group_name));
- Group& group = group_map_[group_name];
-
- // Only allow one timer pending to create a backup socket.
- if (group.backup_task)
- return;
-
- group.backup_task = method_factory_.NewRunnableMethod(
- &ClientSocketPoolBaseHelper::OnBackupSocketTimerFired, group_name);
- MessageLoop::current()->PostDelayedTask(FROM_HERE, group.backup_task,
- ConnectRetryIntervalMs());
-}
-
-void ClientSocketPoolBaseHelper::OnBackupSocketTimerFired(
- const std::string& group_name) {
- CHECK(ContainsKey(group_map_, group_name));
-
- Group& group = group_map_[group_name];
-
- CHECK(group.backup_task);
- group.backup_task = NULL;
-
- CHECK(group.backup_job);
-
- // If there are no more jobs pending, there is no work to do.
- // If we've done our cleanups correctly, this should not happen.
- if (group.jobs.empty()) {
- NOTREACHED();
- return;
- }
-
- // If our backup job is waiting on DNS, or if we can't create any sockets
- // right now due to limits, just reset the timer.
- if (ReachedMaxSocketsLimit() ||
- !group.HasAvailableSocketSlot(max_sockets_per_group_) ||
- (*group.jobs.begin())->GetLoadState() == LOAD_STATE_RESOLVING_HOST) {
- StartBackupSocketTimer(group_name);
- return;
- }
-
- group.backup_job->net_log().AddEvent(NetLog::TYPE_SOCKET_BACKUP_CREATED,
- NULL);
- SIMPLE_STATS_COUNTER("socket.backup_created");
- int rv = group.backup_job->Connect();
- connecting_socket_count_++;
- group.jobs.insert(group.backup_job);
- ConnectJob* job = group.backup_job;
- group.backup_job = NULL;
- if (rv != ERR_IO_PENDING)
- OnConnectJobComplete(rv, job);
-}
-
void ClientSocketPoolBaseHelper::CancelRequest(
const std::string& group_name, ClientSocketHandle* handle) {
PendingCallbackMap::iterator callback_it = pending_callback_map_.find(handle);
@@ -374,20 +314,21 @@ void ClientSocketPoolBaseHelper::CancelRequest(
CHECK(ContainsKey(group_map_, group_name));
- Group& group = group_map_[group_name];
+ Group* group = GetOrCreateGroup(group_name);
// Search pending_requests for matching handle.
- RequestQueue::iterator it = group.pending_requests.begin();
- for (; it != group.pending_requests.end(); ++it) {
+ RequestQueue::iterator it = group->mutable_pending_requests()->begin();
+ for (; it != group->pending_requests().end(); ++it) {
if ((*it)->handle() == handle) {
- const Request* req = RemoveRequestFromQueue(it, &group.pending_requests);
+ const Request* req =
+ RemoveRequestFromQueue(it, group->mutable_pending_requests());
req->net_log().AddEvent(NetLog::TYPE_CANCELLED, NULL);
req->net_log().EndEvent(NetLog::TYPE_SOCKET_POOL, NULL);
delete req;
// We let the job run, unless we're at the socket limit.
- if (group.jobs.size() && ReachedMaxSocketsLimit()) {
- RemoveConnectJob(*group.jobs.begin(), &group);
+ if (group->jobs().size() && ReachedMaxSocketsLimit()) {
+ RemoveConnectJob(*group->jobs().begin(), group);
CheckForStalledSocketGroups();
}
break;
@@ -404,7 +345,7 @@ int ClientSocketPoolBaseHelper::IdleSocketCountInGroup(
GroupMap::const_iterator i = group_map_.find(group_name);
CHECK(i != group_map_.end());
- return i->second.idle_sockets.size();
+ return i->second->idle_sockets().size();
}
LoadState ClientSocketPoolBaseHelper::GetLoadState(
@@ -420,16 +361,16 @@ LoadState ClientSocketPoolBaseHelper::GetLoadState(
}
// Can't use operator[] since it is non-const.
- const Group& group = group_map_.find(group_name)->second;
+ const Group& group = *group_map_.find(group_name)->second;
// Search pending_requests for matching handle.
- RequestQueue::const_iterator it = group.pending_requests.begin();
- for (size_t i = 0; it != group.pending_requests.end(); ++it, ++i) {
+ RequestQueue::const_iterator it = group.pending_requests().begin();
+ for (size_t i = 0; it != group.pending_requests().end(); ++it, ++i) {
if ((*it)->handle() == handle) {
- if (i < group.jobs.size()) {
+ if (i < group.jobs().size()) {
LoadState max_state = LOAD_STATE_IDLE;
- for (ConnectJobSet::const_iterator job_it = group.jobs.begin();
- job_it != group.jobs.end(); ++job_it) {
+ for (ConnectJobSet::const_iterator job_it = group.jobs().begin();
+ job_it != group.jobs().end(); ++job_it) {
max_state = std::max(max_state, (*job_it)->GetLoadState());
}
return max_state;
@@ -471,15 +412,15 @@ void ClientSocketPoolBaseHelper::CleanupIdleSockets(bool force) {
GroupMap::iterator i = group_map_.begin();
while (i != group_map_.end()) {
- Group& group = i->second;
+ Group* group = i->second;
- std::deque<IdleSocket>::iterator j = group.idle_sockets.begin();
- while (j != group.idle_sockets.end()) {
+ std::deque<IdleSocket>::iterator j = group->mutable_idle_sockets()->begin();
+ while (j != group->idle_sockets().end()) {
base::TimeDelta timeout =
j->used ? used_idle_socket_timeout_ : unused_idle_socket_timeout_;
if (force || j->ShouldCleanup(now, timeout)) {
delete j->socket;
- j = group.idle_sockets.erase(j);
+ j = group->mutable_idle_sockets()->erase(j);
DecrementIdleCount();
} else {
++j;
@@ -487,14 +428,36 @@ void ClientSocketPoolBaseHelper::CleanupIdleSockets(bool force) {
}
// Delete group if no longer needed.
- if (group.IsEmpty()) {
- group_map_.erase(i++);
+ if (group->IsEmpty()) {
+ RemoveGroup(i++);
} else {
++i;
}
}
}
+ClientSocketPoolBaseHelper::Group* ClientSocketPoolBaseHelper::GetOrCreateGroup(
+ const std::string& group_name) {
+ GroupMap::iterator it = group_map_.find(group_name);
+ if (it != group_map_.end())
+ return it->second;
+ Group* group = new Group;
+ group_map_[group_name] = group;
+ return group;
+}
+
+void ClientSocketPoolBaseHelper::RemoveGroup(const std::string& group_name) {
+ GroupMap::iterator it = group_map_.find(group_name);
+ CHECK(it != group_map_.end());
+
+ RemoveGroup(it);
+}
+
+void ClientSocketPoolBaseHelper::RemoveGroup(GroupMap::iterator it) {
+ delete it->second;
+ group_map_.erase(it);
+}
+
void ClientSocketPoolBaseHelper::IncrementIdleCount() {
if (++idle_socket_count_ == 1)
timer_.Start(TimeDelta::FromSeconds(kCleanupInterval), this,
@@ -512,20 +475,20 @@ void ClientSocketPoolBaseHelper::ReleaseSocket(const std::string& group_name,
GroupMap::iterator i = group_map_.find(group_name);
CHECK(i != group_map_.end());
- Group& group = i->second;
+ Group* group = i->second;
CHECK_GT(handed_out_socket_count_, 0);
handed_out_socket_count_--;
- CHECK_GT(group.active_socket_count, 0);
- group.active_socket_count--;
+ CHECK_GT(group->active_socket_count(), 0);
+ group->DecrementActiveSocketCount();
const bool can_reuse = socket->IsConnectedAndIdle() &&
id == pool_generation_number_;
if (can_reuse) {
// Add it to the idle list.
- AddIdleSocket(socket, true /* used socket */, &group);
- OnAvailableSocketSlot(group_name, &group);
+ AddIdleSocket(socket, true /* used socket */, group);
+ OnAvailableSocketSlot(group_name, group);
} else {
delete socket;
}
@@ -568,16 +531,16 @@ bool ClientSocketPoolBaseHelper::FindTopStalledGroup(Group** group,
bool has_stalled_group = false;
for (GroupMap::iterator i = group_map_.begin();
i != group_map_.end(); ++i) {
- Group& group = i->second;
- const RequestQueue& queue = group.pending_requests;
+ Group* curr_group = i->second;
+ const RequestQueue& queue = curr_group->pending_requests();
if (queue.empty())
continue;
- if (group.IsStalled(max_sockets_per_group_)) {
+ if (curr_group->IsStalled(max_sockets_per_group_)) {
has_stalled_group = true;
bool has_higher_priority = !top_group ||
- group.TopPendingPriority() < top_group->TopPendingPriority();
+ curr_group->TopPendingPriority() < top_group->TopPendingPriority();
if (has_higher_priority) {
- top_group = &group;
+ top_group = curr_group;
top_group_name = &i->first;
}
}
@@ -596,7 +559,7 @@ void ClientSocketPoolBaseHelper::OnConnectJobComplete(
const std::string group_name = job->group_name();
GroupMap::iterator group_it = group_map_.find(group_name);
CHECK(group_it != group_map_.end());
- Group& group = group_it->second;
+ Group* group = group_it->second;
scoped_ptr<ClientSocket> socket(job->ReleaseSocket());
@@ -604,44 +567,46 @@ void ClientSocketPoolBaseHelper::OnConnectJobComplete(
if (result == OK) {
DCHECK(socket.get());
- RemoveConnectJob(job, &group);
- if (!group.pending_requests.empty()) {
+ RemoveConnectJob(job, group);
+ if (!group->pending_requests().empty()) {
scoped_ptr<const Request> r(RemoveRequestFromQueue(
- group.pending_requests.begin(), &group.pending_requests));
+ group->mutable_pending_requests()->begin(),
+ group->mutable_pending_requests()));
LogBoundConnectJobToRequest(job_log.source(), r.get());
HandOutSocket(
socket.release(), false /* unused socket */, r->handle(),
- base::TimeDelta(), &group, r->net_log());
+ base::TimeDelta(), group, r->net_log());
r->net_log().EndEvent(NetLog::TYPE_SOCKET_POOL, NULL);
InvokeUserCallbackLater(r->handle(), r->callback(), result);
} else {
- AddIdleSocket(socket.release(), false /* unused socket */, &group);
- OnAvailableSocketSlot(group_name, &group);
+ AddIdleSocket(socket.release(), false /* unused socket */, group);
+ OnAvailableSocketSlot(group_name, group);
CheckForStalledSocketGroups();
}
} else {
// If we got a socket, it must contain error information so pass that
// up so that the caller can retrieve it.
bool handed_out_socket = false;
- if (!group.pending_requests.empty()) {
+ if (!group->pending_requests().empty()) {
scoped_ptr<const Request> r(RemoveRequestFromQueue(
- group.pending_requests.begin(), &group.pending_requests));
+ group->mutable_pending_requests()->begin(),
+ group->mutable_pending_requests()));
LogBoundConnectJobToRequest(job_log.source(), r.get());
job->GetAdditionalErrorState(r->handle());
- RemoveConnectJob(job, &group);
+ RemoveConnectJob(job, group);
if (socket.get()) {
handed_out_socket = true;
HandOutSocket(socket.release(), false /* unused socket */, r->handle(),
- base::TimeDelta(), &group, r->net_log());
+ base::TimeDelta(), group, r->net_log());
}
r->net_log().EndEvent(NetLog::TYPE_SOCKET_POOL,
new NetLogIntegerParameter("net_error", result));
InvokeUserCallbackLater(r->handle(), r->callback(), result);
} else {
- RemoveConnectJob(job, &group);
+ RemoveConnectJob(job, group);
}
if (!handed_out_socket) {
- OnAvailableSocketSlot(group_name, &group);
+ OnAvailableSocketSlot(group_name, group);
CheckForStalledSocketGroups();
}
}
@@ -662,12 +627,12 @@ void ClientSocketPoolBaseHelper::RemoveConnectJob(const ConnectJob* job,
connecting_socket_count_--;
DCHECK(group);
- DCHECK(ContainsKey(group->jobs, job));
- group->jobs.erase(job);
+ DCHECK(ContainsKey(group->jobs(), job));
+ group->RemoveJob(job);
// If we've got no more jobs for this group, then we no longer need a
// backup job either.
- if (group->jobs.empty())
+ if (group->jobs().empty())
group->CleanupBackupJob();
DCHECK(job);
@@ -676,20 +641,21 @@ void ClientSocketPoolBaseHelper::RemoveConnectJob(const ConnectJob* job,
void ClientSocketPoolBaseHelper::OnAvailableSocketSlot(
const std::string& group_name, Group* group) {
- if (!group->pending_requests.empty())
+ if (!group->pending_requests().empty())
ProcessPendingRequest(group_name, group);
if (group->IsEmpty())
- group_map_.erase(group_name);
+ RemoveGroup(group_name);
}
void ClientSocketPoolBaseHelper::ProcessPendingRequest(
const std::string& group_name, Group* group) {
int rv = RequestSocketInternal(group_name,
- *group->pending_requests.begin());
+ *group->pending_requests().begin());
if (rv != ERR_IO_PENDING) {
scoped_ptr<const Request> request(RemoveRequestFromQueue(
- group->pending_requests.begin(), &group->pending_requests));
+ group->mutable_pending_requests()->begin(),
+ group->mutable_pending_requests()));
scoped_refptr<NetLog::EventParameters> params;
if (rv != OK)
@@ -725,7 +691,7 @@ void ClientSocketPoolBaseHelper::HandOutSocket(
"source_dependency", socket->NetLog().source()));
handed_out_socket_count_++;
- group->active_socket_count++;
+ group->IncrementActiveSocketCount();
}
void ClientSocketPoolBaseHelper::AddIdleSocket(
@@ -736,26 +702,19 @@ void ClientSocketPoolBaseHelper::AddIdleSocket(
idle_socket.start_time = base::TimeTicks::Now();
idle_socket.used = used;
- group->idle_sockets.push_back(idle_socket);
+ group->mutable_idle_sockets()->push_back(idle_socket);
IncrementIdleCount();
}
void ClientSocketPoolBaseHelper::CancelAllConnectJobs() {
- for (GroupMap::iterator i = group_map_.begin(); i != group_map_.end();) {
- Group& group = i->second;
- connecting_socket_count_ -= group.jobs.size();
- STLDeleteElements(&group.jobs);
-
- if (group.backup_task) {
- group.backup_task->Cancel();
- group.backup_task = NULL;
- }
+ for (GroupMap::iterator i = group_map_.begin(); i != group_map_.end(); ++i) {
+ Group* group = i->second;
+ connecting_socket_count_ -= group->jobs().size();
+ group->RemoveAllJobs();
// Delete group if no longer needed.
- if (group.IsEmpty()) {
- group_map_.erase(i++);
- } else {
- ++i;
+ if (group->IsEmpty()) {
+ RemoveGroup(i);
}
}
}
@@ -775,15 +734,16 @@ void ClientSocketPoolBaseHelper::CloseOneIdleSocket() {
CHECK_GT(idle_socket_count(), 0);
for (GroupMap::iterator i = group_map_.begin(); i != group_map_.end(); ++i) {
- Group& group = i->second;
+ Group* group = i->second;
- if (!group.idle_sockets.empty()) {
- std::deque<IdleSocket>::iterator j = group.idle_sockets.begin();
+ if (!group->idle_sockets().empty()) {
+ std::deque<IdleSocket>::iterator j =
+ group->mutable_idle_sockets()->begin();
delete j->socket;
- group.idle_sockets.erase(j);
+ group->mutable_idle_sockets()->erase(j);
DecrementIdleCount();
- if (group.IsEmpty())
- group_map_.erase(i);
+ if (group->IsEmpty())
+ RemoveGroup(i);
return;
}
@@ -819,6 +779,66 @@ void ClientSocketPoolBaseHelper::InvokeUserCallback(
callback->Run(result);
}
+ClientSocketPoolBaseHelper::Group::Group()
+ : active_socket_count_(0),
+ ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) {}
+
+ClientSocketPoolBaseHelper::Group::~Group() {
+ CleanupBackupJob();
+}
+
+void ClientSocketPoolBaseHelper::Group::StartBackupSocketTimer(
+ const std::string& group_name,
+ ClientSocketPoolBaseHelper* pool) {
+ // Only allow one timer pending to create a backup socket.
+ if (!method_factory_.empty())
+ return;
+
+ MessageLoop::current()->PostDelayedTask(
+ FROM_HERE,
+ method_factory_.NewRunnableMethod(
+ &Group::OnBackupSocketTimerFired, group_name, pool),
+ pool->ConnectRetryIntervalMs());
+}
+
+void ClientSocketPoolBaseHelper::Group::OnBackupSocketTimerFired(
+ std::string group_name,
+ ClientSocketPoolBaseHelper* pool) {
+ // If there are no more jobs pending, there is no work to do.
+ // If we've done our cleanups correctly, this should not happen.
+ if (jobs_.empty()) {
+ NOTREACHED();
+ return;
+ }
+
+ // If our backup job is waiting on DNS, or if we can't create any sockets
+ // right now due to limits, just reset the timer.
+ if (pool->ReachedMaxSocketsLimit() ||
+ !HasAvailableSocketSlot(pool->max_sockets_per_group_) ||
+ (*jobs_.begin())->GetLoadState() == LOAD_STATE_RESOLVING_HOST) {
+ StartBackupSocketTimer(group_name, pool);
+ return;
+ }
+
+ ConnectJob* backup_job = pool->connect_job_factory_->NewConnectJob(
+ group_name, **pending_requests_.begin(), pool);
+ backup_job->net_log().AddEvent(NetLog::TYPE_SOCKET_BACKUP_CREATED, NULL);
+ SIMPLE_STATS_COUNTER("socket.backup_created");
+ int rv = backup_job->Connect();
+ pool->connecting_socket_count_++;
+ AddJob(backup_job);
+ if (rv != ERR_IO_PENDING)
+ pool->OnConnectJobComplete(rv, backup_job);
+}
+
+void ClientSocketPoolBaseHelper::Group::RemoveAllJobs() {
+ // Delete active jobs.
+ STLDeleteElements(&jobs_);
+
+ // Cancel pending backup job.
+ method_factory_.RevokeAll();
+}
+
} // namespace internal
} // namespace net
« 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