| Index: net/spdy/spdy_session_pool.cc
|
| diff --git a/net/spdy/spdy_session_pool.cc b/net/spdy/spdy_session_pool.cc
|
| index 308a80b1e7175cefa941b7c3f2b4a7f55df6f586..fd0c66523daaa6d2779abb30c8d2b56ced87e432 100644
|
| --- a/net/spdy/spdy_session_pool.cc
|
| +++ b/net/spdy/spdy_session_pool.cc
|
| @@ -107,7 +107,7 @@ base::WeakPtr<SpdySession> SpdySessionPool::CreateAvailableSessionFromSocket(
|
|
|
| base::WeakPtr<SpdySession> available_session = new_session->GetWeakPtr();
|
| sessions_.insert(new_session.release());
|
| - MapKeyToAvailableSession(key, available_session);
|
| + MapKeyToAvailableSession(key, available_session, /* ip_pooled = */ false);
|
|
|
| net_log.AddEvent(
|
| NetLogEventType::HTTP2_SESSION_POOL_IMPORTED_SESSION_FROM_SOCKET,
|
| @@ -130,6 +130,7 @@ base::WeakPtr<SpdySession> SpdySessionPool::CreateAvailableSessionFromSocket(
|
| base::WeakPtr<SpdySession> SpdySessionPool::FindAvailableSession(
|
| const SpdySessionKey& key,
|
| const GURL& url,
|
| + bool enable_ip_based_pooling,
|
| const NetLogWithSource& net_log) {
|
| UnclaimedPushedStreamMap::iterator url_it =
|
| unclaimed_pushed_streams_.find(url);
|
| @@ -169,6 +170,9 @@ base::WeakPtr<SpdySession> SpdySessionPool::FindAvailableSession(
|
| NetLogEventType::HTTP2_SESSION_POOL_FOUND_EXISTING_SESSION,
|
| it->second->net_log().source().ToEventParametersCallback());
|
| } else {
|
| + if (!enable_ip_based_pooling)
|
| + return base::WeakPtr<SpdySession>();
|
| +
|
| UMA_HISTOGRAM_ENUMERATION("Net.SpdySessionGet",
|
| FOUND_EXISTING_FROM_IP_POOL,
|
| SPDY_SESSION_GET_MAX);
|
| @@ -180,6 +184,9 @@ base::WeakPtr<SpdySession> SpdySessionPool::FindAvailableSession(
|
| return it->second;
|
| }
|
|
|
| + if (!enable_ip_based_pooling)
|
| + return base::WeakPtr<SpdySession>();
|
| +
|
| // Look up IP addresses from resolver cache.
|
| HostResolver::RequestInfo resolve_info(key.host_port_pair());
|
| AddressList addresses;
|
| @@ -231,7 +238,7 @@ base::WeakPtr<SpdySession> SpdySessionPool::FindAvailableSession(
|
| NetLogEventType::HTTP2_SESSION_POOL_FOUND_EXISTING_SESSION_FROM_IP_POOL,
|
| available_session->net_log().source().ToEventParametersCallback());
|
| // Add this session to the map so that we can find it next time.
|
| - MapKeyToAvailableSession(key, available_session);
|
| + MapKeyToAvailableSession(key, available_session, /* ip_pooled = */ true);
|
| available_session->AddPooledAlias(key);
|
| return available_session;
|
| }
|
| @@ -241,12 +248,15 @@ base::WeakPtr<SpdySession> SpdySessionPool::FindAvailableSession(
|
|
|
| void SpdySessionPool::MakeSessionUnavailable(
|
| const base::WeakPtr<SpdySession>& available_session) {
|
| - UnmapKey(available_session->spdy_session_key());
|
| + // Remove the entry that was added by CreateAvailableSessionFromSocket() under
|
| + // |available_session|'s proper key.
|
| + UnmapKey(available_session->spdy_session_key(), /* ip_pooled = */ false);
|
| RemoveAliases(available_session->spdy_session_key());
|
| const std::set<SpdySessionKey>& aliases = available_session->pooled_aliases();
|
| for (std::set<SpdySessionKey>::const_iterator it = aliases.begin();
|
| it != aliases.end(); ++it) {
|
| - UnmapKey(*it);
|
| + // Remove all the pooled entries that map alias keys to this session.
|
| + UnmapKey(*it, /* ip_pooled = */ true);
|
| RemoveAliases(*it);
|
| }
|
| DCHECK(!IsSessionAvailable(available_session));
|
| @@ -427,6 +437,187 @@ void SpdySessionPool::DumpMemoryStats(
|
| cert_size);
|
| }
|
|
|
| +template <class T, class U>
|
| +SpdySessionPool::AvailableSessionMap::Iterator<T, U>::Iterator()
|
| + : ip_pooled_(false), session_map_(nullptr) {}
|
| +
|
| +template <class T, class U>
|
| +SpdySessionPool::AvailableSessionMap::Iterator<T, U>::Iterator(
|
| + const Iterator& other)
|
| + : iterator_(other.iterator_),
|
| + ip_pooled_(other.ip_pooled_),
|
| + session_map_(other.session_map_) {}
|
| +
|
| +template <class T, class U>
|
| +void SpdySessionPool::AvailableSessionMap::Iterator<T, U>::operator=(
|
| + const Iterator& other) {
|
| + iterator_ = other.iterator_;
|
| + ip_pooled_ = other.ip_pooled_;
|
| + session_map_ = other.session_map_;
|
| +}
|
| +
|
| +template <class T, class U>
|
| +SpdySessionPool::AvailableSessionMap::Iterator<T, U>::~Iterator() {}
|
| +
|
| +// Must return a dereferencable iterator unless both maps are empty.
|
| +// static
|
| +template <class T, class U>
|
| +SpdySessionPool::AvailableSessionMap::Iterator<T, U>
|
| +SpdySessionPool::AvailableSessionMap::Iterator<T, U>::begin(U* session_map) {
|
| + if (session_map->non_ip_pooled_sessions_.empty()) {
|
| + // If |ip_pooled_sessions_| is not empty, this is deferencable.
|
| + // If |ip_pooled_sessions_| is empty, then |begin() == end()|,
|
| + // therefore the return value represents AvailableSessionMap::end().
|
| + return SpdySessionPool::AvailableSessionMap::Iterator<T, U>(
|
| + session_map->ip_pooled_sessions_.begin(), /* ip_pooled = */ true,
|
| + session_map);
|
| + }
|
| +
|
| + // |non_ip_pooled_sessions_| is not empty, therefore this is dereferencable.
|
| + return SpdySessionPool::AvailableSessionMap::Iterator<T, U>(
|
| + session_map->non_ip_pooled_sessions_.begin(), /* ip_pooled = */ false,
|
| + session_map);
|
| +}
|
| +
|
| +// static
|
| +template <class T, class U>
|
| +SpdySessionPool::AvailableSessionMap::Iterator<T, U>
|
| +SpdySessionPool::AvailableSessionMap::Iterator<T, U>::end(U* session_map) {
|
| + return SpdySessionPool::AvailableSessionMap::Iterator<T, U>(
|
| + session_map->ip_pooled_sessions_.end(), /* ip_pooled = */ true,
|
| + session_map);
|
| +}
|
| +
|
| +template <class T, class U>
|
| +bool SpdySessionPool::AvailableSessionMap::Iterator<T, U>::operator==(
|
| + const SpdySessionPool::AvailableSessionMap::Iterator<T, U>& other) const {
|
| + // Compare |iterator_| last, because comparing iterators from different
|
| + // containers results in a runtime error when using debug_map.
|
| + return session_map_ == other.session_map_ && ip_pooled_ == other.ip_pooled_ &&
|
| + iterator_ == other.iterator_;
|
| +}
|
| +
|
| +template <class T, class U>
|
| +bool SpdySessionPool::AvailableSessionMap::Iterator<T, U>::operator!=(
|
| + const SpdySessionPool::AvailableSessionMap::Iterator<T, U>& other) const {
|
| + return !(*this == other);
|
| +}
|
| +
|
| +template <class T, class U>
|
| +T& SpdySessionPool::AvailableSessionMap::Iterator<T, U>::operator->() {
|
| + return iterator_;
|
| +}
|
| +
|
| +template <class T, class U>
|
| +SpdySessionPool::AvailableSessionMap::Iterator<T, U>&
|
| + SpdySessionPool::AvailableSessionMap::Iterator<T, U>::operator++() {
|
| + // end() is a non-incrementable iterator.
|
| + DCHECK(*this != session_map_->end());
|
| +
|
| + ++iterator_;
|
| +
|
| + // If Iterator is already pointing to an element of |ip_pooled_sessions_|,
|
| + // then simply incrementing it will get to the next element.
|
| + if (ip_pooled_)
|
| + return *this;
|
| +
|
| + // When the past-the-end iterator is reached in |non_ip_pooled_sessions_|, the
|
| + // Iterator should start iterating through elements of |ip_pooled_sessions_|,
|
| + // because every Iterator starting from begin() until end() is reached has to
|
| + // be dereferencable.
|
| + if (iterator_ == session_map_->non_ip_pooled_sessions_.end()) {
|
| + // This gives the correct result even if |ip_pooled_sessions_| is empty: in
|
| + // that case ip_pooled_sessions_.begin() is the same as
|
| + // ip_pooled_sessions_.end(), which yields the internal representation of
|
| + // available_session_map.end().
|
| + iterator_ = session_map_->ip_pooled_sessions_.begin();
|
| + ip_pooled_ = true;
|
| + }
|
| +
|
| + return *this;
|
| +}
|
| +
|
| +template <class T, class U>
|
| +SpdySessionPool::AvailableSessionMap::Iterator<T, U>::Iterator(T iterator,
|
| + bool ip_pooled,
|
| + U* session_map)
|
| + : iterator_(iterator), ip_pooled_(ip_pooled), session_map_(session_map) {}
|
| +
|
| +SpdySessionPool::AvailableSessionMap::AvailableSessionMap() {}
|
| +SpdySessionPool::AvailableSessionMap::~AvailableSessionMap() {}
|
| +
|
| +SpdySessionPool::AvailableSessionMap::iterator
|
| +SpdySessionPool::AvailableSessionMap::begin() {
|
| + return SpdySessionPool::AvailableSessionMap::Iterator<
|
| + MapType::iterator, AvailableSessionMap>::begin(this);
|
| +}
|
| +
|
| +SpdySessionPool::AvailableSessionMap::iterator
|
| +SpdySessionPool::AvailableSessionMap::end() {
|
| + return SpdySessionPool::AvailableSessionMap::Iterator<
|
| + MapType::iterator, AvailableSessionMap>::end(this);
|
| +}
|
| +
|
| +SpdySessionPool::AvailableSessionMap::const_iterator
|
| +SpdySessionPool::AvailableSessionMap::begin() const {
|
| + return SpdySessionPool::AvailableSessionMap::Iterator<
|
| + MapType::const_iterator, const AvailableSessionMap>::begin(this);
|
| +}
|
| +
|
| +SpdySessionPool::AvailableSessionMap::const_iterator
|
| +SpdySessionPool::AvailableSessionMap::end() const {
|
| + return SpdySessionPool::AvailableSessionMap::Iterator<
|
| + MapType::const_iterator, const AvailableSessionMap>::end(this);
|
| +}
|
| +
|
| +bool SpdySessionPool::AvailableSessionMap::empty() const {
|
| + return non_ip_pooled_sessions_.empty() && ip_pooled_sessions_.empty();
|
| +}
|
| +
|
| +SpdySessionPool::AvailableSessionMap::iterator
|
| +SpdySessionPool::AvailableSessionMap::find(const key_type& key) {
|
| + MapType::iterator it = non_ip_pooled_sessions_.find(key);
|
| + if (it != non_ip_pooled_sessions_.end())
|
| + return SpdySessionPool::AvailableSessionMap::Iterator<
|
| + MapType::iterator, SpdySessionPool::AvailableSessionMap>(
|
| + it,
|
| + /* ip_pooled = */ false, this);
|
| +
|
| + it = ip_pooled_sessions_.find(key);
|
| + // If |it == ip_pooled_sessions_.end()|, then this is the internal
|
| + // representation of AvailableSessionMap::end().
|
| + return SpdySessionPool::AvailableSessionMap::Iterator<
|
| + MapType::iterator, SpdySessionPool::AvailableSessionMap>(
|
| + it, /* ip_pooled = */ true, this);
|
| +}
|
| +
|
| +void SpdySessionPool::AvailableSessionMap::insert(const value_type& value,
|
| + bool ip_pooled) {
|
| + // A session is non IP pooled with respect to the key
|
| + // iff the key matches the session's proper key.
|
| + CHECK_EQ(!ip_pooled, value.first.Equals(value.second->spdy_session_key()));
|
| +
|
| + // There must not already be an entry with key |value.first| in the map.
|
| + std::pair<MapType::iterator, bool> result =
|
| + ip_pooled ? ip_pooled_sessions_.insert(value)
|
| + : non_ip_pooled_sessions_.insert(value);
|
| + CHECK(result.second);
|
| +}
|
| +
|
| +void SpdySessionPool::AvailableSessionMap::erase(const key_type& key,
|
| + bool ip_pooled) {
|
| + // |key| must exist in the map.
|
| + if (ip_pooled) {
|
| + MapType::iterator it = ip_pooled_sessions_.find(key);
|
| + CHECK(it != ip_pooled_sessions_.end());
|
| + ip_pooled_sessions_.erase(it);
|
| + } else {
|
| + MapType::iterator it = non_ip_pooled_sessions_.find(key);
|
| + CHECK(it != non_ip_pooled_sessions_.end());
|
| + non_ip_pooled_sessions_.erase(it);
|
| + }
|
| +}
|
| +
|
| bool SpdySessionPool::IsSessionAvailable(
|
| const base::WeakPtr<SpdySession>& session) const {
|
| for (AvailableSessionMap::const_iterator it = available_sessions_.begin();
|
| @@ -439,11 +630,10 @@ bool SpdySessionPool::IsSessionAvailable(
|
|
|
| void SpdySessionPool::MapKeyToAvailableSession(
|
| const SpdySessionKey& key,
|
| - const base::WeakPtr<SpdySession>& session) {
|
| + const base::WeakPtr<SpdySession>& session,
|
| + bool ip_pooled) {
|
| DCHECK(base::ContainsKey(sessions_, session.get()));
|
| - std::pair<AvailableSessionMap::iterator, bool> result =
|
| - available_sessions_.insert(std::make_pair(key, session));
|
| - CHECK(result.second);
|
| + available_sessions_.insert(std::make_pair(key, session), ip_pooled);
|
| }
|
|
|
| SpdySessionPool::AvailableSessionMap::iterator
|
| @@ -452,10 +642,8 @@ SpdySessionPool::LookupAvailableSessionByKey(
|
| return available_sessions_.find(key);
|
| }
|
|
|
| -void SpdySessionPool::UnmapKey(const SpdySessionKey& key) {
|
| - AvailableSessionMap::iterator it = LookupAvailableSessionByKey(key);
|
| - CHECK(it != available_sessions_.end());
|
| - available_sessions_.erase(it);
|
| +void SpdySessionPool::UnmapKey(const SpdySessionKey& key, bool ip_pooled) {
|
| + available_sessions_.erase(key, ip_pooled);
|
| }
|
|
|
| void SpdySessionPool::RemoveAliases(const SpdySessionKey& key) {
|
|
|