summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormatt dannenberg <matt.dannenberg@10gen.com>2015-02-20 10:42:51 -0500
committermatt dannenberg <matt.dannenberg@10gen.com>2015-03-10 10:32:53 -0400
commit1b64013e01d1af85f9fb49daa565e8dded2c52a3 (patch)
tree902fc246da4f6af291a2e25a8af58e1f35e42fdd
parentf974b0e9639199b3f41dfcb38358859290343c55 (diff)
downloadmongo-1b64013e01d1af85f9fb49daa565e8dded2c52a3.tar.gz
SERVER-16436 cleanup unused connections in the NetworkInterface's ConenctionPool
-rw-r--r--src/mongo/db/repl/network_interface_impl.cpp41
1 files changed, 40 insertions, 1 deletions
diff --git a/src/mongo/db/repl/network_interface_impl.cpp b/src/mongo/db/repl/network_interface_impl.cpp
index 9f4b64d01fd..80b46cd22c5 100644
--- a/src/mongo/db/repl/network_interface_impl.cpp
+++ b/src/mongo/db/repl/network_interface_impl.cpp
@@ -58,6 +58,9 @@ namespace {
const size_t kMinThreads = 1;
const size_t kMaxThreads = 51; // Set to 1 + max repl set size, for heartbeat + wiggle room.
+ const unsigned long long kNeverTooStale = std::numeric_limits<unsigned long long>::max();
+ // 5 Minutes (Note: Must be larger than kMaxConnectionAge below)
+ const long long kCleanUpInterval = 5 * 60 * 1000;
const Seconds kMaxIdleThreadAge(30);
const Seconds kMaxConnectionAge(30);
@@ -75,6 +78,7 @@ namespace {
typedef stdx::list<ConnectionInfo> ConnectionList;
typedef unordered_map<HostAndPort, ConnectionList> HostConnectionMap;
+ typedef std::map<HostAndPort, Date_t> HostLastUsedMap;
/**
* RAII class for connections from the pool. To use the connection pool, instantiate one of
@@ -159,6 +163,11 @@ namespace {
bool shouldKeepConnection(Date_t now, const ConnectionInfo& connInfo) const;
/**
+ * Apply cleanup policy to any host(s) not active in the last kCleanupInterval milliseconds.
+ */
+ void cleanUpStaleHosts_inlock(Date_t now);
+
+ /**
* Implementation of cleanUpOlderThan which assumes that _mutex is already held.
*/
void cleanUpOlderThan_inlock(Date_t now);
@@ -183,6 +192,12 @@ namespace {
// List of non-idle connections.
ConnectionList _inUseConnections;
+
+ // Map of HostAndPorts to when they were last used.
+ HostLastUsedMap _lastUsedHosts;
+
+ // Time representing when the connections were last cleaned.
+ Date_t _lastCleanUpTime;
};
/**
@@ -209,7 +224,7 @@ namespace {
return _connInfo->conn;
}
- NetworkInterfaceImpl::ConnectionPool::ConnectionPool() {}
+ NetworkInterfaceImpl::ConnectionPool::ConnectionPool() : _lastCleanUpTime(0ULL) {}
NetworkInterfaceImpl::ConnectionPool::~ConnectionPool() {
cleanUpOlderThan(Date_t(~0ULL));
@@ -271,17 +286,40 @@ namespace {
}
}
+ void NetworkInterfaceImpl::ConnectionPool::cleanUpStaleHosts_inlock(Date_t now) {
+ if (now > _lastCleanUpTime + kCleanUpInterval) {
+ for (HostLastUsedMap::iterator itr = _lastUsedHosts.begin();
+ itr != _lastUsedHosts.end();
+ itr++) {
+ if (itr->second <= _lastCleanUpTime) {
+ ConnectionList connList = _connections.find(itr->first)->second;
+ cleanUpOlderThan_inlock(now, &connList);
+ invariant(connList.empty());
+ itr->second = Date_t(kNeverTooStale);
+ }
+ }
+ _lastCleanUpTime = now;
+ }
+ }
+
NetworkInterfaceImpl::ConnectionPool::ConnectionList::iterator
NetworkInterfaceImpl::ConnectionPool::acquireConnection(
const HostAndPort& target,
Date_t now,
Milliseconds timeout) {
boost::unique_lock<boost::mutex> lk(_mutex);
+
+ // Clean up connections on stale/unused hosts
+ cleanUpStaleHosts_inlock(now);
+
for (HostConnectionMap::iterator hostConns;
((hostConns = _connections.find(target)) != _connections.end());) {
+ // Clean up the requested host to remove stale/unused connections
cleanUpOlderThan_inlock(now, &hostConns->second);
if (hostConns->second.empty()) {
+ // prevent host from causing unnecessary cleanups
+ _lastUsedHosts[hostConns->first] = Date_t(kNeverTooStale);
break;
}
_inUseConnections.splice(_inUseConnections.begin(),
@@ -341,6 +379,7 @@ namespace {
ConnectionList& hostConns = _connections[iter->conn->getServerHostAndPort()];
cleanUpOlderThan_inlock(now, &hostConns);
hostConns.splice(hostConns.begin(), _inUseConnections, iter);
+ _lastUsedHosts[iter->conn->getServerHostAndPort()] = now;
}
void NetworkInterfaceImpl::ConnectionPool::destroyConnection(ConnectionList::iterator iter) {