summaryrefslogtreecommitdiff
path: root/src/mongo/db/ops
diff options
context:
space:
mode:
authorDavid Storch <david.storch@10gen.com>2014-12-02 20:10:01 -0500
committerDavid Storch <david.storch@10gen.com>2014-12-04 17:41:11 -0500
commit367810995073e01ee58159deb1bb5b878882632f (patch)
tree3074960c42a7b63e4e3be337e44f33a036a6679f /src/mongo/db/ops
parent5080932a79ce0152535169ec3b42edde2951bdcd (diff)
downloadmongo-367810995073e01ee58159deb1bb5b878882632f.tar.gz
SERVER-16101 replace DeleteExecutor with ParsedDelete
Diffstat (limited to 'src/mongo/db/ops')
-rw-r--r--src/mongo/db/ops/delete.cpp21
-rw-r--r--src/mongo/db/ops/delete_executor.cpp199
-rw-r--r--src/mongo/db/ops/delete_executor.h132
-rw-r--r--src/mongo/db/ops/parsed_delete.cpp104
-rw-r--r--src/mongo/db/ops/parsed_delete.h109
5 files changed, 231 insertions, 334 deletions
diff --git a/src/mongo/db/ops/delete.cpp b/src/mongo/db/ops/delete.cpp
index 8fc12448a21..fcaa2b6d02b 100644
--- a/src/mongo/db/ops/delete.cpp
+++ b/src/mongo/db/ops/delete.cpp
@@ -28,8 +28,10 @@
#include "mongo/db/ops/delete.h"
-#include "mongo/db/ops/delete_executor.h"
+#include "mongo/db/exec/delete.h"
#include "mongo/db/ops/delete_request.h"
+#include "mongo/db/ops/parsed_delete.h"
+#include "mongo/db/query/get_executor.h"
namespace mongo {
@@ -55,8 +57,21 @@ namespace mongo {
request.setGod(god);
request.setFromMigrate(fromMigrate);
request.setYieldPolicy(policy);
- DeleteExecutor executor(txn, &request);
- return executor.execute(db);
+
+ Collection* collection = NULL;
+ if (db) {
+ collection = db->getCollection(txn, nsString.ns());
+ }
+
+ ParsedDelete parsedDelete(txn, &request);
+ uassertStatusOK(parsedDelete.parseRequest());
+
+ PlanExecutor* rawExec;
+ uassertStatusOK(getExecutorDelete(txn, collection, &parsedDelete, &rawExec));
+ boost::scoped_ptr<PlanExecutor> exec(rawExec);
+
+ uassertStatusOK(exec->executePlan());
+ return DeleteStage::getNumDeleted(exec.get());
}
} // namespace mongo
diff --git a/src/mongo/db/ops/delete_executor.cpp b/src/mongo/db/ops/delete_executor.cpp
deleted file mode 100644
index 01b08e6c56d..00000000000
--- a/src/mongo/db/ops/delete_executor.cpp
+++ /dev/null
@@ -1,199 +0,0 @@
-/**
- * Copyright (C) 2014 MongoDB Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- * As a special exception, the copyright holders give permission to link the
- * code of portions of this program with the OpenSSL library under certain
- * conditions as described in each individual source file and distribute
- * linked combinations including the program with the OpenSSL library. You
- * must comply with the GNU Affero General Public License in all respects for
- * all of the code used other than as permitted herein. If you modify file(s)
- * with this exception, you may extend this exception to your version of the
- * file(s), but you are not obligated to do so. If you do not wish to do so,
- * delete this exception statement from your version. If you delete this
- * exception statement from all source files in the program, then also delete
- * it in the license file.
- */
-
-#define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kWrite
-
-#include "mongo/platform/basic.h"
-
-#include "mongo/db/ops/delete_executor.h"
-
-#include "mongo/db/catalog/collection.h"
-#include "mongo/db/catalog/database.h"
-#include "mongo/db/exec/delete.h"
-#include "mongo/db/ops/delete_request.h"
-#include "mongo/db/query/canonical_query.h"
-#include "mongo/db/query/get_executor.h"
-#include "mongo/db/query/query_planner_common.h"
-#include "mongo/db/repl/repl_coordinator_global.h"
-#include "mongo/util/assert_util.h"
-#include "mongo/util/log.h"
-#include "mongo/util/mongoutils/str.h"
-
-namespace mongo {
-
- DeleteExecutor::DeleteExecutor(OperationContext* txn, const DeleteRequest* request) :
- _txn(txn),
- _request(request),
- _canonicalQuery(),
- _isQueryParsed(false) {
- }
-
- DeleteExecutor::~DeleteExecutor() {}
-
- Status DeleteExecutor::prepare() {
- if (_isQueryParsed)
- return Status::OK();
-
- dassert(!_canonicalQuery.get());
-
- if (CanonicalQuery::isSimpleIdQuery(_request->getQuery())) {
- _isQueryParsed = true;
- return Status::OK();
- }
-
- CanonicalQuery* cqRaw;
- const WhereCallbackReal whereCallback(_txn, _request->getNamespaceString().db());
-
- Status status = CanonicalQuery::canonicalize(_request->getNamespaceString().ns(),
- _request->getQuery(),
- _request->isExplain(),
- &cqRaw,
- whereCallback);
- if (status.isOK()) {
- _canonicalQuery.reset(cqRaw);
- _isQueryParsed = true;
- }
-
- return status;
- }
-
- 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(),
- _isQueryParsed);
-
- const NamespaceString& ns(_request->getNamespaceString());
- if (!_request->isGod()) {
- if (ns.isSystem()) {
- uassert(12050,
- "cannot delete from system namespace",
- legalClientSystemNS(ns.ns(), true));
- }
- if (ns.ns().find('$') != string::npos) {
- log() << "cannot delete from collection with reserved $ in name: " << ns << endl;
- uasserted(10100, "cannot delete from collection with reserved $ in name");
- }
- }
-
- // Note that 'collection' may by NULL in the case that the collection or database 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 = NULL;
- if (db) {
- collection = db->getCollection(_txn, ns.ns());
- }
-
- if (collection && collection->isCapped()) {
- return Status(ErrorCodes::IllegalOperation,
- str::stream() << "cannot remove from a capped collection: " << ns.ns());
- }
-
- if (_request->shouldCallLogOp() &&
- !repl::getGlobalReplicationCoordinator()->canAcceptWritesForDatabase(ns.db())) {
- return Status(ErrorCodes::NotMaster,
- str::stream() << "Not primary while removing from " << ns.ns());
- }
-
- // If yielding is allowed for this plan, then set an auto yield policy. Otherwise set
- // a manual yield policy.
- const bool canYield = !_request->isGod() &&
- PlanExecutor::YIELD_AUTO == _request->getYieldPolicy() && (
- _canonicalQuery.get() ?
- !QueryPlannerCommon::hasNode(_canonicalQuery->root(), MatchExpression::ATOMIC) :
- !LiteParsedQuery::isQueryIsolated(_request->getQuery()));
-
- PlanExecutor::YieldPolicy policy = canYield ? PlanExecutor::YIELD_AUTO :
- PlanExecutor::YIELD_MANUAL;
-
- PlanExecutor* rawExec;
- Status getExecStatus = Status::OK();
- if (_canonicalQuery.get()) {
- // This is the non-idhack branch.
- getExecStatus = getExecutorDelete(_txn,
- collection,
- _canonicalQuery.release(),
- _request->isMulti(),
- _request->shouldCallLogOp(),
- _request->isFromMigrate(),
- _request->isExplain(),
- policy,
- &rawExec);
- }
- else {
- // This is the idhack branch.
- getExecStatus = getExecutorDelete(_txn,
- collection,
- ns.ns(),
- _request->getQuery(),
- _request->isMulti(),
- _request->shouldCallLogOp(),
- _request->isFromMigrate(),
- _request->isExplain(),
- policy,
- &rawExec);
- }
-
- if (!getExecStatus.isOK()) {
- return getExecStatus;
- }
-
- invariant(rawExec);
- _exec.reset(rawExec);
-
- return Status::OK();
- }
-
- 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());
-
- 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());
- const DeleteStats* deleteStats =
- static_cast<const DeleteStats*>(deleteStage->getSpecificStats());
- return deleteStats->docsDeleted;
- }
-
-} // namespace mongo
diff --git a/src/mongo/db/ops/delete_executor.h b/src/mongo/db/ops/delete_executor.h
deleted file mode 100644
index cc984af1c95..00000000000
--- a/src/mongo/db/ops/delete_executor.h
+++ /dev/null
@@ -1,132 +0,0 @@
-/**
- * Copyright (C) 2014 MongoDB Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License, version 3,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- * As a special exception, the copyright holders give permission to link the
- * code of portions of this program with the OpenSSL library under certain
- * conditions as described in each individual source file and distribute
- * linked combinations including the program with the OpenSSL library. You
- * must comply with the GNU Affero General Public License in all respects for
- * all of the code used other than as permitted herein. If you modify file(s)
- * with this exception, you may extend this exception to your version of the
- * file(s), but you are not obligated to do so. If you do not wish to do so,
- * delete this exception statement from your version. If you delete this
- * exception statement from all source files in the program, then also delete
- * it in the license file.
- */
-
-#pragma once
-
-#include <memory>
-
-#include "mongo/base/disallow_copying.h"
-#include "mongo/base/status.h"
-#include "mongo/db/query/plan_executor.h"
-
-
-namespace mongo {
-
- class CanonicalQuery;
- class Database;
- class DeleteRequest;
- class OperationContext;
-
- /**
- * Implementation of the processing of a delete operation in a mongod.
- *
- * The executor has two important methods, prepare() and execute(). The prepare() method can
- * run without locks, and does whatever parsing and precomputation can be done without access to
- * database data. The execute method performs the delete, but the caller must already hold the
- * appropriate database lock.
- *
- * Expected usage is approximately:
- * DeleteRequest request(...);
- * // configure request
- * DeleteExecutor executor(txn, &request);
- * uassertStatusOK(executor.prepare());
- * // Get locks, get ready to execute.
- * try {
- * long long nDeleted = executor.execute();
- * }
- * catch (const DBException& ex) {
- * // Error handling.
- * }
- */
- class DeleteExecutor {
- MONGO_DISALLOW_COPYING(DeleteExecutor);
- public:
- /**
- * Constructs a delete executor.
- *
- * The object pointed to by "request" must stay in scope for the life of the constructed
- * executor.
- */
- DeleteExecutor(OperationContext* txn, const DeleteRequest* request);
-
- ~DeleteExecutor();
-
- /**
- * Performs preparatory work that does not require database locks.
- *
- * Returns Status::OK() on success. Other results indicate that the executor will not run
- * correctly, and should be abandoned.
- *
- * Calling prepare() is optional. It is available for situations in which the user
- * wishes to do as much work as possible before acquiring database locks.
- */
- 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.
- *
- * Returns the number of documents deleted.
- */
- long long execute(Database* db);
-
- private:
- // Transactional context. Not owned by us.
- OperationContext* _txn;
-
- // Unowned pointer to the request object that this executor will process.
- const DeleteRequest* const _request;
-
- // 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;
-
- };
-
-} // namespace mongo
diff --git a/src/mongo/db/ops/parsed_delete.cpp b/src/mongo/db/ops/parsed_delete.cpp
new file mode 100644
index 00000000000..da1b2c77a25
--- /dev/null
+++ b/src/mongo/db/ops/parsed_delete.cpp
@@ -0,0 +1,104 @@
+/**
+ * Copyright (C) 2014 MongoDB Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the GNU Affero General Public License in all respects for
+ * all of the code used other than as permitted herein. If you modify file(s)
+ * with this exception, you may extend this exception to your version of the
+ * file(s), but you are not obligated to do so. If you do not wish to do so,
+ * delete this exception statement from your version. If you delete this
+ * exception statement from all source files in the program, then also delete
+ * it in the license file.
+ */
+
+#define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kWrite
+
+#include "mongo/platform/basic.h"
+
+#include "mongo/db/ops/parsed_delete.h"
+
+#include "mongo/db/catalog/collection.h"
+#include "mongo/db/catalog/database.h"
+#include "mongo/db/exec/delete.h"
+#include "mongo/db/ops/delete_request.h"
+#include "mongo/db/query/canonical_query.h"
+#include "mongo/db/query/get_executor.h"
+#include "mongo/db/query/query_planner_common.h"
+#include "mongo/db/repl/repl_coordinator_global.h"
+#include "mongo/util/assert_util.h"
+#include "mongo/util/log.h"
+#include "mongo/util/mongoutils/str.h"
+
+namespace mongo {
+
+ ParsedDelete::ParsedDelete(OperationContext* txn, const DeleteRequest* request) :
+ _txn(txn),
+ _request(request) { }
+
+ Status ParsedDelete::parseRequest() {
+ dassert(!_canonicalQuery.get());
+
+ if (CanonicalQuery::isSimpleIdQuery(_request->getQuery())) {
+ return Status::OK();
+ }
+
+ return parseQueryToCQ();
+ }
+
+ Status ParsedDelete::parseQueryToCQ() {
+ dassert(!_canonicalQuery.get());
+
+ CanonicalQuery* cqRaw;
+ const WhereCallbackReal whereCallback(_txn, _request->getNamespaceString().db());
+
+ Status status = CanonicalQuery::canonicalize(_request->getNamespaceString().ns(),
+ _request->getQuery(),
+ _request->isExplain(),
+ &cqRaw,
+ whereCallback);
+
+ if (status.isOK()) {
+ cqRaw->setIsForWrite(true);
+ _canonicalQuery.reset(cqRaw);
+ }
+
+ return status;
+ }
+
+ const DeleteRequest* ParsedDelete::getRequest() const {
+ return _request;
+ }
+
+ bool ParsedDelete::canYield() const {
+ return !_request->isGod() &&
+ PlanExecutor::YIELD_AUTO == _request->getYieldPolicy() && (
+ _canonicalQuery.get() ?
+ !QueryPlannerCommon::hasNode(_canonicalQuery->root(), MatchExpression::ATOMIC) :
+ !LiteParsedQuery::isQueryIsolated(_request->getQuery()));
+ }
+
+ bool ParsedDelete::hasParsedQuery() const {
+ return _canonicalQuery.get() != NULL;
+ }
+
+ CanonicalQuery* ParsedDelete::releaseParsedQuery() {
+ invariant(_canonicalQuery.get() != NULL);
+ return _canonicalQuery.release();
+ }
+
+} // namespace mongo
diff --git a/src/mongo/db/ops/parsed_delete.h b/src/mongo/db/ops/parsed_delete.h
new file mode 100644
index 00000000000..c117db28cb7
--- /dev/null
+++ b/src/mongo/db/ops/parsed_delete.h
@@ -0,0 +1,109 @@
+/**
+ * Copyright (C) 2014 MongoDB Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the GNU Affero General Public License in all respects for
+ * all of the code used other than as permitted herein. If you modify file(s)
+ * with this exception, you may extend this exception to your version of the
+ * file(s), but you are not obligated to do so. If you do not wish to do so,
+ * delete this exception statement from your version. If you delete this
+ * exception statement from all source files in the program, then also delete
+ * it in the license file.
+ */
+
+#pragma once
+
+#include "mongo/base/disallow_copying.h"
+#include "mongo/base/status.h"
+#include "mongo/db/query/plan_executor.h"
+
+namespace mongo {
+
+ class CanonicalQuery;
+ class Database;
+ class DeleteRequest;
+ class OperationContext;
+
+ /**
+ * This class takes a pointer to a DeleteRequest, and converts that request into a parsed form
+ * via the parseRequest() method. A ParsedDelete can then be used to retrieve a PlanExecutor
+ * capable of executing the delete.
+ *
+ * A delete request is parsed to a CanonicalQuery, so this class is a thin, delete-specific
+ * wrapper around canonicalization.
+ *
+ * No locks need to be held during parsing.
+ */
+ class ParsedDelete {
+ MONGO_DISALLOW_COPYING(ParsedDelete);
+ public:
+ /**
+ * Constructs a parsed delete.
+ *
+ * The object pointed to by "request" must stay in scope for the life of the constructed
+ * ParsedDelete.
+ */
+ ParsedDelete(OperationContext* txn, const DeleteRequest* request);
+
+ /**
+ * Parses the delete request to a canonical query. On success, the parsed delete can be
+ * used to create a PlanExecutor capable of executing this delete.
+ */
+ Status parseRequest();
+
+ /**
+ * As an optimization, we do not create a canonical query if the predicate is a simple
+ * _id equality. This method can be used to force full parsing to a canonical query,
+ * as a fallback if the idhack path is not available (e.g. no _id index).
+ */
+ Status parseQueryToCQ();
+
+ /**
+ * Get the raw request.
+ */
+ const DeleteRequest* getRequest() const;
+
+ /**
+ * Is this delete allowed to yield?
+ */
+ bool canYield() const;
+
+ /**
+ * As an optimization, we don't create a canonical query for updates with simple _id
+ * queries. Use this method to determine whether or not we actually parsed the query.
+ */
+ bool hasParsedQuery() const;
+
+ /**
+ * Releases ownership of the canonical query to the caller.
+ */
+ CanonicalQuery* releaseParsedQuery();
+
+ private:
+ // Transactional context. Not owned by us.
+ OperationContext* _txn;
+
+ // Unowned pointer to the request object that this executor will process.
+ const DeleteRequest* const _request;
+
+ // Parsed query object, or NULL if the query proves to be an id hack query.
+ std::auto_ptr<CanonicalQuery> _canonicalQuery;
+
+ };
+
+} // namespace mongo