void ConnectionPool::_cleanUpOlderThan_inlock(Date_t now) { HostConnectionMap::iterator hostConns = _connections.begin(); while (hostConns != _connections.end()) { _cleanUpOlderThan_inlock(now, &hostConns->second); if (hostConns->second.empty()) { _connections.erase(hostConns++); } else { ++hostConns; } } }
void ConnectionPool::releaseConnection(ConnectionList::iterator iter, const Date_t now) { boost::lock_guard<boost::mutex> lk(_mutex); if (!_shouldKeepConnection(now, *iter)) { _destroyConnection_inlock(&_inUseConnections, iter); return; } ConnectionList& hostConns = _connections[iter->conn->getServerHostAndPort()]; _cleanUpOlderThan_inlock(now, &hostConns); hostConns.splice(hostConns.begin(), _inUseConnections, iter); _lastUsedHosts[iter->conn->getServerHostAndPort()] = now; }
void ConnectionPool::cleanUpOlderThan(Date_t now) { stdx::lock_guard<stdx::mutex> lk(_mutex); HostConnectionMap::iterator hostConns = _connections.begin(); while (hostConns != _connections.end()) { _cleanUpOlderThan_inlock(now, &hostConns->second); if (hostConns->second.empty()) { _connections.erase(hostConns++); } else { ++hostConns; } } }
void 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 = kNeverTooStale; } } _lastCleanUpTime = now; } }
void ConnectionPool::cleanUpOlderThan(Date_t now) { boost::lock_guard<boost::mutex> lk(_mutex); _cleanUpOlderThan_inlock(now); }
ConnectionPool::ConnectionList::iterator 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] = kNeverTooStale; break; } _inUseConnections.splice(_inUseConnections.begin(), hostConns->second, hostConns->second.begin()); const ConnectionList::iterator candidate = _inUseConnections.begin(); lk.unlock(); try { if (candidate->conn->isStillConnected()) { // setSoTimeout takes a double representing the number of seconds for send and // receive timeouts. Thus, we must take count() and divide by // 1000.0 to get the number of seconds with a fractional part. candidate->conn->setSoTimeout(timeout.count() / 1000.0); return candidate; } } catch (...) { lk.lock(); _destroyConnection_inlock(&_inUseConnections, candidate); throw; } lk.lock(); _destroyConnection_inlock(&_inUseConnections, candidate); } // No idle connection in the pool; make a new one. lk.unlock(); std::auto_ptr<DBClientConnection> conn(new DBClientConnection); // setSoTimeout takes a double representing the number of seconds for send and receive // timeouts. Thus, we must take count() and divide by 1000.0 to get the number // of seconds with a fractional part. conn->setSoTimeout(timeout.count() / 1000.0); std::string errmsg; uassert(28640, str::stream() << "Failed attempt to connect to " << target.toString() << "; " << errmsg, conn->connect(target, errmsg)); conn->port().tag |= _messagingPortTags; if (getGlobalAuthorizationManager()->isAuthEnabled()) { uassert(ErrorCodes::AuthenticationFailed, "Missing credentials for authenticating as internal user", isInternalAuthSet()); conn->auth(getInternalUserAuthParamsWithFallback()); } lk.lock(); return _inUseConnections.insert(_inUseConnections.begin(), ConnectionInfo(conn.release(), now)); }
ConnectionPool::ConnectionList::iterator ConnectionPool::acquireConnection( const HostAndPort& target, Date_t now, Milliseconds timeout) { stdx::unique_lock<stdx::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] = kNeverTooStale; break; } _inUseConnections.splice( _inUseConnections.begin(), hostConns->second, hostConns->second.begin()); const ConnectionList::iterator candidate = _inUseConnections.begin(); lk.unlock(); try { if (candidate->conn->isStillConnected()) { // setSoTimeout takes a double representing the number of seconds for send and // receive timeouts. Thus, we must take count() and divide by // 1000.0 to get the number of seconds with a fractional part. candidate->conn->setSoTimeout(timeout.count() / 1000.0); return candidate; } } catch (...) { lk.lock(); _destroyConnection_inlock(&_inUseConnections, candidate); throw; } lk.lock(); _destroyConnection_inlock(&_inUseConnections, candidate); } // No idle connection in the pool; make a new one. lk.unlock(); std::unique_ptr<DBClientConnection> conn(new DBClientConnection()); // setSoTimeout takes a double representing the number of seconds for send and receive // timeouts. Thus, we must take count() and divide by 1000.0 to get the number // of seconds with a fractional part. conn->setSoTimeout(timeout.count() / 1000.0); if (_hook) { uassertStatusOK( conn->connect(target, [this, &target](const executor::RemoteCommandResponse& isMasterReply) { return _hook->validateHost(target, isMasterReply); })); auto postConnectRequest = uassertStatusOK(_hook->makeRequest(target)); // We might not have a postConnectRequest if (postConnectRequest != boost::none) { auto start = Date_t::now(); auto reply = conn->runCommandWithMetadata(postConnectRequest->dbname, postConnectRequest->cmdObj.firstElementFieldName(), postConnectRequest->metadata, postConnectRequest->cmdObj); auto rcr = executor::RemoteCommandResponse(reply->getCommandReply().getOwned(), reply->getMetadata().getOwned(), Date_t::now() - start); uassertStatusOK(_hook->handleReply(target, std::move(rcr))); } } else { uassertStatusOK(conn->connect(target)); } conn->port().tag |= _messagingPortTags; if (getGlobalAuthorizationManager()->isAuthEnabled()) { uassert(ErrorCodes::AuthenticationFailed, "Missing credentials for authenticating as internal user", isInternalAuthSet()); conn->auth(getInternalUserAuthParamsWithFallback()); } lk.lock(); return _inUseConnections.insert(_inUseConnections.begin(), ConnectionInfo(conn.release(), now)); }
ConnectionPool::ConnectionList::iterator ConnectionPool::acquireConnection( const HostAndPort& target, Date_t now, Milliseconds timeout) { stdx::unique_lock<stdx::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] = kNeverTooStale; break; } _inUseConnections.splice( _inUseConnections.begin(), hostConns->second, hostConns->second.begin()); const ConnectionList::iterator candidate = _inUseConnections.begin(); lk.unlock(); try { if (candidate->conn->isStillConnected()) { // setSoTimeout takes a double representing the number of seconds for send and // receive timeouts. Thus, we must express 'timeout' in milliseconds and divide by // 1000.0 to get the number of seconds with a fractional part. candidate->conn->setSoTimeout(durationCount<Milliseconds>(timeout) / 1000.0); return candidate; } } catch (...) { lk.lock(); _destroyConnection_inlock(&_inUseConnections, candidate); throw; } lk.lock(); _destroyConnection_inlock(&_inUseConnections, candidate); } // No idle connection in the pool; make a new one. lk.unlock(); std::unique_ptr<DBClientConnection> conn; if (_hook) { conn.reset(new DBClientConnection( false, // auto reconnect 0, // socket timeout {}, // MongoURI [this, target](const executor::RemoteCommandResponse& isMasterReply) { return _hook->validateHost(target, BSONObj(), isMasterReply); })); } else { conn.reset(new DBClientConnection()); } // setSoTimeout takes a double representing the number of seconds for send and receive // timeouts. Thus, we must express 'timeout' in milliseconds and divide by 1000.0 to get // the number of seconds with a fractional part. conn->setSoTimeout(durationCount<Milliseconds>(timeout) / 1000.0); uassertStatusOK(conn->connect(target, StringData())); conn->setTags(_messagingPortTags); if (isInternalAuthSet()) { conn->auth(getInternalUserAuthParams()); } if (_hook) { auto postConnectRequest = uassertStatusOK(_hook->makeRequest(target)); // We might not have a postConnectRequest if (postConnectRequest != boost::none) { auto start = Date_t::now(); auto reply = conn->runCommand(OpMsgRequest::fromDBAndBody(postConnectRequest->dbname, postConnectRequest->cmdObj, postConnectRequest->metadata)); auto rcr = executor::RemoteCommandResponse(reply->getCommandReply().getOwned(), Date_t::now() - start); uassertStatusOK(_hook->handleReply(target, std::move(rcr))); } } lk.lock(); return _inUseConnections.insert(_inUseConnections.begin(), ConnectionInfo(conn.release(), now)); }