diff options
author | Geert Bosch <geert@mongodb.com> | 2014-11-20 14:26:43 -0500 |
---|---|---|
committer | Geert Bosch <geert@mongodb.com> | 2014-11-21 13:18:53 -0500 |
commit | e7f6c56327afa51847a95d9d5bc6399209856c10 (patch) | |
tree | 93a6f8b98d13ff81bd21a2ffc9f312e4ff662123 | |
parent | e5644e2ca12a60df677cb8e8dfc70f19a9423b0a (diff) | |
download | mongo-e7f6c56327afa51847a95d9d5bc6399209856c10.tar.gz |
SERVER-16192: Add ScopedTransaction to automatically commitAndRestart()
53 files changed, 167 insertions, 1 deletions
diff --git a/src/mongo/db/catalog/database.cpp b/src/mongo/db/catalog/database.cpp index 3d29797a620..dc15eebd60d 100644 --- a/src/mongo/db/catalog/database.cpp +++ b/src/mongo/db/catalog/database.cpp @@ -532,6 +532,7 @@ namespace mongo { } void dropAllDatabasesExceptLocal(OperationContext* txn) { + ScopedTransaction transaction(txn, MODE_X); Lock::GlobalWrite lk(txn->lockState()); vector<string> n; diff --git a/src/mongo/db/client.cpp b/src/mongo/db/client.cpp index d1ed1a927c8..c6eeef0ff8c 100644 --- a/src/mongo/db/client.cpp +++ b/src/mongo/db/client.cpp @@ -198,7 +198,8 @@ namespace mongo { AutoGetOrCreateDb::AutoGetOrCreateDb(OperationContext* txn, const StringData& ns, LockMode mode) - : _dbLock(txn->lockState(), ns, mode), + : _transaction(txn, MODE_IX), + _dbLock(txn->lockState(), ns, mode), _db(dbHolder().get(txn, ns)) { invariant(mode == MODE_IX || mode == MODE_X); _justCreated = false; diff --git a/src/mongo/db/client.h b/src/mongo/db/client.h index 5fe44c85b09..eb1dc8a91ad 100644 --- a/src/mongo/db/client.h +++ b/src/mongo/db/client.h @@ -113,6 +113,7 @@ namespace mongo { Lock::DBLock& lock() { return _dbLock; } private: + ScopedTransaction _transaction; Lock::DBLock _dbLock; // not const, as we may need to relock for implicit create Database* _db; bool _justCreated; diff --git a/src/mongo/db/cloner.cpp b/src/mongo/db/cloner.cpp index 58e8d03c49d..452916c15cf 100644 --- a/src/mongo/db/cloner.cpp +++ b/src/mongo/db/cloner.cpp @@ -111,6 +111,7 @@ namespace mongo { invariant(from_collection.coll() != "system.indexes"); // XXX: can probably take dblock instead + ScopedTransaction transaction(txn, MODE_X); Lock::GlobalWrite lk(txn->lockState()); // Make sure database still exists after we resume from the temp release @@ -317,6 +318,7 @@ namespace mongo { const NamespaceString nss(ns); const string dbname = nss.db().toString(); + ScopedTransaction transaction(txn, MODE_IX); Lock::DBLock dbWrite(txn->lockState(), dbname, MODE_X); Database* db = dbHolder().openDb(txn, dbname); diff --git a/src/mongo/db/commands/apply_ops.cpp b/src/mongo/db/commands/apply_ops.cpp index 4b2858d9505..c7aa7de3888 100644 --- a/src/mongo/db/commands/apply_ops.cpp +++ b/src/mongo/db/commands/apply_ops.cpp @@ -82,6 +82,7 @@ namespace mongo { // SERVER-4328 todo : is global ok or does this take a long time? i believe multiple // ns used so locking individually requires more analysis + ScopedTransaction transaction(txn, MODE_X); Lock::GlobalWrite globalWriteLock(txn->lockState()); DBDirectClient db(txn); @@ -137,6 +138,7 @@ namespace mongo { // We do not have a wrapping WriteUnitOfWork so it is possible for a journal // commit to happen with a subset of ops applied. // TODO figure out what to do about this. + ScopedTransaction transaction(txn, MODE_IX); Lock::DBLock lk(txn->lockState(), nsToDatabaseSubstring(ns), MODE_X); invariant(txn->lockState()->isRecursive()); diff --git a/src/mongo/db/commands/clone.cpp b/src/mongo/db/commands/clone.cpp index 2acc7b1e452..ddf2775c55f 100644 --- a/src/mongo/db/commands/clone.cpp +++ b/src/mongo/db/commands/clone.cpp @@ -114,6 +114,7 @@ namespace mongo { set<string> clonedColls; + ScopedTransaction transaction(txn, MODE_IX); Lock::DBLock dbXLock(txn->lockState(), dbname, MODE_X); Cloner cloner; diff --git a/src/mongo/db/commands/collection_to_capped.cpp b/src/mongo/db/commands/collection_to_capped.cpp index 9e0f2615038..52769976cfd 100644 --- a/src/mongo/db/commands/collection_to_capped.cpp +++ b/src/mongo/db/commands/collection_to_capped.cpp @@ -161,6 +161,7 @@ namespace mongo { return false; } + ScopedTransaction transaction(txn, MODE_IX); Lock::DBLock dbXLock(txn->lockState(), dbname, MODE_X); Client::Context ctx(txn, dbname); @@ -214,6 +215,7 @@ namespace mongo { bool fromRepl ) { // calls renamecollection which does a global lock, so we must too: // + ScopedTransaction transaction(txn, MODE_X); Lock::GlobalWrite globalWriteLock(txn->lockState()); Client::Context ctx(txn, dbname); diff --git a/src/mongo/db/commands/compact.cpp b/src/mongo/db/commands/compact.cpp index 2bc8a330c57..66d8f353e17 100644 --- a/src/mongo/db/commands/compact.cpp +++ b/src/mongo/db/commands/compact.cpp @@ -146,6 +146,7 @@ namespace mongo { compactOptions.validateDocuments = cmdObj["validate"].trueValue(); + ScopedTransaction transaction(txn, MODE_IX); Lock::DBLock lk(txn->lockState(), db, MODE_X); BackgroundOperation::assertNoBgOpInProgForNs(ns.ns()); Client::Context ctx(txn, ns); diff --git a/src/mongo/db/commands/copydb.cpp b/src/mongo/db/commands/copydb.cpp index a04a25a50d6..e5d6df6d3d8 100644 --- a/src/mongo/db/commands/copydb.cpp +++ b/src/mongo/db/commands/copydb.cpp @@ -215,10 +215,12 @@ namespace mongo { if (fromSelf) { // SERVER-4328 todo lock just the two db's not everything for the fromself case + ScopedTransaction transaction(txn, MODE_X); Lock::GlobalWrite lk(txn->lockState()); return cloner.go(txn, todb, fromhost, cloneOptions, NULL, errmsg); } + ScopedTransaction transaction(txn, MODE_IX); Lock::DBLock lk (txn->lockState(), todb, MODE_X); return cloner.go(txn, todb, fromhost, cloneOptions, NULL, errmsg); } diff --git a/src/mongo/db/commands/cpuprofile.cpp b/src/mongo/db/commands/cpuprofile.cpp index d279f4b51d1..44cae32b50c 100644 --- a/src/mongo/db/commands/cpuprofile.cpp +++ b/src/mongo/db/commands/cpuprofile.cpp @@ -133,6 +133,7 @@ namespace mongo { std::string &errmsg, BSONObjBuilder &result, bool fromRepl ) { + ScopedTransaction transaction(txn, MODE_IX); Lock::DBLock dbXLock(txn->lockState(), db, MODE_X); // The lock here is just to prevent concurrency, nothing will write. Client::Context ctx(txn, db); @@ -152,6 +153,7 @@ namespace mongo { std::string &errmsg, BSONObjBuilder &result, bool fromRepl ) { + ScopedTransaction transaction(txn, MODE_IX); Lock::DBLock dbXLock(txn->lockState(), db, MODE_X); Client::Context ctx(txn, db); diff --git a/src/mongo/db/commands/create_indexes.cpp b/src/mongo/db/commands/create_indexes.cpp index 7b27aee91bb..67cd6bdff33 100644 --- a/src/mongo/db/commands/create_indexes.cpp +++ b/src/mongo/db/commands/create_indexes.cpp @@ -136,6 +136,7 @@ namespace mongo { // now we know we have to create index(es) // Note: createIndexes command does not currently respect shard versioning. + ScopedTransaction transaction(txn, MODE_IX); Lock::DBLock dbLock(txn->lockState(), ns.db(), MODE_X); Database* db = dbHolder().get(txn, ns.db()); if (!db) { diff --git a/src/mongo/db/commands/drop_indexes.cpp b/src/mongo/db/commands/drop_indexes.cpp index 1e92d0e0f21..85e212efbdd 100644 --- a/src/mongo/db/commands/drop_indexes.cpp +++ b/src/mongo/db/commands/drop_indexes.cpp @@ -104,6 +104,7 @@ namespace mongo { CmdDropIndexes() : Command("dropIndexes", false, "deleteIndexes") { } bool run(OperationContext* txn, const string& dbname, BSONObj& jsobj, int, string& errmsg, BSONObjBuilder& anObjBuilder, bool fromRepl) { + ScopedTransaction transaction(txn, MODE_IX); Lock::DBLock dbXLock(txn->lockState(), dbname, MODE_X); WriteUnitOfWork wunit(txn); bool ok = wrappedRun(txn, dbname, jsobj, errmsg, anObjBuilder); @@ -245,6 +246,7 @@ namespace mongo { LOG(0) << "CMD: reIndex " << toDeleteNs << endl; + ScopedTransaction transaction(txn, MODE_IX); Lock::DBLock dbXLock(txn->lockState(), dbname, MODE_X); Client::Context ctx(txn, toDeleteNs); diff --git a/src/mongo/db/commands/find_and_modify.cpp b/src/mongo/db/commands/find_and_modify.cpp index c6f7f7fca97..ce9e8dd2849 100644 --- a/src/mongo/db/commands/find_and_modify.cpp +++ b/src/mongo/db/commands/find_and_modify.cpp @@ -126,6 +126,7 @@ namespace mongo { if ( !ok && errmsg == "no-collection" ) { // Take X lock so we can create collection, then re-run operation. + ScopedTransaction transaction(txn, MODE_IX); Lock::DBLock lk(txn->lockState(), dbname, MODE_X); Client::Context ctx(txn, ns, false /* don't check version */); Database* db = ctx.db(); @@ -402,6 +403,7 @@ namespace mongo { } } + ScopedTransaction transaction(txn, MODE_IX); Lock::DBLock dbXLock(txn->lockState(), dbname, MODE_X); Client::Context ctx(txn, ns); diff --git a/src/mongo/db/commands/fsync.cpp b/src/mongo/db/commands/fsync.cpp index 69f04cf547c..fb4e41bb4b7 100644 --- a/src/mongo/db/commands/fsync.cpp +++ b/src/mongo/db/commands/fsync.cpp @@ -134,6 +134,7 @@ namespace mongo { // the simple fsync command case if (sync) { // can this be GlobalRead? and if it can, it should be nongreedy. + ScopedTransaction transaction(txn, MODE_X); Lock::GlobalWrite w(txn->lockState()); getDur().commitNow(txn); @@ -152,6 +153,7 @@ namespace mongo { SimpleMutex::scoped_lock lkf(filesLockedFsync); OperationContextImpl txn; // XXX? + ScopedTransaction transaction(&txn, MODE_X); Lock::GlobalWrite global(txn.lockState()); // No WriteUnitOfWork needed SimpleMutex::scoped_lock lk(fsyncCmd.m); diff --git a/src/mongo/db/commands/list_databases.cpp b/src/mongo/db/commands/list_databases.cpp index e852e30617f..c84f38333b9 100644 --- a/src/mongo/db/commands/list_databases.cpp +++ b/src/mongo/db/commands/list_databases.cpp @@ -87,6 +87,7 @@ namespace mongo { b.append( "name", dbname ); { + ScopedTransaction transaction(txn, MODE_IS); Lock::DBLock dbLock(txn->lockState(), dbname, MODE_IS); Database* db = dbHolder().get( txn, dbname ); diff --git a/src/mongo/db/commands/mr.cpp b/src/mongo/db/commands/mr.cpp index 72af37852fe..331ab2dfee5 100644 --- a/src/mongo/db/commands/mr.cpp +++ b/src/mongo/db/commands/mr.cpp @@ -334,6 +334,7 @@ namespace mongo { if (_useIncremental) { // We don't want to log the deletion of incLong as it isn't replicated. While // harmless, this would lead to a scary looking warning on the secondaries. + ScopedTransaction(_txn, MODE_IX); Lock::DBLock lk(_txn->lockState(), nsToDatabaseSubstring(_config.incLong), MODE_X); @@ -538,6 +539,7 @@ namespace mongo { invariant( !txn->lockState()->isLocked() ); + ScopedTransaction transaction(txn, MODE_X); Lock::GlobalWrite lock(txn->lockState()); // TODO(erh): this is how it was, but seems it doesn't need to be global return postProcessCollectionNonAtomic(txn, op, pm); } @@ -576,6 +578,7 @@ namespace mongo { if (_config.outputOptions.outType == Config::REPLACE || _safeCount(_db, _config.outputOptions.finalNamespace) == 0) { + ScopedTransaction transaction(txn, MODE_X); Lock::GlobalWrite lock(txn->lockState()); // TODO(erh): why global??? // replace: just rename from temp to final collection name, dropping previous collection _db.dropCollection( _config.outputOptions.finalNamespace ); @@ -598,6 +601,7 @@ namespace mongo { _safeCount(_db, _config.tempNamespace, BSONObj())); auto_ptr<DBClientCursor> cursor = _db.query(_config.tempNamespace , BSONObj()); while (cursor->more()) { + ScopedTransaction(_txn, MODE_IX); Lock::DBLock lock(_txn->lockState(), nsToDatabaseSubstring(_config.outputOptions.finalNamespace), MODE_X); @@ -617,6 +621,7 @@ namespace mongo { _safeCount(_db, _config.tempNamespace, BSONObj())); auto_ptr<DBClientCursor> cursor = _db.query( _config.tempNamespace , BSONObj() ); while ( cursor->more() ) { + ScopedTransaction transaction(txn, MODE_X); Lock::GlobalWrite lock(txn->lockState()); // TODO(erh) why global? BSONObj temp = cursor->nextSafe(); BSONObj old; diff --git a/src/mongo/db/commands/rename_collection.cpp b/src/mongo/db/commands/rename_collection.cpp index ed548cc3bf9..9f5ff7b54fc 100644 --- a/src/mongo/db/commands/rename_collection.cpp +++ b/src/mongo/db/commands/rename_collection.cpp @@ -112,6 +112,7 @@ namespace mongo { string& errmsg, BSONObjBuilder& result, bool fromRepl) { + ScopedTransaction transaction(txn, MODE_X); Lock::GlobalWrite globalWriteLock(txn->lockState()); string source = cmdObj.getStringField( name.c_str() ); string target = cmdObj.getStringField( "to" ); diff --git a/src/mongo/db/commands/test_commands.cpp b/src/mongo/db/commands/test_commands.cpp index 73c0911d58d..cb1245508da 100644 --- a/src/mongo/db/commands/test_commands.cpp +++ b/src/mongo/db/commands/test_commands.cpp @@ -66,6 +66,7 @@ namespace mongo { string ns = dbname + "." + coll; BSONObj obj = cmdObj[ "obj" ].embeddedObjectUserCheck(); + ScopedTransaction transaction(txn, MODE_IX); Lock::DBLock lk(txn->lockState(), dbname, MODE_X); WriteUnitOfWork wunit(txn); Client::Context ctx(txn, ns ); @@ -117,10 +118,12 @@ namespace mongo { } if(cmdObj.getBoolField("w")) { + ScopedTransaction transaction(txn, MODE_X); Lock::GlobalWrite lk(txn->lockState()); sleepmillis(millis); } else { + ScopedTransaction transaction(txn, MODE_S); Lock::GlobalRead lk(txn->lockState()); sleepmillis(millis); } diff --git a/src/mongo/db/commands/write_commands/batch_executor.cpp b/src/mongo/db/commands/write_commands/batch_executor.cpp index 17552185f0e..7fed228ed3f 100644 --- a/src/mongo/db/commands/write_commands/batch_executor.cpp +++ b/src/mongo/db/commands/write_commands/batch_executor.cpp @@ -736,6 +736,7 @@ namespace mongo { private: bool _lockAndCheckImpl(WriteOpResult* result, bool intentLock=true); + ScopedTransaction _transaction; // Guard object for the write lock on the target database. scoped_ptr<Lock::DBLock> _writeLock; scoped_ptr<Lock::CollectionLock> _collLock; @@ -943,6 +944,7 @@ namespace mongo { txn(txn), request(aRequest), currIndex(0), + _transaction(txn, MODE_IX), _collection(NULL) { } @@ -1200,6 +1202,7 @@ namespace mongo { } if ( createCollection ) { + ScopedTransaction transaction(txn, MODE_IX); Lock::DBLock lk(txn->lockState(), nsString.db(), MODE_X); Client::Context ctx(txn, nsString.ns(), false /* don't check version */); Database* db = ctx.db(); @@ -1216,6 +1219,7 @@ namespace mongo { } /////////////////////////////////////////// + ScopedTransaction transaction(txn, MODE_IX); Lock::DBLock dbLock(txn->lockState(), nsString.db(), MODE_IX); Lock::CollectionLock colLock(txn->lockState(), nsString.ns(), diff --git a/src/mongo/db/db.cpp b/src/mongo/db/db.cpp index 34d915bced6..060943b5e7c 100644 --- a/src/mongo/db/db.cpp +++ b/src/mongo/db/db.cpp @@ -252,6 +252,7 @@ namespace mongo { OperationContextImpl txn; + ScopedTransaction transaction(&txn, MODE_X); Lock::GlobalWrite lk(txn.lockState()); AutoGetOrCreateDb autoDb(&txn, "local", mongo::MODE_X); Database* db = autoDb.getDb(); @@ -310,6 +311,7 @@ namespace mongo { */ static unsigned long long checkIfReplMissingFromCommandLine(OperationContext* txn) { // This is helpful for the query below to work as you can't open files when readlocked + ScopedTransaction transaction(txn, MODE_X); Lock::GlobalWrite lk(txn->lockState()); if (!repl::getGlobalReplicationCoordinator()->getSettings().usingReplSets()) { DBDirectClient c(txn); @@ -322,6 +324,7 @@ namespace mongo { LOG(1) << "enter repairDatabases (to check pdfile version #)" << endl; OperationContextImpl txn; + ScopedTransaction transaction(&txn, MODE_X); Lock::GlobalWrite lk(txn.lockState()); vector<string> dbNames; diff --git a/src/mongo/db/dbcommands.cpp b/src/mongo/db/dbcommands.cpp index 0c6164f8f3a..6ffe89f1820 100644 --- a/src/mongo/db/dbcommands.cpp +++ b/src/mongo/db/dbcommands.cpp @@ -202,6 +202,7 @@ namespace mongo { { // TODO: SERVER-4328 Don't lock globally + ScopedTransaction transaction(txn, MODE_X); Lock::GlobalWrite lk(txn->lockState()); if (dbHolder().get(txn, dbname) == NULL) { return true; // didn't exist, was no-op @@ -286,6 +287,7 @@ namespace mongo { } // TODO: SERVER-4328 Don't lock globally + ScopedTransaction transaction(txn, MODE_X); Lock::GlobalWrite lk(txn->lockState()); Client::Context context(txn, dbname ); @@ -358,6 +360,7 @@ namespace mongo { // Needs to be locked exclusively, because creates the system.profile collection // in the local database. // + ScopedTransaction transaction(txn, MODE_IX); Lock::DBLock dbXLock(txn->lockState(), dbname, MODE_X); Client::Context ctx(txn, dbname); @@ -413,6 +416,7 @@ namespace mongo { // This doesn't look like it requires exclusive DB lock, because it uses its own diag // locking, but originally the lock was set to be WRITE, so preserving the behaviour. // + ScopedTransaction transaction(txn, MODE_IX); Lock::DBLock dbXLock(txn->lockState(), dbname, MODE_X); Client::Context ctx(txn, dbname); @@ -482,6 +486,7 @@ namespace mongo { return false; } + ScopedTransaction transaction(txn, MODE_IX); Lock::DBLock dbXLock(txn->lockState(), dbname, MODE_X); Client::Context ctx(txn, nsToDrop); Database* db = ctx.db(); @@ -582,6 +587,7 @@ namespace mongo { !options["capped"].trueValue() || options["size"].isNumber() || options.hasField("$nExtents")); + ScopedTransaction transaction(txn, MODE_IX); Lock::DBLock dbXLock(txn->lockState(), dbname, MODE_X); WriteUnitOfWork wunit(txn); Client::Context ctx(txn, ns); @@ -998,6 +1004,7 @@ namespace mongo { const std::string ns = dbname + "." + collName; + ScopedTransaction transaction(txn, MODE_IX); Lock::DBLock dbXLock(txn->lockState(), dbname, MODE_X); WriteUnitOfWork wunit(txn); Client::Context ctx(txn, ns ); diff --git a/src/mongo/db/dbeval.cpp b/src/mongo/db/dbeval.cpp index d3f3901c7d1..a371469c73b 100644 --- a/src/mongo/db/dbeval.cpp +++ b/src/mongo/db/dbeval.cpp @@ -150,6 +150,7 @@ namespace mongo { return dbEval(txn, dbname, cmdObj, result, errmsg); } + ScopedTransaction transaction(txn, MODE_X); Lock::GlobalWrite lk(txn->lockState()); // No WriteUnitOfWork necessary, as dbEval will create its own, see "nolock" case above Client::Context ctx(txn, dbname ); diff --git a/src/mongo/db/exec/stagedebug_cmd.cpp b/src/mongo/db/exec/stagedebug_cmd.cpp index 493b28cb567..5ae063eed2d 100644 --- a/src/mongo/db/exec/stagedebug_cmd.cpp +++ b/src/mongo/db/exec/stagedebug_cmd.cpp @@ -121,6 +121,7 @@ namespace mongo { // TODO A write lock is currently taken here to accommodate stages that perform writes // (e.g. DeleteStage). This should be changed to use a read lock for read-only // execution trees. + ScopedTransaction transaction(txn, MODE_IX); Lock::DBLock lk(txn->lockState(), dbname, MODE_X); Client::Context ctx(txn, dbname); diff --git a/src/mongo/db/index_builder.cpp b/src/mongo/db/index_builder.cpp index 1047d9a44d6..f784c5064e0 100644 --- a/src/mongo/db/index_builder.cpp +++ b/src/mongo/db/index_builder.cpp @@ -72,6 +72,7 @@ namespace mongo { txn.getCurOp()->reset(HostAndPort(), dbInsert); NamespaceString ns(_index["ns"].String()); + ScopedTransaction transaction(&txn, MODE_IX); Lock::DBLock dlk(txn.lockState(), ns.db(), MODE_X); Client::Context ctx(&txn, ns.getSystemIndexesCollection()); diff --git a/src/mongo/db/index_rebuilder.cpp b/src/mongo/db/index_rebuilder.cpp index e684bdc0baa..b23270e3afe 100644 --- a/src/mongo/db/index_rebuilder.cpp +++ b/src/mongo/db/index_rebuilder.cpp @@ -64,6 +64,7 @@ namespace { // This write lock is held throughout the index building process // for this namespace. + ScopedTransaction transaction(txn, MODE_IX); Lock::DBLock lk(txn->lockState(), nsToDatabaseSubstring(ns), MODE_X); Client::Context ctx(txn, ns); diff --git a/src/mongo/db/instance.cpp b/src/mongo/db/instance.cpp index 9c97fccecdb..57f5cf5fb2b 100644 --- a/src/mongo/db/instance.cpp +++ b/src/mongo/db/instance.cpp @@ -573,6 +573,7 @@ namespace { uassertStatusOK(executor.prepare()); // Tentatively take an intent lock, fix up if we need to create the collection + ScopedTransaction transaction(txn, MODE_IX); Lock::DBLock dbLock(txn->lockState(), ns.db(), MODE_IX); if (dbHolder().get(txn, ns.db()) == NULL) { // If DB doesn't exist, don't implicitly create it in Client::Context @@ -606,6 +607,7 @@ namespace { UpdateExecutor executor(txn, &request, &op.debug()); uassertStatusOK(executor.prepare()); + ScopedTransaction transaction(txn, MODE_IX); Lock::DBLock dbLock(txn->lockState(), ns.db(), MODE_X); Client::Context ctx(txn, ns); Database* db = ctx.db(); @@ -968,6 +970,7 @@ namespace { { const bool isIndexBuild = (nsToCollectionSubstring(ns) == "system.indexes"); const LockMode mode = isIndexBuild ? MODE_X : MODE_IX; + ScopedTransaction transaction(txn, MODE_IX); Lock::DBLock dbLock(txn->lockState(), nsString.db(), mode); Lock::CollectionLock collLock(txn->lockState(), nsString.ns(), mode); @@ -995,6 +998,7 @@ namespace { } // Collection didn't exist so try again with MODE_X + ScopedTransaction transaction(txn, MODE_IX); Lock::DBLock dbLock(txn->lockState(), nsString.db(), MODE_X); // CONCURRENCY TODO: is being read locked in big log sufficient here? @@ -1057,6 +1061,7 @@ namespace { repl::getGlobalReplicationCoordinator()->shutdown(); + ScopedTransaction transaction(&txn, MODE_X); Lock::GlobalWrite lk(txn.lockState()); log() << "now exiting" << endl; diff --git a/src/mongo/db/operation_context.h b/src/mongo/db/operation_context.h index 3897fa4820d..fcdd3724c62 100644 --- a/src/mongo/db/operation_context.h +++ b/src/mongo/db/operation_context.h @@ -33,6 +33,7 @@ #include "mongo/base/string_data.h" #include "mongo/db/storage/recovery_unit.h" #include "mongo/db/concurrency/locker.h" +#include "mongo/db/concurrency/d_concurrency.h" namespace mongo { @@ -175,4 +176,35 @@ namespace mongo { bool _ended; }; + class Database; + + /** + * RAII-style class to mark the scope of a transaction. ScopedTransactions may be nested. + * An outermost ScopedTransaction calls commitAndRestart() on destruction, so that the storage + * engine can release resources, such as snapshots or locks, that it may have acquired during + * the transaction. Note that any writes are committed in nested WriteUnitOfWork scopes, + * so write conflicts cannot happen on completing a ScopedTransaction. + * + * TODO: The ScopedTransaction should hold the global lock + */ + class ScopedTransaction { + MONGO_DISALLOW_COPYING(ScopedTransaction); + public: + /** + * The mode for the transaction indicates whether the transaction will write (MODE_IX) or + * only read (MODE_IS), or needs to run without other writers (MODE_S) or any other + * operations (MODE_X) on the server. + */ + ScopedTransaction(OperationContext* txn, LockMode mode) : _txn(txn) { } + + ~ScopedTransaction() { + if (!_txn->lockState()->isLocked()) { + _txn->recoveryUnit()->commitAndRestart(); + } + } + + private: + OperationContext* _txn; + }; + } // namespace mongo diff --git a/src/mongo/db/ops/update_executor.cpp b/src/mongo/db/ops/update_executor.cpp index bd95b062024..23645123af9 100644 --- a/src/mongo/db/ops/update_executor.cpp +++ b/src/mongo/db/ops/update_executor.cpp @@ -137,6 +137,7 @@ namespace mongo { locker->isLockHeldForMode( ResourceId( RESOURCE_DATABASE, nsString.db() ), MODE_X ) ); + ScopedTransaction transaction(_txn, MODE_IX); Lock::DBLock lk(_txn->lockState(), nsString.db(), MODE_X); WriteUnitOfWork wuow(_txn); diff --git a/src/mongo/db/repl/bgsync.cpp b/src/mongo/db/repl/bgsync.cpp index cf6be9c7cac..e5b2cbe032d 100644 --- a/src/mongo/db/repl/bgsync.cpp +++ b/src/mongo/db/repl/bgsync.cpp @@ -521,6 +521,7 @@ namespace { long long BackgroundSync::_readLastAppliedHash(OperationContext* txn) { BSONObj oplogEntry; try { + ScopedTransaction transaction(txn, MODE_IX); Lock::DBLock lk(txn->lockState(), "local", MODE_X); bool success = Helpers::getLast(txn, rsoplog, oplogEntry); if (!success) { diff --git a/src/mongo/db/repl/master_slave.cpp b/src/mongo/db/repl/master_slave.cpp index 4aea655198b..543afab4fbb 100644 --- a/src/mongo/db/repl/master_slave.cpp +++ b/src/mongo/db/repl/master_slave.cpp @@ -170,6 +170,7 @@ namespace repl { bool exists = Helpers::getSingleton(txn, "local.me", _me); if (!exists || !_me.hasField("host") || _me["host"].String() != myname) { + ScopedTransaction transaction(txn, MODE_IX); Lock::DBLock dblk(txn->lockState(), "local", MODE_X); WriteUnitOfWork wunit(txn); // clean out local.me @@ -820,6 +821,7 @@ namespace repl { } // obviously global isn't ideal, but non-repl set is old so // keeping it simple + ScopedTransaction transaction(txn, MODE_X); Lock::GlobalWrite lk(txn->lockState()); save(txn); } @@ -871,6 +873,7 @@ namespace repl { log() << "repl: " << ns << " oplog is empty" << endl; } { + ScopedTransaction transaction(txn, MODE_X); Lock::GlobalWrite lk(txn->lockState()); save(txn); } @@ -943,6 +946,7 @@ namespace repl { const bool moreInitialSyncsPending = !addDbNextPass.empty() && n; if ( moreInitialSyncsPending || !oplogReader.more() ) { + ScopedTransaction transaction(txn, MODE_X); Lock::GlobalWrite lk(txn->lockState()); if (tailing) { @@ -959,6 +963,7 @@ namespace repl { OCCASIONALLY if( n > 0 && ( n > 100000 || time(0) - saveLast > 60 ) ) { // periodically note our progress, in case we are doing a lot of work and crash + ScopedTransaction transaction(txn, MODE_X); Lock::GlobalWrite lk(txn->lockState()); syncedTo = nextOpTime; // can't update local log ts since there are pending operations from our peer @@ -1000,6 +1005,7 @@ namespace repl { verify( justOne ); oplogReader.putBack( op ); _sleepAdviceTime = nextOpTime.getSecs() + replSettings.slavedelay + 1; + ScopedTransaction transaction(txn, MODE_X); Lock::GlobalWrite lk(txn->lockState()); if ( n > 0 ) { syncedTo = last; @@ -1082,6 +1088,7 @@ namespace repl { int _replMain(OperationContext* txn, ReplSource::SourceVector& sources, int& nApplied) { { ReplInfo r("replMain load sources"); + ScopedTransaction transaction(txn, MODE_X); Lock::GlobalWrite lk(txn->lockState()); ReplSource::loadAll(txn, sources); @@ -1153,6 +1160,7 @@ namespace repl { while ( 1 ) { int s = 0; { + ScopedTransaction transaction(txn, MODE_X); Lock::GlobalWrite lk(txn->lockState()); if ( replAllDead ) { // throttledForceResyncDead can throw @@ -1184,6 +1192,7 @@ namespace repl { } { + ScopedTransaction transaction(txn, MODE_X); Lock::GlobalWrite lk(txn->lockState()); verify( syncing == 1 ); syncing--; @@ -1310,6 +1319,7 @@ namespace repl { } OperationContextImpl txn; // XXX + ScopedTransaction transaction(&txn, MODE_S); Lock::GlobalRead lk(txn.lockState()); for( unsigned i = a; i <= b; i++ ) { diff --git a/src/mongo/db/repl/minvalid.cpp b/src/mongo/db/repl/minvalid.cpp index 30a22a611ea..0005f364963 100644 --- a/src/mongo/db/repl/minvalid.cpp +++ b/src/mongo/db/repl/minvalid.cpp @@ -50,17 +50,20 @@ namespace { } // namespace void clearInitialSyncFlag(OperationContext* txn) { + ScopedTransaction transaction(txn, MODE_IX); Lock::DBLock lk(txn->lockState(), "local", MODE_X); Helpers::putSingleton(txn, minvalidNS, BSON("$unset" << initialSyncFlag)); } void setInitialSyncFlag(OperationContext* txn) { + ScopedTransaction transaction(txn, MODE_IX); Lock::DBLock lk(txn->lockState(), "local", MODE_X); Helpers::putSingleton(txn, minvalidNS, BSON("$set" << initialSyncFlag)); } bool getInitialSyncFlag() { OperationContextImpl txn; + ScopedTransaction transaction(&txn, MODE_IX); Lock::DBLock lk(txn.lockState(), "local", MODE_X); BSONObj mv; bool found = Helpers::getSingleton( &txn, minvalidNS, mv); @@ -72,11 +75,13 @@ namespace { } void setMinValid(OperationContext* ctx, OpTime ts) { + ScopedTransaction transaction(ctx, MODE_IX); Lock::DBLock lk(ctx->lockState(), "local", MODE_X); Helpers::putSingleton(ctx, minvalidNS, BSON("$set" << BSON("ts" << ts))); } OpTime getMinValid(OperationContext* txn) { + ScopedTransaction transaction(txn, MODE_IS); Lock::DBLock lk(txn->lockState(), "local", MODE_S); BSONObj mv; bool found = Helpers::getSingleton(txn, minvalidNS, mv); diff --git a/src/mongo/db/repl/network_interface_impl.cpp b/src/mongo/db/repl/network_interface_impl.cpp index d84d2148210..b459260f2ef 100644 --- a/src/mongo/db/repl/network_interface_impl.cpp +++ b/src/mongo/db/repl/network_interface_impl.cpp @@ -535,6 +535,7 @@ namespace { const stdx::function<void (OperationContext*)>& callback) { Client::initThreadIfNotAlready(); OperationContextImpl txn; + ScopedTransaction transaction(&txn, MODE_X); Lock::GlobalWrite lk(txn.lockState()); callback(&txn); } diff --git a/src/mongo/db/repl/oplog.cpp b/src/mongo/db/repl/oplog.cpp index 9842d675f16..0f68a52a6a8 100644 --- a/src/mongo/db/repl/oplog.cpp +++ b/src/mongo/db/repl/oplog.cpp @@ -149,6 +149,7 @@ namespace repl { todo : make _logOpRS() call this so we don't repeat ourself? */ OpTime _logOpObjRS(OperationContext* txn, const BSONObj& op) { + ScopedTransaction transaction(txn, MODE_IX); Lock::DBLock lk(txn->lockState(), "local", MODE_X); const OpTime ts = op["ts"]._opTime(); @@ -265,6 +266,7 @@ namespace repl { return; } + ScopedTransaction transaction(txn, MODE_IX); Lock::DBLock lk(txn->lockState(), "local", MODE_IX); Lock::CollectionLock lk2(txn->lockState(), rsoplog, MODE_IX); @@ -335,6 +337,7 @@ namespace repl { return; } + ScopedTransaction transaction(txn, MODE_IX); Lock::DBLock lk(txn->lockState(), "local", MODE_IX); if( logNS == 0 ) { @@ -459,6 +462,7 @@ namespace repl { } void createOplog(OperationContext* txn) { + ScopedTransaction transaction(txn, MODE_X); Lock::GlobalWrite lk(txn->lockState()); const char * ns = "local.oplog.$main"; diff --git a/src/mongo/db/repl/repl_coordinator_external_state_impl.cpp b/src/mongo/db/repl/repl_coordinator_external_state_impl.cpp index 48bdf194987..c6c15238363 100644 --- a/src/mongo/db/repl/repl_coordinator_external_state_impl.cpp +++ b/src/mongo/db/repl/repl_coordinator_external_state_impl.cpp @@ -125,6 +125,7 @@ namespace { std::string myname = getHostName(); OID myRID; { + ScopedTransaction transaction(txn, MODE_IX); Lock::DBLock lock(txn->lockState(), meDatabaseName, MODE_X); BSONObj me; @@ -171,6 +172,7 @@ namespace { OperationContext* txn, const BSONObj& config) { try { + ScopedTransaction transaction(txn, MODE_IX); Lock::DBLock dbWriteLock(txn->lockState(), configDatabaseName, MODE_X); Helpers::putSingleton(txn, configCollectionName, config); return Status::OK(); diff --git a/src/mongo/db/repl/repl_coordinator_impl.cpp b/src/mongo/db/repl/repl_coordinator_impl.cpp index ad835cc531d..ca95291f26e 100644 --- a/src/mongo/db/repl/repl_coordinator_impl.cpp +++ b/src/mongo/db/repl/repl_coordinator_impl.cpp @@ -529,6 +529,7 @@ namespace { } lk.unlock(); boost::scoped_ptr<OperationContext> txn(_externalState->createOperationContext("rsDrain")); + ScopedTransaction transaction(txn.get(), MODE_X); Lock::GlobalWrite globalWriteLock(txn->lockState()); lk.lock(); if (!_isWaitingForDrainToComplete) { diff --git a/src/mongo/db/repl/resync.cpp b/src/mongo/db/repl/resync.cpp index fc47875005b..61cb3e4632b 100644 --- a/src/mongo/db/repl/resync.cpp +++ b/src/mongo/db/repl/resync.cpp @@ -66,6 +66,7 @@ namespace repl { BSONObjBuilder& result, bool fromRepl) { + ScopedTransaction transaction(txn, MODE_X); Lock::GlobalWrite globalWriteLock(txn->lockState()); ReplicationCoordinator* replCoord = getGlobalReplicationCoordinator(); diff --git a/src/mongo/db/repl/rs_initialsync.cpp b/src/mongo/db/repl/rs_initialsync.cpp index b349d81a1f0..efdf411bc4c 100644 --- a/src/mongo/db/repl/rs_initialsync.cpp +++ b/src/mongo/db/repl/rs_initialsync.cpp @@ -116,6 +116,7 @@ namespace { options.syncIndexes = ! dataPass; // Make database stable + ScopedTransaction transaction(txn, MODE_IX); Lock::DBLock dbWrite(txn->lockState(), db, MODE_X); if (!cloner.go(txn, db, host, options, NULL, err, &errCode)) { @@ -200,6 +201,7 @@ namespace { if (!init->syncApply(txn, op)) { bool retry; { + ScopedTransaction transaction(txn, MODE_X); Lock::GlobalWrite lk(txn->lockState()); retry = init->shouldRetry(txn, op); } diff --git a/src/mongo/db/repl/sync_source_feedback.cpp b/src/mongo/db/repl/sync_source_feedback.cpp index 71c1c6f0485..677cb8c7e2c 100644 --- a/src/mongo/db/repl/sync_source_feedback.cpp +++ b/src/mongo/db/repl/sync_source_feedback.cpp @@ -77,6 +77,7 @@ namespace repl { void SyncSourceFeedback::ensureMe(OperationContext* txn) { string myname = getHostName(); { + ScopedTransaction transaction(txn, MODE_IX); Lock::DBLock dlk(txn->lockState(), "local", MODE_X); Client::Context ctx(txn, "local"); diff --git a/src/mongo/db/repl/sync_tail.cpp b/src/mongo/db/repl/sync_tail.cpp index b779fb6e16b..e191f96c1b1 100644 --- a/src/mongo/db/repl/sync_tail.cpp +++ b/src/mongo/db/repl/sync_tail.cpp @@ -474,6 +474,7 @@ namespace repl { namespace { void tryToGoLiveAsASecondary(OperationContext* txn, ReplicationCoordinator* replCoord) { + ScopedTransaction transaction(txn, MODE_S); Lock::GlobalRead readLock(txn->lockState()); if (replCoord->getMaintenanceMode()) { @@ -647,6 +648,7 @@ namespace { OpTime lastOpTime; { OperationContextImpl txn; // XXX? + ScopedTransaction transaction(&txn, MODE_IX); Lock::DBLock lk(txn.lockState(), "local", MODE_X); WriteUnitOfWork wunit(&txn); @@ -757,6 +759,7 @@ namespace { if (!st->syncApply(&txn, *it)) { bool status; { + ScopedTransaction transaction(&txn, MODE_X); Lock::GlobalWrite lk(txn.lockState()); status = st->shouldRetry(&txn, *it); } diff --git a/src/mongo/db/storage/mmap_v1/dur_recover.cpp b/src/mongo/db/storage/mmap_v1/dur_recover.cpp index 82642630bbd..75d8ec93556 100644 --- a/src/mongo/db/storage/mmap_v1/dur_recover.cpp +++ b/src/mongo/db/storage/mmap_v1/dur_recover.cpp @@ -602,6 +602,7 @@ namespace mongo { // we use a lock so that exitCleanly will wait for us // to finish (or at least to notice what is up and stop) OperationContextImpl txn; + ScopedTransaction transaction(&txn, MODE_X); Lock::GlobalWrite lk(txn.lockState()); // can't lock groupCommitMutex here as diff --git a/src/mongo/db/ttl.cpp b/src/mongo/db/ttl.cpp index 3a6258462e3..9e1413ce973 100644 --- a/src/mongo/db/ttl.cpp +++ b/src/mongo/db/ttl.cpp @@ -137,6 +137,7 @@ namespace mongo { vector<BSONObj>* indexes ) { invariant( indexes && indexes->empty() ); + ScopedTransaction transaction( txn, MODE_IS ); Lock::DBLock dbLock( txn->lockState(), dbName, MODE_IS ); Database* db = dbHolder().get( txn, dbName ); diff --git a/src/mongo/dbtests/basictests.cpp b/src/mongo/dbtests/basictests.cpp index 35cafb2fc9b..a6883bc68df 100644 --- a/src/mongo/dbtests/basictests.cpp +++ b/src/mongo/dbtests/basictests.cpp @@ -353,6 +353,7 @@ namespace BasicTests { public: void run() { OperationContextImpl txn; + ScopedTransaction transaction(&txn, MODE_X); Lock::GlobalWrite lk(txn.lockState()); Database db("dbtests_basictests_ownsns", NULL ); diff --git a/src/mongo/dbtests/dbhelper_tests.cpp b/src/mongo/dbtests/dbhelper_tests.cpp index 95ce55b4132..d84990e80fe 100644 --- a/src/mongo/dbtests/dbhelper_tests.cpp +++ b/src/mongo/dbtests/dbhelper_tests.cpp @@ -63,6 +63,7 @@ namespace mongo { { // Remove _id range [_min, _max). + ScopedTransaction transaction(&txn, MODE_IX); Lock::DBLock lk(txn.lockState(), nsToDatabaseSubstring(ns), MODE_X); Client::Context ctx(&txn, ns ); diff --git a/src/mongo/dbtests/indexcatalogtests.cpp b/src/mongo/dbtests/indexcatalogtests.cpp index c9903f6d4a2..a9819ba10b3 100644 --- a/src/mongo/dbtests/indexcatalogtests.cpp +++ b/src/mongo/dbtests/indexcatalogtests.cpp @@ -33,6 +33,7 @@ namespace IndexCatalogTests { public: IndexIteratorTests() { OperationContextImpl txn; + ScopedTransaction transaction(&txn, MODE_IX); Lock::DBLock lk(txn.lockState(), nsToDatabaseSubstring(_ns), MODE_X); Client::Context ctx(&txn, _ns); WriteUnitOfWork wuow(&txn); @@ -45,6 +46,7 @@ namespace IndexCatalogTests { ~IndexIteratorTests() { OperationContextImpl txn; + ScopedTransaction transaction(&txn, MODE_IX); Lock::DBLock lk(txn.lockState(), nsToDatabaseSubstring(_ns), MODE_X); Client::Context ctx(&txn, _ns); WriteUnitOfWork wuow(&txn); diff --git a/src/mongo/dbtests/namespacetests.cpp b/src/mongo/dbtests/namespacetests.cpp index 4914dbc325e..762b14d8e69 100644 --- a/src/mongo/dbtests/namespacetests.cpp +++ b/src/mongo/dbtests/namespacetests.cpp @@ -526,6 +526,7 @@ namespace NamespaceTests { OperationContextImpl txn; + ScopedTransaction transaction(&txn, MODE_IX); Lock::DBLock lk(txn.lockState(), dbName, MODE_X); bool justCreated; @@ -569,6 +570,7 @@ namespace NamespaceTests { OperationContextImpl txn; + ScopedTransaction transaction(&txn, MODE_IX); Lock::DBLock lk(txn.lockState(), dbName, MODE_X); bool justCreated; diff --git a/src/mongo/dbtests/query_stage_fetch.cpp b/src/mongo/dbtests/query_stage_fetch.cpp index b1f6084e1f5..c126f3e0d7f 100644 --- a/src/mongo/dbtests/query_stage_fetch.cpp +++ b/src/mongo/dbtests/query_stage_fetch.cpp @@ -147,6 +147,7 @@ namespace QueryStageFetch { class FetchStageFilter : public QueryStageFetchBase { public: void run() { + ScopedTransaction transaction(&_txn, MODE_IX); Lock::DBLock lk(_txn.lockState(), nsToDatabaseSubstring(ns()), MODE_X); Client::Context ctx(&_txn, ns()); Database* db = ctx.db(); diff --git a/src/mongo/dbtests/querytests.cpp b/src/mongo/dbtests/querytests.cpp index c9cf3886711..43e882e8250 100644 --- a/src/mongo/dbtests/querytests.cpp +++ b/src/mongo/dbtests/querytests.cpp @@ -161,6 +161,7 @@ namespace QueryTests { void run() { // We don't normally allow empty objects in the database, but test that we can find // an empty object (one might be allowed inside a reserved namespace at some point). + ScopedTransaction transaction(&_txn, MODE_X); Lock::GlobalWrite lk(_txn.lockState()); Client::Context ctx(&_txn, "unittests.querytests" ); @@ -632,6 +633,7 @@ namespace QueryTests { } void run() { const char *ns = "unittests.querytests.OplogReplaySlaveReadTill"; + ScopedTransaction transaction(&_txn, MODE_IX); Lock::DBLock lk(_txn.lockState(), "unittests", MODE_X); Client::Context ctx(&_txn, ns ); @@ -1071,6 +1073,7 @@ namespace QueryTests { class DirectLocking : public ClientBase { public: void run() { + ScopedTransaction transaction(&_txn, MODE_X); Lock::GlobalWrite lk(_txn.lockState()); Client::Context ctx(&_txn, "unittests.DirectLocking"); _client.remove( "a.b", BSONObj() ); diff --git a/src/mongo/dbtests/repltests.cpp b/src/mongo/dbtests/repltests.cpp index 25e677ee3bd..f8ebd0d45bd 100644 --- a/src/mongo/dbtests/repltests.cpp +++ b/src/mongo/dbtests/repltests.cpp @@ -131,6 +131,7 @@ namespace ReplTests { return _client.findOne( cllNS(), BSONObj() ); } int count() const { + ScopedTransaction transaction(&_txn, MODE_X); Lock::GlobalWrite lk(_txn.lockState()); Client::Context ctx(&_txn, ns() ); Database* db = ctx.db(); @@ -151,6 +152,7 @@ namespace ReplTests { } int opCount() { OperationContextImpl txn; + ScopedTransaction transaction(&txn, MODE_X); Lock::GlobalWrite lk(txn.lockState()); Client::Context ctx(&txn, cllNS() ); @@ -171,6 +173,7 @@ namespace ReplTests { return count; } void applyAllOperations() { + ScopedTransaction transaction(&_txn, MODE_X); Lock::GlobalWrite lk(_txn.lockState()); vector< BSONObj > ops; { @@ -202,6 +205,7 @@ namespace ReplTests { } } void printAll( const char *ns ) { + ScopedTransaction transaction(&_txn, MODE_X); Lock::GlobalWrite lk(_txn.lockState()); Client::Context ctx(&_txn, ns ); @@ -223,6 +227,7 @@ namespace ReplTests { } // These deletes don't get logged. void deleteAll( const char *ns ) const { + ScopedTransaction transaction(&_txn, MODE_X); Lock::GlobalWrite lk(_txn.lockState()); Client::Context ctx(&_txn, ns ); WriteUnitOfWork wunit(&_txn); @@ -244,6 +249,7 @@ namespace ReplTests { wunit.commit(); } void insert( const BSONObj &o ) const { + ScopedTransaction transaction(&_txn, MODE_X); Lock::GlobalWrite lk(_txn.lockState()); Client::Context ctx(&_txn, ns() ); WriteUnitOfWork wunit(&_txn); @@ -1409,6 +1415,7 @@ namespace ReplTests { bool threw = false; BSONObj o = BSON("ns" << ns() << "o" << BSON("foo" << "bar") << "o2" << BSON("_id" << "in oplog" << "foo" << "bar")); + ScopedTransaction transaction(&_txn, MODE_X); Lock::GlobalWrite lk(_txn.lockState()); // this should fail because we can't connect diff --git a/src/mongo/dbtests/rollbacktests.cpp b/src/mongo/dbtests/rollbacktests.cpp index 793ad9389e8..684f824b4a1 100644 --- a/src/mongo/dbtests/rollbacktests.cpp +++ b/src/mongo/dbtests/rollbacktests.cpp @@ -46,6 +46,7 @@ namespace RollbackTests { namespace { void dropDatabase( OperationContext* txn, const NamespaceString& nss ) { + ScopedTransaction transaction(txn, MODE_X); Lock::GlobalWrite globalWriteLock( txn->lockState() ); Database* db = dbHolder().get( txn, nss.db() ); @@ -60,6 +61,7 @@ namespace { return std::find( names.begin(), names.end(), ns ) != names.end(); } void createCollection( OperationContext* txn, const NamespaceString& nss ) { + ScopedTransaction transaction( txn, MODE_IX ); Lock::DBLock dbXLock( txn->lockState(), nss.db(), MODE_X ); Client::Context ctx( txn, nss.ns() ); { @@ -155,6 +157,7 @@ namespace { NamespaceString nss( ns ); dropDatabase( &txn, nss ); + ScopedTransaction transaction(&txn, MODE_IX); Lock::DBLock dbXLock( txn.lockState(), nss.db(), MODE_X ); Client::Context ctx( &txn, ns ); { @@ -184,6 +187,7 @@ namespace { NamespaceString nss( ns ); dropDatabase( &txn, nss ); + ScopedTransaction transaction(&txn, MODE_IX); Lock::DBLock dbXLock( txn.lockState(), nss.db(), MODE_X ); Client::Context ctx( &txn, ns ); { @@ -225,6 +229,7 @@ namespace { dropDatabase( &txn, source ); dropDatabase( &txn, target ); + ScopedTransaction transaction(&txn, MODE_X); Lock::GlobalWrite globalWriteLock( txn.lockState() ); Client::Context ctx( &txn, source ); @@ -272,6 +277,7 @@ namespace { dropDatabase( &txn, source ); dropDatabase( &txn, target ); + ScopedTransaction transaction(&txn, MODE_X); Lock::GlobalWrite globalWriteLock( txn.lockState() ); Client::Context ctx( &txn, source ); @@ -332,6 +338,7 @@ namespace { OperationContextImpl txn; dropDatabase( &txn, nss ); + ScopedTransaction transaction(&txn, MODE_IX); Lock::DBLock dbXLock( txn.lockState(), nss.db(), MODE_X ); Client::Context ctx( &txn, nss ); @@ -382,6 +389,7 @@ namespace { OperationContextImpl txn; dropDatabase( &txn, nss ); + ScopedTransaction transaction(&txn, MODE_IX); Lock::DBLock dbXLock( txn.lockState(), nss.db(), MODE_X ); Client::Context ctx( &txn, nss ); @@ -416,6 +424,7 @@ namespace { OperationContextImpl txn; dropDatabase( &txn, nss ); + ScopedTransaction transaction(&txn, MODE_IX); Lock::DBLock dbXLock( txn.lockState(), nss.db(), MODE_X ); Client::Context ctx( &txn, nss ); @@ -467,6 +476,7 @@ namespace { dropDatabase( &txn, nss ); createCollection( &txn, nss ); + ScopedTransaction transaction(&txn, MODE_IX); Lock::DBLock dbIXLock( txn.lockState(), nss.db(), MODE_IX ); Lock::CollectionLock collXLock( txn.lockState(), ns, MODE_X ); @@ -509,6 +519,7 @@ namespace { dropDatabase( &txn, nss ); createCollection( &txn, nss ); + ScopedTransaction transaction(&txn, MODE_IX); Lock::DBLock dbIXLock( txn.lockState(), nss.db(), MODE_IX ); Lock::CollectionLock collXLock( txn.lockState(), ns, MODE_X ); @@ -563,6 +574,7 @@ namespace { dropDatabase( &txn, nss ); createCollection( &txn, nss ); + ScopedTransaction transaction(&txn, MODE_IX); Lock::DBLock dbIXLock( txn.lockState(), nss.db(), MODE_IX ); Lock::CollectionLock collXLock( txn.lockState(), ns, MODE_X ); @@ -607,6 +619,7 @@ namespace { dropDatabase( &txn, nss ); createCollection( &txn, nss ); + ScopedTransaction transaction(&txn, MODE_IX); Lock::DBLock dbIXLock( txn.lockState(), nss.db(), MODE_IX ); Lock::CollectionLock collXLock( txn.lockState(), ns, MODE_X ); @@ -669,6 +682,7 @@ namespace { OperationContextImpl txn; NamespaceString nss( ns ); dropDatabase( &txn, nss ); + ScopedTransaction transaction(&txn, MODE_IX); Lock::DBLock dbXLock( txn.lockState(), nss.db(), MODE_X ); Client::Context ctx( &txn, nss.ns() ); string idxNameA = "indexA"; diff --git a/src/mongo/s/d_merge.cpp b/src/mongo/s/d_merge.cpp index e1cc54b6cea..87682902f8e 100644 --- a/src/mongo/s/d_merge.cpp +++ b/src/mongo/s/d_merge.cpp @@ -295,6 +295,7 @@ namespace mongo { // { + ScopedTransaction transaction(txn, MODE_IX); Lock::DBLock writeLk(txn->lockState(), nss.db(), MODE_IX); Lock::CollectionLock collLock(txn->lockState(), nss.ns(), MODE_X); shardingState.mergeChunks(txn, nss.ns(), minKey, maxKey, mergeVersion); diff --git a/src/mongo/s/d_migrate.cpp b/src/mongo/s/d_migrate.cpp index 528f57764d8..d76a32997cd 100644 --- a/src/mongo/s/d_migrate.cpp +++ b/src/mongo/s/d_migrate.cpp @@ -298,6 +298,7 @@ namespace mongo { // TODO: Change this. This is a bad hack for protecting some of the data structures // below that were not properly synchronized with the intended latches in some // usages. + ScopedTransaction transaction(txn, MODE_IX); Lock::DBLock dbLock(txn->lockState(), nsToDatabaseSubstring(_ns), MODE_IX); Lock::CollectionLock collLock(txn->lockState(), _ns, MODE_X); log() << "MigrateFromStatus::done coll lock for " << _ns << " acquired" << endl; @@ -1312,6 +1313,7 @@ namespace mongo { myVersion.incMajor(); { + ScopedTransaction transaction(txn, MODE_IX); Lock::DBLock lk(txn->lockState(), nsToDatabaseSubstring(ns), MODE_IX); Lock::CollectionLock collLock(txn->lockState(), ns, MODE_X); verify( myVersion > shardingState.getVersion( ns ) ); @@ -1348,6 +1350,7 @@ namespace mongo { log() << "moveChunk migrate commit not accepted by TO-shard: " << res << " resetting shard version to: " << origShardVersion << migrateLog; { + ScopedTransaction transaction(txn, MODE_IX); Lock::DBLock dbLock(txn->lockState(), nsToDatabaseSubstring(ns), MODE_IX); Lock::CollectionLock collLock(txn->lockState(), ns, MODE_X); @@ -1522,6 +1525,7 @@ namespace mongo { << "failed migration" << endl; { + ScopedTransaction transaction(txn, MODE_IX); Lock::DBLock dbLock(txn->lockState(), nsToDatabaseSubstring(ns), MODE_IX); Lock::CollectionLock collLock(txn->lockState(), ns, MODE_X); @@ -1730,6 +1734,7 @@ namespace mongo { if ( getState() != DONE ) { // Unprotect the range if needed/possible on unsuccessful TO migration + ScopedTransaction transaction(txn, MODE_IX); Lock::DBLock dbLock(txn->lockState(), nsToDatabaseSubstring(ns), MODE_IX); Lock::CollectionLock collLock(txn->lockState(), ns, MODE_X); @@ -1791,6 +1796,7 @@ namespace mongo { indexSpecs.insert(indexSpecs.begin(), indexes.begin(), indexes.end()); } + ScopedTransaction transaction(txn, MODE_IX); Lock::DBLock lk(txn->lockState(), nsToDatabaseSubstring(ns), MODE_X); Client::Context ctx(txn, ns); Database* db = ctx.db(); @@ -1876,6 +1882,7 @@ namespace mongo { { // Protect the range by noting that we're now starting a migration to it + ScopedTransaction transaction(txn, MODE_IX); Lock::DBLock dbLock(txn->lockState(), nsToDatabaseSubstring(ns), MODE_IX); Lock::CollectionLock collLock(txn->lockState(), ns, MODE_X); @@ -2159,6 +2166,7 @@ namespace mongo { bool didAnything = false; if ( xfer["deleted"].isABSONObj() ) { + ScopedTransaction transaction(txn, MODE_IX); Lock::DBLock dlk(txn->lockState(), nsToDatabaseSubstring(ns), MODE_IX); Helpers::RemoveSaver rs( "moveChunk" , ns , "removedDuring" ); @@ -2290,6 +2298,7 @@ namespace mongo { { // Get global lock to wait for write to be commited to journal. + ScopedTransaction transaction(txn, MODE_S); Lock::GlobalRead lk(txn->lockState()); // if durability is on, force a write to journal diff --git a/src/mongo/s/d_split.cpp b/src/mongo/s/d_split.cpp index 428f94eff19..fc897132594 100644 --- a/src/mongo/s/d_split.cpp +++ b/src/mongo/s/d_split.cpp @@ -793,6 +793,7 @@ namespace mongo { // { + ScopedTransaction transaction(txn, MODE_IX); Lock::DBLock writeLk(txn->lockState(), nsToDatabaseSubstring(ns), MODE_IX); Lock::CollectionLock collLock(txn->lockState(), ns, MODE_X); diff --git a/src/mongo/s/d_state.cpp b/src/mongo/s/d_state.cpp index 0fe9b482132..b6e3c55663c 100644 --- a/src/mongo/s/d_state.cpp +++ b/src/mongo/s/d_state.cpp @@ -595,6 +595,7 @@ namespace mongo { { // Exclusive collection lock needed since we're now potentially changing the metadata, // and don't want reads/writes to be ongoing. + ScopedTransaction transaction(txn, MODE_IX); Lock::DBLock dbLock(txn->lockState(), nsToDatabaseSubstring(ns), MODE_IX); Lock::CollectionLock collLock(txn->lockState(), ns, MODE_X); @@ -977,6 +978,7 @@ namespace mongo { return true; } + ScopedTransaction transaction(txn, MODE_X); Lock::GlobalWrite lk(txn->lockState()); return checkConfigOrInit(txn, configdb, authoritative, errmsg, result, true); } @@ -1265,6 +1267,7 @@ namespace mongo { } bool run(OperationContext* txn, const string& dbname, BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool) { + ScopedTransaction transaction(txn, MODE_IX); Lock::DBLock dbXLock(txn->lockState(), dbname, MODE_X); Client::Context ctx(txn, dbname); |