diff options
author | David Storch <david.storch@10gen.com> | 2014-09-18 14:06:54 -0400 |
---|---|---|
committer | David Storch <david.storch@10gen.com> | 2014-09-19 10:46:17 -0400 |
commit | 6572c75e85cd7ec0a3269a13a5290c9a46416a3e (patch) | |
tree | 62ef5685e1323df63f1c00b99f624d3273b4b5e2 /src/mongo/db/ops | |
parent | 759b6e8cabfb745b712b5ffd0748561129c3b421 (diff) | |
download | mongo-6572c75e85cd7ec0a3269a13a5290c9a46416a3e.tar.gz |
SERVER-14100 explain for delete
Diffstat (limited to 'src/mongo/db/ops')
-rw-r--r-- | src/mongo/db/ops/delete_executor.cpp | 69 | ||||
-rw-r--r-- | src/mongo/db/ops/delete_executor.h | 20 | ||||
-rw-r--r-- | src/mongo/db/ops/delete_request.h | 6 |
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 |