summaryrefslogtreecommitdiff
path: root/src/mongo/db/ops
diff options
context:
space:
mode:
authorDavid Storch <david.storch@10gen.com>2014-09-18 14:06:54 -0400
committerDavid Storch <david.storch@10gen.com>2014-09-19 10:46:17 -0400
commit6572c75e85cd7ec0a3269a13a5290c9a46416a3e (patch)
tree62ef5685e1323df63f1c00b99f624d3273b4b5e2 /src/mongo/db/ops
parent759b6e8cabfb745b712b5ffd0748561129c3b421 (diff)
downloadmongo-6572c75e85cd7ec0a3269a13a5290c9a46416a3e.tar.gz
SERVER-14100 explain for delete
Diffstat (limited to 'src/mongo/db/ops')
-rw-r--r--src/mongo/db/ops/delete_executor.cpp69
-rw-r--r--src/mongo/db/ops/delete_executor.h20
-rw-r--r--src/mongo/db/ops/delete_request.h6
3 files changed, 73 insertions, 22 deletions
diff --git a/src/mongo/db/ops/delete_executor.cpp b/src/mongo/db/ops/delete_executor.cpp
index ddb0c29b025..25f603ce7f6 100644
--- a/src/mongo/db/ops/delete_executor.cpp
+++ b/src/mongo/db/ops/delete_executor.cpp
@@ -78,8 +78,16 @@ namespace mongo {
return status;
}
- long long DeleteExecutor::execute(Database* db) {
- uassertStatusOK(prepare());
+ PlanExecutor* DeleteExecutor::getPlanExecutor() {
+ return _exec.get();
+ }
+
+ Status DeleteExecutor::prepareInLock(Database* db) {
+ // If we have a non-NULL PlanExecutor, then we've already done the in-lock preparation.
+ if (_exec.get()) {
+ return Status::OK();
+ }
+
uassert(17417,
mongoutils::str::stream() <<
"DeleteExecutor::prepare() failed to parse query " << _request->getQuery(),
@@ -98,52 +106,71 @@ namespace mongo {
}
}
+ // Note that 'collection' may by NULL in the case that the collection we are trying to
+ // delete from does not exist. NULL 'collection' is handled by getExecutorDelete(); we
+ // expect to get back a plan executor whose plan is a DeleteStage on top of an EOFStage.
Collection* collection = db->getCollection(_request->getOpCtx(), ns.ns());
- if (NULL == collection) {
- return 0;
- }
- uassert(10101,
- str::stream() << "cannot remove from a capped collection: " << ns.ns(),
- !collection->isCapped());
+ if (collection && collection->isCapped()) {
+ return Status(ErrorCodes::IllegalOperation,
+ str::stream() << "cannot remove from a capped collection: " << ns.ns());
+ }
- uassert(ErrorCodes::NotMaster,
- str::stream() << "Not primary while removing from " << ns.ns(),
- !_request->shouldCallLogOp() ||
- repl::getGlobalReplicationCoordinator()->canAcceptWritesForDatabase(ns.db()));
+ if (_request->shouldCallLogOp() &&
+ !repl::getGlobalReplicationCoordinator()->canAcceptWritesForDatabase(ns.db())) {
+ return Status(ErrorCodes::NotMaster,
+ str::stream() << "Not primary while removing from " << ns.ns());
+ }
PlanExecutor* rawExec;
+ Status getExecStatus = Status::OK();
if (_canonicalQuery.get()) {
// This is the non-idhack branch.
- uassertStatusOK(getExecutorDelete(_request->getOpCtx(),
+ getExecStatus = getExecutorDelete(_request->getOpCtx(),
collection,
_canonicalQuery.release(),
_request->isMulti(),
_request->shouldCallLogOp(),
_request->isFromMigrate(),
- &rawExec));
+ _request->isExplain(),
+ &rawExec);
}
else {
// This is the idhack branch.
- uassertStatusOK(getExecutorDelete(_request->getOpCtx(),
+ getExecStatus = getExecutorDelete(_request->getOpCtx(),
collection,
ns.ns(),
_request->getQuery(),
_request->isMulti(),
_request->shouldCallLogOp(),
_request->isFromMigrate(),
- &rawExec));
+ _request->isExplain(),
+ &rawExec);
+ }
+
+ if (getExecStatus.isOK()) {
+ invariant(rawExec);
+ _exec.reset(rawExec);
}
- scoped_ptr<PlanExecutor> exec(rawExec);
+
+ return getExecStatus;
+ }
+
+ long long DeleteExecutor::execute(Database* db) {
+ uassertStatusOK(prepare());
+
+ // If we've already done the in-lock preparation, this is a no-op.
+ uassertStatusOK(prepareInLock(db));
+ invariant(_exec.get());
// Concurrently mutating state (by us) so we need to register 'exec'.
- const ScopedExecutorRegistration safety(exec.get());
+ const ScopedExecutorRegistration safety(_exec.get());
- uassertStatusOK(exec->executePlan());
+ uassertStatusOK(_exec->executePlan());
// Extract the number of documents deleted from the DeleteStage stats.
- invariant(exec->getRootStage()->stageType() == STAGE_DELETE);
- DeleteStage* deleteStage = static_cast<DeleteStage*>(exec->getRootStage());
+ invariant(_exec->getRootStage()->stageType() == STAGE_DELETE);
+ DeleteStage* deleteStage = static_cast<DeleteStage*>(_exec->getRootStage());
const DeleteStats* deleteStats =
static_cast<const DeleteStats*>(deleteStage->getSpecificStats());
return deleteStats->docsDeleted;
diff --git a/src/mongo/db/ops/delete_executor.h b/src/mongo/db/ops/delete_executor.h
index c0324b14901..e4f5c2f2fe4 100644
--- a/src/mongo/db/ops/delete_executor.h
+++ b/src/mongo/db/ops/delete_executor.h
@@ -32,6 +32,7 @@
#include "mongo/base/disallow_copying.h"
#include "mongo/base/status.h"
+#include "mongo/db/query/plan_executor.h"
namespace mongo {
@@ -87,6 +88,22 @@ namespace mongo {
Status prepare();
/**
+ * Performs preparatory work that *does* require the appropriate database lock. This
+ * preparation involves construction of a PlanExecutor. Construction of a PlanExecutor
+ * requires the database lock because it goes through query planning and optimization,
+ * which may involve partial execution of the delete plan tree.
+ *
+ * On success, a non-NULL PlanExecutor will be available via getPlanExecutor().
+ */
+ Status prepareInLock(Database* db);
+
+ /**
+ * Retrieve the PlanExecutor that will be used to execute this delete upon calling
+ * execute(). Returns NULL if no PlanExecutor has been created.
+ */
+ PlanExecutor* getPlanExecutor();
+
+ /**
* Execute a delete. Requires the caller to hold the database lock on the
* appropriate resources for the request.
*
@@ -101,6 +118,9 @@ namespace mongo {
/// Parsed query object, or NULL if the query proves to be an id hack query.
std::auto_ptr<CanonicalQuery> _canonicalQuery;
+ // The tree of execution stages which will be used to execute the update.
+ boost::scoped_ptr<PlanExecutor> _exec;
+
/// Flag indicating if the query has been successfully parsed.
bool _isQueryParsed;
diff --git a/src/mongo/db/ops/delete_request.h b/src/mongo/db/ops/delete_request.h
index 53f8d13d475..ee58c59d476 100644
--- a/src/mongo/db/ops/delete_request.h
+++ b/src/mongo/db/ops/delete_request.h
@@ -45,13 +45,15 @@ namespace mongo {
_multi(false),
_logop(false),
_god(false),
- _fromMigrate(false) {}
+ _fromMigrate(false),
+ _isExplain(false) {}
void setQuery(const BSONObj& query) { _query = query; }
void setMulti(bool multi = true) { _multi = multi; }
void setUpdateOpLog(bool logop = true) { _logop = logop; }
void setGod(bool god = true) { _god = god; }
void setFromMigrate(bool fromMigrate = true) { _fromMigrate = fromMigrate; }
+ void setExplain(bool isExplain = true) { _isExplain = isExplain; }
const NamespaceString& getNamespaceString() const { return _nsString; }
const BSONObj& getQuery() const { return _query; }
@@ -59,6 +61,7 @@ namespace mongo {
bool shouldCallLogOp() const { return _logop; }
bool isGod() const { return _god; }
bool isFromMigrate() const { return _fromMigrate; }
+ bool isExplain() const { return _isExplain; }
OperationContext* getOpCtx() const { return _txn; }
std::string toString() const;
@@ -71,6 +74,7 @@ namespace mongo {
bool _logop;
bool _god;
bool _fromMigrate;
+ bool _isExplain;
};
} // namespace mongo