diff options
146 files changed, 1398 insertions, 1012 deletions
diff --git a/src/mongo/db/catalog/collection.cpp b/src/mongo/db/catalog/collection.cpp index f21a00abfc6..37d5ae84104 100644 --- a/src/mongo/db/catalog/collection.cpp +++ b/src/mongo/db/catalog/collection.cpp @@ -1,7 +1,7 @@ // collection.cpp /** -* Copyright (C) 2013 10gen Inc. +* Copyright (C) 2013-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, @@ -122,20 +122,23 @@ namespace mongo { return true; } - RecordIterator* Collection::getIterator( const DiskLoc& start, bool tailable, - const CollectionScanParams::Direction& dir) const { + RecordIterator* Collection::getIterator( OperationContext* txn, + const DiskLoc& start, + bool tailable, + const CollectionScanParams::Direction& dir) const { invariant( ok() ); - return _recordStore->getIterator( start, tailable, dir ); + return _recordStore->getIterator( txn, start, tailable, dir ); } - vector<RecordIterator*> Collection::getManyIterators() const { - return _recordStore->getManyIterators(); + vector<RecordIterator*> Collection::getManyIterators( OperationContext* txn ) const { + return _recordStore->getManyIterators(txn); } - int64_t Collection::countTableScan( const MatchExpression* expression ) { - scoped_ptr<RecordIterator> iterator( getIterator( DiskLoc(), - false, - CollectionScanParams::FORWARD ) ); + int64_t Collection::countTableScan( OperationContext* txn, const MatchExpression* expression ) { + scoped_ptr<RecordIterator> iterator( getIterator( txn, + DiskLoc(), + false, + CollectionScanParams::FORWARD ) ); int64_t count = 0; while ( !iterator->isEOF() ) { DiskLoc loc = iterator->getNext(); @@ -178,7 +181,7 @@ namespace mongo { if ( isCapped() ) { // TOOD: old god not done - Status ret = _indexCatalog.checkNoIndexConflicts( docToInsert ); + Status ret = _indexCatalog.checkNoIndexConflicts( txn, docToInsert ); if ( !ret.isOK() ) return StatusWith<DiskLoc>( ret ); } @@ -332,7 +335,7 @@ namespace mongo { || repl::getGlobalReplicationCoordinator()->shouldIgnoreUniqueIndex(descriptor); UpdateTicket* updateTicket = new UpdateTicket(); updateTickets.mutableMap()[descriptor] = updateTicket; - Status ret = iam->validateUpdate(objOld, objNew, oldLocation, options, updateTicket ); + Status ret = iam->validateUpdate(txn, objOld, objNew, oldLocation, options, updateTicket ); if ( !ret.isOK() ) { return StatusWith<DiskLoc>( ret ); } @@ -527,7 +530,7 @@ namespace mongo { invariant( iam ); int64_t keys; - iam->validate(&keys); + iam->validate(txn, &keys); indexes.appendNumber(descriptor->indexNamespace(), static_cast<long long>(keys)); idxn++; diff --git a/src/mongo/db/catalog/collection.h b/src/mongo/db/catalog/collection.h index 6ddf8bd9cf4..dea27fdc77b 100644 --- a/src/mongo/db/catalog/collection.h +++ b/src/mongo/db/catalog/collection.h @@ -1,7 +1,7 @@ // collection.h /** -* Copyright (C) 2012 10gen Inc. +* Copyright (C) 2012-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, @@ -137,7 +137,8 @@ namespace mongo { * canonical to get all would be * getIterator( DiskLoc(), false, CollectionScanParams::FORWARD ) */ - RecordIterator* getIterator( const DiskLoc& start = DiskLoc(), + RecordIterator* getIterator( OperationContext* txn, + const DiskLoc& start = DiskLoc(), bool tailable = false, const CollectionScanParams::Direction& dir = CollectionScanParams::FORWARD ) const; @@ -146,7 +147,7 @@ namespace mongo { * all returned iterators is equivalent to Iterating the full collection. * Caller owns all pointers in the vector. */ - std::vector<RecordIterator*> getManyIterators() const; + std::vector<RecordIterator*> getManyIterators( OperationContext* txn ) const; /** @@ -154,7 +155,7 @@ namespace mongo { * this should only be used at a very low level * does no yielding, indexes, etc... */ - int64_t countTableScan( const MatchExpression* expression ); + int64_t countTableScan( OperationContext* txn, const MatchExpression* expression ); void deleteDocument( OperationContext* txn, const DiskLoc& loc, diff --git a/src/mongo/db/catalog/collection_catalog_entry.h b/src/mongo/db/catalog/collection_catalog_entry.h index 28d2def59ff..1b0175b59c8 100644 --- a/src/mongo/db/catalog/collection_catalog_entry.h +++ b/src/mongo/db/catalog/collection_catalog_entry.h @@ -51,7 +51,7 @@ namespace mongo { // ------- indexes ---------- - virtual CollectionOptions getCollectionOptions() const = 0; + virtual CollectionOptions getCollectionOptions( OperationContext* txn ) const = 0; virtual int getTotalIndexCount() const = 0; diff --git a/src/mongo/db/catalog/database.cpp b/src/mongo/db/catalog/database.cpp index cbfd70a1502..e9ff8027e50 100644 --- a/src/mongo/db/catalog/database.cpp +++ b/src/mongo/db/catalog/database.cpp @@ -1,7 +1,7 @@ // database.cpp /** -* Copyright (C) 2008 10gen Inc. +* Copyright (C) 2008-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, @@ -172,7 +172,7 @@ namespace mongo { CollectionCatalogEntry* coll = _dbEntry->getCollectionCatalogEntry( txn, ns ); - CollectionOptions options = coll->getCollectionOptions(); + CollectionOptions options = coll->getCollectionOptions( txn ); if ( !options.temp ) continue; @@ -267,7 +267,7 @@ namespace mongo { size += collection->dataSize(); BSONObjBuilder temp; - storageSize += collection->getRecordStore()->storageSize( &temp ); + storageSize += collection->getRecordStore()->storageSize( opCtx, &temp ); numExtents += temp.obj()["numExtents"].numberInt(); // XXX indexes += collection->getIndexCatalog()->numIndexesTotal(); diff --git a/src/mongo/db/catalog/index_catalog.cpp b/src/mongo/db/catalog/index_catalog.cpp index 840d0042872..52df950c274 100644 --- a/src/mongo/db/catalog/index_catalog.cpp +++ b/src/mongo/db/catalog/index_catalog.cpp @@ -1,7 +1,7 @@ // index_catalog.cpp /** -* Copyright (C) 2013 10gen Inc. +* Copyright (C) 2013-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, @@ -222,7 +222,8 @@ namespace mongo { } auto_ptr<Runner> runner( - InternalPlanner::collectionScan(db->_indexesName, + InternalPlanner::collectionScan(txn, + db->_indexesName, db->getCollection(txn, db->_indexesName))); BSONObj index; @@ -691,7 +692,7 @@ namespace mongo { EqualityMatchExpression expr; BSONObj nsBSON = BSON( "ns" << _collection->ns() ); invariant( expr.init( "ns", nsBSON.firstElement() ).isOK() ); - numSystemIndexesEntries = systemIndexes->countTableScan( &expr ); + numSystemIndexesEntries = systemIndexes->countTableScan( txn, &expr ); } else { // this is ok, 0 is the right number @@ -1078,7 +1079,7 @@ namespace mongo { } } - Status IndexCatalog::checkNoIndexConflicts( const BSONObj &obj ) { + Status IndexCatalog::checkNoIndexConflicts( OperationContext* txn, const BSONObj &obj ) { IndexIterator ii = getIndexIterator( true ); while ( ii.more() ) { IndexDescriptor* descriptor = ii.next(); @@ -1096,7 +1097,7 @@ namespace mongo { options.dupsAllowed = false; UpdateTicket ticket; - Status ret = iam->validateUpdate(BSONObj(), obj, DiskLoc(), options, &ticket); + Status ret = iam->validateUpdate(txn, BSONObj(), obj, DiskLoc(), options, &ticket); if ( !ret.isOK() ) return ret; } diff --git a/src/mongo/db/catalog/index_catalog.h b/src/mongo/db/catalog/index_catalog.h index d4f3edcb281..9d509b9ebbe 100644 --- a/src/mongo/db/catalog/index_catalog.h +++ b/src/mongo/db/catalog/index_catalog.h @@ -1,7 +1,7 @@ // index_catalog.h /** -* Copyright (C) 2013 10gen Inc. +* Copyright (C) 2013-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, @@ -247,7 +247,7 @@ namespace mongo { * checks all unique indexes and checks for conflicts * should not throw */ - Status checkNoIndexConflicts( const BSONObj& obj ); + Status checkNoIndexConflicts( OperationContext* txn, const BSONObj& obj ); // ------- temp internal ------- diff --git a/src/mongo/db/catalog/index_create.cpp b/src/mongo/db/catalog/index_create.cpp index 176939669c4..b230121d533 100644 --- a/src/mongo/db/catalog/index_create.cpp +++ b/src/mongo/db/catalog/index_create.cpp @@ -1,7 +1,7 @@ // index_create.cpp /** -* Copyright (C) 2008 10gen Inc. +* Copyright (C) 2008-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, @@ -104,7 +104,7 @@ namespace mongo { unsigned long long n = 0; unsigned long long numDropped = 0; - auto_ptr<Runner> runner(InternalPlanner::collectionScan(ns,collection)); + auto_ptr<Runner> runner(InternalPlanner::collectionScan(txn,ns,collection)); std::string idxName = descriptor->indexName(); diff --git a/src/mongo/db/commands/collection_to_capped.cpp b/src/mongo/db/commands/collection_to_capped.cpp index e7859976de0..d2dbf60e565 100644 --- a/src/mongo/db/commands/collection_to_capped.cpp +++ b/src/mongo/db/commands/collection_to_capped.cpp @@ -1,7 +1,7 @@ // collection_to_capped.cpp /** -* Copyright (C) 2013 10gen Inc. +* Copyright (C) 2013-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, @@ -81,9 +81,10 @@ namespace mongo { // datasize and extentSize can't be compared exactly, so add some padding to 'size' long long excessSize = static_cast<long long>( fromCollection->dataSize() - - ( toCollection->getRecordStore()->storageSize() * 2 ) ); + ( toCollection->getRecordStore()->storageSize( txn ) * 2 ) ); - scoped_ptr<Runner> runner( InternalPlanner::collectionScan(fromNs, + scoped_ptr<Runner> runner( InternalPlanner::collectionScan(txn, + fromNs, fromCollection, InternalPlanner::FORWARD ) ); diff --git a/src/mongo/db/commands/count.cpp b/src/mongo/db/commands/count.cpp index aa43882ea78..9c901e71025 100644 --- a/src/mongo/db/commands/count.cpp +++ b/src/mongo/db/commands/count.cpp @@ -98,7 +98,7 @@ namespace mongo { limit = -limit; } - uassertStatusOK(getRunnerCount(collection, query, hintObj, &rawRunner)); + uassertStatusOK(getRunnerCount(txn, collection, query, hintObj, &rawRunner)); auto_ptr<Runner> runner(rawRunner); // Store the plan summary string in CurOp. @@ -177,7 +177,7 @@ namespace mongo { // Get an executor for the command and use it to generate the explain output. CanonicalQuery* rawCq; PlanExecutor* rawExec; - Status execStatus = parseCountToExecutor(cmdObj, dbname, ns, collection, + Status execStatus = parseCountToExecutor(txn, cmdObj, dbname, ns, collection, &rawCq, &rawExec); if (!execStatus.isOK()) { return execStatus; @@ -189,7 +189,8 @@ namespace mongo { return Explain::explainStages(exec.get(), cq.get(), verbosity, out); } - Status CmdCount::parseCountToExecutor(const BSONObj& cmdObj, + Status CmdCount::parseCountToExecutor(OperationContext* txn, + const BSONObj& cmdObj, const std::string& dbname, const std::string& ns, Collection* collection, @@ -229,7 +230,7 @@ namespace mongo { auto_ptr<CanonicalQuery> autoCq(cq); - Status execStat = getExecutor(collection, cq, execOut, + Status execStat = getExecutor(txn, collection, cq, execOut, QueryPlannerParams::PRIVATE_IS_COUNT); if (!execStat.isOK()) { return execStat; diff --git a/src/mongo/db/commands/count.h b/src/mongo/db/commands/count.h index eeaaac204f1..f6dcc19c535 100644 --- a/src/mongo/db/commands/count.h +++ b/src/mongo/db/commands/count.h @@ -98,7 +98,8 @@ namespace mongo { * TODO: the regular run() command for count should call this instead of getting * a runner. */ - Status parseCountToExecutor(const BSONObj& cmdObj, + Status parseCountToExecutor(OperationContext* txn, + const BSONObj& cmdObj, const std::string& dbname, const std::string& ns, Collection* collection, diff --git a/src/mongo/db/commands/dbhash.cpp b/src/mongo/db/commands/dbhash.cpp index 9b4a2a385aa..47405dd9888 100644 --- a/src/mongo/db/commands/dbhash.cpp +++ b/src/mongo/db/commands/dbhash.cpp @@ -1,7 +1,7 @@ // dbhash.cpp /** -* Copyright (C) 2013 10gen Inc. +* Copyright (C) 2013-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, @@ -84,7 +84,8 @@ namespace mongo { auto_ptr<Runner> runner; if ( desc ) { - runner.reset(InternalPlanner::indexScan(collection, + runner.reset(InternalPlanner::indexScan(opCtx, + collection, desc, BSONObj(), BSONObj(), @@ -93,7 +94,8 @@ namespace mongo { InternalPlanner::IXSCAN_FETCH)); } else if ( collection->isCapped() ) { - runner.reset(InternalPlanner::collectionScan(fullCollectionName, + runner.reset(InternalPlanner::collectionScan(opCtx, + fullCollectionName, collection)); } else { diff --git a/src/mongo/db/commands/distinct.cpp b/src/mongo/db/commands/distinct.cpp index 9e35ef3b0c7..ce582933d7a 100644 --- a/src/mongo/db/commands/distinct.cpp +++ b/src/mongo/db/commands/distinct.cpp @@ -1,7 +1,7 @@ // distinct.cpp /** -* Copyright (C) 2012 10gen Inc. +* Copyright (C) 2012-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, @@ -115,7 +115,7 @@ namespace mongo { } Runner* rawRunner; - Status status = getRunnerDistinct(collection, query, key, &rawRunner); + Status status = getRunnerDistinct(txn, collection, query, key, &rawRunner); if (!status.isOK()) { uasserted(17216, mongoutils::str::stream() << "Can't get runner for query " << query << ": " << status.toString()); diff --git a/src/mongo/db/commands/find_and_modify.cpp b/src/mongo/db/commands/find_and_modify.cpp index 125826760a0..f242327f935 100644 --- a/src/mongo/db/commands/find_and_modify.cpp +++ b/src/mongo/db/commands/find_and_modify.cpp @@ -1,7 +1,7 @@ // find_and_modify.cpp /** -* Copyright (C) 2012 10gen Inc. +* Copyright (C) 2012-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, @@ -153,7 +153,7 @@ namespace mongo { Runner* rawRunner; massert(17384, "Could not get runner for query " + queryOriginal.toString(), - getRunner(collection, cq, &rawRunner, QueryPlannerParams::DEFAULT).isOK()); + getRunner(txn, collection, cq, &rawRunner, QueryPlannerParams::DEFAULT).isOK()); auto_ptr<Runner> runner(rawRunner); diff --git a/src/mongo/db/commands/geonear.cpp b/src/mongo/db/commands/geonear.cpp index bbcc5ab19f5..f994004e2b2 100644 --- a/src/mongo/db/commands/geonear.cpp +++ b/src/mongo/db/commands/geonear.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2012 10gen Inc. +* Copyright (C) 2012-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, @@ -187,7 +187,7 @@ namespace mongo { } Runner* rawRunner; - if (!getRunner(collection, cq, &rawRunner, 0).isOK()) { + if (!getRunner(txn, collection, cq, &rawRunner, 0).isOK()) { errmsg = "can't get query runner"; return false; } diff --git a/src/mongo/db/commands/group.cpp b/src/mongo/db/commands/group.cpp index b65f4f85fcd..519a5989dd1 100644 --- a/src/mongo/db/commands/group.cpp +++ b/src/mongo/db/commands/group.cpp @@ -1,7 +1,7 @@ // group.cpp /** -* Copyright (C) 2012 10gen Inc. +* Copyright (C) 2012-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, @@ -147,7 +147,7 @@ namespace mongo { } Runner* rawRunner; - if (!getRunner(collection, cq, &rawRunner).isOK()) { + if (!getRunner(txn,collection, cq, &rawRunner).isOK()) { uasserted(17213, "Can't get runner for query " + query.toString()); return 0; } diff --git a/src/mongo/db/commands/list_collections.cpp b/src/mongo/db/commands/list_collections.cpp index 46667c1a319..f7c32549627 100644 --- a/src/mongo/db/commands/list_collections.cpp +++ b/src/mongo/db/commands/list_collections.cpp @@ -1,7 +1,7 @@ // list_collections.cpp /** -* Copyright (C) 2014 10gen Inc. +* 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, @@ -83,7 +83,7 @@ namespace mongo { b.append( "name", nsToCollectionSubstring( ns ) ); CollectionOptions options = - dbEntry->getCollectionCatalogEntry( txn, ns )->getCollectionOptions(); + dbEntry->getCollectionCatalogEntry( txn, ns )->getCollectionOptions(txn); b.append( "options", options.toBSON() ); arr.append( b.obj() ); diff --git a/src/mongo/db/commands/mr.cpp b/src/mongo/db/commands/mr.cpp index a55597b58b2..b319dbd9e8a 100644 --- a/src/mongo/db/commands/mr.cpp +++ b/src/mongo/db/commands/mr.cpp @@ -981,7 +981,7 @@ namespace mongo { whereCallback).isOK()); Runner* rawRunner; - verify(getRunner(ctx->ctx().db()->getCollection(_txn, _config.incLong), + verify(getRunner(_txn, ctx->ctx().db()->getCollection(_txn, _config.incLong), cq, &rawRunner, QueryPlannerParams::NO_TABLE_SCAN).isOK()); auto_ptr<Runner> runner(rawRunner); @@ -1324,7 +1324,7 @@ namespace mongo { } Runner* rawRunner; - if (!getRunner(ctx->db()->getCollection(txn, config.ns), cq, &rawRunner).isOK()) { + if (!getRunner(txn, ctx->db()->getCollection(txn, config.ns), cq, &rawRunner).isOK()) { uasserted(17239, "Can't get runner for query " + config.filter.toString()); return 0; } diff --git a/src/mongo/db/commands/parallel_collection_scan.cpp b/src/mongo/db/commands/parallel_collection_scan.cpp index 4f41daa71f1..c10cf053534 100644 --- a/src/mongo/db/commands/parallel_collection_scan.cpp +++ b/src/mongo/db/commands/parallel_collection_scan.cpp @@ -185,7 +185,7 @@ namespace mongo { "numCursors has to be between 1 and 10000" << " was: " << numCursors ) ); - OwnedPointerVector<RecordIterator> iterators(collection->getManyIterators()); + OwnedPointerVector<RecordIterator> iterators(collection->getManyIterators(txn)); if (iterators.size() < numCursors) { numCursors = iterators.size(); diff --git a/src/mongo/db/commands/pipeline_command.cpp b/src/mongo/db/commands/pipeline_command.cpp index 6e5232d4c12..5033dd05da7 100644 --- a/src/mongo/db/commands/pipeline_command.cpp +++ b/src/mongo/db/commands/pipeline_command.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2011 10gen Inc. + * Copyright (c) 2011-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, @@ -324,7 +324,8 @@ namespace { // This does mongod-specific stuff like creating the input Runner and adding to the // front of the pipeline if needed. - boost::shared_ptr<Runner> input = PipelineD::prepareCursorSource(collection, + boost::shared_ptr<Runner> input = PipelineD::prepareCursorSource(txn, + collection, pPipeline, pCtx); pPipeline->stitch(); diff --git a/src/mongo/db/commands/rename_collection.cpp b/src/mongo/db/commands/rename_collection.cpp index a878e8222f1..904041aa648 100644 --- a/src/mongo/db/commands/rename_collection.cpp +++ b/src/mongo/db/commands/rename_collection.cpp @@ -1,7 +1,7 @@ // rename_collection.cpp /** -* Copyright (C) 2013 10gen Inc. +* Copyright (C) 2013-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, @@ -181,7 +181,7 @@ namespace mongo { indexesInProg = stopIndexBuilds( txn, srcCtx.db(), cmdObj ); capped = sourceColl->isCapped(); if ( capped ) { - size = sourceColl->getRecordStore()->storageSize(); + size = sourceColl->getRecordStore()->storageSize( txn ); } } } @@ -252,7 +252,7 @@ namespace mongo { { Client::Context srcCtx(txn, source); sourceColl = srcCtx.db()->getCollection( txn, source ); - sourceIt.reset( sourceColl->getIterator( DiskLoc(), false, CollectionScanParams::FORWARD ) ); + sourceIt.reset( sourceColl->getIterator( txn, DiskLoc(), false, CollectionScanParams::FORWARD ) ); } Collection* targetColl = NULL; diff --git a/src/mongo/db/commands/test_commands.cpp b/src/mongo/db/commands/test_commands.cpp index 8f7e91d04f0..9036445a88b 100644 --- a/src/mongo/db/commands/test_commands.cpp +++ b/src/mongo/db/commands/test_commands.cpp @@ -1,7 +1,7 @@ // test_commands.cpp /** -* Copyright (C) 2013 10gen Inc. +* Copyright (C) 2013-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, @@ -150,7 +150,8 @@ namespace mongo { Collection* collection = ctx.ctx().db()->getCollection( txn, nss.ns() ); massert( 13417, "captrunc collection not found or empty", collection); - boost::scoped_ptr<Runner> runner(InternalPlanner::collectionScan(nss.ns(), + boost::scoped_ptr<Runner> runner(InternalPlanner::collectionScan(txn, + nss.ns(), collection, InternalPlanner::BACKWARD)); DiskLoc end; diff --git a/src/mongo/db/concurrency/SConscript b/src/mongo/db/concurrency/SConscript index f032e337bd2..97507d58197 100644 --- a/src/mongo/db/concurrency/SConscript +++ b/src/mongo/db/concurrency/SConscript @@ -10,7 +10,8 @@ env.Library( LIBDEPS=[ '$BUILD_DIR/mongo/base/base', '$BUILD_DIR/third_party/shim_boost', - '$BUILD_DIR/mongo/foundation' + '$BUILD_DIR/mongo/foundation', + '$BUILD_DIR/mongo/server_parameters' ], ) diff --git a/src/mongo/db/concurrency/lock_mgr.cpp b/src/mongo/db/concurrency/lock_mgr.cpp index c25636dad52..68e161fc0a9 100644 --- a/src/mongo/db/concurrency/lock_mgr.cpp +++ b/src/mongo/db/concurrency/lock_mgr.cpp @@ -33,10 +33,11 @@ #include <boost/thread/locks.hpp> #include <sstream> +#include "mongo/base/init.h" +#include "mongo/db/server_parameters.h" #include "mongo/util/assert_util.h" #include "mongo/util/log.h" #include "mongo/util/timer.h" -#include "mongo/base/init.h" using boost::unique_lock; @@ -274,6 +275,11 @@ namespace mongo { /*---------- LockManager public functions (mutex guarded) ---------*/ + + // This startup parameter enables experimental document-level locking features + // It should be removed once full document-level locking is checked-in. + MONGO_EXPORT_STARTUP_SERVER_PARAMETER(useExperimentalDocLocking, bool, false); + static LockManager* _singleton = NULL; MONGO_INITIALIZER(InstantiateLockManager)(InitializerContext* context) { @@ -379,7 +385,12 @@ namespace mongo { } void LockManager::acquireLock(LockRequest* lr, Notifier* notifier) { - if (NULL == lr) return; + if (!useExperimentalDocLocking) { + return; + } + + invariant(lr); + { unique_lock<boost::mutex> lk(_mutex); _throwIfShuttingDown(); @@ -408,6 +419,10 @@ namespace mongo { const LockMode& mode, const ResourceId& resId, Notifier* notifier) { + if (kReservedResourceId == resId || !useExperimentalDocLocking) { + return; + } + { unique_lock<boost::mutex> lk(_mutex); _throwIfShuttingDown(); @@ -472,7 +487,8 @@ namespace mongo { } LockManager::LockStatus LockManager::releaseLock(LockRequest* lr) { - if (NULL == lr) return kLockNotFound; + if (!useExperimentalDocLocking) return kLockNotFound; + invariant(lr); { unique_lock<boost::mutex> lk(_mutex); _throwIfShuttingDown(lr->requestor); @@ -485,6 +501,10 @@ namespace mongo { LockManager::LockStatus LockManager::release(const Transaction* holder, const LockMode& mode, const ResourceId& resId) { + if (kReservedResourceId == resId || !useExperimentalDocLocking) { + return kLockNotFound; + } + { unique_lock<boost::mutex> lk(_mutex); _throwIfShuttingDown(holder); @@ -529,7 +549,7 @@ namespace mongo { return numLocksReleased; } #endif - void LockManager::abort(Transaction* goner) { + void LockManager::abort(Transaction* goner) { { unique_lock<boost::mutex> lk(_mutex); _throwIfShuttingDown(goner); @@ -619,6 +639,9 @@ namespace mongo { bool LockManager::isLocked(const Transaction* holder, const LockMode& mode, const ResourceId& resId) const { + if (!useExperimentalDocLocking) { + return false; + } { unique_lock<boost::mutex> lk(_mutex); _throwIfShuttingDown(holder); diff --git a/src/mongo/db/concurrency/lock_mgr.h b/src/mongo/db/concurrency/lock_mgr.h index b19cb528077..9a94bd33799 100644 --- a/src/mongo/db/concurrency/lock_mgr.h +++ b/src/mongo/db/concurrency/lock_mgr.h @@ -39,7 +39,6 @@ #include "mongo/platform/compiler.h" #include "mongo/platform/cstdint.h" #include "mongo/util/timer.h" - #include "mongo/bson/util/atomic_int.h" /* @@ -60,6 +59,9 @@ namespace mongo { + // Defined in lock_mgr.cpp + extern bool useExperimentalDocLocking; + class ResourceId { public: ResourceId() : _rid(0) { } @@ -69,7 +71,7 @@ namespace mongo { operator size_t() const { return _rid; } private: - size_t _rid; + uint64_t _rid; }; static const ResourceId kReservedResourceId = 0; @@ -706,29 +708,29 @@ namespace mongo { class SharedResourceLock : public ResourceLock { public: - SharedResourceLock(Transaction* requestor, void* resource) - : ResourceLock(LockManager::getSingleton(), - requestor, - kShared, - (size_t)resource) { } - SharedResourceLock(Transaction* requestor, size_t resource) - : ResourceLock(LockManager::getSingleton(), - requestor, - kShared, - resource) { } + SharedResourceLock(Transaction* requestor, void* resource) + : ResourceLock(LockManager::getSingleton(), + requestor, + kShared, + (size_t)resource) { } + SharedResourceLock(Transaction* requestor, uint64_t resource) + : ResourceLock(LockManager::getSingleton(), + requestor, + kShared, + resource) { } }; class ExclusiveResourceLock : public ResourceLock { public: - ExclusiveResourceLock(Transaction* requestor, void* resource) - : ResourceLock(LockManager::getSingleton(), - requestor, - kExclusive, - (size_t)resource) { } - ExclusiveResourceLock(Transaction* requestor, size_t resource) - : ResourceLock(LockManager::getSingleton(), - requestor, - kExclusive, - resource) { } + ExclusiveResourceLock(Transaction* requestor, void* resource) + : ResourceLock(LockManager::getSingleton(), + requestor, + kExclusive, + (size_t)resource) { } + ExclusiveResourceLock(Transaction* requestor, uint64_t resource) + : ResourceLock(LockManager::getSingleton(), + requestor, + kExclusive, + resource) { } }; } // namespace mongo diff --git a/src/mongo/db/d_concurrency.cpp b/src/mongo/db/d_concurrency.cpp index 530dc4d3879..bccc4d977d0 100644 --- a/src/mongo/db/d_concurrency.cpp +++ b/src/mongo/db/d_concurrency.cpp @@ -1,7 +1,7 @@ // @file d_concurrency.cpp /** -* Copyright (C) 2008 10gen Inc. +* Copyright (C) 2008-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, @@ -847,11 +847,4 @@ namespace mongo { } } lockStatsServerStatusSection; - - - // This startup parameter enables experimental document-level locking features, which work - // for update-in-place changes only (i.e., no index updates and no document growth or - // movement). It should be removed once full document-level locking is checked-in. - MONGO_EXPORT_STARTUP_SERVER_PARAMETER(useExperimentalDocLocking, bool, false); - } diff --git a/src/mongo/db/d_concurrency.h b/src/mongo/db/d_concurrency.h index a11351b5a84..7a93b0936ae 100644 --- a/src/mongo/db/d_concurrency.h +++ b/src/mongo/db/d_concurrency.h @@ -1,7 +1,7 @@ // @file d_concurrency.h /** -* Copyright (C) 2008 10gen Inc. +* Copyright (C) 2008-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, @@ -250,7 +250,4 @@ namespace mongo { ~writelocktry(); bool got() const { return _got; } }; - - // Defined in instance.cpp - extern bool useExperimentalDocLocking; } diff --git a/src/mongo/db/db.cpp b/src/mongo/db/db.cpp index b3ba3020306..612c1c28d3d 100644 --- a/src/mongo/db/db.cpp +++ b/src/mongo/db/db.cpp @@ -1,7 +1,7 @@ // @file db.cpp : Defines main() for the mongod program. /** -* Copyright (C) 2008 10gen Inc. +* Copyright (C) 2008-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, @@ -366,7 +366,7 @@ namespace mongo { const string systemIndexes = ctx.db()->name() + ".system.indexes"; Collection* coll = ctx.db()->getCollection( &txn, systemIndexes ); - auto_ptr<Runner> runner(InternalPlanner::collectionScan(systemIndexes,coll)); + auto_ptr<Runner> runner(InternalPlanner::collectionScan(&txn, systemIndexes,coll)); BSONObj index; Runner::RunnerState state; while (Runner::RUNNER_ADVANCED == (state = runner->getNext(&index, NULL))) { diff --git a/src/mongo/db/dbcommands.cpp b/src/mongo/db/dbcommands.cpp index 96804e2dfc0..e8bfba4218c 100644 --- a/src/mongo/db/dbcommands.cpp +++ b/src/mongo/db/dbcommands.cpp @@ -1,7 +1,7 @@ // dbcommands.cpp /** -* Copyright (C) 2012 10gen Inc. +* Copyright (C) 2012-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, @@ -674,7 +674,7 @@ namespace mongo { } Runner* rawRunner; - if (!getRunner(coll, cq, &rawRunner, QueryPlannerParams::NO_TABLE_SCAN).isOK()) { + if (!getRunner(txn, coll, cq, &rawRunner, QueryPlannerParams::NO_TABLE_SCAN).isOK()) { uasserted(17241, "Can't get runner for query " + query.toString()); return 0; } @@ -797,7 +797,7 @@ namespace mongo { result.append( "millis" , timer.millis() ); return 1; } - runner.reset(InternalPlanner::collectionScan(ns,collection)); + runner.reset(InternalPlanner::collectionScan(txn, ns,collection)); } else if ( min.isEmpty() || max.isEmpty() ) { errmsg = "only one of min or max specified"; @@ -822,7 +822,7 @@ namespace mongo { min = Helpers::toKeyFormat( kp.extendRangeBound( min, false ) ); max = Helpers::toKeyFormat( kp.extendRangeBound( max, false ) ); - runner.reset(InternalPlanner::indexScan(collection, idx, min, max, false)); + runner.reset(InternalPlanner::indexScan(txn, collection, idx, min, max, false)); } long long avgObjSize = collection->dataSize() / collection->numRecords(); @@ -925,12 +925,12 @@ namespace mongo { result.append( "avgObjSize" , collection->averageObjectSize() ); result.appendNumber( "storageSize", - static_cast<long long>(collection->getRecordStore()->storageSize( &result, + static_cast<long long>(collection->getRecordStore()->storageSize( txn, &result, verbose ? 1 : 0 ) ) / scale ); result.append( "nindexes" , collection->getIndexCatalog()->numIndexesReady() ); - collection->getRecordStore()->appendCustomStats( &result, scale ); + collection->getRecordStore()->appendCustomStats( txn, &result, scale ); BSONObjBuilder indexSizes; result.appendNumber( "totalIndexSize" , db->getIndexSizeForCollection(txn, diff --git a/src/mongo/db/dbhelpers.cpp b/src/mongo/db/dbhelpers.cpp index f0ac18ca3bc..83b5b0b7ec5 100644 --- a/src/mongo/db/dbhelpers.cpp +++ b/src/mongo/db/dbhelpers.cpp @@ -1,7 +1,7 @@ // dbhelpers.cpp /** -* Copyright (C) 2008 10gen Inc. +* Copyright (C) 2008-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, @@ -114,7 +114,7 @@ namespace mongo { Runner* rawRunner; size_t options = requireIndex ? QueryPlannerParams::NO_TABLE_SCAN : QueryPlannerParams::DEFAULT; massert(17245, "Could not get runner for query " + query.toString(), - getRunner(collection, cq, &rawRunner, options).isOK()); + getRunner(txn, collection, cq, &rawRunner, options).isOK()); auto_ptr<Runner> runner(rawRunner); Runner::RunnerState state; @@ -156,7 +156,7 @@ namespace mongo { BtreeBasedAccessMethod* accessMethod = static_cast<BtreeBasedAccessMethod*>(catalog->getIndex( desc )); - DiskLoc loc = accessMethod->findSingle( query["_id"].wrap() ); + DiskLoc loc = accessMethod->findSingle( txn, query["_id"].wrap() ); if ( loc.isNull() ) return false; result = collection->docFor( loc ); @@ -173,7 +173,7 @@ namespace mongo { // See SERVER-12397. This may not always be true. BtreeBasedAccessMethod* accessMethod = static_cast<BtreeBasedAccessMethod*>(catalog->getIndex( desc )); - return accessMethod->findSingle( idquery["_id"].wrap() ); + return accessMethod->findSingle( txn, idquery["_id"].wrap() ); } /* Get the first object from a collection. Generally only useful if the collection @@ -183,7 +183,8 @@ namespace mongo { */ bool Helpers::getSingleton(OperationContext* txn, const char *ns, BSONObj& result) { Client::Context context(txn, ns); - auto_ptr<Runner> runner(InternalPlanner::collectionScan(ns, + auto_ptr<Runner> runner(InternalPlanner::collectionScan(txn, + ns, context.db()->getCollection(txn, ns))); Runner::RunnerState state = runner->getNext(&result, NULL); @@ -194,7 +195,8 @@ namespace mongo { bool Helpers::getLast(OperationContext* txn, const char *ns, BSONObj& result) { Client::Context ctx(txn, ns); Collection* coll = ctx.db()->getCollection( txn, ns ); - auto_ptr<Runner> runner(InternalPlanner::collectionScan(ns, + auto_ptr<Runner> runner(InternalPlanner::collectionScan(txn, + ns, coll, InternalPlanner::BACKWARD)); Runner::RunnerState state = runner->getNext(&result, NULL); @@ -359,7 +361,7 @@ namespace mongo { IndexDescriptor* desc = collection->getIndexCatalog()->findIndexByKeyPattern( indexKeyPattern.toBSON() ); - auto_ptr<Runner> runner(InternalPlanner::indexScan(collection, desc, min, max, + auto_ptr<Runner> runner(InternalPlanner::indexScan(txn, collection, desc, min, max, maxInclusive, InternalPlanner::FORWARD, InternalPlanner::IXSCAN_FETCH)); @@ -520,7 +522,7 @@ namespace mongo { bool isLargeChunk = false; long long docCount = 0; - auto_ptr<Runner> runner(InternalPlanner::indexScan(collection, idx, min, max, false)); + auto_ptr<Runner> runner(InternalPlanner::indexScan(txn, collection, idx, min, max, false)); // we can afford to yield here because any change to the base data that we might miss is // already being queued and will be migrated in the 'transferMods' stage diff --git a/src/mongo/db/exec/2dcommon.cpp b/src/mongo/db/exec/2dcommon.cpp index 7ffc110d8f6..f7c01ac3a25 100644 --- a/src/mongo/db/exec/2dcommon.cpp +++ b/src/mongo/db/exec/2dcommon.cpp @@ -231,8 +231,12 @@ namespace twod_exec { // The only time these may be equal is when we actually equal the location // itself, otherwise our expanding algorithm will fail. // static - bool BtreeLocation::initial(const IndexDescriptor* descriptor, const TwoDIndexingParams& params, - BtreeLocation& min, BtreeLocation& max, GeoHash start) { + bool BtreeLocation::initial(OperationContext* txn, + const IndexDescriptor* descriptor, + const TwoDIndexingParams& params, + BtreeLocation& min, + BtreeLocation& max, + GeoHash start) { verify(descriptor); min._eof = false; @@ -294,10 +298,10 @@ namespace twod_exec { verify(maxParams.bounds.isValidFor(descriptor->keyPattern(), 1)); min._ws.reset(new WorkingSet()); - min._scan.reset(new IndexScan(minParams, min._ws.get(), NULL)); + min._scan.reset(new IndexScan(txn, minParams, min._ws.get(), NULL)); max._ws.reset(new WorkingSet()); - max._scan.reset(new IndexScan(maxParams, max._ws.get(), NULL)); + max._scan.reset(new IndexScan(txn, maxParams, max._ws.get(), NULL)); min.advance(); max.advance(); @@ -396,7 +400,9 @@ namespace twod_exec { // Are we finished getting points? bool GeoBrowse::moreToDo() { return _state != DONE; } - bool GeoBrowse::checkAndAdvance(BtreeLocation* bl, const GeoHash& hash, int& totalFound) { + bool GeoBrowse::checkAndAdvance(BtreeLocation* bl, + const GeoHash& hash, + int& totalFound) { if (bl->eof()) { return false; } //cout << "looking at " << bl->_loc.obj().toString() << " dl " << bl->_loc.toString() << endl; @@ -433,7 +439,7 @@ namespace twod_exec { if(! isNeighbor) _prefix = expandStartHash(); - if (!BtreeLocation::initial(_descriptor, _params, _min, _max, _prefix)) { + if (!BtreeLocation::initial(&_txn, _descriptor, _params, _min, _max, _prefix)) { _state = isNeighbor ? DONE_NEIGHBOR : DONE; } else { _state = DOING_EXPAND; diff --git a/src/mongo/db/exec/2dcommon.h b/src/mongo/db/exec/2dcommon.h index 9283e327ee0..1d27b610a70 100644 --- a/src/mongo/db/exec/2dcommon.h +++ b/src/mongo/db/exec/2dcommon.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2013 10gen Inc. + * Copyright (C) 2013-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, @@ -32,10 +32,14 @@ #include "mongo/db/geo/shapes.h" #include "mongo/db/index/2d_access_method.h" +#include "mongo/db/operation_context_noop.h" #pragma once namespace mongo { + + class OperationContext; + namespace twod_exec { // @@ -111,7 +115,6 @@ namespace twod_exec { struct BtreeLocation { BtreeLocation() : _eof(false) { } - scoped_ptr<IndexScan> _scan; scoped_ptr<WorkingSet> _ws; DiskLoc _loc; @@ -130,8 +133,12 @@ namespace twod_exec { // Returns the min and max keys which bound a particular location. // The only time these may be equal is when we actually equal the location // itself, otherwise our expanding algorithm will fail. - static bool initial(const IndexDescriptor* descriptor, const TwoDIndexingParams& params, - BtreeLocation& min, BtreeLocation& max, GeoHash start); + static bool initial(OperationContext* txn, + const IndexDescriptor* descriptor, + const TwoDIndexingParams& params, + BtreeLocation& min, + BtreeLocation& max, + GeoHash start); }; // @@ -207,7 +214,9 @@ namespace twod_exec { // Fills the stack, but only checks a maximum number of maxToCheck points at a time. // Further calls to this function will continue the expand/check neighbors algorithm. - virtual void fillStack(int maxToCheck, int maxToAdd = -1, bool onlyExpand = false); + virtual void fillStack(int maxToCheck, + int maxToAdd = -1, + bool onlyExpand = false); bool checkAndAdvance(BtreeLocation* bl, const GeoHash& hash, int& totalFound); @@ -273,6 +282,7 @@ namespace twod_exec { private: const Collection* _collection; + OperationContextNoop _txn; }; } // namespace twod_exec diff --git a/src/mongo/db/exec/2dnear.cpp b/src/mongo/db/exec/2dnear.cpp index d1f276c233a..a42ad52d5de 100644 --- a/src/mongo/db/exec/2dnear.cpp +++ b/src/mongo/db/exec/2dnear.cpp @@ -40,8 +40,8 @@ namespace mongo { // static const char* TwoDNear::kStageType = "GEO_NEAR_2D"; - TwoDNear::TwoDNear(const TwoDNearParams& params, WorkingSet* ws) - : _commonStats(kStageType) { + TwoDNear::TwoDNear(OperationContext* txn, const TwoDNearParams& params, WorkingSet* ws) + : _txn(txn), _commonStats(kStageType) { _params = params; _workingSet = ws; _initted = false; diff --git a/src/mongo/db/exec/2dnear.h b/src/mongo/db/exec/2dnear.h index 265f3ff6402..2216f76c41d 100644 --- a/src/mongo/db/exec/2dnear.h +++ b/src/mongo/db/exec/2dnear.h @@ -64,7 +64,7 @@ namespace mongo { class TwoDNear : public PlanStage { public: - TwoDNear(const TwoDNearParams& params, WorkingSet* ws); + TwoDNear(OperationContext* txn, const TwoDNearParams& params, WorkingSet* ws); virtual ~TwoDNear(); virtual bool isEOF(); @@ -83,6 +83,10 @@ namespace mongo { static const char* kStageType; private: + + // transactional context for read locks. Not owned by us + OperationContext* _txn; + WorkingSet* _workingSet; // Stats diff --git a/src/mongo/db/exec/collection_scan.cpp b/src/mongo/db/exec/collection_scan.cpp index 195ab21e551..d76ce92e19c 100644 --- a/src/mongo/db/exec/collection_scan.cpp +++ b/src/mongo/db/exec/collection_scan.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2013 10gen Inc. + * Copyright (C) 2013-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, @@ -42,10 +42,12 @@ namespace mongo { // static const char* CollectionScan::kStageType = "COLLSCAN"; - CollectionScan::CollectionScan(const CollectionScanParams& params, + CollectionScan::CollectionScan(OperationContext* txn, + const CollectionScanParams& params, WorkingSet* workingSet, const MatchExpression* filter) - : _workingSet(workingSet), + : _txn(txn), + _workingSet(workingSet), _filter(filter), _params(params), _nsDropped(false), @@ -66,7 +68,8 @@ namespace mongo { return PlanStage::DEAD; } - _iter.reset( _params.collection->getIterator( _params.start, + _iter.reset( _params.collection->getIterator( _txn, + _params.start, _params.tailable, _params.direction ) ); diff --git a/src/mongo/db/exec/collection_scan.h b/src/mongo/db/exec/collection_scan.h index f752c69e4c3..fbc47701d84 100644 --- a/src/mongo/db/exec/collection_scan.h +++ b/src/mongo/db/exec/collection_scan.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2013 10gen Inc. + * Copyright (C) 2013-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, @@ -37,6 +37,7 @@ namespace mongo { class RecordIterator; class WorkingSet; + class OperationContext; /** * Scans over a collection, starting at the DiskLoc provided in params and continuing until @@ -46,7 +47,8 @@ namespace mongo { */ class CollectionScan : public PlanStage { public: - CollectionScan(const CollectionScanParams& params, + CollectionScan(OperationContext* txn, + const CollectionScanParams& params, WorkingSet* workingSet, const MatchExpression* filter); @@ -71,6 +73,9 @@ namespace mongo { */ bool diskLocInMemory(DiskLoc loc); + // transactional context for read locks. Not owned by us + OperationContext* _txn; + // WorkingSet is not owned by us. WorkingSet* _workingSet; diff --git a/src/mongo/db/exec/count.cpp b/src/mongo/db/exec/count.cpp index eeb860e9e92..5b5264e0e63 100644 --- a/src/mongo/db/exec/count.cpp +++ b/src/mongo/db/exec/count.cpp @@ -36,8 +36,9 @@ namespace mongo { // static const char* Count::kStageType = "COUNT"; - Count::Count(const CountParams& params, WorkingSet* workingSet) - : _workingSet(workingSet), + Count::Count(OperationContext* txn, const CountParams& params, WorkingSet* workingSet) + : _txn(txn), + _workingSet(workingSet), _descriptor(params.descriptor), _iam(params.descriptor->getIndexCatalog()->getIndex(params.descriptor)), _btreeCursor(NULL), @@ -54,7 +55,7 @@ namespace mongo { cursorOptions.direction = CursorOptions::INCREASING; IndexCursor *cursor; - Status s = _iam->newCursor(cursorOptions, &cursor); + Status s = _iam->newCursor(_txn, cursorOptions, &cursor); verify(s.isOK()); verify(cursor); @@ -69,7 +70,7 @@ namespace mongo { // Create the cursor that points at our end position. IndexCursor* endCursor; - verify(_iam->newCursor(cursorOptions, &endCursor).isOK()); + verify(_iam->newCursor(_txn, cursorOptions, &endCursor).isOK()); verify(endCursor); // Is this assumption always valid? See SERVER-12397 diff --git a/src/mongo/db/exec/count.h b/src/mongo/db/exec/count.h index a3a82ab0032..3371587c368 100644 --- a/src/mongo/db/exec/count.h +++ b/src/mongo/db/exec/count.h @@ -36,6 +36,7 @@ #include "mongo/db/index/index_access_method.h" #include "mongo/db/jsobj.h" #include "mongo/db/matcher/expression.h" +#include "mongo/db/operation_context.h" #include "mongo/platform/unordered_set.h" namespace mongo { @@ -67,7 +68,7 @@ namespace mongo { */ class Count : public PlanStage { public: - Count(const CountParams& params, WorkingSet* workingSet); + Count(OperationContext* txn, const CountParams& params, WorkingSet* workingSet); virtual ~Count() { } virtual StageState work(WorkingSetID* out); @@ -95,6 +96,9 @@ namespace mongo { */ void checkEnd(); + // transactional context for read locks. Not owned by us + OperationContext* _txn; + // The WorkingSet we annotate with results. Not owned by us. WorkingSet* _workingSet; diff --git a/src/mongo/db/exec/distinct_scan.cpp b/src/mongo/db/exec/distinct_scan.cpp index 3cbd9e84d08..a55ea4e997e 100644 --- a/src/mongo/db/exec/distinct_scan.cpp +++ b/src/mongo/db/exec/distinct_scan.cpp @@ -39,8 +39,9 @@ namespace mongo { // static const char* DistinctScan::kStageType = "DISTINCT"; - DistinctScan::DistinctScan(const DistinctParams& params, WorkingSet* workingSet) - : _workingSet(workingSet), + DistinctScan::DistinctScan(OperationContext* txn, const DistinctParams& params, WorkingSet* workingSet) + : _txn(txn), + _workingSet(workingSet), _descriptor(params.descriptor), _iam(params.descriptor->getIndexCatalog()->getIndex(params.descriptor)), _btreeCursor(NULL), @@ -60,7 +61,7 @@ namespace mongo { } IndexCursor *cursor; - Status s = _iam->newCursor(cursorOptions, &cursor); + Status s = _iam->newCursor(_txn, cursorOptions, &cursor); verify(s.isOK()); verify(cursor); // Is this assumption always valid? See SERVER-12397 diff --git a/src/mongo/db/exec/distinct_scan.h b/src/mongo/db/exec/distinct_scan.h index 9e088da5068..d81a936937f 100644 --- a/src/mongo/db/exec/distinct_scan.h +++ b/src/mongo/db/exec/distinct_scan.h @@ -79,7 +79,7 @@ namespace mongo { */ class DistinctScan : public PlanStage { public: - DistinctScan(const DistinctParams& params, WorkingSet* workingSet); + DistinctScan(OperationContext* txn, const DistinctParams& params, WorkingSet* workingSet); virtual ~DistinctScan() { } virtual StageState work(WorkingSetID* out); @@ -105,6 +105,9 @@ namespace mongo { /** See if the cursor is pointing at or past _endKey, if _endKey is non-empty. */ void checkEnd(); + // transactional context for read locks. Not owned by us + OperationContext* _txn; + // The WorkingSet we annotate with results. Not owned by us. WorkingSet* _workingSet; diff --git a/src/mongo/db/exec/idhack.cpp b/src/mongo/db/exec/idhack.cpp index d27f7a34b5b..e577210226f 100644 --- a/src/mongo/db/exec/idhack.cpp +++ b/src/mongo/db/exec/idhack.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2013 10gen Inc. + * Copyright (C) 2013-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, @@ -40,8 +40,10 @@ namespace mongo { // static const char* IDHackStage::kStageType = "IDHACK"; - IDHackStage::IDHackStage(const Collection* collection, CanonicalQuery* query, WorkingSet* ws) - : _collection(collection), + IDHackStage::IDHackStage(OperationContext* txn, const Collection* collection, + CanonicalQuery* query, WorkingSet* ws) + : _txn(txn), + _collection(collection), _workingSet(ws), _key(query->getQueryObj()["_id"].wrap()), _query(query), @@ -49,8 +51,10 @@ namespace mongo { _done(false), _commonStats(kStageType) { } - IDHackStage::IDHackStage(Collection* collection, const BSONObj& key, WorkingSet* ws) - : _collection(collection), + IDHackStage::IDHackStage(OperationContext* txn, Collection* collection, + const BSONObj& key, WorkingSet* ws) + : _txn(txn), + _collection(collection), _workingSet(ws), _key(key), _query(NULL), @@ -88,7 +92,7 @@ namespace mongo { static_cast<const BtreeBasedAccessMethod*>(catalog->getIndex(idDesc)); // Look up the key by going directly to the Btree. - DiskLoc loc = accessMethod->findSingle( _key ); + DiskLoc loc = accessMethod->findSingle( _txn, _key ); // Key not found. if (loc.isNull()) { diff --git a/src/mongo/db/exec/idhack.h b/src/mongo/db/exec/idhack.h index 3f266638d9e..85cdd78abae 100644 --- a/src/mongo/db/exec/idhack.h +++ b/src/mongo/db/exec/idhack.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2013 10gen Inc. + * Copyright (C) 2013-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, @@ -42,9 +42,11 @@ namespace mongo { class IDHackStage : public PlanStage { public: /** Takes ownership of all the arguments -collection. */ - IDHackStage(const Collection* collection, CanonicalQuery* query, WorkingSet* ws); + IDHackStage(OperationContext* txn, const Collection* collection, + CanonicalQuery* query, WorkingSet* ws); - IDHackStage(Collection* collection, const BSONObj& key, WorkingSet* ws); + IDHackStage(OperationContext* txn, Collection* collection, + const BSONObj& key, WorkingSet* ws); virtual ~IDHackStage(); @@ -69,6 +71,9 @@ namespace mongo { static const char* kStageType; private: + // transactional context for read locks. Not owned by us + OperationContext* _txn; + // Not owned here. const Collection* _collection; diff --git a/src/mongo/db/exec/index_scan.cpp b/src/mongo/db/exec/index_scan.cpp index 1982f134b8d..b4ee4706cf0 100644 --- a/src/mongo/db/exec/index_scan.cpp +++ b/src/mongo/db/exec/index_scan.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2013 10gen Inc. + * Copyright (C) 2013-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, @@ -51,9 +51,12 @@ namespace mongo { // static const char* IndexScan::kStageType = "IXSCAN"; - IndexScan::IndexScan(const IndexScanParams& params, WorkingSet* workingSet, + IndexScan::IndexScan(OperationContext* txn, + const IndexScanParams& params, + WorkingSet* workingSet, const MatchExpression* filter) - : _workingSet(workingSet), + : _txn(txn), + _workingSet(workingSet), _hitEnd(false), _filter(filter), _shouldDedup(true), @@ -90,7 +93,7 @@ namespace mongo { } IndexCursor *cursor; - Status s = _iam->newCursor(cursorOptions, &cursor); + Status s = _iam->newCursor(_txn, cursorOptions, &cursor); verify(s.isOK()); _indexCursor.reset(cursor); diff --git a/src/mongo/db/exec/index_scan.h b/src/mongo/db/exec/index_scan.h index 6b993f387ad..02b14f1e6d8 100644 --- a/src/mongo/db/exec/index_scan.h +++ b/src/mongo/db/exec/index_scan.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2013 10gen Inc. + * Copyright (C) 2013-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, @@ -80,7 +80,9 @@ namespace mongo { */ class IndexScan : public PlanStage { public: - IndexScan(const IndexScanParams& params, WorkingSet* workingSet, + IndexScan(OperationContext* txn, + const IndexScanParams& params, + WorkingSet* workingSet, const MatchExpression* filter); virtual ~IndexScan() { } @@ -108,6 +110,9 @@ namespace mongo { /** See if the cursor is pointing at or past _endKey, if _endKey is non-empty. */ void checkEnd(); + // transactional context for read locks. Not owned by us + OperationContext* _txn; + // The WorkingSet we annotate with results. Not owned by us. WorkingSet* _workingSet; diff --git a/src/mongo/db/exec/oplogstart.cpp b/src/mongo/db/exec/oplogstart.cpp index c569bfb8a34..93d4028ed10 100644 --- a/src/mongo/db/exec/oplogstart.cpp +++ b/src/mongo/db/exec/oplogstart.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2013 10gen Inc. + * Copyright (C) 2013-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, @@ -35,8 +35,12 @@ namespace mongo { // Does not take ownership. - OplogStart::OplogStart(const Collection* collection, MatchExpression* filter, WorkingSet* ws) - : _needInit(true), + OplogStart::OplogStart(OperationContext* txn, + const Collection* collection, + MatchExpression* filter, + WorkingSet* ws) + : _txn(txn), + _needInit(true), _backwardsScanning(false), _extentHopping(false), _done(false), @@ -52,7 +56,7 @@ namespace mongo { CollectionScanParams params; params.collection = _collection; params.direction = CollectionScanParams::BACKWARD; - _cs.reset(new CollectionScan(params, _workingSet, NULL)); + _cs.reset(new CollectionScan(_txn, params, _workingSet, NULL)); _needInit = false; _backwardsScanning = true; _timer.reset(); @@ -105,7 +109,7 @@ namespace mongo { _cs.reset(); // Set up our extent hopping state. - _subIterators = _collection->getManyIterators(); + _subIterators = _collection->getManyIterators(_txn); } PlanStage::StageState OplogStart::workBackwardsScan(WorkingSetID* out) { diff --git a/src/mongo/db/exec/oplogstart.h b/src/mongo/db/exec/oplogstart.h index e10721a9064..5d313368532 100644 --- a/src/mongo/db/exec/oplogstart.h +++ b/src/mongo/db/exec/oplogstart.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2013 10gen Inc. + * Copyright (C) 2013-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, @@ -60,7 +60,10 @@ namespace mongo { class OplogStart : public PlanStage { public: // Does not take ownership. - OplogStart(const Collection* collection, MatchExpression* filter, WorkingSet* ws); + OplogStart(OperationContext* txn, + const Collection* collection, + MatchExpression* filter, + WorkingSet* ws); virtual ~OplogStart(); virtual StageState work(WorkingSetID* out); @@ -88,6 +91,9 @@ namespace mongo { StageState workExtentHopping(WorkingSetID* out); + // transactional context for read locks. Not owned by us + OperationContext* _txn; + // If we're backwards scanning we just punt to a collscan. scoped_ptr<CollectionScan> _cs; diff --git a/src/mongo/db/exec/s2near.cpp b/src/mongo/db/exec/s2near.cpp index c7d37111840..66babb6d832 100644 --- a/src/mongo/db/exec/s2near.cpp +++ b/src/mongo/db/exec/s2near.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2013 MongoDB Inc. + * Copyright (C) 2013-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, @@ -43,8 +43,8 @@ namespace mongo { // static const char* S2NearStage::kStageType = "GEO_NEAR_2DSPHERE"; - S2NearStage::S2NearStage(const S2NearParams& params, WorkingSet* ws) - : _commonStats(kStageType) { + S2NearStage::S2NearStage(OperationContext* txn, const S2NearParams& params, WorkingSet* ws) + : _txn(txn), _commonStats(kStageType) { _initted = false; _params = params; _ws = ws; @@ -282,7 +282,7 @@ namespace mongo { // Owns geo filter. _keyGeoFilter.reset(new GeoS2KeyMatchExpression( &_annulus, _params.baseBounds.fields[_nearFieldIndex].name)); - IndexScan* scan = new IndexScan(params, _ws, _keyGeoFilter.get()); + IndexScan* scan = new IndexScan(_txn, params, _ws, _keyGeoFilter.get()); // Owns 'scan'. _child.reset(new FetchStage(_ws, scan, _params.filter, _params.collection)); diff --git a/src/mongo/db/exec/s2near.h b/src/mongo/db/exec/s2near.h index f273b8bf992..e71f697c23e 100644 --- a/src/mongo/db/exec/s2near.h +++ b/src/mongo/db/exec/s2near.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2013 MongoDB Inc. + * Copyright (C) 2013-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, @@ -43,6 +43,8 @@ namespace mongo { + class OperationContext; + struct S2NearParams { S2NearParams() : collection(NULL) { } Collection* collection; @@ -63,7 +65,7 @@ namespace mongo { * Takes: index to scan over, MatchExpression with near point, other MatchExpressions for * covered data, */ - S2NearStage(const S2NearParams& params, WorkingSet* ws); + S2NearStage(OperationContext* txn, const S2NearParams& params, WorkingSet* ws); virtual ~S2NearStage(); @@ -87,6 +89,9 @@ namespace mongo { StageState addResultToQueue(WorkingSetID* out); void nextAnnulus(); + // transactional context for read locks. Not owned by us + OperationContext* _txn; + bool _worked; S2NearParams _params; diff --git a/src/mongo/db/exec/stagedebug_cmd.cpp b/src/mongo/db/exec/stagedebug_cmd.cpp index c2f6698414d..346d481d8be 100644 --- a/src/mongo/db/exec/stagedebug_cmd.cpp +++ b/src/mongo/db/exec/stagedebug_cmd.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2013 10gen Inc. + * Copyright (C) 2013-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, @@ -134,7 +134,7 @@ namespace mongo { OwnedPointerVector<MatchExpression> exprs; auto_ptr<WorkingSet> ws(new WorkingSet()); - PlanStage* userRoot = parseQuery(collection, planObj, ws.get(), &exprs); + PlanStage* userRoot = parseQuery(txn, collection, planObj, ws.get(), &exprs); uassert(16911, "Couldn't parse plan from " + cmdObj.toString(), NULL != userRoot); // Add a fetch at the top for the user so we can get obj back for sure. @@ -153,7 +153,8 @@ namespace mongo { return true; } - PlanStage* parseQuery(Collection* collection, + PlanStage* parseQuery(OperationContext* txn, + Collection* collection, BSONObj obj, WorkingSet* workingSet, OwnedPointerVector<MatchExpression>* exprs) { @@ -211,7 +212,7 @@ namespace mongo { params.bounds.endKeyInclusive = nodeArgs["endKeyInclusive"].Bool(); params.direction = nodeArgs["direction"].numberInt(); - return new IndexScan(params, workingSet, matcher); + return new IndexScan(txn, params, workingSet, matcher); } else if ("andHash" == nodeName) { uassert(16921, "Nodes argument must be provided to AND", @@ -226,7 +227,7 @@ namespace mongo { uassert(16922, "node of AND isn't an obj?: " + e.toString(), e.isABSONObj()); - PlanStage* subNode = parseQuery(collection, e.Obj(), workingSet, exprs); + PlanStage* subNode = parseQuery(txn, collection, e.Obj(), workingSet, exprs); uassert(16923, "Can't parse sub-node of AND: " + e.Obj().toString(), NULL != subNode); // takes ownership @@ -252,7 +253,7 @@ namespace mongo { uassert(16925, "node of AND isn't an obj?: " + e.toString(), e.isABSONObj()); - PlanStage* subNode = parseQuery(collection, e.Obj(), workingSet, exprs); + PlanStage* subNode = parseQuery(txn, collection, e.Obj(), workingSet, exprs); uassert(16926, "Can't parse sub-node of AND: " + e.Obj().toString(), NULL != subNode); // takes ownership @@ -275,7 +276,7 @@ namespace mongo { while (it.more()) { BSONElement e = it.next(); if (!e.isABSONObj()) { return NULL; } - PlanStage* subNode = parseQuery(collection, e.Obj(), workingSet, exprs); + PlanStage* subNode = parseQuery(txn, collection, e.Obj(), workingSet, exprs); uassert(16936, "Can't parse sub-node of OR: " + e.Obj().toString(), NULL != subNode); // takes ownership @@ -287,7 +288,8 @@ namespace mongo { else if ("fetch" == nodeName) { uassert(16929, "Node argument must be provided to fetch", nodeArgs["node"].isABSONObj()); - PlanStage* subNode = parseQuery(collection, + PlanStage* subNode = parseQuery(txn, + collection, nodeArgs["node"].Obj(), workingSet, exprs); @@ -300,7 +302,8 @@ namespace mongo { nodeArgs["node"].isABSONObj()); uassert(16931, "Num argument must be provided to limit", nodeArgs["num"].isNumber()); - PlanStage* subNode = parseQuery(collection, + PlanStage* subNode = parseQuery(txn, + collection, nodeArgs["node"].Obj(), workingSet, exprs); @@ -313,7 +316,8 @@ namespace mongo { nodeArgs["node"].isABSONObj()); uassert(16933, "Num argument must be provided to skip", nodeArgs["num"].isNumber()); - PlanStage* subNode = parseQuery(collection, + PlanStage* subNode = parseQuery(txn, + collection, nodeArgs["node"].Obj(), workingSet, exprs); @@ -333,7 +337,7 @@ namespace mongo { params.direction = CollectionScanParams::BACKWARD; } - return new CollectionScan(params, workingSet, matcher); + return new CollectionScan(txn, params, workingSet, matcher); } // sort is disabled for now. #if 0 @@ -342,7 +346,7 @@ namespace mongo { nodeArgs["node"].isABSONObj()); uassert(16970, "Pattern argument must be provided to sort", nodeArgs["pattern"].isABSONObj()); - PlanStage* subNode = parseQuery(db, nodeArgs["node"].Obj(), workingSet, exprs); + PlanStage* subNode = parseQuery(txn, db, nodeArgs["node"].Obj(), workingSet, exprs); SortStageParams params; params.pattern = nodeArgs["pattern"].Obj(); return new SortStage(params, workingSet, subNode); @@ -367,7 +371,7 @@ namespace mongo { uassert(16973, "node of mergeSort isn't an obj?: " + e.toString(), e.isABSONObj()); - PlanStage* subNode = parseQuery(collection, e.Obj(), workingSet, exprs); + PlanStage* subNode = parseQuery(txn, collection, e.Obj(), workingSet, exprs); uassert(16974, "Can't parse sub-node of mergeSort: " + e.Obj().toString(), NULL != subNode); // takes ownership @@ -403,7 +407,7 @@ namespace mongo { return NULL; } - return new TextStage(params, workingSet, matcher); + return new TextStage(txn, params, workingSet, matcher); } else { return NULL; diff --git a/src/mongo/db/exec/subplan.cpp b/src/mongo/db/exec/subplan.cpp index 67e631abebd..6875a53f977 100644 --- a/src/mongo/db/exec/subplan.cpp +++ b/src/mongo/db/exec/subplan.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2013 10gen Inc. + * Copyright (C) 2013-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, @@ -46,11 +46,13 @@ namespace mongo { // static const char* SubplanStage::kStageType = "SUBPLAN"; - SubplanStage::SubplanStage(Collection* collection, + SubplanStage::SubplanStage(OperationContext* txn, + Collection* collection, WorkingSet* ws, const QueryPlannerParams& params, CanonicalQuery* cq) - : _state(SubplanStage::PLANNING), + : _txn(txn), + _state(SubplanStage::PLANNING), _collection(collection), _ws(ws), _plannerParams(params), @@ -75,12 +77,13 @@ namespace mongo { } // static - Status SubplanStage::make(Collection* collection, + Status SubplanStage::make(OperationContext* txn, + Collection* collection, WorkingSet* ws, const QueryPlannerParams& params, CanonicalQuery* cq, SubplanStage** out) { - auto_ptr<SubplanStage> autoStage(new SubplanStage(collection, ws, params, cq)); + auto_ptr<SubplanStage> autoStage(new SubplanStage(txn, collection, ws, params, cq)); Status planningStatus = autoStage->planSubqueries(); if (!planningStatus.isOK()) { return planningStatus; @@ -262,7 +265,8 @@ namespace mongo { // Dump all the solutions into the MPR. for (size_t ix = 0; ix < solutions.size(); ++ix) { PlanStage* nextPlanRoot; - verify(StageBuilder::build(_collection, + verify(StageBuilder::build(_txn, + _collection, *solutions[ix], sharedWorkingSet, &nextPlanRoot)); @@ -349,7 +353,7 @@ namespace mongo { auto_ptr<MultiPlanStage> multiPlanStage(new MultiPlanStage(_collection, _query)); WorkingSet* ws = new WorkingSet(); PlanStage* root; - verify(StageBuilder::build(_collection, *soln, ws, &root)); + verify(StageBuilder::build(_txn, _collection, *soln, ws, &root)); multiPlanStage->addPlan(soln, root, ws); // Takes ownership first two arguments. multiPlanStage->pickBestPlan(); @@ -402,7 +406,9 @@ namespace mongo { else if (!_killed) { // Couldn't run as subplans so we'll just call normal getExecutor. PlanExecutor* exec; - Status status = getExecutorAlwaysPlan(_collection, _query, _plannerParams, &exec); + + Status status = getExecutorAlwaysPlan( + _txn, _collection, _query, _plannerParams, &exec); if (!status.isOK()) { // We utterly failed. diff --git a/src/mongo/db/exec/subplan.h b/src/mongo/db/exec/subplan.h index 1fb6c698523..5e63d82286c 100644 --- a/src/mongo/db/exec/subplan.h +++ b/src/mongo/db/exec/subplan.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2013 10gen Inc. + * Copyright (C) 2013-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, @@ -40,6 +40,8 @@ namespace mongo { + class OperationContext; + /** * The SubplanStage is used for rooted $or queries. It plans each clause of the $or * individually, and then creates an overall query plan based on the winning plan from @@ -55,7 +57,8 @@ namespace mongo { * * 'out' is valid only if an OK status is returned. */ - static Status make(Collection* collection, + static Status make(OperationContext* txn, + Collection* collection, WorkingSet* ws, const QueryPlannerParams& params, CanonicalQuery* cq, @@ -91,7 +94,8 @@ namespace mongo { Status planSubqueries(); private: - SubplanStage(Collection* collection, + SubplanStage(OperationContext* txn, + Collection* collection, WorkingSet* ws, const QueryPlannerParams& params, CanonicalQuery* cq); @@ -103,6 +107,9 @@ namespace mongo { RUNNING, }; + // transactional context for read locks. Not owned by us + OperationContext* _txn; + SubplanningState _state; Collection* _collection; diff --git a/src/mongo/db/exec/text.cpp b/src/mongo/db/exec/text.cpp index 50f7e3f99e4..85ddde49100 100644 --- a/src/mongo/db/exec/text.cpp +++ b/src/mongo/db/exec/text.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2013 10gen Inc. + * Copyright (C) 2013-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, @@ -41,10 +41,12 @@ namespace mongo { // static const char* TextStage::kStageType = "TEXT"; - TextStage::TextStage(const TextStageParams& params, + TextStage::TextStage(OperationContext* txn, + const TextStageParams& params, WorkingSet* ws, const MatchExpression* filter) - : _params(params), + : _txn(txn), + _params(params), _ftsMatcher(params.query, params.spec), _ws(ws), _filter(filter), @@ -180,7 +182,7 @@ namespace mongo { params.bounds.isSimpleRange = true; params.descriptor = _params.index; params.direction = -1; - _scanners.mutableVector().push_back(new IndexScan(params, _ws, NULL)); + _scanners.mutableVector().push_back(new IndexScan(_txn, params, _ws, NULL)); } // If we have no terms we go right to EOF. diff --git a/src/mongo/db/exec/text.h b/src/mongo/db/exec/text.h index 851d3cdada7..48f4c595b27 100644 --- a/src/mongo/db/exec/text.h +++ b/src/mongo/db/exec/text.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2013 10gen Inc. + * Copyright (C) 2013-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, @@ -52,6 +52,8 @@ namespace mongo { using fts::FTSSpec; using fts::MAX_WEIGHT; + class OperationContext; + struct TextStageParams { TextStageParams(const FTSSpec& s) : spec(s) {} @@ -93,7 +95,10 @@ namespace mongo { DONE, }; - TextStage(const TextStageParams& params, WorkingSet* ws, const MatchExpression* filter); + TextStage(OperationContext* txn, + const TextStageParams& params, + WorkingSet* ws, + const MatchExpression* filter); virtual ~TextStage(); @@ -137,6 +142,9 @@ namespace mongo { */ StageState returnResults(WorkingSetID* out); + // transactional context for read locks. Not owned by us + OperationContext* _txn; + // Parameters of this text stage. TextStageParams _params; diff --git a/src/mongo/db/fts/fts_command_mongod.cpp b/src/mongo/db/fts/fts_command_mongod.cpp index 4c0915df8db..a2c4b35e165 100644 --- a/src/mongo/db/fts/fts_command_mongod.cpp +++ b/src/mongo/db/fts/fts_command_mongod.cpp @@ -1,7 +1,7 @@ // fts_command_mongod.h /** -* Copyright (C) 2012 10gen Inc. +* Copyright (C) 2012-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, @@ -113,7 +113,7 @@ namespace mongo { } Runner* rawRunner; - Status getRunnerStatus = getRunner(ctx.ctx().db()->getCollection(txn, ns), cq, &rawRunner); + Status getRunnerStatus = getRunner(txn, ctx.ctx().db()->getCollection(txn, ns), cq, &rawRunner); if (!getRunnerStatus.isOK()) { errmsg = getRunnerStatus.reason(); return false; diff --git a/src/mongo/db/geo/haystack.cpp b/src/mongo/db/geo/haystack.cpp index 27cc3cb0633..ad8b06f00eb 100644 --- a/src/mongo/db/geo/haystack.cpp +++ b/src/mongo/db/geo/haystack.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2008-2013 10gen Inc. + * Copyright (C) 2008-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, @@ -110,7 +110,7 @@ namespace mongo { IndexDescriptor* desc = idxs[0]; HaystackAccessMethod* ham = static_cast<HaystackAccessMethod*>( collection->getIndexCatalog()->getIndex(desc) ); - ham->searchCommand(collection, nearElt.Obj(), maxDistance.numberDouble(), search.Obj(), + ham->searchCommand(txn, collection, nearElt.Obj(), maxDistance.numberDouble(), search.Obj(), &result, limit); return 1; } diff --git a/src/mongo/db/index/btree_based_access_method.cpp b/src/mongo/db/index/btree_based_access_method.cpp index 0e09b1cb98a..664aa7de94c 100644 --- a/src/mongo/db/index/btree_based_access_method.cpp +++ b/src/mongo/db/index/btree_based_access_method.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2013 10gen Inc. +* Copyright (C) 2013-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, @@ -143,8 +143,8 @@ namespace mongo { return ret; } - Status BtreeBasedAccessMethod::newCursor(const CursorOptions& opts, IndexCursor** out) const { - *out = new BtreeIndexCursor(_newInterface->newCursor(opts.direction)); + Status BtreeBasedAccessMethod::newCursor(OperationContext* txn, const CursorOptions& opts, IndexCursor** out) const { + *out = new BtreeIndexCursor(_newInterface->newCursor(txn, opts.direction)); return Status::OK(); } @@ -197,11 +197,11 @@ namespace mongo { return _newInterface->initAsEmpty(txn); } - Status BtreeBasedAccessMethod::touch(const BSONObj& obj) { + Status BtreeBasedAccessMethod::touch(OperationContext* txn, const BSONObj& obj) { BSONObjSet keys; getKeys(obj, &keys); - boost::scoped_ptr<BtreeInterface::Cursor> cursor(_newInterface->newCursor(1)); + boost::scoped_ptr<BtreeInterface::Cursor> cursor(_newInterface->newCursor(txn, 1)); for (BSONObjSet::const_iterator i = keys.begin(); i != keys.end(); ++i) { cursor->locate(*i, DiskLoc()); } @@ -214,8 +214,8 @@ namespace mongo { return _newInterface->touch(txn); } - DiskLoc BtreeBasedAccessMethod::findSingle(const BSONObj& key) const { - boost::scoped_ptr<BtreeInterface::Cursor> cursor(_newInterface->newCursor(1)); + DiskLoc BtreeBasedAccessMethod::findSingle( OperationContext* txn, const BSONObj& key) const { + boost::scoped_ptr<BtreeInterface::Cursor> cursor(_newInterface->newCursor(txn, 1)); cursor->locate(key, minDiskLoc); // A null bucket means the key wasn't found (nor was anything found after it). @@ -233,15 +233,16 @@ namespace mongo { return cursor->getDiskLoc(); } - Status BtreeBasedAccessMethod::validate(int64_t* numKeys) { + Status BtreeBasedAccessMethod::validate(OperationContext* txn, int64_t* numKeys) { // XXX: long long vs int64_t long long keys; - _newInterface->fullValidate(&keys); + _newInterface->fullValidate(txn, &keys); *numKeys = keys; return Status::OK(); } - Status BtreeBasedAccessMethod::validateUpdate(const BSONObj &from, + Status BtreeBasedAccessMethod::validateUpdate(OperationContext* txn, + const BSONObj &from, const BSONObj &to, const DiskLoc &record, const InsertDeleteOptions &options, @@ -264,7 +265,7 @@ namespace mongo { if (checkForDups) { for (vector<BSONObj*>::iterator i = data->added.begin(); i != data->added.end(); i++) { - Status check = _newInterface->dupKeyCheck(**i, record); + Status check = _newInterface->dupKeyCheck(txn, **i, record); if (!check.isOK()) { status->_isValid = false; return check; diff --git a/src/mongo/db/index/btree_based_access_method.h b/src/mongo/db/index/btree_based_access_method.h index 5b1aa351ae1..710a323b60a 100644 --- a/src/mongo/db/index/btree_based_access_method.h +++ b/src/mongo/db/index/btree_based_access_method.h @@ -1,5 +1,5 @@ /** -* Copyright (C) 2013 10gen Inc. +* Copyright (C) 2013-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, @@ -74,7 +74,8 @@ namespace mongo { const InsertDeleteOptions& options, int64_t* numDeleted); - virtual Status validateUpdate(const BSONObj& from, + virtual Status validateUpdate(OperationContext* txn, + const BSONObj& from, const BSONObj& to, const DiskLoc& loc, const InsertDeleteOptions& options, @@ -84,7 +85,9 @@ namespace mongo { const UpdateTicket& ticket, int64_t* numUpdated); - virtual Status newCursor(const CursorOptions& opts, IndexCursor** out) const; + virtual Status newCursor(OperationContext* txn, + const CursorOptions& opts, + IndexCursor** out) const; virtual Status initializeAsEmpty(OperationContext* txn); @@ -94,14 +97,14 @@ namespace mongo { bool mayInterrupt, std::set<DiskLoc>* dups ); - virtual Status touch(const BSONObj& obj); + virtual Status touch(OperationContext* txn, const BSONObj& obj); virtual Status touch(OperationContext* txn) const; - virtual Status validate(int64_t* numKeys); + virtual Status validate(OperationContext* txn, int64_t* numKeys); // XXX: consider migrating callers to use IndexCursor instead - virtual DiskLoc findSingle( const BSONObj& key ) const; + virtual DiskLoc findSingle( OperationContext* txn, const BSONObj& key ) const; /** * Invalidates all active cursors, which point at the bucket being deleted. diff --git a/src/mongo/db/index/btree_based_bulk_access_method.h b/src/mongo/db/index/btree_based_bulk_access_method.h index 88dad32ea04..0c766aad1ec 100644 --- a/src/mongo/db/index/btree_based_bulk_access_method.h +++ b/src/mongo/db/index/btree_based_bulk_access_method.h @@ -1,5 +1,5 @@ /** -* Copyright (C) 2013 10gen Inc. +* Copyright (C) 2013-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, @@ -75,7 +75,7 @@ namespace mongo { return Status::OK(); } - virtual Status touch(const BSONObj& obj) { + virtual Status touch(OperationContext* txn, const BSONObj& obj) { return _notAllowed(); } @@ -83,7 +83,7 @@ namespace mongo { return _notAllowed(); } - virtual Status validate(int64_t* numKeys) { + virtual Status validate(OperationContext* txn, int64_t* numKeys) { return _notAllowed(); } @@ -95,7 +95,8 @@ namespace mongo { return _notAllowed(); } - virtual Status validateUpdate(const BSONObj& from, + virtual Status validateUpdate(OperationContext* txn, + const BSONObj& from, const BSONObj& to, const DiskLoc& loc, const InsertDeleteOptions& options, @@ -109,7 +110,9 @@ namespace mongo { return _notAllowed(); } - virtual Status newCursor(const CursorOptions& opts, IndexCursor** out) const { + virtual Status newCursor(OperationContext*txn, + const CursorOptions& opts, + IndexCursor** out) const { return _notAllowed(); } diff --git a/src/mongo/db/index/haystack_access_method.cpp b/src/mongo/db/index/haystack_access_method.cpp index 44492bc87a2..a2fbe010a3f 100644 --- a/src/mongo/db/index/haystack_access_method.cpp +++ b/src/mongo/db/index/haystack_access_method.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2013 10gen Inc. + * Copyright (C) 2013-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, @@ -61,7 +61,7 @@ namespace mongo { ExpressionKeysPrivate::getHaystackKeys(obj, _geoField, _otherFields, _bucketSize, keys); } - void HaystackAccessMethod::searchCommand(Collection* collection, + void HaystackAccessMethod::searchCommand(OperationContext* txn, Collection* collection, const BSONObj& nearObj, double maxDistance, const BSONObj& search, BSONObjBuilder* result, unsigned limit) { @@ -100,7 +100,7 @@ namespace mongo { unordered_set<DiskLoc, DiskLoc::Hasher> thisPass; - scoped_ptr<Runner> runner(InternalPlanner::indexScan(collection, + scoped_ptr<Runner> runner(InternalPlanner::indexScan(txn, collection, _descriptor, key, key, true)); Runner::RunnerState state; DiskLoc loc; diff --git a/src/mongo/db/index/haystack_access_method.h b/src/mongo/db/index/haystack_access_method.h index 5ce9d787450..ebab7177a59 100644 --- a/src/mongo/db/index/haystack_access_method.h +++ b/src/mongo/db/index/haystack_access_method.h @@ -1,5 +1,5 @@ /** -* Copyright (C) 2013 10gen Inc. +* Copyright (C) 2013-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, @@ -36,6 +36,7 @@ namespace mongo { class Collection; + class OperationContext; /** * Maps (lat, lng) to the bucketSize-sided square bucket that contains it. @@ -62,7 +63,7 @@ namespace mongo { protected: friend class GeoHaystackSearchCommand; - void searchCommand(Collection* collection, + void searchCommand(OperationContext* txn, Collection* collection, const BSONObj& nearObj, double maxDistance, const BSONObj& search, BSONObjBuilder* result, unsigned limit); diff --git a/src/mongo/db/index/index_access_method.h b/src/mongo/db/index/index_access_method.h index 90bed6811d1..8cef5a5ef29 100644 --- a/src/mongo/db/index/index_access_method.h +++ b/src/mongo/db/index/index_access_method.h @@ -1,5 +1,5 @@ /** -* Copyright (C) 2013 10gen Inc. +* Copyright (C) 2013-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, @@ -91,7 +91,8 @@ namespace mongo { * * There is no obligation to perform the update after performing validation. */ - virtual Status validateUpdate(const BSONObj& from, + virtual Status validateUpdate(OperationContext* txn, + const BSONObj& from, const BSONObj& to, const DiskLoc& loc, const InsertDeleteOptions& options, @@ -113,7 +114,7 @@ namespace mongo { * Fills in '*out' with an IndexCursor. Return a status indicating success or reason of * failure. If the latter, '*out' contains NULL. See index_cursor.h for IndexCursor usage. */ - virtual Status newCursor(const CursorOptions& opts, IndexCursor** out) const = 0; + virtual Status newCursor(OperationContext* txn, const CursorOptions& opts, IndexCursor** out) const = 0; // ------ index level operations ------ @@ -131,12 +132,12 @@ namespace mongo { * appropriate pages are not swapped out. * See prefetch.cpp. */ - virtual Status touch(const BSONObj& obj) = 0; + virtual Status touch(OperationContext* txn, const BSONObj& obj) = 0; /** * this pages in the entire index */ - virtual Status touch( OperationContext* txn ) const = 0; + virtual Status touch(OperationContext* txn) const = 0; /** * Walk the entire index, checking the internal structure for consistency. @@ -147,7 +148,7 @@ namespace mongo { * Currently wasserts that the index is invalid. This could/should be changed in * the future to return a Status. */ - virtual Status validate(int64_t* numKeys) = 0; + virtual Status validate(OperationContext* txn, int64_t* numKeys) = 0; // // Bulk operations support diff --git a/src/mongo/db/ops/delete_executor.cpp b/src/mongo/db/ops/delete_executor.cpp index 2d776984236..e7eb2a9546c 100644 --- a/src/mongo/db/ops/delete_executor.cpp +++ b/src/mongo/db/ops/delete_executor.cpp @@ -118,11 +118,12 @@ namespace mongo { Runner* rawRunner; if (_canonicalQuery.get()) { - uassertStatusOK(getRunner(collection, _canonicalQuery.release(), &rawRunner)); + uassertStatusOK(getRunner(txn, collection, _canonicalQuery.release(), &rawRunner)); } else { CanonicalQuery* ignored; - uassertStatusOK(getRunner(collection, + uassertStatusOK(getRunner(txn, + collection, ns.ns(), _request->getQuery(), &rawRunner, diff --git a/src/mongo/db/ops/update.cpp b/src/mongo/db/ops/update.cpp index b39008a1bef..e675fd142ac 100644 --- a/src/mongo/db/ops/update.cpp +++ b/src/mongo/db/ops/update.cpp @@ -1,7 +1,7 @@ //@file update.cpp /** - * Copyright (C) 2008 10gen Inc. + * Copyright (C) 2008-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, @@ -457,8 +457,8 @@ namespace mongo { Runner* rawRunner; Status status = cq ? - getRunner(collection, cqHolder.release(), &rawRunner) : - getRunner(collection, nsString.ns(), request.getQuery(), &rawRunner, &cq); + getRunner(txn, collection, cqHolder.release(), &rawRunner) : + getRunner(txn, collection, nsString.ns(), request.getQuery(), &rawRunner, &cq); uassert(17243, "could not get runner " + request.getQuery().toString() + "; " + causedBy(status), status.isOK()); diff --git a/src/mongo/db/pipeline/pipeline_d.cpp b/src/mongo/db/pipeline/pipeline_d.cpp index 6f62767f999..1f6f93f1274 100644 --- a/src/mongo/db/pipeline/pipeline_d.cpp +++ b/src/mongo/db/pipeline/pipeline_d.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2012 10gen Inc. + * Copyright (c) 2012-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, @@ -75,6 +75,7 @@ namespace { } boost::shared_ptr<Runner> PipelineD::prepareCursorSource( + OperationContext* txn, Collection* collection, const intrusive_ptr<Pipeline>& pPipeline, const intrusive_ptr<ExpressionContext>& pExpCtx) { @@ -178,7 +179,7 @@ namespace { &cq, whereCallback); Runner* rawRunner; - if (status.isOK() && getRunner(collection, cq, &rawRunner, runnerOptions).isOK()) { + if (status.isOK() && getRunner(txn, collection, cq, &rawRunner, runnerOptions).isOK()) { // success: The Runner will handle sorting for us using an index. runner.reset(rawRunner); sortInRunner = true; @@ -203,7 +204,7 @@ namespace { whereCallback)); Runner* rawRunner; - uassertStatusOK(getRunner(collection, cq, &rawRunner, runnerOptions)); + uassertStatusOK(getRunner(txn, collection, cq, &rawRunner, runnerOptions)); runner.reset(rawRunner); } diff --git a/src/mongo/db/pipeline/pipeline_d.h b/src/mongo/db/pipeline/pipeline_d.h index b6b34e6f378..b9d85a69dbb 100644 --- a/src/mongo/db/pipeline/pipeline_d.h +++ b/src/mongo/db/pipeline/pipeline_d.h @@ -1,5 +1,5 @@ /** - * Copyright 2012 (c) 10gen Inc. + * Copyright (C) 2012-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, @@ -34,6 +34,7 @@ namespace mongo { class Collection; class DocumentSourceCursor; struct ExpressionContext; + class OperationContext; class Pipeline; class Runner; @@ -71,6 +72,7 @@ namespace mongo { * @param pExpCtx the expression context for this pipeline */ static boost::shared_ptr<Runner> prepareCursorSource( + OperationContext* txn, Collection* collection, const intrusive_ptr<Pipeline> &pPipeline, const intrusive_ptr<ExpressionContext> &pExpCtx); diff --git a/src/mongo/db/prefetch.cpp b/src/mongo/db/prefetch.cpp index 88ba08716e7..fe2500f4b16 100644 --- a/src/mongo/db/prefetch.cpp +++ b/src/mongo/db/prefetch.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2008 10gen Inc. +* Copyright (C) 2008-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, @@ -58,7 +58,8 @@ namespace mongo { "repl.preload.docs", &prefetchDocStats ); - void prefetchIndexPages(Collection* collection, + void prefetchIndexPages(OperationContext* txn, + Collection* collection, const repl::ReplSetImpl::IndexPrefetchConfig& prefetchConfig, const BSONObj& obj); @@ -111,7 +112,7 @@ namespace mongo { // a way to achieve that would be to prefetch the record first, and then afterwards do // this part. // - prefetchIndexPages(collection, prefetchConfig, obj); + prefetchIndexPages(txn, collection, prefetchConfig, obj); // do not prefetch the data for inserts; it doesn't exist yet // @@ -128,7 +129,8 @@ namespace mongo { } // page in pages needed for all index lookups on a given object - void prefetchIndexPages(Collection* collection, + void prefetchIndexPages(OperationContext* txn, + Collection* collection, const repl::ReplSetImpl::IndexPrefetchConfig& prefetchConfig, const BSONObj& obj) { DiskLoc unusedDl; // unused @@ -151,7 +153,7 @@ namespace mongo { return; IndexAccessMethod* iam = collection->getIndexCatalog()->getIndex( desc ); verify( iam ); - iam->touch(obj); + iam->touch(txn, obj); } catch (const DBException& e) { LOG(2) << "ignoring exception in prefetchIndexPages(): " << e.what() << endl; @@ -170,7 +172,7 @@ namespace mongo { IndexDescriptor* desc = ii.next(); IndexAccessMethod* iam = collection->getIndexCatalog()->getIndex( desc ); verify( iam ); - iam->touch(obj); + iam->touch(txn, obj); } catch (const DBException& e) { LOG(2) << "ignoring exception in prefetchIndexPages(): " << e.what() << endl; diff --git a/src/mongo/db/query/explain.h b/src/mongo/db/query/explain.h index 32d144466f5..bf4b5b4742c 100644 --- a/src/mongo/db/query/explain.h +++ b/src/mongo/db/query/explain.h @@ -38,6 +38,7 @@ namespace mongo { class Collection; + class OperationContext; // Temporarily hide the new explain implementation behind a setParameter. // TODO: take this out, and make the new implementation the default. @@ -131,7 +132,6 @@ namespace mongo { * are no stages, this requires a special explain format. */ static void explainCountEmptyQuery(BSONObjBuilder* out); - }; } // namespace diff --git a/src/mongo/db/query/get_executor.cpp b/src/mongo/db/query/get_executor.cpp index 74ec3f62f38..2a547a465c9 100644 --- a/src/mongo/db/query/get_executor.cpp +++ b/src/mongo/db/query/get_executor.cpp @@ -162,7 +162,8 @@ namespace mongo { plannerParams->options |= QueryPlannerParams::SPLIT_LIMITED_SORT; } - Status getExecutorIDHack(Collection* collection, + Status getExecutorIDHack(OperationContext* txn, + Collection* collection, CanonicalQuery* query, const QueryPlannerParams& plannerParams, PlanExecutor** out) { @@ -170,7 +171,7 @@ namespace mongo { LOG(2) << "Using idhack: " << query->toStringShort(); WorkingSet* ws = new WorkingSet(); - PlanStage* root = new IDHackStage(collection, query, ws); + PlanStage* root = new IDHackStage(txn, collection, query, ws); // Might have to filter out orphaned docs. if (plannerParams.options & QueryPlannerParams::INCLUDE_SHARD_FILTER) { @@ -201,7 +202,8 @@ namespace mongo { return Status::OK(); } - Status getExecutor(Collection* collection, + Status getExecutor(OperationContext* txn, + Collection* collection, CanonicalQuery* canonicalQuery, PlanExecutor** out, size_t plannerOptions) { @@ -226,7 +228,7 @@ namespace mongo { // If we have an _id index we can use the idhack runner. if (IDHackStage::supportsQuery(*canonicalQuery) && collection->getIndexCatalog()->findIdIndex()) { - return getExecutorIDHack(collection, canonicalQuery, plannerParams, out); + return getExecutorIDHack(txn, collection, canonicalQuery, plannerParams, out); } // Tailable: If the query requests tailable the collection must be capped. @@ -267,7 +269,7 @@ namespace mongo { WorkingSet* sharedWs = new WorkingSet(); PlanStage *root, *backupRoot=NULL; - verify(StageBuilder::build(collection, *qs, sharedWs, &root)); + verify(StageBuilder::build(txn, collection, *qs, sharedWs, &root)); if ((plannerParams.options & QueryPlannerParams::PRIVATE_IS_COUNT) && turnIxscanIntoCount(qs)) { LOG(2) << "Using fast count: " << canonicalQuery->toStringShort() @@ -278,7 +280,7 @@ namespace mongo { } } else if (NULL != backupQs) { - verify(StageBuilder::build(collection, *backupQs, sharedWs, &backupRoot)); + verify(StageBuilder::build(txn, collection, *backupQs, sharedWs, &backupRoot)); } // add a CachedPlanStage on top of the previous root @@ -298,7 +300,7 @@ namespace mongo { auto_ptr<WorkingSet> ws(new WorkingSet()); SubplanStage* subplan; - Status runnerStatus = SubplanStage::make(collection, ws.get(), plannerParams, + Status runnerStatus = SubplanStage::make(txn, collection, ws.get(), plannerParams, canonicalQuery, &subplan); if (!runnerStatus.isOK()) { return runnerStatus; @@ -308,10 +310,11 @@ namespace mongo { return Status::OK(); } - return getExecutorAlwaysPlan(collection, canonicalQuery, plannerParams, out); + return getExecutorAlwaysPlan(txn, collection, canonicalQuery, plannerParams, out); } - Status getExecutorAlwaysPlan(Collection* collection, + Status getExecutorAlwaysPlan(OperationContext* txn, + Collection* collection, CanonicalQuery* canonicalQuery, const QueryPlannerParams& plannerParams, PlanExecutor** execOut) { @@ -355,7 +358,8 @@ namespace mongo { // We're not going to cache anything that's fast count. WorkingSet* ws = new WorkingSet(); PlanStage* root; - verify(StageBuilder::build(collection, *solutions[i], ws, &root)); + + verify(StageBuilder::build(txn, collection, *solutions[i], ws, &root)); *execOut = new PlanExecutor(ws, root, solutions[i], collection); return Status::OK(); @@ -371,7 +375,8 @@ namespace mongo { // Only one possible plan. Run it. Build the stages from the solution. WorkingSet* ws = new WorkingSet(); PlanStage* root; - verify(StageBuilder::build(collection, *solutions[0], ws, &root)); + + verify(StageBuilder::build(txn, collection, *solutions[0], ws, &root)); *execOut = new PlanExecutor(ws, root, solutions[0], collection); return Status::OK(); @@ -391,7 +396,7 @@ namespace mongo { // version of StageBuild::build when WorkingSet is shared PlanStage* nextPlanRoot; - verify(StageBuilder::build(collection, *solutions[ix], + verify(StageBuilder::build(txn, collection, *solutions[ix], sharedWorkingSet, &nextPlanRoot)); // Owns none of the arguments @@ -581,7 +586,8 @@ namespace mongo { } // namespace - Status getExecutorCount(Collection* collection, + Status getExecutorCount(OperationContext* txn, + Collection* collection, const BSONObj& query, const BSONObj& hintObj, PlanExecutor** execOut) { @@ -602,7 +608,7 @@ namespace mongo { scoped_ptr<CanonicalQuery> cleanupCq(cq); - return getExecutor(collection, cq, execOut, QueryPlannerParams::PRIVATE_IS_COUNT); + return getExecutor(txn, collection, cq, execOut, QueryPlannerParams::PRIVATE_IS_COUNT); } // @@ -658,7 +664,8 @@ namespace mongo { return false; } - Status getExecutorDistinct(Collection* collection, + Status getExecutorDistinct(OperationContext* txn, + Collection* collection, const BSONObj& query, const std::string& field, PlanExecutor** out) { @@ -709,7 +716,7 @@ namespace mongo { scoped_ptr<CanonicalQuery> cleanupCq(cq); // Does not take ownership of its args. - return getExecutor(collection, cq, out); + return getExecutor(txn, collection, cq, out); } // @@ -758,7 +765,7 @@ namespace mongo { WorkingSet* ws = new WorkingSet(); PlanStage* root; - verify(StageBuilder::build(collection, *soln, ws, &root)); + verify(StageBuilder::build(txn, collection, *soln, ws, &root)); // Takes ownership of 'ws', 'root', and 'soln'. *out = new PlanExecutor(ws, root, soln, collection); return Status::OK(); @@ -768,7 +775,7 @@ namespace mongo { vector<QuerySolution*> solutions; status = QueryPlanner::plan(*cq, plannerParams, &solutions); if (!status.isOK()) { - return getExecutor(collection, cq, out); + return getExecutor(txn, collection, cq, out); } // We look for a solution that has an ixscan we can turn into a distinctixscan @@ -787,7 +794,7 @@ namespace mongo { // Build and return the SSR over solutions[i]. WorkingSet* ws = new WorkingSet(); PlanStage* root; - verify(StageBuilder::build(collection, *solutions[i], ws, &root)); + verify(StageBuilder::build(txn, collection, *solutions[i], ws, &root)); // Takes ownership of 'ws', 'root', and 'solutions[i]'. *out = new PlanExecutor(ws, root, solutions[i], collection); return Status::OK(); @@ -810,7 +817,7 @@ namespace mongo { cleanupCq.reset(cq); // Does not take ownership. - return getExecutor(collection, cq, out); + return getExecutor(txn, collection, cq, out); } } // namespace mongo diff --git a/src/mongo/db/query/get_executor.h b/src/mongo/db/query/get_executor.h index fc78e302709..f1eb40db2db 100644 --- a/src/mongo/db/query/get_executor.h +++ b/src/mongo/db/query/get_executor.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2013 10gen Inc. + * Copyright (C) 2013-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, @@ -62,7 +62,8 @@ namespace mongo { * If the query cannot be executed, returns a Status indicating why. Deletes * rawCanonicalQuery. */ - Status getExecutor(Collection* collection, + Status getExecutor(OperationContext* txn, + Collection* collection, CanonicalQuery* canonicalQuery, PlanExecutor** out, size_t plannerOptions = 0); @@ -94,7 +95,8 @@ namespace mongo { * possible values of a certain field. As such, we can skip lots of data in certain cases (see * body of method for detail). */ - Status getExecutorDistinct(Collection* collection, + Status getExecutorDistinct(OperationContext* txn, + Collection* collection, const BSONObj& query, const std::string& field, PlanExecutor** out); @@ -106,7 +108,8 @@ namespace mongo { * As such, with certain covered queries, we can skip the overhead of fetching etc. when * executing a count. */ - Status getExecutorCount(Collection* collection, + Status getExecutorCount(OperationContext* txn, + Collection* collection, const BSONObj& query, const BSONObj& hintObj, PlanExecutor** execOut); @@ -119,7 +122,8 @@ namespace mongo { * Returns the resulting executor through 'execOut'. The caller must delete 'execOut', * if an OK status is returned. */ - Status getExecutorAlwaysPlan(Collection* collection, + Status getExecutorAlwaysPlan(OperationContext* txn, + Collection* collection, CanonicalQuery* canonicalQuery, const QueryPlannerParams& plannerParams, PlanExecutor** execOut); diff --git a/src/mongo/db/query/get_runner.cpp b/src/mongo/db/query/get_runner.cpp index 3e027d60cff..429cbc15d33 100644 --- a/src/mongo/db/query/get_runner.cpp +++ b/src/mongo/db/query/get_runner.cpp @@ -69,7 +69,8 @@ namespace mongo { MONGO_LOG_DEFAULT_COMPONENT_FILE(::mongo::logger::LogComponent::kQuery); - Status getRunner(Collection* collection, + Status getRunner(OperationContext* txn, + Collection* collection, const std::string& ns, const BSONObj& unparsedQuery, Runner** outRunner, @@ -92,13 +93,13 @@ namespace mongo { collection->ns(), unparsedQuery, outCanonicalQuery, whereCallback); if (!status.isOK()) return status; - return getRunner(collection, *outCanonicalQuery, outRunner, plannerOptions); + return getRunner(txn, collection, *outCanonicalQuery, outRunner, plannerOptions); } LOG(2) << "Using idhack: " << unparsedQuery.toString(); *outCanonicalQuery = NULL; - *outRunner = new IDHackRunner(collection, unparsedQuery["_id"].wrap()); + *outRunner = new IDHackRunner(txn, collection, unparsedQuery["_id"].wrap()); return Status::OK(); } @@ -111,7 +112,8 @@ namespace mongo { /** * For a given query, get a runner. */ - Status getRunner(Collection* collection, + Status getRunner(OperationContext* txn, + Collection* collection, CanonicalQuery* rawCanonicalQuery, Runner** out, size_t plannerOptions) { @@ -132,7 +134,7 @@ namespace mongo { if (IDHackStage::supportsQuery(*canonicalQuery) && collection->getIndexCatalog()->findIdIndex()) { LOG(2) << "Using idhack: " << canonicalQuery->toStringShort(); - *out = new IDHackRunner(collection, canonicalQuery.release()); + *out = new IDHackRunner(txn, collection, canonicalQuery.release()); return Status::OK(); } @@ -179,7 +181,7 @@ namespace mongo { WorkingSet* sharedWs = new WorkingSet(); PlanStage *root, *backupRoot=NULL; - verify(StageBuilder::build(collection, *qs, sharedWs, &root)); + verify(StageBuilder::build(txn, collection, *qs, sharedWs, &root)); if ((plannerParams.options & QueryPlannerParams::PRIVATE_IS_COUNT) && turnIxscanIntoCount(qs)) { LOG(2) << "Using fast count: " << canonicalQuery->toStringShort() @@ -190,7 +192,7 @@ namespace mongo { } } else if (NULL != backupQs) { - verify(StageBuilder::build(collection, *backupQs, sharedWs, &backupRoot)); + verify(StageBuilder::build(txn, collection, *backupQs, sharedWs, &backupRoot)); } // add a CachedPlanStage on top of the previous root @@ -210,7 +212,7 @@ namespace mongo { LOG(2) << "Running query as sub-queries: " << canonicalQuery->toStringShort(); SubplanRunner* runner; - Status runnerStatus = SubplanRunner::make(collection, plannerParams, + Status runnerStatus = SubplanRunner::make(txn, collection, plannerParams, canonicalQuery.release(), &runner); if (!runnerStatus.isOK()) { return runnerStatus; @@ -220,10 +222,11 @@ namespace mongo { return Status::OK(); } - return getRunnerAlwaysPlan(collection, canonicalQuery.release(), plannerParams, out); + return getRunnerAlwaysPlan(txn, collection, canonicalQuery.release(), plannerParams, out); } - Status getRunnerAlwaysPlan(Collection* collection, + Status getRunnerAlwaysPlan(OperationContext* txn, + Collection* collection, CanonicalQuery* rawCanonicalQuery, const QueryPlannerParams& plannerParams, Runner** out) { @@ -266,7 +269,7 @@ namespace mongo { // We're not going to cache anything that's fast count. WorkingSet* ws = new WorkingSet(); PlanStage* root; - verify(StageBuilder::build(collection, *solutions[i], ws, &root)); + verify(StageBuilder::build(txn, collection, *solutions[i], ws, &root)); *out = new SingleSolutionRunner(collection, canonicalQuery.release(), solutions[i], @@ -285,7 +288,7 @@ namespace mongo { // Only one possible plan. Run it. Build the stages from the solution. WorkingSet* ws = new WorkingSet(); PlanStage* root; - verify(StageBuilder::build(collection, *solutions[0], ws, &root)); + verify(StageBuilder::build(txn, collection, *solutions[0], ws, &root)); // And, run the plan. *out = new SingleSolutionRunner(collection, @@ -310,7 +313,7 @@ namespace mongo { // version of StageBuild::build when WorkingSet is shared PlanStage* nextPlanRoot; - verify(StageBuilder::build(collection, *solutions[ix], + verify(StageBuilder::build(txn, collection, *solutions[ix], sharedWorkingSet, &nextPlanRoot)); // Owns none of the arguments @@ -506,7 +509,8 @@ namespace mongo { } // namespace - Status getRunnerCount(Collection* collection, + Status getRunnerCount(OperationContext* txn, + Collection* collection, const BSONObj& query, const BSONObj& hintObj, Runner** out) { @@ -525,14 +529,15 @@ namespace mongo { &cq, whereCallback)); - return getRunner(collection, cq, out, QueryPlannerParams::PRIVATE_IS_COUNT); + return getRunner(txn, collection, cq, out, QueryPlannerParams::PRIVATE_IS_COUNT); } // // Distinct hack // - Status getRunnerDistinct(Collection* collection, + Status getRunnerDistinct(OperationContext* txn, + Collection* collection, const BSONObj& query, const string& field, Runner** out) { @@ -581,7 +586,7 @@ namespace mongo { } // Takes ownership of cq. - return getRunner(collection, cq, out); + return getRunner(txn, collection, cq, out); } // @@ -628,7 +633,7 @@ namespace mongo { WorkingSet* ws = new WorkingSet(); PlanStage* root; - verify(StageBuilder::build(collection, *soln, ws, &root)); + verify(StageBuilder::build(txn, collection, *soln, ws, &root)); *out = new SingleSolutionRunner(collection, cq, soln, root, ws); return Status::OK(); } @@ -637,7 +642,7 @@ namespace mongo { vector<QuerySolution*> solutions; status = QueryPlanner::plan(*cq, plannerParams, &solutions); if (!status.isOK()) { - return getRunner(collection, cq, out); + return getRunner(txn, collection, cq, out); } // We look for a solution that has an ixscan we can turn into a distinctixscan @@ -656,7 +661,7 @@ namespace mongo { // Build and return the SSR over solutions[i]. WorkingSet* ws = new WorkingSet(); PlanStage* root; - verify(StageBuilder::build(collection, *solutions[i], ws, &root)); + verify(StageBuilder::build(txn, collection, *solutions[i], ws, &root)); *out = new SingleSolutionRunner(collection, cq, solutions[i], root, ws); return Status::OK(); } @@ -677,7 +682,7 @@ namespace mongo { } // Takes ownership of cq. - return getRunner(collection, cq, out); + return getRunner(txn, collection, cq, out); } ScopedRunnerRegistration::ScopedRunnerRegistration(Runner* runner) diff --git a/src/mongo/db/query/get_runner.h b/src/mongo/db/query/get_runner.h index eabc78d3bdd..2d9dd75c88e 100644 --- a/src/mongo/db/query/get_runner.h +++ b/src/mongo/db/query/get_runner.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2013 10gen Inc. + * Copyright (C) 2013-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, @@ -37,6 +37,7 @@ namespace mongo { class Collection; + class OperationContext; /** * Get a runner for a query. Takes ownership of rawCanonicalQuery. @@ -47,7 +48,8 @@ namespace mongo { * If the query cannot be executed, returns a Status indicating why. Deletes * rawCanonicalQuery. */ - Status getRunner(Collection* collection, + Status getRunner(OperationContext* txn, + Collection* collection, CanonicalQuery* rawCanonicalQuery, Runner** out, size_t plannerOptions = 0); @@ -63,7 +65,8 @@ namespace mongo { * the returned runner. On failure, returns other status values, and '*outRunner' and * '*outCanonicalQuery' have unspecified values. */ - Status getRunner(Collection* collection, + Status getRunner(OperationContext* txn, + Collection* collection, const std::string& ns, const BSONObj& unparsedQuery, Runner** outRunner, @@ -76,7 +79,8 @@ namespace mongo { * possible values of a certain field. As such, we can skip lots of data in certain cases (see * body of method for detail). */ - Status getRunnerDistinct(Collection* collection, + Status getRunnerDistinct(OperationContext* txn, + Collection* collection, const BSONObj& query, const std::string& field, Runner** out); @@ -88,7 +92,8 @@ namespace mongo { * As such, with certain covered queries, we can skip the overhead of fetching etc. when * executing a count. */ - Status getRunnerCount(Collection* collection, + Status getRunnerCount(OperationContext* txn, + Collection* collection, const BSONObj& query, const BSONObj& hintObj, Runner** out); @@ -96,7 +101,8 @@ namespace mongo { /** * Get a runner for a query. Ignores the cache and always plans the full query. */ - Status getRunnerAlwaysPlan(Collection* collection, + Status getRunnerAlwaysPlan(OperationContext* txn, + Collection* collection, CanonicalQuery* rawCanonicalQuery, const QueryPlannerParams& plannerParams, Runner** out); diff --git a/src/mongo/db/query/idhack_runner.cpp b/src/mongo/db/query/idhack_runner.cpp index b9c0da6f82b..5382a4e4bfa 100644 --- a/src/mongo/db/query/idhack_runner.cpp +++ b/src/mongo/db/query/idhack_runner.cpp @@ -1,5 +1,5 @@ /** - * Copyright 2013 MongoDB Inc. + * Copyright 2013-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, @@ -43,8 +43,11 @@ namespace mongo { - IDHackRunner::IDHackRunner(const Collection* collection, CanonicalQuery* query) - : _collection(collection), + IDHackRunner::IDHackRunner(OperationContext* txn, + const Collection* collection, + CanonicalQuery* query) + : _txn(txn), + _collection(collection), _key(query->getQueryObj()["_id"].wrap()), _query(query), _killed(false), @@ -52,8 +55,9 @@ namespace mongo { _nscanned(0), _nscannedObjects(0) { } - IDHackRunner::IDHackRunner(Collection* collection, const BSONObj& key) - : _collection(collection), + IDHackRunner::IDHackRunner(OperationContext* txn, Collection* collection, const BSONObj& key) + : _txn(txn), + _collection(collection), _key(key), _query(NULL), _killed(false), @@ -80,7 +84,7 @@ namespace mongo { static_cast<const BtreeBasedAccessMethod*>(catalog->getIndex(idDesc)); // Look up the key by going directly to the Btree. - DiskLoc loc = accessMethod->findSingle( _key ); + DiskLoc loc = accessMethod->findSingle(_txn, _key ); // Key not found. if (loc.isNull()) { diff --git a/src/mongo/db/query/idhack_runner.h b/src/mongo/db/query/idhack_runner.h index 23e2d02691c..a6747a6d83b 100644 --- a/src/mongo/db/query/idhack_runner.h +++ b/src/mongo/db/query/idhack_runner.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2013 10gen Inc. + * Copyright (C) 2013-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, @@ -50,10 +50,14 @@ namespace mongo { class IDHackRunner : public Runner { public: - /** Takes ownership of all the arguments -collection. */ - IDHackRunner(const Collection* collection, CanonicalQuery* query); + /** Takes ownership of all the arguments -txn, -collection. */ + IDHackRunner(OperationContext* txn, + const Collection* collection, + CanonicalQuery* query); - IDHackRunner(Collection* collection, const BSONObj& key); + IDHackRunner(OperationContext* txn, + Collection* collection, + const BSONObj& key); virtual ~IDHackRunner(); @@ -88,6 +92,9 @@ namespace mongo { */ BSONObj applyProjection(const BSONObj& docObj) const; + // transactional context for read locks. Not owned by us + OperationContext* _txn; + // Not owned here. const Collection* _collection; diff --git a/src/mongo/db/query/internal_plans.h b/src/mongo/db/query/internal_plans.h index c6a576d80f9..dae7af1c521 100644 --- a/src/mongo/db/query/internal_plans.h +++ b/src/mongo/db/query/internal_plans.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2013 10gen Inc. + * Copyright (C) 2013-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, @@ -38,6 +38,8 @@ namespace mongo { + class OperationContext; + /** * The internal planner is a one-stop shop for "off-the-shelf" plans. Most internal procedures * that do not require advanced queries could be served by plans already in here. @@ -62,7 +64,8 @@ namespace mongo { /** * Return a collection scan. Caller owns pointer. */ - static Runner* collectionScan(const StringData& ns, + static Runner* collectionScan(OperationContext* txn, + const StringData& ns, Collection* collection, const Direction direction = FORWARD, const DiskLoc startLoc = DiskLoc()) { @@ -84,14 +87,15 @@ namespace mongo { } WorkingSet* ws = new WorkingSet(); - CollectionScan* cs = new CollectionScan(params, ws, NULL); + CollectionScan* cs = new CollectionScan(txn, params, ws, NULL); return new InternalRunner(collection, cs, ws); } /** * Return an index scan. Caller owns returned pointer. */ - static Runner* indexScan(const Collection* collection, + static Runner* indexScan(OperationContext* txn, + const Collection* collection, const IndexDescriptor* descriptor, const BSONObj& startKey, const BSONObj& endKey, bool endKeyInclusive, Direction direction = FORWARD, @@ -108,11 +112,11 @@ namespace mongo { params.bounds.endKeyInclusive = endKeyInclusive; WorkingSet* ws = new WorkingSet(); - IndexScan* ix = new IndexScan(params, ws, NULL); + IndexScan* ix = new IndexScan(txn, params, ws, NULL); if (IXSCAN_FETCH & options) { return new InternalRunner( - collection, new FetchStage(ws, ix, NULL, collection), ws); + collection, new FetchStage(ws, ix, NULL, collection), ws); } else { return new InternalRunner(collection, ix, ws); diff --git a/src/mongo/db/query/internal_runner.h b/src/mongo/db/query/internal_runner.h index d6af5e43db2..d01a39606f6 100644 --- a/src/mongo/db/query/internal_runner.h +++ b/src/mongo/db/query/internal_runner.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2013 10gen Inc. + * Copyright (C) 2013-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, @@ -39,11 +39,12 @@ namespace mongo { class BSONObj; class CanonicalQuery; class DiskLoc; + class OperationContext; class PlanExecutor; + struct PlanInfo; class PlanStage; struct QuerySolution; class TypeExplain; - struct PlanInfo; class WorkingSet; /** diff --git a/src/mongo/db/query/new_find.cpp b/src/mongo/db/query/new_find.cpp index ac4e4d1766b..db2afd847fb 100644 --- a/src/mongo/db/query/new_find.cpp +++ b/src/mongo/db/query/new_find.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2013 10gen Inc. + * Copyright (C) 2013-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, @@ -365,7 +365,10 @@ namespace mongo { return qr; } - Status getOplogStartHack(Collection* collection, CanonicalQuery* cq, Runner** runnerOut) { + Status getOplogStartHack(OperationContext* txn, + Collection* collection, + CanonicalQuery* cq, + Runner** runnerOut) { if ( collection == NULL ) return Status(ErrorCodes::InternalError, "getOplogStartHack called with a NULL collection" ); @@ -398,7 +401,7 @@ namespace mongo { // Make an oplog start finding stage. WorkingSet* oplogws = new WorkingSet(); - OplogStart* stage = new OplogStart(collection, tsExpr, oplogws); + OplogStart* stage = new OplogStart(txn, collection, tsExpr, oplogws); // Takes ownership of ws and stage. auto_ptr<InternalRunner> runner(new InternalRunner(collection, stage, oplogws)); @@ -408,7 +411,7 @@ namespace mongo { Runner::RunnerState state = runner->getNext(NULL, &startLoc); // This is normal. The start of the oplog is the beginning of the collection. - if (Runner::RUNNER_EOF == state) { return getRunner(collection, cq, runnerOut); } + if (Runner::RUNNER_EOF == state) { return getRunner(txn, collection, cq, runnerOut); } // This is not normal. An error was encountered. if (Runner::RUNNER_ADVANCED != state) { @@ -426,7 +429,7 @@ namespace mongo { params.tailable = cq->getParsed().hasOption(QueryOption_CursorTailable); WorkingSet* ws = new WorkingSet(); - CollectionScan* cs = new CollectionScan(params, ws, cq->root()); + CollectionScan* cs = new CollectionScan(txn, params, ws, cq->root()); // Takes ownership of cq, cs, ws. *runnerOut = new SingleSolutionRunner(collection, cq, NULL, cs, ws); return Status::OK(); @@ -528,7 +531,7 @@ namespace mongo { bb.skip(sizeof(QueryResult)); PlanExecutor* rawExec; - Status execStatus = getExecutor(collection, cq, &rawExec, options); + Status execStatus = getExecutor(txn, collection, cq, &rawExec, options); if (!execStatus.isOK()) { uasserted(17510, "Explain error: " + execStatus.reason()); } @@ -581,7 +584,7 @@ namespace mongo { rawRunner = new EOFRunner(cq, cq->ns()); } else if (pq.hasOption(QueryOption_OplogReplay)) { - status = getOplogStartHack(collection, cq, &rawRunner); + status = getOplogStartHack(txn, collection, cq, &rawRunner); } else { // Takes ownership of cq. @@ -589,7 +592,7 @@ namespace mongo { if (shardingState.needCollectionMetadata(pq.ns())) { options |= QueryPlannerParams::INCLUDE_SHARD_FILTER; } - status = getRunner(collection, cq, &rawRunner, options); + status = getRunner(txn, collection, cq, &rawRunner, options); } if (!status.isOK()) { diff --git a/src/mongo/db/query/stage_builder.cpp b/src/mongo/db/query/stage_builder.cpp index a332088c1b2..5e29d472dfb 100644 --- a/src/mongo/db/query/stage_builder.cpp +++ b/src/mongo/db/query/stage_builder.cpp @@ -53,7 +53,8 @@ namespace mongo { - PlanStage* buildStages(Collection* collection, + PlanStage* buildStages(OperationContext* txn, + Collection* collection, const QuerySolution& qsol, const QuerySolutionNode* root, WorkingSet* ws) { @@ -65,7 +66,7 @@ namespace mongo { params.direction = (csn->direction == 1) ? CollectionScanParams::FORWARD : CollectionScanParams::BACKWARD; params.maxScan = csn->maxScan; - return new CollectionScan(params, ws, csn->filter.get()); + return new CollectionScan(txn, params, ws, csn->filter.get()); } else if (STAGE_IXSCAN == root->getType()) { const IndexScanNode* ixn = static_cast<const IndexScanNode*>(root); @@ -89,17 +90,17 @@ namespace mongo { params.direction = ixn->direction; params.maxScan = ixn->maxScan; params.addKeyMetadata = ixn->addKeyMetadata; - return new IndexScan(params, ws, ixn->filter.get()); + return new IndexScan(txn, params, ws, ixn->filter.get()); } else if (STAGE_FETCH == root->getType()) { const FetchNode* fn = static_cast<const FetchNode*>(root); - PlanStage* childStage = buildStages(collection, qsol, fn->children[0], ws); + PlanStage* childStage = buildStages(txn, collection, qsol, fn->children[0], ws); if (NULL == childStage) { return NULL; } return new FetchStage(ws, childStage, fn->filter.get(), collection); } else if (STAGE_SORT == root->getType()) { const SortNode* sn = static_cast<const SortNode*>(root); - PlanStage* childStage = buildStages(collection, qsol, sn->children[0], ws); + PlanStage* childStage = buildStages(txn, collection, qsol, sn->children[0], ws); if (NULL == childStage) { return NULL; } SortStageParams params; params.collection = collection; @@ -110,7 +111,7 @@ namespace mongo { } else if (STAGE_PROJECTION == root->getType()) { const ProjectionNode* pn = static_cast<const ProjectionNode*>(root); - PlanStage* childStage = buildStages(collection, qsol, pn->children[0], ws); + PlanStage* childStage = buildStages(txn, collection, qsol, pn->children[0], ws); if (NULL == childStage) { return NULL; } ProjectionStageParams params(WhereCallbackReal(collection->ns().db())); @@ -135,13 +136,13 @@ namespace mongo { } else if (STAGE_LIMIT == root->getType()) { const LimitNode* ln = static_cast<const LimitNode*>(root); - PlanStage* childStage = buildStages(collection, qsol, ln->children[0], ws); + PlanStage* childStage = buildStages(txn, collection, qsol, ln->children[0], ws); if (NULL == childStage) { return NULL; } return new LimitStage(ln->limit, ws, childStage); } else if (STAGE_SKIP == root->getType()) { const SkipNode* sn = static_cast<const SkipNode*>(root); - PlanStage* childStage = buildStages(collection, qsol, sn->children[0], ws); + PlanStage* childStage = buildStages(txn, collection, qsol, sn->children[0], ws); if (NULL == childStage) { return NULL; } return new SkipStage(sn->skip, ws, childStage); } @@ -149,7 +150,7 @@ namespace mongo { const AndHashNode* ahn = static_cast<const AndHashNode*>(root); auto_ptr<AndHashStage> ret(new AndHashStage(ws, ahn->filter.get(), collection)); for (size_t i = 0; i < ahn->children.size(); ++i) { - PlanStage* childStage = buildStages(collection, qsol, ahn->children[i], ws); + PlanStage* childStage = buildStages(txn, collection, qsol, ahn->children[i], ws); if (NULL == childStage) { return NULL; } ret->addChild(childStage); } @@ -159,7 +160,7 @@ namespace mongo { const OrNode * orn = static_cast<const OrNode*>(root); auto_ptr<OrStage> ret(new OrStage(ws, orn->dedup, orn->filter.get())); for (size_t i = 0; i < orn->children.size(); ++i) { - PlanStage* childStage = buildStages(collection, qsol, orn->children[i], ws); + PlanStage* childStage = buildStages(txn, collection, qsol, orn->children[i], ws); if (NULL == childStage) { return NULL; } ret->addChild(childStage); } @@ -169,7 +170,7 @@ namespace mongo { const AndSortedNode* asn = static_cast<const AndSortedNode*>(root); auto_ptr<AndSortedStage> ret(new AndSortedStage(ws, asn->filter.get(), collection)); for (size_t i = 0; i < asn->children.size(); ++i) { - PlanStage* childStage = buildStages(collection, qsol, asn->children[i], ws); + PlanStage* childStage = buildStages(txn, collection, qsol, asn->children[i], ws); if (NULL == childStage) { return NULL; } ret->addChild(childStage); } @@ -182,7 +183,7 @@ namespace mongo { params.pattern = msn->sort; auto_ptr<MergeSortStage> ret(new MergeSortStage(params, ws, collection)); for (size_t i = 0; i < msn->children.size(); ++i) { - PlanStage* childStage = buildStages(collection, qsol, msn->children[i], ws); + PlanStage* childStage = buildStages(txn, collection, qsol, msn->children[i], ws); if (NULL == childStage) { return NULL; } ret->addChild(childStage); } @@ -198,7 +199,7 @@ namespace mongo { params.numWanted = node->numWanted; params.addPointMeta = node->addPointMeta; params.addDistMeta = node->addDistMeta; - return new TwoDNear(params, ws); + return new TwoDNear(txn, params, ws); } else if (STAGE_GEO_NEAR_2DSPHERE == root->getType()) { const GeoNear2DSphereNode* node = static_cast<const GeoNear2DSphereNode*>(root); @@ -210,7 +211,7 @@ namespace mongo { params.filter = node->filter.get(); params.addPointMeta = node->addPointMeta; params.addDistMeta = node->addDistMeta; - return new S2NearStage(params, ws); + return new S2NearStage(txn, params, ws); } else if (STAGE_TEXT == root->getType()) { const TextNode* node = static_cast<const TextNode*>(root); @@ -245,18 +246,18 @@ namespace mongo { return NULL; } - return new TextStage(params, ws, node->filter.get()); + return new TextStage(txn, params, ws, node->filter.get()); } else if (STAGE_SHARDING_FILTER == root->getType()) { const ShardingFilterNode* fn = static_cast<const ShardingFilterNode*>(root); - PlanStage* childStage = buildStages(collection, qsol, fn->children[0], ws); + PlanStage* childStage = buildStages(txn, collection, qsol, fn->children[0], ws); if (NULL == childStage) { return NULL; } return new ShardFilterStage(shardingState.getCollectionMetadata(collection->ns()), ws, childStage); } else if (STAGE_KEEP_MUTATIONS == root->getType()) { const KeepMutationsNode* km = static_cast<const KeepMutationsNode*>(root); - PlanStage* childStage = buildStages(collection, qsol, km->children[0], ws); + PlanStage* childStage = buildStages(txn, collection, qsol, km->children[0], ws); if (NULL == childStage) { return NULL; } return new KeepMutationsStage(km->filter.get(), ws, childStage); } @@ -275,7 +276,7 @@ namespace mongo { params.direction = dn->direction; params.bounds = dn->bounds; params.fieldNo = dn->fieldNo; - return new DistinctScan(params, ws); + return new DistinctScan(txn, params, ws); } else if (STAGE_COUNT == root->getType()) { const CountNode* cn = static_cast<const CountNode*>(root); @@ -294,7 +295,7 @@ namespace mongo { params.endKey = cn->endKey; params.endKeyInclusive = cn->endKeyInclusive; - return new Count(params, ws); + return new Count(txn, params, ws); } else { mongoutils::str::stream ss; @@ -306,14 +307,15 @@ namespace mongo { } // static (this one is used for Cached and MultiPlanStage) - bool StageBuilder::build(Collection* collection, + bool StageBuilder::build(OperationContext* txn, + Collection* collection, const QuerySolution& solution, WorkingSet* wsIn, PlanStage** rootOut) { if (NULL == wsIn || NULL == rootOut) { return false; } QuerySolutionNode* solutionNode = solution.root.get(); if (NULL == solutionNode) { return false; } - return NULL != (*rootOut = buildStages(collection, solution, solutionNode, wsIn)); + return NULL != (*rootOut = buildStages(txn, collection, solution, solutionNode, wsIn)); } } // namespace mongo diff --git a/src/mongo/db/query/stage_builder.h b/src/mongo/db/query/stage_builder.h index 9f3c9f20d60..c9c88e800bd 100644 --- a/src/mongo/db/query/stage_builder.h +++ b/src/mongo/db/query/stage_builder.h @@ -34,6 +34,8 @@ namespace mongo { + class OperationContext; + /** * The StageBuilder converts a QuerySolution to an executable tree of PlanStage(s). */ @@ -47,7 +49,8 @@ namespace mongo { * * Returns false otherwise. *rootOut and *wsOut are invalid. */ - static bool build(Collection* collection, + static bool build(OperationContext* txn, + Collection* collection, const QuerySolution& solution, WorkingSet* wsIn, PlanStage** rootOut); diff --git a/src/mongo/db/query/subplan_runner.cpp b/src/mongo/db/query/subplan_runner.cpp index 765bd236a90..c107f829c77 100644 --- a/src/mongo/db/query/subplan_runner.cpp +++ b/src/mongo/db/query/subplan_runner.cpp @@ -93,11 +93,12 @@ namespace mongo { } // static - Status SubplanRunner::make(Collection* collection, + Status SubplanRunner::make(OperationContext* txn, + Collection* collection, const QueryPlannerParams& params, CanonicalQuery* cq, SubplanRunner** out) { - auto_ptr<SubplanRunner> autoRunner(new SubplanRunner(collection, params, cq)); + auto_ptr<SubplanRunner> autoRunner(new SubplanRunner(txn, collection, params, cq)); Status planningStatus = autoRunner->planSubqueries(); if (!planningStatus.isOK()) { return planningStatus; @@ -107,10 +108,12 @@ namespace mongo { return Status::OK(); } - SubplanRunner::SubplanRunner(Collection* collection, + SubplanRunner::SubplanRunner(OperationContext* txn, + Collection* collection, const QueryPlannerParams& params, CanonicalQuery* cq) - : _state(SubplanRunner::PLANNING), + : _txn(txn), + _state(SubplanRunner::PLANNING), _collection(collection), _plannerParams(params), _query(cq), @@ -150,7 +153,8 @@ namespace mongo { Runner* runner; Status status = getRunnerAlwaysPlan( - _collection, _query.release(), _plannerParams, &runner); + _txn, _collection, _query.release(), _plannerParams, &runner + ); if (!status.isOK()) { // We utterly failed. @@ -315,7 +319,8 @@ namespace mongo { // Dump all the solutions into the MPR. for (size_t ix = 0; ix < solutions.size(); ++ix) { PlanStage* nextPlanRoot; - verify(StageBuilder::build(_collection, + verify(StageBuilder::build(_txn, + _collection, *solutions[ix], sharedWorkingSet, &nextPlanRoot)); @@ -404,7 +409,7 @@ namespace mongo { MultiPlanStage* multiPlanStage = new MultiPlanStage(_collection, _query.get()); WorkingSet* ws = new WorkingSet(); PlanStage* root; - verify(StageBuilder::build(_collection, *soln, ws, &root)); + verify(StageBuilder::build(_txn, _collection, *soln, ws, &root)); multiPlanStage->addPlan(soln, root, ws); // Takes ownership first two arguments. multiPlanStage->pickBestPlan(); diff --git a/src/mongo/db/query/subplan_runner.h b/src/mongo/db/query/subplan_runner.h index 907fe719363..896772450ad 100644 --- a/src/mongo/db/query/subplan_runner.h +++ b/src/mongo/db/query/subplan_runner.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2013 10gen Inc. + * Copyright (C) 2013-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, @@ -42,6 +42,7 @@ namespace mongo { class BSONObj; class CanonicalQuery; class DiskLoc; + class OperationContext; class TypeExplain; struct PlanInfo; @@ -53,7 +54,8 @@ namespace mongo { * * 'out' is valid only if an OK status is returned. */ - static Status make(Collection* collection, + static Status make(OperationContext* txn, + Collection* collection, const QueryPlannerParams& params, CanonicalQuery* cq, SubplanRunner** out); @@ -94,7 +96,8 @@ namespace mongo { Status planSubqueries(); private: - SubplanRunner(Collection* collection, + SubplanRunner(OperationContext* txn, + Collection* collection, const QueryPlannerParams& params, CanonicalQuery* cq); @@ -105,6 +108,9 @@ namespace mongo { RUNNING, }; + // transactional context for read locks. Not owned by us + OperationContext* _txn; + SubplanRunnerState _state; Collection* _collection; diff --git a/src/mongo/db/repl/master_slave.cpp b/src/mongo/db/repl/master_slave.cpp index 54afae7e969..00c7e40d86f 100644 --- a/src/mongo/db/repl/master_slave.cpp +++ b/src/mongo/db/repl/master_slave.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2008 10gen Inc. +* Copyright (C) 2008-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, @@ -252,7 +252,8 @@ namespace repl { // add if missing int n = 0; auto_ptr<Runner> runner( - InternalPlanner::collectionScan(localSources, + InternalPlanner::collectionScan(txn, + localSources, ctx.db()->getCollection(txn, localSources))); BSONObj obj; Runner::RunnerState state; @@ -296,7 +297,8 @@ namespace repl { } auto_ptr<Runner> runner( - InternalPlanner::collectionScan(localSources, + InternalPlanner::collectionScan(txn, + localSources, ctx.db()->getCollection(txn, localSources))); BSONObj obj; Runner::RunnerState state; diff --git a/src/mongo/db/repl/oplog.cpp b/src/mongo/db/repl/oplog.cpp index dbe5fd62b79..f8414766eea 100644 --- a/src/mongo/db/repl/oplog.cpp +++ b/src/mongo/db/repl/oplog.cpp @@ -1,7 +1,7 @@ // @file oplog.cpp /** -* Copyright (C) 2008 10gen Inc. +* Copyright (C) 2008-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, @@ -473,7 +473,7 @@ namespace repl { if ( collection ) { if (replSettings.oplogSize != 0) { - int o = (int)(collection->getRecordStore()->storageSize() / ( 1024 * 1024 ) ); + int o = (int)(collection->getRecordStore()->storageSize(&txn) / ( 1024 * 1024 ) ); int n = (int)(replSettings.oplogSize / (1024 * 1024)); if ( n != o ) { stringstream ss; diff --git a/src/mongo/db/repl/repl_info.cpp b/src/mongo/db/repl/repl_info.cpp index 17f5b893cd5..740cc8f044a 100644 --- a/src/mongo/db/repl/repl_info.cpp +++ b/src/mongo/db/repl/repl_info.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2008 10gen Inc. +* Copyright (C) 2008-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, @@ -83,7 +83,8 @@ namespace repl { const char* localSources = "local.sources"; Client::ReadContext ctx(txn, localSources); auto_ptr<Runner> runner( - InternalPlanner::collectionScan(localSources, + InternalPlanner::collectionScan(txn, + localSources, ctx.ctx().db()->getCollection(txn, localSources))); BSONObj obj; diff --git a/src/mongo/db/repl/rs_rollback.cpp b/src/mongo/db/repl/rs_rollback.cpp index 321885f60d7..32093b02374 100644 --- a/src/mongo/db/repl/rs_rollback.cpp +++ b/src/mongo/db/repl/rs_rollback.cpp @@ -1,6 +1,6 @@ /* @file rs_rollback.cpp * -* Copyright (C) 2008 10gen Inc. +* Copyright (C) 2008-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, @@ -237,7 +237,8 @@ namespace repl { Client::Context ctx(txn, rsoplog); boost::scoped_ptr<Runner> runner( - InternalPlanner::collectionScan(rsoplog, + InternalPlanner::collectionScan(txn, + rsoplog, ctx.db()->getCollection(txn, rsoplog), InternalPlanner::BACKWARD)); diff --git a/src/mongo/db/storage/heap1/heap1_btree_impl.cpp b/src/mongo/db/storage/heap1/heap1_btree_impl.cpp index 25695ccef65..2d5ae2fc63b 100644 --- a/src/mongo/db/storage/heap1/heap1_btree_impl.cpp +++ b/src/mongo/db/storage/heap1/heap1_btree_impl.cpp @@ -279,12 +279,12 @@ namespace { } - virtual void fullValidate(long long *numKeysOut) { + virtual void fullValidate(OperationContext* txn, long long *numKeysOut) { // TODO check invariants? *numKeysOut = _data->size(); } - virtual Status dupKeyCheck(const BSONObj& key, const DiskLoc& loc) { + virtual Status dupKeyCheck(OperationContext* txn, const BSONObj& key, const DiskLoc& loc) { invariant(!hasFieldNames(key)); if (isDup(*_data, key, loc)) return dupKeyError(key); @@ -302,8 +302,9 @@ namespace { class ForwardCursor : public BtreeInterface::Cursor { public: - ForwardCursor(const IndexSet& data) - : _data(data), + ForwardCursor(const IndexSet& data, OperationContext* txn) + : _txn(txn), + _data(data), _it(data.end()) {} @@ -387,6 +388,7 @@ namespace { } private: + OperationContext* _txn; // not owned const IndexSet& _data; IndexSet::const_iterator _it; @@ -399,8 +401,9 @@ namespace { // TODO see if this can share any code with ForwardIterator class ReverseCursor : public BtreeInterface::Cursor { public: - ReverseCursor(const IndexSet& data) - : _data(data), + ReverseCursor(const IndexSet& data, OperationContext* txn) + : _txn(txn), + _data(data), _it(data.rend()) {} @@ -499,6 +502,7 @@ namespace { return IndexSet::const_reverse_iterator(it); } + OperationContext* _txn; // not owned const IndexSet& _data; IndexSet::const_reverse_iterator _it; @@ -508,12 +512,12 @@ namespace { DiskLoc _savedLoc; }; - virtual BtreeInterface::Cursor* newCursor(int direction) const { + virtual BtreeInterface::Cursor* newCursor(OperationContext* txn, int direction) const { if (direction == 1) - return new ForwardCursor(*_data); + return new ForwardCursor(*_data, txn); invariant(direction == -1); - return new ReverseCursor(*_data); + return new ReverseCursor(*_data, txn); } virtual Status initAsEmpty(OperationContext* txn) { diff --git a/src/mongo/db/storage/heap1/heap1_database_catalog_entry.h b/src/mongo/db/storage/heap1/heap1_database_catalog_entry.h index 825477c5ffb..1268d26ff3e 100644 --- a/src/mongo/db/storage/heap1/heap1_database_catalog_entry.h +++ b/src/mongo/db/storage/heap1/heap1_database_catalog_entry.h @@ -150,7 +150,7 @@ namespace mongo { const StringData& idxName, long long newExpireSeconds ); - CollectionOptions getCollectionOptions() const { return options; } + CollectionOptions getCollectionOptions(OperationContext* txn) const { return options; } CollectionOptions options; scoped_ptr<HeapRecordStore> rs; diff --git a/src/mongo/db/storage/mmap_v1/mmap_v1_database_catalog_entry.cpp b/src/mongo/db/storage/mmap_v1/mmap_v1_database_catalog_entry.cpp index cf1d805900d..a9ed7d8650f 100644 --- a/src/mongo/db/storage/mmap_v1/mmap_v1_database_catalog_entry.cpp +++ b/src/mongo/db/storage/mmap_v1/mmap_v1_database_catalog_entry.cpp @@ -180,7 +180,7 @@ namespace mongo { invariant( details ); RecordStoreV1Base* systemIndexRecordStore = _getIndexRecordStore(); - scoped_ptr<RecordIterator> it( systemIndexRecordStore->getIterator() ); + scoped_ptr<RecordIterator> it( systemIndexRecordStore->getIterator(txn) ); while ( !it->isEOF() ) { DiskLoc loc = it->getNext(); @@ -289,7 +289,7 @@ namespace mongo { BSONObj oldSpec; { RecordStoreV1Base* rs = _getNamespaceRecordStore(); - scoped_ptr<RecordIterator> it( rs->getIterator() ); + scoped_ptr<RecordIterator> it( rs->getIterator(txn) ); while ( !it->isEOF() ) { DiskLoc loc = it->getNext(); BSONObj entry = it->dataFor( loc ).toBson(); @@ -481,7 +481,7 @@ namespace mongo { &_extentManager, false ) ); - if ( nsEntry->recordStore->storageSize() == 0 ) + if ( nsEntry->recordStore->storageSize( txn ) == 0 ) nsEntry->recordStore->increaseStorageSize( txn, _extentManager.initialSize( 128 ), -1 ); } @@ -497,7 +497,7 @@ namespace mongo { &_extentManager, true ) ); - if ( indexEntry->recordStore->storageSize() == 0 ) + if ( indexEntry->recordStore->storageSize( txn ) == 0 ) indexEntry->recordStore->increaseStorageSize( txn, _extentManager.initialSize( 128 ), -1 ); } @@ -581,10 +581,10 @@ namespace mongo { // Must do this at least once, otherwise we leave the collection with no // extents, which is invalid. int sz = _massageExtentSize( &_extentManager, - options.cappedSize - rs->storageSize() ); + options.cappedSize - rs->storageSize(txn) ); sz &= 0xffffff00; rs->increaseStorageSize( txn, sz, -1 ); - } while( rs->storageSize() < options.cappedSize ); + } while( rs->storageSize(txn) < options.cappedSize ); } else { rs->increaseStorageSize( txn, _extentManager.initialSize( 128 ), -1 ); @@ -773,7 +773,7 @@ namespace mongo { RecordStoreV1Base* rs = _getNamespaceRecordStore(); invariant( rs ); - scoped_ptr<RecordIterator> it( rs->getIterator() ); + scoped_ptr<RecordIterator> it( rs->getIterator(txn) ); while ( !it->isEOF() ) { DiskLoc loc = it->getNext(); BSONObj entry = it->dataFor( loc ).toBson(); @@ -785,7 +785,8 @@ namespace mongo { } } - CollectionOptions MMAPV1DatabaseCatalogEntry::getCollectionOptions( const StringData& ns ) const { + CollectionOptions MMAPV1DatabaseCatalogEntry::getCollectionOptions( OperationContext* txn, + const StringData& ns ) const { if ( nsToCollectionSubstring( ns ) == "system.namespaces" ) { return CollectionOptions(); } @@ -793,7 +794,7 @@ namespace mongo { RecordStoreV1Base* rs = _getNamespaceRecordStore(); invariant( rs ); - scoped_ptr<RecordIterator> it( rs->getIterator() ); + scoped_ptr<RecordIterator> it( rs->getIterator(txn) ); while ( !it->isEOF() ) { DiskLoc loc = it->getNext(); BSONObj entry = it->dataFor( loc ).toBson(); diff --git a/src/mongo/db/storage/mmap_v1/mmap_v1_database_catalog_entry.h b/src/mongo/db/storage/mmap_v1/mmap_v1_database_catalog_entry.h index 9215ef37d93..16a88b84ede 100644 --- a/src/mongo/db/storage/mmap_v1/mmap_v1_database_catalog_entry.h +++ b/src/mongo/db/storage/mmap_v1/mmap_v1_database_catalog_entry.h @@ -101,7 +101,8 @@ namespace mongo { const MmapV1ExtentManager* getExtentManager() const { return &_extentManager; } MmapV1ExtentManager* getExtentManager() { return &_extentManager; } - CollectionOptions getCollectionOptions( const StringData& ns ) const; + CollectionOptions getCollectionOptions( OperationContext* txn, + const StringData& ns ) const; private: diff --git a/src/mongo/db/storage/mmap_v1/repair_database.cpp b/src/mongo/db/storage/mmap_v1/repair_database.cpp index 836827a0ee6..8fb06a5eae6 100644 --- a/src/mongo/db/storage/mmap_v1/repair_database.cpp +++ b/src/mongo/db/storage/mmap_v1/repair_database.cpp @@ -345,9 +345,10 @@ namespace mongo { Client::Context ctx(txn, ns ); Collection* coll = originalDatabase->getCollection( txn, ns ); if ( coll ) { - scoped_ptr<RecordIterator> it( coll->getIterator( DiskLoc(), - false, - CollectionScanParams::FORWARD ) ); + scoped_ptr<RecordIterator> it( coll->getIterator( txn, + DiskLoc(), + false, + CollectionScanParams::FORWARD ) ); while ( !it->isEOF() ) { DiskLoc loc = it->getNext(); BSONObj obj = coll->docFor( loc ); @@ -411,9 +412,9 @@ namespace mongo { } - scoped_ptr<RecordIterator> iterator( originalCollection->getIterator( DiskLoc(), - false, - CollectionScanParams::FORWARD ) ); + scoped_ptr<RecordIterator> iterator( + originalCollection->getIterator( txn, DiskLoc(), false, + CollectionScanParams::FORWARD )); while ( !iterator->isEOF() ) { DiskLoc loc = iterator->getNext(); invariant( !loc.isNull() ); diff --git a/src/mongo/db/storage/rocks/rocks_btree_impl.cpp b/src/mongo/db/storage/rocks/rocks_btree_impl.cpp index 385081bbf2d..00cbbf1c580 100644 --- a/src/mongo/db/storage/rocks/rocks_btree_impl.cpp +++ b/src/mongo/db/storage/rocks/rocks_btree_impl.cpp @@ -202,6 +202,7 @@ namespace mongo { } scoped_ptr<rocksdb::Iterator> _iterator; + OperationContext* _txn; // not owned bool _direction; mutable bool _cached; @@ -231,7 +232,7 @@ namespace mongo { if ( !dupsAllowed ) { // XXX: this is slow - Status status = dupKeyCheck( key, loc ); + Status status = dupKeyCheck( txn, key, loc ); if ( !status.isOK() ) return status; } @@ -263,12 +264,12 @@ namespace mongo { return 1; // XXX: fix? does it matter since its so slow to check? } - Status RocksBtreeImpl::dupKeyCheck(const BSONObj& key, const DiskLoc& loc) { + Status RocksBtreeImpl::dupKeyCheck(OperationContext* txn, const BSONObj& key, const DiskLoc& loc) { // XXX: not done yet! return Status::OK(); } - void RocksBtreeImpl::fullValidate(long long* numKeysOut) { + void RocksBtreeImpl::fullValidate(OperationContext* txn, long long* numKeysOut) { // XXX: no key counts if ( numKeysOut ) numKeysOut[0] = -1; @@ -284,9 +285,11 @@ namespace mongo { return Status::OK(); } - BtreeInterface::Cursor* RocksBtreeImpl::newCursor(int direction) const { + BtreeInterface::Cursor* RocksBtreeImpl::newCursor(OperationContext* txn, + int direction) const { return new RocksCursor( _db->NewIterator( rocksdb::ReadOptions(), _columnFamily ), + txn, direction ); } diff --git a/src/mongo/db/storage/rocks/rocks_btree_impl.h b/src/mongo/db/storage/rocks/rocks_btree_impl.h index 5bb419f1d55..2a15e46aad5 100644 --- a/src/mongo/db/storage/rocks/rocks_btree_impl.h +++ b/src/mongo/db/storage/rocks/rocks_btree_impl.h @@ -64,15 +64,17 @@ namespace mongo { const BSONObj& key, const DiskLoc& loc); - virtual Status dupKeyCheck(const BSONObj& key, const DiskLoc& loc); + virtual Status dupKeyCheck(OperationContext* txn, + const BSONObj& key, + const DiskLoc& loc); - virtual void fullValidate(long long* numKeysOut); + virtual void fullValidate(OperationContext* txn, long long* numKeysOut); virtual bool isEmpty(); virtual Status touch(OperationContext* txn) const; - virtual Cursor* newCursor(int direction) const; + virtual Cursor* newCursor(OperationContext* int direction) const; virtual Status initAsEmpty(OperationContext* txn); diff --git a/src/mongo/db/storage/rocks/rocks_collection_catalog_entry.cpp b/src/mongo/db/storage/rocks/rocks_collection_catalog_entry.cpp index 5b45242a9ec..fdbae7d4442 100644 --- a/src/mongo/db/storage/rocks/rocks_collection_catalog_entry.cpp +++ b/src/mongo/db/storage/rocks/rocks_collection_catalog_entry.cpp @@ -53,7 +53,7 @@ namespace mongo { _metaDataKey = string("metadata-") + ns.toString(); } - CollectionOptions RocksCollectionCatalogEntry::getCollectionOptions() const { + CollectionOptions RocksCollectionCatalogEntry::getCollectionOptions( OperationContext* txn ) const { // todo: put more options in here? return CollectionOptions(); } diff --git a/src/mongo/db/storage/rocks/rocks_collection_catalog_entry.h b/src/mongo/db/storage/rocks/rocks_collection_catalog_entry.h index a32387a2da7..6a9a71804bf 100644 --- a/src/mongo/db/storage/rocks/rocks_collection_catalog_entry.h +++ b/src/mongo/db/storage/rocks/rocks_collection_catalog_entry.h @@ -42,7 +42,7 @@ namespace mongo { virtual ~RocksCollectionCatalogEntry(){} - virtual CollectionOptions getCollectionOptions() const; + virtual CollectionOptions getCollectionOptions(OperationContext* txn) const; // ------- indexes ---------- diff --git a/src/mongo/db/storage/rocks/rocks_record_store.cpp b/src/mongo/db/storage/rocks/rocks_record_store.cpp index 06ae8bf6242..664e643b760 100644 --- a/src/mongo/db/storage/rocks/rocks_record_store.cpp +++ b/src/mongo/db/storage/rocks/rocks_record_store.cpp @@ -180,7 +180,8 @@ namespace mongo { return Status::OK(); } - RecordIterator* RocksRecordStore::getIterator( const DiskLoc& start, + RecordIterator* RocksRecordStore::getIterator( OperationContext* txn, + const DiskLoc& start, bool tailable, const CollectionScanParams::Direction& dir ) const { @@ -191,11 +192,11 @@ namespace mongo { } - RecordIterator* RocksRecordStore::getIteratorForRepair() const { - return getIterator(); + RecordIterator* RocksRecordStore::getIteratorForRepair(OperationContext* txn) const { + return getIterator(txn); } - std::vector<RecordIterator*> RocksRecordStore::getManyIterators() const { + std::vector<RecordIterator*> RocksRecordStore::getManyIterators(OperationContext* txn) const { invariant( false ); } @@ -218,7 +219,9 @@ namespace mongo { return Status::OK(); } - void RocksRecordStore::appendCustomStats( BSONObjBuilder* result, double scale ) const { + void RocksRecordStore::appendCustomStats( OperationContext* txn, + BSONObjBuilder* result, + double scale ) const { string statsString; bool valid = _db->GetProperty( _columnFamily, "rocksdb.stats", &statsString ); invariant( valid ); diff --git a/src/mongo/db/storage/rocks/rocks_record_store.h b/src/mongo/db/storage/rocks/rocks_record_store.h index 492e8079fc6..eeaf8df9882 100644 --- a/src/mongo/db/storage/rocks/rocks_record_store.h +++ b/src/mongo/db/storage/rocks/rocks_record_store.h @@ -90,15 +90,16 @@ namespace mongo { const char* damangeSource, const mutablebson::DamageVector& damages ); - virtual RecordIterator* getIterator( const DiskLoc& start = DiskLoc(), + virtual RecordIterator* getIterator( OperationContext* txn, + const DiskLoc& start = DiskLoc(), bool tailable = false, const CollectionScanParams::Direction& dir = CollectionScanParams::FORWARD ) const; - virtual RecordIterator* getIteratorForRepair() const; + virtual RecordIterator* getIteratorForRepair( OperationContext* txn ) const; - virtual std::vector<RecordIterator*> getManyIterators() const; + virtual std::vector<RecordIterator*> getManyIterators( OperationContext* txn ) const; virtual Status truncate( OperationContext* txn ); @@ -114,7 +115,9 @@ namespace mongo { ValidateAdaptor* adaptor, ValidateResults* results, BSONObjBuilder* output ) const; - virtual void appendCustomStats( BSONObjBuilder* result, double scale ) const; + virtual void appendCustomStats( OperationContext* txn, + BSONObjBuilder* result, + double scale ) const; virtual Status touch( OperationContext* txn, BSONObjBuilder* output ) const; diff --git a/src/mongo/db/storage/rocks/rocks_record_store_test.cpp b/src/mongo/db/storage/rocks/rocks_record_store_test.cpp index 119aacb565e..4c003da75f9 100644 --- a/src/mongo/db/storage/rocks/rocks_record_store_test.cpp +++ b/src/mongo/db/storage/rocks/rocks_record_store_test.cpp @@ -330,8 +330,9 @@ namespace mongo { } { + MyOperationContext opCtx( db.get() ); BSONObjBuilder b; - rs.appendCustomStats( &b, 1 ); + rs.appendCustomStats( &opCtx, &b, 1 ); BSONObj obj = b.obj(); ASSERT( obj["stats"].String().find( "WAL" ) != string::npos ); } diff --git a/src/mongo/db/structure/SConscript b/src/mongo/db/structure/SConscript index 360876db22a..f6163c4aaf4 100644 --- a/src/mongo/db/structure/SConscript +++ b/src/mongo/db/structure/SConscript @@ -10,6 +10,7 @@ env.Library( LIBDEPS= [ '$BUILD_DIR/mongo/bson', '$BUILD_DIR/mongo/db/commands/server_status_core', + '$BUILD_DIR/mongo/db/concurrency/lock_mgr', '$BUILD_DIR/mongo/foundation', '$BUILD_DIR/mongo/mongocommon', ] diff --git a/src/mongo/db/structure/btree/btree_interface.cpp b/src/mongo/db/structure/btree/btree_interface.cpp index 46e3997f84f..ef5efccf832 100644 --- a/src/mongo/db/structure/btree/btree_interface.cpp +++ b/src/mongo/db/structure/btree/btree_interface.cpp @@ -98,12 +98,14 @@ namespace mongo { return _btree->unindex(txn, key, loc); } - virtual void fullValidate(long long *numKeysOut) { - *numKeysOut = _btree->fullValidate(NULL, false, false, 0); + virtual void fullValidate(OperationContext* txn, long long *numKeysOut) { + *numKeysOut = _btree->fullValidate(txn, NULL, false, false, 0); } - virtual Status dupKeyCheck(const BSONObj& key, const DiskLoc& loc) { - return _btree->dupKeyCheck(key, loc); + virtual Status dupKeyCheck(OperationContext* txn, + const BSONObj& key, + const DiskLoc& loc) { + return _btree->dupKeyCheck(txn, key, loc); } virtual bool isEmpty() { @@ -116,8 +118,11 @@ namespace mongo { class Cursor : public BtreeInterface::Cursor { public: - Cursor(const BtreeLogic<OnDiskFormat>* btree, int direction) - : _btree(btree), + Cursor(OperationContext* txn, + const BtreeLogic<OnDiskFormat>* btree, + int direction) + : _txn(txn), + _btree(btree), _direction(direction), _bucket(btree->getHead()), // XXX this shouldn't be nessisary, but is. _ofs(0) { @@ -142,7 +147,7 @@ namespace mongo { } virtual bool locate(const BSONObj& key, const DiskLoc& loc) { - return _btree->locate(key, loc, _direction, &_ofs, &_bucket); + return _btree->locate(_txn, key, loc, _direction, &_ofs, &_bucket); } virtual void customLocate(const BSONObj& keyBegin, @@ -151,7 +156,8 @@ namespace mongo { const vector<const BSONElement*>& keyEnd, const vector<bool>& keyEndInclusive) { - _btree->customLocate(&_bucket, + _btree->customLocate(_txn, + &_bucket, &_ofs, keyBegin, keyBeginLen, @@ -167,7 +173,8 @@ namespace mongo { const vector<const BSONElement*>& keyEnd, const vector<bool>& keyEndInclusive) { - _btree->advanceTo(&_bucket, + _btree->advanceTo(_txn, + &_bucket, &_ofs, keyBegin, keyBeginLen, @@ -186,7 +193,7 @@ namespace mongo { } virtual void advance() { - _btree->advance(&_bucket, &_ofs, _direction); + _btree->advance(_txn, &_bucket, &_ofs, _direction); } virtual void savePosition() { @@ -198,7 +205,8 @@ namespace mongo { virtual void restorePosition() { if (!_bucket.isNull()) { - _btree->restorePosition(_savedKey, + _btree->restorePosition(_txn, + _savedKey, _savedLoc, _direction, &_bucket, @@ -207,6 +215,7 @@ namespace mongo { } private: + OperationContext* _txn; // not owned const BtreeLogic<OnDiskFormat>* const _btree; const int _direction; @@ -218,8 +227,8 @@ namespace mongo { DiskLoc _savedLoc; }; - virtual Cursor* newCursor(int direction) const { - return new Cursor(_btree.get(), direction); + virtual Cursor* newCursor(OperationContext* txn, int direction) const { + return new Cursor(txn, _btree.get(), direction); } virtual Status initAsEmpty(OperationContext* txn) { diff --git a/src/mongo/db/structure/btree/btree_interface.h b/src/mongo/db/structure/btree/btree_interface.h index 92339c1fe63..845a02d467a 100644 --- a/src/mongo/db/structure/btree/btree_interface.h +++ b/src/mongo/db/structure/btree/btree_interface.h @@ -107,14 +107,16 @@ namespace mongo { const DiskLoc& loc) = 0; // TODO: Hide this by exposing an update method? - virtual Status dupKeyCheck(const BSONObj& key, const DiskLoc& loc) = 0; + virtual Status dupKeyCheck(OperationContext* txn, + const BSONObj& key, + const DiskLoc& loc) = 0; // // Information about the tree // // TODO: expose full set of args for testing? - virtual void fullValidate(long long* numKeysOut) = 0; + virtual void fullValidate(OperationContext* txn, long long* numKeysOut) = 0; virtual bool isEmpty() = 0; @@ -187,7 +189,7 @@ namespace mongo { /** * Caller takes ownership. BtreeInterface must outlive all Cursors it produces. */ - virtual Cursor* newCursor(int direction) const = 0; + virtual Cursor* newCursor(OperationContext* txn, int direction) const = 0; // // Index creation diff --git a/src/mongo/db/structure/btree/btree_logic.cpp b/src/mongo/db/structure/btree/btree_logic.cpp index 88b6f32b8f4..8d05a65ab0c 100644 --- a/src/mongo/db/structure/btree/btree_logic.cpp +++ b/src/mongo/db/structure/btree/btree_logic.cpp @@ -566,10 +566,8 @@ namespace mongo { memcpy(bucket->data + ofs, temp + ofs, dataUsed); bucket->emptySize = tdz - dataUsed - bucket->n * sizeof(KeyHeaderType); - { - int foo = bucket->emptySize; - invariant( foo >= 0 ); - } + int foo = bucket->emptySize; + invariant( foo >= 0 ); setPacked(bucket); assertValid(_indexName, bucket, _ordering); } @@ -667,7 +665,8 @@ namespace mongo { } template <class BtreeLayout> - void BtreeLogic<BtreeLayout>::customLocate(DiskLoc* locInOut, + void BtreeLogic<BtreeLayout>::customLocate(OperationContext* txn, + DiskLoc* locInOut, int* keyOfsInOut, const BSONObj& keyBegin, int keyBeginLen, @@ -677,7 +676,8 @@ namespace mongo { int direction) const { pair<DiskLoc, int> unused; - customLocate(locInOut, + customLocate(txn, + locInOut, keyOfsInOut, keyBegin, keyBeginLen, @@ -687,27 +687,32 @@ namespace mongo { direction, unused); - skipUnusedKeys(locInOut, keyOfsInOut, direction); + skipUnusedKeys(txn, locInOut, keyOfsInOut, direction); } template <class BtreeLayout> - void BtreeLogic<BtreeLayout>::advance(DiskLoc* bucketLocInOut, + void BtreeLogic<BtreeLayout>::advance(OperationContext* txn, + DiskLoc* bucketLocInOut, int* posInOut, int direction) const { - *bucketLocInOut = advance(*bucketLocInOut, posInOut, direction); - skipUnusedKeys(bucketLocInOut, posInOut, direction); + *bucketLocInOut = advance(txn, *bucketLocInOut, posInOut, direction); + skipUnusedKeys(txn, bucketLocInOut, posInOut, direction); } template <class BtreeLayout> - void BtreeLogic<BtreeLayout>::skipUnusedKeys(DiskLoc* loc, int* pos, int direction) const { + void BtreeLogic<BtreeLayout>::skipUnusedKeys(OperationContext* txn, + DiskLoc* loc, + int* pos, + int direction) const { while (!loc->isNull() && !keyIsUsed(*loc, *pos)) { - *loc = advance(*loc, pos, direction); + *loc = advance(txn, *loc, pos, direction); } } template <class BtreeLayout> - void BtreeLogic<BtreeLayout>::advanceTo(DiskLoc* thisLocInOut, + void BtreeLogic<BtreeLayout>::advanceTo(OperationContext* txn, + DiskLoc* thisLocInOut, int* keyOfsInOut, const BSONObj &keyBegin, int keyBeginLen, @@ -716,7 +721,8 @@ namespace mongo { const vector<bool>& keyEndInclusive, int direction) const { - advanceToImpl(thisLocInOut, + advanceToImpl(txn, + thisLocInOut, keyOfsInOut, keyBegin, keyBeginLen, @@ -725,7 +731,7 @@ namespace mongo { keyEndInclusive, direction); - skipUnusedKeys(thisLocInOut, keyOfsInOut, direction); + skipUnusedKeys(txn, thisLocInOut, keyOfsInOut, direction); } /** @@ -738,7 +744,8 @@ namespace mongo { * and reverse implementations would be more efficient */ template <class BtreeLayout> - void BtreeLogic<BtreeLayout>::advanceToImpl(DiskLoc* thisLocInOut, + void BtreeLogic<BtreeLayout>::advanceToImpl(OperationContext* txn, + DiskLoc* thisLocInOut, int* keyOfsInOut, const BSONObj &keyBegin, int keyBeginLen, @@ -831,7 +838,8 @@ namespace mongo { } } - customLocate(thisLocInOut, + customLocate(txn, + thisLocInOut, keyOfsInOut, keyBegin, keyBeginLen, @@ -843,7 +851,8 @@ namespace mongo { } template <class BtreeLayout> - void BtreeLogic<BtreeLayout>::customLocate(DiskLoc* locInOut, + void BtreeLogic<BtreeLayout>::customLocate(OperationContext* txn, + DiskLoc* locInOut, int* keyOfsInOut, const BSONObj& keyBegin, int keyBeginLen, @@ -1071,28 +1080,31 @@ namespace mongo { } template <class BtreeLayout> - bool BtreeLogic<BtreeLayout>::exists(const KeyDataType& key) const { + bool BtreeLogic<BtreeLayout>::exists(OperationContext* txn, const KeyDataType& key) const { int position = 0; // Find the DiskLoc bool found; - DiskLoc bucket = _locate(getRootLoc(), key, &position, &found, minDiskLoc, 1); + + DiskLoc bucket = _locate(txn, getRootLoc(), key, &position, &found, minDiskLoc, 1); while (!bucket.isNull()) { FullKey fullKey = getFullKey(getBucket(bucket), position); if (fullKey.header.isUsed()) { return fullKey.data.woEqual(key); } - bucket = advance(bucket, &position, 1); + bucket = advance(txn, bucket, &position, 1); } return false; } template <class BtreeLayout> - Status BtreeLogic<BtreeLayout>::dupKeyCheck(const BSONObj& key, const DiskLoc& loc) const { + Status BtreeLogic<BtreeLayout>::dupKeyCheck(OperationContext* txn, + const BSONObj& key, + const DiskLoc& loc) const { KeyDataOwnedType theKey(key); - if (!wouldCreateDup(theKey, loc)) { + if (!wouldCreateDup(txn, theKey, loc)) { return Status::OK(); } @@ -1100,11 +1112,13 @@ namespace mongo { } template <class BtreeLayout> - bool BtreeLogic<BtreeLayout>::wouldCreateDup(const KeyDataType& key, + bool BtreeLogic<BtreeLayout>::wouldCreateDup(OperationContext* txn, + const KeyDataType& key, const DiskLoc self) const { int position; bool found; - DiskLoc posLoc = _locate(getRootLoc(), key, &position, &found, minDiskLoc, 1); + + DiskLoc posLoc = _locate(txn, getRootLoc(), key, &position, &found, minDiskLoc, 1); while (!posLoc.isNull()) { FullKey fullKey = getFullKey(getBucket(posLoc), position); @@ -1117,7 +1131,7 @@ namespace mongo { break; } - posLoc = advance(posLoc, &position, 1); + posLoc = advance(txn, posLoc, &position, 1); } return false; } @@ -1146,7 +1160,8 @@ namespace mongo { * note result might be an Unused location! */ template <class BtreeLayout> - Status BtreeLogic<BtreeLayout>::_find(BucketType* bucket, + Status BtreeLogic<BtreeLayout>::_find(OperationContext* txn, + BucketType* bucket, const KeyDataType& key, const DiskLoc& recordLoc, bool errorIfDup, @@ -1180,8 +1195,8 @@ namespace mongo { // This is expensive and we only want to do it once(? -- when would // it happen twice). dupsChecked = true; - if (exists(key)) { - if (wouldCreateDup(key, genericRecordLoc)) { + if (exists(txn, key)) { + if (wouldCreateDup(txn, key, genericRecordLoc)) { return Status(ErrorCodes::DuplicateKey, dupKeyError(key), 11000); } else { @@ -1259,7 +1274,7 @@ namespace mongo { _bucketDeletion->aboutToDeleteBucket(bucketLoc); BucketType* p = getBucket(bucket->parent); - int parentIdx = indexInParent(bucket, bucketLoc); + int parentIdx = indexInParent(txn, bucket, bucketLoc); *txn->recoveryUnit()->writing(&childLocForPos(p, parentIdx)) = DiskLoc(); deallocBucket(txn, bucket, bucketLoc); } @@ -1274,7 +1289,8 @@ namespace mongo { } template <class BtreeLayout> - void BtreeLogic<BtreeLayout>::restorePosition(const BSONObj& savedKey, + void BtreeLogic<BtreeLayout>::restorePosition(OperationContext* txn, + const BSONObj& savedKey, const DiskLoc& savedLoc, int direction, DiskLoc* bucketLocInOut, @@ -1285,7 +1301,7 @@ namespace mongo { // thing should be kept BTree-internal. This'll go away with finer grained locking: we // can hold on to a bucket for as long as we need it. if (-1 == *keyOffsetInOut) { - locate(savedKey, savedLoc, direction, keyOffsetInOut, bucketLocInOut); + locate(txn, savedKey, savedLoc, direction, keyOffsetInOut, bucketLocInOut); return; } @@ -1296,19 +1312,19 @@ namespace mongo { invariant(BtreeLayout::INVALID_N_SENTINEL != bucket->n); if (_keyIsAt(savedKey, savedLoc, bucket, *keyOffsetInOut)) { - skipUnusedKeys(bucketLocInOut, keyOffsetInOut, direction); + skipUnusedKeys(txn, bucketLocInOut, keyOffsetInOut, direction); return; } if (*keyOffsetInOut > 0) { (*keyOffsetInOut)--; if (_keyIsAt(savedKey, savedLoc, bucket, *keyOffsetInOut)) { - skipUnusedKeys(bucketLocInOut, keyOffsetInOut, direction); + skipUnusedKeys(txn, bucketLocInOut, keyOffsetInOut, direction); return; } } - locate(savedKey, savedLoc, direction, keyOffsetInOut, bucketLocInOut); + locate(txn, savedKey, savedLoc, direction, keyOffsetInOut, bucketLocInOut); } template <class BtreeLayout> @@ -1337,7 +1353,6 @@ namespace mongo { int p) { invariant(bucket->n > 0); DiskLoc left = childLocForPos(bucket, p); - if (bucket->n == 1) { if (left.isNull() && bucket->nextChild.isNull()) { _delKeyAtPos(bucket, p); @@ -1400,7 +1415,7 @@ namespace mongo { invariant(!lchild.isNull() || !rchild.isNull()); int advanceDirection = lchild.isNull() ? 1 : -1; int advanceKeyOfs = keypos; - DiskLoc advanceLoc = advance(bucketLoc, &advanceKeyOfs, advanceDirection); + DiskLoc advanceLoc = advance(txn, bucketLoc, &advanceKeyOfs, advanceDirection); // advanceLoc must be a descentant of thisLoc, because thisLoc has a // child in the proper direction and all descendants of thisLoc must be // nonempty because they are not the root. @@ -1435,7 +1450,7 @@ namespace mongo { } else { BucketType* parentBucket = getBucket(bucket->parent); - int bucketIndexInParent = indexInParent(bucket, bucketLoc); + int bucketIndexInParent = indexInParent(txn, bucket, bucketLoc); *txn->recoveryUnit()->writing(&childLocForPos(parentBucket, bucketIndexInParent)) = bucket->nextChild; } @@ -1446,9 +1461,10 @@ namespace mongo { } template <class BtreeLayout> - bool BtreeLogic<BtreeLayout>::canMergeChildren(BucketType* bucket, - const DiskLoc bucketLoc, - const int leftIndex) { + bool BtreeLogic<BtreeLayout>::canMergeChildren(OperationContext* txn, + BucketType* bucket, + const DiskLoc bucketLoc, + const int leftIndex) { invariant(leftIndex >= 0 && leftIndex < bucket->n); DiskLoc leftNodeLoc = childLocForPos(bucket, leftIndex); @@ -1477,9 +1493,12 @@ namespace mongo { * splitPos(). */ template <class BtreeLayout> - int BtreeLogic<BtreeLayout>::_rebalancedSeparatorPos(BucketType* bucket, int leftIndex) { + int BtreeLogic<BtreeLayout>::_rebalancedSeparatorPos(OperationContext* txn, + BucketType* bucket, + int leftIndex) { int split = -1; int rightSize = 0; + const BucketType* l = childForPos(bucket, leftIndex); const BucketType* r = childForPos(bucket, leftIndex + 1); @@ -1539,6 +1558,7 @@ namespace mongo { DiskLoc leftNodeLoc = childLocForPos(bucket, leftIndex); DiskLoc rightNodeLoc = childLocForPos(bucket, leftIndex + 1); + BucketType* l = btreemod(txn, getBucket(leftNodeLoc)); BucketType* r = btreemod(txn, getBucket(rightNodeLoc)); @@ -1578,8 +1598,9 @@ namespace mongo { } template <class BtreeLayout> - int BtreeLogic<BtreeLayout>::indexInParent(BucketType* bucket, - const DiskLoc bucketLoc) const { + int BtreeLogic<BtreeLayout>::indexInParent(OperationContext* txn, + BucketType* bucket, + const DiskLoc bucketLoc) const { invariant(!bucket->parent.isNull()); const BucketType* p = getBucket(bucket->parent); if (p->nextChild == bucketLoc) { @@ -1609,7 +1630,7 @@ namespace mongo { // If we can merge, then we must merge rather than balance to preserve bucket utilization // constraints. - if (canMergeChildren(bucket, bucketLoc, leftIndex)) { + if (canMergeChildren(txn, bucket, bucketLoc, leftIndex)) { return false; } @@ -1718,7 +1739,7 @@ namespace mongo { BucketType* r = btreemod(txn, getBucket(rchild)); _packReadyForMod(r, zeropos); - int split = _rebalancedSeparatorPos(bucket, leftIndex); + int split = _rebalancedSeparatorPos(txn, bucket, leftIndex); // By definition, if we are below the low water mark and cannot merge // then we must actively balance. @@ -1744,7 +1765,7 @@ namespace mongo { } BucketType* p = getBucket(bucket->parent); - int parentIdx = indexInParent(bucket, bucketLoc); + int parentIdx = indexInParent(txn, bucket, bucketLoc); // TODO will missing neighbor case be possible long term? Should we try to merge/balance // somehow in that case if so? @@ -1782,7 +1803,8 @@ namespace mongo { int pos; bool found = false; KeyDataOwnedType ownedKey(key); - DiskLoc loc = _locate(getRootLoc(), ownedKey, &pos, &found, recordLoc, 1); + + DiskLoc loc = _locate(txn, getRootLoc(), ownedKey, &pos, &found, recordLoc, 1); if (found) { BucketType* bucket = btreemod(txn, getBucket(loc)); delKeyAtPos(txn, bucket, loc, pos); @@ -1997,6 +2019,8 @@ namespace mongo { StatusWith<DiskLoc> loc = _recordStore->insertRecord(txn, &docWriter, false); // XXX: remove this(?) or turn into massert or sanely bubble it back up. uassertStatusOK(loc.getStatus()); + + // this is a new bucket, not referenced by anyone, probably don't need this lock BucketType* b = btreemod(txn, getBucket(loc.getValue())); init(b); return loc.getValue(); @@ -2059,15 +2083,17 @@ namespace mongo { } template <class BtreeLayout> - long long BtreeLogic<BtreeLayout>::fullValidate(long long *unusedCount, - bool strict, - bool dumpBuckets, - unsigned depth) { - return _fullValidate(getRootLoc(), unusedCount, strict, dumpBuckets, depth); + long long BtreeLogic<BtreeLayout>::fullValidate(OperationContext* txn, + long long *unusedCount, + bool strict, + bool dumpBuckets, + unsigned depth) { + return _fullValidate(txn, getRootLoc(), unusedCount, strict, dumpBuckets, depth); } template <class BtreeLayout> - long long BtreeLogic<BtreeLayout>::_fullValidate(const DiskLoc bucketLoc, + long long BtreeLogic<BtreeLayout>::_fullValidate(OperationContext* txn, + const DiskLoc bucketLoc, long long *unusedCount, bool strict, bool dumpBuckets, @@ -2103,7 +2129,7 @@ namespace mongo { wassert(b->parent == bucketLoc); } - keyCount += _fullValidate(left, unusedCount, strict, dumpBuckets, depth + 1); + keyCount += _fullValidate(txn, left, unusedCount, strict, dumpBuckets, depth + 1); } } @@ -2116,7 +2142,7 @@ namespace mongo { wassert(b->parent == bucketLoc); } - keyCount += _fullValidate(bucket->nextChild, unusedCount, strict, dumpBuckets, depth + 1); + keyCount += _fullValidate(txn, bucket->nextChild, unusedCount, strict, dumpBuckets, depth + 1); } return keyCount; @@ -2230,7 +2256,7 @@ namespace mongo { int pos; bool found; - Status findStatus = _find(bucket, key, recordLoc, !dupsAllowed, &pos, &found); + Status findStatus = _find(txn, bucket, key, recordLoc, !dupsAllowed, &pos, &found); if (!findStatus.isOK()) { return findStatus; } @@ -2269,9 +2295,10 @@ namespace mongo { } template <class BtreeLayout> - DiskLoc BtreeLogic<BtreeLayout>::advance(const DiskLoc& bucketLoc, - int* posInOut, - int direction) const { + DiskLoc BtreeLogic<BtreeLayout>::advance(OperationContext* txn, + const DiskLoc& bucketLoc, + int* posInOut, + int direction) const { BucketType* bucket = getBucket(bucketLoc); if (*posInOut < 0 || *posInOut >= bucket->n ) { @@ -2343,7 +2370,8 @@ namespace mongo { } template <class BtreeLayout> - bool BtreeLogic<BtreeLayout>::locate(const BSONObj& key, + bool BtreeLogic<BtreeLayout>::locate(OperationContext* txn, + const BSONObj& key, const DiskLoc& recordLoc, const int direction, int* posOut, @@ -2355,28 +2383,33 @@ namespace mongo { bool found = false; KeyDataOwnedType owned(key); - *bucketLocOut = _locate(getRootLoc(), owned, posOut, &found, recordLoc, direction); + *bucketLocOut = _locate(txn, getRootLoc(), owned, posOut, &found, recordLoc, direction); if (!found) { return false; } - skipUnusedKeys(bucketLocOut, posOut, direction); + skipUnusedKeys(txn, bucketLocOut, posOut, direction); return found; } + /** + * Recursively walk down the btree, looking for a match of key and recordLoc. + * Caller should have acquired lock on bucketLoc. + */ template <class BtreeLayout> - DiskLoc BtreeLogic<BtreeLayout>::_locate(const DiskLoc& bucketLoc, - const KeyDataType& key, - int* posOut, - bool* foundOut, - const DiskLoc& recordLoc, - const int direction) const { + DiskLoc BtreeLogic<BtreeLayout>::_locate(OperationContext* txn, + const DiskLoc& bucketLoc, + const KeyDataType& key, + int* posOut, + bool* foundOut, + const DiskLoc& recordLoc, + const int direction) const { int position; BucketType* bucket = getBucket(bucketLoc); // XXX: owned to not owned conversion(?) - _find(bucket, key, recordLoc, false, &position, foundOut); + _find(txn, bucket, key, recordLoc, false, &position, foundOut); // Look in our current bucket. if (*foundOut) { @@ -2388,7 +2421,7 @@ namespace mongo { DiskLoc childLoc = childLocForPos(bucket, position); if (!childLoc.isNull()) { - DiskLoc inChild = _locate(childLoc, key, posOut, foundOut, recordLoc, direction); + DiskLoc inChild = _locate(txn, childLoc, key, posOut, foundOut, recordLoc, direction); if (!inChild.isNull()) { return inChild; } @@ -2455,7 +2488,8 @@ namespace mongo { template <class BtreeLayout> typename BtreeLogic<BtreeLayout>::BucketType* BtreeLogic<BtreeLayout>::childForPos(BucketType* bucket, int pos) const { - return getBucket(childLocForPos(bucket, pos)); + DiskLoc loc = childLocForPos(bucket, pos); + return getBucket(loc); } template <class BtreeLayout> diff --git a/src/mongo/db/structure/btree/btree_logic.h b/src/mongo/db/structure/btree/btree_logic.h index 157040e4891..b7a31f80f52 100644 --- a/src/mongo/db/structure/btree/btree_logic.h +++ b/src/mongo/db/structure/btree/btree_logic.h @@ -137,7 +137,9 @@ namespace mongo { */ Builder* newBuilder(OperationContext* txn, bool dupsAllowed); - Status dupKeyCheck(const BSONObj& key, const DiskLoc& loc) const; + Status dupKeyCheck(OperationContext* txn, + const BSONObj& key, + const DiskLoc& loc) const; Status insert(OperationContext* txn, const BSONObj& rawKey, @@ -152,15 +154,19 @@ namespace mongo { * bucketLocOut would contain the bucket containing key which is before or after the * searched one (dependent on the direction). */ - bool locate(const BSONObj& key, + bool locate(OperationContext* txn, + const BSONObj& key, const DiskLoc& recordLoc, const int direction, int* posOut, DiskLoc* bucketLocOut) const; - void advance(DiskLoc* bucketLocInOut, int* posInOut, int direction) const; + void advance(OperationContext* txn, + DiskLoc* bucketLocInOut, + int* posInOut, + int direction) const; - bool exists(const KeyDataType& key) const; + bool exists(OperationContext* txn, const KeyDataType& key) const; bool unindex(OperationContext* txn, const BSONObj& key, @@ -168,7 +174,8 @@ namespace mongo { bool isEmpty() const; - long long fullValidate(long long *unusedCount, + long long fullValidate(OperationContext*, + long long *unusedCount, bool strict, bool dumpBuckets, unsigned depth); @@ -185,7 +192,8 @@ namespace mongo { // Composite key navigation methods // - void customLocate(DiskLoc* locInOut, + void customLocate(OperationContext* txn, + DiskLoc* locInOut, int* keyOfsInOut, const BSONObj& keyBegin, int keyBeginLen, @@ -194,7 +202,8 @@ namespace mongo { const vector<bool>& keyEndInclusive, int direction) const; - void advanceTo(DiskLoc* thisLocInOut, + void advanceTo(OperationContext*, + DiskLoc* thisLocInOut, int* keyOfsInOut, const BSONObj &keyBegin, int keyBeginLen, @@ -203,7 +212,8 @@ namespace mongo { const vector<bool>& keyEndInclusive, int direction) const; - void restorePosition(const BSONObj& savedKey, + void restorePosition(OperationContext* txn, + const BSONObj& savedKey, const DiskLoc& savedLoc, int direction, DiskLoc* bucketInOut, @@ -330,7 +340,8 @@ namespace mongo { void _pack(OperationContext* txn, BucketType* bucket, const DiskLoc thisLoc, int &refPos); - void customLocate(DiskLoc* locInOut, + void customLocate(OperationContext* txn, + DiskLoc* locInOut, int* keyOfsInOut, const BSONObj& keyBegin, int keyBeginLen, @@ -340,12 +351,13 @@ namespace mongo { int direction, pair<DiskLoc, int>& bestParent) const; - Status _find(BucketType* bucket, - const KeyDataType& key, - const DiskLoc& recordLoc, - bool errorIfDup, - int* keyPositionOut, - bool* foundOut) const; + Status _find(OperationContext* txn, + BucketType* bucket, + const KeyDataType& key, + const DiskLoc& recordLoc, + bool errorIfDup, + int* keyPositionOut, + bool* foundOut) const; bool customFind(int low, int high, @@ -360,7 +372,8 @@ namespace mongo { int* keyOfsInOut, pair<DiskLoc, int>& bestParent) const; - void advanceToImpl(DiskLoc* thisLocInOut, + void advanceToImpl(OperationContext* txn, + DiskLoc* thisLocInOut, int* keyOfsInOut, const BSONObj &keyBegin, int keyBeginLen, @@ -369,35 +382,48 @@ namespace mongo { const vector<bool>& keyEndInclusive, int direction) const; - bool wouldCreateDup(const KeyDataType& key, const DiskLoc self) const; + bool wouldCreateDup(OperationContext* txn, + const KeyDataType& key, + const DiskLoc self) const; bool keyIsUsed(const DiskLoc& loc, const int& pos) const; - void skipUnusedKeys(DiskLoc* loc, int* pos, int direction) const; + void skipUnusedKeys(OperationContext* txn, + DiskLoc* loc, + int* pos, + int direction) const; - DiskLoc advance(const DiskLoc& bucketLoc, int* posInOut, int direction) const; + DiskLoc advance(OperationContext* txn, + const DiskLoc& bucketLoc, + int* posInOut, + int direction) const; - DiskLoc _locate(const DiskLoc& bucketLoc, - const KeyDataType& key, - int* posOut, - bool* foundOut, - const DiskLoc& recordLoc, - const int direction) const; + DiskLoc _locate(OperationContext* txn, + const DiskLoc& bucketLoc, + const KeyDataType& key, + int* posOut, + bool* foundOut, + const DiskLoc& recordLoc, + const int direction) const; - long long _fullValidate(const DiskLoc bucketLoc, - long long *unusedCount, - bool strict, - bool dumpBuckets, - unsigned depth); + long long _fullValidate(OperationContext* txn, + const DiskLoc bucketLoc, + long long *unusedCount, + bool strict, + bool dumpBuckets, + unsigned depth); DiskLoc _addBucket(OperationContext* txn); - bool canMergeChildren(BucketType* bucket, + bool canMergeChildren(OperationContext* txn, + BucketType* bucket, const DiskLoc bucketLoc, const int leftIndex); // has to look in children of 'bucket' and requires record store - int _rebalancedSeparatorPos(BucketType* bucket, int leftIndex); + int _rebalancedSeparatorPos(OperationContext* txn, + BucketType* bucket, + int leftIndex); void _packReadyForMod(BucketType* bucket, int &refPos); @@ -466,7 +492,7 @@ namespace mongo { void doBalanceRightToLeft(OperationContext* txn, BucketType* bucket, - const DiskLoc bucketLoc, + const DiskLoc thisLoc, int leftIndex, int split, BucketType* l, @@ -479,7 +505,9 @@ namespace mongo { const DiskLoc bucketLoc, int leftIndex); - int indexInParent(BucketType* bucket, const DiskLoc bucketLoc) const; + int indexInParent(OperationContext* txn, + BucketType* bucket, + const DiskLoc bucketLoc) const; void doMergeChildren(OperationContext* txn, BucketType* bucket, diff --git a/src/mongo/db/structure/btree/btree_logic_test.cpp b/src/mongo/db/structure/btree/btree_logic_test.cpp index deabd340184..3cfa48a3a25 100644 --- a/src/mongo/db/structure/btree/btree_logic_test.cpp +++ b/src/mongo/db/structure/btree/btree_logic_test.cpp @@ -63,7 +63,8 @@ namespace mongo { protected: void checkValidNumKeys(int nKeys) { - ASSERT_EQUALS(nKeys, _helper.btree.fullValidate(NULL, true, true, 0)); + OperationContextNoop txn; + ASSERT_EQUALS(nKeys, _helper.btree.fullValidate(&txn, NULL, true, true, 0)); } void insert(const BSONObj &key, const DiskLoc dl) { @@ -83,8 +84,9 @@ namespace mongo { int direction) { int pos; DiskLoc loc; + OperationContextNoop txn; ASSERT_EQUALS(expectedFound, - _helper.btree.locate(key, _helper.dummyDiskLoc, direction, &pos, &loc)); + _helper.btree.locate(&txn, key, _helper.dummyDiskLoc, direction, &pos, &loc)); ASSERT_EQUALS(expectedLocation, loc); ASSERT_EQUALS(expectedPos, pos); } @@ -128,8 +130,8 @@ namespace mongo { int bucketRebalancedSeparatorPos(const DiskLoc bucketLoc, int leftIndex) { BucketType* bucket = _helper.btree.getBucket(bucketLoc); - - return _helper.btree._rebalancedSeparatorPos(bucket, leftIndex); + OperationContextNoop txn; + return _helper.btree._rebalancedSeparatorPos(&txn, bucket, leftIndex); } FullKey getKey(const DiskLoc bucketLoc, int pos) const { @@ -328,21 +330,21 @@ namespace mongo { // 'E' is the split point and should be in the head the rest should be ~50/50 const BSONObj splitPoint = simpleKey('E', 800); - this->_helper.btree.locate(splitPoint, this->_helper.dummyDiskLoc, 1, &pos, &loc); + this->_helper.btree.locate(&txn, splitPoint, this->_helper.dummyDiskLoc, 1, &pos, &loc); ASSERT_EQUALS(this->_helper.headManager.getHead(), loc); ASSERT_EQUALS(0, pos); // Find the one before 'E' int largePos; DiskLoc largeLoc; - this->_helper.btree.locate(splitPoint, this->_helper.dummyDiskLoc, 1, &largePos, &largeLoc); - this->_helper.btree.advance(&largeLoc, &largePos, -1); + this->_helper.btree.locate(&txn, splitPoint, this->_helper.dummyDiskLoc, 1, &largePos, &largeLoc); + this->_helper.btree.advance(&txn, &largeLoc, &largePos, -1); // Find the one after 'E' int smallPos; DiskLoc smallLoc; - this->_helper.btree.locate(splitPoint, this->_helper.dummyDiskLoc, 1, &smallPos, &smallLoc); - this->_helper.btree.advance(&smallLoc, &smallPos, 1); + this->_helper.btree.locate(&txn, splitPoint, this->_helper.dummyDiskLoc, 1, &smallPos, &smallLoc); + this->_helper.btree.advance(&txn, &smallLoc, &smallPos, 1); ASSERT_NOT_EQUALS(smallLoc, largeLoc); ASSERT_NOT_EQUALS(smallLoc, loc); @@ -378,23 +380,23 @@ namespace mongo { // 'H' is the maximum 'large' interval key, 90% should be < 'H' and 10% larger const BSONObj splitPoint = simpleKey('H', 800); - this->_helper.btree.locate(splitPoint, this->_helper.dummyDiskLoc, 1, &pos, &loc); + this->_helper.btree.locate(&txn, splitPoint, this->_helper.dummyDiskLoc, 1, &pos, &loc); ASSERT_EQUALS(this->_helper.headManager.getHead(), loc); ASSERT_EQUALS(0, pos); // Find the one before 'H' int largePos; DiskLoc largeLoc; - this->_helper.btree.locate( + this->_helper.btree.locate(&txn, splitPoint, this->_helper.dummyDiskLoc, 1, &largePos, &largeLoc); - this->_helper.btree.advance(&largeLoc, &largePos, -1); + this->_helper.btree.advance(&txn, &largeLoc, &largePos, -1); // Find the one after 'H' int smallPos; DiskLoc smallLoc; - this->_helper.btree.locate( + this->_helper.btree.locate(&txn, splitPoint, this->_helper.dummyDiskLoc, 1, &smallPos, &smallLoc); - this->_helper.btree.advance(&smallLoc, &smallPos, 1); + this->_helper.btree.advance(&txn, &smallLoc, &smallPos, 1); ASSERT_NOT_EQUALS(smallLoc, largeLoc); ASSERT_NOT_EQUALS(smallLoc, loc); @@ -441,7 +443,7 @@ namespace mongo { ASSERT_EQUALS(1, this->_helper.recordStore.numRecords() - 1); long long unusedCount = 0; - ASSERT_EQUALS(expectedCount, this->_helper.btree.fullValidate(&unusedCount, true, true, 0)); + ASSERT_EQUALS(expectedCount, this->_helper.btree.fullValidate(&txn, &unusedCount, true, true, 0)); ASSERT_EQUALS(0, unusedCount); } @@ -497,7 +499,7 @@ namespace mongo { ASSERT_EQUALS(3, this->_helper.recordStore.numRecords() - 1); long long unusedCount = 0; - ASSERT_EQUALS(17, this->_helper.btree.fullValidate(&unusedCount, true, true, 0)); + ASSERT_EQUALS(17, this->_helper.btree.fullValidate(&txn, &unusedCount, true, true, 0)); ASSERT_EQUALS(0, unusedCount); } }; @@ -510,7 +512,7 @@ namespace mongo { ArtificialTreeBuilder<OnDiskFormat> builder(&txn, &this->_helper); builder.makeTree("{d:{b:{a:null},bb:null,_:{c:null}},_:{f:{e:null},_:{g:null}}}"); - ASSERT_EQUALS(8, this->_helper.btree.fullValidate(NULL, true, true, 0)); + ASSERT_EQUALS(8, this->_helper.btree.fullValidate(&txn, NULL, true, true, 0)); // The tree has 7 buckets + 1 for the this->_helper.dummyDiskLoc ASSERT_EQUALS(8, this->_helper.recordStore.numRecords()); @@ -518,7 +520,7 @@ namespace mongo { const BSONObj k = BSON("" << "bb"); verify(this->unindex(k)); - ASSERT_EQUALS(7, this->_helper.btree.fullValidate(NULL, true, true, 0)); + ASSERT_EQUALS(7, this->_helper.btree.fullValidate(&txn, NULL, true, true, 0)); // The tree has 5 buckets + 1 for the this->_helper.dummyDiskLoc ASSERT_EQUALS(6, this->_helper.recordStore.numRecords()); @@ -535,7 +537,7 @@ namespace mongo { ArtificialTreeBuilder<OnDiskFormat> builder(&txn, &this->_helper); builder.makeTree("{d:{b:{a:null},bb:null,cc:{c:null}},_:{f:{e:null},h:{g:null}}}"); - ASSERT_EQUALS(10, this->_helper.btree.fullValidate(NULL, true, true, 0)); + ASSERT_EQUALS(10, this->_helper.btree.fullValidate(&txn, NULL, true, true, 0)); // The tree has 7 buckets + 1 for the this->_helper.dummyDiskLoc ASSERT_EQUALS(8, this->_helper.recordStore.numRecords()); @@ -543,7 +545,7 @@ namespace mongo { const BSONObj k = BSON("" << "bb"); verify(this->unindex(k)); - ASSERT_EQUALS(9, this->_helper.btree.fullValidate(NULL, true, true, 0)); + ASSERT_EQUALS(9, this->_helper.btree.fullValidate(&txn, NULL, true, true, 0)); // The tree has 5 buckets + 1 for the this->_helper.dummyDiskLoc ASSERT_EQUALS(6, this->_helper.recordStore.numRecords()); @@ -564,7 +566,7 @@ namespace mongo { builder.makeTree("{d:{b:{a:null},c:null}}"); - ASSERT_EQUALS(4, this->_helper.btree.fullValidate(NULL, true, true, 0)); + ASSERT_EQUALS(4, this->_helper.btree.fullValidate(&txn, NULL, true, true, 0)); // The tree has 3 buckets + 1 for the this->_helper.dummyDiskLoc ASSERT_EQUALS(4, this->_helper.recordStore.numRecords()); @@ -572,7 +574,7 @@ namespace mongo { const BSONObj k = BSON("" << "c"); verify(this->unindex(k)); - ASSERT_EQUALS(3, this->_helper.btree.fullValidate(NULL, true, true, 0)); + ASSERT_EQUALS(3, this->_helper.btree.fullValidate(&txn, NULL, true, true, 0)); // The tree has 3 buckets + 1 for the this->_helper.dummyDiskLoc ASSERT_EQUALS(4, this->_helper.recordStore.numRecords()); @@ -590,7 +592,7 @@ namespace mongo { builder.makeTree("{d:{b:{a:null},bb:null,cc:{c:null}},i:{f:{e:null},h:{g:null}}}"); - ASSERT_EQUALS(11, this->_helper.btree.fullValidate(NULL, true, true, 0)); + ASSERT_EQUALS(11, this->_helper.btree.fullValidate(&txn, NULL, true, true, 0)); // The tree has 7 buckets + 1 for the this->_helper.dummyDiskLoc ASSERT_EQUALS(8, this->_helper.recordStore.numRecords()); @@ -598,7 +600,7 @@ namespace mongo { const BSONObj k = BSON("" << "bb"); verify(this->unindex(k)); - ASSERT_EQUALS(10, this->_helper.btree.fullValidate(NULL, true, true, 0)); + ASSERT_EQUALS(10, this->_helper.btree.fullValidate(&txn, NULL, true, true, 0)); // Child does not currently replace parent in this case. Also, the tree // has 6 buckets + 1 for the this->_helper.dummyDiskLoc. @@ -617,7 +619,7 @@ namespace mongo { builder.makeTree("{d:{b:{a:null},cc:{c:null}},i:{f:{e:null},ff:null,h:{g:null}}}"); - ASSERT_EQUALS(11, this->_helper.btree.fullValidate(NULL, true, true, 0)); + ASSERT_EQUALS(11, this->_helper.btree.fullValidate(&txn, NULL, true, true, 0)); // The tree has 7 buckets + 1 for the this->_helper.dummyDiskLoc ASSERT_EQUALS(8, this->_helper.recordStore.numRecords()); @@ -625,7 +627,7 @@ namespace mongo { const BSONObj k = BSON("" << "ff"); verify(this->unindex(k)); - ASSERT_EQUALS(10, this->_helper.btree.fullValidate(NULL, true, true, 0)); + ASSERT_EQUALS(10, this->_helper.btree.fullValidate(&txn, NULL, true, true, 0)); // Child does not currently replace parent in this case. Also, the tree // has 6 buckets + 1 for the this->_helper.dummyDiskLoc. @@ -646,7 +648,7 @@ namespace mongo { "dd:null," "_:{f:{e:null},h:{g:null}}}"); - ASSERT_EQUALS(11, this->_helper.btree.fullValidate(NULL, true, true, 0)); + ASSERT_EQUALS(11, this->_helper.btree.fullValidate(&txn, NULL, true, true, 0)); // The tree has 7 buckets + 1 for the this->_helper.dummyDiskLoc ASSERT_EQUALS(8, this->_helper.recordStore.numRecords()); @@ -654,7 +656,7 @@ namespace mongo { const BSONObj k = BSON("" << "bb"); verify(this->unindex(k)); - ASSERT_EQUALS(10, this->_helper.btree.fullValidate(NULL, true, true, 0)); + ASSERT_EQUALS(10, this->_helper.btree.fullValidate(&txn, NULL, true, true, 0)); // The tree has 7 buckets + 1 for the this->_helper.dummyDiskLoc ASSERT_EQUALS(8, this->_helper.recordStore.numRecords()); @@ -674,7 +676,7 @@ namespace mongo { builder.makeTree("{c:{b:{a:null}},d:null,_:{f:{e:null},g:null}}"); - ASSERT_EQUALS(7, this->_helper.btree.fullValidate(NULL, true, true, 0)); + ASSERT_EQUALS(7, this->_helper.btree.fullValidate(&txn, NULL, true, true, 0)); // The tree has 5 buckets + 1 for the this->_helper.dummyDiskLoc ASSERT_EQUALS(6, this->_helper.recordStore.numRecords()); @@ -682,7 +684,7 @@ namespace mongo { const BSONObj k = BSON("" << "g"); verify(this->unindex(k)); - ASSERT_EQUALS(6, this->_helper.btree.fullValidate(NULL, true, true, 0)); + ASSERT_EQUALS(6, this->_helper.btree.fullValidate(&txn, NULL, true, true, 0)); // The tree has 5 buckets + 1 for the this->_helper.dummyDiskLoc ASSERT_EQUALS(6, this->_helper.recordStore.numRecords()); @@ -700,7 +702,7 @@ namespace mongo { builder.makeTree("{c:{b:{a:null}},f:{e:{d:null},ee:null},_:{h:{g:null}}}"); - ASSERT_EQUALS(9, this->_helper.btree.fullValidate(NULL, true, true, 0)); + ASSERT_EQUALS(9, this->_helper.btree.fullValidate(&txn, NULL, true, true, 0)); // The tree has 7 buckets + 1 for the this->_helper.dummyDiskLoc ASSERT_EQUALS(8, this->_helper.recordStore.numRecords()); @@ -708,7 +710,7 @@ namespace mongo { const BSONObj k = BSON("" << "ee"); verify(this->unindex(k)); - ASSERT_EQUALS(8, this->_helper.btree.fullValidate(NULL, true, true, 0)); + ASSERT_EQUALS(8, this->_helper.btree.fullValidate(&txn, NULL, true, true, 0)); // The tree has 6 buckets + 1 for the this->_helper.dummyDiskLoc ASSERT_EQUALS(7, this->_helper.recordStore.numRecords()); @@ -726,7 +728,7 @@ namespace mongo { builder.makeTree("{c:{b:{a:null}},f:{e:{d:null},ee:null},ff:null,_:{h:{g:null}}}"); - ASSERT_EQUALS(10, this->_helper.btree.fullValidate(NULL, true, true, 0)); + ASSERT_EQUALS(10, this->_helper.btree.fullValidate(&txn, NULL, true, true, 0)); // The tree has 7 buckets + 1 for the this->_helper.dummyDiskLoc ASSERT_EQUALS(8, this->_helper.recordStore.numRecords()); @@ -734,7 +736,7 @@ namespace mongo { const BSONObj k = BSON("" << "ee"); verify(this->unindex(k)); - ASSERT_EQUALS(9, this->_helper.btree.fullValidate(NULL, true, true, 0)); + ASSERT_EQUALS(9, this->_helper.btree.fullValidate(&txn, NULL, true, true, 0)); // The tree has 6 buckets + 1 for the this->_helper.dummyDiskLoc ASSERT_EQUALS(7, this->_helper.recordStore.numRecords()); @@ -752,7 +754,7 @@ namespace mongo { builder.makeTree("{c:{b:{a:null}},cc:null,f:{e:{d:null},ee:null},_:{h:{g:null}}}"); - ASSERT_EQUALS(10, this->_helper.btree.fullValidate(NULL, true, true, 0)); + ASSERT_EQUALS(10, this->_helper.btree.fullValidate(&txn, NULL, true, true, 0)); // The tree has 7 buckets + 1 for the this->_helper.dummyDiskLoc ASSERT_EQUALS(8, this->_helper.recordStore.numRecords()); @@ -760,7 +762,7 @@ namespace mongo { const BSONObj k = BSON("" << "ee"); verify(this->unindex(k)); - ASSERT_EQUALS(9, this->_helper.btree.fullValidate(NULL, true, true, 0)); + ASSERT_EQUALS(9, this->_helper.btree.fullValidate(&txn, NULL, true, true, 0)); // The tree has 6 buckets + 1 for the this->_helper.dummyDiskLoc ASSERT_EQUALS(7, this->_helper.recordStore.numRecords()); @@ -778,7 +780,7 @@ namespace mongo { builder.makeTree("{h:{e:{b:{a:null},c:null,d:null},g:{f:null}},j:{i:null}}"); - ASSERT_EQUALS(10, this->_helper.btree.fullValidate(NULL, true, true, 0)); + ASSERT_EQUALS(10, this->_helper.btree.fullValidate(&txn, NULL, true, true, 0)); // The tree has 6 buckets + 1 for the this->_helper.dummyDiskLoc ASSERT_EQUALS(7, this->_helper.recordStore.numRecords()); @@ -786,7 +788,7 @@ namespace mongo { const BSONObj k = BSON("" << "c"); verify(this->unindex(k)); - ASSERT_EQUALS(9, this->_helper.btree.fullValidate(NULL, true, true, 0)); + ASSERT_EQUALS(9, this->_helper.btree.fullValidate(&txn, NULL, true, true, 0)); // The tree has 4 buckets + 1 for the this->_helper.dummyDiskLoc ASSERT_EQUALS(5, this->_helper.recordStore.numRecords()); @@ -805,7 +807,7 @@ namespace mongo { builder.makeTree("{h:{e:{b:{a:null},c:null,d:null},g:{f:null}},_:{i:null}}"); - ASSERT_EQUALS(9, this->_helper.btree.fullValidate(NULL, true, true, 0)); + ASSERT_EQUALS(9, this->_helper.btree.fullValidate(&txn, NULL, true, true, 0)); // The tree has 6 buckets + 1 for the this->_helper.dummyDiskLoc ASSERT_EQUALS(7, this->_helper.recordStore.numRecords()); @@ -813,7 +815,7 @@ namespace mongo { const BSONObj k = BSON("" << "c"); verify(this->unindex(k)); - ASSERT_EQUALS(8, this->_helper.btree.fullValidate(NULL, true, true, 0)); + ASSERT_EQUALS(8, this->_helper.btree.fullValidate(&txn, NULL, true, true, 0)); // The tree has 3 buckets + 1 for the this->_helper.dummyDiskLoc ASSERT_EQUALS(4, this->_helper.recordStore.numRecords()); @@ -831,7 +833,7 @@ namespace mongo { builder.makeTree("{h:{e:{b:{a:null},c:null,d:null},_:{f:null}},_:{i:null}}"); - ASSERT_EQUALS(8, this->_helper.btree.fullValidate(NULL, true, true, 0)); + ASSERT_EQUALS(8, this->_helper.btree.fullValidate(&txn, NULL, true, true, 0)); // The tree has 6 buckets + 1 for the this->_helper.dummyDiskLoc ASSERT_EQUALS(7, this->_helper.recordStore.numRecords()); @@ -839,7 +841,7 @@ namespace mongo { const BSONObj k = BSON("" << "c"); verify(this->unindex(k)); - ASSERT_EQUALS(7, this->_helper.btree.fullValidate(NULL, true, true, 0)); + ASSERT_EQUALS(7, this->_helper.btree.fullValidate(&txn, NULL, true, true, 0)); // The tree has 4 buckets + 1 for the this->_helper.dummyDiskLoc ASSERT_EQUALS(5, this->_helper.recordStore.numRecords()); @@ -897,7 +899,7 @@ namespace mongo { const char *keys = delKeys(); for (const char *i = keys; *i; ++i) { long long unused = 0; - ASSERT_EQUALS(_count, this->_helper.btree.fullValidate(&unused, true, true, 0)); + ASSERT_EQUALS(_count, this->_helper.btree.fullValidate(&txn, &unused, true, true, 0)); ASSERT_EQUALS(0, unused); // The tree has 3 buckets + 1 for the this->_helper.dummyDiskLoc @@ -910,7 +912,7 @@ namespace mongo { } long long unused = 0; - ASSERT_EQUALS(_count, this->_helper.btree.fullValidate(&unused, true, true, 0)); + ASSERT_EQUALS(_count, this->_helper.btree.fullValidate(&txn, &unused, true, true, 0)); ASSERT_EQUALS(0, unused); validate(); @@ -1136,7 +1138,7 @@ namespace mongo { "b:{$20:null,$30:null,$40:null,$50:null,a:null}," "_:{c:null}}"); - ASSERT_EQUALS(14, this->_helper.btree.fullValidate(NULL, true, true, 0)); + ASSERT_EQUALS(14, this->_helper.btree.fullValidate(&txn, NULL, true, true, 0)); // The tree has 4 buckets + 1 for the this->_helper.dummyDiskLoc ASSERT_EQUALS(5, this->_helper.recordStore.numRecords()); @@ -1144,7 +1146,7 @@ namespace mongo { const BSONObj k = BSON("" << bigNumString(0x40, 800)); ASSERT(this->unindex(k)); - ASSERT_EQUALS(13, this->_helper.btree.fullValidate(NULL, true, true, 0)); + ASSERT_EQUALS(13, this->_helper.btree.fullValidate(&txn, NULL, true, true, 0)); // The tree has 4 buckets + 1 for the this->_helper.dummyDiskLoc ASSERT_EQUALS(5, this->_helper.recordStore.numRecords()); @@ -1166,7 +1168,7 @@ namespace mongo { "b:{$20:null,$30:null,$40:null,$50:null,$60:null,$70:null}," "_:{c:null}}"); - ASSERT_EQUALS(13, this->_helper.btree.fullValidate(NULL, true, true, 0)); + ASSERT_EQUALS(13, this->_helper.btree.fullValidate(&txn, NULL, true, true, 0)); // The tree has 4 buckets + 1 for the this->_helper.dummyDiskLoc ASSERT_EQUALS(5, this->_helper.recordStore.numRecords()); @@ -1174,7 +1176,7 @@ namespace mongo { const BSONObj k = BSON("" << bigNumString(0x3, 800)); ASSERT(this->unindex(k)); - ASSERT_EQUALS(12, this->_helper.btree.fullValidate(NULL, true, true, 0)); + ASSERT_EQUALS(12, this->_helper.btree.fullValidate(&txn, NULL, true, true, 0)); // The tree has 4 buckets + 1 for the this->_helper.dummyDiskLoc ASSERT_EQUALS(5, this->_helper.recordStore.numRecords()); @@ -1197,7 +1199,7 @@ namespace mongo { "b:{$30:null,$40:{$35:null},$50:{$45:null}}," "_:{c:null}}"); - ASSERT_EQUALS(23, this->_helper.btree.fullValidate(NULL, true, true, 0)); + ASSERT_EQUALS(23, this->_helper.btree.fullValidate(&txn, NULL, true, true, 0)); // The tree has 14 buckets + 1 for the this->_helper.dummyDiskLoc ASSERT_EQUALS(15, this->_helper.recordStore.numRecords()); @@ -1205,7 +1207,7 @@ namespace mongo { const BSONObj k = BSON("" << bigNumString(0x30, 800)); ASSERT(this->unindex(k)); - ASSERT_EQUALS(22, this->_helper.btree.fullValidate(NULL, true, true, 0)); + ASSERT_EQUALS(22, this->_helper.btree.fullValidate(&txn, NULL, true, true, 0)); // The tree has 14 buckets + 1 for the this->_helper.dummyDiskLoc ASSERT_EQUALS(15, this->_helper.recordStore.numRecords()); @@ -1231,7 +1233,7 @@ namespace mongo { "$90:{$85:null},$100:{$95:null}}," "_:{c:null}}"); - ASSERT_EQUALS(25, this->_helper.btree.fullValidate(NULL, true, true, 0)); + ASSERT_EQUALS(25, this->_helper.btree.fullValidate(&txn, NULL, true, true, 0)); // The tree has 15 buckets + 1 for the this->_helper.dummyDiskLoc ASSERT_EQUALS(16, this->_helper.recordStore.numRecords()); @@ -1239,7 +1241,7 @@ namespace mongo { const BSONObj k = BSON("" << bigNumString(0x5, 800)); ASSERT(this->unindex(k)); - ASSERT_EQUALS(24, this->_helper.btree.fullValidate(NULL, true, true, 0)); + ASSERT_EQUALS(24, this->_helper.btree.fullValidate(&txn, NULL, true, true, 0)); // The tree has 15 buckets + 1 for the this->_helper.dummyDiskLoc ASSERT_EQUALS(16, this->_helper.recordStore.numRecords()); @@ -1262,7 +1264,7 @@ namespace mongo { builder.makeTree("{$10:{$1:null,$2:null,$3:null,$4:null,$5:null,$6:null}," "_:{$20:null,$30:null,$40:null,$50:null,a:null}}"); - ASSERT_EQUALS(12, this->_helper.btree.fullValidate(NULL, true, true, 0)); + ASSERT_EQUALS(12, this->_helper.btree.fullValidate(&txn, NULL, true, true, 0)); // The tree has 3 buckets + 1 for the this->_helper.dummyDiskLoc ASSERT_EQUALS(4, this->_helper.recordStore.numRecords()); @@ -1270,7 +1272,7 @@ namespace mongo { const BSONObj k = BSON("" << bigNumString(0x40, 800)); ASSERT(this->unindex(k)); - ASSERT_EQUALS(11, this->_helper.btree.fullValidate(NULL, true, true, 0)); + ASSERT_EQUALS(11, this->_helper.btree.fullValidate(&txn, NULL, true, true, 0)); // The tree has 3 buckets + 1 for the this->_helper.dummyDiskLoc ASSERT_EQUALS(4, this->_helper.recordStore.numRecords()); @@ -1342,7 +1344,7 @@ namespace mongo { builder.makeTree("{$10:{$1:null,$2:null,$3:null,$4:null,$5:null,$6:null}," "_:{$20:null,$30:null,$40:null,$50:null,a:null}}"); - ASSERT_EQUALS(12, this->_helper.btree.fullValidate(NULL, true, true, 0)); + ASSERT_EQUALS(12, this->_helper.btree.fullValidate(&txn, NULL, true, true, 0)); // The tree has 3 buckets + 1 for the this->_helper.dummyDiskLoc ASSERT_EQUALS(4, this->_helper.recordStore.numRecords()); @@ -1353,7 +1355,7 @@ namespace mongo { const BSONObj k = BSON("" << bigNumString(0x40, 800)); ASSERT(this->unindex(k)); - ASSERT_EQUALS(11, this->_helper.btree.fullValidate(NULL, true, true, 0)); + ASSERT_EQUALS(11, this->_helper.btree.fullValidate(&txn, NULL, true, true, 0)); // The tree has 3 buckets + 1 for the this->_helper.dummyDiskLoc ASSERT_EQUALS(4, this->_helper.recordStore.numRecords()); @@ -1376,7 +1378,7 @@ namespace mongo { "$200:null,$300:null,$400:null,$500:null,$600:null," "$700:null,$800:null,$900:null,_:{c:null}}"); - ASSERT_EQUALS(22, this->_helper.btree.fullValidate(NULL, true, true, 0)); + ASSERT_EQUALS(22, this->_helper.btree.fullValidate(&txn, NULL, true, true, 0)); // The tree has 4 buckets + 1 for the this->_helper.dummyDiskLoc ASSERT_EQUALS(5, this->_helper.recordStore.numRecords()); @@ -1384,7 +1386,7 @@ namespace mongo { const BSONObj k = BSON("" << bigNumString(0x3, 800)); ASSERT(this->unindex(k)); - ASSERT_EQUALS(21, this->_helper.btree.fullValidate(NULL, true, true, 0)); + ASSERT_EQUALS(21, this->_helper.btree.fullValidate(&txn, NULL, true, true, 0)); // The tree has 6 buckets + 1 for the this->_helper.dummyDiskLoc ASSERT_EQUALS(7, this->_helper.recordStore.numRecords()); @@ -1559,7 +1561,7 @@ namespace mongo { "$20:{$11:null,$12:null,$13:null,$14:null}," "_:{$30:null}}"); - ASSERT_EQUALS(13, this->_helper.btree.fullValidate(NULL, true, true, 0)); + ASSERT_EQUALS(13, this->_helper.btree.fullValidate(&txn, NULL, true, true, 0)); // The tree has 4 buckets + 1 for the this->_helper.dummyDiskLoc ASSERT_EQUALS(5, this->_helper.recordStore.numRecords()); @@ -1567,7 +1569,7 @@ namespace mongo { const BSONObj k = BSON("" << bigNumString(0x12, 800)); ASSERT(this->unindex(k)); - ASSERT_EQUALS(12, this->_helper.btree.fullValidate(NULL, true, true, 0)); + ASSERT_EQUALS(12, this->_helper.btree.fullValidate(&txn, NULL, true, true, 0)); // The tree has 4 buckets + 1 for the this->_helper.dummyDiskLoc ASSERT_EQUALS(5, this->_helper.recordStore.numRecords()); @@ -1589,7 +1591,7 @@ namespace mongo { "$20:{$11:null,$12:null,$13:null,$14:null}," "_:{$31:null,$32:null,$33:null,$34:null,$35:null,$36:null}}"); - ASSERT_EQUALS(13, this->_helper.btree.fullValidate(NULL, true, true, 0)); + ASSERT_EQUALS(13, this->_helper.btree.fullValidate(&txn, NULL, true, true, 0)); // The tree has 4 buckets + 1 for the this->_helper.dummyDiskLoc ASSERT_EQUALS(5, this->_helper.recordStore.numRecords()); @@ -1597,7 +1599,7 @@ namespace mongo { const BSONObj k = BSON("" << bigNumString(0x12, 800)); ASSERT(this->unindex(k)); - ASSERT_EQUALS(12, this->_helper.btree.fullValidate(NULL, true, true, 0)); + ASSERT_EQUALS(12, this->_helper.btree.fullValidate(&txn, NULL, true, true, 0)); // The tree has 4 buckets + 1 for the this->_helper.dummyDiskLoc ASSERT_EQUALS(5, this->_helper.recordStore.numRecords()); @@ -1619,7 +1621,7 @@ namespace mongo { "_:{$20:null,$30:null,$40:null,$50:null," "$60:null,$70:null,$80:null,$90:null}}"); - ASSERT_EQUALS(15, this->_helper.btree.fullValidate(NULL, true, true, 0)); + ASSERT_EQUALS(15, this->_helper.btree.fullValidate(&txn, NULL, true, true, 0)); // The tree has 5 buckets + 1 for the this->_helper.dummyDiskLoc ASSERT_EQUALS(6, this->_helper.recordStore.numRecords()); @@ -1627,7 +1629,7 @@ namespace mongo { const BSONObj k = BSON("" << bigNumString(0x7, 800)); ASSERT(this->unindex(k)); - ASSERT_EQUALS(14, this->_helper.btree.fullValidate(NULL, true, true, 0)); + ASSERT_EQUALS(14, this->_helper.btree.fullValidate(&txn, NULL, true, true, 0)); // The tree has 4 buckets + 1 for the this->_helper.dummyDiskLoc ASSERT_EQUALS(5, this->_helper.recordStore.numRecords()); @@ -1647,7 +1649,7 @@ namespace mongo { builder.makeTree("{b:{a:null}}"); - ASSERT_EQUALS(2, this->_helper.btree.fullValidate(NULL, true, true, 0)); + ASSERT_EQUALS(2, this->_helper.btree.fullValidate(&txn, NULL, true, true, 0)); // The tree has 2 buckets + 1 for the this->_helper.dummyDiskLoc ASSERT_EQUALS(3, this->_helper.recordStore.numRecords()); @@ -1655,7 +1657,7 @@ namespace mongo { const BSONObj k = BSON("" << "a"); ASSERT(this->unindex(k)); - ASSERT_EQUALS(1, this->_helper.btree.fullValidate(NULL, true, true, 0)); + ASSERT_EQUALS(1, this->_helper.btree.fullValidate(&txn, NULL, true, true, 0)); // The tree has 1 bucket + 1 for the this->_helper.dummyDiskLoc ASSERT_EQUALS(2, this->_helper.recordStore.numRecords()); @@ -1673,7 +1675,7 @@ namespace mongo { builder.makeTree("{a:null,c:{b:null},d:null}"); - ASSERT_EQUALS(4, this->_helper.btree.fullValidate(NULL, true, true, 0)); + ASSERT_EQUALS(4, this->_helper.btree.fullValidate(&txn, NULL, true, true, 0)); // The tree has 2 buckets + 1 for the this->_helper.dummyDiskLoc ASSERT_EQUALS(3, this->_helper.recordStore.numRecords()); @@ -1681,7 +1683,7 @@ namespace mongo { const BSONObj k = BSON("" << "b"); ASSERT(this->unindex(k)); - ASSERT_EQUALS(3, this->_helper.btree.fullValidate(NULL, true, true, 0)); + ASSERT_EQUALS(3, this->_helper.btree.fullValidate(&txn, NULL, true, true, 0)); // The tree has 1 bucket + 1 for the this->_helper.dummyDiskLoc ASSERT_EQUALS(2, this->_helper.recordStore.numRecords()); @@ -1700,7 +1702,7 @@ namespace mongo { builder.makeTree("{a:null,c:{b:null},d:null}"); long long unused = 0; - ASSERT_EQUALS(4, this->_helper.btree.fullValidate(&unused, true, true, 0)); + ASSERT_EQUALS(4, this->_helper.btree.fullValidate(&txn, &unused, true, true, 0)); // The tree has 2 buckets + 1 for the this->_helper.dummyDiskLoc ASSERT_EQUALS(3, this->_helper.recordStore.numRecords()); @@ -1709,7 +1711,7 @@ namespace mongo { const BSONObj k = BSON("" << "c"); ASSERT(this->unindex(k)); - ASSERT_EQUALS(3, this->_helper.btree.fullValidate(&unused, true, true, 0)); + ASSERT_EQUALS(3, this->_helper.btree.fullValidate(&txn, &unused, true, true, 0)); // The tree has 1 bucket + 1 for the this->_helper.dummyDiskLoc ASSERT_EQUALS(2, this->_helper.recordStore.numRecords()); @@ -1733,7 +1735,7 @@ namespace mongo { this->markKeyUnused(prevChildBucket, 0); long long unused = 0; - ASSERT_EQUALS(3, this->_helper.btree.fullValidate(&unused, true, true, 0)); + ASSERT_EQUALS(3, this->_helper.btree.fullValidate(&txn, &unused, true, true, 0)); // The tree has 2 buckets + 1 for the this->_helper.dummyDiskLoc ASSERT_EQUALS(3, this->_helper.recordStore.numRecords()); @@ -1743,7 +1745,7 @@ namespace mongo { ASSERT(this->unindex(k)); unused = 0; - ASSERT_EQUALS(2, this->_helper.btree.fullValidate(&unused, true, true, 0)); + ASSERT_EQUALS(2, this->_helper.btree.fullValidate(&txn, &unused, true, true, 0)); // The tree has 1 bucket + 1 for the this->_helper.dummyDiskLoc ASSERT_EQUALS(2, this->_helper.recordStore.numRecords()); @@ -1764,7 +1766,7 @@ namespace mongo { builder.makeTree("{a:null,_:{b:null}}"); long long unused = 0; - ASSERT_EQUALS(2, this->_helper.btree.fullValidate(&unused, true, true, 0)); + ASSERT_EQUALS(2, this->_helper.btree.fullValidate(&txn, &unused, true, true, 0)); // The tree has 2 buckets + 1 for the this->_helper.dummyDiskLoc ASSERT_EQUALS(3, this->_helper.recordStore.numRecords()); @@ -1774,7 +1776,7 @@ namespace mongo { ASSERT(this->unindex(k)); unused = 0; - ASSERT_EQUALS(1, this->_helper.btree.fullValidate(&unused, true, true, 0)); + ASSERT_EQUALS(1, this->_helper.btree.fullValidate(&txn, &unused, true, true, 0)); // The tree has 1 bucket + 1 for the this->_helper.dummyDiskLoc ASSERT_EQUALS(2, this->_helper.recordStore.numRecords()); @@ -1794,7 +1796,7 @@ namespace mongo { builder.makeTree("{a:null,y:{d:{c:{b:null}},_:{e:null}},z:null}"); long long unused = 0; - ASSERT_EQUALS(7, this->_helper.btree.fullValidate(&unused, true, true, 0)); + ASSERT_EQUALS(7, this->_helper.btree.fullValidate(&txn, &unused, true, true, 0)); // The tree has 5 buckets + 1 for the this->_helper.dummyDiskLoc ASSERT_EQUALS(6, this->_helper.recordStore.numRecords()); @@ -1804,7 +1806,7 @@ namespace mongo { ASSERT(this->unindex(k)); unused = 0; - ASSERT_EQUALS(6, this->_helper.btree.fullValidate(&unused, true, true, 0)); + ASSERT_EQUALS(6, this->_helper.btree.fullValidate(&txn, &unused, true, true, 0)); // The tree has 3 buckets + 1 for the this->_helper.dummyDiskLoc ASSERT_EQUALS(4, this->_helper.recordStore.numRecords()); @@ -1824,7 +1826,7 @@ namespace mongo { builder.makeTree("{a:null,_:{e:{c:null},_:{f:null}}}"); long long unused = 0; - ASSERT_EQUALS(4, this->_helper.btree.fullValidate(&unused, true, true, 0)); + ASSERT_EQUALS(4, this->_helper.btree.fullValidate(&txn, &unused, true, true, 0)); // The tree has 4 buckets + 1 for the this->_helper.dummyDiskLoc ASSERT_EQUALS(5, this->_helper.recordStore.numRecords()); @@ -1834,7 +1836,7 @@ namespace mongo { ASSERT(this->unindex(k)); unused = 0; - ASSERT_EQUALS(3, this->_helper.btree.fullValidate(&unused, true, true, 0)); + ASSERT_EQUALS(3, this->_helper.btree.fullValidate(&txn, &unused, true, true, 0)); // The tree has 2 buckets + 1 for the this->_helper.dummyDiskLoc ASSERT_EQUALS(3, this->_helper.recordStore.numRecords()); @@ -1854,7 +1856,7 @@ namespace mongo { builder.makeTree("{a:null,d:{c:{b:null}},e:null}"); long long unused = 0; - ASSERT_EQUALS(5, this->_helper.btree.fullValidate(&unused, true, true, 0)); + ASSERT_EQUALS(5, this->_helper.btree.fullValidate(&txn, &unused, true, true, 0)); // The tree has 3 buckets + 1 for the this->_helper.dummyDiskLoc ASSERT_EQUALS(4, this->_helper.recordStore.numRecords()); @@ -1863,7 +1865,7 @@ namespace mongo { const BSONObj k = BSON("" << "d"); ASSERT(this->unindex(k)); - ASSERT_EQUALS(4, this->_helper.btree.fullValidate(&unused, true, true, 0)); + ASSERT_EQUALS(4, this->_helper.btree.fullValidate(&txn, &unused, true, true, 0)); // The tree has 3 buckets + 1 for the this->_helper.dummyDiskLoc ASSERT_EQUALS(4, this->_helper.recordStore.numRecords()); @@ -1886,7 +1888,7 @@ namespace mongo { builder.makeTree("{a:null,_:{c:null,_:{d:null}}}"); long long unused = 0; - ASSERT_EQUALS(3, this->_helper.btree.fullValidate(&unused, true, true, 0)); + ASSERT_EQUALS(3, this->_helper.btree.fullValidate(&txn, &unused, true, true, 0)); // The tree has 3 buckets + 1 for the this->_helper.dummyDiskLoc ASSERT_EQUALS(4, this->_helper.recordStore.numRecords()); @@ -1895,7 +1897,7 @@ namespace mongo { const BSONObj k = BSON("" << "a"); ASSERT(this->unindex(k)); - ASSERT_EQUALS(2, this->_helper.btree.fullValidate(&unused, true, true, 0)); + ASSERT_EQUALS(2, this->_helper.btree.fullValidate(&txn, &unused, true, true, 0)); // The tree has 3 buckets + 1 for the this->_helper.dummyDiskLoc ASSERT_EQUALS(4, this->_helper.recordStore.numRecords()); @@ -1919,7 +1921,7 @@ namespace mongo { "$40:null,$50:null,$60:null,$70:null,$80:null,$90:null,$100:null}"); long long unused = 0; - ASSERT_EQUALS(13, this->_helper.btree.fullValidate(&unused, true, true, 0)); + ASSERT_EQUALS(13, this->_helper.btree.fullValidate(&txn, &unused, true, true, 0)); // The tree has 4 buckets + 1 for the this->_helper.dummyDiskLoc ASSERT_EQUALS(5, this->_helper.recordStore.numRecords()); @@ -1928,7 +1930,7 @@ namespace mongo { const BSONObj k = BSON("" << bigNumString(0x30, 0x10)); ASSERT(this->unindex(k)); - ASSERT_EQUALS(12, this->_helper.btree.fullValidate(&unused, true, true, 0)); + ASSERT_EQUALS(12, this->_helper.btree.fullValidate(&txn, &unused, true, true, 0)); // The tree has 4 buckets + 1 for the this->_helper.dummyDiskLoc ASSERT_EQUALS(5, this->_helper.recordStore.numRecords()); @@ -1951,7 +1953,7 @@ namespace mongo { "$80:null,$90:null,$100$10:{$95:{$93:null},_:{$97:null}}}"); long long unused = 0; - ASSERT_EQUALS(13, this->_helper.btree.fullValidate(&unused, true, true, 0)); + ASSERT_EQUALS(13, this->_helper.btree.fullValidate(&txn, &unused, true, true, 0)); // The tree has 4 buckets + 1 for the this->_helper.dummyDiskLoc ASSERT_EQUALS(5, this->_helper.recordStore.numRecords()); @@ -1960,7 +1962,7 @@ namespace mongo { const BSONObj k = BSON("" << bigNumString(0x100, 0x10)); ASSERT(this->unindex(k)); - ASSERT_EQUALS(12, this->_helper.btree.fullValidate(&unused, true, true, 0)); + ASSERT_EQUALS(12, this->_helper.btree.fullValidate(&txn, &unused, true, true, 0)); // The tree has 4 buckets + 1 for the this->_helper.dummyDiskLoc ASSERT_EQUALS(5, this->_helper.recordStore.numRecords()); @@ -2044,14 +2046,14 @@ namespace mongo { } long long unused = 0; - ASSERT_EQUALS( 0, bt()->fullValidate( dl(), order(), &unused, true ) ); + ASSERT_EQUALS( 0, bt()->fullValidate(&txn, dl(), order(), &unused, true ) ); for ( long long i = 50000; i < 50100; ++i ) { insert( i ); } long long unused2 = 0; - ASSERT_EQUALS( 100, bt()->fullValidate( dl(), order(), &unused2, true ) ); + ASSERT_EQUALS( 100, bt()->fullValidate(&txn, dl(), order(), &unused2, true ) ); // log() << "old unused: " << unused << ", new unused: " << unused2 << endl; // diff --git a/src/mongo/db/structure/btree/btree_test_help.cpp b/src/mongo/db/structure/btree/btree_test_help.cpp index deaca1285ab..a2deff60d27 100644 --- a/src/mongo/db/structure/btree/btree_test_help.cpp +++ b/src/mongo/db/structure/btree/btree_test_help.cpp @@ -174,7 +174,8 @@ namespace mongo { bool ArtificialTreeBuilder<OnDiskFormat>::isPresent(const BSONObj &key, int direction) const { int pos; DiskLoc loc; - return _helper->btree.locate(key, _helper->dummyDiskLoc, direction, &pos, &loc); + OperationContextNoop txn; + return _helper->btree.locate(&txn, key, _helper->dummyDiskLoc, direction, &pos, &loc); } // Static diff --git a/src/mongo/db/structure/catalog/namespace_details_collection_entry.cpp b/src/mongo/db/structure/catalog/namespace_details_collection_entry.cpp index 018d6a735c3..16bfb2cc5cc 100644 --- a/src/mongo/db/structure/catalog/namespace_details_collection_entry.cpp +++ b/src/mongo/db/structure/catalog/namespace_details_collection_entry.cpp @@ -47,8 +47,8 @@ namespace mongo { _db( db ) { } - CollectionOptions NamespaceDetailsCollectionCatalogEntry::getCollectionOptions() const { - return _db->getCollectionOptions( ns().ns() ); + CollectionOptions NamespaceDetailsCollectionCatalogEntry::getCollectionOptions(OperationContext* txn) const { + return _db->getCollectionOptions( txn, ns().ns() ); } int NamespaceDetailsCollectionCatalogEntry::getTotalIndexCount() const { diff --git a/src/mongo/db/structure/catalog/namespace_details_collection_entry.h b/src/mongo/db/structure/catalog/namespace_details_collection_entry.h index e034abf047a..78a5b96f181 100644 --- a/src/mongo/db/structure/catalog/namespace_details_collection_entry.h +++ b/src/mongo/db/structure/catalog/namespace_details_collection_entry.h @@ -52,7 +52,7 @@ namespace mongo { virtual ~NamespaceDetailsCollectionCatalogEntry(){} - virtual CollectionOptions getCollectionOptions() const; + virtual CollectionOptions getCollectionOptions(OperationContext* txn) const; virtual int getTotalIndexCount() const; diff --git a/src/mongo/db/structure/catalog/namespace_details_rsv1_metadata.cpp b/src/mongo/db/structure/catalog/namespace_details_rsv1_metadata.cpp index 88625f0104b..4b03af168c8 100644 --- a/src/mongo/db/structure/catalog/namespace_details_rsv1_metadata.cpp +++ b/src/mongo/db/structure/catalog/namespace_details_rsv1_metadata.cpp @@ -101,7 +101,7 @@ namespace mongo { } } - const DiskLoc& NamespaceDetailsRSV1MetaData::firstExtent() const { + const DiskLoc& NamespaceDetailsRSV1MetaData::firstExtent( OperationContext* txn ) const { return _details->firstExtent; } @@ -109,7 +109,7 @@ namespace mongo { *txn->recoveryUnit()->writing( &_details->firstExtent ) = loc; } - const DiskLoc& NamespaceDetailsRSV1MetaData::lastExtent() const { + const DiskLoc& NamespaceDetailsRSV1MetaData::lastExtent( OperationContext* txn ) const { return _details->lastExtent; } @@ -156,7 +156,7 @@ namespace mongo { return true; } - int NamespaceDetailsRSV1MetaData::lastExtentSize() const { + int NamespaceDetailsRSV1MetaData::lastExtentSize( OperationContext* txn ) const { return _details->lastExtentSize; } @@ -191,7 +191,8 @@ namespace mongo { if ( !_namespaceRecordStore ) return; - scoped_ptr<RecordIterator> iterator( _namespaceRecordStore->getIterator( DiskLoc(), + scoped_ptr<RecordIterator> iterator( _namespaceRecordStore->getIterator( txn, + DiskLoc(), false, CollectionScanParams::FORWARD ) ); while ( !iterator->isEOF() ) { diff --git a/src/mongo/db/structure/catalog/namespace_details_rsv1_metadata.h b/src/mongo/db/structure/catalog/namespace_details_rsv1_metadata.h index d4460de8bf2..7e8ab9af7a7 100644 --- a/src/mongo/db/structure/catalog/namespace_details_rsv1_metadata.h +++ b/src/mongo/db/structure/catalog/namespace_details_rsv1_metadata.h @@ -77,10 +77,10 @@ namespace mongo { const DiskLoc& loc ); virtual void orphanDeletedList(OperationContext* txn); - virtual const DiskLoc& firstExtent() const; + virtual const DiskLoc& firstExtent( OperationContext* txn ) const; virtual void setFirstExtent( OperationContext* txn, const DiskLoc& loc ); - virtual const DiskLoc& lastExtent() const; + virtual const DiskLoc& lastExtent( OperationContext* txn ) const; virtual void setLastExtent( OperationContext* txn, const DiskLoc& loc ); virtual bool isCapped() const; @@ -91,7 +91,7 @@ namespace mongo { virtual bool clearUserFlag( OperationContext* txn, int flag ); virtual bool replaceUserFlags( OperationContext* txn, int flags ); - virtual int lastExtentSize() const; + virtual int lastExtentSize( OperationContext* txn ) const; virtual void setLastExtentSize( OperationContext* txn, int newMax ); virtual long long maxCappedDocs() const; diff --git a/src/mongo/db/structure/record_store.h b/src/mongo/db/structure/record_store.h index c3805976959..1d6ca0098b0 100644 --- a/src/mongo/db/structure/record_store.h +++ b/src/mongo/db/structure/record_store.h @@ -46,6 +46,7 @@ namespace mongo { class MAdvise; class NamespaceDetails; class OperationContext; + class Record; class RecordStoreCompactAdaptor; class RecordStore; @@ -133,7 +134,9 @@ namespace mongo { * @param extraInfo - optional more debug info * @param level - optional, level of debug info to put in (higher is more) */ - virtual int64_t storageSize( BSONObjBuilder* extraInfo = NULL, int infoLevel = 0 ) const = 0; + virtual int64_t storageSize( OperationContext* txn, + BSONObjBuilder* extraInfo = NULL, + int infoLevel = 0 ) const = 0; // CRUD related @@ -170,9 +173,10 @@ namespace mongo { /** * returned iterator owned by caller * canonical to get all would be - * getIterator( DiskLoc(), false, CollectionScanParams::FORWARD ) + * getIterator( txn, DiskLoc(), false, CollectionScanParams::FORWARD ) */ - virtual RecordIterator* getIterator( const DiskLoc& start = DiskLoc(), + virtual RecordIterator* getIterator( OperationContext* txn, + const DiskLoc& start = DiskLoc(), bool tailable = false, const CollectionScanParams::Direction& dir = CollectionScanParams::FORWARD @@ -183,13 +187,13 @@ namespace mongo { * damaged records. The iterator might return every record in the store if all of them * are reachable and not corrupted. */ - virtual RecordIterator* getIteratorForRepair() const = 0; + virtual RecordIterator* getIteratorForRepair( OperationContext* txn ) const = 0; /** * Returns many iterators that partition the RecordStore into many disjoint sets. Iterating * all returned iterators is equivalent to Iterating the full store. */ - virtual std::vector<RecordIterator*> getManyIterators() const = 0; + virtual std::vector<RecordIterator*> getManyIterators( OperationContext* txn ) const = 0; // higher level @@ -233,7 +237,9 @@ namespace mongo { * @param scaleSize - amount by which to scale size metrics * appends any custom stats from the RecordStore or other unique stats */ - virtual void appendCustomStats( BSONObjBuilder* result, double scale ) const = 0; + virtual void appendCustomStats( OperationContext* txn, + BSONObjBuilder* result, + double scale ) const = 0; /** * Load all data into cache. diff --git a/src/mongo/db/structure/record_store_heap.cpp b/src/mongo/db/structure/record_store_heap.cpp index bbaa86ebea1..789b8e2fedd 100644 --- a/src/mongo/db/structure/record_store_heap.cpp +++ b/src/mongo/db/structure/record_store_heap.cpp @@ -29,6 +29,7 @@ * it in the license file. */ +#include "mongo/db/operation_context_noop.h" #include "mongo/db/structure/record_store_heap.h" namespace mongo { @@ -217,29 +218,30 @@ namespace mongo { return Status::OK(); } - RecordIterator* HeapRecordStore::getIterator(const DiskLoc& start, + RecordIterator* HeapRecordStore::getIterator(OperationContext* txn, + const DiskLoc& start, bool tailable, const CollectionScanParams::Direction& dir) const { if (tailable) invariant(_isCapped && dir == CollectionScanParams::FORWARD); if (dir == CollectionScanParams::FORWARD) { - return new HeapRecordIterator(_records, *this, start, tailable); + return new HeapRecordIterator(txn, _records, *this, start, tailable); } else { - return new HeapRecordIterator(_records, *this, start); + return new HeapRecordIterator(txn, _records, *this, start); } } - RecordIterator* HeapRecordStore::getIteratorForRepair() const { + RecordIterator* HeapRecordStore::getIteratorForRepair(OperationContext* txn) const { // TODO maybe make different from HeapRecordIterator - return new HeapRecordIterator(_records, *this); + return new HeapRecordIterator(txn, _records, *this); } - std::vector<RecordIterator*> HeapRecordStore::getManyIterators() const { + std::vector<RecordIterator*> HeapRecordStore::getManyIterators(OperationContext* txn) const { std::vector<RecordIterator*> out; // TODO maybe find a way to return multiple iterators. - out.push_back(new HeapRecordIterator(_records, *this)); + out.push_back(new HeapRecordIterator(txn, _records, *this)); return out; } @@ -297,7 +299,9 @@ namespace mongo { } - void HeapRecordStore::appendCustomStats( BSONObjBuilder* result, double scale ) const { + void HeapRecordStore::appendCustomStats( OperationContext* txn, + BSONObjBuilder* result, + double scale ) const { result->append( "note", "HeapRecordStore has no cusom stats yet" ); } @@ -319,7 +323,9 @@ namespace mongo { invariant(!"increaseStorageSize not yet implemented"); } - int64_t HeapRecordStore::storageSize(BSONObjBuilder* extraInfo, int infoLevel) const { + int64_t HeapRecordStore::storageSize(OperationContext* txn, + BSONObjBuilder* extraInfo, + int infoLevel) const { // Note: not making use of extraInfo or infoLevel since we don't have extents const int64_t recordOverhead = numRecords() * HeapRecord::HeaderSize; return _dataSize + recordOverhead; @@ -337,11 +343,13 @@ namespace mongo { // Forward Iterator // - HeapRecordIterator::HeapRecordIterator(const HeapRecordStore::Records& records, + HeapRecordIterator::HeapRecordIterator(OperationContext* txn, + const HeapRecordStore::Records& records, const HeapRecordStore& rs, DiskLoc start, bool tailable) - : _tailable(tailable), + : _txn(txn), + _tailable(tailable), _lastLoc(minDiskLoc), _killedByInvalidate(false), _records(records), @@ -425,10 +433,12 @@ namespace mongo { // Reverse Iterator // - HeapRecordReverseIterator::HeapRecordReverseIterator(const HeapRecordStore::Records& records, + HeapRecordReverseIterator::HeapRecordReverseIterator(OperationContext* txn, + const HeapRecordStore::Records& records, const HeapRecordStore& rs, DiskLoc start) - : _killedByInvalidate(false), + : _txn(txn), + _killedByInvalidate(false), _records(records), _rs(rs) { if (start.isNull()) { diff --git a/src/mongo/db/structure/record_store_heap.h b/src/mongo/db/structure/record_store_heap.h index 0ea43cc8d76..59959c4c968 100644 --- a/src/mongo/db/structure/record_store_heap.h +++ b/src/mongo/db/structure/record_store_heap.h @@ -79,12 +79,14 @@ namespace mongo { const char* damangeSource, const mutablebson::DamageVector& damages ); - virtual RecordIterator* getIterator( const DiskLoc& start, bool tailable, + virtual RecordIterator* getIterator( OperationContext* txn, + const DiskLoc& start, + bool tailable, const CollectionScanParams::Direction& dir) const; - virtual RecordIterator* getIteratorForRepair() const; + virtual RecordIterator* getIteratorForRepair( OperationContext* txn ) const; - virtual std::vector<RecordIterator*> getManyIterators() const; + virtual std::vector<RecordIterator*> getManyIterators( OperationContext* txn ) const; virtual Status truncate( OperationContext* txn ); @@ -102,7 +104,9 @@ namespace mongo { ValidateAdaptor* adaptor, ValidateResults* results, BSONObjBuilder* output ) const; - virtual void appendCustomStats( BSONObjBuilder* result, double scale ) const; + virtual void appendCustomStats( OperationContext* txn, + BSONObjBuilder* result, + double scale ) const; virtual Status touch( OperationContext* txn, BSONObjBuilder* output ) const; @@ -112,7 +116,9 @@ namespace mongo { virtual void increaseStorageSize( OperationContext* txn, int size, bool enforceQuota ); - virtual int64_t storageSize(BSONObjBuilder* extraInfo = NULL, int infoLevel = 0) const; + virtual int64_t storageSize( OperationContext* txn, + BSONObjBuilder* extraInfo = NULL, + int infoLevel = 0) const; virtual long long dataSize() const { return _dataSize; } @@ -170,7 +176,8 @@ namespace mongo { class HeapRecordIterator : public RecordIterator { public: - HeapRecordIterator(const HeapRecordStore::Records& records, + HeapRecordIterator(OperationContext* txn, + const HeapRecordStore::Records& records, const HeapRecordStore& rs, DiskLoc start = DiskLoc(), bool tailable = false); @@ -190,6 +197,7 @@ namespace mongo { virtual RecordData dataFor( const DiskLoc& loc ) const; private: + OperationContext* _txn; // not owned HeapRecordStore::Records::const_iterator _it; bool _tailable; DiskLoc _lastLoc; // only for restarting tailable @@ -201,7 +209,8 @@ namespace mongo { class HeapRecordReverseIterator : public RecordIterator { public: - HeapRecordReverseIterator(const HeapRecordStore::Records& records, + HeapRecordReverseIterator(OperationContext* txn, + const HeapRecordStore::Records& records, const HeapRecordStore& rs, DiskLoc start = DiskLoc()); @@ -220,6 +229,7 @@ namespace mongo { virtual RecordData dataFor( const DiskLoc& loc ) const; private: + OperationContext* _txn; // not owned HeapRecordStore::Records::const_reverse_iterator _it; bool _killedByInvalidate; diff --git a/src/mongo/db/structure/record_store_v1_base.cpp b/src/mongo/db/structure/record_store_v1_base.cpp index f929b0ef984..784a391e204 100644 --- a/src/mongo/db/structure/record_store_v1_base.cpp +++ b/src/mongo/db/structure/record_store_v1_base.cpp @@ -1,7 +1,7 @@ // record_store_v1_base.cpp /** - * Copyright (C) 2013 10gen Inc. + * Copyright (C) 2013-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, @@ -31,6 +31,7 @@ #include "mongo/db/structure/record_store_v1_base.h" #include "mongo/db/catalog/collection.h" +#include "mongo/db/concurrency/lock_mgr.h" #include "mongo/db/operation_context.h" #include "mongo/db/storage/mmap_v1/extent.h" #include "mongo/db/storage/mmap_v1/extent_manager.h" @@ -71,13 +72,16 @@ namespace mongo { } - int64_t RecordStoreV1Base::storageSize( BSONObjBuilder* extraInfo, int level ) const { + int64_t RecordStoreV1Base::storageSize( OperationContext* txn, + BSONObjBuilder* extraInfo, + int level ) const { BSONArrayBuilder extentInfo; int64_t total = 0; int n = 0; - DiskLoc cur = _details->firstExtent(); + DiskLoc cur = _details->firstExtent(txn); + while ( !cur.isNull() ) { Extent* e = _extentManager->getExtent( cur ); @@ -87,8 +91,7 @@ namespace mongo { if ( extraInfo && level > 0 ) { extentInfo.append( BSON( "len" << e->length << "loc: " << e->myLoc.toBSONObj() ) ); } - - cur = e->xnext; + cur = e->xnext; } if ( extraInfo ) { @@ -118,27 +121,28 @@ namespace mongo { return reinterpret_cast<DeletedRecord*>( recordFor( loc ) ); } - Extent* RecordStoreV1Base::_getExtent( const DiskLoc& loc ) const { + Extent* RecordStoreV1Base::_getExtent( OperationContext* txn, const DiskLoc& loc ) const { return _extentManager->getExtent( loc ); } - DiskLoc RecordStoreV1Base::_getExtentLocForRecord( const DiskLoc& loc ) const { + DiskLoc RecordStoreV1Base::_getExtentLocForRecord( OperationContext* txn, const DiskLoc& loc ) const { return _extentManager->extentLocForV1( loc ); } - DiskLoc RecordStoreV1Base::getNextRecord( const DiskLoc& loc ) const { - DiskLoc next = getNextRecordInExtent( loc ); - if ( !next.isNull() ) + DiskLoc RecordStoreV1Base::getNextRecord( OperationContext* txn, const DiskLoc& loc ) const { + DiskLoc next = getNextRecordInExtent( txn, loc ); + if ( !next.isNull() ) { return next; + } // now traverse extents - Extent* e = _getExtent( _getExtentLocForRecord(loc) ); + Extent* e = _getExtent( txn, _getExtentLocForRecord(txn, loc) ); while ( 1 ) { if ( e->xnext.isNull() ) return DiskLoc(); // end of collection - e = _getExtent( e->xnext ); + e = _getExtent( txn, e->xnext ); if ( !e->firstRecord.isNull() ) break; // entire extent could be empty, keep looking @@ -146,18 +150,19 @@ namespace mongo { return e->firstRecord; } - DiskLoc RecordStoreV1Base::getPrevRecord( const DiskLoc& loc ) const { - DiskLoc prev = getPrevRecordInExtent( loc ); - if ( !prev.isNull() ) + DiskLoc RecordStoreV1Base::getPrevRecord( OperationContext* txn, const DiskLoc& loc ) const { + DiskLoc prev = getPrevRecordInExtent( txn, loc ); + if ( !prev.isNull() ) { return prev; + } // now traverse extents - Extent *e = _getExtent(_getExtentLocForRecord(loc)); + Extent *e = _getExtent(txn, _getExtentLocForRecord(txn, loc)); while ( 1 ) { if ( e->xprev.isNull() ) return DiskLoc(); // end of collection - e = _getExtent( e->xprev ); + e = _getExtent( txn, e->xprev ); if ( !e->firstRecord.isNull() ) break; // entire extent could be empty, keep looking @@ -167,7 +172,8 @@ namespace mongo { } DiskLoc RecordStoreV1Base::_findFirstSpot( OperationContext* txn, - const DiskLoc& extDiskLoc, Extent* e ) { + const DiskLoc& extDiskLoc, + Extent* e ) { DiskLoc emptyLoc = extDiskLoc; emptyLoc.inc( Extent::HeaderSize() ); int delRecLength = e->length - Extent::HeaderSize(); @@ -188,25 +194,26 @@ namespace mongo { } - DiskLoc RecordStoreV1Base::getNextRecordInExtent( const DiskLoc& loc ) const { + DiskLoc RecordStoreV1Base::getNextRecordInExtent( OperationContext* txn, const DiskLoc& loc ) const { int nextOffset = recordFor( loc )->nextOfs(); if ( nextOffset == DiskLoc::NullOfs ) return DiskLoc(); fassert( 17441, abs(nextOffset) >= 8 ); // defensive - return DiskLoc( loc.a(), nextOffset ); + DiskLoc result( loc.a(), nextOffset ); + return result; } - DiskLoc RecordStoreV1Base::getPrevRecordInExtent( const DiskLoc& loc ) const { + DiskLoc RecordStoreV1Base::getPrevRecordInExtent( OperationContext* txn, const DiskLoc& loc ) const { int prevOffset = recordFor( loc )->prevOfs(); if ( prevOffset == DiskLoc::NullOfs ) return DiskLoc(); fassert( 17442, abs(prevOffset) >= 8 ); // defensive - return DiskLoc( loc.a(), prevOffset ); - + DiskLoc result( loc.a(), prevOffset ); + return result; } @@ -356,13 +363,13 @@ namespace mongo { /* remove ourself from the record next/prev chain */ { if ( todelete->prevOfs() != DiskLoc::NullOfs ) { - DiskLoc prev = getPrevRecordInExtent( dl ); + DiskLoc prev = getPrevRecordInExtent( txn, dl ); Record* prevRecord = recordFor( prev ); txn->recoveryUnit()->writingInt( prevRecord->nextOfs() ) = todelete->nextOfs(); } if ( todelete->nextOfs() != DiskLoc::NullOfs ) { - DiskLoc next = getNextRecord( dl ); + DiskLoc next = getNextRecord( txn, dl ); Record* nextRecord = recordFor( next ); txn->recoveryUnit()->writingInt( nextRecord->prevOfs() ) = todelete->prevOfs(); } @@ -370,7 +377,8 @@ namespace mongo { /* remove ourself from extent pointers */ { - Extent *e = _getExtent( todelete->myExtentLoc(dl) ); + DiskLoc extentLoc = todelete->myExtentLoc(dl); + Extent *e = _getExtent( txn, extentLoc ); if ( e->firstRecord == dl ) { txn->recoveryUnit()->writing(&e->firstRecord); if ( todelete->nextOfs() == DiskLoc::NullOfs ) @@ -410,15 +418,16 @@ namespace mongo { } - RecordIterator* RecordStoreV1Base::getIteratorForRepair() const { - return new RecordStoreV1RepairIterator(this); + RecordIterator* RecordStoreV1Base::getIteratorForRepair(OperationContext* txn) const { + return new RecordStoreV1RepairIterator(txn, this); } void RecordStoreV1Base::_addRecordToRecListInExtent(OperationContext* txn, Record *r, DiskLoc loc) { dassert( recordFor(loc) == r ); - Extent *e = _getExtent( _getExtentLocForRecord( loc ) ); + DiskLoc extentLoc = _getExtentLocForRecord( txn, loc ); + Extent *e = _getExtent( txn, extentLoc ); if ( e->lastRecord.isNull() ) { *txn->recoveryUnit()->writing(&e->firstRecord) = loc; *txn->recoveryUnit()->writing(&e->lastRecord) = loc; @@ -440,7 +449,6 @@ namespace mongo { isCapped(), size, enforceQuota ); - Extent *e = _extentManager->getExtent( eloc ); invariant( e ); @@ -453,8 +461,8 @@ namespace mongo { DiskLoc emptyLoc = _findFirstSpot( txn, eloc, e ); - if ( _details->lastExtent().isNull() ) { - invariant( _details->firstExtent().isNull() ); + if ( _details->lastExtent(txn).isNull() ) { + invariant( _details->firstExtent(txn).isNull() ); _details->setFirstExtent( txn, eloc ); _details->setLastExtent( txn, eloc ); _details->setCapExtent( txn, eloc ); @@ -462,9 +470,9 @@ namespace mongo { invariant( e->xnext.isNull() ); } else { - invariant( !_details->firstExtent().isNull() ); - *txn->recoveryUnit()->writing(&e->xprev) = _details->lastExtent(); - *txn->recoveryUnit()->writing(&_extentManager->getExtent(_details->lastExtent())->xnext) = eloc; + invariant( !_details->firstExtent(txn).isNull() ); + *txn->recoveryUnit()->writing(&e->xprev) = _details->lastExtent(txn); + *txn->recoveryUnit()->writing(&_extentManager->getExtent(_details->lastExtent(txn))->xnext) = eloc; _details->setLastExtent( txn, eloc ); } @@ -494,36 +502,37 @@ namespace mongo { output->appendNumber("datasize", _details->dataSize()); output->appendNumber("nrecords", _details->numRecords()); - output->appendNumber("lastExtentSize", _details->lastExtentSize()); + output->appendNumber("lastExtentSize", _details->lastExtentSize(txn)); output->appendNumber("padding", _details->paddingFactor()); - if ( _details->firstExtent().isNull() ) + if ( _details->firstExtent(txn).isNull() ) output->append( "firstExtent", "null" ); else output->append( "firstExtent", - str::stream() << _details->firstExtent().toString() + str::stream() << _details->firstExtent(txn).toString() << " ns:" - << _getExtent( _details->firstExtent() )->nsDiagnostic.toString()); - if ( _details->lastExtent().isNull() ) + << _getExtent( txn, _details->firstExtent(txn) )->nsDiagnostic.toString()); + if ( _details->lastExtent(txn).isNull() ) output->append( "lastExtent", "null" ); else - output->append( "lastExtent", str::stream() << _details->lastExtent().toString() + output->append( "lastExtent", str::stream() << _details->lastExtent(txn).toString() << " ns:" - << _getExtent( _details->lastExtent() )->nsDiagnostic.toString()); + << _getExtent( txn, _details->lastExtent(txn) )->nsDiagnostic.toString()); // 22222222222222222222222222 { // validate extent basics BSONArrayBuilder extentData; int extentCount = 0; + DiskLoc extentDiskLoc; try { - if ( !_details->firstExtent().isNull() ) { - _getExtent( _details->firstExtent() )->assertOk(); - _getExtent( _details->lastExtent() )->assertOk(); + if ( !_details->firstExtent(txn).isNull() ) { + _getExtent( txn, _details->firstExtent(txn) )->assertOk(); + _getExtent( txn, _details->lastExtent(txn) )->assertOk(); } - DiskLoc extentDiskLoc = _details->firstExtent(); + extentDiskLoc = _details->firstExtent(txn); while (!extentDiskLoc.isNull()) { - Extent* thisExtent = _getExtent( extentDiskLoc ); + Extent* thisExtent = _getExtent( txn, extentDiskLoc ); if (full) { extentData << thisExtent->dump(); } @@ -531,18 +540,19 @@ namespace mongo { results->valid = false; } DiskLoc nextDiskLoc = thisExtent->xnext; + if (extentCount > 0 && !nextDiskLoc.isNull() - && _getExtent( nextDiskLoc )->xprev != extentDiskLoc) { + && _getExtent( txn, nextDiskLoc )->xprev != extentDiskLoc) { StringBuilder sb; - sb << "'xprev' pointer " << _getExtent( nextDiskLoc )->xprev.toString() + sb << "'xprev' pointer " << _getExtent( txn, nextDiskLoc )->xprev.toString() << " in extent " << nextDiskLoc.toString() << " does not point to extent " << extentDiskLoc.toString(); results->errors.push_back( sb.str() ); results->valid = false; } - if (nextDiskLoc.isNull() && extentDiskLoc != _details->lastExtent()) { + if (nextDiskLoc.isNull() && extentDiskLoc != _details->lastExtent(txn)) { StringBuilder sb; - sb << "'lastExtent' pointer " << _details->lastExtent().toString() + sb << "'lastExtent' pointer " << _details->lastExtent(txn).toString() << " does not point to last extent in list " << extentDiskLoc.toString(); results->errors.push_back( sb.str() ); results->valid = false; @@ -571,31 +581,33 @@ namespace mongo { // 333333333333333333333333333 bool testingLastExtent = false; try { - if (_details->firstExtent().isNull()) { + DiskLoc firstExtentLoc = _details->firstExtent(txn); + if (firstExtentLoc.isNull()) { // this is ok } else { - output->append("firstExtentDetails", _getExtent(_details->firstExtent())->dump()); - if (!_getExtent(_details->firstExtent())->xprev.isNull()) { + output->append("firstExtentDetails", _getExtent(txn, firstExtentLoc)->dump()); + if (!_getExtent(txn, firstExtentLoc)->xprev.isNull()) { StringBuilder sb; - sb << "'xprev' pointer in 'firstExtent' " << _details->firstExtent().toString() - << " is " << _getExtent(_details->firstExtent())->xprev.toString() + sb << "'xprev' pointer in 'firstExtent' " << _details->firstExtent(txn).toString() + << " is " << _getExtent(txn, firstExtentLoc)->xprev.toString() << ", should be null"; results->errors.push_back( sb.str() ); results->valid = false; } } testingLastExtent = true; - if (_details->lastExtent().isNull()) { + DiskLoc lastExtentLoc = _details->lastExtent(txn); + if (lastExtentLoc.isNull()) { // this is ok } else { - if (_details->firstExtent() != _details->lastExtent()) { - output->append("lastExtentDetails", _getExtent(_details->lastExtent())->dump()); - if (!_getExtent(_details->lastExtent())->xnext.isNull()) { + if (firstExtentLoc != lastExtentLoc) { + output->append("lastExtentDetails", _getExtent(txn, lastExtentLoc)->dump()); + if (!_getExtent(txn, lastExtentLoc)->xnext.isNull()) { StringBuilder sb; - sb << "'xnext' pointer in 'lastExtent' " << _details->lastExtent().toString() - << " is " << _getExtent(_details->lastExtent())->xnext.toString() + sb << "'xnext' pointer in 'lastExtent' " << lastExtentLoc.toString() + << " is " << _getExtent(txn, lastExtentLoc)->xnext.toString() << ", should be null"; results->errors.push_back( sb.str() ); results->valid = false; @@ -626,7 +638,8 @@ namespace mongo { int outOfOrder = 0; DiskLoc cl_last; - scoped_ptr<RecordIterator> iterator( getIterator( DiskLoc(), + scoped_ptr<RecordIterator> iterator( getIterator( txn, + DiskLoc(), false, CollectionScanParams::FORWARD ) ); DiskLoc cl; @@ -771,8 +784,10 @@ namespace mongo { return Status::OK(); } - void RecordStoreV1Base::appendCustomStats( BSONObjBuilder* result, double scale ) const { - result->append( "lastExtentSize", _details->lastExtentSize() / scale ); + void RecordStoreV1Base::appendCustomStats( OperationContext* txn, + BSONObjBuilder* result, + double scale ) const { + result->append( "lastExtentSize", _details->lastExtentSize(txn) / scale ); result->append( "paddingFactor", _details->paddingFactor() ); result->append( "userFlags", _details->userFlags() ); @@ -793,21 +808,21 @@ namespace mongo { Status RecordStoreV1Base::touch( OperationContext* txn, BSONObjBuilder* output ) const { Timer t; - // Note: when this class has document level locking, we'll need a lock to get extents - // and then ideally only hold the collection lock from above while doing actual touching. - std::vector<touch_location> ranges; { - Extent* ext = _getExtent( _details->firstExtent() ); + DiskLoc nextLoc = _details->firstExtent(txn); + Extent* ext = _getExtent( txn, nextLoc ); while ( ext ) { touch_location tl; tl.root = reinterpret_cast<const char*>(ext); tl.length = ext->length; ranges.push_back(tl); - if ( ext->xnext.isNull() ) + + nextLoc = ext->xnext; + if ( nextLoc.isNull() ) ext = NULL; else - ext = _getExtent( ext->xnext ); + ext = _getExtent( txn, nextLoc ); } } @@ -859,8 +874,9 @@ namespace mongo { } void RecordStoreV1Base::IntraExtentIterator::invalidate(const DiskLoc& dl) { - if (dl == _curr) + if (dl == _curr) { getNext(); + } } /* @return the size for an allocated record quantized to 1/16th of the BucketSize diff --git a/src/mongo/db/structure/record_store_v1_base.h b/src/mongo/db/structure/record_store_v1_base.h index 3d393e355ee..7265528762a 100644 --- a/src/mongo/db/structure/record_store_v1_base.h +++ b/src/mongo/db/structure/record_store_v1_base.h @@ -1,7 +1,7 @@ // record_store_v1_base.h /** -* Copyright (C) 2013 10gen Inc. +* Copyright (C) 2013-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, @@ -72,10 +72,10 @@ namespace mongo { const DiskLoc& loc ) = 0; virtual void orphanDeletedList(OperationContext* txn) = 0; - virtual const DiskLoc& firstExtent() const = 0; + virtual const DiskLoc& firstExtent( OperationContext* txn ) const = 0; virtual void setFirstExtent( OperationContext* txn, const DiskLoc& loc ) = 0; - virtual const DiskLoc& lastExtent() const = 0; + virtual const DiskLoc& lastExtent( OperationContext* txn ) const = 0; virtual void setLastExtent( OperationContext* txn, const DiskLoc& loc ) = 0; virtual bool isCapped() const = 0; @@ -86,7 +86,7 @@ namespace mongo { virtual bool clearUserFlag( OperationContext* txn, int flag ) = 0; virtual bool replaceUserFlags( OperationContext* txn, int flags ) = 0; - virtual int lastExtentSize() const = 0; + virtual int lastExtentSize( OperationContext* txn) const = 0; virtual void setLastExtentSize( OperationContext* txn, int newMax ) = 0; virtual long long maxCappedDocs() const = 0; @@ -127,7 +127,9 @@ namespace mongo { virtual long long dataSize() const { return _details->dataSize(); } virtual long long numRecords() const { return _details->numRecords(); } - virtual int64_t storageSize( BSONObjBuilder* extraInfo = NULL, int level = 0 ) const; + virtual int64_t storageSize( OperationContext* txn, + BSONObjBuilder* extraInfo = NULL, + int level = 0 ) const; virtual RecordData dataFor( const DiskLoc& loc ) const; @@ -155,7 +157,7 @@ namespace mongo { const char* damangeSource, const mutablebson::DamageVector& damages ); - virtual RecordIterator* getIteratorForRepair() const; + virtual RecordIterator* getIteratorForRepair( OperationContext* txn ) const; void increaseStorageSize( OperationContext* txn, int size, bool enforceQuota ); @@ -164,7 +166,9 @@ namespace mongo { ValidateAdaptor* adaptor, ValidateResults* results, BSONObjBuilder* output ) const; - virtual void appendCustomStats( BSONObjBuilder* result, double scale ) const; + virtual void appendCustomStats( OperationContext* txn, + BSONObjBuilder* result, + double scale ) const; virtual Status touch( OperationContext* txn, BSONObjBuilder* output ) const; @@ -177,13 +181,13 @@ namespace mongo { */ int getRecordAllocationSize( int minRecordSize ) const; - DiskLoc getExtentLocForRecord( const DiskLoc& loc ) const; + DiskLoc getExtentLocForRecord( OperationContext* txn, const DiskLoc& loc ) const; - DiskLoc getNextRecord( const DiskLoc& loc ) const; - DiskLoc getPrevRecord( const DiskLoc& loc ) const; + DiskLoc getNextRecord( OperationContext* txn, const DiskLoc& loc ) const; + DiskLoc getPrevRecord( OperationContext* txn, const DiskLoc& loc ) const; - DiskLoc getNextRecordInExtent( const DiskLoc& loc ) const; - DiskLoc getPrevRecordInExtent( const DiskLoc& loc ) const; + DiskLoc getNextRecordInExtent( OperationContext* txn, const DiskLoc& loc ) const; + DiskLoc getPrevRecordInExtent( OperationContext* txn, const DiskLoc& loc ) const; /* @return the size for an allocated record quantized to 1/16th of the BucketSize. @param allocSize requested size to allocate @@ -221,15 +225,15 @@ namespace mongo { virtual DeletedRecord* drec( const DiskLoc& loc ) const; // just a wrapper for _extentManager->getExtent( loc ); - Extent* _getExtent( const DiskLoc& loc ) const; + Extent* _getExtent( OperationContext* txn, const DiskLoc& loc ) const; - DiskLoc _getExtentLocForRecord( const DiskLoc& loc ) const; + DiskLoc _getExtentLocForRecord( OperationContext* txn, const DiskLoc& loc ) const; - DiskLoc _getNextRecord( const DiskLoc& loc ) const; - DiskLoc _getPrevRecord( const DiskLoc& loc ) const; + DiskLoc _getNextRecord( OperationContext* txn, const DiskLoc& loc ) const; + DiskLoc _getPrevRecord( OperationContext* txn, const DiskLoc& loc ) const; - DiskLoc _getNextRecordInExtent( const DiskLoc& loc ) const; - DiskLoc _getPrevRecordInExtent( const DiskLoc& loc ) const; + DiskLoc _getNextRecordInExtent( OperationContext* txn, const DiskLoc& loc ) const; + DiskLoc _getPrevRecordInExtent( OperationContext* txn, const DiskLoc& loc ) const; /** * finds the first suitable DiskLoc for data @@ -268,14 +272,17 @@ namespace mongo { */ class RecordStoreV1Base::IntraExtentIterator : public RecordIterator { public: - IntraExtentIterator(DiskLoc start, const RecordStoreV1Base* rs, bool forward = true) - : _curr(start), _rs(rs), _forward(forward) {} + IntraExtentIterator(OperationContext* txn, + DiskLoc start, + const RecordStoreV1Base* rs, + bool forward = true) + : _txn(txn), _curr(start), _rs(rs), _forward(forward) {} virtual bool isEOF() { return _curr.isNull(); } virtual DiskLoc curr() { return _curr; } - virtual DiskLoc getNext(); + virtual DiskLoc getNext( ); virtual void invalidate(const DiskLoc& dl); @@ -287,6 +294,7 @@ namespace mongo { private: virtual const Record* recordFor( const DiskLoc& loc ) const { return _rs->recordFor(loc); } + OperationContext* _txn; DiskLoc _curr; const RecordStoreV1Base* _rs; bool _forward; diff --git a/src/mongo/db/structure/record_store_v1_capped.cpp b/src/mongo/db/structure/record_store_v1_capped.cpp index 57657a1f3b2..fbc6c2e8186 100644 --- a/src/mongo/db/structure/record_store_v1_capped.cpp +++ b/src/mongo/db/structure/record_store_v1_capped.cpp @@ -67,7 +67,7 @@ namespace mongo { : RecordStoreV1Base( ns, details, em, isSystemIndexes ), _deleteCallback( collection ) { - DiskLoc extentLoc = details->firstExtent(); + DiskLoc extentLoc = details->firstExtent(txn); while ( !extentLoc.isNull() ) { _extentAdvice.push_back( _extentManager->cacheHint( extentLoc, ExtentManager::Sequential ) ); @@ -94,11 +94,11 @@ namespace mongo { // the extent check is a way to try and improve performance // since we have to iterate all the extents (for now) to get // storage size - if ( lenToAlloc > storageSize() ) { + if ( lenToAlloc > storageSize(txn) ) { return StatusWith<DiskLoc>( ErrorCodes::BadValue, mongoutils::str::stream() << "document is larger than capped size " - << lenToAlloc << " > " << storageSize(), + << lenToAlloc << " > " << storageSize(txn), 16328 ); } @@ -136,7 +136,7 @@ namespace mongo { if ( !_details->capFirstNewRecord().isValid() ) { advanceCapExtent( txn, _ns ); - if ( _details->capExtent() != _details->firstExtent() ) + if ( _details->capExtent() != _details->firstExtent(txn) ) _details->setCapFirstNewRecord( txn, DiskLoc().setInvalid() ); // else signal done with first iteration through extents. continue; @@ -155,7 +155,7 @@ namespace mongo { firstEmptyExtent = _details->capExtent(); advanceCapExtent( txn, _ns ); if ( firstEmptyExtent == _details->capExtent() ) { - _maybeComplain( lenToAlloc ); + _maybeComplain( txn, lenToAlloc ); return StatusWith<DiskLoc>( ErrorCodes::InternalError, "no space in capped collection" ); } @@ -220,7 +220,7 @@ namespace mongo { setListOfAllDeletedRecords( txn, DiskLoc() ); // preserve firstExtent/lastExtent - _details->setCapExtent( txn, _details->firstExtent() ); + _details->setCapExtent( txn, _details->firstExtent(txn) ); _details->setStats( txn, 0, 0 ); // preserve lastExtentSize // nIndexes preserve 0 @@ -234,7 +234,7 @@ namespace mongo { // Reset all existing extents and recreate the deleted list. Extent* ext; - for( DiskLoc extLoc = _details->firstExtent(); + for( DiskLoc extLoc = _details->firstExtent(txn); !extLoc.isNull(); extLoc = ext->xnext ) { ext = _extentManager->getExtent(extLoc); @@ -340,7 +340,7 @@ namespace mongo { // NOTE cappedLastDelRecLastExtent() set to DiskLoc() in above // Last, in case we're killed before getting here - _details->setCapExtent( txn, _details->firstExtent() ); + _details->setCapExtent( txn, _details->firstExtent(txn) ); } } @@ -369,7 +369,7 @@ namespace mongo { void CappedRecordStoreV1::advanceCapExtent( OperationContext* txn, const StringData& ns ) { // We want cappedLastDelRecLastExtent() to be the last DeletedRecord of the prev cap extent // (or DiskLoc() if new capExtent == firstExtent) - if ( _details->capExtent() == _details->lastExtent() ) + if ( _details->capExtent() == _details->lastExtent(txn) ) setLastDelRecLastExtent( txn, DiskLoc() ); else { DiskLoc i = cappedFirstDeletedInCurExtent(); @@ -378,7 +378,7 @@ namespace mongo { } _details->setCapExtent( txn, - theCapExtent()->xnext.isNull() ? _details->firstExtent() + theCapExtent()->xnext.isNull() ? _details->firstExtent(txn) : theCapExtent()->xnext ); /* this isn't true if a collection has been renamed...that is ok just used for diagnostics */ @@ -415,7 +415,7 @@ namespace mongo { } void CappedRecordStoreV1::cappedTruncateLastDelUpdate(OperationContext* txn) { - if ( _details->capExtent() == _details->firstExtent() ) { + if ( _details->capExtent() == _details->firstExtent(txn) ) { // Only one extent of the collection is in use, so there // is no deleted record in a previous extent, so nullify // cappedLastDelRecLastExtent(). @@ -522,8 +522,8 @@ namespace mongo { DiskLoc newCapExtent = _details->capExtent(); do { // Find the previous extent, looping if necessary. - newCapExtent = ( newCapExtent == _details->firstExtent() ) ? - _details->lastExtent() : + newCapExtent = ( newCapExtent == _details->firstExtent(txn) ) ? + _details->lastExtent(txn) : _extentManager->getExtent(newCapExtent)->xprev; _extentManager->getExtent(newCapExtent)->assertOk(); } @@ -586,23 +586,26 @@ namespace mongo { } } - RecordIterator* CappedRecordStoreV1::getIterator( const DiskLoc& start, bool tailable, + RecordIterator* CappedRecordStoreV1::getIterator( OperationContext* txn, + const DiskLoc& start, + bool tailable, const CollectionScanParams::Direction& dir) const { - return new CappedRecordStoreV1Iterator( this, start, tailable, dir ); + return new CappedRecordStoreV1Iterator( txn, this, start, tailable, dir ); } - vector<RecordIterator*> CappedRecordStoreV1::getManyIterators() const { + vector<RecordIterator*> CappedRecordStoreV1::getManyIterators( OperationContext* txn ) const { OwnedPointerVector<RecordIterator> iterators; if (!_details->capLooped()) { // if we haven't looped yet, just spit out all extents (same as non-capped impl) const Extent* ext; - for (DiskLoc extLoc = details()->firstExtent(); !extLoc.isNull(); extLoc = ext->xnext) { - ext = _getExtent(extLoc); + for (DiskLoc extLoc = details()->firstExtent(txn); !extLoc.isNull(); extLoc = ext->xnext) { + ext = _getExtent(txn, extLoc); if (ext->firstRecord.isNull()) continue; - iterators.push_back(new RecordStoreV1Base::IntraExtentIterator(ext->firstRecord, + iterators.push_back(new RecordStoreV1Base::IntraExtentIterator(txn, + ext->firstRecord, this)); } } @@ -616,28 +619,32 @@ namespace mongo { // First do the "old" portion of capExtent if there is any DiskLoc extLoc = capExtent; { - const Extent* ext = _getExtent(extLoc); + const Extent* ext = _getExtent(txn, extLoc); if (ext->firstRecord != details()->capFirstNewRecord()) { // this means there is old data in capExtent - iterators.push_back(new RecordStoreV1Base::IntraExtentIterator(ext->firstRecord, + iterators.push_back(new RecordStoreV1Base::IntraExtentIterator(txn, + ext->firstRecord, this)); } - extLoc = ext->xnext.isNull() ? details()->firstExtent() : ext->xnext; + extLoc = ext->xnext.isNull() ? details()->firstExtent(txn) : ext->xnext; } // Next handle all the other extents while (extLoc != capExtent) { - const Extent* ext = _getExtent(extLoc); - iterators.push_back(new RecordStoreV1Base::IntraExtentIterator(ext->firstRecord, + const Extent* ext = _getExtent(txn, extLoc); + iterators.push_back(new RecordStoreV1Base::IntraExtentIterator(txn, + ext->firstRecord, this)); - extLoc = ext->xnext.isNull() ? details()->firstExtent() : ext->xnext; + extLoc = ext->xnext.isNull() ? details()->firstExtent(txn) : ext->xnext; } // Finally handle the "new" data in the capExtent iterators.push_back( - new RecordStoreV1Base::IntraExtentIterator(details()->capFirstNewRecord(), this)); + new RecordStoreV1Base::IntraExtentIterator(txn, + details()->capFirstNewRecord(), + this)); } return iterators.release(); @@ -650,13 +657,13 @@ namespace mongo { invariant(false); } - void CappedRecordStoreV1::_maybeComplain( int len ) const { + void CappedRecordStoreV1::_maybeComplain( OperationContext* txn, int len ) const { RARELY { std::stringstream buf; buf << "couldn't make room for record len: " << len << " in capped ns " << _ns << '\n'; buf << "numRecords: " << numRecords() << '\n'; int i = 0; - for ( DiskLoc e = _details->firstExtent(); + for ( DiskLoc e = _details->firstExtent(txn); !e.isNull(); e = _extentManager->getExtent( e )->xnext, ++i ) { buf << " Extent " << i; @@ -676,12 +683,13 @@ namespace mongo { warning() << buf.str(); // assume it is unusually large record; if not, something is broken - fassert( 17438, len * 5 > _details->lastExtentSize() ); + fassert( 17438, len * 5 > _details->lastExtentSize(txn) ); } } - DiskLoc CappedRecordStoreV1::firstRecord( const DiskLoc &startExtent ) const { - for (DiskLoc i = startExtent.isNull() ? _details->firstExtent() : startExtent; + DiskLoc CappedRecordStoreV1::firstRecord( OperationContext* txn, + const DiskLoc &startExtent ) const { + for (DiskLoc i = startExtent.isNull() ? _details->firstExtent(txn) : startExtent; !i.isNull(); i = _extentManager->getExtent( i )->xnext ) { @@ -693,8 +701,9 @@ namespace mongo { return DiskLoc(); } - DiskLoc CappedRecordStoreV1::lastRecord( const DiskLoc &startExtent ) const { - for (DiskLoc i = startExtent.isNull() ? _details->lastExtent() : startExtent; + DiskLoc CappedRecordStoreV1::lastRecord( OperationContext* txn, + const DiskLoc &startExtent ) const { + for (DiskLoc i = startExtent.isNull() ? _details->lastExtent(txn) : startExtent; !i.isNull(); i = _extentManager->getExtent( i )->xprev ) { diff --git a/src/mongo/db/structure/record_store_v1_capped.h b/src/mongo/db/structure/record_store_v1_capped.h index dcc19cf0c08..02f28727f30 100644 --- a/src/mongo/db/structure/record_store_v1_capped.h +++ b/src/mongo/db/structure/record_store_v1_capped.h @@ -62,10 +62,11 @@ namespace mongo { */ virtual void temp_cappedTruncateAfter( OperationContext* txn, DiskLoc end, bool inclusive ); - virtual RecordIterator* getIterator( const DiskLoc& start, bool tailable, + virtual RecordIterator* getIterator( OperationContext* txn, + const DiskLoc& start, bool tailable, const CollectionScanParams::Direction& dir) const; - virtual std::vector<RecordIterator*> getManyIterators() const; + virtual std::vector<RecordIterator*> getManyIterators( OperationContext* txn ) const; virtual bool compactSupported() const { return false; } @@ -75,9 +76,11 @@ namespace mongo { CompactStats* stats ); // Start from firstExtent by default. - DiskLoc firstRecord( const DiskLoc &startExtent = DiskLoc() ) const; + DiskLoc firstRecord( OperationContext* txn, + const DiskLoc &startExtent = DiskLoc() ) const; // Start from lastExtent by default. - DiskLoc lastRecord( const DiskLoc &startExtent = DiskLoc() ) const; + DiskLoc lastRecord( OperationContext* txn, + const DiskLoc &startExtent = DiskLoc() ) const; protected: @@ -121,7 +124,7 @@ namespace mongo { DiskLoc end, bool inclusive); - void _maybeComplain( int len ) const; + void _maybeComplain( OperationContext* txn, int len ) const; // -- end copy from cap.cpp -- diff --git a/src/mongo/db/structure/record_store_v1_capped_iterator.cpp b/src/mongo/db/structure/record_store_v1_capped_iterator.cpp index 12e6f945f20..c10557d6547 100644 --- a/src/mongo/db/structure/record_store_v1_capped_iterator.cpp +++ b/src/mongo/db/structure/record_store_v1_capped_iterator.cpp @@ -39,10 +39,11 @@ namespace mongo { // // Capped collection traversal // - CappedRecordStoreV1Iterator::CappedRecordStoreV1Iterator( const CappedRecordStoreV1* collection, + CappedRecordStoreV1Iterator::CappedRecordStoreV1Iterator( OperationContext* txn, + const CappedRecordStoreV1* collection, const DiskLoc& start, bool tailable, const CollectionScanParams::Direction& dir) - : _recordStore(collection), _curr(start), _tailable(tailable), + : _txn(txn), _recordStore(collection), _curr(start), _tailable(tailable), _direction(dir), _killedByInvalidate(false) { if (_curr.isNull()) { @@ -55,7 +56,7 @@ namespace mongo { // Going forwards. if (!nsd->capLooped()) { // If our capped collection doesn't loop around, the first record is easy. - _curr = collection->firstRecord(); + _curr = collection->firstRecord(_txn); } else { // Our capped collection has "looped' around. @@ -72,7 +73,7 @@ namespace mongo { // Going backwards if (!nsd->capLooped()) { // Start at the end. - _curr = collection->lastRecord(); + _curr = collection->lastRecord(_txn); } else { _curr = _getExtent( nsd->capExtent() )->lastRecord; @@ -205,7 +206,7 @@ namespace mongo { if (!next.isNull()) { return next; } - return _recordStore->firstRecord(); + return _recordStore->firstRecord(_txn); } DiskLoc CappedRecordStoreV1Iterator::prevLoop(const DiskLoc& curr) { @@ -214,7 +215,7 @@ namespace mongo { if (!prev.isNull()) { return prev; } - return _recordStore->lastRecord(); + return _recordStore->lastRecord(_txn); } RecordData CappedRecordStoreV1Iterator::dataFor( const DiskLoc& loc ) const { @@ -226,11 +227,11 @@ namespace mongo { } DiskLoc CappedRecordStoreV1Iterator::_getNextRecord( const DiskLoc& loc ) { - return _recordStore->getNextRecord( loc ); + return _recordStore->getNextRecord( _txn, loc ); } DiskLoc CappedRecordStoreV1Iterator::_getPrevRecord( const DiskLoc& loc ) { - return _recordStore->getPrevRecord( loc ); + return _recordStore->getPrevRecord( _txn, loc ); } } // namespace mongo diff --git a/src/mongo/db/structure/record_store_v1_capped_iterator.h b/src/mongo/db/structure/record_store_v1_capped_iterator.h index 041aef81c05..c63d265ec2e 100644 --- a/src/mongo/db/structure/record_store_v1_capped_iterator.h +++ b/src/mongo/db/structure/record_store_v1_capped_iterator.h @@ -47,7 +47,8 @@ namespace mongo { */ class CappedRecordStoreV1Iterator : public RecordIterator { public: - CappedRecordStoreV1Iterator( const CappedRecordStoreV1* collection, + CappedRecordStoreV1Iterator( OperationContext* txn, + const CappedRecordStoreV1* collection, const DiskLoc& start, bool tailable, const CollectionScanParams::Direction& dir ); @@ -76,6 +77,9 @@ namespace mongo { DiskLoc _getNextRecord( const DiskLoc& loc ); DiskLoc _getPrevRecord( const DiskLoc& loc ); + // transactional context for read locks. Not owned by us + OperationContext* _txn; + // The collection we're iterating over. const CappedRecordStoreV1* _recordStore; diff --git a/src/mongo/db/structure/record_store_v1_capped_test.cpp b/src/mongo/db/structure/record_store_v1_capped_test.cpp index 1ab2c5fae07..6ec414ff87d 100644 --- a/src/mongo/db/structure/record_store_v1_capped_test.cpp +++ b/src/mongo/db/structure/record_store_v1_capped_test.cpp @@ -70,7 +70,7 @@ namespace { { BSONObjBuilder b; - int64_t storageSize = rs.storageSize( &b ); + int64_t storageSize = rs.storageSize( &txn, &b ); BSONObj obj = b.obj(); ASSERT_EQUALS( 1, obj["numExtents"].numberInt() ); ASSERT_EQUALS( storageSize, em.quantizeExtentSize( 1024 ) ); @@ -127,7 +127,7 @@ namespace { {DiskLoc(0, 1100), 900}, {} }; - assertStateV1RS(recs, drecs, &em, md); + assertStateV1RS(&txn, recs, drecs, &em, md); ASSERT_EQUALS(md->capExtent(), DiskLoc(0, 0)); ASSERT_EQUALS(md->capFirstNewRecord(), DiskLoc().setInvalid()); // unlooped } @@ -173,7 +173,7 @@ namespace { {DiskLoc(0, 1500), 50}, // gap at end of extent {} }; - assertStateV1RS(recs, drecs, &em, md); + assertStateV1RS(&txn, recs, drecs, &em, md); ASSERT_EQUALS(md->capExtent(), DiskLoc(0, 0)); ASSERT_EQUALS(md->capFirstNewRecord(), DiskLoc(0, 1000)); } @@ -219,7 +219,7 @@ namespace { {DiskLoc(0, 1500), 50}, // gap at end of extent {} }; - assertStateV1RS(recs, drecs, &em, md); + assertStateV1RS(&txn, recs, drecs, &em, md); ASSERT_EQUALS(md->capExtent(), DiskLoc(0, 0)); ASSERT_EQUALS(md->capFirstNewRecord(), DiskLoc(0, 1000)); } @@ -268,7 +268,7 @@ namespace { {DiskLoc(0, 1500), 123}, // gap at end of extent {} }; - assertStateV1RS(recs, drecs, &em, md); + assertStateV1RS(&txn, recs, drecs, &em, md); ASSERT_EQUALS(md->capExtent(), DiskLoc(0, 0)); ASSERT_EQUALS(md->capFirstNewRecord(), DiskLoc(0, 1000)); } @@ -315,7 +315,7 @@ namespace { {DiskLoc(0, 1600), 24}, // gap at end of extent {} }; - assertStateV1RS(recs, drecs, &em, md); + assertStateV1RS(&txn, recs, drecs, &em, md); ASSERT_EQUALS(md->capExtent(), DiskLoc(0, 0)); ASSERT_EQUALS(md->capFirstNewRecord(), DiskLoc(0, 1000)); } @@ -362,7 +362,7 @@ namespace { {DiskLoc(1, 1100), 900}, {} }; - assertStateV1RS(recs, drecs, &em, md); + assertStateV1RS(&txn, recs, drecs, &em, md); ASSERT_EQUALS(md->capExtent(), DiskLoc(1, 0)); ASSERT_EQUALS(md->capFirstNewRecord(), DiskLoc().setInvalid()); // unlooped } @@ -413,7 +413,7 @@ namespace { {DiskLoc(1, 1900), 100}, {} }; - assertStateV1RS(recs, drecs, &em, md); + assertStateV1RS(&txn, recs, drecs, &em, md); ASSERT_EQUALS(md->capExtent(), DiskLoc(1, 0)); ASSERT_EQUALS(md->capFirstNewRecord(), DiskLoc(1, 1000)); } @@ -468,7 +468,7 @@ namespace { {DiskLoc(0, 1920), 80}, {} }; - assertStateV1RS(recs, drecs, &em, md); + assertStateV1RS(&txn, recs, drecs, &em, md); ASSERT_EQUALS(md->capExtent(), DiskLoc(0, 0)); ASSERT_EQUALS(md->capFirstNewRecord(), DiskLoc(0, 1000)); } @@ -550,7 +550,7 @@ namespace { {DiskLoc(0, 1628), 84}, {} }; - assertStateV1RS(recs, drecs, &em, md); + assertStateV1RS(&txn, recs, drecs, &em, md); ASSERT_EQUALS(md->capExtent(), DiskLoc(0, 0)); ASSERT_EQUALS(md->capFirstNewRecord(), DiskLoc(0, 1000)); } diff --git a/src/mongo/db/structure/record_store_v1_repair_iterator.cpp b/src/mongo/db/structure/record_store_v1_repair_iterator.cpp index 373f8760bf7..aaa96fa2db8 100644 --- a/src/mongo/db/structure/record_store_v1_repair_iterator.cpp +++ b/src/mongo/db/structure/record_store_v1_repair_iterator.cpp @@ -35,8 +35,9 @@ namespace mongo { - RecordStoreV1RepairIterator::RecordStoreV1RepairIterator(const RecordStoreV1Base* recordStore) - : _recordStore(recordStore), _stage(FORWARD_SCAN) { + RecordStoreV1RepairIterator::RecordStoreV1RepairIterator(OperationContext* txn, + const RecordStoreV1Base* recordStore) + : _txn(txn), _recordStore(recordStore), _stage(FORWARD_SCAN) { // Position the iterator at the first record // @@ -73,10 +74,10 @@ namespace mongo { else { switch (_stage) { case FORWARD_SCAN: - _currRecord = _recordStore->getNextRecordInExtent(_currRecord); + _currRecord = _recordStore->getNextRecordInExtent(_txn, _currRecord); break; case BACKWARD_SCAN: - _currRecord = _recordStore->getPrevRecordInExtent(_currRecord); + _currRecord = _recordStore->getPrevRecordInExtent(_txn, _currRecord); break; default: invariant(!"This should never be reached."); @@ -113,10 +114,10 @@ namespace mongo { if (_currExtent.isNull()) { switch (_stage) { case FORWARD_SCAN: - _currExtent = _recordStore->details()->firstExtent(); + _currExtent = _recordStore->details()->firstExtent(_txn); break; case BACKWARD_SCAN: - _currExtent = _recordStore->details()->lastExtent(); + _currExtent = _recordStore->details()->lastExtent(_txn); break; default: invariant(DONE == _stage); diff --git a/src/mongo/db/structure/record_store_v1_repair_iterator.h b/src/mongo/db/structure/record_store_v1_repair_iterator.h index 01170617b78..a0319982fda 100644 --- a/src/mongo/db/structure/record_store_v1_repair_iterator.h +++ b/src/mongo/db/structure/record_store_v1_repair_iterator.h @@ -42,7 +42,8 @@ namespace mongo { */ class RecordStoreV1RepairIterator : public RecordIterator { public: - RecordStoreV1RepairIterator(const RecordStoreV1Base* recordStore); + RecordStoreV1RepairIterator(OperationContext* txn, + const RecordStoreV1Base* recordStore); virtual ~RecordStoreV1RepairIterator() { } virtual bool isEOF(); @@ -68,6 +69,9 @@ namespace mongo { */ bool _advanceToNextValidExtent(); + // transactional context for read locks. Not owned by us + OperationContext* _txn; + // Reference to the owning RecordStore. The store must not be deleted while there are // active iterators on it. // diff --git a/src/mongo/db/structure/record_store_v1_simple.cpp b/src/mongo/db/structure/record_store_v1_simple.cpp index 7e99a1b7640..21dd0d7363e 100644 --- a/src/mongo/db/structure/record_store_v1_simple.cpp +++ b/src/mongo/db/structure/record_store_v1_simple.cpp @@ -1,7 +1,7 @@ // record_store_v1_simple.cpp /** - * Copyright (C) 2013 10gen Inc. + * Copyright (C) 2013-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, @@ -96,6 +96,7 @@ namespace mongo { int bestmatchlen = INT_MAX; // sentinel meaning we haven't found a record big enough int b = bucket(lenToAlloc); DiskLoc cur = _details->deletedListEntry(b); + int extra = 5; // look for a better fit, a little. int chain = 0; while ( 1 ) { @@ -220,9 +221,7 @@ namespace mongo { newDelW->nextDeleted().Null(); addDeletedRec( txn, newDelLoc ); - return loc; - } StatusWith<DiskLoc> SimpleRecordStoreV1::allocRecord( OperationContext* txn, @@ -236,7 +235,7 @@ namespace mongo { increaseStorageSize( txn, _extentManager->followupSize( lengthWithHeaders, - _details->lastExtentSize()), + _details->lastExtentSize(txn)), enforceQuota ); loc = _allocFromExistingExtents( txn, lengthWithHeaders ); @@ -247,14 +246,14 @@ namespace mongo { log() << "warning: alloc() failed after allocating new extent. " << "lengthWithHeaders: " << lengthWithHeaders << " last extent size:" - << _details->lastExtentSize() << "; trying again"; + << _details->lastExtentSize(txn) << "; trying again"; - for ( int z = 0; z < 10 && lengthWithHeaders > _details->lastExtentSize(); z++ ) { + for ( int z = 0; z < 10 && lengthWithHeaders > _details->lastExtentSize(txn); z++ ) { log() << "try #" << z << endl; increaseStorageSize( txn, _extentManager->followupSize( lengthWithHeaders, - _details->lastExtentSize()), + _details->lastExtentSize(txn)), enforceQuota ); loc = _allocFromExistingExtents( txn, lengthWithHeaders ); @@ -280,20 +279,22 @@ namespace mongo { _details->setDeletedListEntry(txn, b, dloc); } - RecordIterator* SimpleRecordStoreV1::getIterator( const DiskLoc& start, bool tailable, + RecordIterator* SimpleRecordStoreV1::getIterator( OperationContext* txn, + const DiskLoc& start, + bool tailable, const CollectionScanParams::Direction& dir) const { - return new SimpleRecordStoreV1Iterator( this, start, dir ); + return new SimpleRecordStoreV1Iterator( txn, this, start, dir ); } - vector<RecordIterator*> SimpleRecordStoreV1::getManyIterators() const { + vector<RecordIterator*> SimpleRecordStoreV1::getManyIterators( OperationContext* txn ) const { OwnedPointerVector<RecordIterator> iterators; const Extent* ext; - for (DiskLoc extLoc = details()->firstExtent(); !extLoc.isNull(); extLoc = ext->xnext) { - ext = _getExtent(extLoc); + for (DiskLoc extLoc = details()->firstExtent(txn); !extLoc.isNull(); extLoc = ext->xnext) { + ext = _getExtent(txn, extLoc); if (ext->firstRecord.isNull()) continue; - - iterators.push_back(new RecordStoreV1Base::IntraExtentIterator(ext->firstRecord, this)); + iterators.push_back( + new RecordStoreV1Base::IntraExtentIterator(txn, ext->firstRecord, this)); } return iterators.release(); @@ -370,7 +371,7 @@ namespace mongo { while( 1 ) { Record *recOld = recordFor(L); RecordData oldData = recOld->toRecordData(); - L = getNextRecordInExtent(L); + L = getNextRecordInExtent(txn, L); if ( compactOptions->validateDocuments && !adaptor->isDataValid( oldData ) ) { // object is corrupt! @@ -432,8 +433,8 @@ namespace mongo { } } // if !L.isNull() - invariant( _details->firstExtent() == diskloc ); - invariant( _details->lastExtent() != diskloc ); + invariant( _details->firstExtent(txn) == diskloc ); + invariant( _details->lastExtent(txn) != diskloc ); DiskLoc newFirst = e->xnext; _details->setFirstExtent( txn, newFirst ); *txn->recoveryUnit()->writing(&_extentManager->getExtent( newFirst )->xprev) = DiskLoc(); @@ -462,7 +463,7 @@ namespace mongo { txn->recoveryUnit()->commitIfNeeded(); list<DiskLoc> extents; - for( DiskLoc extLocation = _details->firstExtent(); + for( DiskLoc extLocation = _details->firstExtent(txn); !extLocation.isNull(); extLocation = _extentManager->getExtent( extLocation )->xnext ) { extents.push_back( extLocation ); @@ -476,7 +477,7 @@ namespace mongo { _details->setLastExtentSize( txn, 0 ); // create a new extent so new records go there - increaseStorageSize( txn, _details->lastExtentSize(), true ); + increaseStorageSize( txn, _details->lastExtentSize(txn), true ); // reset data size and record counts to 0 for this namespace // as we're about to tally them up again for each new extent @@ -492,8 +493,8 @@ namespace mongo { pm.hit(); } - invariant( _extentManager->getExtent( _details->firstExtent() )->xprev.isNull() ); - invariant( _extentManager->getExtent( _details->lastExtent() )->xnext.isNull() ); + invariant( _extentManager->getExtent( _details->firstExtent(txn) )->xprev.isNull() ); + invariant( _extentManager->getExtent( _details->lastExtent(txn) )->xnext.isNull() ); // indexes will do their own progress meter pm.finished(); diff --git a/src/mongo/db/structure/record_store_v1_simple.h b/src/mongo/db/structure/record_store_v1_simple.h index b6b11c9366d..786be3c8056 100644 --- a/src/mongo/db/structure/record_store_v1_simple.h +++ b/src/mongo/db/structure/record_store_v1_simple.h @@ -1,7 +1,7 @@ // record_store_v1_simple.h /** -* Copyright (C) 2013 10gen Inc. +* Copyright (C) 2013-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, @@ -50,10 +50,10 @@ namespace mongo { const char* name() const { return "SimpleRecordStoreV1"; } - virtual RecordIterator* getIterator( const DiskLoc& start, bool tailable, + virtual RecordIterator* getIterator( OperationContext* txn, const DiskLoc& start, bool tailable, const CollectionScanParams::Direction& dir) const; - virtual std::vector<RecordIterator*> getManyIterators() const; + virtual std::vector<RecordIterator*> getManyIterators(OperationContext* txn) const; virtual Status truncate(OperationContext* txn); diff --git a/src/mongo/db/structure/record_store_v1_simple_iterator.cpp b/src/mongo/db/structure/record_store_v1_simple_iterator.cpp index 19163be6aeb..675042d3948 100644 --- a/src/mongo/db/structure/record_store_v1_simple_iterator.cpp +++ b/src/mongo/db/structure/record_store_v1_simple_iterator.cpp @@ -39,23 +39,24 @@ namespace mongo { // Regular / non-capped collection traversal // - SimpleRecordStoreV1Iterator::SimpleRecordStoreV1Iterator(const SimpleRecordStoreV1* collection, + SimpleRecordStoreV1Iterator::SimpleRecordStoreV1Iterator(OperationContext* txn, + const SimpleRecordStoreV1* collection, const DiskLoc& start, const CollectionScanParams::Direction& dir) - : _curr(start), _recordStore(collection), _direction(dir) { + : _txn(txn), _curr(start), _recordStore(collection), _direction(dir) { if (_curr.isNull()) { const ExtentManager* em = _recordStore->_extentManager; - if ( _recordStore->details()->firstExtent().isNull() ) { + if ( _recordStore->details()->firstExtent(txn).isNull() ) { // nothing in the collection - verify( _recordStore->details()->lastExtent().isNull() ); + verify( _recordStore->details()->lastExtent(txn).isNull() ); } else if (CollectionScanParams::FORWARD == _direction) { // Find a non-empty extent and start with the first record in it. - Extent* e = em->getExtent( _recordStore->details()->firstExtent() ); + Extent* e = em->getExtent( _recordStore->details()->firstExtent(txn) ); while (e->firstRecord.isNull() && !e->xnext.isNull()) { e = em->getExtent( e->xnext ); @@ -68,7 +69,7 @@ namespace mongo { else { // Walk backwards, skipping empty extents, and use the last record in the first // non-empty extent we see. - Extent* e = em->getExtent( _recordStore->details()->lastExtent() ); + Extent* e = em->getExtent( _recordStore->details()->lastExtent(txn) ); // TODO ELABORATE // Does one of e->lastRecord.isNull(), e.firstRecord.isNull() imply the other? @@ -95,10 +96,10 @@ namespace mongo { // Move to the next thing. if (!isEOF()) { if (CollectionScanParams::FORWARD == _direction) { - _curr = _recordStore->getNextRecord( _curr ); + _curr = _recordStore->getNextRecord( _txn, _curr ); } else { - _curr = _recordStore->getPrevRecord( _curr ); + _curr = _recordStore->getPrevRecord( _txn, _curr ); } } diff --git a/src/mongo/db/structure/record_store_v1_simple_iterator.h b/src/mongo/db/structure/record_store_v1_simple_iterator.h index 33746f7e655..7688b15be85 100644 --- a/src/mongo/db/structure/record_store_v1_simple_iterator.h +++ b/src/mongo/db/structure/record_store_v1_simple_iterator.h @@ -42,7 +42,8 @@ namespace mongo { */ class SimpleRecordStoreV1Iterator : public RecordIterator { public: - SimpleRecordStoreV1Iterator( const SimpleRecordStoreV1* records, + SimpleRecordStoreV1Iterator( OperationContext* txn, + const SimpleRecordStoreV1* records, const DiskLoc& start, const CollectionScanParams::Direction& dir ); virtual ~SimpleRecordStoreV1Iterator() { } @@ -58,6 +59,9 @@ namespace mongo { virtual RecordData dataFor( const DiskLoc& loc ) const; private: + // for getNext, not owned + OperationContext* _txn; + // The result returned on the next call to getNext(). DiskLoc _curr; diff --git a/src/mongo/db/structure/record_store_v1_simple_test.cpp b/src/mongo/db/structure/record_store_v1_simple_test.cpp index 31659f89030..4788e46b1cf 100644 --- a/src/mongo/db/structure/record_store_v1_simple_test.cpp +++ b/src/mongo/db/structure/record_store_v1_simple_test.cpp @@ -231,7 +231,7 @@ namespace { LocAndSize drecs[] = { {} }; - assertStateV1RS(recs, drecs, &em, md); + assertStateV1RS(&txn, recs, drecs, &em, md); } } @@ -262,7 +262,7 @@ namespace { LocAndSize drecs[] = { {} }; - assertStateV1RS(recs, drecs, &em, md); + assertStateV1RS(&txn, recs, drecs, &em, md); } } @@ -296,7 +296,7 @@ namespace { LocAndSize drecs[] = { {} }; - assertStateV1RS(recs, drecs, &em, md); + assertStateV1RS(&txn, recs, drecs, &em, md); } } @@ -334,7 +334,7 @@ namespace { {DiskLoc(0, 1320), 24}, {} }; - assertStateV1RS(recs, drecs, &em, md); + assertStateV1RS(&txn, recs, drecs, &em, md); } } @@ -372,7 +372,7 @@ namespace { LocAndSize drecs[] = { {} }; - assertStateV1RS(recs, drecs, &em, md); + assertStateV1RS(&txn, recs, drecs, &em, md); } } @@ -497,7 +497,7 @@ namespace { {DiskLoc(1, 1000), 1000}, {} }; - assertStateV1RS(recs, drecs, &em, md); + assertStateV1RS(&txn, recs, drecs, &em, md); } } @@ -550,7 +550,7 @@ namespace { {DiskLoc(0, 1700), 999}, {} }; - assertStateV1RS(recs, drecs, &em, md); + assertStateV1RS(&txn, recs, drecs, &em, md); } } @@ -657,7 +657,7 @@ namespace { {DiskLoc(0, 4100), 75}, {} }; - assertStateV1RS(recs, drecs, &em, md); + assertStateV1RS(&txn, recs, drecs, &em, md); } } @@ -769,7 +769,7 @@ namespace { {DiskLoc(0, 9000), 140}, {} }; - assertStateV1RS(recs, drecs, &em, md); + assertStateV1RS(&txn, recs, drecs, &em, md); } } } diff --git a/src/mongo/db/structure/record_store_v1_test_help.cpp b/src/mongo/db/structure/record_store_v1_test_help.cpp index 3b4767e9dad..fb25786d54d 100644 --- a/src/mongo/db/structure/record_store_v1_test_help.cpp +++ b/src/mongo/db/structure/record_store_v1_test_help.cpp @@ -121,7 +121,7 @@ namespace mongo { invariant( false ); } - const DiskLoc& DummyRecordStoreV1MetaData::firstExtent() const { + const DiskLoc& DummyRecordStoreV1MetaData::firstExtent(OperationContext* txn) const { return _firstExtent; } @@ -130,7 +130,7 @@ namespace mongo { _firstExtent = loc; } - const DiskLoc& DummyRecordStoreV1MetaData::lastExtent() const { + const DiskLoc& DummyRecordStoreV1MetaData::lastExtent(OperationContext* txn) const { return _lastExtent; } @@ -171,7 +171,7 @@ namespace mongo { } - int DummyRecordStoreV1MetaData::lastExtentSize() const { + int DummyRecordStoreV1MetaData::lastExtentSize(OperationContext* txn) const { return _lastExtentSize; } @@ -302,9 +302,11 @@ namespace { } } - void printRecList(const ExtentManager* em, const RecordStoreV1MetaData* md) { + void printRecList(OperationContext* txn, + const ExtentManager* em, + const RecordStoreV1MetaData* md) { log() << " *** BEGIN ACTUAL RECORD LIST *** "; - DiskLoc extLoc = md->firstExtent(); + DiskLoc extLoc = md->firstExtent(txn); std::set<DiskLoc> seenLocs; while (!extLoc.isNull()) { Extent* ext = em->getExtent(extLoc, true); @@ -371,7 +373,7 @@ namespace { // Need to start with a blank slate invariant(em->numFiles() == 0); - invariant(md->firstExtent().isNull()); + invariant(md->firstExtent(txn).isNull()); // pre-allocate extents (even extents that aren't part of this RS) { @@ -410,7 +412,7 @@ namespace { if (records && !records[0].loc.isNull()) { int recIdx = 0; - DiskLoc extLoc = md->firstExtent(); + DiskLoc extLoc = md->firstExtent(txn); while (!extLoc.isNull()) { Extent* ext = em->getExtent(extLoc); int prevOfs = DiskLoc::NullOfs; @@ -492,10 +494,11 @@ namespace { } // Make sure we set everything up as requested. - assertStateV1RS(records, drecs, em, md); + assertStateV1RS(txn, records, drecs, em, md); } - void assertStateV1RS(const LocAndSize* records, + void assertStateV1RS(OperationContext* txn, + const LocAndSize* records, const LocAndSize* drecs, const ExtentManager* em, const DummyRecordStoreV1MetaData* md) { @@ -508,7 +511,7 @@ namespace { int recIdx = 0; - DiskLoc extLoc = md->firstExtent(); + DiskLoc extLoc = md->firstExtent(txn); while (!extLoc.isNull()) { // for each Extent Extent* ext = em->getExtent(extLoc, true); int expectedPrevOfs = DiskLoc::NullOfs; @@ -534,7 +537,7 @@ namespace { } if (ext->xnext.isNull()) { - ASSERT_EQUALS(md->lastExtent(), extLoc); + ASSERT_EQUALS(md->lastExtent(txn), extLoc); } extLoc = ext->xnext; @@ -557,7 +560,7 @@ namespace { // the first drec in the capExtent. If the capExtent is the first Extent, // it should be Null. - if (md->capExtent() == md->firstExtent()) { + if (md->capExtent() == md->firstExtent(txn)) { ASSERT_EQUALS(actualLoc, DiskLoc()); } else { @@ -597,7 +600,7 @@ namespace { } catch (...) { // If a test fails, provide extra info to make debugging easier - printRecList(em, md); + printRecList(txn, em, md); printDRecList(em, md); throw; } diff --git a/src/mongo/db/structure/record_store_v1_test_help.h b/src/mongo/db/structure/record_store_v1_test_help.h index ed65e3d0a40..75c62205b72 100644 --- a/src/mongo/db/structure/record_store_v1_test_help.h +++ b/src/mongo/db/structure/record_store_v1_test_help.h @@ -65,10 +65,10 @@ namespace mongo { const DiskLoc& loc ); virtual void orphanDeletedList(OperationContext* txn); - virtual const DiskLoc& firstExtent() const; + virtual const DiskLoc& firstExtent( OperationContext* txn ) const; virtual void setFirstExtent( OperationContext* txn, const DiskLoc& loc ); - virtual const DiskLoc& lastExtent() const; + virtual const DiskLoc& lastExtent( OperationContext* txn ) const; virtual void setLastExtent( OperationContext* txn, const DiskLoc& loc ); virtual bool isCapped() const; @@ -80,7 +80,7 @@ namespace mongo { virtual bool replaceUserFlags( OperationContext* txn, int flags ); - virtual int lastExtentSize() const; + virtual int lastExtentSize( OperationContext* txn ) const; virtual void setLastExtentSize( OperationContext* txn, int newMax ); virtual long long maxCappedDocs() const; @@ -189,7 +189,8 @@ namespace mongo { * List of LocAndSize are terminated by a Null DiskLoc. Passing a NULL pointer means don't check * that list. */ - void assertStateV1RS(const LocAndSize* records, + void assertStateV1RS(OperationContext* txn, + const LocAndSize* records, const LocAndSize* drecs, const ExtentManager* em, const DummyRecordStoreV1MetaData* md); diff --git a/src/mongo/dbtests/documentsourcetests.cpp b/src/mongo/dbtests/documentsourcetests.cpp index 6972e8d7262..1c37fa6db4c 100644 --- a/src/mongo/dbtests/documentsourcetests.cpp +++ b/src/mongo/dbtests/documentsourcetests.cpp @@ -1,7 +1,7 @@ // documentsourcetests.cpp : Unit tests for DocumentSource classes. /** - * Copyright (C) 2012 10gen Inc. + * Copyright (C) 2012-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, @@ -178,7 +178,7 @@ namespace DocumentSourceTests { CanonicalQuery* cq; uassertStatusOK(CanonicalQuery::canonicalize(ns, /*query=*/BSONObj(), &cq)); Runner* runnerBare; - uassertStatusOK(getRunner(ctx.ctx().db()->getCollection(&_opCtx, ns), cq, &runnerBare)); + uassertStatusOK(getRunner(&_opCtx, ctx.ctx().db()->getCollection(&_opCtx, ns), cq, &runnerBare)); _runner.reset(runnerBare); _runner->saveState(); diff --git a/src/mongo/dbtests/jstests.cpp b/src/mongo/dbtests/jstests.cpp index a5f8ff997b6..605e171e2c9 100644 --- a/src/mongo/dbtests/jstests.cpp +++ b/src/mongo/dbtests/jstests.cpp @@ -2,7 +2,7 @@ // /** - * Copyright (C) 2009 10gen Inc. + * Copyright (C) 2009-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, @@ -2010,7 +2010,6 @@ namespace JSTests { OperationContextImpl txn; DBDirectClient client(&txn); - client.update( "test.system.js" , query.obj() , update.obj() , true /* upsert */ ); scoped_ptr<Scope> s( globalScriptEngine->newScope() ); diff --git a/src/mongo/dbtests/namespacetests.cpp b/src/mongo/dbtests/namespacetests.cpp index 4309b9c2356..698678be8ec 100644 --- a/src/mongo/dbtests/namespacetests.cpp +++ b/src/mongo/dbtests/namespacetests.cpp @@ -2,7 +2,7 @@ // /** - * Copyright (C) 2008 10gen Inc. + * Copyright (C) 2008-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, @@ -363,14 +363,16 @@ namespace NamespaceTests { DiskLoc last, first; { - auto_ptr<Runner> runner(InternalPlanner::collectionScan(ns(), + auto_ptr<Runner> runner(InternalPlanner::collectionScan(&txn, + ns(), collection(), InternalPlanner::BACKWARD)); runner->getNext(NULL, &last); ASSERT( !last.isNull() ); } { - auto_ptr<Runner> runner(InternalPlanner::collectionScan(ns(), + auto_ptr<Runner> runner(InternalPlanner::collectionScan(&txn, + ns(), collection(), InternalPlanner::FORWARD)); runner->getNext(NULL, &first); @@ -383,14 +385,16 @@ namespace NamespaceTests { { DiskLoc loc; - auto_ptr<Runner> runner(InternalPlanner::collectionScan(ns(), + auto_ptr<Runner> runner(InternalPlanner::collectionScan(&txn, + ns(), collection(), InternalPlanner::FORWARD)); runner->getNext(NULL, &loc); ASSERT( first == loc); } { - auto_ptr<Runner> runner(InternalPlanner::collectionScan(ns(), + auto_ptr<Runner> runner(InternalPlanner::collectionScan(&txn, + ns(), collection(), InternalPlanner::BACKWARD)); DiskLoc loc; diff --git a/src/mongo/dbtests/oplogstarttests.cpp b/src/mongo/dbtests/oplogstarttests.cpp index 4f4f88c1ccc..0c6b5c0f20b 100644 --- a/src/mongo/dbtests/oplogstarttests.cpp +++ b/src/mongo/dbtests/oplogstarttests.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2013 MongoDB Inc. + * Copyright (C) 2013-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, @@ -77,7 +77,7 @@ namespace OplogStartTests { ASSERT(s.isOK()); _cq.reset(cq); _oplogws.reset(new WorkingSet()); - _stage.reset(new OplogStart(collection(), _cq->root(), _oplogws.get())); + _stage.reset(new OplogStart(&_txn, collection(), _cq->root(), _oplogws.get())); } void assertWorkingSetMemberHasId(WorkingSetID id, int expectedId) { diff --git a/src/mongo/dbtests/plan_ranking.cpp b/src/mongo/dbtests/plan_ranking.cpp index 7b8f01add03..4908eb180ef 100644 --- a/src/mongo/dbtests/plan_ranking.cpp +++ b/src/mongo/dbtests/plan_ranking.cpp @@ -114,7 +114,7 @@ namespace PlanRankingTests { // Put each solution from the planner into the MPR. for (size_t i = 0; i < solutions.size(); ++i) { PlanStage* root; - ASSERT(StageBuilder::build(collection, *solutions[i], ws, &root)); + ASSERT(StageBuilder::build(&_txn, collection, *solutions[i], ws, &root)); // Takes ownership of all arguments. _mps->addPlan(solutions[i], root, ws); } diff --git a/src/mongo/dbtests/query_multi_plan_runner.cpp b/src/mongo/dbtests/query_multi_plan_runner.cpp index 81982df6768..e9256246757 100644 --- a/src/mongo/dbtests/query_multi_plan_runner.cpp +++ b/src/mongo/dbtests/query_multi_plan_runner.cpp @@ -118,7 +118,7 @@ namespace QueryMultiPlanRunner { const Collection* coll = ctx.ctx().db()->getCollection(&_txn, ns()); auto_ptr<WorkingSet> sharedWs(new WorkingSet()); - IndexScan* ix = new IndexScan(ixparams, sharedWs.get(), NULL); + IndexScan* ix = new IndexScan(&_txn, ixparams, sharedWs.get(), NULL); auto_ptr<PlanStage> firstRoot(new FetchStage(sharedWs.get(), ix, NULL, coll)); // Plan 1: CollScan with matcher. @@ -132,7 +132,7 @@ namespace QueryMultiPlanRunner { verify(swme.isOK()); auto_ptr<MatchExpression> filter(swme.getValue()); // Make the stage. - auto_ptr<PlanStage> secondRoot(new CollectionScan(csparams, sharedWs.get(), + auto_ptr<PlanStage> secondRoot(new CollectionScan(&_txn, csparams, sharedWs.get(), filter.get())); // Hand the plans off to the runner. diff --git a/src/mongo/dbtests/query_single_solution_runner.cpp b/src/mongo/dbtests/query_single_solution_runner.cpp index 91596c5cf49..4f4ddd09570 100644 --- a/src/mongo/dbtests/query_single_solution_runner.cpp +++ b/src/mongo/dbtests/query_single_solution_runner.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2013 MongoDB Inc. + * Copyright (C) 2013-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, @@ -91,7 +91,7 @@ namespace QuerySingleSolutionRunner { verify(swme.isOK()); auto_ptr<MatchExpression> filter(swme.getValue()); // Make the stage. - auto_ptr<PlanStage> root(new CollectionScan(csparams, ws.get(), filter.release())); + auto_ptr<PlanStage> root(new CollectionScan(&_txn, csparams, ws.get(), filter.release())); CanonicalQuery* cq; verify(CanonicalQuery::canonicalize(ns(), filterObj, &cq).isOK()); @@ -133,7 +133,7 @@ namespace QuerySingleSolutionRunner { const Collection* coll = context.db()->getCollection(&_txn, ns()); auto_ptr<WorkingSet> ws(new WorkingSet()); - IndexScan* ix = new IndexScan(ixparams, ws.get(), NULL); + IndexScan* ix = new IndexScan(&_txn, ixparams, ws.get(), NULL); auto_ptr<PlanStage> root(new FetchStage(ws.get(), ix, NULL, coll)); CanonicalQuery* cq; diff --git a/src/mongo/dbtests/query_stage_and.cpp b/src/mongo/dbtests/query_stage_and.cpp index 75b144c7e45..a7b77876237 100644 --- a/src/mongo/dbtests/query_stage_and.cpp +++ b/src/mongo/dbtests/query_stage_and.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2013 10gen Inc. + * Copyright (C) 2013-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, @@ -72,8 +72,8 @@ namespace QueryStageAnd { } void getLocs(set<DiskLoc>* out, Collection* coll) { - RecordIterator* it = coll->getIterator(DiskLoc(), false, - CollectionScanParams::FORWARD); + RecordIterator* it = coll->getIterator(&_txn, DiskLoc(), false, + CollectionScanParams::FORWARD); while (!it->isEOF()) { DiskLoc nextLoc = it->getNext(); out->insert(nextLoc); @@ -154,7 +154,7 @@ namespace QueryStageAnd { params.bounds.endKey = BSONObj(); params.bounds.endKeyInclusive = true; params.direction = -1; - ah->addChild(new IndexScan(params, &ws, NULL)); + ah->addChild(new IndexScan(&_txn, params, &ws, NULL)); // Bar >= 10 params.descriptor = getIndex(BSON("bar" << 1), coll); @@ -162,7 +162,7 @@ namespace QueryStageAnd { params.bounds.endKey = BSONObj(); params.bounds.endKeyInclusive = true; params.direction = 1; - ah->addChild(new IndexScan(params, &ws, NULL)); + ah->addChild(new IndexScan(&_txn, params, &ws, NULL)); // ah reads the first child into its hash table. // ah should read foo=20, foo=19, ..., foo=0 in that order. @@ -258,12 +258,12 @@ namespace QueryStageAnd { params.bounds.endKey = BSONObj(); params.bounds.endKeyInclusive = true; params.direction = -1; - ah->addChild(new IndexScan(params, &ws, NULL)); + ah->addChild(new IndexScan(&_txn, params, &ws, NULL)); // Bar <= 19 (descending) params.descriptor = getIndex(BSON("bar" << 1), coll); params.bounds.startKey = BSON("" << 19); - ah->addChild(new IndexScan(params, &ws, NULL)); + ah->addChild(new IndexScan(&_txn, params, &ws, NULL)); // First call to work reads the first result from the children. // The first result is for the first scan over foo is {foo: 20, bar: 20, baz: 20}. @@ -344,7 +344,7 @@ namespace QueryStageAnd { params.bounds.endKey = BSONObj(); params.bounds.endKeyInclusive = true; params.direction = -1; - ah->addChild(new IndexScan(params, &ws, NULL)); + ah->addChild(new IndexScan(&_txn, params, &ws, NULL)); // Bar >= 10 params.descriptor = getIndex(BSON("bar" << 1), coll); @@ -352,7 +352,7 @@ namespace QueryStageAnd { params.bounds.endKey = BSONObj(); params.bounds.endKeyInclusive = true; params.direction = 1; - ah->addChild(new IndexScan(params, &ws, NULL)); + ah->addChild(new IndexScan(&_txn, params, &ws, NULL)); ctx.commit(); // foo == bar == baz, and foo<=20, bar>=10, so our values are: @@ -399,7 +399,7 @@ namespace QueryStageAnd { params.bounds.endKey = BSONObj(); params.bounds.endKeyInclusive = true; params.direction = -1; - ah->addChild(new IndexScan(params, &ws, NULL)); + ah->addChild(new IndexScan(&_txn, params, &ws, NULL)); // Bar >= 10 params.descriptor = getIndex(BSON("bar" << 1), coll); @@ -407,7 +407,7 @@ namespace QueryStageAnd { params.bounds.endKey = BSONObj(); params.bounds.endKeyInclusive = true; params.direction = 1; - ah->addChild(new IndexScan(params, &ws, NULL)); + ah->addChild(new IndexScan(&_txn, params, &ws, NULL)); ctx.commit(); // Stage execution should fail. @@ -452,7 +452,7 @@ namespace QueryStageAnd { params.bounds.endKey = BSONObj(); params.bounds.endKeyInclusive = true; params.direction = -1; - ah->addChild(new IndexScan(params, &ws, NULL)); + ah->addChild(new IndexScan(&_txn, params, &ws, NULL)); // Bar >= 10 params.descriptor = getIndex(BSON("bar" << 1 << "big" << 1), coll); @@ -460,7 +460,7 @@ namespace QueryStageAnd { params.bounds.endKey = BSONObj(); params.bounds.endKeyInclusive = true; params.direction = 1; - ah->addChild(new IndexScan(params, &ws, NULL)); + ah->addChild(new IndexScan(&_txn, params, &ws, NULL)); ctx.commit(); // foo == bar == baz, and foo<=20, bar>=10, so our values are: @@ -500,7 +500,7 @@ namespace QueryStageAnd { params.bounds.endKey = BSONObj(); params.bounds.endKeyInclusive = true; params.direction = -1; - ah->addChild(new IndexScan(params, &ws, NULL)); + ah->addChild(new IndexScan(&_txn, params, &ws, NULL)); // Bar >= 10 params.descriptor = getIndex(BSON("bar" << 1), coll); @@ -508,7 +508,7 @@ namespace QueryStageAnd { params.bounds.endKey = BSONObj(); params.bounds.endKeyInclusive = true; params.direction = 1; - ah->addChild(new IndexScan(params, &ws, NULL)); + ah->addChild(new IndexScan(&_txn, params, &ws, NULL)); // 5 <= baz <= 15 params.descriptor = getIndex(BSON("baz" << 1), coll); @@ -516,7 +516,7 @@ namespace QueryStageAnd { params.bounds.endKey = BSON("" << 15); params.bounds.endKeyInclusive = true; params.direction = 1; - ah->addChild(new IndexScan(params, &ws, NULL)); + ah->addChild(new IndexScan(&_txn, params, &ws, NULL)); ctx.commit(); // foo == bar == baz, and foo<=20, bar>=10, 5<=baz<=15, so our values are: @@ -567,7 +567,7 @@ namespace QueryStageAnd { params.bounds.endKey = BSONObj(); params.bounds.endKeyInclusive = true; params.direction = -1; - ah->addChild(new IndexScan(params, &ws, NULL)); + ah->addChild(new IndexScan(&_txn, params, &ws, NULL)); // Bar >= 10 params.descriptor = getIndex(BSON("bar" << 1 << "big" << 1), coll); @@ -575,7 +575,7 @@ namespace QueryStageAnd { params.bounds.endKey = BSONObj(); params.bounds.endKeyInclusive = true; params.direction = 1; - ah->addChild(new IndexScan(params, &ws, NULL)); + ah->addChild(new IndexScan(&_txn, params, &ws, NULL)); // 5 <= baz <= 15 params.descriptor = getIndex(BSON("baz" << 1), coll); @@ -583,7 +583,7 @@ namespace QueryStageAnd { params.bounds.endKey = BSON("" << 15); params.bounds.endKeyInclusive = true; params.direction = 1; - ah->addChild(new IndexScan(params, &ws, NULL)); + ah->addChild(new IndexScan(&_txn, params, &ws, NULL)); ctx.commit(); // Stage execution should fail. @@ -621,7 +621,7 @@ namespace QueryStageAnd { params.bounds.endKey = BSONObj(); params.bounds.endKeyInclusive = true; params.direction = -1; - ah->addChild(new IndexScan(params, &ws, NULL)); + ah->addChild(new IndexScan(&_txn, params, &ws, NULL)); // Bar == 5. Index scan should be eof. params.descriptor = getIndex(BSON("bar" << 1), coll); @@ -629,7 +629,7 @@ namespace QueryStageAnd { params.bounds.endKey = BSON("" << 5); params.bounds.endKeyInclusive = true; params.direction = 1; - ah->addChild(new IndexScan(params, &ws, NULL)); + ah->addChild(new IndexScan(&_txn, params, &ws, NULL)); int count = 0; int works = 0; @@ -682,7 +682,7 @@ namespace QueryStageAnd { params.bounds.endKey = BSONObj(); params.bounds.endKeyInclusive = true; params.direction = 1; - ah->addChild(new IndexScan(params, &ws, NULL)); + ah->addChild(new IndexScan(&_txn, params, &ws, NULL)); // Bar <= 100 params.descriptor = getIndex(BSON("bar" << 1), coll); @@ -693,7 +693,7 @@ namespace QueryStageAnd { params.bounds.endKey = BSON("" << ""); params.bounds.endKeyInclusive = false; params.direction = -1; - ah->addChild(new IndexScan(params, &ws, NULL)); + ah->addChild(new IndexScan(&_txn, params, &ws, NULL)); ctx.commit(); ASSERT_EQUALS(0, countResults(ah.get())); @@ -734,7 +734,7 @@ namespace QueryStageAnd { params.bounds.endKey = BSONObj(); params.bounds.endKeyInclusive = true; params.direction = -1; - ah->addChild(new IndexScan(params, &ws, NULL)); + ah->addChild(new IndexScan(&_txn, params, &ws, NULL)); // Bar >= 95 params.descriptor = getIndex(BSON("bar" << 1), coll); @@ -742,7 +742,7 @@ namespace QueryStageAnd { params.bounds.endKey = BSONObj(); params.bounds.endKeyInclusive = true; params.direction = 1; - ah->addChild(new IndexScan(params, &ws, NULL)); + ah->addChild(new IndexScan(&_txn, params, &ws, NULL)); ctx.commit(); // Bar == 97 @@ -787,11 +787,11 @@ namespace QueryStageAnd { params.bounds.endKey = BSON("" << 1); params.bounds.endKeyInclusive = true; params.direction = 1; - ah->addChild(new IndexScan(params, &ws, NULL)); + ah->addChild(new IndexScan(&_txn, params, &ws, NULL)); // Scan over bar == 1 params.descriptor = getIndex(BSON("bar" << 1), coll); - ah->addChild(new IndexScan(params, &ws, NULL)); + ah->addChild(new IndexScan(&_txn, params, &ws, NULL)); // Get the set of disklocs in our collection to use later. set<DiskLoc> data; @@ -914,15 +914,15 @@ namespace QueryStageAnd { params.bounds.endKey = BSON("" << 1); params.bounds.endKeyInclusive = true; params.direction = 1; - ah->addChild(new IndexScan(params, &ws, NULL)); + ah->addChild(new IndexScan(&_txn, params, &ws, NULL)); // bar == 1 params.descriptor = getIndex(BSON("bar" << 1), coll); - ah->addChild(new IndexScan(params, &ws, NULL)); + ah->addChild(new IndexScan(&_txn, params, &ws, NULL)); // baz == 1 params.descriptor = getIndex(BSON("baz" << 1), coll); - ah->addChild(new IndexScan(params, &ws, NULL)); + ah->addChild(new IndexScan(&_txn, params, &ws, NULL)); ctx.commit(); ASSERT_EQUALS(50, countResults(ah.get())); @@ -960,7 +960,7 @@ namespace QueryStageAnd { params.bounds.endKey = BSON("" << 7); params.bounds.endKeyInclusive = true; params.direction = 1; - ah->addChild(new IndexScan(params, &ws, NULL)); + ah->addChild(new IndexScan(&_txn, params, &ws, NULL)); // Bar == 20, not EOF. params.descriptor = getIndex(BSON("bar" << 1), coll); @@ -968,7 +968,7 @@ namespace QueryStageAnd { params.bounds.endKey = BSON("" << 20); params.bounds.endKeyInclusive = true; params.direction = 1; - ah->addChild(new IndexScan(params, &ws, NULL)); + ah->addChild(new IndexScan(&_txn, params, &ws, NULL)); ctx.commit(); ASSERT_EQUALS(0, countResults(ah.get())); @@ -1009,7 +1009,7 @@ namespace QueryStageAnd { params.bounds.endKey = BSON("" << 7); params.bounds.endKeyInclusive = true; params.direction = 1; - ah->addChild(new IndexScan(params, &ws, NULL)); + ah->addChild(new IndexScan(&_txn, params, &ws, NULL)); // bar == 20. params.descriptor = getIndex(BSON("bar" << 1), coll); @@ -1017,7 +1017,7 @@ namespace QueryStageAnd { params.bounds.endKey = BSON("" << 20); params.bounds.endKeyInclusive = true; params.direction = 1; - ah->addChild(new IndexScan(params, &ws, NULL)); + ah->addChild(new IndexScan(&_txn, params, &ws, NULL)); ctx.commit(); ASSERT_EQUALS(0, countResults(ah.get())); @@ -1058,11 +1058,11 @@ namespace QueryStageAnd { params.bounds.endKey = BSON("" << 1); params.bounds.endKeyInclusive = true; params.direction = 1; - ah->addChild(new IndexScan(params, &ws, NULL)); + ah->addChild(new IndexScan(&_txn, params, &ws, NULL)); // bar == 1 params.descriptor = getIndex(BSON("bar" << 1), coll); - ah->addChild(new IndexScan(params, &ws, NULL)); + ah->addChild(new IndexScan(&_txn, params, &ws, NULL)); ctx.commit(); // Filter drops everything. @@ -1100,13 +1100,13 @@ namespace QueryStageAnd { params.bounds.endKey = BSON("" << 1); params.bounds.endKeyInclusive = true; params.direction = 1; - ah->addChild(new IndexScan(params, &ws, NULL)); + ah->addChild(new IndexScan(&_txn, params, &ws, NULL)); // Intersect with 7 <= bar < 10000 params.descriptor = getIndex(BSON("bar" << 1), coll); params.bounds.startKey = BSON("" << 7); params.bounds.endKey = BSON("" << 10000); - ah->addChild(new IndexScan(params, &ws, NULL)); + ah->addChild(new IndexScan(&_txn, params, &ws, NULL)); WorkingSetID lastId = WorkingSet::INVALID_ID; diff --git a/src/mongo/dbtests/query_stage_collscan.cpp b/src/mongo/dbtests/query_stage_collscan.cpp index 06088bf425a..415a651babc 100644 --- a/src/mongo/dbtests/query_stage_collscan.cpp +++ b/src/mongo/dbtests/query_stage_collscan.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2013 10gen Inc. + * Copyright (C) 2013-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, @@ -352,7 +352,7 @@ namespace QueryStageCollectionScan { // Make a scan and have the runner own it. WorkingSet* ws = new WorkingSet(); - PlanStage* ps = new CollectionScan(params, ws, filterExpr.get()); + PlanStage* ps = new CollectionScan(&_txn, params, ws, filterExpr.get()); PlanExecutor runner(ws, ps, params.collection); // Use the runner to count the number of objects scanned. @@ -371,7 +371,7 @@ namespace QueryStageCollectionScan { params.direction = direction; params.tailable = false; - scoped_ptr<CollectionScan> scan(new CollectionScan(params, &ws, NULL)); + scoped_ptr<CollectionScan> scan(new CollectionScan(&_txn, params, &ws, NULL)); while (!scan->isEOF()) { WorkingSetID id = WorkingSet::INVALID_ID; PlanStage::StageState state = scan->work(&id); @@ -457,7 +457,7 @@ namespace QueryStageCollectionScan { // Make a scan and have the runner own it. WorkingSet* ws = new WorkingSet(); - PlanStage* ps = new CollectionScan(params, ws, NULL); + PlanStage* ps = new CollectionScan(&_txn, params, ws, NULL); PlanExecutor runner(ws, ps, params.collection); int count = 0; @@ -486,7 +486,7 @@ namespace QueryStageCollectionScan { params.tailable = false; WorkingSet* ws = new WorkingSet(); - PlanStage* ps = new CollectionScan(params, ws, NULL); + PlanStage* ps = new CollectionScan(&_txn, params, ws, NULL); PlanExecutor runner(ws, ps, params.collection); int count = 0; @@ -522,7 +522,7 @@ namespace QueryStageCollectionScan { params.tailable = false; WorkingSet ws; - scoped_ptr<CollectionScan> scan(new CollectionScan(params, &ws, NULL)); + scoped_ptr<CollectionScan> scan(new CollectionScan(&_txn, params, &ws, NULL)); int count = 0; while (count < 10) { @@ -584,7 +584,7 @@ namespace QueryStageCollectionScan { params.tailable = false; WorkingSet ws; - scoped_ptr<CollectionScan> scan(new CollectionScan(params, &ws, NULL)); + scoped_ptr<CollectionScan> scan(new CollectionScan(&_txn, params, &ws, NULL)); int count = 0; while (count < 10) { diff --git a/src/mongo/dbtests/query_stage_count.cpp b/src/mongo/dbtests/query_stage_count.cpp index b4a86309568..6a7a039008e 100644 --- a/src/mongo/dbtests/query_stage_count.cpp +++ b/src/mongo/dbtests/query_stage_count.cpp @@ -129,7 +129,7 @@ namespace QueryStageCount { params.endKeyInclusive = true; WorkingSet ws; - Count count(params, &ws); + Count count(&_txn, params, &ws); int numCounted = runCount(&count); ASSERT_EQUALS(2, numCounted); @@ -162,7 +162,7 @@ namespace QueryStageCount { params.endKeyInclusive = true; WorkingSet ws; - Count count(params, &ws); + Count count(&_txn, params, &ws); int numCounted = runCount(&count); ASSERT_EQUALS(5, numCounted); @@ -195,7 +195,7 @@ namespace QueryStageCount { params.endKeyInclusive = false; WorkingSet ws; - Count count(params, &ws); + Count count(&_txn, params, &ws); int numCounted = runCount(&count); ASSERT_EQUALS(3, numCounted); @@ -224,7 +224,7 @@ namespace QueryStageCount { params.endKeyInclusive = false; WorkingSet ws; - Count count(params, &ws); + Count count(&_txn, params, &ws); int numCounted = runCount(&count); ASSERT_EQUALS(0, numCounted); @@ -254,7 +254,7 @@ namespace QueryStageCount { params.endKeyInclusive = false; WorkingSet ws; - Count count(params, &ws); + Count count(&_txn, params, &ws); int numCounted = runCount(&count); ASSERT_EQUALS(0, numCounted); @@ -285,7 +285,7 @@ namespace QueryStageCount { params.endKeyInclusive = true; WorkingSet ws; - Count count(params, &ws); + Count count(&_txn, params, &ws); int numCounted = runCount(&count); ASSERT_EQUALS(0, numCounted); @@ -317,7 +317,7 @@ namespace QueryStageCount { params.endKeyInclusive = true; WorkingSet ws; - Count count(params, &ws); + Count count(&_txn, params, &ws); WorkingSetID wsid; int numCounted = 0; @@ -369,7 +369,7 @@ namespace QueryStageCount { params.endKeyInclusive = true; WorkingSet ws; - Count count(params, &ws); + Count count(&_txn, params, &ws); WorkingSetID wsid; int numCounted = 0; @@ -424,7 +424,7 @@ namespace QueryStageCount { params.endKeyInclusive = true; WorkingSet ws; - Count count(params, &ws); + Count count(&_txn, params, &ws); WorkingSetID wsid; int numCounted = 0; @@ -482,7 +482,7 @@ namespace QueryStageCount { params.endKeyInclusive = true; WorkingSet ws; - Count count(params, &ws); + Count count(&_txn, params, &ws); WorkingSetID wsid; int numCounted = 0; @@ -541,7 +541,7 @@ namespace QueryStageCount { params.endKeyInclusive = true; WorkingSet ws; - Count count(params, &ws); + Count count(&_txn, params, &ws); int numCounted = runCount(&count); ASSERT_EQUALS(7, numCounted); @@ -575,7 +575,7 @@ namespace QueryStageCount { params.endKeyInclusive = true; // yes? WorkingSet ws; - Count count(params, &ws); + Count count(&_txn, params, &ws); int numCounted = runCount(&count); ASSERT_EQUALS(9, numCounted); @@ -606,7 +606,7 @@ namespace QueryStageCount { params.endKeyInclusive = true; WorkingSet ws; - Count count(params, &ws); + Count count(&_txn, params, &ws); WorkingSetID wsid; int numCounted = 0; diff --git a/src/mongo/dbtests/query_stage_distinct.cpp b/src/mongo/dbtests/query_stage_distinct.cpp index ac61fc55fce..ccf03b58bf3 100644 --- a/src/mongo/dbtests/query_stage_distinct.cpp +++ b/src/mongo/dbtests/query_stage_distinct.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2013 10gen Inc. + * Copyright (C) 2013-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, @@ -145,7 +145,7 @@ namespace QueryStageDistinct { params.bounds.fields.push_back(oil); WorkingSet ws; - DistinctScan* distinct = new DistinctScan(params, &ws); + DistinctScan* distinct = new DistinctScan(&_txn, params, &ws); WorkingSetID wsid; // Get our first result. @@ -210,7 +210,7 @@ namespace QueryStageDistinct { params.bounds.fields.push_back(oil); WorkingSet ws; - DistinctScan* distinct = new DistinctScan(params, &ws); + DistinctScan* distinct = new DistinctScan(&_txn, params, &ws); // We should see each number in the range [1, 6] exactly once. std::set<int> seen; diff --git a/src/mongo/dbtests/query_stage_fetch.cpp b/src/mongo/dbtests/query_stage_fetch.cpp index bc95554164a..e758afe8518 100644 --- a/src/mongo/dbtests/query_stage_fetch.cpp +++ b/src/mongo/dbtests/query_stage_fetch.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2013 10gen Inc. + * Copyright (C) 2013-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, @@ -57,8 +57,8 @@ namespace QueryStageFetch { } void getLocs(set<DiskLoc>* out, Collection* coll) { - RecordIterator* it = coll->getIterator(DiskLoc(), false, - CollectionScanParams::FORWARD); + RecordIterator* it = coll->getIterator(&_txn, DiskLoc(), false, + CollectionScanParams::FORWARD); while (!it->isEOF()) { DiskLoc nextLoc = it->getNext(); out->insert(nextLoc); diff --git a/src/mongo/dbtests/query_stage_keep.cpp b/src/mongo/dbtests/query_stage_keep.cpp index eca675d6966..9eced015261 100644 --- a/src/mongo/dbtests/query_stage_keep.cpp +++ b/src/mongo/dbtests/query_stage_keep.cpp @@ -61,8 +61,8 @@ namespace QueryStageKeep { } void getLocs(set<DiskLoc>* out, Collection* coll) { - RecordIterator* it = coll->getIterator(DiskLoc(), false, - CollectionScanParams::FORWARD); + RecordIterator* it = coll->getIterator(&_txn, DiskLoc(), false, + CollectionScanParams::FORWARD); while (!it->isEOF()) { DiskLoc nextLoc = it->getNext(); out->insert(nextLoc); @@ -135,7 +135,7 @@ namespace QueryStageKeep { params.direction = CollectionScanParams::FORWARD; params.tailable = false; params.start = DiskLoc(); - CollectionScan* cs = new CollectionScan(params, &ws, NULL); + CollectionScan* cs = new CollectionScan(&_txn, params, &ws, NULL); // Create a KeepMutations stage to merge in the 10 flagged objects. // Takes ownership of 'cs' diff --git a/src/mongo/dbtests/query_stage_merge_sort.cpp b/src/mongo/dbtests/query_stage_merge_sort.cpp index 2aa83912515..0a1492c4b0d 100644 --- a/src/mongo/dbtests/query_stage_merge_sort.cpp +++ b/src/mongo/dbtests/query_stage_merge_sort.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2013 10gen Inc. + * Copyright (C) 2013-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, @@ -74,8 +74,10 @@ namespace QueryStageMergeSortTests { } void getLocs(set<DiskLoc>* out, Collection* coll) { - RecordIterator* it = coll->getIterator(DiskLoc(), false, - CollectionScanParams::FORWARD); + RecordIterator* it = coll->getIterator(&_txn, + DiskLoc(), + false, + CollectionScanParams::FORWARD); while (!it->isEOF()) { DiskLoc nextLoc = it->getNext(); out->insert(nextLoc); @@ -145,11 +147,11 @@ namespace QueryStageMergeSortTests { params.bounds.endKey = objWithMaxKey(1); params.bounds.endKeyInclusive = true; params.direction = 1; - ms->addChild(new IndexScan(params, ws, NULL)); + ms->addChild(new IndexScan(&_txn, params, ws, NULL)); // b:1 params.descriptor = getIndex(secondIndex, coll); - ms->addChild(new IndexScan(params, ws, NULL)); + ms->addChild(new IndexScan(&_txn, params, ws, NULL)); ctx.commit(); // Must fetch if we want to easily pull out an obj. @@ -209,11 +211,11 @@ namespace QueryStageMergeSortTests { params.bounds.endKey = objWithMaxKey(1); params.bounds.endKeyInclusive = true; params.direction = 1; - ms->addChild(new IndexScan(params, ws, NULL)); + ms->addChild(new IndexScan(&_txn, params, ws, NULL)); // b:1 params.descriptor = getIndex(secondIndex, coll); - ms->addChild(new IndexScan(params, ws, NULL)); + ms->addChild(new IndexScan(&_txn, params, ws, NULL)); ctx.commit(); PlanExecutor runner(ws, new FetchStage(ws, ms, NULL, coll), coll); @@ -272,11 +274,11 @@ namespace QueryStageMergeSortTests { params.bounds.endKey = objWithMaxKey(1); params.bounds.endKeyInclusive = true; params.direction = 1; - ms->addChild(new IndexScan(params, ws, NULL)); + ms->addChild(new IndexScan(&_txn, params, ws, NULL)); // b:1 params.descriptor = getIndex(secondIndex, coll); - ms->addChild(new IndexScan(params, ws, NULL)); + ms->addChild(new IndexScan(&_txn, params, ws, NULL)); ctx.commit(); PlanExecutor runner(ws, new FetchStage(ws, ms, NULL, coll), coll); @@ -338,11 +340,11 @@ namespace QueryStageMergeSortTests { params.bounds.endKeyInclusive = true; // This is the direction along the index. params.direction = 1; - ms->addChild(new IndexScan(params, ws, NULL)); + ms->addChild(new IndexScan(&_txn, params, ws, NULL)); // b:1 params.descriptor = getIndex(secondIndex, coll); - ms->addChild(new IndexScan(params, ws, NULL)); + ms->addChild(new IndexScan(&_txn, params, ws, NULL)); ctx.commit(); PlanExecutor runner(ws, new FetchStage(ws, ms, NULL, coll), coll); @@ -401,13 +403,13 @@ namespace QueryStageMergeSortTests { params.bounds.endKey = objWithMaxKey(1); params.bounds.endKeyInclusive = true; params.direction = 1; - ms->addChild(new IndexScan(params, ws, NULL)); + ms->addChild(new IndexScan(&_txn, params, ws, NULL)); // b:51 (EOF) params.descriptor = getIndex(secondIndex, coll); params.bounds.startKey = BSON("" << 51 << "" << MinKey); params.bounds.endKey = BSON("" << 51 << "" << MaxKey); - ms->addChild(new IndexScan(params, ws, NULL)); + ms->addChild(new IndexScan(&_txn, params, ws, NULL)); ctx.commit(); PlanExecutor runner(ws, new FetchStage(ws, ms, NULL, coll), coll); @@ -459,7 +461,7 @@ namespace QueryStageMergeSortTests { BSONObj indexSpec = BSON(index << 1 << "foo" << 1); addIndex(indexSpec); params.descriptor = getIndex(indexSpec, coll); - ms->addChild(new IndexScan(params, ws, NULL)); + ms->addChild(new IndexScan(&_txn, params, ws, NULL)); } ctx.commit(); @@ -514,7 +516,7 @@ namespace QueryStageMergeSortTests { BSONObj indexSpec = BSON(index << 1 << "foo" << 1); addIndex(indexSpec); params.descriptor = getIndex(indexSpec, coll); - ms->addChild(new IndexScan(params, &ws, NULL)); + ms->addChild(new IndexScan(&_txn, params, &ws, NULL)); } set<DiskLoc> locs; diff --git a/src/mongo/dbtests/query_stage_sort.cpp b/src/mongo/dbtests/query_stage_sort.cpp index 60838f5df77..81e500cb238 100644 --- a/src/mongo/dbtests/query_stage_sort.cpp +++ b/src/mongo/dbtests/query_stage_sort.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2013 10gen Inc. + * Copyright (C) 2013-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, @@ -66,8 +66,8 @@ namespace QueryStageSortTests { } void getLocs(set<DiskLoc>* out, Collection* coll) { - RecordIterator* it = coll->getIterator(DiskLoc(), false, - CollectionScanParams::FORWARD); + RecordIterator* it = coll->getIterator(&_txn, DiskLoc(), false, + CollectionScanParams::FORWARD); while (!it->isEOF()) { DiskLoc nextLoc = it->getNext(); out->insert(nextLoc); diff --git a/src/mongo/dbtests/query_stage_tests.cpp b/src/mongo/dbtests/query_stage_tests.cpp index 91640817f74..24b0ef3db1e 100644 --- a/src/mongo/dbtests/query_stage_tests.cpp +++ b/src/mongo/dbtests/query_stage_tests.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2013 10gen Inc. + * Copyright (C) 2013-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, @@ -83,7 +83,7 @@ namespace QueryStageTests { WorkingSet* ws = new WorkingSet(); PlanExecutor runner(ws, - new IndexScan(params, ws, filterExpr.get()), + new IndexScan(&_txn, params, ws, filterExpr.get()), ctx.ctx().db()->getCollection(&_txn, ns())); int count = 0; diff --git a/src/mongo/dbtests/repltests.cpp b/src/mongo/dbtests/repltests.cpp index 4694c942f73..4580b5682d2 100644 --- a/src/mongo/dbtests/repltests.cpp +++ b/src/mongo/dbtests/repltests.cpp @@ -2,7 +2,7 @@ // /** - * Copyright (C) 2009 10gen Inc. + * Copyright (C) 2009-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, @@ -133,8 +133,8 @@ namespace ReplTests { } int count = 0; - RecordIterator* it = coll->getIterator( DiskLoc(), false, - CollectionScanParams::FORWARD ); + RecordIterator* it = coll->getIterator( &_txn, DiskLoc(), false, + CollectionScanParams::FORWARD ); for ( ; !it->isEOF(); it->getNext() ) { ++count; } @@ -154,8 +154,8 @@ namespace ReplTests { } int count = 0; - RecordIterator* it = coll->getIterator( DiskLoc(), false, - CollectionScanParams::FORWARD ); + RecordIterator* it = coll->getIterator( &txn, DiskLoc(), false, + CollectionScanParams::FORWARD ); for ( ; !it->isEOF(); it->getNext() ) { ++count; } @@ -173,8 +173,8 @@ namespace ReplTests { Database* db = ctx.db(); Collection* coll = db->getCollection( &txn, cllNS() ); - RecordIterator* it = coll->getIterator( DiskLoc(), false, - CollectionScanParams::FORWARD ); + RecordIterator* it = coll->getIterator( &txn, DiskLoc(), false, + CollectionScanParams::FORWARD ); while ( !it->isEOF() ) { DiskLoc currLoc = it->getNext(); ops.push_back(coll->docFor(currLoc)); @@ -208,8 +208,8 @@ namespace ReplTests { coll = db->createCollection( &txn, ns ); } - RecordIterator* it = coll->getIterator( DiskLoc(), false, - CollectionScanParams::FORWARD ); + RecordIterator* it = coll->getIterator( &txn, DiskLoc(), false, + CollectionScanParams::FORWARD ); ::mongo::log() << "all for " << ns << endl; while ( !it->isEOF() ) { DiskLoc currLoc = it->getNext(); @@ -231,8 +231,8 @@ namespace ReplTests { } vector< DiskLoc > toDelete; - RecordIterator* it = coll->getIterator( DiskLoc(), false, - CollectionScanParams::FORWARD ); + RecordIterator* it = coll->getIterator( &txn, DiskLoc(), false, + CollectionScanParams::FORWARD ); while ( !it->isEOF() ) { toDelete.push_back( it->getNext() ); } diff --git a/src/mongo/dbtests/runner_registry.cpp b/src/mongo/dbtests/runner_registry.cpp index a6c2b4dfac6..970027d9450 100644 --- a/src/mongo/dbtests/runner_registry.cpp +++ b/src/mongo/dbtests/runner_registry.cpp @@ -1,5 +1,5 @@ /** - * Copyright (C) 2013 10gen Inc. + * Copyright (C) 2013-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, @@ -75,7 +75,7 @@ namespace RunnerRegistry { params.collection = collection(); params.direction = CollectionScanParams::FORWARD; params.tailable = false; - auto_ptr<CollectionScan> scan(new CollectionScan(params, ws.get(), NULL)); + auto_ptr<CollectionScan> scan(new CollectionScan(&_opCtx, params, ws.get(), NULL)); // Create a runner to hold it CanonicalQuery* cq; diff --git a/src/mongo/s/d_migrate.cpp b/src/mongo/s/d_migrate.cpp index 2d4cc1eacca..2fb6aa8be8f 100644 --- a/src/mongo/s/d_migrate.cpp +++ b/src/mongo/s/d_migrate.cpp @@ -1,7 +1,7 @@ // d_migrate.cpp /** -* Copyright (C) 2008 10gen Inc. +* Copyright (C) 2008-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, @@ -417,7 +417,7 @@ namespace mongo { BSONObj min = Helpers::toKeyFormat( kp.extendRangeBound( _min, false ) ); BSONObj max = Helpers::toKeyFormat( kp.extendRangeBound( _max, false ) ); - auto_ptr<Runner> runner(InternalPlanner::indexScan(collection, idx, min, max, false)); + auto_ptr<Runner> runner(InternalPlanner::indexScan(txn, collection, idx, min, max, false)); // use the average object size to estimate how many objects a full chunk would carry // do that while traversing the chunk's range using the sharding index, below diff --git a/src/mongo/s/d_split.cpp b/src/mongo/s/d_split.cpp index 7dde165002c..3233cfefd88 100644 --- a/src/mongo/s/d_split.cpp +++ b/src/mongo/s/d_split.cpp @@ -1,7 +1,7 @@ // @file d_split.cpp /** -* Copyright (C) 2008 10gen Inc. +* Copyright (C) 2008-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, @@ -146,7 +146,7 @@ namespace mongo { max = Helpers::toKeyFormat( kp.extendRangeBound( max, false ) ); } - auto_ptr<Runner> runner(InternalPlanner::indexScan(collection, idx, min, max, + auto_ptr<Runner> runner(InternalPlanner::indexScan(txn, collection, idx, min, max, false, InternalPlanner::FORWARD)); // Find the 'missingField' value used to represent a missing document field in a key of @@ -377,7 +377,7 @@ namespace mongo { long long currCount = 0; long long numChunks = 0; - auto_ptr<Runner> runner(InternalPlanner::indexScan(collection, idx, min, max, + auto_ptr<Runner> runner(InternalPlanner::indexScan(txn, collection, idx, min, max, false, InternalPlanner::FORWARD)); BSONObj currKey; @@ -435,7 +435,7 @@ namespace mongo { currCount = 0; log() << "splitVector doing another cycle because of force, keyCount now: " << keyCount << endl; - runner.reset(InternalPlanner::indexScan(collection, idx, min, max, + runner.reset(InternalPlanner::indexScan(txn, collection, idx, min, max, false, InternalPlanner::FORWARD)); state = runner->getNext(&currKey, NULL); @@ -879,7 +879,7 @@ namespace mongo { BSONObj newmin = Helpers::toKeyFormat( kp.extendRangeBound( chunk.min, false) ); BSONObj newmax = Helpers::toKeyFormat( kp.extendRangeBound( chunk.max, false) ); - auto_ptr<Runner> runner(InternalPlanner::indexScan(collection, idx, + auto_ptr<Runner> runner(InternalPlanner::indexScan(txn, collection, idx, newmin, newmax, false)); // check if exactly one document found diff --git a/src/mongo/tools/dump.cpp b/src/mongo/tools/dump.cpp index ba3ff655092..0b6eafb2e58 100644 --- a/src/mongo/tools/dump.cpp +++ b/src/mongo/tools/dump.cpp @@ -1,5 +1,5 @@ /** -* Copyright (C) 2008 10gen Inc. +* Copyright (C) 2008-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, @@ -292,8 +292,8 @@ public: return _repairByName(toolGlobalParams.db); } - void _repairExtents(Collection* coll, Writer& writer) { - scoped_ptr<RecordIterator> iter(coll->getRecordStore()->getIteratorForRepair()); + void _repairExtents(OperationContext* opCtx, Collection* coll, Writer& writer) { + scoped_ptr<RecordIterator> iter(coll->getRecordStore()->getIteratorForRepair(opCtx)); for (DiskLoc currLoc = iter->getNext(); !currLoc.isNull(); currLoc = iter->getNext()) { if (logger::globalLogDomain()->shouldLog(logger::LogSeverity::Debug(1))) { @@ -359,7 +359,7 @@ public: Writer w( f , &m ); try { - _repairExtents(collection, w); + _repairExtents(opCtx, collection, w); } catch ( DBException& e ){ toolError() << "Repair scan failed: " << e.toString() << std::endl; |