diff options
author | Billy Donahue <billy.donahue@mongodb.com> | 2018-03-05 15:48:48 -0500 |
---|---|---|
committer | Billy Donahue <billy.donahue@mongodb.com> | 2018-03-06 10:04:53 -0500 |
commit | e3a3f54a6c0ec4f471e0aff7a48b8a30f8c0e9cb (patch) | |
tree | 9c2f4ac5a4d8751336397c8af59a08bf78f1c201 /src/mongo/db/commands.h | |
parent | 5dfa372b25b1a26bb12e09fdb029ff219b0f5343 (diff) | |
download | mongo-e3a3f54a6c0ec4f471e0aff7a48b8a30f8c0e9cb.tar.gz |
SERVER-33065 CommandReplyBuilder and CommandInvocation
Revert "Revert "SERVER-33065 CommandReplyBuilder and CommandInvocation""
This reverts commit 74177edb35b6ce7594e4751051010ceade592484.
Leave out the unintentional repl/ change this time.
Diffstat (limited to 'src/mongo/db/commands.h')
-rw-r--r-- | src/mongo/db/commands.h | 243 |
1 files changed, 181 insertions, 62 deletions
diff --git a/src/mongo/db/commands.h b/src/mongo/db/commands.h index 5779d89e7e9..2a9611fb70f 100644 --- a/src/mongo/db/commands.h +++ b/src/mongo/db/commands.h @@ -82,6 +82,13 @@ struct CommandHelpers { static bool appendCommandStatus(BSONObjBuilder& result, const Status& status); /** + * If "ok" field is present in `reply`, uses its truthiness. + * Otherwise, the absence of failure is considered success, `reply` is patched to indicate it. + * Returns true if reply indicates a success. + */ + static bool extractOrAppendOk(BSONObjBuilder& reply); + + /** * Helper for setting a writeConcernError field in the command result object if * a writeConcern error occurs. * @@ -187,6 +194,8 @@ struct CommandHelpers { static constexpr StringData kHelpFieldName = "help"_sd; }; +class CommandInvocation; + /** * Serves as a base for server commands. See the constructor for more details. */ @@ -207,6 +216,9 @@ public: // See https://gcc.gnu.org/wiki/VerboseDiagnostics#missing_vtable virtual ~Command(); + virtual std::unique_ptr<CommandInvocation> parse(OperationContext* opCtx, + const OpMsgRequest& request); + /** * Returns the command's name. This value never changes for the lifetime of the command. */ @@ -240,16 +252,6 @@ public: } /** - * supportsWriteConcern returns true if this command should be parsed for a writeConcern - * field and wait for that write concern to be satisfied after the command runs. - * - * @param cmd is a BSONObj representation of the command that is used to determine if the - * the command supports a write concern. Ex. aggregate only supports write concern - * when $out is provided. - */ - virtual bool supportsWriteConcern(const BSONObj& cmd) const = 0; - - /** * Return true if only the admin ns has privileges to run this command. */ virtual bool adminOnly() const { @@ -267,7 +269,7 @@ public: return false; } - virtual AllowedOnSecondary secondaryAllowed(ServiceContext*) const = 0; + virtual AllowedOnSecondary secondaryAllowed(ServiceContext* context) const = 0; /** * Override and return fales if the command opcounters should not be incremented on @@ -292,23 +294,6 @@ public: } /** - * Commands which can be explained override this method. Any operation which has a query - * part and executes as a tree of execution stages can be explained. A command should - * implement explain by: - * - * 1) Calling its custom parse function in order to parse the command. The output of - * this function should be a CanonicalQuery (representing the query part of the - * operation), and a PlanExecutor which wraps the tree of execution stages. - * - * 2) Calling Explain::explainStages(...) on the PlanExecutor. This is the function - * which knows how to convert an execution stage tree into explain output. - */ - virtual Status explain(OperationContext* opCtx, - const std::string& dbname, - const BSONObj& cmdObj, - ExplainOptions::Verbosity verbosity, - BSONObjBuilder* out) const; - /** * Checks if the client associated with the given OperationContext is authorized to run this * command. */ @@ -343,33 +328,6 @@ public: } /** - * Returns true if this Command supports the given readConcern level. Takes the command object - * and the name of the database on which it was invoked as arguments, so that readConcern can be - * conditionally rejected based on the command's parameters and/or namespace. - * - * If a readConcern level argument is sent to a command that returns false the command processor - * will reject the command, returning an appropriate error message. - * - * Note that this is never called on mongos. Sharded commands are responsible for forwarding - * the option to the shards as needed. We rely on the shards to fail the commands in the - * cases where it isn't supported. - */ - virtual bool supportsReadConcern(const std::string& dbName, - const BSONObj& cmdObj, - repl::ReadConcernLevel level) const { - return level == repl::ReadConcernLevel::kLocalReadConcern; - } - - /** - * Returns true if command allows afterClusterTime in its readConcern. The command may not allow - * it if it is specifically intended not to take any LockManager locks. Waiting for - * afterClusterTime takes the MODE_IS lock. - */ - virtual bool allowsAfterClusterTime(const BSONObj& cmdObj) const { - return true; - } - - /** * Returns LogicalOp for this command. */ virtual LogicalOp getLogicalOp() const { @@ -402,13 +360,6 @@ public: } /** - * Runs the command. - * - * Forwards to enhancedRun, but additionally runs audit checks if run throws unauthorized. - */ - bool publicRun(OperationContext* opCtx, const OpMsgRequest& request, BSONObjBuilder& result); - - /** * Generates a reply from the 'help' information associated with a command. The state of * the passed ReplyBuilder will be in kOutputDocs after calling this method. */ @@ -456,6 +407,62 @@ public: static bool testCommandsEnabled; private: + class InvocationShim; + + /** + * Commands which can be explained override this method. Any operation which has a query + * part and executes as a tree of execution stages can be explained. A command should + * implement explain by: + * + * 1) Calling its custom parse function in order to parse the command. The output of + * this function should be a CanonicalQuery (representing the query part of the + * operation), and a PlanExecutor which wraps the tree of execution stages. + * + * 2) Calling Explain::explainStages(...) on the PlanExecutor. This is the function + * which knows how to convert an execution stage tree into explain output. + */ + virtual Status explain(OperationContext* opCtx, + const OpMsgRequest& request, + ExplainOptions::Verbosity verbosity, + BSONObjBuilder* out) const; + + /** + * supportsWriteConcern returns true if this command should be parsed for a writeConcern + * field and wait for that write concern to be satisfied after the command runs. + * + * @param cmd is a BSONObj representation of the command that is used to determine if the + * the command supports a write concern. Ex. aggregate only supports write concern + * when $out is provided. + */ + virtual bool supportsWriteConcern(const BSONObj& cmd) const = 0; + + /** + * Returns true if this Command supports the given readConcern level. Takes the command object + * and the name of the database on which it was invoked as arguments, so that readConcern can be + * conditionally rejected based on the command's parameters and/or namespace. + * + * If a readConcern level argument is sent to a command that returns false the command processor + * will reject the command, returning an appropriate error message. + * + * Note that this is never called on mongos. Sharded commands are responsible for forwarding + * the option to the shards as needed. We rely on the shards to fail the commands in the + * cases where it isn't supported. + */ + virtual bool supportsReadConcern(const std::string& dbName, + const BSONObj& cmdObj, + repl::ReadConcernLevel level) const { + return level == repl::ReadConcernLevel::kLocalReadConcern; + } + + /** + * Returns true if command allows afterClusterTime in its readConcern. The command may not allow + * it if it is specifically intended not to take any LockManager locks. Waiting for + * afterClusterTime takes the MODE_IS lock. + */ + virtual bool allowsAfterClusterTime(const BSONObj& cmdObj) const { + return true; + } + /** * Runs the command. * @@ -480,6 +487,118 @@ private: ServerStatusMetricField<Counter64> _commandsFailedMetric; }; +class CommandReplyBuilder { +public: + explicit CommandReplyBuilder(BSONObjBuilder bodyObj); + + CommandReplyBuilder(const CommandReplyBuilder&) = delete; + CommandReplyBuilder& operator=(const CommandReplyBuilder&) = delete; + + /** + * Returns a BSONObjBuilder that can be used to build the reply in-place. The returned + * builder (or an object into which it has been moved) must be completed before calling + * any more methods on this object. A builder is completed by a call to `done()` or by + * its destructor. Can be called repeatedly to append multiple things to the reply, as + * long as each returned builder must be completed between calls. + */ + BSONObjBuilder getBodyBuilder() const; + + void reset(); + +private: + BufBuilder* const _bodyBuf; + const std::size_t _bodyOffset; +}; + +/** + * Represents a single invocation of a given command. + */ +class CommandInvocation { +public: + CommandInvocation(const Command* definition) : _definition(definition) {} + virtual ~CommandInvocation(); + + /** + * Runs the command, filling in result. Any exception thrown from here will cause result + * to be reset and filled in with the error. Non-const to permit modifying the request + * type to perform normalization. Calls that return normally without setting an "ok" + * field into result are assumed to have completed successfully. Failure should be + * indicated either by throwing (preferred), or by calling + * `CommandHelpers::extractOrAppendOk`. + */ + virtual void run(OperationContext* opCtx, CommandReplyBuilder* result) = 0; + + virtual void explain(OperationContext* opCtx, + ExplainOptions::Verbosity verbosity, + BSONObjBuilder* result) = 0; + + /** + * The primary namespace on which this command operates. May just be the db. + */ + virtual NamespaceString ns() const = 0; + + /** + * Returns true if this command should be parsed for a writeConcern field and wait + * for that write concern to be satisfied after the command runs. + */ + virtual bool supportsWriteConcern() const = 0; + + virtual Command::AllowedOnSecondary secondaryAllowed(ServiceContext* context) const = 0; + + /** + * Returns true if this Command supports the given readConcern level. Takes the command object + * and the name of the database on which it was invoked as arguments, so that readConcern can be + * conditionally rejected based on the command's parameters and/or namespace. + * + * If a readConcern level argument is sent to a command that returns false the command processor + * will reject the command, returning an appropriate error message. + * + * Note that this is never called on mongos. Sharded commands are responsible for forwarding + * the option to the shards as needed. We rely on the shards to fail the commands in the + * cases where it isn't supported. + */ + virtual bool supportsReadConcern(repl::ReadConcernLevel level) const { + return level == repl::ReadConcernLevel::kLocalReadConcern; + } + + /** + * Returns true if command allows afterClusterTime in its readConcern. The command may not allow + * it if it is specifically intended not to take any LockManager locks. Waiting for + * afterClusterTime takes the MODE_IS lock. + */ + virtual bool allowsAfterClusterTime() const { + return true; + } + + /** + * The command definition that this invocation runs. + * Note: nonvirtual. + */ + const Command* definition() const { + return _definition; + } + + /** + * Throws DBException, most likely `ErrorCodes::Unauthorized`, unless + * the client executing "opCtx" is authorized to run the given command + * with the given parameters on the given named database. + * Note: nonvirtual. + */ + void checkAuthorization(OperationContext* opCtx) const; + +protected: + ResourcePattern resourcePattern() const; + +private: + /** + * Polymorphic extension point for `checkAuthorization`. + * Throws unless `opCtx`'s client is authorized to `run()` this. + */ + virtual void doCheckAuthorization(OperationContext* opCtx) const = 0; + + const Command* const _definition; +}; + /** * A subclass of Command that only cares about the BSONObj body and doesn't need access to document * sequences. |