summaryrefslogtreecommitdiff
path: root/src/mongo/client
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/client')
-rw-r--r--src/mongo/client/authenticate.cpp9
-rw-r--r--src/mongo/client/authenticate.h2
-rw-r--r--src/mongo/client/authenticate_test.cpp2
-rw-r--r--src/mongo/client/dbclient.cpp13
-rw-r--r--src/mongo/client/fetcher.cpp12
-rw-r--r--src/mongo/client/fetcher_test.cpp36
-rw-r--r--src/mongo/client/remote_command_retry_scheduler.cpp2
-rw-r--r--src/mongo/client/remote_command_retry_scheduler_test.cpp61
-rw-r--r--src/mongo/client/remote_command_runner_impl.cpp219
-rw-r--r--src/mongo/client/sasl_client_authenticate_impl.cpp2
10 files changed, 284 insertions, 74 deletions
diff --git a/src/mongo/client/authenticate.cpp b/src/mongo/client/authenticate.cpp
index 224517e00be..7d45da9ef08 100644
--- a/src/mongo/client/authenticate.cpp
+++ b/src/mongo/client/authenticate.cpp
@@ -159,7 +159,7 @@ void authMongoCR(RunCommandHook runCommand, const BSONObj& params, AuthCompletio
// Ensure response was valid
std::string nonce;
- BSONObj nonceResponse = response.getValue().data;
+ BSONObj nonceResponse = response.data;
auto valid = bsonExtractStringField(nonceResponse, "nonce", &nonce);
if (!valid.isOK())
return handler({ErrorCodes::AuthenticationFailed,
@@ -235,7 +235,8 @@ void authX509(RunCommandHook runCommand,
//
bool isFailedAuthOk(const AuthResponse& response) {
- return (response == ErrorCodes::AuthenticationFailed && serverGlobalParams.transitionToAuth);
+ return (response.status == ErrorCodes::AuthenticationFailed &&
+ serverGlobalParams.transitionToAuth);
}
void auth(RunCommandHook runCommand,
@@ -305,9 +306,9 @@ void authenticateClient(const BSONObj& params,
// NOTE: this assumes that runCommand executes synchronously.
asyncAuth(runCommand, params, hostname, clientName, [](AuthResponse response) {
// DBClient expects us to throw in case of an auth error.
- uassertStatusOK(response);
+ uassertStatusOK(response.status);
- auto serverResponse = response.getValue().data;
+ auto serverResponse = response.data;
uassert(ErrorCodes::AuthenticationFailed,
serverResponse["errmsg"].str(),
isOk(serverResponse));
diff --git a/src/mongo/client/authenticate.h b/src/mongo/client/authenticate.h
index 65c649c49c2..6ad596477bf 100644
--- a/src/mongo/client/authenticate.h
+++ b/src/mongo/client/authenticate.h
@@ -43,7 +43,7 @@ class BSONObj;
namespace auth {
-using AuthResponse = StatusWith<executor::RemoteCommandResponse>;
+using AuthResponse = executor::RemoteCommandResponse;
using AuthCompletionHandler = stdx::function<void(AuthResponse)>;
using RunCommandResultHandler = AuthCompletionHandler;
using RunCommandHook =
diff --git a/src/mongo/client/authenticate_test.cpp b/src/mongo/client/authenticate_test.cpp
index 3044da9f6cd..97b876cf814 100644
--- a/src/mongo/client/authenticate_test.cpp
+++ b/src/mongo/client/authenticate_test.cpp
@@ -92,7 +92,7 @@ public:
// Then pop a response and call the handler
ASSERT(!_responses.empty());
- handler(StatusWith<RemoteCommandResponse>(_responses.front()));
+ handler(_responses.front());
_responses.pop();
}
diff --git a/src/mongo/client/dbclient.cpp b/src/mongo/client/dbclient.cpp
index 254a537c255..cbf72c4ae7d 100644
--- a/src/mongo/client/dbclient.cpp
+++ b/src/mongo/client/dbclient.cpp
@@ -445,8 +445,7 @@ void DBClientWithCommands::_auth(const BSONObj& params) {
Milliseconds millis(Date_t::now() - start);
// Hand control back to authenticateClient()
- handler(StatusWith<RemoteCommandResponse>(
- RemoteCommandResponse(data, metadata, millis)));
+ handler({data, metadata, millis});
} catch (...) {
handler(exceptionToStatus());
@@ -713,7 +712,7 @@ private:
/**
* Initializes the wire version of conn, and returns the isMaster reply.
*/
-StatusWith<executor::RemoteCommandResponse> initWireVersion(DBClientConnection* conn) {
+executor::RemoteCommandResponse initWireVersion(DBClientConnection* conn) {
try {
// We need to force the usage of OP_QUERY on this command, even if we have previously
// detected support for OP_COMMAND on a connection. This is necessary to handle the case
@@ -773,16 +772,16 @@ Status DBClientConnection::connect(const HostAndPort& serverAddress) {
auto swIsMasterReply = initWireVersion(this);
if (!swIsMasterReply.isOK()) {
_failed = true;
- return swIsMasterReply.getStatus();
+ return swIsMasterReply.status;
}
// Ensure that the isMaster response is "ok:1".
- auto isMasterStatus = getStatusFromCommandResult(swIsMasterReply.getValue().data);
+ auto isMasterStatus = getStatusFromCommandResult(swIsMasterReply.data);
if (!isMasterStatus.isOK()) {
return isMasterStatus;
}
- auto swProtocolSet = rpc::parseProtocolSetFromIsMasterReply(swIsMasterReply.getValue().data);
+ auto swProtocolSet = rpc::parseProtocolSetFromIsMasterReply(swIsMasterReply.data);
if (!swProtocolSet.isOK()) {
return swProtocolSet.getStatus();
}
@@ -799,7 +798,7 @@ Status DBClientConnection::connect(const HostAndPort& serverAddress) {
}
if (_hook) {
- auto validationStatus = _hook(swIsMasterReply.getValue());
+ auto validationStatus = _hook(swIsMasterReply);
if (!validationStatus.isOK()) {
// Disconnect and mark failed.
_failed = true;
diff --git a/src/mongo/client/fetcher.cpp b/src/mongo/client/fetcher.cpp
index 5aa46e549cd..e2a8bdf2402 100644
--- a/src/mongo/client/fetcher.cpp
+++ b/src/mongo/client/fetcher.cpp
@@ -301,7 +301,7 @@ Status Fetcher::_scheduleGetMore(const BSONObj& cmdObj) {
void Fetcher::_callback(const RemoteCommandCallbackArgs& rcbd, const char* batchFieldName) {
if (!rcbd.response.isOK()) {
- _work(StatusWith<Fetcher::QueryResponse>(rcbd.response.getStatus()), nullptr, nullptr);
+ _work(StatusWith<Fetcher::QueryResponse>(rcbd.response.status), nullptr, nullptr);
_finishCallback();
return;
}
@@ -312,7 +312,7 @@ void Fetcher::_callback(const RemoteCommandCallbackArgs& rcbd, const char* batch
return;
}
- const BSONObj& queryResponseObj = rcbd.response.getValue().data;
+ const BSONObj& queryResponseObj = rcbd.response.data;
Status status = getStatusFromCommandResult(queryResponseObj);
if (!status.isOK()) {
_work(StatusWith<Fetcher::QueryResponse>(status), nullptr, nullptr);
@@ -328,8 +328,8 @@ void Fetcher::_callback(const RemoteCommandCallbackArgs& rcbd, const char* batch
return;
}
- batchData.otherFields.metadata = std::move(rcbd.response.getValue().metadata);
- batchData.elapsedMillis = rcbd.response.getValue().elapsedMillis;
+ batchData.otherFields.metadata = std::move(rcbd.response.metadata);
+ batchData.elapsedMillis = rcbd.response.elapsedMillis.value_or(Milliseconds{0});
{
stdx::lock_guard<stdx::mutex> lk(_mutex);
batchData.first = _first;
@@ -380,10 +380,10 @@ void Fetcher::_sendKillCursors(const CursorId id, const NamespaceString& nss) {
if (id) {
auto logKillCursorsResult = [](const RemoteCommandCallbackArgs& args) {
if (!args.response.isOK()) {
- warning() << "killCursors command task failed: " << args.response.getStatus();
+ warning() << "killCursors command task failed: " << args.response.status;
return;
}
- auto status = getStatusFromCommandResult(args.response.getValue().data);
+ auto status = getStatusFromCommandResult(args.response.data);
if (!status.isOK()) {
warning() << "killCursors command failed: " << status;
}
diff --git a/src/mongo/client/fetcher_test.cpp b/src/mongo/client/fetcher_test.cpp
index b20cb9a099f..26778806b6c 100644
--- a/src/mongo/client/fetcher_test.cpp
+++ b/src/mongo/client/fetcher_test.cpp
@@ -44,6 +44,8 @@ using namespace mongo;
using executor::NetworkInterfaceMock;
using executor::TaskExecutor;
+using ResponseStatus = TaskExecutor::ResponseStatus;
+
const HostAndPort source("localhost", -1);
const BSONObj findCmdObj = BSON("find"
<< "coll");
@@ -61,12 +63,11 @@ public:
void processNetworkResponse(const BSONObj& obj,
ReadyQueueState readyQueueStateAfterProcessing,
FetcherState fetcherStateAfterProcessing);
- void processNetworkResponse(const BSONObj& obj,
- Milliseconds elapsed,
+ void processNetworkResponse(const ResponseStatus,
ReadyQueueState readyQueueStateAfterProcessing,
FetcherState fetcherStateAfterProcessing);
- void processNetworkResponse(ErrorCodes::Error code,
- const std::string& reason,
+ void processNetworkResponse(const BSONObj& obj,
+ Milliseconds elapsed,
ReadyQueueState readyQueueStateAfterProcessing,
FetcherState fetcherStateAfterProcessing);
@@ -148,12 +149,11 @@ void FetcherTest::processNetworkResponse(const BSONObj& obj,
finishProcessingNetworkResponse(readyQueueStateAfterProcessing, fetcherStateAfterProcessing);
}
-void FetcherTest::processNetworkResponse(ErrorCodes::Error code,
- const std::string& reason,
+void FetcherTest::processNetworkResponse(ResponseStatus rs,
ReadyQueueState readyQueueStateAfterProcessing,
FetcherState fetcherStateAfterProcessing) {
executor::NetworkInterfaceMock::InNetworkGuard guard(getNet());
- getNet()->scheduleErrorResponse({code, reason});
+ getNet()->scheduleErrorResponse(rs);
finishProcessingNetworkResponse(readyQueueStateAfterProcessing, fetcherStateAfterProcessing);
}
@@ -373,8 +373,8 @@ TEST_F(FetcherTest, ScheduleButShutdown) {
TEST_F(FetcherTest, FindCommandFailed1) {
ASSERT_OK(fetcher->schedule());
- processNetworkResponse(
- ErrorCodes::BadValue, "bad hint", ReadyQueueState::kEmpty, FetcherState::kInactive);
+ auto rs = ResponseStatus(ErrorCodes::BadValue, "bad hint", Milliseconds(0));
+ processNetworkResponse(rs, ReadyQueueState::kEmpty, FetcherState::kInactive);
ASSERT_EQUALS(ErrorCodes::BadValue, status.code());
ASSERT_EQUALS("bad hint", status.reason());
ASSERT_FALSE(fetcher->inShutdown_forTest());
@@ -939,7 +939,7 @@ TEST_F(FetcherTest, UpdateNextActionAfterSecondBatch) {
ASSERT_EQUALS(cursorId, cursors.front().numberLong());
// Failed killCursors command response should be logged.
- getNet()->scheduleSuccessfulResponse(noi, {BSON("ok" << false), {}});
+ getNet()->scheduleSuccessfulResponse(noi, {BSON("ok" << false), {}, Milliseconds(0)});
getNet()->runReadyNetworkOperations();
}
@@ -1049,12 +1049,10 @@ TEST_F(FetcherTest, FetcherAppliesRetryPolicyToFirstCommandButNotToGetMoreReques
// Retry policy is applied to find command.
const BSONObj doc = BSON("_id" << 1);
- processNetworkResponse(
- ErrorCodes::BadValue, "first", ReadyQueueState::kHasReadyRequests, FetcherState::kActive);
- processNetworkResponse(ErrorCodes::InternalError,
- "second",
- ReadyQueueState::kHasReadyRequests,
- FetcherState::kActive);
+ auto rs = ResponseStatus(ErrorCodes::BadValue, "first", Milliseconds(0));
+ processNetworkResponse(rs, ReadyQueueState::kHasReadyRequests, FetcherState::kActive);
+ rs = ResponseStatus(ErrorCodes::InternalError, "second", Milliseconds(0));
+ processNetworkResponse(rs, ReadyQueueState::kHasReadyRequests, FetcherState::kActive);
processNetworkResponse(BSON("cursor" << BSON("id" << 1LL << "ns"
<< "db.coll"
<< "firstBatch"
@@ -1070,11 +1068,9 @@ TEST_F(FetcherTest, FetcherAppliesRetryPolicyToFirstCommandButNotToGetMoreReques
ASSERT_EQUALS(doc, documents.front());
ASSERT_TRUE(Fetcher::NextAction::kGetMore == nextAction);
+ rs = ResponseStatus(ErrorCodes::OperationFailed, "getMore failed", Milliseconds(0));
// No retry policy for subsequent getMore commands.
- processNetworkResponse(ErrorCodes::OperationFailed,
- "getMore failed",
- ReadyQueueState::kEmpty,
- FetcherState::kInactive);
+ processNetworkResponse(rs, ReadyQueueState::kEmpty, FetcherState::kInactive);
ASSERT_EQUALS(ErrorCodes::OperationFailed, status);
ASSERT_FALSE(fetcher->inShutdown_forTest());
}
diff --git a/src/mongo/client/remote_command_retry_scheduler.cpp b/src/mongo/client/remote_command_retry_scheduler.cpp
index 8c20d0af925..ded4a10d964 100644
--- a/src/mongo/client/remote_command_retry_scheduler.cpp
+++ b/src/mongo/client/remote_command_retry_scheduler.cpp
@@ -207,7 +207,7 @@ Status RemoteCommandRetryScheduler::_schedule_inlock(std::size_t requestCount) {
void RemoteCommandRetryScheduler::_remoteCommandCallback(
const executor::TaskExecutor::RemoteCommandCallbackArgs& rcba, std::size_t requestCount) {
- auto status = rcba.response.getStatus();
+ auto status = rcba.response.status;
if (status.isOK() || status == ErrorCodes::CallbackCanceled ||
requestCount == _retryPolicy->getMaximumAttempts() ||
diff --git a/src/mongo/client/remote_command_retry_scheduler_test.cpp b/src/mongo/client/remote_command_retry_scheduler_test.cpp
index 6e2c70fe9dc..705324f94c5 100644
--- a/src/mongo/client/remote_command_retry_scheduler_test.cpp
+++ b/src/mongo/client/remote_command_retry_scheduler_test.cpp
@@ -48,6 +48,7 @@
namespace {
using namespace mongo;
+using ResponseStatus = executor::TaskExecutor::ResponseStatus;
class CallbackResponseSaver;
@@ -56,8 +57,8 @@ public:
void start(RemoteCommandRetryScheduler* scheduler);
void checkCompletionStatus(RemoteCommandRetryScheduler* scheduler,
const CallbackResponseSaver& callbackResponseSaver,
- const executor::TaskExecutor::ResponseStatus& response);
- void processNetworkResponse(const executor::TaskExecutor::ResponseStatus& response);
+ const ResponseStatus& response);
+ void processNetworkResponse(const ResponseStatus& response);
void runReadyNetworkOperations();
protected:
@@ -76,10 +77,10 @@ public:
*/
void operator()(const executor::TaskExecutor::RemoteCommandCallbackArgs& rcba);
- std::vector<StatusWith<executor::RemoteCommandResponse>> getResponses() const;
+ std::vector<ResponseStatus> getResponses() const;
private:
- std::vector<StatusWith<executor::RemoteCommandResponse>> _responses;
+ std::vector<ResponseStatus> _responses;
};
/**
@@ -119,20 +120,19 @@ void RemoteCommandRetrySchedulerTest::start(RemoteCommandRetryScheduler* schedul
void RemoteCommandRetrySchedulerTest::checkCompletionStatus(
RemoteCommandRetryScheduler* scheduler,
const CallbackResponseSaver& callbackResponseSaver,
- const executor::TaskExecutor::ResponseStatus& response) {
+ const ResponseStatus& response) {
ASSERT_FALSE(scheduler->isActive());
auto responses = callbackResponseSaver.getResponses();
ASSERT_EQUALS(1U, responses.size());
if (response.isOK()) {
- ASSERT_OK(responses.front().getStatus());
- ASSERT_EQUALS(response.getValue(), responses.front().getValue());
+ ASSERT_OK(responses.front().status);
+ ASSERT_EQUALS(response, responses.front());
} else {
- ASSERT_EQUALS(response.getStatus(), responses.front().getStatus());
+ ASSERT_EQUALS(response.status, responses.front().status);
}
}
-void RemoteCommandRetrySchedulerTest::processNetworkResponse(
- const executor::TaskExecutor::ResponseStatus& response) {
+void RemoteCommandRetrySchedulerTest::processNetworkResponse(const ResponseStatus& response) {
auto net = getNet();
executor::NetworkInterfaceMock::InNetworkGuard guard(net);
ASSERT_TRUE(net->hasReadyRequests());
@@ -163,8 +163,7 @@ void CallbackResponseSaver::operator()(
_responses.push_back(rcba.response);
}
-std::vector<StatusWith<executor::RemoteCommandResponse>> CallbackResponseSaver::getResponses()
- const {
+std::vector<ResponseStatus> CallbackResponseSaver::getResponses() const {
return _responses;
}
@@ -327,7 +326,6 @@ TEST_F(RemoteCommandRetrySchedulerTest,
&scheduler, callback, {ErrorCodes::CallbackCanceled, "executor shutdown"});
}
-
TEST_F(RemoteCommandRetrySchedulerTest,
ShuttingDownSchedulerAfterSchedulerStartupInvokesCallbackWithCallbackCanceledError) {
CallbackResponseSaver callback;
@@ -353,10 +351,9 @@ TEST_F(RemoteCommandRetrySchedulerTest, SchedulerInvokesCallbackOnNonRetryableEr
start(&scheduler);
// This should match one of the non-retryable error codes in the policy.
- Status response(ErrorCodes::OperationFailed, "injected error");
-
- processNetworkResponse(response);
- checkCompletionStatus(&scheduler, callback, response);
+ ResponseStatus rs(ErrorCodes::OperationFailed, "injected error", Milliseconds(0));
+ processNetworkResponse(rs);
+ checkCompletionStatus(&scheduler, callback, rs);
}
TEST_F(RemoteCommandRetrySchedulerTest, SchedulerInvokesCallbackOnFirstSuccessfulResponse) {
@@ -368,8 +365,7 @@ TEST_F(RemoteCommandRetrySchedulerTest, SchedulerInvokesCallbackOnFirstSuccessfu
start(&scheduler);
// Elapsed time in response is ignored on successful responses.
- executor::RemoteCommandResponse response(
- BSON("ok" << 1 << "x" << 123), BSON("z" << 456), Milliseconds(100));
+ ResponseStatus response(BSON("ok" << 1 << "x" << 123), BSON("z" << 456), Milliseconds(100));
processNetworkResponse(response);
checkCompletionStatus(&scheduler, callback, response);
@@ -386,11 +382,10 @@ TEST_F(RemoteCommandRetrySchedulerTest, SchedulerIgnoresEmbeddedErrorInSuccessfu
// Scheduler does not parse document in a successful response for embedded errors.
// This is the case with some commands (e.g. find) which do not always return errors using the
// wire protocol.
- executor::RemoteCommandResponse response(
- BSON("ok" << 0 << "code" << int(ErrorCodes::FailedToParse) << "errmsg"
- << "injected error"),
- BSON("z" << 456),
- Milliseconds(100));
+ ResponseStatus response(BSON("ok" << 0 << "code" << int(ErrorCodes::FailedToParse) << "errmsg"
+ << "injected error"),
+ BSON("z" << 456),
+ Milliseconds(100));
processNetworkResponse(response);
checkCompletionStatus(&scheduler, callback, response);
@@ -406,14 +401,15 @@ TEST_F(RemoteCommandRetrySchedulerTest,
&badExecutor, request, stdx::ref(callback), std::move(policy));
start(&scheduler);
- processNetworkResponse({ErrorCodes::HostNotFound, "first"});
+ processNetworkResponse({ErrorCodes::HostNotFound, "first", Milliseconds(0)});
// scheduleRemoteCommand() will fail with ErrorCodes::ShutdownInProgress when trying to send
// third remote command request after processing second failed response.
badExecutor.scheduleRemoteCommandFailPoint = true;
- processNetworkResponse({ErrorCodes::HostNotFound, "second"});
+ processNetworkResponse({ErrorCodes::HostNotFound, "second", Milliseconds(0)});
- checkCompletionStatus(&scheduler, callback, {ErrorCodes::ShutdownInProgress, ""});
+ checkCompletionStatus(
+ &scheduler, callback, {ErrorCodes::ShutdownInProgress, "", Milliseconds(0)});
}
TEST_F(RemoteCommandRetrySchedulerTest,
@@ -427,10 +423,10 @@ TEST_F(RemoteCommandRetrySchedulerTest,
&getExecutor(), request, stdx::ref(callback), std::move(policy));
start(&scheduler);
- processNetworkResponse({ErrorCodes::HostNotFound, "first"});
- processNetworkResponse({ErrorCodes::HostUnreachable, "second"});
+ processNetworkResponse({ErrorCodes::HostNotFound, "first", Milliseconds(0)});
+ processNetworkResponse({ErrorCodes::HostUnreachable, "second", Milliseconds(0)});
- Status response(ErrorCodes::NetworkTimeout, "last");
+ ResponseStatus response(ErrorCodes::NetworkTimeout, "last", Milliseconds(0));
processNetworkResponse(response);
checkCompletionStatus(&scheduler, callback, response);
}
@@ -443,10 +439,9 @@ TEST_F(RemoteCommandRetrySchedulerTest, SchedulerShouldRetryUntilSuccessfulRespo
&getExecutor(), request, stdx::ref(callback), std::move(policy));
start(&scheduler);
- processNetworkResponse({ErrorCodes::HostNotFound, "first"});
+ processNetworkResponse({ErrorCodes::HostNotFound, "first", Milliseconds(0)});
- executor::RemoteCommandResponse response(
- BSON("ok" << 1 << "x" << 123), BSON("z" << 456), Milliseconds(100));
+ ResponseStatus response(BSON("ok" << 1 << "x" << 123), BSON("z" << 456), Milliseconds(100));
processNetworkResponse(response);
checkCompletionStatus(&scheduler, callback, response);
}
diff --git a/src/mongo/client/remote_command_runner_impl.cpp b/src/mongo/client/remote_command_runner_impl.cpp
new file mode 100644
index 00000000000..2eef602d1f9
--- /dev/null
+++ b/src/mongo/client/remote_command_runner_impl.cpp
@@ -0,0 +1,219 @@
+/**
+ * Copyright (C) 2015 MongoDB Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the GNU Affero General Public License in all respects for
+ * all of the code used other than as permitted herein. If you modify file(s)
+ * with this exception, you may extend this exception to your version of the
+ * file(s), but you are not obligated to do so. If you do not wish to do so,
+ * delete this exception statement from your version. If you delete this
+ * exception statement from all source files in the program, then also delete
+ * it in the license file.
+ */
+
+#include "mongo/platform/basic.h"
+
+#include "mongo/client/remote_command_runner_impl.h"
+
+#include "mongo/base/status_with.h"
+#include "mongo/db/namespace_string.h"
+#include "mongo/db/query/cursor_response.h"
+#include "mongo/db/query/getmore_request.h"
+#include "mongo/executor/downconvert_find_and_getmore_commands.h"
+#include "mongo/executor/network_connection_hook.h"
+#include "mongo/rpc/get_status_from_command_result.h"
+#include "mongo/rpc/protocol.h"
+#include "mongo/util/assert_util.h"
+
+namespace mongo {
+namespace {
+
+using executor::RemoteCommandRequest;
+using ResponseStatus = executor::RemoteCommandResponse;
+
+/**
+ * Calculates the timeout for a network operation expiring at "expDate", given
+ * that it is now "nowDate".
+ *
+ * Returns 0ms to indicate no expiration date, a number of milliseconds until "expDate", or
+ * ErrorCodes::ExceededTimeLimit if "expDate" is not later than "nowDate".
+ */
+StatusWith<Milliseconds> getTimeoutMillis(const Date_t expDate, const Date_t nowDate) {
+ if (expDate == RemoteCommandRequest::kNoExpirationDate) {
+ return Milliseconds(0);
+ }
+ if (expDate <= nowDate) {
+ return {ErrorCodes::ExceededTimeLimit,
+ str::stream() << "Went to run command, but it was too late. "
+ "Expiration was set to "
+ << dateToISOStringUTC(expDate)};
+ }
+ return expDate - nowDate;
+}
+
+/**
+ * Peeks at error in cursor. If an error has occurred, converts the {$err: "...", code: N}
+ * cursor error to a Status.
+ */
+Status getStatusFromCursorResult(DBClientCursor& cursor) {
+ BSONObj error;
+ if (!cursor.peekError(&error)) {
+ return Status::OK();
+ }
+
+ BSONElement e = error.getField("code");
+ return Status(e.isNumber() ? ErrorCodes::fromInt(e.numberInt()) : ErrorCodes::UnknownError,
+ getErrField(error).valuestrsafe());
+}
+
+using RequestDownconverter = StatusWith<Message> (*)(const RemoteCommandRequest&);
+using ReplyUpconverter = ResponseStatus (*)(std::int32_t requestId,
+ StringData cursorNamespace,
+ const Message& response);
+
+template <RequestDownconverter downconvertRequest, ReplyUpconverter upconvertReply>
+ResponseStatus runDownconvertedCommand(DBClientConnection* conn,
+ const RemoteCommandRequest& request) {
+ auto swDownconvertedRequest = downconvertRequest(request);
+ if (!swDownconvertedRequest.isOK()) {
+ return swDownconvertedRequest.getStatus();
+ }
+
+ Message requestMsg{std::move(swDownconvertedRequest.getValue())};
+ Message responseMsg;
+
+ try {
+ conn->call(requestMsg, responseMsg, true, nullptr);
+ } catch (...) {
+ return exceptionToStatus();
+ }
+
+ auto messageId = requestMsg.header().getId();
+
+ return upconvertReply(messageId, DbMessage(requestMsg).getns(), responseMsg);
+}
+
+/**
+ * Downconverts the specified find command to a find protocol operation and sends it to the
+ * server on the specified connection.
+ */
+ResponseStatus runDownconvertedFindCommand(DBClientConnection* conn,
+ const RemoteCommandRequest& request) {
+ return runDownconvertedCommand<executor::downconvertFindCommandRequest,
+ executor::upconvertLegacyQueryResponse>(conn, request);
+}
+
+/**
+ * Downconverts the specified getMore command to legacy getMore operation and sends it to the
+ * server on the specified connection.
+ */
+ResponseStatus runDownconvertedGetMoreCommand(DBClientConnection* conn,
+ const RemoteCommandRequest& request) {
+ return runDownconvertedCommand<executor::downconvertGetMoreCommandRequest,
+ executor::upconvertLegacyGetMoreResponse>(conn, request);
+}
+
+} // namespace
+
+RemoteCommandRunnerImpl::RemoteCommandRunnerImpl(
+ int messagingTags, std::unique_ptr<executor::NetworkConnectionHook> hook)
+ : _connPool(messagingTags, std::move(hook)) {}
+
+RemoteCommandRunnerImpl::~RemoteCommandRunnerImpl() {
+ invariant(!_active);
+}
+
+void RemoteCommandRunnerImpl::startup() {
+ _active = true;
+}
+
+void RemoteCommandRunnerImpl::shutdown() {
+ if (!_active) {
+ return;
+ }
+
+ _connPool.closeAllInUseConnections();
+ _active = false;
+}
+
+ResponseStatus RemoteCommandRunnerImpl::runCommand(const RemoteCommandRequest& request) {
+ try {
+ const Date_t requestStartDate = Date_t::now();
+ const auto timeoutMillis = getTimeoutMillis(request.expirationDate, requestStartDate);
+ if (!timeoutMillis.isOK()) {
+ return {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 {std::move(output),
+ std::move(metadata),
+ Milliseconds(requestFinishDate - requestStartDate)};
+ } catch (const DBException& ex) {
+ return {ex.toStatus()};
+ } catch (const std::exception& ex) {
+ return {ErrorCodes::UnknownError,
+ str::stream() << "Sending command " << request.cmdObj << " on database "
+ << request.dbname
+ << " over network to "
+ << request.target.toString()
+ << " received exception "
+ << ex.what()};
+ }
+}
+
+} // namespace mongo
diff --git a/src/mongo/client/sasl_client_authenticate_impl.cpp b/src/mongo/client/sasl_client_authenticate_impl.cpp
index aa4d7e64838..8a06acedb31 100644
--- a/src/mongo/client/sasl_client_authenticate_impl.cpp
+++ b/src/mongo/client/sasl_client_authenticate_impl.cpp
@@ -210,7 +210,7 @@ void asyncSaslConversation(auth::RunCommandHook runCommand,
return handler(std::move(response));
}
- auto serverResponse = response.getValue().data.getOwned();
+ auto serverResponse = response.data.getOwned();
auto code = getStatusFromCommandResult(serverResponse).code();
// Server versions 2.3.2 and earlier may return "ok: 1" with a non-zero