StatusWith<Shard::CommandResponse> ShardRemote::_runCommand(OperationContext* txn, const ReadPreferenceSetting& readPref, const string& dbName, const BSONObj& cmdObj) { const BSONObj cmdWithMaxTimeMS = (isConfig() ? appendMaxTimeToCmdObj(txn, cmdObj) : cmdObj); const auto host = _targeter->findHost(readPref, RemoteCommandTargeter::selectFindHostMaxWaitTime(txn)); if (!host.isOK()) { return host.getStatus(); } RemoteCommandRequest request(host.getValue(), dbName, cmdWithMaxTimeMS, _getMetadataForCommand(readPref), isConfig() ? kConfigCommandTimeout : executor::RemoteCommandRequest::kNoTimeout); StatusWith<RemoteCommandResponse> swResponse = Status(ErrorCodes::InternalError, "Internal error running command"); TaskExecutor* executor = Grid::get(txn)->getExecutorPool()->getFixedExecutor(); auto callStatus = executor->scheduleRemoteCommand( request, [&swResponse](const RemoteCommandCallbackArgs& args) { swResponse = args.response; }); if (!callStatus.isOK()) { return callStatus.getStatus(); } // Block until the command is carried out executor->wait(callStatus.getValue()); updateReplSetMonitor(host.getValue(), swResponse.getStatus()); if (!swResponse.isOK()) { if (swResponse.getStatus().compareCode(ErrorCodes::ExceededTimeLimit)) { LOG(0) << "Operation timed out with status " << swResponse.getStatus(); } return swResponse.getStatus(); } BSONObj responseObj = swResponse.getValue().data.getOwned(); BSONObj responseMetadata = swResponse.getValue().metadata.getOwned(); Status commandStatus = getStatusFromCommandResult(responseObj); Status writeConcernStatus = getWriteConcernStatusFromCommandResult(responseObj); updateReplSetMonitor(host.getValue(), commandStatus); return CommandResponse(std::move(responseObj), std::move(responseMetadata), std::move(commandStatus), std::move(writeConcernStatus)); }
Shard::HostWithResponse ShardRemote::_runCommand(OperationContext* txn, const ReadPreferenceSetting& readPref, const string& dbName, Milliseconds maxTimeMSOverride, const BSONObj& cmdObj) { ReadPreferenceSetting readPrefWithMinOpTime(readPref); if (getId() == "config") { readPrefWithMinOpTime.minOpTime = grid.configOpTime(); } const auto host = _targeter->findHost(txn, readPrefWithMinOpTime); if (!host.isOK()) { return Shard::HostWithResponse(boost::none, host.getStatus()); } const Milliseconds requestTimeout = std::min(txn->getRemainingMaxTimeMillis(), maxTimeMSOverride); const RemoteCommandRequest request( host.getValue(), dbName, appendMaxTimeToCmdObj(maxTimeMSOverride, cmdObj), _appendMetadataForCommand(txn, readPrefWithMinOpTime), txn, requestTimeout < Milliseconds::max() ? requestTimeout : RemoteCommandRequest::kNoTimeout); RemoteCommandResponse swResponse = Status(ErrorCodes::InternalError, "Internal error running command"); TaskExecutor* executor = Grid::get(txn)->getExecutorPool()->getFixedExecutor(); auto callStatus = executor->scheduleRemoteCommand( request, [&swResponse](const RemoteCommandCallbackArgs& args) { swResponse = args.response; }); if (!callStatus.isOK()) { return Shard::HostWithResponse(host.getValue(), callStatus.getStatus()); } // Block until the command is carried out executor->wait(callStatus.getValue()); updateReplSetMonitor(host.getValue(), swResponse.status); if (!swResponse.isOK()) { if (swResponse.status.compareCode(ErrorCodes::ExceededTimeLimit)) { LOG(0) << "Operation timed out with status " << redact(swResponse.status); } return Shard::HostWithResponse(host.getValue(), swResponse.status); } BSONObj responseObj = swResponse.data.getOwned(); BSONObj responseMetadata = swResponse.metadata.getOwned(); Status commandStatus = getStatusFromCommandResult(responseObj); Status writeConcernStatus = getWriteConcernStatusFromCommandResult(responseObj); // Tell the replica set monitor of any errors updateReplSetMonitor(host.getValue(), commandStatus); updateReplSetMonitor(host.getValue(), writeConcernStatus); return Shard::HostWithResponse(host.getValue(), CommandResponse(std::move(responseObj), std::move(responseMetadata), std::move(commandStatus), std::move(writeConcernStatus))); }