diff options
author | Adam Midvidy <amidvidy@gmail.com> | 2015-06-24 13:54:45 -0400 |
---|---|---|
committer | Adam Midvidy <amidvidy@gmail.com> | 2015-06-24 15:50:30 -0400 |
commit | 1fc9cba6988ab1b600be1a0549caf6146619e4df (patch) | |
tree | a5fcf53a04666b1bfc2ca43332cd824894154985 /src/mongo/rpc | |
parent | 313c3bdc2547f2746639e84f8668a756ad95d8f3 (diff) | |
download | mongo-1fc9cba6988ab1b600be1a0549caf6146619e4df.tar.gz |
SERVER-19035 autodetect support for OP_COMMAND in remote servers
Diffstat (limited to 'src/mongo/rpc')
-rw-r--r-- | src/mongo/rpc/factory.cpp | 28 | ||||
-rw-r--r-- | src/mongo/rpc/factory.h | 13 | ||||
-rw-r--r-- | src/mongo/rpc/protocol.cpp | 43 | ||||
-rw-r--r-- | src/mongo/rpc/protocol.h | 6 | ||||
-rw-r--r-- | src/mongo/rpc/protocol_test.cpp | 36 |
5 files changed, 126 insertions, 0 deletions
diff --git a/src/mongo/rpc/factory.cpp b/src/mongo/rpc/factory.cpp index 085fa9e7a7b..ae16d16c62e 100644 --- a/src/mongo/rpc/factory.cpp +++ b/src/mongo/rpc/factory.cpp @@ -31,8 +31,12 @@ #include "mongo/rpc/factory.h" #include "mongo/rpc/command_reply.h" +#include "mongo/rpc/command_reply_builder.h" +#include "mongo/rpc/command_request.h" #include "mongo/rpc/command_request_builder.h" #include "mongo/rpc/legacy_reply.h" +#include "mongo/rpc/legacy_reply_builder.h" +#include "mongo/rpc/legacy_request.h" #include "mongo/rpc/legacy_request_builder.h" #include "mongo/rpc/protocol.h" #include "mongo/stdx/memory.h" @@ -68,5 +72,29 @@ std::unique_ptr<ReplyInterface> makeReply(const Message* unownedMessage) { } } +std::unique_ptr<RequestInterface> makeRequest(const Message* unownedMessage) { + switch (unownedMessage->operation()) { + case mongo::dbQuery: + return stdx::make_unique<LegacyRequest>(unownedMessage); + case mongo::dbCommand: + return stdx::make_unique<CommandRequest>(unownedMessage); + default: + uasserted(ErrorCodes::UnsupportedFormat, + str::stream() << "Received a reply message with unexpected opcode: " + << unownedMessage->operation()); + } +} + +std::unique_ptr<ReplyBuilderInterface> makeReplyBuilder(Protocol protocol) { + switch (protocol) { + case Protocol::kOpQuery: + return stdx::make_unique<LegacyReplyBuilder>(); + case Protocol::kOpCommandV1: + return stdx::make_unique<CommandReplyBuilder>(); + default: + MONGO_UNREACHABLE; + } +} + } // namespace rpc } // namespace mongo diff --git a/src/mongo/rpc/factory.h b/src/mongo/rpc/factory.h index 7de92664b69..2776ffacc47 100644 --- a/src/mongo/rpc/factory.h +++ b/src/mongo/rpc/factory.h @@ -41,8 +41,10 @@ namespace mongo { class Message; namespace rpc { +class ReplyBuilderInterface; class ReplyInterface; class RequestBuilderInterface; +class RequestInterface; /** * Returns the appropriate concrete RequestBuilder. Throws if one cannot be chosen. @@ -56,5 +58,16 @@ std::unique_ptr<RequestBuilderInterface> makeRequestBuilder(ProtocolSet clientPr */ std::unique_ptr<ReplyInterface> makeReply(const Message* unownedMessage); +/** + * Returns the appropriate concrete Request according to the contents of the message. + * Throws if one cannot be chosen. + */ +std::unique_ptr<RequestInterface> makeRequest(const Message* unownedMessage); + +/** + * Returns the appropriate concrete ReplyBuilder. + */ +std::unique_ptr<ReplyBuilderInterface> makeReplyBuilder(Protocol protocol); + } // namespace rpc } // namespace mongo diff --git a/src/mongo/rpc/protocol.cpp b/src/mongo/rpc/protocol.cpp index f50860b85fd..3bb68f77672 100644 --- a/src/mongo/rpc/protocol.cpp +++ b/src/mongo/rpc/protocol.cpp @@ -34,6 +34,9 @@ #include <iterator> #include "mongo/base/string_data.h" +#include "mongo/bson/util/bson_extract.h" +#include "mongo/db/jsobj.h" +#include "mongo/db/wire_version.h" #include "mongo/util/mongoutils/str.h" namespace mongo { @@ -105,5 +108,45 @@ StatusWith<ProtocolSet> parseProtocolSet(StringData repr) { << "and 'all' (0x3) are supported."); } +StatusWith<ProtocolSet> parseProtocolSetFromIsMasterReply(const BSONObj& isMasterReply) { + long long maxWireVersion; + auto maxWireExtractStatus = + bsonExtractIntegerField(isMasterReply, "maxWireVersion", &maxWireVersion); + + long long minWireVersion; + auto minWireExtractStatus = + bsonExtractIntegerField(isMasterReply, "minWireVersion", &minWireVersion); + + // MongoDB 2.4 and earlier do not have maxWireVersion/minWireVersion in their 'isMaster' replies + if ((maxWireExtractStatus == minWireExtractStatus) && + (maxWireExtractStatus == ErrorCodes::NoSuchKey)) { + return supports::kOpQueryOnly; + } else if (!maxWireExtractStatus.isOK()) { + return maxWireExtractStatus; + } else if (!minWireExtractStatus.isOK()) { + return minWireExtractStatus; + } + + bool hasWireVersionForOpCommandInMongod = (minWireVersion <= WireVersion::RELEASE_3_1_5) && + (maxWireVersion >= WireVersion::RELEASE_3_1_5); + + bool isMongos = false; + + std::string msgField; + auto msgFieldExtractStatus = bsonExtractStringField(isMasterReply, "msg", &msgField); + + if (msgFieldExtractStatus == ErrorCodes::NoSuchKey) { + isMongos = false; + } else if (!msgFieldExtractStatus.isOK()) { + return msgFieldExtractStatus; + } else { + isMongos = (msgField == "isdbgrid"); + } + + return (!isMongos && hasWireVersionForOpCommandInMongod) ? supports::kAll + : supports::kOpQueryOnly; +} + + } // namespace rpc } // namespace mongo diff --git a/src/mongo/rpc/protocol.h b/src/mongo/rpc/protocol.h index 99e6cacc92c..8999f0b40d2 100644 --- a/src/mongo/rpc/protocol.h +++ b/src/mongo/rpc/protocol.h @@ -35,6 +35,7 @@ #include "mongo/platform/cstdint.h" namespace mongo { +class BSONObj; namespace rpc { /** @@ -95,5 +96,10 @@ StatusWith<StringData> toString(ProtocolSet protocols); */ StatusWith<ProtocolSet> parseProtocolSet(StringData repr); +/** + * Determines the ProtocolSet of a remote server from an isMaster reply. + */ +StatusWith<ProtocolSet> parseProtocolSetFromIsMasterReply(const BSONObj& isMasterReply); + } // namespace rpc } // namespace mongo diff --git a/src/mongo/rpc/protocol_test.cpp b/src/mongo/rpc/protocol_test.cpp index 71ff1559fda..0f26cc586b2 100644 --- a/src/mongo/rpc/protocol_test.cpp +++ b/src/mongo/rpc/protocol_test.cpp @@ -29,12 +29,17 @@ #include "mongo/platform/basic.h" #include "mongo/base/status.h" +#include "mongo/db/jsobj.h" +#include "mongo/db/wire_version.h" #include "mongo/rpc/protocol.h" #include "mongo/unittest/unittest.h" namespace { +using mongo::WireVersion; using namespace mongo::rpc; +using mongo::unittest::assertGet; +using mongo::BSONObj; // Checks if negotiation of the first to protocol sets results in the 'proto' const auto assert_negotiated = [](ProtocolSet fst, ProtocolSet snd, Protocol proto) { @@ -63,4 +68,35 @@ TEST(Protocol, FailedNegotiation) { assert_not_negotiated(supports::kOpCommandOnly, supports::kNone); } +TEST(Protocol, parseProtocolSetFromIsMasterReply) { + { + // MongoDB 3.2 (mongod) + auto mongod32 = BSON("maxWireVersion" + << static_cast<int>(WireVersion::RELEASE_3_1_5) << "minWireVersion" + << static_cast<int>(WireVersion::RELEASE_2_4_AND_BEFORE)); + + ASSERT_EQ(assertGet(parseProtocolSetFromIsMasterReply(mongod32)), supports::kAll); + } + { + // MongoDB 3.2 (mongos) + auto mongos32 = BSON("maxWireVersion" + << static_cast<int>(WireVersion::RELEASE_3_1_5) << "minWireVersion" + << static_cast<int>(WireVersion::RELEASE_2_4_AND_BEFORE) << "msg" + << "isdbgrid"); + + ASSERT_EQ(assertGet(parseProtocolSetFromIsMasterReply(mongos32)), supports::kOpQueryOnly); + } + { + // MongoDB 3.0 (mongod) + auto mongod30 = BSON("maxWireVersion" + << static_cast<int>(WireVersion::RELEASE_2_7_7) << "minWireVersion" + << static_cast<int>(WireVersion::RELEASE_2_4_AND_BEFORE)); + ASSERT_EQ(assertGet(parseProtocolSetFromIsMasterReply(mongod30)), supports::kOpQueryOnly); + } + { + auto mongod24 = BSONObj(); + ASSERT_EQ(assertGet(parseProtocolSetFromIsMasterReply(mongod24)), supports::kOpQueryOnly); + } +} + } // namespace |