diff options
author | Adam Midvidy <amidvidy@gmail.com> | 2015-06-15 14:06:09 -0400 |
---|---|---|
committer | Adam Midvidy <amidvidy@gmail.com> | 2015-06-16 16:25:39 -0400 |
commit | 49c54afb7abfeceb0f9f03ed59df69b9cf22a5e7 (patch) | |
tree | 6e71691c78f7354d49bd87986c983aad2530d4ae | |
parent | 4eb15b34d157e2719fc9034f5956b698d96ef64e (diff) | |
download | mongo-49c54afb7abfeceb0f9f03ed59df69b9cf22a5e7.tar.gz |
SERVER-18292 expose protocol type of RPC classes and
check that they match in runCommandWithMetadata
24 files changed, 111 insertions, 19 deletions
diff --git a/src/mongo/client/dbclient.cpp b/src/mongo/client/dbclient.cpp index eca99e1614a..fc38fdb224e 100644 --- a/src/mongo/client/dbclient.cpp +++ b/src/mongo/client/dbclient.cpp @@ -280,6 +280,10 @@ namespace { StringData command, const BSONObj& metadata, const BSONObj& commandArgs) { + uassert(ErrorCodes::InvalidNamespace, str::stream() << "Database name '" << database + << "' is not valid.", + NamespaceString::validDBName(database)); + BSONObjBuilder metadataBob; metadataBob.appendElements(metadata); @@ -287,10 +291,6 @@ namespace { uassertStatusOK(_metadataWriter(&metadataBob)); } - uassert(ErrorCodes::InvalidNamespace, str::stream() << "Database name '" << database - << "' is not valid.", - NamespaceString::validDBName(database)); - auto requestBuilder = rpc::makeRequestBuilder(getClientRPCProtocols(), getServerRPCProtocols()); @@ -313,9 +313,14 @@ namespace { << "on host '" << host << "' ", call(*requestMsg, *replyMsg, false, &host)); - auto commandReply = rpc::makeReply(replyMsg.get(), - getClientRPCProtocols(), - getServerRPCProtocols()); + auto commandReply = rpc::makeReply(replyMsg.get()); + + uassert(ErrorCodes::RPCProtocolNegotiationFailed, + str::stream() << "Mismatched RPC protocols - request was '" + << opToString(requestMsg->operation()) << "' '" + << " but reply was '" + << opToString(replyMsg->operation()) << "' ", + requestBuilder->getProtocol() == commandReply->getProtocol()); if (ErrorCodes::SendStaleConfig == getStatusFromCommandResult(commandReply->getCommandReply())) { diff --git a/src/mongo/rpc/command_reply.cpp b/src/mongo/rpc/command_reply.cpp index 449308fbed3..7782b3b4997 100644 --- a/src/mongo/rpc/command_reply.cpp +++ b/src/mongo/rpc/command_reply.cpp @@ -71,6 +71,10 @@ namespace rpc { return _outputDocs; } + Protocol CommandReply::getProtocol() const { + return rpc::Protocol::kOpCommandV1; + } + bool operator==(const CommandReply& lhs, const CommandReply& rhs) { return std::tie(lhs._metadata, lhs._commandReply, lhs._outputDocs) == std::tie(rhs._metadata, rhs._commandReply, rhs._outputDocs); diff --git a/src/mongo/rpc/command_reply.h b/src/mongo/rpc/command_reply.h index 8f888e6190d..73a3fe60ccf 100644 --- a/src/mongo/rpc/command_reply.h +++ b/src/mongo/rpc/command_reply.h @@ -80,6 +80,8 @@ namespace rpc { */ DocumentRange getOutputDocs() const final; + Protocol getProtocol() const final; + friend bool operator==(const CommandReply& lhs, const CommandReply& rhs); friend bool operator!=(const CommandReply& lhs, const CommandReply& rhs); diff --git a/src/mongo/rpc/command_reply_builder.cpp b/src/mongo/rpc/command_reply_builder.cpp index 09d4156e09f..e52eb750ede 100644 --- a/src/mongo/rpc/command_reply_builder.cpp +++ b/src/mongo/rpc/command_reply_builder.cpp @@ -77,6 +77,10 @@ namespace rpc { return _state; } + Protocol CommandReplyBuilder::getProtocol() const { + return rpc::Protocol::kOpCommandV1; + } + std::unique_ptr<Message> CommandReplyBuilder::done() { invariant(_state == State::kOutputDocs); // TODO: we can elide a large copy here by transferring the internal buffer of diff --git a/src/mongo/rpc/command_reply_builder.h b/src/mongo/rpc/command_reply_builder.h index cf2cf01ee93..ec39986baba 100644 --- a/src/mongo/rpc/command_reply_builder.h +++ b/src/mongo/rpc/command_reply_builder.h @@ -33,6 +33,7 @@ #include "mongo/base/status_with.h" #include "mongo/db/jsobj.h" #include "mongo/rpc/document_range.h" +#include "mongo/rpc/protocol.h" #include "mongo/rpc/reply_builder_interface.h" #include "mongo/util/net/message.h" @@ -64,6 +65,10 @@ namespace rpc { State getState() const final; + Protocol getProtocol() const final; + + void reset() final; + /** * Writes data then transfers ownership of the message to the caller. * The behavior of calling any methods on the object is subsequently diff --git a/src/mongo/rpc/command_request.cpp b/src/mongo/rpc/command_request.cpp index 00a9fb7b477..f3006b73aa8 100644 --- a/src/mongo/rpc/command_request.cpp +++ b/src/mongo/rpc/command_request.cpp @@ -124,5 +124,9 @@ namespace rpc { return !(lhs == rhs); } + Protocol CommandRequest::getProtocol() const { + return rpc::Protocol::kOpCommandV1; + } + } // namespace rpc } // namespace mongo diff --git a/src/mongo/rpc/command_request.h b/src/mongo/rpc/command_request.h index b96323477c2..cf2b54a7d42 100644 --- a/src/mongo/rpc/command_request.h +++ b/src/mongo/rpc/command_request.h @@ -31,6 +31,7 @@ #include "mongo/base/string_data.h" #include "mongo/db/jsobj.h" #include "mongo/rpc/document_range.h" +#include "mongo/rpc/protocol.h" #include "mongo/rpc/request_interface.h" namespace mongo { @@ -87,6 +88,8 @@ namespace rpc { */ DocumentRange getInputDocs() const final; + Protocol getProtocol() const final; + friend bool operator==(const CommandRequest& lhs, const CommandRequest& rhs); friend bool operator!=(const CommandRequest& lhs, const CommandRequest& rhs); diff --git a/src/mongo/rpc/command_request_builder.cpp b/src/mongo/rpc/command_request_builder.cpp index b65ddc3f0b3..b06fe47075d 100644 --- a/src/mongo/rpc/command_request_builder.cpp +++ b/src/mongo/rpc/command_request_builder.cpp @@ -94,6 +94,10 @@ namespace rpc { return _state; } + Protocol CommandRequestBuilder::getProtocol() const { + return rpc::Protocol::kOpCommandV1; + } + std::unique_ptr<Message> CommandRequestBuilder::done() { invariant(_state == State::kInputDocs); // TODO: we can elide a large copy here by transferring the internal buffer of diff --git a/src/mongo/rpc/command_request_builder.h b/src/mongo/rpc/command_request_builder.h index 12298a48f3c..453b48f9cad 100644 --- a/src/mongo/rpc/command_request_builder.h +++ b/src/mongo/rpc/command_request_builder.h @@ -33,6 +33,7 @@ #include "mongo/base/string_data.h" #include "mongo/db/jsobj.h" #include "mongo/rpc/document_range.h" +#include "mongo/rpc/protocol.h" #include "mongo/rpc/request_builder_interface.h" #include "mongo/util/net/message.h" @@ -72,6 +73,8 @@ namespace rpc { State getState() const final; + Protocol getProtocol() const final; + /** * Writes data then transfers ownership of the message to the caller. * The behavior of calling any methods on the object is subsequently diff --git a/src/mongo/rpc/factory.cpp b/src/mongo/rpc/factory.cpp index 1edca3950b3..81bcf42c969 100644 --- a/src/mongo/rpc/factory.cpp +++ b/src/mongo/rpc/factory.cpp @@ -37,6 +37,8 @@ #include "mongo/rpc/protocol.h" #include "mongo/stdx/memory.h" #include "mongo/util/assert_util.h" +#include "mongo/util/mongoutils/str.h" +#include "mongo/util/net/message.h" namespace mongo { namespace rpc { @@ -53,16 +55,17 @@ namespace rpc { } } - std::unique_ptr<ReplyInterface> makeReply(const Message* unownedMessage, - ProtocolSet clientProtos, - ProtocolSet serverProtos) { - switch (uassertStatusOK(negotiate(clientProtos, serverProtos))) { - case Protocol::kOpQuery: + std::unique_ptr<ReplyInterface> makeReply(const Message* unownedMessage) { + + switch (unownedMessage->operation()) { + case mongo::opReply: return stdx::make_unique<LegacyReply>(unownedMessage); - case Protocol::kOpCommandV1: + case mongo::dbCommandReply: return stdx::make_unique<CommandReply>(unownedMessage); default: - MONGO_UNREACHABLE; + uasserted(ErrorCodes::UnsupportedFormat, + str::stream() << "Received a reply message with unexpected opcode: " + << unownedMessage->operation()); } } diff --git a/src/mongo/rpc/factory.h b/src/mongo/rpc/factory.h index 0e178a54ecb..93398d86e50 100644 --- a/src/mongo/rpc/factory.h +++ b/src/mongo/rpc/factory.h @@ -49,12 +49,12 @@ namespace rpc { */ std::unique_ptr<RequestBuilderInterface> makeRequestBuilder(ProtocolSet clientProtos, ProtocolSet serverProtos); + /** - * Returns the appropriate concrete Reply. Throws if one cannot be chosen. + * Returns the appropriate concrete Reply according to the contents of the message. + * Throws if one cannot be chosen. */ - std::unique_ptr<ReplyInterface> makeReply(const Message* unownedMessage, - ProtocolSet clientProtos, - ProtocolSet serverProtos); + std::unique_ptr<ReplyInterface> makeReply(const Message* unownedMessage); } // namespace rpc } // namespace mongo diff --git a/src/mongo/rpc/legacy_reply.cpp b/src/mongo/rpc/legacy_reply.cpp index 31923818160..3c16df28426 100644 --- a/src/mongo/rpc/legacy_reply.cpp +++ b/src/mongo/rpc/legacy_reply.cpp @@ -83,5 +83,9 @@ namespace rpc { return DocumentRange{}; } + Protocol LegacyReply::getProtocol() const { + return rpc::Protocol::kOpQuery; + } + } // namespace rpc } // namespace mongo diff --git a/src/mongo/rpc/legacy_reply.h b/src/mongo/rpc/legacy_reply.h index f4182c1d3a0..e839d305b42 100644 --- a/src/mongo/rpc/legacy_reply.h +++ b/src/mongo/rpc/legacy_reply.h @@ -32,6 +32,7 @@ #include "mongo/db/jsobj.h" #include "mongo/rpc/document_range.h" #include "mongo/rpc/reply_interface.h" +#include "mongo/rpc/protocol.h" namespace mongo { class Message; @@ -75,6 +76,8 @@ namespace rpc { */ DocumentRange getOutputDocs() const final; + Protocol getProtocol() const final; + private: const Message* _message; diff --git a/src/mongo/rpc/legacy_reply_builder.cpp b/src/mongo/rpc/legacy_reply_builder.cpp index 343e6874d4f..69134af3628 100644 --- a/src/mongo/rpc/legacy_reply_builder.cpp +++ b/src/mongo/rpc/legacy_reply_builder.cpp @@ -82,6 +82,10 @@ namespace rpc { return _state; } + Protocol LegacyReplyBuilder::getProtocol() const { + return rpc::Protocol::kOpQuery; + } + std::unique_ptr<Message> LegacyReplyBuilder::done() { invariant(_state == State::kOutputDocs); std::unique_ptr<Message> message = stdx::make_unique<Message>(); diff --git a/src/mongo/rpc/legacy_reply_builder.h b/src/mongo/rpc/legacy_reply_builder.h index cb8a52cae45..98dba8c8be5 100644 --- a/src/mongo/rpc/legacy_reply_builder.h +++ b/src/mongo/rpc/legacy_reply_builder.h @@ -33,6 +33,7 @@ #include "mongo/base/status_with.h" #include "mongo/bson/util/builder.h" #include "mongo/rpc/document_range.h" +#include "mongo/rpc/protocol.h" #include "mongo/rpc/reply_builder_interface.h" namespace mongo { @@ -55,6 +56,8 @@ namespace rpc { std::unique_ptr<Message> done() final; + Protocol getProtocol() const final; + private: BufBuilder _builder{}; BSONObj _metadata{}; diff --git a/src/mongo/rpc/legacy_request.cpp b/src/mongo/rpc/legacy_request.cpp index 459bc5f3d83..613cfe35ea1 100644 --- a/src/mongo/rpc/legacy_request.cpp +++ b/src/mongo/rpc/legacy_request.cpp @@ -74,5 +74,9 @@ namespace rpc { return DocumentRange{}; } + Protocol LegacyRequest::getProtocol() const { + return rpc::Protocol::kOpQuery; + } + } // namespace rpc } // namespace mongo diff --git a/src/mongo/rpc/legacy_request.h b/src/mongo/rpc/legacy_request.h index 93567a6fe6c..eb6df488e26 100644 --- a/src/mongo/rpc/legacy_request.h +++ b/src/mongo/rpc/legacy_request.h @@ -32,6 +32,7 @@ #include "mongo/db/dbmessage.h" #include "mongo/db/jsobj.h" #include "mongo/rpc/document_range.h" +#include "mongo/rpc/protocol.h" #include "mongo/rpc/request_interface.h" namespace mongo { @@ -87,6 +88,8 @@ namespace rpc { */ DocumentRange getInputDocs() const final; + Protocol getProtocol() const final; + private: const Message* _message; // TODO: metadata will be handled in SERVER-18236 diff --git a/src/mongo/rpc/legacy_request_builder.cpp b/src/mongo/rpc/legacy_request_builder.cpp index 6997bf739ea..fc96d738905 100644 --- a/src/mongo/rpc/legacy_request_builder.cpp +++ b/src/mongo/rpc/legacy_request_builder.cpp @@ -110,6 +110,10 @@ namespace rpc { return _state; } + Protocol LegacyRequestBuilder::getProtocol() const { + return rpc::Protocol::kOpQuery; + } + std::unique_ptr<Message> LegacyRequestBuilder::done() { invariant(_state == State::kInputDocs); _message->setData(dbQuery, _builder.buf(), _builder.len()); diff --git a/src/mongo/rpc/legacy_request_builder.h b/src/mongo/rpc/legacy_request_builder.h index 0beed3b9a71..83890df45e2 100644 --- a/src/mongo/rpc/legacy_request_builder.h +++ b/src/mongo/rpc/legacy_request_builder.h @@ -56,6 +56,8 @@ namespace rpc { State getState() const final; + Protocol getProtocol() const final; + std::unique_ptr<Message> done() final; private: diff --git a/src/mongo/rpc/protocol.h b/src/mongo/rpc/protocol.h index ba370a90e69..bb77caf5e85 100644 --- a/src/mongo/rpc/protocol.h +++ b/src/mongo/rpc/protocol.h @@ -83,7 +83,7 @@ namespace supports { /** * Converts a ProtocolSet to a string. Currently only the predefined ProtocolSets in the * 'supports' namespace are supported. - * + * * This intentionally does not conform to the STL 'to_string' convention so that it will * not conflict with the to_string overload for uint64_t. */ diff --git a/src/mongo/rpc/reply_builder_interface.h b/src/mongo/rpc/reply_builder_interface.h index 00942fe1dac..1abc04bba9e 100644 --- a/src/mongo/rpc/reply_builder_interface.h +++ b/src/mongo/rpc/reply_builder_interface.h @@ -32,6 +32,7 @@ #include "mongo/base/disallow_copying.h" #include "mongo/base/status_with.h" +#include "mongo/rpc/protocol.h" namespace mongo { class BSONObj; @@ -112,6 +113,12 @@ namespace rpc { virtual State getState() const = 0; /** + * Gets the protocol used to serialize this reply. This should be used for validity checks + * only - runtime behavior changes should be implemented with polymorphism. + */ + virtual Protocol getProtocol() const = 0; + + /** * Writes data then transfers ownership of the message to the caller. The behavior of * calling any methods on the builder is subsequently undefined. */ diff --git a/src/mongo/rpc/reply_interface.h b/src/mongo/rpc/reply_interface.h index 3fd5644f785..ac0514dc64f 100644 --- a/src/mongo/rpc/reply_interface.h +++ b/src/mongo/rpc/reply_interface.h @@ -29,6 +29,7 @@ #pragma once #include "mongo/base/disallow_copying.h" +#include "mongo/rpc/protocol.h" namespace mongo { class BSONObj; @@ -68,6 +69,12 @@ namespace rpc { */ virtual DocumentRange getOutputDocs() const = 0; + /** + * Gets the protocol used to deserialize this reply. This should be used for validity + * checks only - runtime behavior changes should be implemented with polymorphism. + */ + virtual Protocol getProtocol() const = 0; + protected: ReplyInterface() = default; }; diff --git a/src/mongo/rpc/request_builder_interface.h b/src/mongo/rpc/request_builder_interface.h index 39623e12a10..7297bf393c5 100644 --- a/src/mongo/rpc/request_builder_interface.h +++ b/src/mongo/rpc/request_builder_interface.h @@ -31,6 +31,7 @@ #include <memory> #include "mongo/base/disallow_copying.h" +#include "mongo/rpc/protocol.h" namespace mongo { class Message; @@ -104,6 +105,12 @@ namespace rpc { virtual State getState() const = 0; /** + * Gets the protocol used to serialize this request. This should only be used for asserts, + * and not for runtime behavior changes, which should be handled with polymorphism. + */ + virtual Protocol getProtocol() const = 0; + + /** * Writes data then transfers ownership of the message to the caller. * The behavior of calling any methods on the object is subsequently * undefined. diff --git a/src/mongo/rpc/request_interface.h b/src/mongo/rpc/request_interface.h index 27f407f3f5c..0933e728ab9 100644 --- a/src/mongo/rpc/request_interface.h +++ b/src/mongo/rpc/request_interface.h @@ -29,6 +29,7 @@ #pragma once #include "mongo/base/disallow_copying.h" +#include "mongo/rpc/protocol.h" namespace mongo { class BSONObj; @@ -80,6 +81,12 @@ namespace rpc { */ virtual DocumentRange getInputDocs() 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; }; |