diff options
Diffstat (limited to 'net/base/client_socket_pool.cc')
-rw-r--r-- | net/base/client_socket_pool.cc | 273 |
1 files changed, 33 insertions, 240 deletions
diff --git a/net/base/client_socket_pool.cc b/net/base/client_socket_pool.cc index 9f14fe7..4171b0c 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); } } |