summaryrefslogtreecommitdiff
path: root/src/mongo/db/ops
diff options
context:
space:
mode:
authorDavid Storch <david.storch@10gen.com>2014-12-04 11:40:04 -0500
committerDavid Storch <david.storch@10gen.com>2014-12-04 17:41:11 -0500
commit5080932a79ce0152535169ec3b42edde2951bdcd (patch)
tree3fd5abb6a6e31fffda93446c5382ed8a745b1a99 /src/mongo/db/ops
parent4062e8f9493d4a8f9c32aba70fb19217241850c9 (diff)
downloadmongo-5080932a79ce0152535169ec3b42edde2951bdcd.tar.gz
SERVER-16101 replace UpdateExecutor with ParsedUpdate
Diffstat (limited to 'src/mongo/db/ops')
-rw-r--r--src/mongo/db/ops/parsed_update.cpp132
-rw-r--r--src/mongo/db/ops/parsed_update.h126
-rw-r--r--src/mongo/db/ops/update.cpp48
-rw-r--r--src/mongo/db/ops/update_executor.cpp326
-rw-r--r--src/mongo/db/ops/update_executor.h149
5 files changed, 303 insertions, 478 deletions
diff --git a/src/mongo/db/ops/parsed_update.cpp b/src/mongo/db/ops/parsed_update.cpp
new file mode 100644
index 00000000000..19413b777fd
--- /dev/null
+++ b/src/mongo/db/ops/parsed_update.cpp
@@ -0,0 +1,132 @@
+/**
+ * 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::kWrites
+
+#include "mongo/platform/basic.h"
+
+#include "mongo/db/ops/parsed_update.h"
+#include "mongo/db/ops/update_request.h"
+#include "mongo/db/query/canonical_query.h"
+#include "mongo/db/query/query_planner_common.h"
+
+namespace mongo {
+
+ ParsedUpdate::ParsedUpdate(OperationContext* txn, const UpdateRequest* request) :
+ _txn(txn),
+ _request(request),
+ _driver(UpdateDriver::Options()),
+ _canonicalQuery() { }
+
+ Status ParsedUpdate::parseRequest() {
+ // We parse the update portion before the query portion because the dispostion of the update
+ // may determine whether or not we need to produce a CanonicalQuery at all. For example, if
+ // the update involves the positional-dollar operator, we must have a CanonicalQuery even if
+ // it isn't required for query execution.
+ Status status = parseUpdate();
+ if (!status.isOK())
+ return status;
+ status = parseQuery();
+ if (!status.isOK())
+ return status;
+ return Status::OK();
+ }
+
+ Status ParsedUpdate::parseQuery() {
+ dassert(!_canonicalQuery.get());
+
+ if (!_driver.needMatchDetails() && CanonicalQuery::isSimpleIdQuery(_request->getQuery())) {
+ return Status::OK();
+ }
+
+ return parseQueryToCQ();
+ }
+
+ Status ParsedUpdate::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;
+ }
+
+ Status ParsedUpdate::parseUpdate() {
+ const NamespaceString& ns(_request->getNamespaceString());
+
+ // Should the modifiers validate their embedded docs via okForStorage
+ // Only user updates should be checked. Any system or replication stuff should pass through.
+ // Config db docs shouldn't get checked for valid field names since the shard key can have
+ // a dot (".") in it.
+ const bool shouldValidate = !(_request->isFromReplication() ||
+ ns.isConfigDB() ||
+ _request->isFromMigration());
+
+ _driver.setLogOp(true);
+ _driver.setModOptions(ModifierInterface::Options(_request->isFromReplication(),
+ shouldValidate));
+
+ return _driver.parse(_request->getUpdates(), _request->isMulti());
+ }
+
+ bool ParsedUpdate::canYield() const {
+ return !_request->isGod() &&
+ PlanExecutor::YIELD_AUTO == _request->getYieldPolicy() && (
+ _canonicalQuery.get() ?
+ !QueryPlannerCommon::hasNode(_canonicalQuery->root(), MatchExpression::ATOMIC) :
+ !LiteParsedQuery::isQueryIsolated(_request->getQuery()));
+ }
+
+ bool ParsedUpdate::hasParsedQuery() const {
+ return _canonicalQuery.get() != NULL;
+ }
+
+ CanonicalQuery* ParsedUpdate::releaseParsedQuery() {
+ invariant(_canonicalQuery.get() != NULL);
+ return _canonicalQuery.release();
+ }
+
+ const UpdateRequest* ParsedUpdate::getRequest() const {
+ return _request;
+ }
+
+ UpdateDriver* ParsedUpdate::getDriver() {
+ return &_driver;
+ }
+
+} // namespace mongo
diff --git a/src/mongo/db/ops/parsed_update.h b/src/mongo/db/ops/parsed_update.h
new file mode 100644
index 00000000000..f93a264b3b8
--- /dev/null
+++ b/src/mongo/db/ops/parsed_update.h
@@ -0,0 +1,126 @@
+/**
+ * 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/ops/update_driver.h"
+
+namespace mongo {
+
+ class CanonicalQuery;
+ class OperationContext;
+ class UpdateRequest;
+
+ /**
+ * This class takes a pointer to an UpdateRequest, and converts that request into a parsed form
+ * via the parseRequest() method. A ParsedUpdate can then be used to retrieve a PlanExecutor
+ * capable of executing the update.
+ *
+ * No locks need to be held during parsing.
+ *
+ * The query part of the update is parsed to a CanonicalQuery, and the update part is parsed
+ * using the UpdateDriver.
+ */
+ class ParsedUpdate {
+ MONGO_DISALLOW_COPYING(ParsedUpdate);
+ public:
+ /**
+ * Constructs a parsed update.
+ *
+ * The object pointed to by "request" must stay in scope for the life of the constructed
+ * ParsedUpdate.
+ */
+ ParsedUpdate(OperationContext* txn, const UpdateRequest* request);
+
+ /**
+ * Parses the update request to a canonical query and an update driver. On success, the
+ * parsed update can be used to create a PlanExecutor for this update.
+ */
+ 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 UpdateRequest* getRequest() const;
+
+ /**
+ * Get a pointer to the update driver, the abstraction which both parses the update and
+ * is capable of applying mods / computing damages.
+ */
+ UpdateDriver* getDriver();
+
+ /**
+ * Is this update 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:
+ /**
+ * Parses the query portion of the update request.
+ */
+ Status parseQuery();
+
+ /**
+ * Parses the update-descriptor portion of the update request.
+ */
+ Status parseUpdate();
+
+ // Unowned pointer to the transactional context.
+ OperationContext* _txn;
+
+ // Unowned pointer to the request object to process.
+ const UpdateRequest* const _request;
+
+ // Driver for processing updates on matched documents.
+ UpdateDriver _driver;
+
+ // Parsed query object, or NULL if the query proves to be an id hack query.
+ std::auto_ptr<CanonicalQuery> _canonicalQuery;
+ };
+
+} // namespace mongo
diff --git a/src/mongo/db/ops/update.cpp b/src/mongo/db/ops/update.cpp
index 66f797458eb..12b2303ccc2 100644
--- a/src/mongo/db/ops/update.cpp
+++ b/src/mongo/db/ops/update.cpp
@@ -38,13 +38,14 @@
#include "mongo/db/catalog/collection.h"
#include "mongo/db/catalog/database_holder.h"
#include "mongo/db/clientcursor.h"
+#include "mongo/db/concurrency/d_concurrency.h"
#include "mongo/db/exec/update.h"
#include "mongo/db/operation_context_impl.h"
#include "mongo/db/ops/update_driver.h"
-#include "mongo/db/ops/update_executor.h"
#include "mongo/db/ops/update_lifecycle.h"
#include "mongo/db/query/explain.h"
#include "mongo/db/query/get_executor.h"
+#include "mongo/db/repl/oplog.h"
#include "mongo/db/update_index_data.h"
#include "mongo/util/log.h"
@@ -54,9 +55,50 @@ namespace mongo {
Database* db,
const UpdateRequest& request,
OpDebug* opDebug) {
+ invariant(db);
- UpdateExecutor executor(txn, &request, opDebug);
- return executor.execute(db);
+ // Explain should never use this helper.
+ invariant(!request.isExplain());
+
+ const NamespaceString& nsString = request.getNamespaceString();
+ Collection* collection = db->getCollection(txn, nsString.ns());
+
+ // The update stage does not create its own collection. As such, if the update is
+ // an upsert, create the collection that the update stage inserts into beforehand.
+ if (!collection && request.isUpsert()) {
+ // We have to have an exclusive lock on the db to be allowed to create the collection.
+ // Callers should either get an X or create the collection.
+ const Locker* locker = txn->lockState();
+ invariant(locker->isW() ||
+ locker->isLockHeldForMode(ResourceId(RESOURCE_DATABASE, nsString.db()),
+ MODE_X));
+
+ ScopedTransaction transaction(txn, MODE_IX);
+ Lock::DBLock lk(txn->lockState(), nsString.db(), MODE_X);
+
+ WriteUnitOfWork wuow(txn);
+ collection = db->createCollection(txn, nsString.ns());
+ invariant(collection);
+
+ if (!request.isFromReplication()) {
+ repl::logOp(txn,
+ "c",
+ (db->name() + ".$cmd").c_str(),
+ BSON("create" << (nsString.coll())));
+ }
+ wuow.commit();
+ }
+
+ // Parse the update, get an executor for it, run the executor, get stats out.
+ ParsedUpdate parsedUpdate(txn, &request);
+ uassertStatusOK(parsedUpdate.parseRequest());
+
+ PlanExecutor* rawExec;
+ uassertStatusOK(getExecutorUpdate(txn, collection, &parsedUpdate, opDebug, &rawExec));
+ boost::scoped_ptr<PlanExecutor> exec(rawExec);
+
+ uassertStatusOK(exec->executePlan());
+ return UpdateStage::makeUpdateResult(exec.get(), opDebug);
}
BSONObj applyUpdateOperators(const BSONObj& from, const BSONObj& operators) {
diff --git a/src/mongo/db/ops/update_executor.cpp b/src/mongo/db/ops/update_executor.cpp
deleted file mode 100644
index 23645123af9..00000000000
--- a/src/mongo/db/ops/update_executor.cpp
+++ /dev/null
@@ -1,326 +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/update_executor.h"
-
-#include "mongo/db/catalog/database.h"
-#include "mongo/db/concurrency/d_concurrency.h"
-#include "mongo/db/exec/update.h"
-#include "mongo/db/ops/update.h"
-#include "mongo/db/ops/update_driver.h"
-#include "mongo/db/ops/update_lifecycle.h"
-#include "mongo/db/ops/update_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/oplog.h"
-#include "mongo/db/repl/repl_coordinator_global.h"
-#include "mongo/util/assert_util.h"
-#include "mongo/util/fail_point_service.h"
-#include "mongo/util/log.h"
-
-namespace mongo {
-
- namespace {
-
- // TODO: Make this a function on NamespaceString, or make it cleaner.
- inline void validateUpdate(const char* ns ,
- const BSONObj& updateobj,
- const BSONObj& patternOrig) {
- uassert(10155 , "cannot update reserved $ collection", strchr(ns, '$') == 0);
- if (strstr(ns, ".system.")) {
- /* dm: it's very important that system.indexes is never updated as IndexDetails
- has pointers into it */
- uassert(10156,
- str::stream() << "cannot update system collection: "
- << ns << " q: " << patternOrig << " u: " << updateobj,
- legalClientSystemNS(ns , true));
- }
- }
-
- } // namespace
-
- UpdateExecutor::UpdateExecutor(OperationContext* txn, const UpdateRequest* request,
- OpDebug* opDebug) :
- _txn(txn),
- _request(request),
- _opDebug(opDebug),
- _driver(UpdateDriver::Options()),
- _canonicalQuery(),
- _isQueryParsed(false),
- _isUpdateParsed(false) {
- }
-
- UpdateExecutor::~UpdateExecutor() {}
-
- Status UpdateExecutor::prepare() {
- // We parse the update portion before the query portion because the dispostion of the update
- // may determine whether or not we need to produce a CanonicalQuery at all. For example, if
- // the update involves the positional-dollar operator, we must have a CanonicalQuery even if
- // it isn't required for query execution.
- Status status = parseUpdate();
- if (!status.isOK())
- return status;
- status = parseQuery();
- if (!status.isOK())
- return status;
- return Status::OK();
- }
-
- PlanExecutor* UpdateExecutor::getPlanExecutor() {
- return _exec.get();
- }
-
- MONGO_FP_DECLARE(implicitCollectionCreationDelay);
-
- Status UpdateExecutor::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();
- }
-
- const NamespaceString& nsString = _request->getNamespaceString();
- UpdateLifecycle* lifecycle = _request->getLifecycle();
-
- validateUpdate(nsString.ns().c_str(), _request->getUpdates(), _request->getQuery());
-
- // The batch executor is responsible for creating a database if this update is being
- // performed against a non-existent database. However, it is possible for either the
- // database or collection to be NULL for an explain. In this case, the explain is
- // a no-op which returns a trivial EOF plan.
- Collection* collection = NULL;
- if (db) {
- collection = db->getCollection(_txn, nsString.ns());
- }
- else {
- invariant(_request->isExplain());
- }
-
- // The update stage does not create its own collection. As such, if the update is
- // an upsert, create the collection that the update stage inserts into beforehand.
- // We can only create the collection if this is not an explain, as explains should not
- // alter the state of the database.
- if (!collection && _request->isUpsert() && !_request->isExplain()) {
- // We have to have an exclsive lock on the db to be allowed to create the collection.
- // Callers should either get an X or create the collection.
- const Locker* locker = _txn->lockState();
- invariant( locker->isW() ||
- locker->isLockHeldForMode( ResourceId( RESOURCE_DATABASE, nsString.db() ),
- MODE_X ) );
-
- ScopedTransaction transaction(_txn, MODE_IX);
- Lock::DBLock lk(_txn->lockState(), nsString.db(), MODE_X);
-
- WriteUnitOfWork wuow(_txn);
- invariant(db->createCollection(_txn, nsString.ns()));
-
- if (!_request->isFromReplication()) {
- repl::logOp(_txn,
- "c",
- (db->name() + ".$cmd").c_str(),
- BSON("create" << (nsString.coll())));
- }
- wuow.commit();
- collection = db->getCollection(_txn, nsString.ns());
- invariant(collection);
- }
-
- // TODO: This seems a bit circuitious.
- _opDebug->updateobj = _request->getUpdates();
-
- // If this is a user-issued update, then we want to return an error: you cannot perform
- // writes on a secondary. If this is an update to a secondary from the replication system,
- // however, then we make an exception and let the write proceed. In this case,
- // shouldCallLogOp() will be false.
- if (_request->shouldCallLogOp() &&
- !repl::getGlobalReplicationCoordinator()->canAcceptWritesForDatabase(nsString.db())) {
- return Status(ErrorCodes::NotMaster,
- str::stream() << "Not primary while performing update on "
- << nsString.ns());
- }
-
- if (lifecycle) {
- lifecycle->setCollection(collection);
- _driver.refreshIndexKeys(lifecycle->getIndexKeys(_txn));
- }
-
- // 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 = NULL;
- Status getExecStatus = Status::OK();
- if (_canonicalQuery.get()) {
- // This is the regular path for when we have a CanonicalQuery.
- getExecStatus = getExecutorUpdate(_txn,
- collection,
- _canonicalQuery.release(),
- _request,
- &_driver,
- _opDebug,
- policy,
- &rawExec);
- }
- else {
- // This is the idhack fast-path for getting a PlanExecutor without doing the work
- // to create a CanonicalQuery.
- getExecStatus = getExecutorUpdate(_txn,
- collection,
- nsString.ns(),
- _request,
- &_driver,
- _opDebug,
- policy,
- &rawExec);
- }
-
- if (!getExecStatus.isOK()) {
- return getExecStatus;
- }
-
- invariant(rawExec);
- _exec.reset(rawExec);
-
- return Status::OK();
- }
-
- UpdateResult UpdateExecutor::execute(Database* db) {
- uassertStatusOK(prepare());
-
- LOG(3) << "processing update : " << *_request;
-
- // If we've already done the in-lock preparation, this is a no-op.
- Status status = prepareInLock(db);
- uassert(17243,
- "could not get executor " + _request->getQuery().toString()
- + "; " + causedBy(status),
- status.isOK());
-
- // Run the plan (don't need to collect results because UpdateStage always returns
- // NEED_TIME).
- uassertStatusOK(_exec->executePlan());
-
- // Get stats from the root stage.
- invariant(_exec->getRootStage()->stageType() == STAGE_UPDATE);
- UpdateStage* updateStage = static_cast<UpdateStage*>(_exec->getRootStage());
- const UpdateStats* updateStats =
- static_cast<const UpdateStats*>(updateStage->getSpecificStats());
-
- // Use stats from the root stage to fill out opDebug.
- _opDebug->nMatched = updateStats->nMatched;
- _opDebug->nModified = updateStats->nModified;
- _opDebug->upsert = updateStats->inserted;
- _opDebug->fastmodinsert = updateStats->fastmodinsert;
- _opDebug->fastmod = updateStats->fastmod;
-
- // Historically, 'opDebug' considers 'nMatched' and 'nModified' to be 1 (rather than 0) if
- // there is an upsert that inserts a document. The UpdateStage does not participate in this
- // madness in order to have saner stats reporting for explain. This means that we have to
- // set these values "manually" in the case of an insert.
- if (updateStats->inserted) {
- _opDebug->nMatched = 1;
- _opDebug->nModified = 1;
- }
-
- // Get summary information about the plan.
- PlanSummaryStats stats;
- Explain::getSummaryStats(_exec.get(), &stats);
- _opDebug->nscanned = stats.totalKeysExamined;
- _opDebug->nscannedObjects = stats.totalDocsExamined;
-
- return UpdateResult(updateStats->nMatched > 0 /* Did we update at least one obj? */,
- !_driver.isDocReplacement() /* $mod or obj replacement */,
- _opDebug->nModified /* number of modified docs, no no-ops */,
- _opDebug->nMatched /* # of docs matched/updated, even no-ops */,
- updateStats->objInserted);
- }
-
- Status UpdateExecutor::parseQuery() {
- if (_isQueryParsed)
- return Status::OK();
-
- dassert(!_canonicalQuery.get());
- dassert(_isUpdateParsed);
-
- if (!_driver.needMatchDetails() && 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()) {
- cqRaw->setIsForWrite( true );
- _canonicalQuery.reset(cqRaw);
- _isQueryParsed = true;
- }
-
- return status;
- }
-
- Status UpdateExecutor::parseUpdate() {
- if (_isUpdateParsed)
- return Status::OK();
-
- const NamespaceString& ns(_request->getNamespaceString());
-
- // Should the modifiers validate their embedded docs via okForStorage
- // Only user updates should be checked. Any system or replication stuff should pass through.
- // Config db docs shouldn't get checked for valid field names since the shard key can have
- // a dot (".") in it.
- const bool shouldValidate = !(_request->isFromReplication() ||
- ns.isConfigDB() ||
- _request->isFromMigration());
-
- _driver.setLogOp(true);
- _driver.setModOptions(ModifierInterface::Options(_request->isFromReplication(),
- shouldValidate));
- Status status = _driver.parse(_request->getUpdates(), _request->isMulti());
- if (status.isOK())
- _isUpdateParsed = true;
- return status;
- }
-
-} // namespace mongo
diff --git a/src/mongo/db/ops/update_executor.h b/src/mongo/db/ops/update_executor.h
deleted file mode 100644
index d0ef41083a2..00000000000
--- a/src/mongo/db/ops/update_executor.h
+++ /dev/null
@@ -1,149 +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/ops/update_driver.h"
-#include "mongo/db/ops/update_result.h"
-#include "mongo/db/query/plan_executor.h"
-
-namespace mongo {
-
- class CanonicalQuery;
- class OpDebug;
- class OperationContext;
- class UpdateRequest;
-
- /**
- * Implementation of the processing of an update 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 update, but the caller must already hold the
- * appropriate database lock.
- *
- * Expected usage is approximately:
- * UpdateRequest request(...);
- * // configure request
- * UpdateExecutor executor(txn, &request, opDebug);
- * uassertStatusOK(executor.prepare());
- * // Get locks, get ready to execute.
- * try {
- * UpdateResult res = executor.execute();
- * }
- * catch (const DBException& ex) {
- * // Error handling.
- * }
- */
- class UpdateExecutor {
- MONGO_DISALLOW_COPYING(UpdateExecutor);
- public:
- /**
- * Constructs an update executor.
- *
- * The objects pointed to by "request" and "opDebug" must stay in scope for the life of the
- * constructed executor.
- */
- UpdateExecutor(OperationContext* txn, const UpdateRequest* request, OpDebug* opDebug);
-
- ~UpdateExecutor();
-
- /**
- * 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 update 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 update upon calling
- * execute(). Returns NULL if no PlanExecutor has been created.
- */
- PlanExecutor* getPlanExecutor();
-
- /**
- * Execute an update. Requires the caller to hold the database lock on the
- * appropriate resources for the request.
- */
- UpdateResult execute(Database* db);
-
- private:
- /**
- * Parses the query portion of the update request.
- */
- Status parseQuery();
-
- /**
- * Parses the update-descriptor portion of the update request.
- */
- Status parseUpdate();
-
- // Transactional context. Not owned by us.
- OperationContext* _txn;
-
- // Unowned pointer to the request object that this executor will process.
- const UpdateRequest* const _request;
-
- // Unowned pointer to the opdebug object that this executor will populate with debug data.
- OpDebug* const _opDebug;
-
- // Driver for processing updates on matched documents.
- UpdateDriver _driver;
-
- // 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;
-
- // Flag indicatin gif the update description has been successfully parsed.
- bool _isUpdateParsed;
- };
-
-} // namespace mongo