ResponseStatus NetworkInterfaceImpl::runCommand( const ReplicationExecutor::RemoteCommandRequest& request) { try { BSONObj output; StatusWith<int> timeoutStatus = getTimeoutMillis(request.expirationDate, now()); if (!timeoutStatus.isOK()) return ResponseStatus(timeoutStatus.getStatus()); int timeout = timeoutStatus.getValue(); Timer timer; ScopedDbConnection conn(request.target.toString(), timeout); conn->runCommand(request.dbname, request.cmdObj, output); conn.done(); return ResponseStatus(Response(output, Milliseconds(timer.millis()))); } catch (const DBException& ex) { return ResponseStatus(ex.toStatus()); } catch (const std::exception& ex) { return ResponseStatus( ErrorCodes::UnknownError, mongoutils::str::stream() << "Sending command " << request.cmdObj << " on database " << request.dbname << " over network to " << request.target.toString() << " received exception " << ex.what()); } }
ResponseStatus NetworkInterfaceMock::runCommand( const ReplicationExecutor::RemoteCommandRequest& request) { boost::unique_lock<boost::mutex> lk(_mutex); Date_t wakeupTime = _now + _simulatedNetworkLatencyMillis; while (wakeupTime < _now) { _timeElapsed.wait(lk); } StatusWith<int> toStatus = getTimeoutMillis(request.expirationDate, _now); if (!toStatus.isOK()) return ResponseStatus(toStatus.getStatus()); lk.unlock(); return _helper(request); }
StatusWith<RemoteCommandResponse> RemoteCommandRunnerImpl::runCommand( const RemoteCommandRequest& request) { try { const Date_t requestStartDate = Date_t::now(); const auto timeoutMillis = getTimeoutMillis(request.expirationDate, requestStartDate); if (!timeoutMillis.isOK()) { return StatusWith<RemoteCommandResponse>(timeoutMillis.getStatus()); } ConnectionPool::ConnectionPtr conn( &_connPool, request.target, requestStartDate, timeoutMillis.getValue()); BSONObj output; BSONObj metadata; // If remote server does not support either find or getMore commands, down convert // to using DBClientInterface::query()/getMore(). // Perform down conversion based on wire protocol version. // 'commandName' will be an empty string if the command object is an empty BSON // document. StringData commandName = request.cmdObj.firstElement().fieldNameStringData(); const auto isFindCmd = commandName == QueryRequest::kFindCommandName; const auto isGetMoreCmd = commandName == GetMoreRequest::kGetMoreCommandName; const auto isFindOrGetMoreCmd = isFindCmd || isGetMoreCmd; // We are using the wire version to check if we need to downconverting find/getMore // requests because coincidentally, the find/getMore command is only supported by // servers that also accept OP_COMMAND. bool supportsFindAndGetMoreCommands = rpc::supportsWireVersionForOpCommandInMongod( conn.get()->getMinWireVersion(), conn.get()->getMaxWireVersion()); if (!isFindOrGetMoreCmd || supportsFindAndGetMoreCommands) { rpc::UniqueReply commandResponse = conn.get()->runCommandWithMetadata(request.dbname, request.cmdObj.firstElementFieldName(), request.metadata, request.cmdObj); output = commandResponse->getCommandReply().getOwned(); metadata = commandResponse->getMetadata().getOwned(); } else if (isFindCmd) { return runDownconvertedFindCommand(conn.get(), request); } else if (isGetMoreCmd) { return runDownconvertedGetMoreCommand(conn.get(), request); } const Date_t requestFinishDate = Date_t::now(); conn.done(requestFinishDate); return StatusWith<RemoteCommandResponse>( RemoteCommandResponse(std::move(output), std::move(metadata), Milliseconds(requestFinishDate - requestStartDate))); } catch (const DBException& ex) { return StatusWith<RemoteCommandResponse>(ex.toStatus()); } catch (const std::exception& ex) { return StatusWith<RemoteCommandResponse>( ErrorCodes::UnknownError, str::stream() << "Sending command " << request.cmdObj << " on database " << request.dbname << " over network to " << request.target.toString() << " received exception " << ex.what()); } }