summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdam Midvidy <amidvidy@gmail.com>2015-06-15 14:06:09 -0400
committerAdam Midvidy <amidvidy@gmail.com>2015-06-16 16:25:39 -0400
commit49c54afb7abfeceb0f9f03ed59df69b9cf22a5e7 (patch)
tree6e71691c78f7354d49bd87986c983aad2530d4ae
parent4eb15b34d157e2719fc9034f5956b698d96ef64e (diff)
downloadmongo-49c54afb7abfeceb0f9f03ed59df69b9cf22a5e7.tar.gz
SERVER-18292 expose protocol type of RPC classes and
check that they match in runCommandWithMetadata
-rw-r--r--src/mongo/client/dbclient.cpp19
-rw-r--r--src/mongo/rpc/command_reply.cpp4
-rw-r--r--src/mongo/rpc/command_reply.h2
-rw-r--r--src/mongo/rpc/command_reply_builder.cpp4
-rw-r--r--src/mongo/rpc/command_reply_builder.h5
-rw-r--r--src/mongo/rpc/command_request.cpp4
-rw-r--r--src/mongo/rpc/command_request.h3
-rw-r--r--src/mongo/rpc/command_request_builder.cpp4
-rw-r--r--src/mongo/rpc/command_request_builder.h3
-rw-r--r--src/mongo/rpc/factory.cpp17
-rw-r--r--src/mongo/rpc/factory.h8
-rw-r--r--src/mongo/rpc/legacy_reply.cpp4
-rw-r--r--src/mongo/rpc/legacy_reply.h3
-rw-r--r--src/mongo/rpc/legacy_reply_builder.cpp4
-rw-r--r--src/mongo/rpc/legacy_reply_builder.h3
-rw-r--r--src/mongo/rpc/legacy_request.cpp4
-rw-r--r--src/mongo/rpc/legacy_request.h3
-rw-r--r--src/mongo/rpc/legacy_request_builder.cpp4
-rw-r--r--src/mongo/rpc/legacy_request_builder.h2
-rw-r--r--src/mongo/rpc/protocol.h2
-rw-r--r--src/mongo/rpc/reply_builder_interface.h7
-rw-r--r--src/mongo/rpc/reply_interface.h7
-rw-r--r--src/mongo/rpc/request_builder_interface.h7
-rw-r--r--src/mongo/rpc/request_interface.h7
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;
};