| Index: net/base/client_socket_pool.cc
|
| ===================================================================
|
| --- net/base/client_socket_pool.cc (revision 14127)
|
| +++ net/base/client_socket_pool.cc (working copy)
|
| @@ -28,9 +28,13 @@
|
|
|
| namespace net {
|
|
|
| -ClientSocketPool::ClientSocketPool(int max_sockets_per_group)
|
| +ClientSocketPool::ClientSocketPool(int max_sockets_per_group, int max_sockets)
|
| : idle_socket_count_(0),
|
| - max_sockets_per_group_(max_sockets_per_group) {
|
| + active_socket_count_(0),
|
| + max_sockets_per_group_(max_sockets_per_group),
|
| + max_sockets_(max_sockets),
|
| + may_have_stalled_group_(false) {
|
| + DCHECK(max_sockets_per_group <= max_sockets);
|
| }
|
|
|
| ClientSocketPool::~ClientSocketPool() {
|
| @@ -60,7 +64,9 @@
|
| Group& group = group_map_[handle->group_name_];
|
|
|
| // Can we make another active socket now?
|
| - if (group.active_socket_count == max_sockets_per_group_) {
|
| + bool has_max_sockets = (active_socket_count_ == max_sockets_);
|
| + if (group.active_socket_count == max_sockets_per_group_ || has_max_sockets) {
|
| + may_have_stalled_group_ |= has_max_sockets;
|
| Request r;
|
| r.handle = handle;
|
| DCHECK(callback);
|
| @@ -72,6 +78,7 @@
|
|
|
| // OK, we are going to activate one.
|
| group.active_socket_count++;
|
| + active_socket_count_++;
|
|
|
| // Use idle sockets in LIFO order because they're more likely to be
|
| // still reusable.
|
| @@ -92,13 +99,10 @@
|
| }
|
|
|
| void ClientSocketPool::CancelRequest(ClientSocketHandle* handle) {
|
| - Group& group = group_map_[handle->group_name_];
|
| + GroupMap::iterator i = group_map_.find(handle->group_name_);
|
| + DCHECK(i != group_map_.end());
|
| + Group& group = i->second;
|
|
|
| - // In order for us to be canceling a pending request, we must have active
|
| - // sockets equaling the limit. NOTE: The correctness of the code doesn't
|
| - // require this assertion.
|
| - DCHECK(group.active_socket_count == max_sockets_per_group_);
|
| -
|
| // Search pending_requests for matching handle.
|
| std::deque<Request>::iterator it = group.pending_requests.begin();
|
| for (; it != group.pending_requests.end(); ++it) {
|
| @@ -107,6 +111,10 @@
|
| break;
|
| }
|
| }
|
| +
|
| + // Delete group if no longer needed.
|
| + if (group.empty())
|
| + group_map_.erase(i);
|
| }
|
|
|
| void ClientSocketPool::ReleaseSocket(ClientSocketHandle* handle) {
|
| @@ -152,8 +160,7 @@
|
| }
|
|
|
| // Delete group if no longer needed.
|
| - if (group.active_socket_count == 0 && group.idle_sockets.empty()) {
|
| - DCHECK(group.pending_requests.empty());
|
| + if (group.empty()) {
|
| group_map_.erase(i++);
|
| } else {
|
| ++i;
|
| @@ -180,7 +187,10 @@
|
| Group& group = i->second;
|
|
|
| DCHECK(group.active_socket_count > 0);
|
| + DCHECK(active_socket_count_ > 0);
|
| +
|
| group.active_socket_count--;
|
| + active_socket_count_--;
|
|
|
| bool can_reuse = ptr->get() && (*ptr)->IsConnectedAndIdle();
|
| if (can_reuse) {
|
| @@ -195,20 +205,50 @@
|
| }
|
|
|
| // Process one pending request.
|
| - if (!group.pending_requests.empty()) {
|
| - Request r = group.pending_requests.front();
|
| - group.pending_requests.pop_front();
|
| - int rv = RequestSocket(r.handle, r.priority, NULL);
|
| - DCHECK(rv == OK);
|
| - r.callback->Run(rv);
|
| - return;
|
| + if (may_have_stalled_group_) {
|
| + // The highest priority pending request may belong to another group, so
|
| + // check all of them. Worst-case this takes |max_sockets_| iterations.
|
| + if (Group* top_group = FindTopStalledGroup())
|
| + StartPendingRequestForGroup(top_group);
|
| +
|
| + // Check if there are any stalled groups left.
|
| + if (!FindTopStalledGroup())
|
| + may_have_stalled_group_ = false;
|
| +
|
| + } else if (!group.pending_requests.empty()) {
|
| + // Otherwise just dequeue the first pending request of |group|.
|
| + StartPendingRequestForGroup(&group);
|
| }
|
|
|
| // Delete group if no longer needed.
|
| - if (group.active_socket_count == 0 && group.idle_sockets.empty()) {
|
| - DCHECK(group.pending_requests.empty());
|
| + if (group.empty())
|
| group_map_.erase(i);
|
| +}
|
| +
|
| +void ClientSocketPool::StartPendingRequestForGroup(Group* group) {
|
| + Request r = group->pending_requests.front();
|
| + group->pending_requests.pop_front();
|
| + int rv = RequestSocket(r.handle, r.priority, NULL);
|
| + DCHECK(rv == OK);
|
| + r.callback->Run(rv);
|
| +}
|
| +
|
| +// Search for the highest priority pending request, amongst the groups that
|
| +// are not at the |max_sockets_per_group_| limit. Note: for requests with
|
| +// the same priority, the winner is based on group hash ordering (and not
|
| +// insertion order).
|
| +ClientSocketPool::Group* ClientSocketPool::FindTopStalledGroup() {
|
| + Group* top_group = NULL;
|
| + for (GroupMap::iterator i = group_map_.begin(); i != group_map_.end(); ++i) {
|
| + Group* group = &i->second;
|
| + const RequestQueue& queue = group->pending_requests;
|
| + if (group->active_socket_count < max_sockets_per_group_ &&
|
| + !queue.empty() && (top_group == NULL || queue.front().priority >
|
| + top_group->pending_requests.front().priority)) {
|
| + top_group = group;
|
| + }
|
| }
|
| + return top_group;
|
| }
|
|
|
| } // namespace net
|
|
|