diff options
-rw-r--r-- | src/mongo/client/SConscript | 1 | ||||
-rw-r--r-- | src/mongo/client/remote_command_runner_impl.cpp | 51 | ||||
-rw-r--r-- | src/mongo/db/query/getmore_request.cpp | 7 | ||||
-rw-r--r-- | src/mongo/db/query/getmore_request.h | 2 | ||||
-rw-r--r-- | src/mongo/db/query/lite_parsed_query.cpp | 7 | ||||
-rw-r--r-- | src/mongo/db/query/lite_parsed_query.h | 2 | ||||
-rw-r--r-- | src/mongo/rpc/protocol.cpp | 12 | ||||
-rw-r--r-- | src/mongo/rpc/protocol.h | 5 |
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 |