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); |
} |
} |