| Index: net/base/client_socket_pool.cc
|
| diff --git a/net/base/client_socket_pool.cc b/net/base/client_socket_pool.cc
|
| index 9f14fe76d06f6d86fbcd6dea42b9899a2e844d3e..4171b0c3d07de2d76f4819675ec0c00cf7bf5a2a 100644
|
| --- a/net/base/client_socket_pool.cc
|
| +++ b/net/base/client_socket_pool.cc
|
| @@ -4,16 +4,10 @@
|
|
|
| #include "net/base/client_socket_pool.h"
|
|
|
| -#include "base/compiler_specific.h"
|
| -#include "base/field_trial.h"
|
| #include "base/message_loop.h"
|
| -#include "base/time.h"
|
| -#include "base/stl_util-inl.h"
|
| -#include "net/base/client_socket_factory.h"
|
| +#include "net/base/client_socket.h"
|
| #include "net/base/client_socket_handle.h"
|
| -#include "net/base/dns_resolution_observer.h"
|
| #include "net/base/net_errors.h"
|
| -#include "net/base/tcp_client_socket.h"
|
|
|
| using base::TimeDelta;
|
|
|
| @@ -34,123 +28,8 @@ const int kIdleTimeout = 300; // 5 minutes.
|
|
|
| namespace net {
|
|
|
| -ClientSocketPool::ConnectingSocket::ConnectingSocket(
|
| - const std::string& group_name,
|
| - const ClientSocketHandle* handle,
|
| - ClientSocketFactory* client_socket_factory,
|
| - ClientSocketPool* pool)
|
| - : group_name_(group_name),
|
| - handle_(handle),
|
| - client_socket_factory_(client_socket_factory),
|
| - ALLOW_THIS_IN_INITIALIZER_LIST(
|
| - callback_(this,
|
| - &ClientSocketPool::ConnectingSocket::OnIOComplete)),
|
| - pool_(pool) {}
|
| -
|
| -ClientSocketPool::ConnectingSocket::~ConnectingSocket() {}
|
| -
|
| -int ClientSocketPool::ConnectingSocket::Connect(
|
| - const std::string& host,
|
| - int port,
|
| - CompletionCallback* callback) {
|
| - DidStartDnsResolution(host, this);
|
| - int rv = resolver_.Resolve(host, port, &addresses_, &callback_);
|
| - if (rv == OK) {
|
| - // TODO(willchan): This code is broken. It should be fixed, but the code
|
| - // path is impossible in the current implementation since the host resolver
|
| - // always dumps the request to a worker pool, so it cannot complete
|
| - // synchronously.
|
| - connect_start_time_ = base::Time::Now();
|
| - rv = socket_->Connect(&callback_);
|
| - }
|
| - return rv;
|
| -}
|
| -
|
| -ClientSocket* ClientSocketPool::ConnectingSocket::ReleaseSocket() {
|
| - return socket_.release();
|
| -}
|
| -
|
| -void ClientSocketPool::ConnectingSocket::OnIOComplete(int result) {
|
| - DCHECK_NE(result, ERR_IO_PENDING);
|
| -
|
| - GroupMap::iterator group_it = pool_->group_map_.find(group_name_);
|
| - if (group_it == pool_->group_map_.end()) {
|
| - // The request corresponding to this ConnectingSocket has been canceled.
|
| - // Stop bothering with it.
|
| - delete this;
|
| - return;
|
| - }
|
| -
|
| - Group& group = group_it->second;
|
| -
|
| - RequestMap* request_map = &group.connecting_requests;
|
| - RequestMap::iterator it = request_map->find(handle_);
|
| - if (it == request_map->end()) {
|
| - // The request corresponding to this ConnectingSocket has been canceled.
|
| - // Stop bothering with it.
|
| - group.active_socket_count--;
|
| -
|
| - // Delete group if no longer needed.
|
| - if (group.active_socket_count == 0 && group.idle_sockets.empty()) {
|
| - DCHECK(group.pending_requests.empty());
|
| - DCHECK(group.connecting_requests.empty());
|
| - pool_->group_map_.erase(group_it);
|
| - }
|
| - delete this;
|
| - return;
|
| - }
|
| -
|
| - if (result == OK) {
|
| - if (it->second.load_state == LOAD_STATE_RESOLVING_HOST) {
|
| - it->second.load_state = LOAD_STATE_CONNECTING;
|
| - socket_.reset(client_socket_factory_->CreateTCPClientSocket(addresses_));
|
| - connect_start_time_ = base::Time::Now();
|
| - result = socket_->Connect(&callback_);
|
| - if (result == ERR_IO_PENDING)
|
| - return;
|
| - } else {
|
| - DCHECK(connect_start_time_ != base::Time());
|
| - base::TimeDelta connect_duration =
|
| - base::Time::Now() - connect_start_time_;
|
| -
|
| - UMA_HISTOGRAM_CLIPPED_TIMES(
|
| - FieldTrial::MakeName(
|
| - "Net.TCP_Connection_Latency", "DnsImpact").data(),
|
| - connect_duration,
|
| - base::TimeDelta::FromMilliseconds(1),
|
| - base::TimeDelta::FromMinutes(10),
|
| - 100);
|
| - }
|
| - }
|
| -
|
| - // Now, we either succeeded at Connect()'ing, or we failed at host resolution
|
| - // or Connect()'ing. Either way, we'll run the callback to alert the client.
|
| -
|
| - Request request = it->second;
|
| - request_map->erase(it);
|
| -
|
| - if (result == OK) {
|
| - request.handle->set_socket(socket_.release());
|
| - request.handle->set_is_reused(false);
|
| - } else {
|
| - group.active_socket_count--;
|
| -
|
| - // Delete group if no longer needed.
|
| - if (group.active_socket_count == 0 && group.idle_sockets.empty()) {
|
| - DCHECK(group.pending_requests.empty());
|
| - DCHECK(group.connecting_requests.empty());
|
| - pool_->group_map_.erase(group_it);
|
| - }
|
| - }
|
| -
|
| - request.callback->Run(result);
|
| - delete this;
|
| -}
|
| -
|
| -ClientSocketPool::ClientSocketPool(int max_sockets_per_group,
|
| - ClientSocketFactory* client_socket_factory)
|
| - : client_socket_factory_(client_socket_factory),
|
| - idle_socket_count_(0),
|
| +ClientSocketPool::ClientSocketPool(int max_sockets_per_group)
|
| + : idle_socket_count_(0),
|
| max_sockets_per_group_(max_sockets_per_group) {
|
| }
|
|
|
| @@ -175,15 +54,10 @@ void ClientSocketPool::InsertRequestIntoQueue(const Request& r,
|
| pending_requests->insert(it, r);
|
| }
|
|
|
| -int ClientSocketPool::RequestSocket(const std::string& group_name,
|
| - const std::string& host,
|
| - int port,
|
| +int ClientSocketPool::RequestSocket(ClientSocketHandle* handle,
|
| int priority,
|
| - ClientSocketHandle* handle,
|
| CompletionCallback* callback) {
|
| - DCHECK(!host.empty());
|
| - DCHECK_GE(priority, 0);
|
| - Group& group = group_map_[group_name];
|
| + Group& group = group_map_[handle->group_name_];
|
|
|
| // Can we make another active socket now?
|
| if (group.active_socket_count == max_sockets_per_group_) {
|
| @@ -192,9 +66,6 @@ int ClientSocketPool::RequestSocket(const std::string& group_name,
|
| DCHECK(callback);
|
| r.callback = callback;
|
| r.priority = priority;
|
| - r.host = host;
|
| - r.port = port;
|
| - r.load_state = LOAD_STATE_IDLE;
|
| InsertRequestIntoQueue(r, &group.pending_requests);
|
| return ERR_IO_PENDING;
|
| }
|
| @@ -202,91 +73,49 @@ int ClientSocketPool::RequestSocket(const std::string& group_name,
|
| // OK, we are going to activate one.
|
| group.active_socket_count++;
|
|
|
| + // Use idle sockets in LIFO order because they're more likely to be
|
| + // still reusable.
|
| while (!group.idle_sockets.empty()) {
|
| IdleSocket idle_socket = group.idle_sockets.back();
|
| group.idle_sockets.pop_back();
|
| DecrementIdleCount();
|
| - if (idle_socket.socket->IsConnectedAndIdle()) {
|
| + if ((*idle_socket.ptr)->IsConnectedAndIdle()) {
|
| // We found one we can reuse!
|
| - handle->set_socket(idle_socket.socket);
|
| - handle->set_is_reused(true);
|
| + handle->socket_ = idle_socket.ptr;
|
| return OK;
|
| }
|
| - delete idle_socket.socket;
|
| + delete idle_socket.ptr;
|
| }
|
|
|
| - // We couldn't find a socket to reuse, so allocate and connect a new one.
|
| - scoped_ptr<ConnectingSocket> connecting_socket(
|
| - new ConnectingSocket(group_name, handle, client_socket_factory_, this));
|
| - int rv = connecting_socket->Connect(host, port, callback);
|
| - if (rv == OK) {
|
| - handle->set_socket(connecting_socket->ReleaseSocket());
|
| - handle->set_is_reused(false);
|
| - } else if (rv == ERR_IO_PENDING) {
|
| - // The ConnectingSocket will delete itself.
|
| - connecting_socket.release();
|
| - Request r;
|
| - r.handle = handle;
|
| - DCHECK(callback);
|
| - r.callback = callback;
|
| - r.priority = priority;
|
| - r.host = host;
|
| - r.port = port;
|
| - r.load_state = LOAD_STATE_RESOLVING_HOST;
|
| - group_map_[group_name].connecting_requests[handle] = r;
|
| - } else {
|
| - group.active_socket_count--;
|
| -
|
| - // Delete group if no longer needed.
|
| - if (group.active_socket_count == 0 && group.idle_sockets.empty()) {
|
| - DCHECK(group.pending_requests.empty());
|
| - DCHECK(group.connecting_requests.empty());
|
| - group_map_.erase(group_name);
|
| - }
|
| - }
|
| -
|
| - return rv;
|
| + handle->socket_ = new ClientSocketPtr();
|
| + return OK;
|
| }
|
|
|
| -void ClientSocketPool::CancelRequest(const std::string& group_name,
|
| - const ClientSocketHandle* handle) {
|
| - DCHECK(ContainsKey(group_map_, group_name));
|
| +void ClientSocketPool::CancelRequest(ClientSocketHandle* handle) {
|
| + Group& group = group_map_[handle->group_name_];
|
|
|
| - Group& group = group_map_[group_name];
|
| + // 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.
|
| - RequestQueue::iterator it = group.pending_requests.begin();
|
| + std::deque<Request>::iterator it = group.pending_requests.begin();
|
| for (; it != group.pending_requests.end(); ++it) {
|
| if (it->handle == handle) {
|
| group.pending_requests.erase(it);
|
| - return;
|
| - }
|
| - }
|
| -
|
| - // It's invalid to cancel a non-existent request.
|
| - DCHECK(ContainsKey(group.connecting_requests, handle));
|
| -
|
| - RequestMap::iterator map_it = group.connecting_requests.find(handle);
|
| - if (map_it != group.connecting_requests.end()) {
|
| - group.connecting_requests.erase(map_it);
|
| - group.active_socket_count--;
|
| -
|
| - // Delete group if no longer needed.
|
| - if (group.active_socket_count == 0 && group.idle_sockets.empty()) {
|
| - DCHECK(group.pending_requests.empty());
|
| - DCHECK(group.connecting_requests.empty());
|
| - group_map_.erase(group_name);
|
| + break;
|
| }
|
| }
|
| }
|
|
|
| -void ClientSocketPool::ReleaseSocket(const std::string& group_name,
|
| - ClientSocket* socket) {
|
| +void ClientSocketPool::ReleaseSocket(ClientSocketHandle* handle) {
|
| // Run this asynchronously to allow the caller to finish before we let
|
| // another to begin doing work. This also avoids nasty recursion issues.
|
| // NOTE: We cannot refer to the handle argument after this method returns.
|
| MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
|
| - this, &ClientSocketPool::DoReleaseSocket, group_name, socket));
|
| + this, &ClientSocketPool::DoReleaseSocket, handle->group_name_,
|
| + handle->socket_));
|
| }
|
|
|
| void ClientSocketPool::CloseIdleSockets() {
|
| @@ -301,42 +130,10 @@ int ClientSocketPool::IdleSocketCountInGroup(
|
| return i->second.idle_sockets.size();
|
| }
|
|
|
| -LoadState ClientSocketPool::GetLoadState(
|
| - const std::string& group_name,
|
| - const ClientSocketHandle* handle) const {
|
| - DCHECK(ContainsKey(group_map_, group_name)) << group_name;
|
| -
|
| - // Can't use operator[] since it is non-const.
|
| - const Group& group = group_map_.find(group_name)->second;
|
| -
|
| - // Search connecting_requests for matching handle.
|
| - RequestMap::const_iterator map_it = group.connecting_requests.find(handle);
|
| - if (map_it != group.connecting_requests.end()) {
|
| - const LoadState load_state = map_it->second.load_state;
|
| - DCHECK(load_state == LOAD_STATE_RESOLVING_HOST ||
|
| - load_state == LOAD_STATE_CONNECTING);
|
| - return load_state;
|
| - }
|
| -
|
| - // Search pending_requests for matching handle.
|
| - RequestQueue::const_iterator it = group.pending_requests.begin();
|
| - for (; it != group.pending_requests.end(); ++it) {
|
| - if (it->handle == handle) {
|
| - DCHECK_EQ(LOAD_STATE_IDLE, it->load_state);
|
| - // TODO(wtc): Add a state for being on the wait list.
|
| - // See http://www.crbug.com/5077.
|
| - return LOAD_STATE_IDLE;
|
| - }
|
| - }
|
| -
|
| - NOTREACHED();
|
| - return LOAD_STATE_IDLE;
|
| -}
|
| -
|
| bool ClientSocketPool::IdleSocket::ShouldCleanup(base::TimeTicks now) const {
|
| bool timed_out = (now - start_time) >=
|
| base::TimeDelta::FromSeconds(kIdleTimeout);
|
| - return timed_out || !socket->IsConnectedAndIdle();
|
| + return timed_out || !(*ptr)->IsConnectedAndIdle();
|
| }
|
|
|
| void ClientSocketPool::CleanupIdleSockets(bool force) {
|
| @@ -354,7 +151,7 @@ void ClientSocketPool::CleanupIdleSockets(bool force) {
|
| std::deque<IdleSocket>::iterator j = group.idle_sockets.begin();
|
| while (j != group.idle_sockets.end()) {
|
| if (force || j->ShouldCleanup(now)) {
|
| - delete j->socket;
|
| + delete j->ptr;
|
| j = group.idle_sockets.erase(j);
|
| DecrementIdleCount();
|
| } else {
|
| @@ -365,7 +162,6 @@ void ClientSocketPool::CleanupIdleSockets(bool force) {
|
| // Delete group if no longer needed.
|
| if (group.active_socket_count == 0 && group.idle_sockets.empty()) {
|
| DCHECK(group.pending_requests.empty());
|
| - DCHECK(group.connecting_requests.empty());
|
| group_map_.erase(i++);
|
| } else {
|
| ++i;
|
| @@ -385,43 +181,40 @@ void ClientSocketPool::DecrementIdleCount() {
|
| }
|
|
|
| void ClientSocketPool::DoReleaseSocket(const std::string& group_name,
|
| - ClientSocket* socket) {
|
| + ClientSocketPtr* ptr) {
|
| GroupMap::iterator i = group_map_.find(group_name);
|
| DCHECK(i != group_map_.end());
|
|
|
| Group& group = i->second;
|
|
|
| - DCHECK_GT(group.active_socket_count, 0);
|
| + DCHECK(group.active_socket_count > 0);
|
| group.active_socket_count--;
|
|
|
| - const bool can_reuse = socket->IsConnectedAndIdle();
|
| + bool can_reuse = ptr->get() && (*ptr)->IsConnectedAndIdle();
|
| if (can_reuse) {
|
| IdleSocket idle_socket;
|
| - idle_socket.socket = socket;
|
| + idle_socket.ptr = ptr;
|
| idle_socket.start_time = base::TimeTicks::Now();
|
|
|
| group.idle_sockets.push_back(idle_socket);
|
| IncrementIdleCount();
|
| } else {
|
| - delete socket;
|
| + delete ptr;
|
| }
|
|
|
| // Process one pending request.
|
| if (!group.pending_requests.empty()) {
|
| Request r = group.pending_requests.front();
|
| group.pending_requests.pop_front();
|
| -
|
| - int rv = RequestSocket(
|
| - group_name, r.host, r.port, r.priority, r.handle, r.callback);
|
| - if (rv != ERR_IO_PENDING)
|
| - r.callback->Run(rv);
|
| + int rv = RequestSocket(r.handle, r.priority, NULL);
|
| + DCHECK(rv == OK);
|
| + r.callback->Run(rv);
|
| return;
|
| }
|
|
|
| // Delete group if no longer needed.
|
| if (group.active_socket_count == 0 && group.idle_sockets.empty()) {
|
| DCHECK(group.pending_requests.empty());
|
| - DCHECK(group.connecting_requests.empty());
|
| group_map_.erase(i);
|
| }
|
| }
|
|
|