summaryrefslogtreecommitdiff
path: root/src/mongo/db/commands.h
diff options
context:
space:
mode:
authorBilly Donahue <billy.donahue@mongodb.com>2018-03-05 15:48:48 -0500
committerBilly Donahue <billy.donahue@mongodb.com>2018-03-06 10:04:53 -0500
commite3a3f54a6c0ec4f471e0aff7a48b8a30f8c0e9cb (patch)
tree9c2f4ac5a4d8751336397c8af59a08bf78f1c201 /src/mongo/db/commands.h
parent5dfa372b25b1a26bb12e09fdb029ff219b0f5343 (diff)
downloadmongo-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.h243
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.