summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/http/http_network_session.cc15
-rw-r--r--net/http/http_network_session.h12
-rw-r--r--net/socket/client_socket_pool_base.cc77
-rw-r--r--net/socket/client_socket_pool_base.h49
-rw-r--r--net/socket/client_socket_pool_base_unittest.cc368
-rw-r--r--net/socket/tcp_client_socket_pool.cc3
-rw-r--r--net/socket/tcp_client_socket_pool.h3
-rw-r--r--net/socket/tcp_client_socket_pool_unittest.cc5
8 files changed, 441 insertions, 91 deletions
diff --git a/net/http/http_network_session.cc b/net/http/http_network_session.cc
index a498ed0..b705766 100644
--- a/net/http/http_network_session.cc
+++ b/net/http/http_network_session.cc
@@ -9,8 +9,23 @@
namespace net {
// static
+int HttpNetworkSession::max_sockets_ = 100;
+
+// static
int HttpNetworkSession::max_sockets_per_group_ = 6;
+HttpNetworkSession::HttpNetworkSession(
+ HostResolver* host_resolver,
+ ProxyService* proxy_service,
+ ClientSocketFactory* client_socket_factory)
+ : connection_pool_(new TCPClientSocketPool(
+ max_sockets_, max_sockets_per_group_, host_resolver,
+ client_socket_factory)),
+ host_resolver_(host_resolver),
+ proxy_service_(proxy_service) {
+ DCHECK(proxy_service);
+}
+
// static
void HttpNetworkSession::set_max_sockets_per_group(int socket_count) {
DCHECK(0 < socket_count);
diff --git a/net/http/http_network_session.h b/net/http/http_network_session.h
index 3529bc8..487ade4 100644
--- a/net/http/http_network_session.h
+++ b/net/http/http_network_session.h
@@ -5,7 +5,6 @@
#ifndef NET_HTTP_HTTP_NETWORK_SESSION_H_
#define NET_HTTP_HTTP_NETWORK_SESSION_H_
-#include "base/logging.h"
#include "base/ref_counted.h"
#include "net/base/ssl_client_auth_cache.h"
#include "net/base/ssl_config_service.h"
@@ -22,13 +21,7 @@ class ProxyService;
class HttpNetworkSession : public base::RefCounted<HttpNetworkSession> {
public:
HttpNetworkSession(HostResolver* host_resolver, ProxyService* proxy_service,
- ClientSocketFactory* client_socket_factory)
- : connection_pool_(new TCPClientSocketPool(
- max_sockets_per_group_, host_resolver, client_socket_factory)),
- host_resolver_(host_resolver),
- proxy_service_(proxy_service) {
- DCHECK(proxy_service);
- }
+ ClientSocketFactory* client_socket_factory);
HttpAuthCache* auth_cache() { return &auth_cache_; }
SSLClientAuthCache* ssl_client_auth_cache() {
@@ -46,6 +39,9 @@ class HttpNetworkSession : public base::RefCounted<HttpNetworkSession> {
private:
FRIEND_TEST(HttpNetworkTransactionTest, GroupNameForProxyConnections);
+ // Total limit of sockets. Not a constant to allow experiments.
+ static int max_sockets_;
+
// Default to allow up to 6 connections per host. Experiment and tuning may
// try other values (greater than 0). Too large may cause many problems, such
// as home routers blocking the connections!?!?
diff --git a/net/socket/client_socket_pool_base.cc b/net/socket/client_socket_pool_base.cc
index 313e046..d10cf60 100644
--- a/net/socket/client_socket_pool_base.cc
+++ b/net/socket/client_socket_pool_base.cc
@@ -47,11 +47,19 @@ ConnectJob::ConnectJob(const std::string& group_name,
ConnectJob::~ConnectJob() {}
ClientSocketPoolBase::ClientSocketPoolBase(
+ int max_sockets,
int max_sockets_per_group,
ConnectJobFactory* connect_job_factory)
: idle_socket_count_(0),
+ connecting_socket_count_(0),
+ handed_out_socket_count_(0),
+ max_sockets_(max_sockets),
max_sockets_per_group_(max_sockets_per_group),
- connect_job_factory_(connect_job_factory) {}
+ may_have_stalled_group_(false),
+ connect_job_factory_(connect_job_factory) {
+ DCHECK_LE(0, max_sockets_per_group);
+ DCHECK_LE(max_sockets_per_group, max_sockets);
+}
ClientSocketPoolBase::~ClientSocketPoolBase() {
if (g_late_binding)
@@ -89,7 +97,13 @@ int ClientSocketPoolBase::RequestSocket(
Group& group = group_map_[group_name];
// Can we make another active socket now?
- if (!group.HasAvailableSocketSlot(max_sockets_per_group_)) {
+ if (ReachedMaxSocketsLimit() ||
+ !group.HasAvailableSocketSlot(max_sockets_per_group_)) {
+ if (ReachedMaxSocketsLimit()) {
+ // We could check if we really have a stalled group here, but it requires
+ // a scan of all groups, so just flip a flag here, and do the check later.
+ may_have_stalled_group_ = true;
+ }
CHECK(callback);
Request r(handle, callback, priority, resolve_info);
InsertRequestIntoQueue(r, &group.pending_requests);
@@ -120,6 +134,8 @@ int ClientSocketPoolBase::RequestSocket(
HandOutSocket(connect_job->ReleaseSocket(), false /* not reused */,
handle, &group);
} else if (rv == ERR_IO_PENDING) {
+ connecting_socket_count_++;
+
ConnectJob* job = connect_job.release();
if (g_late_binding) {
CHECK(!ContainsKey(connect_job_map_, handle));
@@ -291,6 +307,9 @@ void ClientSocketPoolBase::DoReleaseSocket(const std::string& group_name,
Group& group = i->second;
+ CHECK(handed_out_socket_count_ > 0);
+ handed_out_socket_count_--;
+
CHECK(group.active_socket_count > 0);
group.active_socket_count--;
@@ -304,6 +323,38 @@ void ClientSocketPoolBase::DoReleaseSocket(const std::string& group_name,
OnAvailableSocketSlot(group_name, &group);
}
+// 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).
+int ClientSocketPoolBase::FindTopStalledGroup(Group** group,
+ std::string* group_name) {
+ Group* top_group = NULL;
+ const std::string* top_group_name = NULL;
+ int stalled_group_count = 0;
+ for (GroupMap::iterator i = group_map_.begin();
+ i != group_map_.end(); ++i) {
+ Group& group = i->second;
+ const RequestQueue& queue = group.pending_requests;
+ if (queue.empty())
+ continue;
+ bool has_slot = group.HasAvailableSocketSlot(max_sockets_per_group_);
+ if (has_slot)
+ stalled_group_count++;
+ bool has_higher_priority = !top_group ||
+ group.TopPendingPriority() > top_group->TopPendingPriority();
+ if (has_slot && has_higher_priority) {
+ top_group = &group;
+ top_group_name = &i->first;
+ }
+ }
+ if (top_group) {
+ *group = top_group;
+ *group_name = *top_group_name;
+ }
+ return stalled_group_count;
+}
+
void ClientSocketPoolBase::OnConnectJobComplete(int result, ConnectJob* job) {
DCHECK_NE(ERR_IO_PENDING, result);
const std::string group_name = job->group_name();
@@ -369,6 +420,9 @@ void ClientSocketPoolBase::EnableLateBindingOfSockets(bool enabled) {
void ClientSocketPoolBase::RemoveConnectJob(
const ClientSocketHandle* handle, ConnectJob *job, Group* group) {
+ CHECK(connecting_socket_count_ > 0);
+ connecting_socket_count_--;
+
if (g_late_binding) {
DCHECK(job);
delete job;
@@ -399,7 +453,15 @@ void ClientSocketPoolBase::MaybeOnAvailableSocketSlot(
void ClientSocketPoolBase::OnAvailableSocketSlot(const std::string& group_name,
Group* group) {
- if (!group->pending_requests.empty()) {
+ if (may_have_stalled_group_) {
+ std::string top_group_name;
+ Group* top_group;
+ int stalled_group_count = FindTopStalledGroup(&top_group, &top_group_name);
+ if (stalled_group_count <= 1)
+ may_have_stalled_group_ = false;
+ if (stalled_group_count >= 1)
+ ProcessPendingRequest(top_group_name, top_group);
+ } else if (!group->pending_requests.empty()) {
ProcessPendingRequest(group_name, group);
// |group| may no longer be valid after this point. Be careful not to
// access it again.
@@ -435,6 +497,8 @@ void ClientSocketPoolBase::HandOutSocket(
DCHECK(socket);
handle->set_socket(socket);
handle->set_is_reused(reused);
+
+ handed_out_socket_count_++;
group->active_socket_count++;
}
@@ -465,4 +529,11 @@ void ClientSocketPoolBase::CancelAllConnectJobs() {
}
}
+bool ClientSocketPoolBase::ReachedMaxSocketsLimit() const {
+ // Each connecting socket will eventually connect and be handed out.
+ int total = handed_out_socket_count_ + connecting_socket_count_;
+ DCHECK_LE(total, max_sockets_);
+ return total == max_sockets_;
+}
+
} // namespace net
diff --git a/net/socket/client_socket_pool_base.h b/net/socket/client_socket_pool_base.h
index fc3582d..36281b4 100644
--- a/net/socket/client_socket_pool_base.h
+++ b/net/socket/client_socket_pool_base.h
@@ -127,7 +127,8 @@ class ClientSocketPoolBase
DISALLOW_COPY_AND_ASSIGN(ConnectJobFactory);
};
- ClientSocketPoolBase(int max_sockets_per_group,
+ ClientSocketPoolBase(int max_sockets,
+ int max_sockets_per_group,
ConnectJobFactory* connect_job_factory);
~ClientSocketPoolBase();
@@ -150,10 +151,6 @@ class ClientSocketPoolBase
return idle_socket_count_;
}
- int max_sockets_per_group() const {
- return max_sockets_per_group_;
- }
-
int IdleSocketCountInGroup(const std::string& group_name) const;
LoadState GetLoadState(const std::string& group_name,
@@ -169,6 +166,9 @@ class ClientSocketPoolBase
// afterward and receive the socket from the job).
static void EnableLateBindingOfSockets(bool enabled);
+ // For testing.
+ bool may_have_stalled_group() const { return may_have_stalled_group_; }
+
private:
// Entry for a persistent socket which became idle at time |start_time|.
struct IdleSocket {
@@ -204,6 +204,10 @@ class ClientSocketPoolBase
max_sockets_per_group;
}
+ int TopPendingPriority() const {
+ return pending_requests.front().priority;
+ }
+
std::deque<IdleSocket> idle_sockets;
std::set<const ConnectJob*> jobs;
RequestQueue pending_requests;
@@ -230,6 +234,12 @@ class ClientSocketPoolBase
// Called via PostTask by ReleaseSocket.
void DoReleaseSocket(const std::string& group_name, ClientSocket* socket);
+ // Scans the group map for groups which have an available socket slot and
+ // at least one pending request. Returns number of groups found, and if found
+ // at least one, fills |group| and |group_name| with data of the stalled group
+ // having highest priority.
+ int FindTopStalledGroup(Group** group, std::string* group_name);
+
// Called when timer_ fires. This method scans the idle sockets removing
// sockets that timed out or can't be reused.
void OnCleanupTimerFired() {
@@ -269,6 +279,10 @@ class ClientSocketPoolBase
// longer needed.
void CancelAllConnectJobs();
+ // Returns true if we can't create any more sockets due to the total limit.
+ // TODO(phajdan.jr): Also take idle sockets into account.
+ bool ReachedMaxSocketsLimit() const;
+
GroupMap group_map_;
ConnectJobMap connect_job_map_;
@@ -280,9 +294,34 @@ class ClientSocketPoolBase
// The total number of idle sockets in the system.
int idle_socket_count_;
+ // Number of connecting sockets across all groups.
+ int connecting_socket_count_;
+
+ // Number of connected sockets we handed out across all groups.
+ int handed_out_socket_count_;
+
+ // The maximum total number of sockets. See ReachedMaxSocketsLimit.
+ const int max_sockets_;
+
// The maximum number of sockets kept per group.
const int max_sockets_per_group_;
+ // Until the maximum number of sockets limit is reached, a group can only
+ // have pending requests if it exceeds the "max sockets per group" limit.
+ //
+ // This means when a socket is released, the only pending requests that can
+ // be started next belong to the same group.
+ //
+ // However once the |max_sockets_| limit is reached, this stops being true:
+ // groups can now have pending requests without having first reached the
+ // |max_sockets_per_group_| limit. So choosing the next request involves
+ // selecting the highest priority request across *all* groups.
+ //
+ // Since reaching the maximum number of sockets is an edge case, we make note
+ // of when it happens, and thus avoid doing the slower "scan all groups"
+ // in the common case.
+ bool may_have_stalled_group_;
+
const scoped_ptr<ConnectJobFactory> connect_job_factory_;
// Controls whether or not we use late binding of sockets.
diff --git a/net/socket/client_socket_pool_base_unittest.cc b/net/socket/client_socket_pool_base_unittest.cc
index 5f6c6fc..f5ad77e 100644
--- a/net/socket/client_socket_pool_base_unittest.cc
+++ b/net/socket/client_socket_pool_base_unittest.cc
@@ -18,6 +18,8 @@ namespace net {
namespace {
+const int kDefaultMaxSockets = 4;
+
const int kDefaultMaxSocketsPerGroup = 2;
const int kDefaultPriority = 5;
@@ -255,10 +257,11 @@ class TestConnectJobFactory : public ClientSocketPoolBase::ConnectJobFactory {
class TestClientSocketPool : public ClientSocketPool {
public:
TestClientSocketPool(
+ int max_sockets,
int max_sockets_per_group,
ClientSocketPoolBase::ConnectJobFactory* connect_job_factory)
: base_(new ClientSocketPoolBase(
- max_sockets_per_group, connect_job_factory)) {}
+ max_sockets, max_sockets_per_group, connect_job_factory)) {}
virtual int RequestSocket(
const std::string& group_name,
@@ -297,9 +300,7 @@ class TestClientSocketPool : public ClientSocketPool {
return base_->GetLoadState(group_name, handle);
}
- int MaxSocketsPerGroup() const {
- return base_->max_sockets_per_group();
- }
+ const ClientSocketPoolBase* base() const { return base_.get(); }
private:
const scoped_refptr<ClientSocketPoolBase> base_;
@@ -322,9 +323,10 @@ class ClientSocketPoolBaseTest : public testing::Test {
connect_job_factory_(
new TestConnectJobFactory(&client_socket_factory_)) {}
- void CreatePool(int max_sockets_per_group) {
+ void CreatePool(int max_sockets, int max_sockets_per_group) {
DCHECK(!pool_.get());
- pool_ = new TestClientSocketPool(max_sockets_per_group,
+ pool_ = new TestClientSocketPool(max_sockets,
+ max_sockets_per_group,
connect_job_factory_);
}
@@ -336,9 +338,14 @@ class ClientSocketPoolBaseTest : public testing::Test {
// The tests often call Reset() on handles at the end which may post
// DoReleaseSocket() tasks.
MessageLoop::current()->RunAllPending();
- // Need to delete |pool_| before we turn late binding back off.
- // TODO(willchan): Remove this line when late binding becomes the default.
+
+ // Need to delete |pool_| before we turn late binding back off. We also need
+ // to delete |requests_| because the pool is reference counted and requests
+ // keep reference to it.
+ // TODO(willchan): Remove this part when late binding becomes the default.
pool_ = NULL;
+ requests_.reset();
+
ClientSocketPoolBase::EnableLateBindingOfSockets(false);
}
@@ -374,20 +381,24 @@ class ClientSocketPoolBaseTest : public testing::Test {
NO_KEEP_ALIVE,
};
+ bool ReleaseOneConnection(KeepAlive keep_alive) {
+ ScopedVector<TestSocketRequest>::iterator i;
+ for (i = requests_.begin(); i != requests_.end(); ++i) {
+ if ((*i)->handle.is_initialized()) {
+ if (keep_alive == NO_KEEP_ALIVE)
+ (*i)->handle.socket()->Disconnect();
+ (*i)->handle.Reset();
+ MessageLoop::current()->RunAllPending();
+ return true;
+ }
+ }
+ return false;
+ }
+
void ReleaseAllConnections(KeepAlive keep_alive) {
bool released_one;
do {
- released_one = false;
- ScopedVector<TestSocketRequest>::iterator i;
- for (i = requests_.begin(); i != requests_.end(); ++i) {
- if ((*i)->handle.is_initialized()) {
- if (keep_alive == NO_KEEP_ALIVE)
- (*i)->handle.socket()->Disconnect();
- (*i)->handle.Reset();
- MessageLoop::current()->RunAllPending();
- released_one = true;
- }
- }
+ released_one = ReleaseOneConnection(keep_alive);
} while (released_one);
}
@@ -406,7 +417,7 @@ const int ClientSocketPoolBaseTest::kIndexOutOfBounds = -1;
const int ClientSocketPoolBaseTest::kRequestNotFound = -2;
TEST_F(ClientSocketPoolBaseTest, BasicSynchronous) {
- CreatePool(kDefaultMaxSocketsPerGroup);
+ CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
TestCompletionCallback callback;
ClientSocketHandle handle(pool_.get());
@@ -418,7 +429,7 @@ TEST_F(ClientSocketPoolBaseTest, BasicSynchronous) {
}
TEST_F(ClientSocketPoolBaseTest, BasicAsynchronous) {
- CreatePool(kDefaultMaxSocketsPerGroup);
+ CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
TestSocketRequest req(pool_.get(), &request_order_);
@@ -432,7 +443,7 @@ TEST_F(ClientSocketPoolBaseTest, BasicAsynchronous) {
}
TEST_F(ClientSocketPoolBaseTest, InitConnectionFailure) {
- CreatePool(kDefaultMaxSocketsPerGroup);
+ CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
connect_job_factory_->set_job_type(TestConnectJob::kMockFailingJob);
TestSocketRequest req(pool_.get(), &request_order_);
@@ -442,7 +453,7 @@ TEST_F(ClientSocketPoolBaseTest, InitConnectionFailure) {
}
TEST_F(ClientSocketPoolBaseTest, InitConnectionAsynchronousFailure) {
- CreatePool(kDefaultMaxSocketsPerGroup);
+ CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
connect_job_factory_->set_job_type(TestConnectJob::kMockPendingFailingJob);
TestSocketRequest req(pool_.get(), &request_order_);
@@ -452,8 +463,225 @@ TEST_F(ClientSocketPoolBaseTest, InitConnectionAsynchronousFailure) {
EXPECT_EQ(ERR_CONNECTION_FAILED, req.WaitForResult());
}
+TEST_F(ClientSocketPoolBaseTest, TotalLimit) {
+ CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
+
+ EXPECT_EQ(OK, StartRequest("a", kDefaultPriority));
+ EXPECT_EQ(OK, StartRequest("b", kDefaultPriority));
+ EXPECT_EQ(OK, StartRequest("c", kDefaultPriority));
+ EXPECT_EQ(OK, StartRequest("d", kDefaultPriority));
+
+ EXPECT_EQ(static_cast<int>(requests_.size()),
+ client_socket_factory_.allocation_count());
+ EXPECT_EQ(requests_.size() - kDefaultMaxSockets,
+ TestSocketRequest::completion_count);
+
+ EXPECT_EQ(ERR_IO_PENDING, StartRequest("e", kDefaultPriority));
+ EXPECT_EQ(ERR_IO_PENDING, StartRequest("f", kDefaultPriority));
+ EXPECT_EQ(ERR_IO_PENDING, StartRequest("g", kDefaultPriority));
+
+ ReleaseAllConnections(KEEP_ALIVE);
+
+ EXPECT_EQ(static_cast<int>(requests_.size()),
+ client_socket_factory_.allocation_count());
+ EXPECT_EQ(requests_.size() - kDefaultMaxSockets,
+ TestSocketRequest::completion_count);
+
+ EXPECT_EQ(1, GetOrderOfRequest(1));
+ EXPECT_EQ(2, GetOrderOfRequest(2));
+ EXPECT_EQ(3, GetOrderOfRequest(3));
+ EXPECT_EQ(4, GetOrderOfRequest(4));
+ EXPECT_EQ(5, GetOrderOfRequest(5));
+ EXPECT_EQ(6, GetOrderOfRequest(6));
+ EXPECT_EQ(7, GetOrderOfRequest(7));
+}
+
+TEST_F(ClientSocketPoolBaseTest, TotalLimitReachedNewGroup) {
+ CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
+
+ // Reach all limits: max total sockets, and max sockets per group.
+ EXPECT_EQ(OK, StartRequest("a", kDefaultPriority));
+ EXPECT_EQ(OK, StartRequest("a", kDefaultPriority));
+ EXPECT_EQ(OK, StartRequest("b", kDefaultPriority));
+ EXPECT_EQ(OK, StartRequest("b", kDefaultPriority));
+
+ EXPECT_EQ(static_cast<int>(requests_.size()),
+ client_socket_factory_.allocation_count());
+ EXPECT_EQ(requests_.size() - kDefaultMaxSockets,
+ TestSocketRequest::completion_count);
+
+ // Now create a new group and verify that we don't starve it.
+ EXPECT_EQ(ERR_IO_PENDING, StartRequest("c", kDefaultPriority));
+
+ ReleaseAllConnections(KEEP_ALIVE);
+
+ EXPECT_EQ(static_cast<int>(requests_.size()),
+ client_socket_factory_.allocation_count());
+ EXPECT_EQ(requests_.size() - kDefaultMaxSockets,
+ TestSocketRequest::completion_count);
+
+ EXPECT_EQ(1, GetOrderOfRequest(1));
+ EXPECT_EQ(2, GetOrderOfRequest(2));
+ EXPECT_EQ(3, GetOrderOfRequest(3));
+ EXPECT_EQ(4, GetOrderOfRequest(4));
+ EXPECT_EQ(5, GetOrderOfRequest(5));
+}
+
+TEST_F(ClientSocketPoolBaseTest, TotalLimitRespectsPriority) {
+ CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
+
+ EXPECT_EQ(OK, StartRequest("b", 3));
+ EXPECT_EQ(OK, StartRequest("a", 3));
+ EXPECT_EQ(OK, StartRequest("b", 6));
+ EXPECT_EQ(OK, StartRequest("a", 6));
+
+ EXPECT_EQ(static_cast<int>(requests_.size()),
+ client_socket_factory_.allocation_count());
+
+ EXPECT_EQ(ERR_IO_PENDING, StartRequest("c", 4));
+ EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", 5));
+ EXPECT_EQ(ERR_IO_PENDING, StartRequest("b", 7));
+
+ ReleaseAllConnections(KEEP_ALIVE);
+
+ // We're re-using one socket for group "a", and one for "b".
+ EXPECT_EQ(static_cast<int>(requests_.size()) - 2,
+ client_socket_factory_.allocation_count());
+ EXPECT_EQ(requests_.size() - kDefaultMaxSockets,
+ TestSocketRequest::completion_count);
+
+ // First 4 requests don't have to wait, and finish in order.
+ EXPECT_EQ(1, GetOrderOfRequest(1));
+ EXPECT_EQ(2, GetOrderOfRequest(2));
+ EXPECT_EQ(3, GetOrderOfRequest(3));
+ EXPECT_EQ(4, GetOrderOfRequest(4));
+
+ // Request ("b", 7) has the highest priority, then ("a", 5),
+ // and then ("c", 4).
+ EXPECT_EQ(7, GetOrderOfRequest(5));
+ EXPECT_EQ(6, GetOrderOfRequest(6));
+ EXPECT_EQ(5, GetOrderOfRequest(7));
+}
+
+TEST_F(ClientSocketPoolBaseTest, TotalLimitRespectsGroupLimit) {
+ CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
+
+ EXPECT_EQ(OK, StartRequest("a", 3));
+ EXPECT_EQ(OK, StartRequest("a", 6));
+ EXPECT_EQ(OK, StartRequest("b", 3));
+ EXPECT_EQ(OK, StartRequest("b", 6));
+
+ EXPECT_EQ(static_cast<int>(requests_.size()),
+ client_socket_factory_.allocation_count());
+
+ EXPECT_EQ(ERR_IO_PENDING, StartRequest("c", 6));
+ EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", 4));
+ EXPECT_EQ(ERR_IO_PENDING, StartRequest("b", 7));
+
+ ReleaseAllConnections(KEEP_ALIVE);
+
+ // We're re-using one socket for group "a", and one for "b".
+ EXPECT_EQ(static_cast<int>(requests_.size()) - 2,
+ client_socket_factory_.allocation_count());
+ EXPECT_EQ(requests_.size() - kDefaultMaxSockets,
+ TestSocketRequest::completion_count);
+
+ // First 4 requests don't have to wait, and finish in order.
+ EXPECT_EQ(1, GetOrderOfRequest(1));
+ EXPECT_EQ(2, GetOrderOfRequest(2));
+ EXPECT_EQ(3, GetOrderOfRequest(3));
+ EXPECT_EQ(4, GetOrderOfRequest(4));
+
+ // Request ("b", 7) has the highest priority, but we can't make new socket for
+ // group "b", because it has reached the per-group limit. Then we make
+ // socket for ("c", 6), because it has higher priority than ("a", 4),
+ // and we still can't make a socket for group "b".
+ EXPECT_EQ(5, GetOrderOfRequest(5));
+ EXPECT_EQ(6, GetOrderOfRequest(6));
+ EXPECT_EQ(7, GetOrderOfRequest(7));
+}
+
+// Make sure that we count connecting sockets against the total limit.
+TEST_F(ClientSocketPoolBaseTest, TotalLimitCountsConnectingSockets) {
+ CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
+
+ EXPECT_EQ(OK, StartRequest("a", kDefaultPriority));
+ EXPECT_EQ(OK, StartRequest("b", kDefaultPriority));
+ EXPECT_EQ(OK, StartRequest("c", kDefaultPriority));
+
+ // Create one asynchronous request.
+ connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
+ EXPECT_EQ(ERR_IO_PENDING, StartRequest("d", kDefaultPriority));
+
+ // The next synchronous request should wait for its turn.
+ connect_job_factory_->set_job_type(TestConnectJob::kMockJob);
+ EXPECT_EQ(ERR_IO_PENDING, StartRequest("e", kDefaultPriority));
+
+ ReleaseAllConnections(KEEP_ALIVE);
+
+ EXPECT_EQ(static_cast<int>(requests_.size()),
+ client_socket_factory_.allocation_count());
+
+ EXPECT_EQ(1, GetOrderOfRequest(1));
+ EXPECT_EQ(2, GetOrderOfRequest(2));
+ EXPECT_EQ(3, GetOrderOfRequest(3));
+ EXPECT_EQ(4, GetOrderOfRequest(4));
+}
+
+// Inside ClientSocketPoolBase we have a may_have_stalled_group flag,
+// which tells it to use more expensive, but accurate, group selection
+// algorithm. Make sure it doesn't get stuck in the "on" state.
+TEST_F(ClientSocketPoolBaseTest, MayHaveStalledGroupReset) {
+ CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
+
+ EXPECT_FALSE(pool_->base()->may_have_stalled_group());
+
+ // Reach group socket limit.
+ EXPECT_EQ(OK, StartRequest("a", kDefaultPriority));
+ EXPECT_EQ(OK, StartRequest("a", kDefaultPriority));
+ EXPECT_FALSE(pool_->base()->may_have_stalled_group());
+
+ // Reach total limit, but don't request more sockets.
+ EXPECT_EQ(OK, StartRequest("b", kDefaultPriority));
+ EXPECT_EQ(OK, StartRequest("b", kDefaultPriority));
+ EXPECT_FALSE(pool_->base()->may_have_stalled_group());
+
+ // Request one more socket while we are at the maximum sockets limit.
+ // This should flip the may_have_stalled_group flag.
+ EXPECT_EQ(ERR_IO_PENDING, StartRequest("c", kDefaultPriority));
+ EXPECT_TRUE(pool_->base()->may_have_stalled_group());
+
+ // After releasing first connection for "a", we're still at the
+ // maximum sockets limit, but every group's pending queue is empty,
+ // so we reset the flag.
+ EXPECT_TRUE(ReleaseOneConnection(KEEP_ALIVE));
+ EXPECT_FALSE(pool_->base()->may_have_stalled_group());
+
+ // Requesting additional socket while at the total limit should
+ // flip the flag back to "on".
+ EXPECT_EQ(ERR_IO_PENDING, StartRequest("c", kDefaultPriority));
+ EXPECT_TRUE(pool_->base()->may_have_stalled_group());
+
+ // We'll request one more socket to verify that we don't reset the flag
+ // too eagerly.
+ EXPECT_EQ(ERR_IO_PENDING, StartRequest("d", kDefaultPriority));
+ EXPECT_TRUE(pool_->base()->may_have_stalled_group());
+
+ // We're at the maximum socket limit, and still have one request pending
+ // for "d". Flag should be "on".
+ EXPECT_TRUE(ReleaseOneConnection(KEEP_ALIVE));
+ EXPECT_TRUE(pool_->base()->may_have_stalled_group());
+
+ // Now every group's pending queue should be empty again.
+ EXPECT_TRUE(ReleaseOneConnection(KEEP_ALIVE));
+ EXPECT_FALSE(pool_->base()->may_have_stalled_group());
+
+ ReleaseAllConnections(KEEP_ALIVE);
+ EXPECT_FALSE(pool_->base()->may_have_stalled_group());
+}
+
TEST_F(ClientSocketPoolBaseTest, PendingRequests) {
- CreatePool(kDefaultMaxSocketsPerGroup);
+ CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
EXPECT_EQ(OK, StartRequest("a", kDefaultPriority));
EXPECT_EQ(OK, StartRequest("a", kDefaultPriority));
@@ -480,7 +708,7 @@ TEST_F(ClientSocketPoolBaseTest, PendingRequests) {
}
TEST_F(ClientSocketPoolBaseTest, PendingRequests_NoKeepAlive) {
- CreatePool(kDefaultMaxSocketsPerGroup);
+ CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
EXPECT_EQ(OK, StartRequest("a", kDefaultPriority));
EXPECT_EQ(OK, StartRequest("a", kDefaultPriority));
@@ -505,7 +733,7 @@ TEST_F(ClientSocketPoolBaseTest, PendingRequests_NoKeepAlive) {
// The pending connect job will be cancelled and should not call back into
// ClientSocketPoolBase.
TEST_F(ClientSocketPoolBaseTest, CancelRequestClearGroup) {
- CreatePool(kDefaultMaxSocketsPerGroup);
+ CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
TestSocketRequest req(pool_.get(), &request_order_);
@@ -516,7 +744,7 @@ TEST_F(ClientSocketPoolBaseTest, CancelRequestClearGroup) {
}
TEST_F(ClientSocketPoolBaseTest, TwoRequestsCancelOne) {
- CreatePool(kDefaultMaxSocketsPerGroup);
+ CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
TestSocketRequest req(pool_.get(), &request_order_);
@@ -536,7 +764,7 @@ TEST_F(ClientSocketPoolBaseTest, TwoRequestsCancelOne) {
}
TEST_F(ClientSocketPoolBaseTest, ConnectCancelConnect) {
- CreatePool(kDefaultMaxSocketsPerGroup);
+ CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
ClientSocketHandle handle(pool_.get());
@@ -561,7 +789,7 @@ TEST_F(ClientSocketPoolBaseTest, ConnectCancelConnect) {
}
TEST_F(ClientSocketPoolBaseTest, CancelRequest) {
- CreatePool(kDefaultMaxSocketsPerGroup);
+ CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
EXPECT_EQ(OK, StartRequest("a", kDefaultPriority));
EXPECT_EQ(OK, StartRequest("a", kDefaultPriority));
@@ -640,7 +868,7 @@ class RequestSocketCallback : public CallbackRunner< Tuple1<int> > {
};
TEST_F(ClientSocketPoolBaseTest, RequestPendingJobTwice) {
- CreatePool(kDefaultMaxSocketsPerGroup);
+ CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
ClientSocketHandle handle(pool_.get());
@@ -655,7 +883,7 @@ TEST_F(ClientSocketPoolBaseTest, RequestPendingJobTwice) {
}
TEST_F(ClientSocketPoolBaseTest, RequestPendingJobThenSynchronous) {
- CreatePool(kDefaultMaxSocketsPerGroup);
+ CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
ClientSocketHandle handle(pool_.get());
@@ -672,7 +900,7 @@ TEST_F(ClientSocketPoolBaseTest, RequestPendingJobThenSynchronous) {
// Make sure that pending requests get serviced after active requests get
// cancelled.
TEST_F(ClientSocketPoolBaseTest, CancelActiveRequestWithPendingRequests) {
- CreatePool(kDefaultMaxSocketsPerGroup);
+ CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
@@ -703,26 +931,24 @@ TEST_F(ClientSocketPoolBaseTest, CancelActiveRequestWithPendingRequests) {
// Make sure that pending requests get serviced after active requests fail.
TEST_F(ClientSocketPoolBaseTest, FailingActiveRequestWithPendingRequests) {
- CreatePool(kDefaultMaxSocketsPerGroup);
+ const size_t kMaxSockets = 5;
+ CreatePool(kMaxSockets, kDefaultMaxSocketsPerGroup);
connect_job_factory_->set_job_type(TestConnectJob::kMockPendingFailingJob);
- scoped_ptr<TestSocketRequest> reqs[kDefaultMaxSocketsPerGroup * 2 + 1];
+ const size_t kNumberOfRequests = 2 * kDefaultMaxSocketsPerGroup + 1;
+ ASSERT_LE(kNumberOfRequests, kMaxSockets); // Otherwise the test will hang.
// Queue up all the requests
- for (size_t i = 0; i < arraysize(reqs); ++i) {
- reqs[i].reset(new TestSocketRequest(pool_.get(), &request_order_));
- int rv = reqs[i]->handle.Init("a", ignored_request_info_,
- kDefaultPriority, reqs[i].get());
- EXPECT_EQ(ERR_IO_PENDING, rv);
- }
+ for (size_t i = 0; i < kNumberOfRequests; ++i)
+ EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority));
- for (size_t i = 0; i < arraysize(reqs); ++i)
- EXPECT_EQ(ERR_CONNECTION_FAILED, reqs[i]->WaitForResult());
+ for (size_t i = 0; i < kNumberOfRequests; ++i)
+ EXPECT_EQ(ERR_CONNECTION_FAILED, requests_[i]->WaitForResult());
}
TEST_F(ClientSocketPoolBaseTest, CancelActiveRequestThenRequestSocket) {
- CreatePool(kDefaultMaxSocketsPerGroup);
+ CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
@@ -747,7 +973,7 @@ TEST_F(ClientSocketPoolBaseTest, CancelActiveRequestThenRequestSocket) {
// next job finishes synchronously. The callback for the asynchronous job
// should be first though.
TEST_F(ClientSocketPoolBaseTest, PendingJobCompletionOrder) {
- CreatePool(kDefaultMaxSocketsPerGroup);
+ CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
// First two jobs are async.
connect_job_factory_->set_job_type(TestConnectJob::kMockPendingFailingJob);
@@ -788,7 +1014,7 @@ TEST_F(ClientSocketPoolBaseTest, PendingJobCompletionOrder) {
// When a ConnectJob is coupled to a request, even if a free socket becomes
// available, the request will be serviced by the ConnectJob.
TEST_F(ClientSocketPoolBaseTest, ReleaseSockets) {
- CreatePool(kDefaultMaxSocketsPerGroup);
+ CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
ClientSocketPoolBase::EnableLateBindingOfSockets(false);
// Start job 1 (async OK)
@@ -834,7 +1060,7 @@ class ClientSocketPoolBaseTest_LateBinding : public ClientSocketPoolBaseTest {
};
TEST_F(ClientSocketPoolBaseTest_LateBinding, BasicSynchronous) {
- CreatePool(kDefaultMaxSocketsPerGroup);
+ CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
TestCompletionCallback callback;
ClientSocketHandle handle(pool_.get());
@@ -846,7 +1072,7 @@ TEST_F(ClientSocketPoolBaseTest_LateBinding, BasicSynchronous) {
}
TEST_F(ClientSocketPoolBaseTest_LateBinding, BasicAsynchronous) {
- CreatePool(kDefaultMaxSocketsPerGroup);
+ CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
TestSocketRequest req(pool_.get(), &request_order_);
@@ -860,7 +1086,7 @@ TEST_F(ClientSocketPoolBaseTest_LateBinding, BasicAsynchronous) {
}
TEST_F(ClientSocketPoolBaseTest_LateBinding, InitConnectionFailure) {
- CreatePool(kDefaultMaxSocketsPerGroup);
+ CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
connect_job_factory_->set_job_type(TestConnectJob::kMockFailingJob);
TestSocketRequest req(pool_.get(), &request_order_);
@@ -871,7 +1097,7 @@ TEST_F(ClientSocketPoolBaseTest_LateBinding, InitConnectionFailure) {
TEST_F(ClientSocketPoolBaseTest_LateBinding,
InitConnectionAsynchronousFailure) {
- CreatePool(kDefaultMaxSocketsPerGroup);
+ CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
connect_job_factory_->set_job_type(TestConnectJob::kMockPendingFailingJob);
TestSocketRequest req(pool_.get(), &request_order_);
@@ -882,7 +1108,7 @@ TEST_F(ClientSocketPoolBaseTest_LateBinding,
}
TEST_F(ClientSocketPoolBaseTest_LateBinding, PendingRequests) {
- CreatePool(kDefaultMaxSocketsPerGroup);
+ CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
EXPECT_EQ(OK, StartRequest("a", kDefaultPriority));
EXPECT_EQ(OK, StartRequest("a", kDefaultPriority));
@@ -909,7 +1135,7 @@ TEST_F(ClientSocketPoolBaseTest_LateBinding, PendingRequests) {
}
TEST_F(ClientSocketPoolBaseTest_LateBinding, PendingRequests_NoKeepAlive) {
- CreatePool(kDefaultMaxSocketsPerGroup);
+ CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
EXPECT_EQ(OK, StartRequest("a", kDefaultPriority));
EXPECT_EQ(OK, StartRequest("a", kDefaultPriority));
@@ -934,7 +1160,7 @@ TEST_F(ClientSocketPoolBaseTest_LateBinding, PendingRequests_NoKeepAlive) {
// The pending connect job will be cancelled and should not call back into
// ClientSocketPoolBase.
TEST_F(ClientSocketPoolBaseTest_LateBinding, CancelRequestClearGroup) {
- CreatePool(kDefaultMaxSocketsPerGroup);
+ CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
TestSocketRequest req(pool_.get(), &request_order_);
@@ -945,7 +1171,7 @@ TEST_F(ClientSocketPoolBaseTest_LateBinding, CancelRequestClearGroup) {
}
TEST_F(ClientSocketPoolBaseTest_LateBinding, TwoRequestsCancelOne) {
- CreatePool(kDefaultMaxSocketsPerGroup);
+ CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
TestSocketRequest req(pool_.get(), &request_order_);
@@ -965,7 +1191,7 @@ TEST_F(ClientSocketPoolBaseTest_LateBinding, TwoRequestsCancelOne) {
}
TEST_F(ClientSocketPoolBaseTest_LateBinding, ConnectCancelConnect) {
- CreatePool(kDefaultMaxSocketsPerGroup);
+ CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
ClientSocketHandle handle(pool_.get());
@@ -990,7 +1216,7 @@ TEST_F(ClientSocketPoolBaseTest_LateBinding, ConnectCancelConnect) {
}
TEST_F(ClientSocketPoolBaseTest_LateBinding, CancelRequest) {
- CreatePool(kDefaultMaxSocketsPerGroup);
+ CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
EXPECT_EQ(OK, StartRequest("a", kDefaultPriority));
EXPECT_EQ(OK, StartRequest("a", kDefaultPriority));
@@ -1022,7 +1248,7 @@ TEST_F(ClientSocketPoolBaseTest_LateBinding, CancelRequest) {
}
TEST_F(ClientSocketPoolBaseTest_LateBinding, RequestPendingJobTwice) {
- CreatePool(kDefaultMaxSocketsPerGroup);
+ CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
ClientSocketHandle handle(pool_.get());
@@ -1037,7 +1263,7 @@ TEST_F(ClientSocketPoolBaseTest_LateBinding, RequestPendingJobTwice) {
}
TEST_F(ClientSocketPoolBaseTest_LateBinding, RequestPendingJobThenSynchronous) {
- CreatePool(kDefaultMaxSocketsPerGroup);
+ CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
ClientSocketHandle handle(pool_.get());
@@ -1055,7 +1281,7 @@ TEST_F(ClientSocketPoolBaseTest_LateBinding, RequestPendingJobThenSynchronous) {
// cancelled.
TEST_F(ClientSocketPoolBaseTest_LateBinding,
CancelActiveRequestWithPendingRequests) {
- CreatePool(kDefaultMaxSocketsPerGroup);
+ CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
@@ -1087,27 +1313,25 @@ TEST_F(ClientSocketPoolBaseTest_LateBinding,
// Make sure that pending requests get serviced after active requests fail.
TEST_F(ClientSocketPoolBaseTest_LateBinding,
FailingActiveRequestWithPendingRequests) {
- CreatePool(kDefaultMaxSocketsPerGroup);
+ const int kMaxSockets = 5;
+ CreatePool(kMaxSockets, kDefaultMaxSocketsPerGroup);
connect_job_factory_->set_job_type(TestConnectJob::kMockPendingFailingJob);
- scoped_ptr<TestSocketRequest> reqs[kDefaultMaxSocketsPerGroup * 2 + 1];
+ const int kNumberOfRequests = 2 * kDefaultMaxSocketsPerGroup + 1;
+ ASSERT_LE(kNumberOfRequests, kMaxSockets); // Otherwise the test hangs.
// Queue up all the requests
- for (size_t i = 0; i < arraysize(reqs); ++i) {
- reqs[i].reset(new TestSocketRequest(pool_.get(), &request_order_));
- int rv = reqs[i]->handle.Init("a", ignored_request_info_,
- kDefaultPriority, reqs[i].get());
- EXPECT_EQ(ERR_IO_PENDING, rv);
- }
+ for (int i = 0; i < kNumberOfRequests; ++i)
+ EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority));
- for (size_t i = 0; i < arraysize(reqs); ++i)
- EXPECT_EQ(ERR_CONNECTION_FAILED, reqs[i]->WaitForResult());
+ for (int i = 0; i < kNumberOfRequests; ++i)
+ EXPECT_EQ(ERR_CONNECTION_FAILED, requests_[i]->WaitForResult());
}
TEST_F(ClientSocketPoolBaseTest_LateBinding,
CancelActiveRequestThenRequestSocket) {
- CreatePool(kDefaultMaxSocketsPerGroup);
+ CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
@@ -1131,7 +1355,7 @@ TEST_F(ClientSocketPoolBaseTest_LateBinding,
// When requests and ConnectJobs are not coupled, the request will get serviced
// by whatever comes first.
TEST_F(ClientSocketPoolBaseTest_LateBinding, ReleaseSockets) {
- CreatePool(kDefaultMaxSocketsPerGroup);
+ CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
// Start job 1 (async OK)
connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
@@ -1175,7 +1399,7 @@ TEST_F(ClientSocketPoolBaseTest_LateBinding, ReleaseSockets) {
// The requests are not coupled to the jobs. So, the requests should finish in
// their priority / insertion order.
TEST_F(ClientSocketPoolBaseTest_LateBinding, PendingJobCompletionOrder) {
- CreatePool(kDefaultMaxSocketsPerGroup);
+ CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
// First two jobs are async.
connect_job_factory_->set_job_type(TestConnectJob::kMockPendingFailingJob);
@@ -1205,7 +1429,7 @@ TEST_F(ClientSocketPoolBaseTest_LateBinding, PendingJobCompletionOrder) {
}
TEST_F(ClientSocketPoolBaseTest_LateBinding, DISABLED_LoadState) {
- CreatePool(kDefaultMaxSocketsPerGroup);
+ CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
connect_job_factory_->set_job_type(
TestConnectJob::kMockAdvancingLoadStateJob);
diff --git a/net/socket/tcp_client_socket_pool.cc b/net/socket/tcp_client_socket_pool.cc
index 6b3fd05..decc23f1 100644
--- a/net/socket/tcp_client_socket_pool.cc
+++ b/net/socket/tcp_client_socket_pool.cc
@@ -132,11 +132,12 @@ ConnectJob* TCPClientSocketPool::TCPConnectJobFactory::NewConnectJob(
}
TCPClientSocketPool::TCPClientSocketPool(
+ int max_sockets,
int max_sockets_per_group,
HostResolver* host_resolver,
ClientSocketFactory* client_socket_factory)
: base_(new ClientSocketPoolBase(
- max_sockets_per_group,
+ max_sockets, max_sockets_per_group,
new TCPConnectJobFactory(client_socket_factory, host_resolver))) {}
TCPClientSocketPool::~TCPClientSocketPool() {}
diff --git a/net/socket/tcp_client_socket_pool.h b/net/socket/tcp_client_socket_pool.h
index 33c38bb..1906dcc 100644
--- a/net/socket/tcp_client_socket_pool.h
+++ b/net/socket/tcp_client_socket_pool.h
@@ -70,7 +70,8 @@ class TCPConnectJob : public ConnectJob {
class TCPClientSocketPool : public ClientSocketPool {
public:
- TCPClientSocketPool(int max_sockets_per_group,
+ TCPClientSocketPool(int max_sockets,
+ int max_sockets_per_group,
HostResolver* host_resolver,
ClientSocketFactory* client_socket_factory);
diff --git a/net/socket/tcp_client_socket_pool_unittest.cc b/net/socket/tcp_client_socket_pool_unittest.cc
index d81137d..a31afcc 100644
--- a/net/socket/tcp_client_socket_pool_unittest.cc
+++ b/net/socket/tcp_client_socket_pool_unittest.cc
@@ -18,6 +18,7 @@ namespace net {
namespace {
+const int kMaxSockets = 32;
const int kMaxSocketsPerGroup = 6;
// Note that the first and the last are the same, the first should be handled
@@ -225,7 +226,8 @@ class TCPClientSocketPoolTest : public testing::Test {
protected:
TCPClientSocketPoolTest()
: host_resolver_(new MockHostResolver),
- pool_(new TCPClientSocketPool(kMaxSocketsPerGroup,
+ pool_(new TCPClientSocketPool(kMaxSockets,
+ kMaxSocketsPerGroup,
host_resolver_,
&client_socket_factory_)) {
}
@@ -618,6 +620,7 @@ TEST_F(TCPClientSocketPoolTest, FailingActiveRequestWithPendingRequests) {
MockClientSocketFactory::MOCK_PENDING_FAILING_CLIENT_SOCKET);
scoped_ptr<TestSocketRequest> reqs[kMaxSocketsPerGroup * 2 + 1];
+ ASSERT_LE(static_cast<int>(arraysize(reqs)), kMaxSockets);
// Queue up all the requests