From 4b51940f6e36878261dc18b8867c27f44c4975a9 Mon Sep 17 00:00:00 2001 From: Moustafa Maher Date: Fri, 15 Jan 2021 01:52:57 +0000 Subject: SERVER-52547 Avoid reparsing the command object multiple times --- src/mongo/db/commands.h | 49 ++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 40 insertions(+), 9 deletions(-) (limited to 'src/mongo/db/commands.h') diff --git a/src/mongo/db/commands.h b/src/mongo/db/commands.h index dc1a53f2e8f..5dcd2d94b77 100644 --- a/src/mongo/db/commands.h +++ b/src/mongo/db/commands.h @@ -958,10 +958,11 @@ public: * */ template -class BasicCommandWithRequestParser : public BasicCommand { -public: +class BasicCommandWithRequestParser : public BasicCommandWithReplyBuilderInterface { +protected: // Commands that only have a single name don't need to define any constructors. - BasicCommandWithRequestParser() : BasicCommand(Derived::Request::kCommandName) {} + BasicCommandWithRequestParser() + : BasicCommandWithReplyBuilderInterface(Derived::Request::kCommandName) {} bool runWithReplyBuilder(OperationContext* opCtx, const std::string& db, @@ -970,21 +971,51 @@ public: auto result = replyBuilder->getBodyBuilder(); // To enforce API versioning - using RequestType = typename Derived::Request; - auto request = RequestType::parse( - IDLParserErrorContext(Derived::Request::kCommandName, - APIParameters::get(opCtx).getAPIStrict().value_or(false)), - cmdObj); + auto requestParser = RequestParser(opCtx, cmdObj); - auto cmdDone = run(opCtx, db, request.toBSON(cmdObj), result); + auto cmdDone = runWithRequestParser(opCtx, db, cmdObj, requestParser, result); validateResult(result.asTempObj()); return cmdDone; } + class RequestParser; + + /** + * Runs the given command. Returns true upon success. + */ + virtual bool runWithRequestParser(OperationContext* opCtx, + const std::string& db, + const BSONObj& cmdObj, + const RequestParser& requestParser, + BSONObjBuilder& result) = 0; + // Custom logic to validate results to enforce API versioning. virtual void validateResult(const BSONObj& resultObj) = 0; }; +template +class BasicCommandWithRequestParser::RequestParser { +public: + using RequestType = typename Derived::Request; + + RequestParser(OperationContext* opCtx, const BSONObj& cmdObj) + : _request{_parseRequest(opCtx, cmdObj)} {} + + const RequestType& request() const { + return _request; + } + +private: + static RequestType _parseRequest(OperationContext* opCtx, const BSONObj& cmdObj) { + return RequestType::parse( + IDLParserErrorContext(RequestType::kCommandName, + APIParameters::get(opCtx).getAPIStrict().value_or(false)), + cmdObj); + } + + RequestType _request; +}; + /** * Deprecated. Do not add new subclasses. */ -- cgit v1.2.1