Revert 57100 - Only create the backup ConnectJob when it is needed.
This reduces the unnecessary NetLog spam, since we would log to the NetLog everytime we created the backup ConnectJob, even though we usually wouldn't actually call Connect() on it. Now, we only create the backup ConnectJob when we intend to call Connect() on it.
Includes some various cleanup necessary for this:
* struct Group => class Group
* method_factory moves from CSP to Group
Review URL: http://codereview.chromium.org/3171017
[email protected]
Review URL: http://codereview.chromium.org/3198009
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@57107 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/net/socket/client_socket_pool_base.cc b/net/socket/client_socket_pool_base.cc
index c239c69..334a9dc 100644
--- a/net/socket/client_socket_pool_base.cc
+++ b/net/socket/client_socket_pool_base.cc
@@ -138,6 +138,7 @@
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);
@@ -187,7 +188,7 @@
const std::string& group_name,
const Request* request) {
request->net_log().BeginEvent(NetLog::TYPE_SOCKET_POOL, NULL);
- Group* group = GetOrCreateGroup(group_name);
+ Group& group = group_map_[group_name];
int rv = RequestSocketInternal(group_name, request);
if (rv != ERR_IO_PENDING) {
@@ -195,7 +196,7 @@
CHECK(!request->handle()->is_initialized());
delete request;
} else {
- InsertRequestIntoQueue(request, group->mutable_pending_requests());
+ InsertRequestIntoQueue(request, &group.pending_requests);
}
return rv;
}
@@ -208,14 +209,14 @@
CHECK(callback);
ClientSocketHandle* const handle = request->handle();
CHECK(handle);
- Group* group = GetOrCreateGroup(group_name);
+ Group& group = group_map_[group_name];
// Try to reuse a socket.
- if (AssignIdleSocketToGroup(request, group))
+ if (AssignIdleSocketToGroup(&group, request))
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;
@@ -241,26 +242,31 @@
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->HasBackupJob() && backup_jobs_enabled_)
- group->StartBackupSocketTimer(group_name, this);
+ if (group.IsEmpty() && !group.backup_job && backup_jobs_enabled_) {
+ group.backup_job = connect_job_factory_->NewConnectJob(group_name,
+ *request,
+ this);
+ StartBackupSocketTimer(group_name);
+ }
connecting_socket_count_++;
- group->AddJob(connect_job.release());
+ ConnectJob* job = connect_job.release();
+ group.jobs.insert(job);
} 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()) {
- RemoveGroup(group_name);
+ base::TimeDelta(), &group, request->net_log());
+ } else if (group.IsEmpty()) {
+ group_map_.erase(group_name);
}
}
@@ -268,12 +274,12 @@
}
bool ClientSocketPoolBaseHelper::AssignIdleSocketToGroup(
- const Request* request, Group* group) {
+ Group* group, const Request* request) {
// 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->mutable_idle_sockets()->pop_back();
+ while (!group->idle_sockets.empty()) {
+ IdleSocket idle_socket = group->idle_sockets.back();
+ group->idle_sockets.pop_back();
DecrementIdleCount();
if (idle_socket.socket->IsConnectedAndIdle()) {
// We found one we can reuse!
@@ -297,6 +303,60 @@
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);
@@ -314,21 +374,20 @@
CHECK(ContainsKey(group_map_, group_name));
- Group* group = GetOrCreateGroup(group_name);
+ Group& group = group_map_[group_name];
// Search pending_requests for matching handle.
- RequestQueue::iterator it = group->mutable_pending_requests()->begin();
- for (; it != group->pending_requests().end(); ++it) {
+ RequestQueue::iterator it = group.pending_requests.begin();
+ for (; it != group.pending_requests.end(); ++it) {
if ((*it)->handle() == handle) {
- const Request* req =
- RemoveRequestFromQueue(it, group->mutable_pending_requests());
+ const Request* req = RemoveRequestFromQueue(it, &group.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;
@@ -345,7 +404,7 @@
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(
@@ -361,16 +420,16 @@
}
// 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;
@@ -412,15 +471,15 @@
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->mutable_idle_sockets()->begin();
- while (j != group->idle_sockets().end()) {
+ std::deque<IdleSocket>::iterator j = group.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->mutable_idle_sockets()->erase(j);
+ j = group.idle_sockets.erase(j);
DecrementIdleCount();
} else {
++j;
@@ -428,36 +487,14 @@
}
// Delete group if no longer needed.
- if (group->IsEmpty()) {
- RemoveGroup(i++);
+ if (group.IsEmpty()) {
+ group_map_.erase(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,
@@ -475,20 +512,20 @@
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->DecrementActiveSocketCount();
+ CHECK_GT(group.active_socket_count, 0);
+ group.active_socket_count--;
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;
}
@@ -531,16 +568,16 @@
bool has_stalled_group = false;
for (GroupMap::iterator i = group_map_.begin();
i != group_map_.end(); ++i) {
- Group* curr_group = i->second;
- const RequestQueue& queue = curr_group->pending_requests();
+ Group& group = i->second;
+ const RequestQueue& queue = group.pending_requests;
if (queue.empty())
continue;
- if (curr_group->IsStalled(max_sockets_per_group_)) {
+ if (group.IsStalled(max_sockets_per_group_)) {
has_stalled_group = true;
bool has_higher_priority = !top_group ||
- curr_group->TopPendingPriority() < top_group->TopPendingPriority();
+ group.TopPendingPriority() < top_group->TopPendingPriority();
if (has_higher_priority) {
- top_group = curr_group;
+ top_group = &group;
top_group_name = &i->first;
}
}
@@ -559,7 +596,7 @@
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());
@@ -567,46 +604,44 @@
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->mutable_pending_requests()->begin(),
- group->mutable_pending_requests()));
+ group.pending_requests.begin(), &group.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->mutable_pending_requests()->begin(),
- group->mutable_pending_requests()));
+ group.pending_requests.begin(), &group.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();
}
}
@@ -627,12 +662,12 @@
connecting_socket_count_--;
DCHECK(group);
- DCHECK(ContainsKey(group->jobs(), job));
- group->RemoveJob(job);
+ DCHECK(ContainsKey(group->jobs, job));
+ group->jobs.erase(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);
@@ -641,21 +676,20 @@
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())
- RemoveGroup(group_name);
+ group_map_.erase(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->mutable_pending_requests()->begin(),
- group->mutable_pending_requests()));
+ group->pending_requests.begin(), &group->pending_requests));
scoped_refptr<NetLog::EventParameters> params;
if (rv != OK)
@@ -691,7 +725,7 @@
"source_dependency", socket->NetLog().source()));
handed_out_socket_count_++;
- group->IncrementActiveSocketCount();
+ group->active_socket_count++;
}
void ClientSocketPoolBaseHelper::AddIdleSocket(
@@ -702,19 +736,26 @@
idle_socket.start_time = base::TimeTicks::Now();
idle_socket.used = used;
- group->mutable_idle_sockets()->push_back(idle_socket);
+ group->idle_sockets.push_back(idle_socket);
IncrementIdleCount();
}
void ClientSocketPoolBaseHelper::CancelAllConnectJobs() {
- for (GroupMap::iterator i = group_map_.begin(); i != group_map_.end(); ++i) {
- Group* group = i->second;
- connecting_socket_count_ -= group->jobs().size();
- group->RemoveAllJobs();
+ 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;
+ }
// Delete group if no longer needed.
- if (group->IsEmpty()) {
- RemoveGroup(i);
+ if (group.IsEmpty()) {
+ group_map_.erase(i++);
+ } else {
+ ++i;
}
}
}
@@ -734,16 +775,15 @@
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->mutable_idle_sockets()->begin();
+ if (!group.idle_sockets.empty()) {
+ std::deque<IdleSocket>::iterator j = group.idle_sockets.begin();
delete j->socket;
- group->mutable_idle_sockets()->erase(j);
+ group.idle_sockets.erase(j);
DecrementIdleCount();
- if (group->IsEmpty())
- RemoveGroup(i);
+ if (group.IsEmpty())
+ group_map_.erase(i);
return;
}
@@ -779,66 +819,6 @@
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