diff options
author | Mathias Stearn <mathias@10gen.com> | 2017-05-19 17:06:56 -0400 |
---|---|---|
committer | Mathias Stearn <mathias@10gen.com> | 2017-06-07 13:28:51 -0400 |
commit | 107327303755a830236bfef5827b543d88223b89 (patch) | |
tree | 25a9c9586fbcf1ba17651fe00abbd4a6bfebd929 | |
parent | b89c05e65c3168cef9c813f3feca2b1a63621ca2 (diff) | |
download | mongo-107327303755a830236bfef5827b543d88223b89.tar.gz |
SERVER-29264 Kill off rpc::RequestInterface
-rw-r--r-- | src/mongo/client/scoped_db_conn_test.cpp | 25 | ||||
-rw-r--r-- | src/mongo/db/assemble_response.cpp | 23 | ||||
-rw-r--r-- | src/mongo/db/repl/replication_coordinator.h | 1 | ||||
-rw-r--r-- | src/mongo/executor/async_mock_stream_factory.cpp | 7 | ||||
-rw-r--r-- | src/mongo/executor/network_interface_asio_test.cpp | 15 | ||||
-rw-r--r-- | src/mongo/executor/remote_command_request.h | 12 | ||||
-rw-r--r-- | src/mongo/rpc/command_request.cpp | 87 | ||||
-rw-r--r-- | src/mongo/rpc/command_request.h | 59 | ||||
-rw-r--r-- | src/mongo/rpc/command_request_builder_test.cpp | 10 | ||||
-rw-r--r-- | src/mongo/rpc/command_request_test.cpp | 14 | ||||
-rw-r--r-- | src/mongo/rpc/factory.cpp | 12 | ||||
-rw-r--r-- | src/mongo/rpc/factory.h | 7 | ||||
-rw-r--r-- | src/mongo/rpc/legacy_request.cpp | 40 | ||||
-rw-r--r-- | src/mongo/rpc/legacy_request.h | 59 | ||||
-rw-r--r-- | src/mongo/rpc/op_msg_rpc_impls.h | 24 | ||||
-rw-r--r-- | src/mongo/rpc/protocol.cpp | 15 | ||||
-rw-r--r-- | src/mongo/rpc/protocol.h | 3 | ||||
-rw-r--r-- | src/mongo/rpc/request_interface.h | 83 | ||||
-rw-r--r-- | src/mongo/rpc/unique_message.h | 3 | ||||
-rw-r--r-- | src/mongo/tools/bridge.cpp | 33 |
20 files changed, 153 insertions, 379 deletions
diff --git a/src/mongo/client/scoped_db_conn_test.cpp b/src/mongo/client/scoped_db_conn_test.cpp index 57d196e7a88..a943ec18cb4 100644 --- a/src/mongo/client/scoped_db_conn_test.cpp +++ b/src/mongo/client/scoped_db_conn_test.cpp @@ -38,7 +38,6 @@ #include "mongo/db/wire_version.h" #include "mongo/rpc/factory.h" #include "mongo/rpc/reply_builder_interface.h" -#include "mongo/rpc/request_interface.h" #include "mongo/stdx/mutex.h" #include "mongo/stdx/thread.h" #include "mongo/transport/service_entry_point.h" @@ -108,15 +107,15 @@ private: return; } - auto request = rpc::makeRequest(&inMessage); - commandRequestHook(request.get()); + auto request = rpc::opMsgRequestFromAnyProtocol(inMessage); + commandRequestHook(request); - auto reply = rpc::makeReplyBuilder(request->getProtocol()); + auto reply = rpc::makeReplyBuilder(rpc::protocolForMessage(inMessage)); BSONObjBuilder commandResponse; // We need to handle the isMaster received during connection. - if (request->getCommandName() == "isMaster") { + if (request.getCommandName() == "isMaster") { commandResponse.append("maxWireVersion", WireVersion::COMMANDS_ACCEPT_WRITE_CONCERN); commandResponse.append("minWireVersion", WireVersion::RELEASE_2_4_AND_BEFORE); } @@ -139,7 +138,7 @@ private: /** * Subclasses can override this in order to make assertions about the command request. */ - virtual void commandRequestHook(const rpc::RequestInterface* request) const {} + virtual void commandRequestHook(const OpMsgRequest& request) const {} std::vector<stdx::thread> _threads; Milliseconds _replyDelay{0}; @@ -533,14 +532,13 @@ TEST_F(DummyServerFixture, DontReturnConnGoneBadToPool) { class DummyServiceEntryPointWithInternalClientInfoCheck final : public DummyServiceEntryPoint { private: - void commandRequestHook(const rpc::RequestInterface* request) const final { - if (request->getCommandName() != "isMaster") { + void commandRequestHook(const OpMsgRequest& request) const final { + if (request.getCommandName() != "isMaster") { // It's not an isMaster request. Nothing to do. return; } - BSONObj commandArgs = request->getCommandArgs(); - auto internalClientElem = commandArgs["internalClient"]; + auto internalClientElem = request.body["internalClient"]; ASSERT_EQ(internalClientElem.type(), BSONType::Object); auto minWireVersionElem = internalClientElem.Obj()["minWireVersion"]; auto maxWireVersionElem = internalClientElem.Obj()["maxWireVersion"]; @@ -571,14 +569,13 @@ TEST_F(DummyServerFixtureWithInternalClientInfoCheck, VerifyIsMasterRequestOnCon class DummyServiceEntryPointWithInternalClientMissingCheck final : public DummyServiceEntryPoint { private: - void commandRequestHook(const rpc::RequestInterface* request) const final { - if (request->getCommandName() != "isMaster") { + void commandRequestHook(const OpMsgRequest& request) const final { + if (request.getCommandName() != "isMaster") { // It's not an isMaster request. Nothing to do. return; } - BSONObj commandArgs = request->getCommandArgs(); - ASSERT_FALSE(commandArgs["internalClient"]); + ASSERT_FALSE(request.body["internalClient"]); } }; diff --git a/src/mongo/db/assemble_response.cpp b/src/mongo/db/assemble_response.cpp index abbb666e8d0..97bf6a194db 100644 --- a/src/mongo/db/assemble_response.cpp +++ b/src/mongo/db/assemble_response.cpp @@ -160,25 +160,16 @@ DbResponse receivedCommand(OperationContext* opCtx, try { // This will throw if the request is on an invalid namespace. - rpc::LegacyRequest legacyRequest{&message}; + auto request = rpc::opMsgRequestFromLegacyRequest(message); // Auth checking for Commands happens later. - int nToReturn = queryMessage.ntoreturn; - beginCommandOp(opCtx, nss, legacyRequest.getCommandArgs()); + beginCommandOp(opCtx, nss, request.body); { stdx::lock_guard<Client> lk(*opCtx->getClient()); op->markCommand_inlock(); } - uassert(16979, - str::stream() << "bad numberToReturn (" << nToReturn - << ") for $cmd type ns - can only be 1 or -1", - nToReturn == 1 || nToReturn == -1); - - auto request = OpMsgRequest::fromDBAndBody(legacyRequest.getDatabase(), - legacyRequest.getCommandArgs(), - legacyRequest.getMetadata()); runCommands(opCtx, request, &builder); op->debug().iscommand = true; @@ -243,21 +234,17 @@ DbResponse receivedRpc(OperationContext* opCtx, Client& client, const Message& m try { // database is validated here - rpc::CommandRequest commandRequest{&message}; + auto request = rpc::opMsgRequestFromLegacyRequest(message); // We construct a legacy $cmd namespace so we can fill in curOp using // the existing logic that existed for OP_QUERY commands - NamespaceString nss(commandRequest.getDatabase(), "$cmd"); - beginCommandOp(opCtx, nss, commandRequest.getCommandArgs()); + NamespaceString nss(request.getDatabase(), "$cmd"); + beginCommandOp(opCtx, nss, request.body); { stdx::lock_guard<Client> lk(*opCtx->getClient()); curOp->markCommand_inlock(); } - - auto request = OpMsgRequest::fromDBAndBody(commandRequest.getDatabase(), - commandRequest.getCommandArgs(), - commandRequest.getMetadata()); runCommands(opCtx, request, &replyBuilder); curOp->debug().iscommand = true; diff --git a/src/mongo/db/repl/replication_coordinator.h b/src/mongo/db/repl/replication_coordinator.h index d682ee756be..6015fa78da8 100644 --- a/src/mongo/db/repl/replication_coordinator.h +++ b/src/mongo/db/repl/replication_coordinator.h @@ -59,7 +59,6 @@ namespace rpc { class OplogQueryMetadata; class ReplSetMetadata; -class RequestInterface; } // namespace rpc diff --git a/src/mongo/executor/async_mock_stream_factory.cpp b/src/mongo/executor/async_mock_stream_factory.cpp index fd87386e6e5..2951f977bcd 100644 --- a/src/mongo/executor/async_mock_stream_factory.cpp +++ b/src/mongo/executor/async_mock_stream_factory.cpp @@ -40,7 +40,6 @@ #include "mongo/rpc/command_reply_builder.h" #include "mongo/rpc/factory.h" #include "mongo/rpc/legacy_reply_builder.h" -#include "mongo/rpc/request_interface.h" #include "mongo/stdx/memory.h" #include "mongo/util/assert_util.h" #include "mongo/util/log.h" @@ -283,10 +282,10 @@ void AsyncMockStreamFactory::MockStream::simulateServer( Message msg(SharedBuffer::allocate(messageData.size())); memcpy(msg.buf(), messageData.data(), messageData.size()); - auto parsedRequest = rpc::makeRequest(&msg); - ASSERT(parsedRequest->getProtocol() == proto); + auto request = rpc::opMsgRequestFromAnyProtocol(msg); + ASSERT(rpc::protocolForMessage(msg) == proto); - RemoteCommandRequest rcr(target(), *parsedRequest, nullptr); + RemoteCommandRequest rcr(target(), request.getDatabase().toString(), request.body, nullptr); messageId = msg.header().getId(); diff --git a/src/mongo/executor/network_interface_asio_test.cpp b/src/mongo/executor/network_interface_asio_test.cpp index 1f14d4063f5..0d353728df0 100644 --- a/src/mongo/executor/network_interface_asio_test.cpp +++ b/src/mongo/executor/network_interface_asio_test.cpp @@ -782,7 +782,7 @@ TEST_F(NetworkInterfaceASIOConnectionHookTest, MakeRequestReturnsNone) { // Simulate user command. stream->simulateServer(rpc::Protocol::kOpCommandV1, [&](RemoteCommandRequest request) -> RemoteCommandResponse { - ASSERT_BSONOBJ_EQ(commandRequest, request.cmdObj); + ASSERT_BSONOBJ_EQ(commandRequest, request.cmdObj.removeField("$db")); RemoteCommandResponse response; response.data = commandReply; @@ -814,6 +814,13 @@ TEST_F(NetworkInterfaceASIOConnectionHookTest, HandleReplyReturnsError) { << "blah" << "ok" << 1.0); + BSONObj hookUnifiedRequest = ([&] { + BSONObjBuilder bob; + bob.appendElements(hookCommandRequest); + bob.appendElements(hookRequestMetadata); + bob.append("$db", "foo"); + return bob.obj(); + }()); BSONObj hookReplyMetadata = BSON("1111" << 2222); Status handleReplyError{ErrorCodes::AuthSchemaIncompatible, "daowdjkpowkdjpow"}; @@ -853,8 +860,8 @@ TEST_F(NetworkInterfaceASIOConnectionHookTest, HandleReplyReturnsError) { // Simulate hook reply stream->simulateServer(rpc::Protocol::kOpCommandV1, [&](RemoteCommandRequest request) -> RemoteCommandResponse { - ASSERT_BSONOBJ_EQ(request.cmdObj, hookCommandRequest); - ASSERT_BSONOBJ_EQ(request.metadata, hookRequestMetadata); + ASSERT_BSONOBJ_EQ(request.cmdObj, hookUnifiedRequest); + ASSERT_BSONOBJ_EQ(request.metadata, BSONObj()); RemoteCommandResponse response; response.data = hookCommandReply; @@ -1027,7 +1034,7 @@ TEST_F(NetworkInterfaceASIOMetadataTest, Metadata) { // Simulate hook reply stream->simulateServer(rpc::Protocol::kOpCommandV1, [&](RemoteCommandRequest request) -> RemoteCommandResponse { - ASSERT_EQ("bar", request.metadata["foo"].str()); + ASSERT_EQ("bar", request.cmdObj["foo"].str()); RemoteCommandResponse response; response.data = BSON("ok" << 1); response.metadata = BSON("baz" diff --git a/src/mongo/executor/remote_command_request.h b/src/mongo/executor/remote_command_request.h index c6195311b69..0eb184e1d05 100644 --- a/src/mongo/executor/remote_command_request.h +++ b/src/mongo/executor/remote_command_request.h @@ -33,7 +33,6 @@ #include "mongo/db/jsobj.h" #include "mongo/rpc/metadata.h" -#include "mongo/rpc/request_interface.h" #include "mongo/util/net/hostandport.h" #include "mongo/util/time_support.h" @@ -78,17 +77,6 @@ struct RemoteCommandRequest { : RemoteCommandRequest( theTarget, theDbName, theCmdObj, rpc::makeEmptyMetadata(), opCtx, timeoutMillis) {} - RemoteCommandRequest(const HostAndPort& theTarget, - const rpc::RequestInterface& request, - OperationContext* opCtx, - Milliseconds timeoutMillis = kNoTimeout) - : RemoteCommandRequest(theTarget, - request.getDatabase().toString(), - request.getCommandArgs(), - request.getMetadata(), - opCtx, - timeoutMillis) {} - std::string toString() const; bool operator==(const RemoteCommandRequest& rhs) const; diff --git a/src/mongo/rpc/command_request.cpp b/src/mongo/rpc/command_request.cpp index 54cb58a4313..a796f6f8a19 100644 --- a/src/mongo/rpc/command_request.cpp +++ b/src/mongo/rpc/command_request.cpp @@ -54,9 +54,11 @@ const std::size_t kMaxCommandNameLength = 128; } // namespace -CommandRequest::CommandRequest(const Message* message) : _message(message) { - char* begin = _message->singleData().data(); - std::size_t length = _message->singleData().dataLen(); +ParsedOpCommand ParsedOpCommand::parse(const Message& message) { + ParsedOpCommand out; + + char* begin = message.singleData().data(); + std::size_t length = message.singleData().dataLen(); // checked in message_port.cpp invariant(length <= MaxMessageSizeBytes); @@ -67,10 +69,10 @@ CommandRequest::CommandRequest(const Message* message) : _message(message) { Terminated<'\0', StringData> str; uassertStatusOK(cur.readAndAdvance<>(&str)); - _database = std::move(str.value); + out.database = str.value.toString(); uassertStatusOK(cur.readAndAdvance<>(&str)); - _commandName = std::move(str.value); + const auto commandName = std::move(str.value); uassert(28637, str::stream() << "Command name parsed in OP_COMMAND message must be between " @@ -78,76 +80,61 @@ CommandRequest::CommandRequest(const Message* message) : _message(message) { << " and " << kMaxCommandNameLength << " bytes. Got: " - << _database, - (_commandName.size() >= kMinCommandNameLength) && - (_commandName.size() <= kMaxCommandNameLength)); + << out.database, + (commandName.size() >= kMinCommandNameLength) && + (commandName.size() <= kMaxCommandNameLength)); Validated<BSONObj> obj; uassertStatusOK(cur.readAndAdvance<>(&obj)); - _commandArgs = std::move(obj.val); + out.body = std::move(obj.val); uassert(39950, - str::stream() << "Command name parsed in OP_COMMAND message '" << _commandName + str::stream() << "Command name parsed in OP_COMMAND message '" << commandName << "' doesn't match command name from object '" - << _commandArgs.firstElementFieldName() + << out.body.firstElementFieldName() << '\'', - _commandArgs.firstElementFieldName() == _commandName); + out.body.firstElementFieldName() == commandName); + + uassertStatusOK(cur.readAndAdvance<>(&obj)); + out.metadata = std::move(obj.val); + + uassert(40419, "OP_COMMAND request contains trailing bytes following metadata", cur.empty()); + + return out; +} + +OpMsgRequest opMsgRequestFromCommandRequest(const Message& message) { + auto parsed = ParsedOpCommand::parse(message); + + BSONObjBuilder bodyBuilder; + bodyBuilder.appendElements(parsed.body); // OP_COMMAND is only used when communicating with 3.4 nodes and they serialize their metadata // fields differently. We do all up-conversion here so that the rest of the code only has to // deal with the current format. - uassertStatusOK(cur.readAndAdvance<>(&obj)); - BSONObjBuilder metadataBuilder; - for (auto elem : obj.val) { + for (auto elem : parsed.metadata) { if (elem.fieldNameStringData() == "configsvr") { - metadataBuilder.appendAs(elem, "$configServerState"); + bodyBuilder.appendAs(elem, "$configServerState"); } else if (elem.fieldNameStringData() == "$ssm") { auto ssmObj = elem.Obj(); if (auto readPrefElem = ssmObj["$readPreference"]) { // Promote the read preference to the top level. - metadataBuilder.append(readPrefElem); + bodyBuilder.append(readPrefElem); } else if (ssmObj["$secondaryOk"].trueValue()) { // Convert secondaryOk to equivalent read preference if none was explicitly // provided. ReadPreferenceSetting(ReadPreference::SecondaryPreferred) - .toContainingBSON(&metadataBuilder); + .toContainingBSON(&bodyBuilder); } } else { - metadataBuilder.append(elem); + bodyBuilder.append(elem); } } - _metadata = metadataBuilder.obj(); - - uassert(40419, "OP_COMMAND request contains trailing bytes following metadata", cur.empty()); -} - -StringData CommandRequest::getDatabase() const { - return _database; -} - -StringData CommandRequest::getCommandName() const { - return _commandName; -} - -const BSONObj& CommandRequest::getMetadata() const { - return _metadata; -} - -const BSONObj& CommandRequest::getCommandArgs() const { - return _commandArgs; -} -bool operator==(const CommandRequest& lhs, const CommandRequest& rhs) { - return (lhs._database == rhs._database) && (lhs._commandName == rhs._commandName) && - SimpleBSONObjComparator::kInstance.evaluate(lhs._metadata == rhs._metadata) && - SimpleBSONObjComparator::kInstance.evaluate(lhs._commandArgs == rhs._commandArgs); -} - -bool operator!=(const CommandRequest& lhs, const CommandRequest& rhs) { - return !(lhs == rhs); -} + bodyBuilder.append("$db", parsed.database); -Protocol CommandRequest::getProtocol() const { - return rpc::Protocol::kOpCommandV1; + OpMsgRequest request; + request.body = bodyBuilder.obj(); + return request; } } // namespace rpc diff --git a/src/mongo/rpc/command_request.h b/src/mongo/rpc/command_request.h index 92106915143..07cefccdb0e 100644 --- a/src/mongo/rpc/command_request.h +++ b/src/mongo/rpc/command_request.h @@ -28,63 +28,28 @@ #pragma once -#include "mongo/base/string_data.h" #include "mongo/db/jsobj.h" -#include "mongo/rpc/protocol.h" -#include "mongo/rpc/request_interface.h" +#include "mongo/util/net/message.h" +#include "mongo/util/net/op_msg.h" namespace mongo { -class Message; - namespace rpc { /** - * An immutable view of an OP_COMMAND message. The underlying bytes are owned - * by a mongo::Message, which must outlive any Reply instances created from it. + * This captures a full OP_COMMAND message before the body and metadata are merged. It should only + * be used for testing and implementation of opMsgRequestFromCommandRequest(). All other code should + * just use the general OpMsgRequest. */ -class CommandRequest : public RequestInterface { -public: - /** - * Construct a Request from a Message. Underlying message MUST outlive the Request. - * Required fields are parsed eagerly, inputDocs are parsed lazily. - */ - explicit CommandRequest(const Message* message); - - ~CommandRequest() = default; - - /** - * The database that the command is to be executed on. - */ - StringData getDatabase() const final; - - /** - * The name of the command to execute. - */ - StringData getCommandName() const final; +struct ParsedOpCommand { + static ParsedOpCommand parse(const Message& message); - /** - * The metadata associated with the command request. This is information that is - * independent of any specific command, i.e. auditing information. - */ - const BSONObj& getMetadata() const final; - - /** - * The arguments to the command - this is passed to the command's run() method. - */ - const BSONObj& getCommandArgs() const final; - - Protocol getProtocol() const final; + std::string database; + BSONObj body; + BSONObj metadata; +}; - friend bool operator==(const CommandRequest& lhs, const CommandRequest& rhs); - friend bool operator!=(const CommandRequest& lhs, const CommandRequest& rhs); -private: - const Message* _message; - StringData _database; - StringData _commandName; - BSONObj _commandArgs; - BSONObj _metadata; -}; +OpMsgRequest opMsgRequestFromCommandRequest(const Message& message); } // namespace rpc } // namespace mongo diff --git a/src/mongo/rpc/command_request_builder_test.cpp b/src/mongo/rpc/command_request_builder_test.cpp index 7e96f06b184..fe9539d41d2 100644 --- a/src/mongo/rpc/command_request_builder_test.cpp +++ b/src/mongo/rpc/command_request_builder_test.cpp @@ -74,12 +74,12 @@ TEST(RequestBuilder, RoundTrip) { .setMetadata(metadata) .done(); - rpc::CommandRequest parsed(&msg); + auto parsed = mongo::rpc::ParsedOpCommand::parse(msg); - ASSERT_EQUALS(parsed.getDatabase(), databaseName); - ASSERT_EQUALS(parsed.getCommandName(), commandName); - ASSERT_BSONOBJ_EQ(parsed.getMetadata(), metadata); - ASSERT_BSONOBJ_EQ(parsed.getCommandArgs(), commandArgs); + ASSERT_EQUALS(parsed.database, databaseName); + ASSERT_EQUALS(StringData(parsed.body.firstElementFieldName()), commandName); + ASSERT_BSONOBJ_EQ(parsed.metadata, metadata); + ASSERT_BSONOBJ_EQ(parsed.body, commandArgs); } } // namespace diff --git a/src/mongo/rpc/command_request_test.cpp b/src/mongo/rpc/command_request_test.cpp index 3d8a6c7d1a5..17fc056ef68 100644 --- a/src/mongo/rpc/command_request_test.cpp +++ b/src/mongo/rpc/command_request_test.cpp @@ -77,12 +77,12 @@ TEST(CommandRequest, ParseAllFields) { Message toSend; toSend.setData(dbCommand, opCommandData.data(), opCommandData.size()); - rpc::CommandRequest opCmd{&toSend}; + auto opCmd = rpc::ParsedOpCommand::parse(toSend); - ASSERT_EQUALS(opCmd.getCommandName(), commandName); - ASSERT_EQUALS(opCmd.getDatabase(), database); - ASSERT_BSONOBJ_EQ(opCmd.getMetadata(), metadata); - ASSERT_BSONOBJ_EQ(opCmd.getCommandArgs(), commandArgs); + ASSERT_EQUALS(opCmd.body.firstElementFieldName(), commandName); + ASSERT_EQUALS(opCmd.database, database); + ASSERT_BSONOBJ_EQ(opCmd.metadata, metadata); + ASSERT_BSONOBJ_EQ(opCmd.body, commandArgs); } TEST(CommandRequest, EmptyCommandObjThrows) { @@ -92,7 +92,7 @@ TEST(CommandRequest, EmptyCommandObjThrows) { crb.setCommandArgs(BSONObj()); crb.setMetadata(BSONObj()); auto msg = crb.done(); - ASSERT_THROWS_CODE(rpc::CommandRequest{&msg}, UserException, 39950); + ASSERT_THROWS_CODE(rpc::ParsedOpCommand::parse(msg), UserException, 39950); } TEST(CommandRequest, MismatchBetweenCommandNamesThrows) { @@ -102,7 +102,7 @@ TEST(CommandRequest, MismatchBetweenCommandNamesThrows) { crb.setCommandArgs(BSON("launchMissiles" << 1)); crb.setMetadata(BSONObj()); auto msg = crb.done(); - ASSERT_THROWS_CODE(rpc::CommandRequest{&msg}, UserException, 39950); + ASSERT_THROWS_CODE(rpc::ParsedOpCommand::parse(msg), UserException, 39950); } } // namespace diff --git a/src/mongo/rpc/factory.cpp b/src/mongo/rpc/factory.cpp index b8b1853c799..38bcbdbfeb8 100644 --- a/src/mongo/rpc/factory.cpp +++ b/src/mongo/rpc/factory.cpp @@ -81,18 +81,18 @@ std::unique_ptr<ReplyInterface> makeReply(const Message* unownedMessage) { } } -std::unique_ptr<RequestInterface> makeRequest(const Message* unownedMessage) { - switch (unownedMessage->operation()) { +OpMsgRequest opMsgRequestFromAnyProtocol(const Message& unownedMessage) { + switch (unownedMessage.operation()) { case mongo::dbMsg: - return stdx::make_unique<OpMsgRequest>(mongo::OpMsgRequest::parse(*unownedMessage)); + return OpMsgRequest::parse(unownedMessage); case mongo::dbQuery: - return stdx::make_unique<LegacyRequest>(unownedMessage); + return opMsgRequestFromLegacyRequest(unownedMessage); case mongo::dbCommand: - return stdx::make_unique<CommandRequest>(unownedMessage); + return opMsgRequestFromCommandRequest(unownedMessage); default: uasserted(ErrorCodes::UnsupportedFormat, str::stream() << "Received a reply message with unexpected opcode: " - << unownedMessage->operation()); + << unownedMessage.operation()); } } diff --git a/src/mongo/rpc/factory.h b/src/mongo/rpc/factory.h index f2d4e2fd3cb..08b3ef0a8d1 100644 --- a/src/mongo/rpc/factory.h +++ b/src/mongo/rpc/factory.h @@ -29,6 +29,7 @@ #pragma once #include "mongo/rpc/protocol.h" +#include "mongo/util/net/op_msg.h" #include <memory> @@ -44,7 +45,6 @@ namespace rpc { class ReplyBuilderInterface; class ReplyInterface; class RequestBuilderInterface; -class RequestInterface; /** * Returns the appropriate concrete RequestBuilder. Throws if one cannot be chosen. @@ -61,10 +61,9 @@ std::unique_ptr<RequestBuilderInterface> makeRequestBuilder(Protocol proto); 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. + * Parses the message (from any protocol) into an OpMsgRequest. */ -std::unique_ptr<RequestInterface> makeRequest(const Message* unownedMessage); +OpMsgRequest opMsgRequestFromAnyProtocol(const Message& unownedMessage); /** * Returns the appropriate concrete ReplyBuilder. diff --git a/src/mongo/rpc/legacy_request.cpp b/src/mongo/rpc/legacy_request.cpp index dd003c91fa7..9d5beae3af2 100644 --- a/src/mongo/rpc/legacy_request.cpp +++ b/src/mongo/rpc/legacy_request.cpp @@ -30,6 +30,7 @@ #include <utility> +#include "mongo/db/dbmessage.h" #include "mongo/rpc/legacy_request.h" #include "mongo/rpc/metadata.h" #include "mongo/util/assert_util.h" @@ -37,35 +38,24 @@ namespace mongo { namespace rpc { -LegacyRequest::LegacyRequest(const Message* message) - : _message(std::move(message)), _dbMessage(*message), _queryMessage(_dbMessage) { - _database = nsToDatabaseSubstring(_queryMessage.ns); +OpMsgRequest opMsgRequestFromLegacyRequest(const Message& message) { + DbMessage dbm(message); + QueryMessage qm(dbm); + NamespaceString ns(qm.ns); - std::tie(_upconvertedCommandArgs, _upconvertedMetadata) = rpc::upconvertRequestMetadata( - std::move(_queryMessage.query), std::move(_queryMessage.queryOptions)); -} - -LegacyRequest::~LegacyRequest() = default; - -StringData LegacyRequest::getDatabase() const { - return _database; -} + uassert(40473, + str::stream() << "Trying to handle namespace " << qm.ns << " as a command", + ns.isCommand()); -StringData LegacyRequest::getCommandName() const { - return _upconvertedCommandArgs.firstElement().fieldNameStringData(); -} - -const BSONObj& LegacyRequest::getMetadata() const { - // TODO SERVER-18236 - return _upconvertedMetadata; -} + uassert(16979, + str::stream() << "bad numberToReturn (" << qm.ntoreturn + << ") for $cmd type ns - can only be 1 or -1", + qm.ntoreturn == 1 || qm.ntoreturn == -1); -const BSONObj& LegacyRequest::getCommandArgs() const { - return _upconvertedCommandArgs; -} + auto bodyAndMetadata = rpc::upconvertRequestMetadata(qm.query, qm.queryOptions); -Protocol LegacyRequest::getProtocol() const { - return rpc::Protocol::kOpQuery; + return OpMsgRequest::fromDBAndBody( + ns.db(), std::get<0>(bodyAndMetadata), std::get<1>(bodyAndMetadata)); } } // namespace rpc diff --git a/src/mongo/rpc/legacy_request.h b/src/mongo/rpc/legacy_request.h index f943114e358..81c0bb9d94c 100644 --- a/src/mongo/rpc/legacy_request.h +++ b/src/mongo/rpc/legacy_request.h @@ -28,66 +28,13 @@ #pragma once -#include "mongo/base/string_data.h" -#include "mongo/db/dbmessage.h" -#include "mongo/db/jsobj.h" -#include "mongo/rpc/protocol.h" -#include "mongo/rpc/request_interface.h" +#include "mongo/util/net/message.h" +#include "mongo/util/net/op_msg.h" namespace mongo { -class Message; - namespace rpc { -/** - * An immutable view of an OP_QUERY command request. The underlying bytes are owned - * by a mongo::Message, which must outlive any LegacyRequest instances created from it. - * - */ -class LegacyRequest : public RequestInterface { -public: - /** - * Construct a Request from a Message. Underlying message MUST outlive the Request. - * Required fields are parsed eagerly, inputDocs are parsed lazily. - */ - explicit LegacyRequest(const Message* message); - - ~LegacyRequest() final; - - /** - * The database that the command is to be executed on. - */ - StringData getDatabase() const final; - - /** - * The name of the command to execute. - */ - StringData getCommandName() const final; - - /** - * The metadata associated with the command request. This is information that is - * independent of any specific command, i.e. auditing information. - */ - const BSONObj& getMetadata() const final; - - /** - * The arguments to the command - this is passed to the command's run() method. - */ - const BSONObj& getCommandArgs() const final; - - Protocol getProtocol() const final; - -private: - const Message* _message; - // TODO: metadata will be handled in SERVER-18236 - // for now getMetadata() is a no op - DbMessage _dbMessage; - QueryMessage _queryMessage; - StringData _database; - - BSONObj _upconvertedMetadata; - BSONObj _upconvertedCommandArgs; -}; +OpMsgRequest opMsgRequestFromLegacyRequest(const Message& message); } // namespace rpc } // namespace mongo diff --git a/src/mongo/rpc/op_msg_rpc_impls.h b/src/mongo/rpc/op_msg_rpc_impls.h index e788c8e684f..adc9a8f24f5 100644 --- a/src/mongo/rpc/op_msg_rpc_impls.h +++ b/src/mongo/rpc/op_msg_rpc_impls.h @@ -31,7 +31,6 @@ #include "mongo/rpc/reply_builder_interface.h" #include "mongo/rpc/reply_interface.h" #include "mongo/rpc/request_builder_interface.h" -#include "mongo/rpc/request_interface.h" #include "mongo/util/net/op_msg.h" namespace mongo { @@ -86,29 +85,6 @@ private: OpMsgBuilder _builder; }; -class OpMsgRequest final : public rpc::RequestInterface { -public: - explicit OpMsgRequest(mongo::OpMsgRequest msg) : _msg(std::move(msg)) {} - StringData getDatabase() const override { - return _msg.getDatabase(); - } - StringData getCommandName() const override { - return _msg.getCommandName(); - } - const BSONObj& getMetadata() const override { - return _msg.body; - } - const BSONObj& getCommandArgs() const override { - return _msg.body; - } - rpc::Protocol getProtocol() const override { - return rpc::Protocol::kOpMsg; - } - -private: - const mongo::OpMsgRequest _msg; -}; - class OpMsgRequestBuilder final : public rpc::RequestBuilderInterface { public: RequestBuilderInterface& setDatabase(StringData database) override { diff --git a/src/mongo/rpc/protocol.cpp b/src/mongo/rpc/protocol.cpp index 02d54c5db55..604dc708b52 100644 --- a/src/mongo/rpc/protocol.cpp +++ b/src/mongo/rpc/protocol.cpp @@ -69,6 +69,21 @@ constexpr ProtocolSetAndName protocolSetNames[] = { } // namespace +Protocol protocolForMessage(const Message& message) { + switch (message.operation()) { + case mongo::dbMsg: + return Protocol::kOpMsg; + case mongo::dbQuery: + return Protocol::kOpQuery; + case mongo::dbCommand: + return Protocol::kOpCommandV1; + default: + uasserted(ErrorCodes::UnsupportedFormat, + str::stream() << "Received a reply message with unexpected opcode: " + << message.operation()); + } +} + StatusWith<Protocol> negotiate(ProtocolSet fst, ProtocolSet snd) { using std::begin; using std::end; diff --git a/src/mongo/rpc/protocol.h b/src/mongo/rpc/protocol.h index 40f656d3e9f..57cb491bf5c 100644 --- a/src/mongo/rpc/protocol.h +++ b/src/mongo/rpc/protocol.h @@ -34,6 +34,7 @@ #include "mongo/base/status_with.h" #include "mongo/db/wire_version.h" +#include "mongo/util/net/message.h" namespace mongo { class BSONObj; @@ -84,6 +85,8 @@ const ProtocolSet kAll = kOpQueryOnly | kOpCommandOnly | kOpMsgOnly; } // namespace supports +Protocol protocolForMessage(const Message& message); + /** * Returns the protocol used to initiate the current operation. */ diff --git a/src/mongo/rpc/request_interface.h b/src/mongo/rpc/request_interface.h deleted file mode 100644 index b2edfb8dba3..00000000000 --- a/src/mongo/rpc/request_interface.h +++ /dev/null @@ -1,83 +0,0 @@ -/** - * 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. - */ - -#pragma once - -#include "mongo/base/disallow_copying.h" -#include "mongo/rpc/protocol.h" - -namespace mongo { -class BSONObj; -class Message; -class StringData; - -namespace rpc { - -/** - * An immutable view of an RPC message. - */ -class RequestInterface { - MONGO_DISALLOW_COPYING(RequestInterface); - -public: - virtual ~RequestInterface() = default; - - /** - * Gets the database that the command is to be executed on. - */ - virtual StringData getDatabase() const = 0; - - /** - * Gets the name of the command to execute. - */ - virtual StringData getCommandName() const = 0; - - /** - * Gets the metadata associated with the command request. This is information that is - * independent of any specific command, i.e. auditing information. See metadata.h for - * further details. - */ - virtual const BSONObj& getMetadata() const = 0; - - /** - * Gets the arguments to the command - this is passed to the command's run() method. - */ - virtual const BSONObj& getCommandArgs() const = 0; - - /** - * Gets the RPC protocol used to deserialize this message. This should only be used for - * asserts, and not for runtime behavior changes, which should be handled with polymorphism. - */ - virtual Protocol getProtocol() const = 0; - -protected: - RequestInterface() = default; -}; - -} // namespace rpc -} // namespace mongo diff --git a/src/mongo/rpc/unique_message.h b/src/mongo/rpc/unique_message.h index 7404a70fe73..d214462b70c 100644 --- a/src/mongo/rpc/unique_message.h +++ b/src/mongo/rpc/unique_message.h @@ -39,8 +39,7 @@ namespace mongo { namespace rpc { /** - * A wrapper around an owned message that includes access to an associated - * ReplyInterface or RequestInterface. + * A wrapper around an owned message that includes access to an associated ReplyInterface. */ template <typename MessageViewType> class UniqueMessage { diff --git a/src/mongo/tools/bridge.cpp b/src/mongo/tools/bridge.cpp index 6cae2ee2cf0..a6730e8a32c 100644 --- a/src/mongo/tools/bridge.cpp +++ b/src/mongo/tools/bridge.cpp @@ -44,7 +44,6 @@ #include "mongo/rpc/command_request.h" #include "mongo/rpc/factory.h" #include "mongo/rpc/reply_builder_interface.h" -#include "mongo/rpc/request_interface.h" #include "mongo/stdx/memory.h" #include "mongo/stdx/mutex.h" #include "mongo/stdx/thread.h" @@ -67,7 +66,7 @@ namespace mongo { namespace { -boost::optional<HostAndPort> extractHostInfo(const rpc::RequestInterface& request) { +boost::optional<HostAndPort> extractHostInfo(const OpMsgRequest& request) { // The initial isMaster request made by mongod and mongos processes should contain a hostInfo // field that identifies the process by its host:port. StringData cmdName = request.getCommandName(); @@ -75,8 +74,7 @@ boost::optional<HostAndPort> extractHostInfo(const rpc::RequestInterface& reques return boost::none; } - BSONObj args = request.getCommandArgs(); - if (auto hostInfoElem = args["hostInfo"]) { + if (auto hostInfoElem = request.body["hostInfo"]) { if (hostInfoElem.type() == String) { return HostAndPort{hostInfoElem.valueStringData()}; } @@ -152,18 +150,19 @@ public: request = std::move(swm.getValue()); } - std::unique_ptr<rpc::RequestInterface> cmdRequest; - if (request.operation() == dbQuery || request.operation() == dbCommand || - request.operation() == dbMsg) { - cmdRequest = rpc::makeRequest(&request); + boost::optional<OpMsgRequest> cmdRequest; + if ((request.operation() == dbQuery && + NamespaceString(DbMessage(request).getns()).isCommand()) || + request.operation() == dbCommand || request.operation() == dbMsg) { + cmdRequest = rpc::opMsgRequestFromAnyProtocol(request); if (receivingFirstMessage) { host = extractHostInfo(*cmdRequest); } std::string hostName = host ? (host->toString()) : "<unknown>"; LOG(1) << "Received \"" << cmdRequest->getCommandName() - << "\" command with arguments " << cmdRequest->getCommandArgs() - << " from " << hostName; + << "\" command with arguments " << cmdRequest->body << " from " + << hostName; } receivingFirstMessage = false; @@ -172,8 +171,8 @@ public: // Handle a message intended to configure the mongobridge and return a response. // The 'request' is consumed by the mongobridge and does not get forwarded to // 'dest'. - if (auto status = maybeProcessBridgeCommand(cmdRequest.get())) { - auto replyBuilder = rpc::makeReplyBuilder(cmdRequest->getProtocol()); + if (auto status = maybeProcessBridgeCommand(cmdRequest)) { + auto replyBuilder = rpc::makeReplyBuilder(rpc::protocolForMessage(request)); BSONObj metadata; BSONObj reply; StatusWith<BSONObj> commandReply(reply); @@ -208,8 +207,8 @@ public: std::string hostName = host ? (host->toString()) : "<unknown>"; if (cmdRequest) { log() << "Discarding \"" << cmdRequest->getCommandName() - << "\" command with arguments " - << cmdRequest->getCommandArgs() << " from " << hostName; + << "\" command with arguments " << cmdRequest->body + << " from " << hostName; } else { log() << "Discarding message " << request << " from " << hostName; } @@ -307,14 +306,14 @@ private: return command->run(cmdObj, _settingsMutex, _settings); } - boost::optional<Status> maybeProcessBridgeCommand(rpc::RequestInterface* cmdRequest) { + boost::optional<Status> maybeProcessBridgeCommand(boost::optional<OpMsgRequest> cmdRequest) { if (!cmdRequest) { return boost::none; } - if (auto forBridge = cmdRequest->getCommandArgs()["$forBridge"]) { + if (auto forBridge = cmdRequest->body["$forBridge"]) { if (forBridge.trueValue()) { - return runBridgeCommand(cmdRequest->getCommandName(), cmdRequest->getCommandArgs()); + return runBridgeCommand(cmdRequest->getCommandName(), cmdRequest->body); } return boost::none; } |