diff options
author | Mathias Stearn <mathias@10gen.com> | 2017-06-12 16:24:36 -0400 |
---|---|---|
committer | Mathias Stearn <mathias@10gen.com> | 2017-06-19 19:02:31 -0400 |
commit | d8ef9342757fb729169c5cd44baa9052f5809b3f (patch) | |
tree | a1fa1e6d7b296b9a1be974a69018d6cde54cd4a1 /src/mongo/client | |
parent | 36c13338c54d9cd7bb978d56487fc692374c8255 (diff) | |
download | mongo-d8ef9342757fb729169c5cd44baa9052f5809b3f.tar.gz |
SERVER-29319 Expose OpMsgRequest interface in DBClient
Diffstat (limited to 'src/mongo/client')
-rw-r--r-- | src/mongo/client/dbclient.cpp | 76 | ||||
-rw-r--r-- | src/mongo/client/dbclient_rs.cpp | 30 | ||||
-rw-r--r-- | src/mongo/client/dbclient_rs.h | 13 | ||||
-rw-r--r-- | src/mongo/client/dbclientinterface.h | 50 |
4 files changed, 78 insertions, 91 deletions
diff --git a/src/mongo/client/dbclient.cpp b/src/mongo/client/dbclient.cpp index 669ca102a6a..4732658795c 100644 --- a/src/mongo/client/dbclient.cpp +++ b/src/mongo/client/dbclient.cpp @@ -169,13 +169,12 @@ const rpc::ReplyMetadataReader& DBClientWithCommands::getReplyMetadataReader() { return _metadataReader; } -rpc::UniqueReply DBClientWithCommands::runCommandWithMetadata(StringData database, - StringData command, - const BSONObj& metadataIn, - const BSONObj& commandArgs) { +std::pair<rpc::UniqueReply, DBClientWithCommands*> DBClientWithCommands::runCommandWithTarget( + OpMsgRequest request) { uassert(ErrorCodes::InvalidNamespace, - str::stream() << "Database name '" << database << "' is not valid.", - NamespaceString::validDBName(database, NamespaceString::DollarInDbNameBehavior::Allow)); + str::stream() << "Database name '" << request.getDatabase() << "' is not valid.", + NamespaceString::validDBName(request.getDatabase(), + NamespaceString::DollarInDbNameBehavior::Allow)); // Make sure to reconnect if needed before building our request, since the request depends on // the negotiated protocol which can change due to a reconnect. @@ -184,19 +183,15 @@ rpc::UniqueReply DBClientWithCommands::runCommandWithMetadata(StringData databas // call() oddly takes this by pointer, so we need to put it on the stack. auto host = getServerAddress(); - auto metadata = metadataIn; - if (_metadataWriter) { - BSONObjBuilder metadataBob(std::move(metadata)); + BSONObjBuilder metadataBob(std::move(request.body)); uassertStatusOK( _metadataWriter((haveClient() ? cc().getOperationContext() : nullptr), &metadataBob)); - metadata = metadataBob.obj(); + request.body = metadataBob.obj(); } - auto requestMsg = rpc::messageFromOpMsgRequest( - getClientRPCProtocols(), - getServerRPCProtocols(), - OpMsgRequest::fromDBAndBody(database, std::move(commandArgs), metadata)); + auto requestMsg = + rpc::messageFromOpMsgRequest(getClientRPCProtocols(), getServerRPCProtocols(), request); Message replyMsg; @@ -206,7 +201,7 @@ rpc::UniqueReply DBClientWithCommands::runCommandWithMetadata(StringData databas uassert(ErrorCodes::HostUnreachable, str::stream() << "network error while attempting to run " << "command '" - << command + << request.getCommandName() << "' " << "on host '" << host @@ -234,43 +229,48 @@ rpc::UniqueReply DBClientWithCommands::runCommandWithMetadata(StringData databas commandReply->getCommandReply()); } - return rpc::UniqueReply(std::move(replyMsg), std::move(commandReply)); + return {rpc::UniqueReply(std::move(replyMsg), std::move(commandReply)), this}; +} + +rpc::UniqueReply DBClientWithCommands::runCommandWithMetadata(StringData database, + StringData command, + const BSONObj& metadata, + BSONObj commandArgs) { + return runCommand(OpMsgRequest::fromDBAndBody(database, std::move(commandArgs), metadata)); } std::tuple<rpc::UniqueReply, DBClientWithCommands*> DBClientWithCommands::runCommandWithMetadataAndTarget(StringData database, StringData command, const BSONObj& metadata, - const BSONObj& commandArgs) { - return std::make_tuple(runCommandWithMetadata(database, command, metadata, commandArgs), this); + BSONObj commandArgs) { + return runCommandWithTarget( + OpMsgRequest::fromDBAndBody(database, std::move(commandArgs), metadata)); } std::tuple<bool, DBClientWithCommands*> DBClientWithCommands::runCommandWithTarget( - const string& dbname, const BSONObj& cmd, BSONObj& info, int options) { + const string& dbname, BSONObj cmd, BSONObj& info, int options) { BSONObj upconvertedCmd; BSONObj upconvertedMetadata; // TODO: This will be downconverted immediately if the underlying // requestBuilder is a legacyRequest builder. Not sure what the best // way to get around that is without breaking the abstraction. - std::tie(upconvertedCmd, upconvertedMetadata) = rpc::upconvertRequestMetadata(cmd, options); - - auto commandName = upconvertedCmd.firstElementFieldName(); + std::tie(upconvertedCmd, upconvertedMetadata) = + rpc::upconvertRequestMetadata(std::move(cmd), options); - auto resultTuple = - runCommandWithMetadataAndTarget(dbname, commandName, upconvertedMetadata, upconvertedCmd); - auto result = std::move(std::get<0>(resultTuple)); + auto result = runCommandWithTarget( + OpMsgRequest::fromDBAndBody(dbname, std::move(upconvertedCmd), upconvertedMetadata)); - info = result->getCommandReply().getOwned(); - - return std::make_tuple(isOk(info), std::get<1>(resultTuple)); + info = result.first->getCommandReply().getOwned(); + return std::make_tuple(isOk(info), result.second); } bool DBClientWithCommands::runCommand(const string& dbname, - const BSONObj& cmd, + BSONObj cmd, BSONObj& info, int options) { - auto res = runCommandWithTarget(dbname, cmd, info, options); + auto res = runCommandWithTarget(dbname, std::move(cmd), info, options); return std::get<0>(res); } @@ -918,18 +918,18 @@ void DBClientConnection::logout(const string& dbname, BSONObj& info) { runCommand(dbname, BSON("logout" << 1), info); } -bool DBClientConnection::runCommand(const string& dbname, - const BSONObj& cmd, - BSONObj& info, - int options) { - if (DBClientWithCommands::runCommand(dbname, cmd, info, options)) - return true; +std::pair<rpc::UniqueReply, DBClientWithCommands*> DBClientConnection::runCommandWithTarget( + OpMsgRequest request) { + auto out = DBClientWithCommands::runCommandWithTarget(std::move(request)); if (!_parentReplSetName.empty()) { - handleNotMasterResponse(info["errmsg"]); + const auto replyBody = out.first->getCommandReply(); + if (!isOk(replyBody)) { + handleNotMasterResponse(replyBody["errmsg"]); + } } - return false; + return out; } void DBClientConnection::_checkConnection() { diff --git a/src/mongo/client/dbclient_rs.cpp b/src/mongo/client/dbclient_rs.cpp index cd80a61f79d..38948381508 100644 --- a/src/mongo/client/dbclient_rs.cpp +++ b/src/mongo/client/dbclient_rs.cpp @@ -903,19 +903,8 @@ void DBClientReplicaSet::checkResponse(const char* data, } } -rpc::UniqueReply DBClientReplicaSet::runCommandWithMetadata(StringData database, - StringData command, - const BSONObj& metadata, - const BSONObj& commandArgs) { - auto ret = runCommandWithMetadataAndTarget(database, command, metadata, commandArgs); - return std::move(std::get<0>(ret)); -} - -std::tuple<rpc::UniqueReply, DBClientWithCommands*> -DBClientReplicaSet::runCommandWithMetadataAndTarget(StringData database, - StringData command, - const BSONObj& metadata, - const BSONObj& commandArgs) { +std::pair<rpc::UniqueReply, DBClientWithCommands*> DBClientReplicaSet::runCommandWithTarget( + OpMsgRequest request) { // This overload exists so we can parse out the read preference and then use server // selection directly without having to re-parse the raw message. @@ -923,15 +912,14 @@ DBClientReplicaSet::runCommandWithMetadataAndTarget(StringData database, // so we don't have to re-parse it, however, that will come with its own set of // complications (e.g. some kind of base class or concept for MetadataSerializable // objects). For now we do it the stupid way. - auto readPref = uassertStatusOK(ReadPreferenceSetting::fromContainingBSON(metadata)); + auto readPref = uassertStatusOK(ReadPreferenceSetting::fromContainingBSON(request.body)); if (readPref.pref == ReadPreference::PrimaryOnly || // If the command is not runnable on a secondary, we run it on the primary // regardless of the read preference. - !_isSecondaryCommand(command, commandArgs)) { + !_isSecondaryCommand(request.getCommandName(), request.body)) { auto conn = checkMaster(); - return std::make_tuple( - conn->runCommandWithMetadata(database, command, metadata, commandArgs), conn); + return conn->runCommandWithTarget(std::move(request)); } auto rpShared = std::make_shared<ReadPreferenceSetting>(std::move(readPref)); @@ -942,10 +930,8 @@ DBClientReplicaSet::runCommandWithMetadataAndTarget(StringData database, if (conn == nullptr) { break; } - // We can't move database and command in case this throws - // and we retry. - return std::make_tuple( - conn->runCommandWithMetadata(database, command, metadata, commandArgs), conn); + // We can't move the request since we need it to retry. + return conn->runCommandWithTarget(request); } catch (const DBException& ex) { _invalidateLastSlaveOkCache(ex.toStatus()); } @@ -954,7 +940,7 @@ DBClientReplicaSet::runCommandWithMetadataAndTarget(StringData database, uasserted(ErrorCodes::NodeNotFound, str::stream() << "Could not satisfy $readPreference of '" << readPref.toString() << "' while attempting to run command " - << command); + << request.getCommandName()); } bool DBClientReplicaSet::call(Message& toSend, diff --git a/src/mongo/client/dbclient_rs.h b/src/mongo/client/dbclient_rs.h index 02e9db27f65..5369bee9ea6 100644 --- a/src/mongo/client/dbclient_rs.h +++ b/src/mongo/client/dbclient_rs.h @@ -186,16 +186,9 @@ public: return true; } - rpc::UniqueReply runCommandWithMetadata(StringData database, - StringData command, - const BSONObj& metadata, - const BSONObj& commandArgs) final; - - std::tuple<rpc::UniqueReply, DBClientWithCommands*> runCommandWithMetadataAndTarget( - StringData database, - StringData command, - const BSONObj& metadata, - const BSONObj& commandArgs) final; + using DBClientWithCommands::runCommandWithTarget; + std::pair<rpc::UniqueReply, DBClientWithCommands*> runCommandWithTarget( + OpMsgRequest request) final; void setRequestMetadataWriter(rpc::RequestMetadataWriter writer) final; diff --git a/src/mongo/client/dbclientinterface.h b/src/mongo/client/dbclientinterface.h index 6d2976d08e4..41296ff6a72 100644 --- a/src/mongo/client/dbclientinterface.h +++ b/src/mongo/client/dbclientinterface.h @@ -47,6 +47,7 @@ #include "mongo/util/mongoutils/str.h" #include "mongo/util/net/abstract_message_port.h" #include "mongo/util/net/message.h" +#include "mongo/util/net/op_msg.h" namespace mongo { @@ -410,15 +411,29 @@ public: const rpc::ReplyMetadataReader& getReplyMetadataReader(); /** + * Runs the specified command request. + */ + virtual std::pair<rpc::UniqueReply, DBClientWithCommands*> runCommandWithTarget( + OpMsgRequest request); + + /** + * Runs the specified command request. This thin wrapper just unwraps the reply and ignores the + * target connection from the above runCommandWithTarget(). + */ + rpc::UniqueReply runCommand(OpMsgRequest request) { + return runCommandWithTarget(std::move(request)).first; + } + + /** * Runs a database command. This variant allows the caller to manually specify the metadata * for the request, and receive it for the reply. * * TODO: rename this to runCommand, and change the old one to runCommandLegacy. */ - virtual rpc::UniqueReply runCommandWithMetadata(StringData database, - StringData command, - const BSONObj& metadata, - const BSONObj& commandArgs); + rpc::UniqueReply runCommandWithMetadata(StringData database, + StringData command, + const BSONObj& metadata, + BSONObj commandArgs); /* * This wraps up the runCommandWithMetadata function above, but returns the DBClient that @@ -427,11 +442,8 @@ public: * * This is used in the shell so that cursors can send getMore through the correct connection. */ - virtual std::tuple<rpc::UniqueReply, DBClientWithCommands*> runCommandWithMetadataAndTarget( - StringData database, - StringData command, - const BSONObj& metadata, - const BSONObj& commandArgs); + std::tuple<rpc::UniqueReply, DBClientWithCommands*> runCommandWithMetadataAndTarget( + StringData database, StringData command, const BSONObj& metadata, BSONObj commandArgs); /** Run a database command. Database commands are represented as BSON objects. Common database commands have prebuilt helper functions -- see below. If a helper is not available you can @@ -446,10 +458,7 @@ public: @return true if the command returned "ok". */ - virtual bool runCommand(const std::string& dbname, - const BSONObj& cmd, - BSONObj& info, - int options = 0); + bool runCommand(const std::string& dbname, BSONObj cmd, BSONObj& info, int options = 0); /* * This wraps up the runCommand function avove, but returns the DBClient that actually ran @@ -458,10 +467,10 @@ public: * * This is used in the shell so that cursors can send getMore through the correct connection. */ - virtual std::tuple<bool, DBClientWithCommands*> runCommandWithTarget(const std::string& dbname, - const BSONObj& cmd, - BSONObj& info, - int options = 0); + std::tuple<bool, DBClientWithCommands*> runCommandWithTarget(const std::string& dbname, + BSONObj cmd, + BSONObj& info, + int options = 0); /** * Authenticates to another cluster member using appropriate authentication data. @@ -1056,10 +1065,9 @@ public: const BSONObj* fieldsToReturn, int queryOptions); - virtual bool runCommand(const std::string& dbname, - const BSONObj& cmd, - BSONObj& info, - int options = 0); + using DBClientWithCommands::runCommandWithTarget; + std::pair<rpc::UniqueReply, DBClientWithCommands*> runCommandWithTarget( + OpMsgRequest request) override; /** @return true if this connection is currently in a failed state. When autoreconnect is on, |