summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/mongo/client/SConscript1
-rw-r--r--src/mongo/client/remote_command_runner_impl.cpp51
-rw-r--r--src/mongo/db/query/getmore_request.cpp7
-rw-r--r--src/mongo/db/query/getmore_request.h2
-rw-r--r--src/mongo/db/query/lite_parsed_query.cpp7
-rw-r--r--src/mongo/db/query/lite_parsed_query.h2
-rw-r--r--src/mongo/rpc/protocol.cpp12
-rw-r--r--src/mongo/rpc/protocol.h5
8 files changed, 57 insertions, 30 deletions
diff --git a/src/mongo/client/SConscript b/src/mongo/client/SConscript
index 0b2d9cf7805..51c93d81ae9 100644
--- a/src/mongo/client/SConscript
+++ b/src/mongo/client/SConscript
@@ -118,6 +118,7 @@ env.Library(
'$BUILD_DIR/mongo/db/query/command_request_response',
'$BUILD_DIR/mongo/db/query/lite_parsed_query',
'$BUILD_DIR/mongo/rpc/metadata',
+ '$BUILD_DIR/mongo/rpc/protocol',
]
)
diff --git a/src/mongo/client/remote_command_runner_impl.cpp b/src/mongo/client/remote_command_runner_impl.cpp
index 6e363240a7a..88742d1e61f 100644
--- a/src/mongo/client/remote_command_runner_impl.cpp
+++ b/src/mongo/client/remote_command_runner_impl.cpp
@@ -35,6 +35,7 @@
#include "mongo/db/query/cursor_responses.h"
#include "mongo/db/query/getmore_request.h"
#include "mongo/rpc/get_status_from_command_result.h"
+#include "mongo/rpc/protocol.h"
#include "mongo/base/status_with.h"
#include "mongo/util/assert_util.h"
@@ -234,27 +235,39 @@ StatusWith<RemoteCommandResponse> RemoteCommandRunnerImpl::runCommand(
ConnectionPool::ConnectionPtr conn(
&_connPool, request.target, requestStartDate, timeoutMillis.getValue());
- rpc::UniqueReply commandResponse =
- conn.get()->runCommandWithMetadata(request.dbname,
- request.cmdObj.firstElementFieldName(),
- request.metadata,
- request.cmdObj);
-
- BSONObj output = commandResponse->getCommandReply().getOwned();
+ BSONObj output;
+ BSONObj metadata;
// If remote server does not support either find or getMore commands, down convert
// to using DBClientInterface::query()/getMore().
- // TODO: Perform down conversion based on wire protocol version.
- // Refer to the down conversion implementation in the shell.
- if (getStatusFromCommandResult(output).code() == ErrorCodes::CommandNotFound) {
- // 'commandName' will be an empty string if the command object is an empty BSON
- // document.
- StringData commandName = request.cmdObj.firstElement().fieldNameStringData();
- if (commandName == "find") {
- runDownconvertedFindCommand(conn.get(), request.dbname, request.cmdObj, &output);
- } else if (commandName == "getMore") {
- runDownconvertedGetMoreCommand(conn.get(), request.dbname, request.cmdObj, &output);
- }
+ // 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 == LiteParsedQuery::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) {
+ runDownconvertedFindCommand(conn.get(), request.dbname, request.cmdObj, &output);
+ } else if (isGetMoreCmd) {
+ runDownconvertedGetMoreCommand(conn.get(), request.dbname, request.cmdObj, &output);
}
const Date_t requestFinishDate = Date_t::now();
@@ -262,7 +275,7 @@ StatusWith<RemoteCommandResponse> RemoteCommandRunnerImpl::runCommand(
return StatusWith<RemoteCommandResponse>(
RemoteCommandResponse(std::move(output),
- commandResponse->getMetadata().getOwned(),
+ std::move(metadata),
Milliseconds(requestFinishDate - requestStartDate)));
} catch (const DBException& ex) {
return StatusWith<RemoteCommandResponse>(ex.toStatus());
diff --git a/src/mongo/db/query/getmore_request.cpp b/src/mongo/db/query/getmore_request.cpp
index 031864cf369..6077362a4eb 100644
--- a/src/mongo/db/query/getmore_request.cpp
+++ b/src/mongo/db/query/getmore_request.cpp
@@ -42,7 +42,6 @@ namespace mongo {
namespace {
-const char kCmdName[] = "getMore";
const char kCollectionField[] = "collection";
const char kBatchSizeField[] = "batchSize";
const char kMaxTimeMSField[] = "maxTimeMS";
@@ -50,6 +49,8 @@ const char kTermField[] = "term";
} // namespace
+const char GetMoreRequest::kGetMoreCommandName[] = "getMore";
+
GetMoreRequest::GetMoreRequest() : cursorid(0), batchSize(0) {}
GetMoreRequest::GetMoreRequest(NamespaceString namespaceString,
@@ -100,7 +101,7 @@ StatusWith<GetMoreRequest> GetMoreRequest::parseFromBSON(const std::string& dbna
for (BSONElement el : cmdObj) {
const char* fieldName = el.fieldName();
- if (str::equals(fieldName, kCmdName)) {
+ if (str::equals(fieldName, kGetMoreCommandName)) {
if (el.type() != BSONType::NumberLong) {
return {ErrorCodes::TypeMismatch,
str::stream() << "Field 'getMore' must be of type long in: " << cmdObj};
@@ -161,7 +162,7 @@ StatusWith<GetMoreRequest> GetMoreRequest::parseFromBSON(const std::string& dbna
BSONObj GetMoreRequest::toBSON() const {
BSONObjBuilder builder;
- builder.append(kCmdName, cursorid);
+ builder.append(kGetMoreCommandName, cursorid);
builder.append(kCollectionField, nss.coll());
if (batchSize) {
diff --git a/src/mongo/db/query/getmore_request.h b/src/mongo/db/query/getmore_request.h
index 575e333121f..972fea15012 100644
--- a/src/mongo/db/query/getmore_request.h
+++ b/src/mongo/db/query/getmore_request.h
@@ -39,6 +39,8 @@
namespace mongo {
struct GetMoreRequest {
+ static const char kGetMoreCommandName[];
+
/**
* Construct an empty request.
*/
diff --git a/src/mongo/db/query/lite_parsed_query.cpp b/src/mongo/db/query/lite_parsed_query.cpp
index 573cdcf20b1..494f39aa799 100644
--- a/src/mongo/db/query/lite_parsed_query.cpp
+++ b/src/mongo/db/query/lite_parsed_query.cpp
@@ -71,7 +71,6 @@ Status checkFieldType(const BSONElement& el, BSONType type) {
}
// Find command field names.
-const char kCmdName[] = "find";
const char kFilterField[] = "filter";
const char kProjectionField[] = "projection";
const char kSortField[] = "sort";
@@ -96,6 +95,8 @@ const char kTermField[] = "term";
} // namespace
+const char LiteParsedQuery::kFindCommandName[] = "find";
+
LiteParsedQuery::LiteParsedQuery(NamespaceString nss) : _nss(std::move(nss)) {}
// static
@@ -111,7 +112,7 @@ StatusWith<unique_ptr<LiteParsedQuery>> LiteParsedQuery::makeFromFindCommand(Nam
while (it.more()) {
BSONElement el = it.next();
const char* fieldName = el.fieldName();
- if (str::equals(fieldName, kCmdName)) {
+ if (str::equals(fieldName, kFindCommandName)) {
Status status = checkFieldType(el, String);
if (!status.isOK()) {
return status;
@@ -422,7 +423,7 @@ StatusWith<unique_ptr<LiteParsedQuery>> LiteParsedQuery::makeAsFindCmd(
BSONObj LiteParsedQuery::asFindCommand() const {
BSONObjBuilder bob;
- bob.append(kCmdName, _nss.coll());
+ bob.append(kFindCommandName, _nss.coll());
if (!_filter.isEmpty()) {
bob.append(kFilterField, _filter);
diff --git a/src/mongo/db/query/lite_parsed_query.h b/src/mongo/db/query/lite_parsed_query.h
index 410a2d84827..692279aab8b 100644
--- a/src/mongo/db/query/lite_parsed_query.h
+++ b/src/mongo/db/query/lite_parsed_query.h
@@ -47,6 +47,8 @@ class StatusWith;
*/
class LiteParsedQuery {
public:
+ static const char kFindCommandName[];
+
/**
* Parses a find command object, 'cmdObj'. Caller must indicate whether or not this lite
* parsed query is an explained query or not via 'isExplain'.
diff --git a/src/mongo/rpc/protocol.cpp b/src/mongo/rpc/protocol.cpp
index 3bb68f77672..fb4683ee4ca 100644
--- a/src/mongo/rpc/protocol.cpp
+++ b/src/mongo/rpc/protocol.cpp
@@ -127,9 +127,6 @@ StatusWith<ProtocolSet> parseProtocolSetFromIsMasterReply(const BSONObj& isMaste
return minWireExtractStatus;
}
- bool hasWireVersionForOpCommandInMongod = (minWireVersion <= WireVersion::RELEASE_3_1_5) &&
- (maxWireVersion >= WireVersion::RELEASE_3_1_5);
-
bool isMongos = false;
std::string msgField;
@@ -143,10 +140,15 @@ StatusWith<ProtocolSet> parseProtocolSetFromIsMasterReply(const BSONObj& isMaste
isMongos = (msgField == "isdbgrid");
}
- return (!isMongos && hasWireVersionForOpCommandInMongod) ? supports::kAll
- : supports::kOpQueryOnly;
+ return (!isMongos && supportsWireVersionForOpCommandInMongod(minWireVersion, maxWireVersion))
+ ? supports::kAll
+ : supports::kOpQueryOnly;
}
+bool supportsWireVersionForOpCommandInMongod(int minWireVersion, int maxWireVersion) {
+ return (minWireVersion <= WireVersion::RELEASE_3_1_5) &&
+ (maxWireVersion >= WireVersion::RELEASE_3_1_5);
+}
} // namespace rpc
} // namespace mongo
diff --git a/src/mongo/rpc/protocol.h b/src/mongo/rpc/protocol.h
index 82c349ccc9e..4efb5e0b833 100644
--- a/src/mongo/rpc/protocol.h
+++ b/src/mongo/rpc/protocol.h
@@ -101,5 +101,10 @@ StatusWith<ProtocolSet> parseProtocolSet(StringData repr);
*/
StatusWith<ProtocolSet> parseProtocolSetFromIsMasterReply(const BSONObj& isMasterReply);
+/**
+ * Returns true if wire version supports OP_COMMAND in mongod (not mongos).
+ */
+bool supportsWireVersionForOpCommandInMongod(int minWireVersion, int maxWireVersion);
+
} // namespace rpc
} // namespace mongo