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) { 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 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)); }