From 4a3315aa161157d999188daed1d276f49c3867bc Mon Sep 17 00:00:00 2001 From: "kristianm@chromium.org" Date: Thu, 8 Sep 2011 04:22:28 +0000 Subject: Exposing CloseIdleConnections in HttpCache, and close idle spdy sessions Adding CloseIdleSessions to SPDY, use it when closing idle sessions in HttpNetworkSession. Expose CloseIdleConnections to HttpCache so it can be use when from clients of the HttpCache. BUG=None TEST=None Review URL: http://codereview.chromium.org/7380004 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@100100 0039d316-1c4b-4281-b951-d872f2087c98 --- net/http/http_cache.cc | 8 +++ net/http/http_cache.h | 3 ++ net/http/http_network_session.cc | 1 + net/spdy/spdy_session.h | 5 ++ net/spdy/spdy_session_pool.cc | 16 ++++++ net/spdy/spdy_session_pool.h | 2 + net/spdy/spdy_session_unittest.cc | 106 ++++++++++++++++++++++++++++++++++++++ 7 files changed, 141 insertions(+) (limited to 'net') diff --git a/net/http/http_cache.cc b/net/http/http_cache.cc index 589777d..738a539 100644 --- a/net/http/http_cache.cc +++ b/net/http/http_cache.cc @@ -465,6 +465,14 @@ void HttpCache::CloseAllConnections() { HttpNetworkSession* session = network->GetSession(); if (session) session->CloseAllConnections(); + } + +void HttpCache::CloseIdleConnections() { + net::HttpNetworkLayer* network = + static_cast(network_layer_.get()); + HttpNetworkSession* session = network->GetSession(); + if (session) + session->CloseIdleConnections(); } void HttpCache::OnExternalCacheHit(const GURL& url, diff --git a/net/http/http_cache.h b/net/http/http_cache.h index 5e29701..e9f0e11 100644 --- a/net/http/http_cache.h +++ b/net/http/http_cache.h @@ -181,6 +181,9 @@ class NET_EXPORT HttpCache : public HttpTransactionFactory, // immediately, but they will not be reusable. This is for debugging. void CloseAllConnections(); + // Close all idle connections. Will close all sockets not in active use. + void CloseIdleConnections(); + // Called whenever an external cache in the system reuses the resource // referred to by |url| and |http_method|. void OnExternalCacheHit(const GURL& url, const std::string& http_method); diff --git a/net/http/http_network_session.cc b/net/http/http_network_session.cc index b52aa107..b5a104d 100644 --- a/net/http/http_network_session.cc +++ b/net/http/http_network_session.cc @@ -94,6 +94,7 @@ void HttpNetworkSession::CloseAllConnections() { void HttpNetworkSession::CloseIdleConnections() { socket_pool_manager_.CloseIdleSockets(); + spdy_session_pool_.CloseIdleSessions(); } } // namespace net diff --git a/net/spdy/spdy_session.h b/net/spdy/spdy_session.h index 4281a20..1a038f8 100644 --- a/net/spdy/spdy_session.h +++ b/net/spdy/spdy_session.h @@ -190,6 +190,11 @@ class NET_EXPORT SpdySession : public base::RefCounted, spdy_session_pool_ = NULL; } + // Returns true if session is not currently active + bool is_active() const { + return !active_streams_.empty(); + } + // Access to the number of active and pending streams. These are primarily // available for testing and diagnostics. size_t num_active_streams() const { return active_streams_.size(); } diff --git a/net/spdy/spdy_session_pool.cc b/net/spdy/spdy_session_pool.cc index d90a1d5..7bac3bc 100644 --- a/net/spdy/spdy_session_pool.cc +++ b/net/spdy/spdy_session_pool.cc @@ -413,4 +413,20 @@ void SpdySessionPool::CloseCurrentSessions() { DCHECK(aliases_.empty()); } +void SpdySessionPool::CloseIdleSessions() { + SpdySessionsMap::const_iterator map_it = sessions_.begin(); + while (map_it != sessions_.end()) { + SpdySessionList* list = map_it->second; + ++map_it; + CHECK(list); + + // Assumes there is only 1 element in the list + SpdySessionList::iterator session_it = list->begin(); + const scoped_refptr& session = *session_it; + CHECK(session); + if (!session->is_active()) + session->CloseSessionOnError(net::ERR_ABORTED, true); + } +} + } // namespace net diff --git a/net/spdy/spdy_session_pool.h b/net/spdy/spdy_session_pool.h index 327e179..3b1ec78 100644 --- a/net/spdy/spdy_session_pool.h +++ b/net/spdy/spdy_session_pool.h @@ -92,6 +92,8 @@ class NET_EXPORT SpdySessionPool // Close only the currently existing SpdySessions. Let any new ones created // continue to live. void CloseCurrentSessions(); + // Close only the idle SpdySessions. + void CloseIdleSessions(); // Removes a SpdySession from the SpdySessionPool. This should only be called // by SpdySession, because otherwise session->state_ is not set to CLOSED. diff --git a/net/spdy/spdy_session_unittest.cc b/net/spdy/spdy_session_unittest.cc index 351b8ed..9a0a2be 100644 --- a/net/spdy/spdy_session_unittest.cc +++ b/net/spdy/spdy_session_unittest.cc @@ -150,6 +150,112 @@ class StreamReleaserCallback : public CallbackRunner > { TestCompletionCallback callback_; }; +// TODO(kristianm): Could also test with more sessions where some are idle, +// and more than one session to a HostPortPair. +TEST_F(SpdySessionTest, CloseIdleSessions) { + SpdySessionDependencies session_deps; + scoped_refptr http_session( + SpdySessionDependencies::SpdyCreateSession(&session_deps)); + SpdySessionPool* spdy_session_pool(http_session->spdy_session_pool()); + + // Set up session 1 + const std::string kTestHost1("http://www.a.com"); + HostPortPair test_host_port_pair1(kTestHost1, 80); + HostPortProxyPair pair1(test_host_port_pair1, ProxyServer::Direct()); + scoped_refptr session1 = + spdy_session_pool->Get(pair1, BoundNetLog()); + scoped_refptr spdy_stream1; + TestCompletionCallback callback1; + GURL url1(kTestHost1); + EXPECT_EQ(OK, session1->CreateStream(url1, + MEDIUM, /* priority, not important */ + &spdy_stream1, + BoundNetLog(), + &callback1)); + + // Set up session 2 + const std::string kTestHost2("http://www.b.com"); + HostPortPair test_host_port_pair2(kTestHost2, 80); + HostPortProxyPair pair2(test_host_port_pair2, ProxyServer::Direct()); + scoped_refptr session2 = + spdy_session_pool->Get(pair2, BoundNetLog()); + scoped_refptr spdy_stream2; + TestCompletionCallback callback2; + GURL url2(kTestHost2); + EXPECT_EQ(OK, session2->CreateStream(url2, + MEDIUM, /* priority, not important */ + &spdy_stream2, + BoundNetLog(), + &callback2)); + + // Set up session 3 + const std::string kTestHost3("http://www.c.com"); + HostPortPair test_host_port_pair3(kTestHost3, 80); + HostPortProxyPair pair3(test_host_port_pair3, ProxyServer::Direct()); + scoped_refptr session3 = + spdy_session_pool->Get(pair3, BoundNetLog()); + scoped_refptr spdy_stream3; + TestCompletionCallback callback3; + GURL url3(kTestHost3); + EXPECT_EQ(OK, session3->CreateStream(url3, + MEDIUM, /* priority, not important */ + &spdy_stream3, + BoundNetLog(), + &callback3)); + + // All sessions are active and not closed + EXPECT_TRUE(session1->is_active()); + EXPECT_FALSE(session1->IsClosed()); + EXPECT_TRUE(session2->is_active()); + EXPECT_FALSE(session2->IsClosed()); + EXPECT_TRUE(session3->is_active()); + EXPECT_FALSE(session3->IsClosed()); + + // Should not do anything, all are active + spdy_session_pool->CloseIdleSessions(); + EXPECT_TRUE(session1->is_active()); + EXPECT_FALSE(session1->IsClosed()); + EXPECT_TRUE(session2->is_active()); + EXPECT_FALSE(session2->IsClosed()); + EXPECT_TRUE(session3->is_active()); + EXPECT_FALSE(session3->IsClosed()); + + // Make sessions 1 and 3 inactive, but keep them open. + // Session 2 still open and active + session1->CloseStream(spdy_stream1->stream_id(), OK); + session3->CloseStream(spdy_stream3->stream_id(), OK); + EXPECT_FALSE(session1->is_active()); + EXPECT_FALSE(session1->IsClosed()); + EXPECT_TRUE(session2->is_active()); + EXPECT_FALSE(session2->IsClosed()); + EXPECT_FALSE(session3->is_active()); + EXPECT_FALSE(session3->IsClosed()); + + // Should close session 1 and 3, 2 should be left open + spdy_session_pool->CloseIdleSessions(); + EXPECT_FALSE(session1->is_active()); + EXPECT_TRUE(session1->IsClosed()); + EXPECT_TRUE(session2->is_active()); + EXPECT_FALSE(session2->IsClosed()); + EXPECT_FALSE(session3->is_active()); + EXPECT_TRUE(session3->IsClosed()); + + // Should not do anything + spdy_session_pool->CloseIdleSessions(); + EXPECT_TRUE(session2->is_active()); + EXPECT_FALSE(session2->IsClosed()); + + // Make 2 not active + session2->CloseStream(spdy_stream2->stream_id(), OK); + EXPECT_FALSE(session2->is_active()); + EXPECT_FALSE(session2->IsClosed()); + + // This should close session 2 + spdy_session_pool->CloseIdleSessions(); + EXPECT_FALSE(session2->is_active()); + EXPECT_TRUE(session2->IsClosed()); +} + // Start with max concurrent streams set to 1. Request two streams. Receive a // settings frame setting max concurrent streams to 2. Have the callback // release the stream, which releases its reference (the last) to the session. -- cgit v1.1