diff options
author | Kaloian Manassiev <kaloian.manassiev@mongodb.com> | 2014-07-09 04:15:56 -0400 |
---|---|---|
committer | Kaloian Manassiev <kaloian.manassiev@mongodb.com> | 2014-07-18 15:16:15 -0400 |
commit | 9066a06214f115c182c2b83ed40e939e05b9c1f8 (patch) | |
tree | 4239137f6521f1d1d77ecc3c3be89b6e6779f7f1 | |
parent | 3c3d656668e26645492ee3dafb241631352426d4 (diff) | |
download | mongo-9066a06214f115c182c2b83ed40e939e05b9c1f8.tar.gz |
SERVER-13961 Pass OperationContext into WhereCallbackReal
There are no functional changes in this commit, just preparation for the
subsequent one, which will add operation context to the JS execution
scope.
39 files changed, 276 insertions, 181 deletions
diff --git a/src/mongo/db/commands/count.cpp b/src/mongo/db/commands/count.cpp index e630ff21dc9..f68f7488785 100644 --- a/src/mongo/db/commands/count.cpp +++ b/src/mongo/db/commands/count.cpp @@ -209,7 +209,7 @@ namespace mongo { const BSONObj hintObj = hint.empty() ? BSONObj() : BSON("$hint" << hint); StringData dbnameData(dbname); - const WhereCallbackReal whereCallback(dbnameData); + const WhereCallbackReal whereCallback(txn, dbnameData); CanonicalQuery* cq; uassertStatusOK(CanonicalQuery::canonicalize(ns, diff --git a/src/mongo/db/commands/find_and_modify.cpp b/src/mongo/db/commands/find_and_modify.cpp index f242327f935..9df4c363b62 100644 --- a/src/mongo/db/commands/find_and_modify.cpp +++ b/src/mongo/db/commands/find_and_modify.cpp @@ -142,7 +142,7 @@ namespace mongo { Collection* collection = cx.db()->getCollection( txn, ns ); - const WhereCallbackReal whereCallback = WhereCallbackReal(StringData(ns)); + const WhereCallbackReal whereCallback = WhereCallbackReal(txn, StringData(ns)); BSONObj doc; bool found = false; @@ -247,7 +247,7 @@ namespace mongo { } const NamespaceString requestNs(ns); - UpdateRequest request(requestNs); + UpdateRequest request(txn, requestNs); request.setQuery(queryModified); request.setUpdates(update); @@ -257,8 +257,7 @@ namespace mongo { // the shard version below, but for now no UpdateLifecycleImpl updateLifecycle(false, requestNs); request.setLifecycle(&updateLifecycle); - UpdateResult res = mongo::update(txn, - cx.db(), + UpdateResult res = mongo::update(cx.db(), request, &txn->getCurOp()->debug()); @@ -328,7 +327,7 @@ namespace mongo { Projection projection; if (fields) { - projection.init(fieldsHolder, WhereCallbackReal(StringData(dbname))); + projection.init(fieldsHolder, WhereCallbackReal(txn, StringData(dbname))); if (!projection.includeID()) { fields = NULL; // do projection in post-processing } diff --git a/src/mongo/db/commands/geo_near_cmd.cpp b/src/mongo/db/commands/geo_near_cmd.cpp index f994004e2b2..7fb6b972efd 100644 --- a/src/mongo/db/commands/geo_near_cmd.cpp +++ b/src/mongo/db/commands/geo_near_cmd.cpp @@ -171,7 +171,7 @@ namespace mongo { CanonicalQuery* cq; const NamespaceString nss(dbname); - const WhereCallbackReal whereCallback(nss.db()); + const WhereCallbackReal whereCallback(txn, nss.db()); if (!CanonicalQuery::canonicalize(ns, rewritten, diff --git a/src/mongo/db/commands/group.cpp b/src/mongo/db/commands/group.cpp index 519a5989dd1..aed8e699e83 100644 --- a/src/mongo/db/commands/group.cpp +++ b/src/mongo/db/commands/group.cpp @@ -134,7 +134,7 @@ namespace mongo { Collection* collection = db->getCollection( txn, ns ); - const WhereCallbackReal whereCallback(StringData(db->name())); + const WhereCallbackReal whereCallback(txn, StringData(db->name())); map<BSONObj,int,BSONObjCmp> map; list<BSONObj> blah; diff --git a/src/mongo/db/commands/index_filter_commands.cpp b/src/mongo/db/commands/index_filter_commands.cpp index e0d5be5255a..139350b3002 100644 --- a/src/mongo/db/commands/index_filter_commands.cpp +++ b/src/mongo/db/commands/index_filter_commands.cpp @@ -67,9 +67,11 @@ namespace { /** * Retrieves a collection's query settings and plan cache from the database. */ - Status getQuerySettingsAndPlanCache(OperationContext* txn, Database* db, const string& ns, - QuerySettings** querySettingsOut, - PlanCache** planCacheOut) { + static Status getQuerySettingsAndPlanCache(OperationContext* txn, + Database* db, + const string& ns, + QuerySettings** querySettingsOut, + PlanCache** planCacheOut) { invariant(db); Collection* collection = db->getCollection(txn, ns); @@ -238,12 +240,15 @@ namespace mongo { // No collection - do nothing. return Status::OK(); } - return clear(querySettings, planCache, ns, cmdObj); + return clear(txn, querySettings, planCache, ns, cmdObj); } // static - Status ClearFilters::clear(QuerySettings* querySettings, PlanCache* planCache, - const std::string& ns, const BSONObj& cmdObj) { + Status ClearFilters::clear(OperationContext* txn, + QuerySettings* querySettings, + PlanCache* planCache, + const std::string& ns, + const BSONObj& cmdObj) { invariant(querySettings); // According to the specification, the planCacheClearFilters command runs in two modes: @@ -252,7 +257,7 @@ namespace mongo { // command arguments. if (cmdObj.hasField("query")) { CanonicalQuery* cqRaw; - Status status = PlanCacheCommand::canonicalize(ns, cmdObj, &cqRaw); + Status status = PlanCacheCommand::canonicalize(txn, ns, cmdObj, &cqRaw); if (!status.isOK()) { return status; } @@ -281,7 +286,7 @@ namespace mongo { querySettings->clearAllowedIndices(); const NamespaceString nss(ns); - const WhereCallbackReal whereCallback(nss.db()); + const WhereCallbackReal whereCallback(txn, nss.db()); // Remove corresponding entries from plan cache. // Admin hints affect the planning process directly. If there were @@ -328,12 +333,15 @@ namespace mongo { if (!status.isOK()) { return status; } - return set(querySettings, planCache, ns, cmdObj); + return set(txn, querySettings, planCache, ns, cmdObj); } // static - Status SetFilter::set(QuerySettings* querySettings, PlanCache* planCache, - const string& ns, const BSONObj& cmdObj) { + Status SetFilter::set(OperationContext* txn, + QuerySettings* querySettings, + PlanCache* planCache, + const string& ns, + const BSONObj& cmdObj) { // indexes - required BSONElement indexesElt = cmdObj.getField("indexes"); if (indexesElt.eoo()) { @@ -362,7 +370,7 @@ namespace mongo { } CanonicalQuery* cqRaw; - Status status = PlanCacheCommand::canonicalize(ns, cmdObj, &cqRaw); + Status status = PlanCacheCommand::canonicalize(txn, ns, cmdObj, &cqRaw); if (!status.isOK()) { return status; } diff --git a/src/mongo/db/commands/index_filter_commands.h b/src/mongo/db/commands/index_filter_commands.h index f6ba8fa9efb..2f106b16f36 100644 --- a/src/mongo/db/commands/index_filter_commands.h +++ b/src/mongo/db/commands/index_filter_commands.h @@ -138,7 +138,10 @@ namespace mongo { * Namespace argument ns is ignored if we are clearing the entire cache. * Removes corresponding entries from plan cache. */ - static Status clear(QuerySettings* querySettings, PlanCache* planCache, const std::string& ns, + static Status clear(OperationContext* txn, + QuerySettings* querySettings, + PlanCache* planCache, + const std::string& ns, const BSONObj& cmdObj); }; @@ -167,7 +170,10 @@ namespace mongo { * Sets index filter for a query shape. * Removes entry for query shape from plan cache. */ - static Status set(QuerySettings* querySettings, PlanCache* planCache, const std::string& ns, + static Status set(OperationContext* txn, + QuerySettings* querySettings, + PlanCache* planCache, + const std::string& ns, const BSONObj& cmdObj); }; diff --git a/src/mongo/db/commands/index_filter_commands_test.cpp b/src/mongo/db/commands/index_filter_commands_test.cpp index c3a5fc1d6a5..e892bcee7a8 100644 --- a/src/mongo/db/commands/index_filter_commands_test.cpp +++ b/src/mongo/db/commands/index_filter_commands_test.cpp @@ -33,6 +33,7 @@ #include "mongo/db/commands/index_filter_commands.h" #include "mongo/db/json.h" +#include "mongo/db/operation_context_noop.h" #include "mongo/db/query/plan_ranker.h" #include "mongo/db/query/query_solution.h" #include "mongo/unittest/unittest.h" @@ -181,35 +182,39 @@ namespace { TEST(IndexFilterCommandsTest, ClearFiltersInvalidParameter) { QuerySettings empty; PlanCache planCache; + OperationContextNoop txn; + // If present, query has to be an object. - ASSERT_NOT_OK(ClearFilters::clear(&empty, &planCache, ns, fromjson("{query: 1234}"))); + ASSERT_NOT_OK(ClearFilters::clear(&txn, &empty, &planCache, ns, fromjson("{query: 1234}"))); // If present, sort must be an object. - ASSERT_NOT_OK(ClearFilters::clear(&empty, &planCache, ns, + ASSERT_NOT_OK(ClearFilters::clear(&txn, &empty, &planCache, ns, fromjson("{query: {a: 1}, sort: 1234}"))); // If present, projection must be an object. - ASSERT_NOT_OK(ClearFilters::clear(&empty, &planCache, ns, + ASSERT_NOT_OK(ClearFilters::clear(&txn, &empty, &planCache, ns, fromjson("{query: {a: 1}, projection: 1234}"))); // Query must pass canonicalization. - ASSERT_NOT_OK(ClearFilters::clear(&empty, &planCache, ns, + ASSERT_NOT_OK(ClearFilters::clear(&txn, &empty, &planCache, ns, fromjson("{query: {a: {$no_such_op: 1}}}"))); // Sort present without query is an error. - ASSERT_NOT_OK(ClearFilters::clear(&empty, &planCache, ns, fromjson("{sort: {a: 1}}"))); + ASSERT_NOT_OK(ClearFilters::clear(&txn, &empty, &planCache, ns, fromjson("{sort: {a: 1}}"))); // Projection present without query is an error. - ASSERT_NOT_OK(ClearFilters::clear(&empty, &planCache, ns, + ASSERT_NOT_OK(ClearFilters::clear(&txn, &empty, &planCache, ns, fromjson("{projection: {_id: 0, a: 1}}"))); } TEST(IndexFilterCommandsTest, ClearNonexistentHint) { QuerySettings querySettings; PlanCache planCache; - ASSERT_OK(SetFilter::set(&querySettings, &planCache, ns, + OperationContextNoop txn; + + ASSERT_OK(SetFilter::set(&txn, &querySettings, &planCache, ns, fromjson("{query: {a: 1}, indexes: [{a: 1}]}"))); vector<BSONObj> filters = getFilters(querySettings); ASSERT_EQUALS(filters.size(), 1U); // Clear nonexistent hint. // Command should succeed and cache should remain unchanged. - ASSERT_OK(ClearFilters::clear(&querySettings, &planCache, ns, fromjson("{query: {b: 1}}"))); + ASSERT_OK(ClearFilters::clear(&txn, &querySettings, &planCache, ns, fromjson("{query: {b: 1}}"))); filters = getFilters(querySettings); ASSERT_EQUALS(filters.size(), 1U); } @@ -221,46 +226,49 @@ namespace { TEST(IndexFilterCommandsTest, SetFilterInvalidParameter) { QuerySettings empty; PlanCache planCache; - ASSERT_NOT_OK(SetFilter::set(&empty, &planCache, ns, fromjson("{}"))); + OperationContextNoop txn; + + ASSERT_NOT_OK(SetFilter::set(&txn, &empty, &planCache, ns, fromjson("{}"))); // Missing required query field. - ASSERT_NOT_OK(SetFilter::set(&empty, &planCache, ns, fromjson("{indexes: [{a: 1}]}"))); + ASSERT_NOT_OK(SetFilter::set(&txn, &empty, &planCache, ns, fromjson("{indexes: [{a: 1}]}"))); // Missing required indexes field. - ASSERT_NOT_OK(SetFilter::set(&empty, &planCache, ns, fromjson("{query: {a: 1}}"))); + ASSERT_NOT_OK(SetFilter::set(&txn, &empty, &planCache, ns, fromjson("{query: {a: 1}}"))); // Query has to be an object. - ASSERT_NOT_OK(SetFilter::set(&empty, &planCache, ns, + ASSERT_NOT_OK(SetFilter::set(&txn, &empty, &planCache, ns, fromjson("{query: 1234, indexes: [{a: 1}, {b: 1}]}"))); // Indexes field has to be an array. - ASSERT_NOT_OK(SetFilter::set(&empty, &planCache, ns, + ASSERT_NOT_OK(SetFilter::set(&txn, &empty, &planCache, ns, fromjson("{query: {a: 1}, indexes: 1234}"))); // Array indexes field cannot empty. - ASSERT_NOT_OK(SetFilter::set(&empty, &planCache, ns, + ASSERT_NOT_OK(SetFilter::set(&txn, &empty, &planCache, ns, fromjson("{query: {a: 1}, indexes: []}"))); // Elements in indexes have to be objects. - ASSERT_NOT_OK(SetFilter::set(&empty, &planCache, ns, + ASSERT_NOT_OK(SetFilter::set(&txn, &empty, &planCache, ns, fromjson("{query: {a: 1}, indexes: [{a: 1}, 99]}"))); // Objects in indexes cannot be empty. - ASSERT_NOT_OK(SetFilter::set(&empty, &planCache, ns, + ASSERT_NOT_OK(SetFilter::set(&txn, &empty, &planCache, ns, fromjson("{query: {a: 1}, indexes: [{a: 1}, {}]}"))); // If present, sort must be an object. - ASSERT_NOT_OK(SetFilter::set(&empty, &planCache, ns, + ASSERT_NOT_OK(SetFilter::set(&txn, &empty, &planCache, ns, fromjson("{query: {a: 1}, sort: 1234, indexes: [{a: 1}, {b: 1}]}"))); // If present, projection must be an object. - ASSERT_NOT_OK(SetFilter::set(&empty, &planCache, ns, + ASSERT_NOT_OK(SetFilter::set(&txn, &empty, &planCache, ns, fromjson("{query: {a: 1}, projection: 1234, indexes: [{a: 1}, {b: 1}]}"))); // Query must pass canonicalization. - ASSERT_NOT_OK(SetFilter::set(&empty, &planCache, ns, + ASSERT_NOT_OK(SetFilter::set(&txn, &empty, &planCache, ns, fromjson("{query: {a: {$no_such_op: 1}}, indexes: [{a: 1}, {b: 1}]}"))); } TEST(IndexFilterCommandsTest, SetAndClearFilters) { QuerySettings querySettings; PlanCache planCache; + OperationContextNoop txn; // Inject query shape into plan cache. addQueryShapeToPlanCache(&planCache, "{a: 1, b: 1}", "{a: -1}", "{_id: 0, a: 1}"); ASSERT_TRUE(planCacheContains(planCache, "{a: 1, b: 1}", "{a: -1}", "{_id: 0, a: 1}")); - ASSERT_OK(SetFilter::set(&querySettings, &planCache, ns, + ASSERT_OK(SetFilter::set(&txn, &querySettings, &planCache, ns, fromjson("{query: {a: 1, b: 1}, sort: {a: -1}, projection: {_id: 0, a: 1}, " "indexes: [{a: 1}]}"))); vector<BSONObj> filters = getFilters(querySettings); @@ -276,20 +284,20 @@ namespace { // Replacing the hint for the same query shape ({a: 1, b: 1} and {b: 2, a: 3} // share same shape) should not change the query settings size. - ASSERT_OK(SetFilter::set(&querySettings, &planCache, ns, + ASSERT_OK(SetFilter::set(&txn, &querySettings, &planCache, ns, fromjson("{query: {b: 2, a: 3}, sort: {a: -1}, projection: {_id: 0, a: 1}, " "indexes: [{a: 1, b: 1}]}"))); filters = getFilters(querySettings); ASSERT_EQUALS(filters.size(), 1U); // Add hint for different query shape. - ASSERT_OK(SetFilter::set(&querySettings, &planCache, ns, + ASSERT_OK(SetFilter::set(&txn, &querySettings, &planCache, ns, fromjson("{query: {b: 1}, indexes: [{b: 1}]}"))); filters = getFilters(querySettings); ASSERT_EQUALS(filters.size(), 2U); // Add hint for 3rd query shape. This is to prepare for ClearHint tests. - ASSERT_OK(SetFilter::set(&querySettings, &planCache, ns, + ASSERT_OK(SetFilter::set(&txn, &querySettings, &planCache, ns, fromjson("{query: {a: 1}, indexes: [{a: 1}]}"))); filters = getFilters(querySettings); ASSERT_EQUALS(filters.size(), 3U); @@ -299,7 +307,7 @@ namespace { addQueryShapeToPlanCache(&planCache, "{b: 1}", "{}", "{}"); // Clear single hint. - ASSERT_OK(ClearFilters::clear(&querySettings, &planCache, ns, + ASSERT_OK(ClearFilters::clear(&txn, &querySettings, &planCache, ns, fromjson("{query: {a: 1}}"))); filters = getFilters(querySettings); ASSERT_EQUALS(filters.size(), 2U); @@ -309,7 +317,7 @@ namespace { ASSERT_TRUE(planCacheContains(planCache, "{b: 1}", "{}", "{}")); // Clear all filters - ASSERT_OK(ClearFilters::clear(&querySettings, &planCache, ns, fromjson("{}"))); + ASSERT_OK(ClearFilters::clear(&txn, &querySettings, &planCache, ns, fromjson("{}"))); filters = getFilters(querySettings); ASSERT_TRUE(filters.empty()); diff --git a/src/mongo/db/commands/mr.cpp b/src/mongo/db/commands/mr.cpp index 58360d4cdd0..df0a6e7b9e3 100644 --- a/src/mongo/db/commands/mr.cpp +++ b/src/mongo/db/commands/mr.cpp @@ -977,7 +977,7 @@ namespace mongo { _db.count(_config.incLong, BSONObj(), QueryOption_SlaveOk))); const NamespaceString nss(_config.incLong); - const WhereCallbackReal whereCallback(nss.db()); + const WhereCallbackReal whereCallback(_txn, nss.db()); CanonicalQuery* cq; verify(CanonicalQuery::canonicalize(_config.incLong, @@ -1317,7 +1317,7 @@ namespace mongo { scoped_ptr<Client::Context> ctx(new Client::Context(txn, config.ns, false)); const NamespaceString nss(config.ns); - const WhereCallbackReal whereCallback(nss.db()); + const WhereCallbackReal whereCallback(txn, nss.db()); CanonicalQuery* cq; if (!CanonicalQuery::canonicalize(config.ns, diff --git a/src/mongo/db/commands/plan_cache_commands.cpp b/src/mongo/db/commands/plan_cache_commands.cpp index 7436ecc9eea..2a8bb83ef8c 100644 --- a/src/mongo/db/commands/plan_cache_commands.cpp +++ b/src/mongo/db/commands/plan_cache_commands.cpp @@ -157,7 +157,9 @@ namespace mongo { } // static - Status PlanCacheCommand::canonicalize(const string& ns, const BSONObj& cmdObj, + Status PlanCacheCommand::canonicalize(OperationContext* txn, + const string& ns, + const BSONObj& cmdObj, CanonicalQuery** canonicalQueryOut) { // query - required BSONElement queryElt = cmdObj.getField("query"); @@ -196,7 +198,7 @@ namespace mongo { CanonicalQuery* cqRaw; const NamespaceString nss(ns); - const WhereCallbackReal whereCallback(nss.db()); + const WhereCallbackReal whereCallback(txn, nss.db()); Status result = CanonicalQuery::canonicalize( ns, queryObj, sortObj, projObj, &cqRaw, whereCallback); @@ -273,11 +275,14 @@ namespace mongo { // No collection - nothing to do. Return OK status. return Status::OK(); } - return clear(planCache, ns, cmdObj); + return clear(txn, planCache, ns, cmdObj); } // static - Status PlanCacheClear::clear(PlanCache* planCache, const string& ns, const BSONObj& cmdObj) { + Status PlanCacheClear::clear(OperationContext* txn, + PlanCache* planCache, + const string& ns, + const BSONObj& cmdObj) { invariant(planCache); // According to the specification, the planCacheClear command runs in two modes: @@ -286,7 +291,7 @@ namespace mongo { // command arguments. if (cmdObj.hasField("query")) { CanonicalQuery* cqRaw; - Status status = PlanCacheCommand::canonicalize(ns, cmdObj, &cqRaw); + Status status = PlanCacheCommand::canonicalize(txn, ns, cmdObj, &cqRaw); if (!status.isOK()) { return status; } @@ -346,14 +351,17 @@ namespace mongo { plansBuilder.doneFast(); return Status::OK(); } - return list(*planCache, ns, cmdObj, bob); + return list(txn, *planCache, ns, cmdObj, bob); } // static - Status PlanCacheListPlans::list(const PlanCache& planCache, const std::string& ns, - const BSONObj& cmdObj, BSONObjBuilder* bob) { + Status PlanCacheListPlans::list(OperationContext* txn, + const PlanCache& planCache, + const std::string& ns, + const BSONObj& cmdObj, + BSONObjBuilder* bob) { CanonicalQuery* cqRaw; - Status status = canonicalize(ns, cmdObj, &cqRaw); + Status status = canonicalize(txn, ns, cmdObj, &cqRaw); if (!status.isOK()) { return status; } diff --git a/src/mongo/db/commands/plan_cache_commands.h b/src/mongo/db/commands/plan_cache_commands.h index 507d4fe4927..1a4a49a3c4f 100644 --- a/src/mongo/db/commands/plan_cache_commands.h +++ b/src/mongo/db/commands/plan_cache_commands.h @@ -89,7 +89,9 @@ namespace mongo { /** * Validatess query shape from command object and returns canonical query. */ - static Status canonicalize(const std::string& ns, const BSONObj& cmdObj, + static Status canonicalize(OperationContext* txn, + const std::string& ns, + const BSONObj& cmdObj, CanonicalQuery** canonicalQueryOut); private: @@ -141,7 +143,10 @@ namespace mongo { * Clears collection's plan cache. * If query shape is provided, clears plans for that single query shape only. */ - static Status clear(PlanCache* planCache, const std::string& ns, const BSONObj& cmdObj); + static Status clear(OperationContext* txn, + PlanCache* planCache, + const std::string& ns, + const BSONObj& cmdObj); }; /** @@ -166,8 +171,11 @@ namespace mongo { /** * Displays the cached plans for a query shape. */ - static Status list(const PlanCache& planCache, const std::string& ns, - const BSONObj& cmdObj, BSONObjBuilder* bob); + static Status list(OperationContext* txn, + const PlanCache& planCache, + const std::string& ns, + const BSONObj& cmdObj, + BSONObjBuilder* bob); }; } // namespace mongo diff --git a/src/mongo/db/commands/plan_cache_commands_test.cpp b/src/mongo/db/commands/plan_cache_commands_test.cpp index 5a6775cdb74..d2cae74ac12 100644 --- a/src/mongo/db/commands/plan_cache_commands_test.cpp +++ b/src/mongo/db/commands/plan_cache_commands_test.cpp @@ -34,6 +34,7 @@ #include <algorithm> #include "mongo/db/json.h" +#include "mongo/db/operation_context_noop.h" #include "mongo/db/query/plan_ranker.h" #include "mongo/db/query/query_solution.h" #include "mongo/unittest/unittest.h" @@ -154,6 +155,8 @@ namespace { // Plan cache with one entry PlanCache planCache; QuerySolution qs; + OperationContextNoop txn; + qs.cacheData.reset(createSolutionCacheData()); std::vector<QuerySolution*> solns; solns.push_back(&qs); @@ -161,7 +164,7 @@ namespace { ASSERT_EQUALS(getShapes(planCache).size(), 1U); // Clear cache and confirm number of keys afterwards. - ASSERT_OK(PlanCacheClear::clear(&planCache, ns, BSONObj())); + ASSERT_OK(PlanCacheClear::clear(&txn, &planCache, ns, BSONObj())); ASSERT_EQUALS(getShapes(planCache).size(), 0U); } @@ -173,35 +176,37 @@ namespace { TEST(PlanCacheCommandsTest, Canonicalize) { // Invalid parameters CanonicalQuery* cqRaw; + OperationContextNoop txn; + // Missing query field - ASSERT_NOT_OK(PlanCacheCommand::canonicalize(ns, fromjson("{}"), &cqRaw)); + ASSERT_NOT_OK(PlanCacheCommand::canonicalize(&txn, ns, fromjson("{}"), &cqRaw)); // Query needs to be an object - ASSERT_NOT_OK(PlanCacheCommand::canonicalize(ns, fromjson("{query: 1}"), &cqRaw)); + ASSERT_NOT_OK(PlanCacheCommand::canonicalize(&txn, ns, fromjson("{query: 1}"), &cqRaw)); // Sort needs to be an object - ASSERT_NOT_OK(PlanCacheCommand::canonicalize(ns, fromjson("{query: {}, sort: 1}"), + ASSERT_NOT_OK(PlanCacheCommand::canonicalize(&txn, ns, fromjson("{query: {}, sort: 1}"), &cqRaw)); // Bad query (invalid sort order) - ASSERT_NOT_OK(PlanCacheCommand::canonicalize(ns, fromjson("{query: {}, sort: {a: 0}}"), + ASSERT_NOT_OK(PlanCacheCommand::canonicalize(&txn, ns, fromjson("{query: {}, sort: {a: 0}}"), &cqRaw)); // Valid parameters - ASSERT_OK(PlanCacheCommand::canonicalize(ns, fromjson("{query: {a: 1, b: 1}}"), &cqRaw)); + ASSERT_OK(PlanCacheCommand::canonicalize(&txn, ns, fromjson("{query: {a: 1, b: 1}}"), &cqRaw)); scoped_ptr<CanonicalQuery> query(cqRaw); // Equivalent query should generate same key. - ASSERT_OK(PlanCacheCommand::canonicalize(ns, fromjson("{query: {b: 1, a: 1}}"), &cqRaw)); + ASSERT_OK(PlanCacheCommand::canonicalize(&txn, ns, fromjson("{query: {b: 1, a: 1}}"), &cqRaw)); scoped_ptr<CanonicalQuery> equivQuery(cqRaw); ASSERT_EQUALS(query->getPlanCacheKey(), equivQuery->getPlanCacheKey()); // Sort query should generate different key from unsorted query. - ASSERT_OK(PlanCacheCommand::canonicalize(ns, + ASSERT_OK(PlanCacheCommand::canonicalize(&txn, ns, fromjson("{query: {a: 1, b: 1}, sort: {a: 1}}"), &cqRaw)); scoped_ptr<CanonicalQuery> sortQuery(cqRaw); ASSERT_NOT_EQUALS(query->getPlanCacheKey(), sortQuery->getPlanCacheKey()); // Projected query should generate different key from unprojected query. - ASSERT_OK(PlanCacheCommand::canonicalize(ns, + ASSERT_OK(PlanCacheCommand::canonicalize(&txn, ns, fromjson("{query: {a: 1, b: 1}, projection: {_id: 0, a: 1}}"), &cqRaw)); scoped_ptr<CanonicalQuery> projectionQuery(cqRaw); ASSERT_NOT_EQUALS(query->getPlanCacheKey(), projectionQuery->getPlanCacheKey()); @@ -213,22 +218,26 @@ namespace { TEST(PlanCacheCommandsTest, planCacheClearInvalidParameter) { PlanCache planCache; + OperationContextNoop txn; + // Query field type must be BSON object. - ASSERT_NOT_OK(PlanCacheClear::clear(&planCache, ns, fromjson("{query: 12345}"))); - ASSERT_NOT_OK(PlanCacheClear::clear(&planCache, ns, fromjson("{query: /keyisnotregex/}"))); + ASSERT_NOT_OK(PlanCacheClear::clear(&txn, &planCache, ns, fromjson("{query: 12345}"))); + ASSERT_NOT_OK(PlanCacheClear::clear(&txn, &planCache, ns, fromjson("{query: /keyisnotregex/}"))); // Query must pass canonicalization. - ASSERT_NOT_OK(PlanCacheClear::clear(&planCache, ns, + ASSERT_NOT_OK(PlanCacheClear::clear(&txn, &planCache, ns, fromjson("{query: {a: {$no_such_op: 1}}}"))); // Sort present without query is an error. - ASSERT_NOT_OK(PlanCacheClear::clear(&planCache, ns, fromjson("{sort: {a: 1}}"))); + ASSERT_NOT_OK(PlanCacheClear::clear(&txn, &planCache, ns, fromjson("{sort: {a: 1}}"))); // Projection present without query is an error. - ASSERT_NOT_OK(PlanCacheClear::clear(&planCache, ns, + ASSERT_NOT_OK(PlanCacheClear::clear(&txn, &planCache, ns, fromjson("{projection: {_id: 0, a: 1}}"))); } TEST(PlanCacheCommandsTest, planCacheClearUnknownKey) { PlanCache planCache; - ASSERT_OK(PlanCacheClear::clear(&planCache, ns, fromjson("{query: {a: 1}}"))); + OperationContextNoop txn; + + ASSERT_OK(PlanCacheClear::clear(&txn, &planCache, ns, fromjson("{query: {a: 1}}"))); } TEST(PlanCacheCommandsTest, planCacheClearOneKey) { @@ -260,7 +269,9 @@ namespace { // Drop {b: 1} from cache. Make sure {a: 1} is still in cache afterwards. BSONObjBuilder bob; - ASSERT_OK(PlanCacheClear::clear(&planCache, ns, BSON("query" << cqB->getQueryObj()))); + OperationContextNoop txn; + + ASSERT_OK(PlanCacheClear::clear(&txn, &planCache, ns, BSON("query" << cqB->getQueryObj()))); vector<BSONObj> shapesAfter = getShapes(planCache); ASSERT_EQUALS(shapesAfter.size(), 1U); ASSERT_EQUALS(shapesAfter[0], shapeA); @@ -308,9 +319,11 @@ namespace { */ vector<BSONObj> getPlans(const PlanCache& planCache, const BSONObj& query, const BSONObj& sort, const BSONObj& projection) { + OperationContextNoop txn; + BSONObjBuilder bob; BSONObj cmdObj = BSON("query" << query << "sort" << sort << "projection" << projection); - ASSERT_OK(PlanCacheListPlans::list(planCache, ns, cmdObj, &bob)); + ASSERT_OK(PlanCacheListPlans::list(&txn, planCache, ns, cmdObj, &bob)); BSONObj resultObj = bob.obj(); BSONElement plansElt = resultObj.getField("plans"); ASSERT_EQUALS(plansElt.type(), mongo::Array); @@ -324,21 +337,24 @@ namespace { TEST(PlanCacheCommandsTest, planCacheListPlansInvalidParameter) { PlanCache planCache; BSONObjBuilder ignored; + OperationContextNoop txn; + // Missing query field is not ok. - ASSERT_NOT_OK(PlanCacheListPlans::list(planCache, ns, BSONObj(), &ignored)); + ASSERT_NOT_OK(PlanCacheListPlans::list(&txn, planCache, ns, BSONObj(), &ignored)); // Query field type must be BSON object. - ASSERT_NOT_OK(PlanCacheListPlans::list(planCache, ns, fromjson("{query: 12345}"), + ASSERT_NOT_OK(PlanCacheListPlans::list(&txn, planCache, ns, fromjson("{query: 12345}"), &ignored)); - ASSERT_NOT_OK(PlanCacheListPlans::list(planCache, ns, fromjson("{query: /keyisnotregex/}"), + ASSERT_NOT_OK(PlanCacheListPlans::list(&txn, planCache, ns, fromjson("{query: /keyisnotregex/}"), &ignored)); } TEST(PlanCacheCommandsTest, planCacheListPlansUnknownKey) { // Leave the plan cache empty. PlanCache planCache; + OperationContextNoop txn; BSONObjBuilder ignored; - ASSERT_OK(PlanCacheListPlans::list(planCache, ns, fromjson("{query: {a: 1}}"), &ignored)); + ASSERT_OK(PlanCacheListPlans::list(&txn, planCache, ns, fromjson("{query: {a: 1}}"), &ignored)); } TEST(PlanCacheCommandsTest, planCacheListPlansOnlyOneSolutionTrue) { diff --git a/src/mongo/db/commands/write_commands/batch_executor.cpp b/src/mongo/db/commands/write_commands/batch_executor.cpp index 2f3a39fa3d7..419c01be9c6 100644 --- a/src/mongo/db/commands/write_commands/batch_executor.cpp +++ b/src/mongo/db/commands/write_commands/batch_executor.cpp @@ -1088,7 +1088,7 @@ namespace mongo { WriteOpResult* result ) { const NamespaceString nsString(updateItem.getRequest()->getNS()); - UpdateRequest request(nsString); + UpdateRequest request(txn, nsString); request.setQuery(updateItem.getUpdate()->getQuery()); request.setUpdates(updateItem.getUpdate()->getUpdateExpr()); request.setMulti(updateItem.getUpdate()->getMulti()); @@ -1115,7 +1115,7 @@ namespace mongo { Client::Context ctx(txn, nsString.ns(), false /* don't check version */); try { - UpdateResult res = executor.execute(txn, ctx.db()); + UpdateResult res = executor.execute(ctx.db()); const long long numDocsModified = res.numDocsModified; const long long numMatched = res.numMatched; @@ -1149,7 +1149,7 @@ namespace mongo { WriteOpResult* result ) { const NamespaceString nss( removeItem.getRequest()->getNS() ); - DeleteRequest request( nss ); + DeleteRequest request(txn, nss); request.setQuery( removeItem.getDelete()->getQuery() ); request.setMulti( removeItem.getDelete()->getLimit() != 1 ); request.setUpdateOpLog(true); @@ -1178,7 +1178,7 @@ namespace mongo { Client::Context writeContext(txn, nss.ns(), false /* don't check version */); try { - result->getStats().n = executor.execute(txn, writeContext.db()); + result->getStats().n = executor.execute(writeContext.db()); } catch ( const DBException& ex ) { status = ex.toStatus(); diff --git a/src/mongo/db/dbhelpers.cpp b/src/mongo/db/dbhelpers.cpp index 8cc0eb0bd1c..ae6b560dbad 100644 --- a/src/mongo/db/dbhelpers.cpp +++ b/src/mongo/db/dbhelpers.cpp @@ -107,7 +107,7 @@ namespace mongo { return DiskLoc(); CanonicalQuery* cq; - const WhereCallbackReal whereCallback(collection->ns().db()); + const WhereCallbackReal whereCallback(txn, collection->ns().db()); massert(17244, "Could not canonicalize " + query.toString(), CanonicalQuery::canonicalize(collection->ns(), query, &cq, whereCallback).isOK()); @@ -216,7 +216,7 @@ namespace mongo { Client::Context context(txn, ns); const NamespaceString requestNs(ns); - UpdateRequest request(requestNs); + UpdateRequest request(txn, requestNs); request.setQuery(id); request.setUpdates(o); @@ -226,7 +226,7 @@ namespace mongo { UpdateLifecycleImpl updateLifecycle(true, requestNs); request.setLifecycle(&updateLifecycle); - update(txn, context.db(), request, &debug); + update(context.db(), request, &debug); } void Helpers::putSingleton(OperationContext* txn, const char *ns, BSONObj obj) { @@ -234,7 +234,7 @@ namespace mongo { Client::Context context(txn, ns); const NamespaceString requestNs(ns); - UpdateRequest request(requestNs); + UpdateRequest request(txn, requestNs); request.setUpdates(obj); request.setUpsert(); @@ -242,7 +242,7 @@ namespace mongo { UpdateLifecycleImpl updateLifecycle(true, requestNs); request.setLifecycle(&updateLifecycle); - update(txn, context.db(), request, &debug); + update(context.db(), request, &debug); context.getClient()->curop()->done(); } @@ -252,14 +252,14 @@ namespace mongo { Client::Context context(txn, ns); const NamespaceString requestNs(ns); - UpdateRequest request(requestNs); + UpdateRequest request(txn, requestNs); request.setGod(); request.setUpdates(obj); request.setUpsert(); request.setUpdateOpLog(logTheOp); - update(txn, context.db(), request, &debug); + update(context.db(), request, &debug); context.getClient()->curop()->done(); } diff --git a/src/mongo/db/exec/stagedebug_cmd.cpp b/src/mongo/db/exec/stagedebug_cmd.cpp index 346d481d8be..952b3b1e104 100644 --- a/src/mongo/db/exec/stagedebug_cmd.cpp +++ b/src/mongo/db/exec/stagedebug_cmd.cpp @@ -177,7 +177,7 @@ namespace mongo { BSONObj argObj = e.Obj(); if (filterTag == e.fieldName()) { StatusWithMatchExpression swme = MatchExpressionParser::parse( - argObj, WhereCallbackReal(collection->ns().db())); + argObj, WhereCallbackReal(txn, collection->ns().db())); if (!swme.isOK()) { return NULL; } // exprs is what will wind up deleting this. matcher = swme.getValue(); diff --git a/src/mongo/db/exec/subplan.cpp b/src/mongo/db/exec/subplan.cpp index 245450998b3..4019aae418b 100644 --- a/src/mongo/db/exec/subplan.cpp +++ b/src/mongo/db/exec/subplan.cpp @@ -156,7 +156,7 @@ namespace mongo { QLOG() << "Subplanner: index " << i << " is " << ie.toString() << endl; } - const WhereCallbackReal whereCallback(_collection->ns().db()); + const WhereCallbackReal whereCallback(_txn, _collection->ns().db()); for (size_t i = 0; i < theOr->numChildren(); ++i) { // Turn the i-th child into its own query. diff --git a/src/mongo/db/fts/fts_command_mongod.cpp b/src/mongo/db/fts/fts_command_mongod.cpp index a2c4b35e165..bebfa07cdfc 100644 --- a/src/mongo/db/fts/fts_command_mongod.cpp +++ b/src/mongo/db/fts/fts_command_mongod.cpp @@ -106,7 +106,7 @@ namespace mongo { limit, BSONObj(), &cq, - WhereCallbackReal(StringData(dbname))); + WhereCallbackReal(txn, StringData(dbname))); if (!canonicalizeStatus.isOK()) { errmsg = canonicalizeStatus.reason(); return false; diff --git a/src/mongo/db/instance.cpp b/src/mongo/db/instance.cpp index da48a427e23..fe90ef4b588 100644 --- a/src/mongo/db/instance.cpp +++ b/src/mongo/db/instance.cpp @@ -104,7 +104,7 @@ namespace mongo { MONGO_FP_DECLARE(rsStopGetMore); - static void inProgCmd( Message &m, DbResponse &dbresponse ) { + static void inProgCmd(OperationContext* txn, Message &m, DbResponse &dbresponse) { DbMessage d(m); QueryMessage q(d); BSONObjBuilder b; @@ -139,7 +139,7 @@ namespace mongo { Client& me = cc(); scoped_lock bl(Client::clientsMutex); - Matcher m(filter, WhereCallbackReal(nss.db())); + Matcher m(filter, WhereCallbackReal(txn, nss.db())); for( set<Client*>::iterator i = Client::clients.begin(); i != Client::clients.end(); i++ ) { Client *c = *i; verify( c ); @@ -346,7 +346,7 @@ namespace mongo { opwrite(m); if( strstr(ns, ".$cmd.sys.") ) { if( strstr(ns, "$cmd.sys.inprog") ) { - inProgCmd(m, dbresponse); + inProgCmd(txn, m, dbresponse); return; } if( strstr(ns, "$cmd.sys.killop") ) { @@ -587,7 +587,7 @@ namespace mongo { op.debug().query = query; op.setQuery(query); - UpdateRequest request(ns); + UpdateRequest request(txn, ns); request.setUpsert(upsert); request.setMulti(multi); @@ -609,7 +609,7 @@ namespace mongo { Client::Context ctx(txn, ns ); - UpdateResult res = executor.execute(txn, ctx.db()); + UpdateResult res = executor.execute(ctx.db()); // for getlasterror lastError.getSafe()->recordUpdate( res.existing , res.numMatched , res.upserted ); @@ -635,7 +635,7 @@ namespace mongo { op.debug().query = pattern; op.setQuery(pattern); - DeleteRequest request(ns); + DeleteRequest request(txn, ns); request.setQuery(pattern); request.setMulti(!justOne); request.setUpdateOpLog(true); @@ -650,7 +650,7 @@ namespace mongo { Client::Context ctx(txn, ns); - long long n = executor.execute(txn, ctx.db()); + long long n = executor.execute(ctx.db()); lastError.getSafe()->recordDelete( n ); op.debug().ndeleted = n; wunit.commit(); diff --git a/src/mongo/db/matcher/expression_parser.h b/src/mongo/db/matcher/expression_parser.h index b463d84f64a..0ba4013aa80 100644 --- a/src/mongo/db/matcher/expression_parser.h +++ b/src/mongo/db/matcher/expression_parser.h @@ -39,6 +39,8 @@ namespace mongo { + class OperationContext; + typedef StatusWith<MatchExpression*> StatusWithMatchExpression; class MatchExpressionParser { @@ -174,11 +176,19 @@ namespace mongo { */ class WhereCallbackReal : public MatchExpressionParser::WhereCallback { public: - WhereCallbackReal(const StringData& dbName); + + /** + * The OperationContext passed here is not owned, but just referenced. It gets assigned to + * any $where parsers, which this callback generates. Therefore, the op context must only + * be destroyed after these parsers and their clones (shallowClone) have been destroyed. + */ + WhereCallbackReal(OperationContext* txn, const StringData& dbName); virtual StatusWithMatchExpression parseWhere(const BSONElement& where) const; private: + // + OperationContext* _txn; const StringData _dbName; }; diff --git a/src/mongo/db/matcher/expression_where.cpp b/src/mongo/db/matcher/expression_where.cpp index 909c648063c..cef554357dc 100644 --- a/src/mongo/db/matcher/expression_where.cpp +++ b/src/mongo/db/matcher/expression_where.cpp @@ -43,7 +43,15 @@ namespace mongo { class WhereMatchExpression : public MatchExpression { public: - WhereMatchExpression() : MatchExpression( WHERE ){ _func = 0; } + WhereMatchExpression(OperationContext* txn) + : MatchExpression(WHERE), + _txn(txn) { + + invariant(_txn != NULL); + + _func = 0; + } + virtual ~WhereMatchExpression(){} Status init(const StringData& dbName, const StringData& theCode, const BSONObj& scope); @@ -55,9 +63,9 @@ namespace mongo { } virtual MatchExpression* shallowClone() const { - WhereMatchExpression* e = new WhereMatchExpression(); + WhereMatchExpression* e = new WhereMatchExpression(_txn); e->init(_dbName, _code, _userScope); - if ( getTag() ) { + if (getTag()) { e->setTag(getTag()->clone()); } return e; @@ -72,12 +80,16 @@ namespace mongo { virtual void resetTag() { setTag(NULL); } private: + string _dbName; string _code; BSONObj _userScope; auto_ptr<Scope> _scope; ScriptingFunction _func; + + // Not owned. See comments insde WhereCallbackReal for the lifetime of this pointer. + OperationContext* _txn; }; Status WhereMatchExpression::init( const StringData& dbName, @@ -98,6 +110,7 @@ namespace mongo { const string userToken = ClientBasic::getCurrent()->getAuthorizationSession() ->getAuthenticatedUserNamesToken(); + _scope = globalScriptEngine->getPooledScope(_dbName, "where" + userToken); _func = _scope->createFunction( _code.c_str() ); @@ -159,8 +172,9 @@ namespace mongo { _userScope == realOther->_userScope; } - WhereCallbackReal::WhereCallbackReal(const StringData& dbName) - : _dbName(dbName) { + WhereCallbackReal::WhereCallbackReal(OperationContext* txn, const StringData& dbName) + : _txn(txn), + _dbName(dbName) { } @@ -169,7 +183,7 @@ namespace mongo { return StatusWithMatchExpression(ErrorCodes::BadValue, "no globalScriptEngine in $where parsing"); - auto_ptr<WhereMatchExpression> exp(new WhereMatchExpression()); + auto_ptr<WhereMatchExpression> exp(new WhereMatchExpression(_txn)); if (where.type() == String || where.type() == Code) { Status s = exp->init(_dbName, where.valuestr(), BSONObj()); if (!s.isOK()) diff --git a/src/mongo/db/ops/delete.cpp b/src/mongo/db/ops/delete.cpp index c78ca1692f1..38b1b2aefe3 100644 --- a/src/mongo/db/ops/delete.cpp +++ b/src/mongo/db/ops/delete.cpp @@ -46,13 +46,13 @@ namespace mongo { bool logop, bool god) { NamespaceString nsString(ns); - DeleteRequest request(nsString); + DeleteRequest request(txn, nsString); request.setQuery(pattern); request.setMulti(!justOne); request.setUpdateOpLog(logop); request.setGod(god); DeleteExecutor executor(&request); - return executor.execute(txn, db); + return executor.execute(db); } } // namespace mongo diff --git a/src/mongo/db/ops/delete_executor.cpp b/src/mongo/db/ops/delete_executor.cpp index e7eb2a9546c..d2c36f3ba3c 100644 --- a/src/mongo/db/ops/delete_executor.cpp +++ b/src/mongo/db/ops/delete_executor.cpp @@ -66,7 +66,8 @@ namespace mongo { } CanonicalQuery* cqRaw; - const WhereCallbackReal whereCallback(_request->getNamespaceString().db()); + const WhereCallbackReal whereCallback( + _request->getOpCtx(), _request->getNamespaceString().db()); Status status = CanonicalQuery::canonicalize(_request->getNamespaceString().ns(), _request->getQuery(), @@ -80,7 +81,7 @@ namespace mongo { return status; } - long long DeleteExecutor::execute(OperationContext* txn, Database* db) { + long long DeleteExecutor::execute(Database* db) { uassertStatusOK(prepare()); uassert(17417, mongoutils::str::stream() << @@ -100,7 +101,7 @@ namespace mongo { } } - Collection* collection = db->getCollection(txn, ns.ns()); + Collection* collection = db->getCollection(_request->getOpCtx(), ns.ns()); if (NULL == collection) { return 0; } @@ -118,11 +119,14 @@ namespace mongo { Runner* rawRunner; if (_canonicalQuery.get()) { - uassertStatusOK(getRunner(txn, collection, _canonicalQuery.release(), &rawRunner)); + uassertStatusOK(getRunner(_request->getOpCtx(), + collection, + _canonicalQuery.release(), + &rawRunner)); } else { CanonicalQuery* ignored; - uassertStatusOK(getRunner(txn, + uassertStatusOK(getRunner(_request->getOpCtx(), collection, ns.ns(), _request->getQuery(), @@ -135,7 +139,7 @@ namespace mongo { DiskLoc rloc; Runner::RunnerState state; - CurOp* curOp = txn->getCurOp(); + CurOp* curOp = _request->getOpCtx()->getCurOp(); int oldYieldCount = curOp->numYields(); while (Runner::RUNNER_ADVANCED == (state = runner->getNext(NULL, &rloc))) { if (oldYieldCount != curOp->numYields()) { @@ -151,8 +155,9 @@ namespace mongo { // TODO: do we want to buffer docs and delete them in a group rather than // saving/restoring state repeatedly? runner->saveState(); - collection->deleteDocument(txn, rloc, false, false, logop ? &toDelete : NULL ); - runner->restoreState(txn); + collection->deleteDocument( + _request->getOpCtx(), rloc, false, false, logop ? &toDelete : NULL); + runner->restoreState(_request->getOpCtx()); nDeleted++; @@ -163,7 +168,8 @@ namespace mongo { } else { bool replJustOne = true; - repl::logOp(txn, "d", ns.ns().c_str(), toDelete, 0, &replJustOne); + repl::logOp( + _request->getOpCtx(), "d", ns.ns().c_str(), toDelete, 0, &replJustOne); } } @@ -172,7 +178,7 @@ namespace mongo { } if (!_request->isGod()) { - txn->recoveryUnit()->commitIfNeeded(); + _request->getOpCtx()->recoveryUnit()->commitIfNeeded(); } if (debug && _request->isGod() && nDeleted == 100) { diff --git a/src/mongo/db/ops/delete_executor.h b/src/mongo/db/ops/delete_executor.h index 475df92a105..c0324b14901 100644 --- a/src/mongo/db/ops/delete_executor.h +++ b/src/mongo/db/ops/delete_executor.h @@ -92,7 +92,7 @@ namespace mongo { * * Returns the number of documents deleted. */ - long long execute(OperationContext* txn, Database* db); + long long execute(Database* db); private: /// Unowned pointer to the request object that this executor will process. diff --git a/src/mongo/db/ops/delete_request.h b/src/mongo/db/ops/delete_request.h index 4e10cb409c2..3ce0a0bb9fd 100644 --- a/src/mongo/db/ops/delete_request.h +++ b/src/mongo/db/ops/delete_request.h @@ -39,7 +39,8 @@ namespace mongo { class DeleteRequest { MONGO_DISALLOW_COPYING(DeleteRequest); public: - explicit DeleteRequest(const NamespaceString& nsString) : + explicit DeleteRequest(OperationContext* txn, const NamespaceString& nsString) : + _txn(txn), _nsString(nsString), _multi(false), _logop(false), @@ -55,10 +56,12 @@ namespace mongo { bool isMulti() const { return _multi; } bool shouldCallLogOp() const { return _logop; } bool isGod() const { return _god; } + OperationContext* getOpCtx() const { return _txn; } std::string toString() const; private: + OperationContext* _txn; const NamespaceString& _nsString; BSONObj _query; bool _multi; diff --git a/src/mongo/db/ops/update.cpp b/src/mongo/db/ops/update.cpp index 53e67a9baf9..f872f39a97d 100644 --- a/src/mongo/db/ops/update.cpp +++ b/src/mongo/db/ops/update.cpp @@ -421,22 +421,19 @@ namespace mongo { } } // namespace - UpdateResult update(OperationContext* txn, - Database* db, + UpdateResult update(Database* db, const UpdateRequest& request, OpDebug* opDebug) { UpdateExecutor executor(&request, opDebug); - return executor.execute(txn, db); + return executor.execute(db); } - UpdateResult update( - OperationContext* txn, - Database* db, - const UpdateRequest& request, - OpDebug* opDebug, - UpdateDriver* driver, - CanonicalQuery* cq) { + UpdateResult update(Database* db, + const UpdateRequest& request, + OpDebug* opDebug, + UpdateDriver* driver, + CanonicalQuery* cq) { LOG(3) << "processing update : " << request; @@ -444,7 +441,7 @@ namespace mongo { const NamespaceString& nsString = request.getNamespaceString(); UpdateLifecycle* lifecycle = request.getLifecycle(); - Collection* collection = db->getCollection(txn, nsString.ns()); + Collection* collection = db->getCollection(request.getOpCtx(), nsString.ns()); validateUpdate(nsString.ns().c_str(), request.getUpdates(), request.getQuery()); @@ -459,8 +456,9 @@ namespace mongo { PlanExecutor* rawExec; Status status = cq ? - getExecutor(txn, collection, cqHolder.release(), &rawExec) : - getExecutor(txn, collection, nsString.ns(), request.getQuery(), &rawExec); + getExecutor(request.getOpCtx(), collection, cqHolder.release(), &rawExec) : + getExecutor(request.getOpCtx(), collection, nsString.ns(), request.getQuery(), &rawExec); + uassert(17243, "could not get executor" + request.getQuery().toString() + "; " + causedBy(status), status.isOK()); @@ -628,7 +626,7 @@ namespace mongo { // If a set of modifiers were all no-ops, we are still 'in place', but there is // no work to do, in which case we want to consider the object unchanged. if (!damages.empty() ) { - collection->updateDocumentWithDamages( txn, loc, source, damages ); + collection->updateDocumentWithDamages(request.getOpCtx(), loc, source, damages); docWasModified = true; opDebug->fastmod = true; } @@ -647,7 +645,7 @@ namespace mongo { str::stream() << "Resulting document after update is larger than " << BSONObjMaxUserSize, newObj.objsize() <= BSONObjMaxUserSize); - StatusWith<DiskLoc> res = collection->updateDocument(txn, + StatusWith<DiskLoc> res = collection->updateDocument(request.getOpCtx(), loc, newObj, true, @@ -674,7 +672,7 @@ namespace mongo { // Call logOp if requested. if (request.shouldCallLogOp() && !logObj.isEmpty()) { BSONObj idQuery = driver->makeOplogEntryQuery(newObj, request.isMulti()); - repl::logOp(txn, "u", nsString.ns().c_str(), logObj , &idQuery, + repl::logOp(request.getOpCtx(), "u", nsString.ns().c_str(), logObj, &idQuery, NULL, request.isFromMigration()); } @@ -687,7 +685,7 @@ namespace mongo { } // Opportunity for journaling to write during the update. - txn->recoveryUnit()->commitIfNeeded(); + request.getOpCtx()->recoveryUnit()->commitIfNeeded(); } // Get summary information about the plan. @@ -775,9 +773,9 @@ namespace mongo { // Only create the collection if the doc will be inserted. if (!collection) { - collection = db->getCollection(txn, request.getNamespaceString().ns()); + collection = db->getCollection(request.getOpCtx(), request.getNamespaceString().ns()); if (!collection) { - collection = db->createCollection(txn, request.getNamespaceString().ns()); + collection = db->createCollection(request.getOpCtx(), request.getNamespaceString().ns()); } } @@ -787,13 +785,18 @@ namespace mongo { str::stream() << "Document to upsert is larger than " << BSONObjMaxUserSize, newObj.objsize() <= BSONObjMaxUserSize); - StatusWith<DiskLoc> newLoc = collection->insertDocument(txn, + StatusWith<DiskLoc> newLoc = collection->insertDocument(request.getOpCtx(), newObj, !request.isGod() /*enforceQuota*/); uassertStatusOK(newLoc.getStatus()); if (request.shouldCallLogOp()) { - repl::logOp(txn, "i", nsString.ns().c_str(), newObj, - NULL, NULL, request.isFromMigration()); + repl::logOp(request.getOpCtx(), + "i", + nsString.ns().c_str(), + newObj, + NULL, + NULL, + request.isFromMigration()); } opDebug->nMatched = 1; diff --git a/src/mongo/db/ops/update.h b/src/mongo/db/ops/update.h index f950fbaf08c..cff79a0d90b 100644 --- a/src/mongo/db/ops/update.h +++ b/src/mongo/db/ops/update.h @@ -46,8 +46,7 @@ namespace mongo { * * Caller must hold the appropriate database locks. */ - UpdateResult update(OperationContext* txn, - Database* db, + UpdateResult update(Database* db, const UpdateRequest& request, OpDebug* opDebug); @@ -59,8 +58,7 @@ namespace mongo { * * TODO: Move this into a private method of UpdateExecutor. */ - UpdateResult update(OperationContext* txn, - Database* db, + UpdateResult update(Database* db, const UpdateRequest& request, OpDebug* opDebug, UpdateDriver* driver, diff --git a/src/mongo/db/ops/update_executor.cpp b/src/mongo/db/ops/update_executor.cpp index fd2f11701a7..268e7616d3c 100644 --- a/src/mongo/db/ops/update_executor.cpp +++ b/src/mongo/db/ops/update_executor.cpp @@ -62,10 +62,9 @@ namespace mongo { return Status::OK(); } - UpdateResult UpdateExecutor::execute(OperationContext* txn, Database* db) { + UpdateResult UpdateExecutor::execute(Database* db) { uassertStatusOK(prepare()); - return update(txn, - db, + return update(db, *_request, _opDebug, &_driver, @@ -85,7 +84,8 @@ namespace mongo { } CanonicalQuery* cqRaw; - const WhereCallbackReal whereCallback(_request->getNamespaceString().db()); + const WhereCallbackReal whereCallback( + _request->getOpCtx(), _request->getNamespaceString().db()); Status status = CanonicalQuery::canonicalize(_request->getNamespaceString().ns(), _request->getQuery(), diff --git a/src/mongo/db/ops/update_executor.h b/src/mongo/db/ops/update_executor.h index 881c0cc0d36..f4a62224c59 100644 --- a/src/mongo/db/ops/update_executor.h +++ b/src/mongo/db/ops/update_executor.h @@ -91,7 +91,7 @@ namespace mongo { * Execute an update. Requires the caller to hold the database lock on the * appropriate resources for the request. */ - UpdateResult execute(OperationContext* txn, Database* db); + UpdateResult execute(Database* db); private: /** diff --git a/src/mongo/db/ops/update_request.h b/src/mongo/db/ops/update_request.h index db0dcbf1e5e..5ed6eca209a 100644 --- a/src/mongo/db/ops/update_request.h +++ b/src/mongo/db/ops/update_request.h @@ -42,8 +42,9 @@ namespace mongo { class UpdateRequest { public: - inline UpdateRequest(const NamespaceString& nsString) - : _nsString(nsString) + inline UpdateRequest(OperationContext* txn, const NamespaceString& nsString) + : _txn(txn) + , _nsString(nsString) , _god(false) , _upsert(false) , _multi(false) @@ -131,6 +132,10 @@ namespace mongo { return _lifecycle; } + inline OperationContext* getOpCtx() const { + return _txn; + } + const std::string toString() const { return str::stream() << " query: " << _query @@ -144,6 +149,9 @@ namespace mongo { } private: + // Not owned. Must live as long as the request lives. + OperationContext* _txn; + const NamespaceString& _nsString; // Contains the query that selects documents to update. diff --git a/src/mongo/db/pipeline/pipeline_d.cpp b/src/mongo/db/pipeline/pipeline_d.cpp index 1f6f93f1274..9259a2a8072 100644 --- a/src/mongo/db/pipeline/pipeline_d.cpp +++ b/src/mongo/db/pipeline/pipeline_d.cpp @@ -167,7 +167,7 @@ namespace { boost::shared_ptr<Runner> runner; bool sortInRunner = false; - const WhereCallbackReal whereCallback(pExpCtx->ns.db()); + const WhereCallbackReal whereCallback(pExpCtx->opCtx, pExpCtx->ns.db()); if (sortStage) { CanonicalQuery* cq; diff --git a/src/mongo/db/query/get_executor.cpp b/src/mongo/db/query/get_executor.cpp index f153434e3b0..4b56863eeaa 100644 --- a/src/mongo/db/query/get_executor.cpp +++ b/src/mongo/db/query/get_executor.cpp @@ -181,7 +181,7 @@ namespace mongo { if (!CanonicalQuery::isSimpleIdQuery(unparsedQuery) || !collection->getIndexCatalog()->findIdIndex()) { - const WhereCallbackReal whereCallback(collection->ns().db()); + const WhereCallbackReal whereCallback(txn, collection->ns().db()); CanonicalQuery* cq; Status status = CanonicalQuery::canonicalize( collection->ns(), unparsedQuery, &cq, whereCallback); @@ -230,7 +230,7 @@ namespace mongo { // so we don't support covered projections. However, we might use the simple inclusion // fast path. if (NULL != canonicalQuery->getProj()) { - ProjectionStageParams params(WhereCallbackReal(collection->ns().db())); + ProjectionStageParams params(WhereCallbackReal(txn, collection->ns().db())); params.projObj = canonicalQuery->getProj()->getProjObj(); // Stuff the right data into the params depending on what proj impl we use. @@ -652,7 +652,7 @@ namespace mongo { PlanExecutor** execOut) { invariant(collection); - const WhereCallbackReal whereCallback(collection->ns().db()); + const WhereCallbackReal whereCallback(txn, collection->ns().db()); CanonicalQuery* cq; uassertStatusOK(CanonicalQuery::canonicalize(collection->ns().ns(), @@ -759,7 +759,7 @@ namespace mongo { } } - const WhereCallbackReal whereCallback(collection->ns().db()); + const WhereCallbackReal whereCallback(txn, collection->ns().db()); // If there are no suitable indices for the distinct hack bail out now into regular planning // with no projection. diff --git a/src/mongo/db/query/get_runner.cpp b/src/mongo/db/query/get_runner.cpp index 429cbc15d33..e93d670a898 100644 --- a/src/mongo/db/query/get_runner.cpp +++ b/src/mongo/db/query/get_runner.cpp @@ -88,7 +88,7 @@ namespace mongo { if (!CanonicalQuery::isSimpleIdQuery(unparsedQuery) || !collection->getIndexCatalog()->findIdIndex()) { - const WhereCallbackReal whereCallback(collection->ns().db()); + const WhereCallbackReal whereCallback(txn, collection->ns().db()); Status status = CanonicalQuery::canonicalize( collection->ns(), unparsedQuery, outCanonicalQuery, whereCallback); if (!status.isOK()) @@ -516,7 +516,7 @@ namespace mongo { Runner** out) { verify(collection); - const WhereCallbackReal whereCallback(collection->ns().db()); + const WhereCallbackReal whereCallback(txn, collection->ns().db()); CanonicalQuery* cq; uassertStatusOK(CanonicalQuery::canonicalize(collection->ns().ns(), @@ -573,7 +573,7 @@ namespace mongo { } } - const WhereCallbackReal whereCallback(collection->ns().db()); + const WhereCallbackReal whereCallback(txn, collection->ns().db()); // If there are no suitable indices for the distinct hack bail out now into regular planning // with no projection. diff --git a/src/mongo/db/query/idhack_runner.cpp b/src/mongo/db/query/idhack_runner.cpp index 5382a4e4bfa..cf8f8dc78f5 100644 --- a/src/mongo/db/query/idhack_runner.cpp +++ b/src/mongo/db/query/idhack_runner.cpp @@ -174,7 +174,7 @@ namespace mongo { BSONObj projectedObj; ProjectionExec projExec(projObj, _query->root(), - WhereCallbackReal(_collection->ns().db())); + WhereCallbackReal(_txn, _collection->ns().db())); projExec.transform(docObj, &projectedObj); return projectedObj; } diff --git a/src/mongo/db/query/new_find.cpp b/src/mongo/db/query/new_find.cpp index 09ab4104d15..3cc4a035a6e 100644 --- a/src/mongo/db/query/new_find.cpp +++ b/src/mongo/db/query/new_find.cpp @@ -496,7 +496,7 @@ namespace mongo { // Parse the qm into a CanonicalQuery. CanonicalQuery* cq; Status canonStatus = CanonicalQuery::canonicalize( - q, &cq, WhereCallbackReal(StringData(ctx.ctx().db()->name()))); + q, &cq, WhereCallbackReal(txn, StringData(ctx.ctx().db()->name()))); if (!canonStatus.isOK()) { uasserted(17287, str::stream() << "Can't canonicalize query: " << canonStatus.toString()); } diff --git a/src/mongo/db/query/stage_builder.cpp b/src/mongo/db/query/stage_builder.cpp index b0441eb0a25..bec04c13fba 100644 --- a/src/mongo/db/query/stage_builder.cpp +++ b/src/mongo/db/query/stage_builder.cpp @@ -113,7 +113,7 @@ namespace mongo { PlanStage* childStage = buildStages(txn, collection, qsol, pn->children[0], ws); if (NULL == childStage) { return NULL; } - ProjectionStageParams params(WhereCallbackReal(collection->ns().db())); + ProjectionStageParams params(WhereCallbackReal(txn, collection->ns().db())); params.projObj = pn->projection; // Stuff the right data into the params depending on what proj impl we use. diff --git a/src/mongo/db/query/subplan_runner.cpp b/src/mongo/db/query/subplan_runner.cpp index c107f829c77..4682c29b2b4 100644 --- a/src/mongo/db/query/subplan_runner.cpp +++ b/src/mongo/db/query/subplan_runner.cpp @@ -203,7 +203,7 @@ namespace mongo { QLOG() << "Subplanner: index " << i << " is " << ie.toString() << endl; } - const WhereCallbackReal whereCallback(_collection->ns().db()); + const WhereCallbackReal whereCallback(_txn, _collection->ns().db()); for (size_t i = 0; i < theOr->numChildren(); ++i) { // Turn the i-th child into its own query. diff --git a/src/mongo/db/repl/master_slave.cpp b/src/mongo/db/repl/master_slave.cpp index 0e216cdd05b..5e591b41f4f 100644 --- a/src/mongo/db/repl/master_slave.cpp +++ b/src/mongo/db/repl/master_slave.cpp @@ -207,13 +207,13 @@ namespace repl { Client::Context ctx(txn, "local.sources"); const NamespaceString requestNs("local.sources"); - UpdateRequest request(requestNs); + UpdateRequest request(txn, requestNs); request.setQuery(pattern); request.setUpdates(o); request.setUpsert(); - UpdateResult res = update(txn, ctx.db(), request, &debug); + UpdateResult res = update(ctx.db(), request, &debug); verify( ! res.modifiers ); verify( res.numMatched == 1 ); diff --git a/src/mongo/db/repl/oplog.cpp b/src/mongo/db/repl/oplog.cpp index e911c19a852..36d7d7810da 100644 --- a/src/mongo/db/repl/oplog.cpp +++ b/src/mongo/db/repl/oplog.cpp @@ -619,7 +619,7 @@ namespace repl { Timer t; const NamespaceString requestNs(ns); - UpdateRequest request(requestNs); + UpdateRequest request(txn, requestNs); request.setQuery(o); request.setUpdates(o); @@ -628,7 +628,7 @@ namespace repl { UpdateLifecycleImpl updateLifecycle(true, requestNs); request.setLifecycle(&updateLifecycle); - update(txn, db, request, &debug); + update(db, request, &debug); if( t.millis() >= 2 ) { RARELY OCCASIONALLY log() << "warning, repl doing slow updates (no _id field) for " << ns << endl; @@ -648,7 +648,7 @@ namespace repl { b.append(_id); const NamespaceString requestNs(ns); - UpdateRequest request(requestNs); + UpdateRequest request(txn, requestNs); request.setQuery(b.done()); request.setUpdates(o); @@ -657,7 +657,7 @@ namespace repl { UpdateLifecycleImpl updateLifecycle(true, requestNs); request.setLifecycle(&updateLifecycle); - update(txn, db, request, &debug); + update(db, request, &debug); } } } @@ -675,7 +675,7 @@ namespace repl { const bool upsert = valueB || convertUpdateToUpsert; const NamespaceString requestNs(ns); - UpdateRequest request(requestNs); + UpdateRequest request(txn, requestNs); request.setQuery(updateCriteria); request.setUpdates(o); @@ -684,7 +684,7 @@ namespace repl { UpdateLifecycleImpl updateLifecycle(true, requestNs); request.setLifecycle(&updateLifecycle); - UpdateResult ur = update(txn, db, request, &debug); + UpdateResult ur = update(db, request, &debug); if( ur.numMatched == 0 ) { if( ur.modifiers ) { diff --git a/src/mongo/db/repl/rs_rollback.cpp b/src/mongo/db/repl/rs_rollback.cpp index 445183fc5c9..b65dbb324bb 100644 --- a/src/mongo/db/repl/rs_rollback.cpp +++ b/src/mongo/db/repl/rs_rollback.cpp @@ -632,7 +632,7 @@ namespace repl { updates++; const NamespaceString requestNs(doc.ns); - UpdateRequest request(requestNs); + UpdateRequest request(txn, requestNs); request.setQuery(pattern); request.setUpdates(it->second); @@ -641,7 +641,7 @@ namespace repl { UpdateLifecycleImpl updateLifecycle(true, requestNs); request.setLifecycle(&updateLifecycle); - update(txn, ctx.db(), request, &debug); + update(ctx.db(), request, &debug); } } diff --git a/src/mongo/dbtests/matchertests.cpp b/src/mongo/dbtests/matchertests.cpp index cee3995395c..efe21b9cb88 100644 --- a/src/mongo/dbtests/matchertests.cpp +++ b/src/mongo/dbtests/matchertests.cpp @@ -222,7 +222,7 @@ namespace MatcherTests { Client::ReadContext ctx(&txn, "unittests.matchertests"); M m(BSON("$where" << "function(){ return this.a == 1; }"), - WhereCallbackReal(StringData("unittests"))); + WhereCallbackReal(&txn, StringData("unittests"))); ASSERT( m.matches( BSON( "a" << 1 ) ) ); ASSERT( !m.matches( BSON( "a" << 2 ) ) ); } |