diff options
author | Charlie Swanson <charlie.swanson@mongodb.com> | 2017-03-02 13:54:24 -0500 |
---|---|---|
committer | Charlie Swanson <charlie.swanson@mongodb.com> | 2017-03-15 11:03:44 -0400 |
commit | f05b9437fbdc53deecf55ed3c20e36af3d733953 (patch) | |
tree | 8b66acc133f83f27ef00f31600538f225ec2746a /src/mongo | |
parent | a1f15dfd788a78da77bda6675132d4144691fce1 (diff) | |
download | mongo-f05b9437fbdc53deecf55ed3c20e36af3d733953.tar.gz |
SERVER-22541 Refactor RAII locking helpers.
Removes the class 'ScopedTransaction' and moves the responsibility of
abandoning the snapshot onto the GlobalLock class. Also renames the
AutoGetCollectionForRead class to AutoGetCollectionForReadCommand, and
adds a new AutoGetCollectionForRead class. Unlike
AutoGetCollectionForReadCommand, this new class will not update the
namespace on the CurrentOp object, nor will it add an entry to Top.
Diffstat (limited to 'src/mongo')
128 files changed, 834 insertions, 919 deletions
diff --git a/src/mongo/db/auth/auth_index_d.cpp b/src/mongo/db/auth/auth_index_d.cpp index 0fe036e03d5..c7ebb0a7054 100644 --- a/src/mongo/db/auth/auth_index_d.cpp +++ b/src/mongo/db/auth/auth_index_d.cpp @@ -85,7 +85,6 @@ Status verifySystemIndexes(OperationContext* opCtx) { const NamespaceString systemUsers = AuthorizationManager::usersCollectionNamespace; // Make sure the old unique index from v2.4 on system.users doesn't exist. - ScopedTransaction scopedXact(opCtx, MODE_IX); AutoGetDb autoDb(opCtx, systemUsers.db(), MODE_X); if (!autoDb.getDb()) { return Status::OK(); diff --git a/src/mongo/db/auth/authz_manager_external_state_d.cpp b/src/mongo/db/auth/authz_manager_external_state_d.cpp index 6d497417ac0..0e259a9d11c 100644 --- a/src/mongo/db/auth/authz_manager_external_state_d.cpp +++ b/src/mongo/db/auth/authz_manager_external_state_d.cpp @@ -78,7 +78,7 @@ Status AuthzManagerExternalStateMongod::findOne(OperationContext* opCtx, const NamespaceString& collectionName, const BSONObj& query, BSONObj* result) { - AutoGetCollectionForRead ctx(opCtx, collectionName); + AutoGetCollectionForReadCommand ctx(opCtx, collectionName); BSONObj found; if (Helpers::findOne(opCtx, ctx.getCollection(), query, found)) { diff --git a/src/mongo/db/catalog/apply_ops.cpp b/src/mongo/db/catalog/apply_ops.cpp index 5e4e00aefb0..ca20b2b848a 100644 --- a/src/mongo/db/catalog/apply_ops.cpp +++ b/src/mongo/db/catalog/apply_ops.cpp @@ -156,7 +156,7 @@ Status _applyOps(OperationContext* opCtx, // // We do not have a wrapping WriteUnitOfWork so it is possible for a journal // commit to happen with a subset of ops applied. - Lock::GlobalWrite globalWriteLockDisallowTempRelease(opCtx->lockState()); + Lock::GlobalWrite globalWriteLockDisallowTempRelease(opCtx); // Ensures that yielding will not happen (see the comment above). DEV { @@ -309,8 +309,7 @@ Status applyOps(OperationContext* opCtx, const std::string& dbName, const BSONObj& applyOpCmd, BSONObjBuilder* result) { - ScopedTransaction scopedXact(opCtx, MODE_X); - Lock::GlobalWrite globalWriteLock(opCtx->lockState()); + Lock::GlobalWrite globalWriteLock(opCtx); bool userInitiatedWritesAndNotPrimary = opCtx->writesAreReplicated() && !repl::getGlobalReplicationCoordinator()->canAcceptWritesForDatabase(opCtx, dbName); diff --git a/src/mongo/db/catalog/capped_utils.cpp b/src/mongo/db/catalog/capped_utils.cpp index d05c1ef2f92..5d4ac36c168 100644 --- a/src/mongo/db/catalog/capped_utils.cpp +++ b/src/mongo/db/catalog/capped_utils.cpp @@ -53,7 +53,6 @@ namespace mongo { Status emptyCapped(OperationContext* opCtx, const NamespaceString& collectionName) { - ScopedTransaction scopedXact(opCtx, MODE_IX); AutoGetDb autoDb(opCtx, collectionName.db(), MODE_X); bool userInitiatedWritesAndNotPrimary = opCtx->writesAreReplicated() && @@ -242,7 +241,6 @@ Status convertToCapped(OperationContext* opCtx, StringData dbname = collectionName.db(); StringData shortSource = collectionName.coll(); - ScopedTransaction transaction(opCtx, MODE_IX); AutoGetDb autoDb(opCtx, collectionName.db(), MODE_X); bool userInitiatedWritesAndNotPrimary = opCtx->writesAreReplicated() && diff --git a/src/mongo/db/catalog/coll_mod.cpp b/src/mongo/db/catalog/coll_mod.cpp index fdbfd26677b..a2df7e2c791 100644 --- a/src/mongo/db/catalog/coll_mod.cpp +++ b/src/mongo/db/catalog/coll_mod.cpp @@ -220,7 +220,6 @@ Status collMod(OperationContext* opCtx, const BSONObj& cmdObj, BSONObjBuilder* result) { StringData dbName = nss.db(); - ScopedTransaction transaction(opCtx, MODE_IX); AutoGetDb autoDb(opCtx, dbName, MODE_X); Database* const db = autoDb.getDb(); Collection* coll = db ? db->getCollection(nss) : nullptr; diff --git a/src/mongo/db/catalog/collection.cpp b/src/mongo/db/catalog/collection.cpp index 8ef63ac7ad7..a86944badf3 100644 --- a/src/mongo/db/catalog/collection.cpp +++ b/src/mongo/db/catalog/collection.cpp @@ -48,6 +48,7 @@ #include "mongo/db/catalog/index_create.h" #include "mongo/db/clientcursor.h" #include "mongo/db/commands/server_status_metric.h" +#include "mongo/db/concurrency/d_concurrency.h" #include "mongo/db/curop.h" #include "mongo/db/index/index_access_method.h" #include "mongo/db/keypattern.h" diff --git a/src/mongo/db/catalog/create_collection.cpp b/src/mongo/db/catalog/create_collection.cpp index ec963bdf0a8..f8a39c20350 100644 --- a/src/mongo/db/catalog/create_collection.cpp +++ b/src/mongo/db/catalog/create_collection.cpp @@ -73,8 +73,7 @@ Status createCollection(OperationContext* opCtx, options.hasField("$nExtents")); MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { - ScopedTransaction transaction(opCtx, MODE_IX); - Lock::DBLock dbXLock(opCtx->lockState(), dbName, MODE_X); + Lock::DBLock dbXLock(opCtx, dbName, MODE_X); OldClientContext ctx(opCtx, nss.ns()); if (opCtx->writesAreReplicated() && !repl::getGlobalReplicationCoordinator()->canAcceptWritesFor(opCtx, nss)) { diff --git a/src/mongo/db/catalog/cursor_manager.cpp b/src/mongo/db/catalog/cursor_manager.cpp index 2c9f9b2d9d8..b2079e9e03e 100644 --- a/src/mongo/db/catalog/cursor_manager.cpp +++ b/src/mongo/db/catalog/cursor_manager.cpp @@ -226,7 +226,7 @@ bool GlobalCursorIdCache::eraseCursor(OperationContext* opCtx, CursorId id, bool // If not, then the cursor must be owned by a collection. Erase the cursor under the // collection lock (to prevent the collection from going away during the erase). - AutoGetCollectionForRead ctx(opCtx, nss); + AutoGetCollectionForReadCommand ctx(opCtx, nss); Collection* collection = ctx.getCollection(); if (!collection) { if (checkAuth) @@ -266,7 +266,7 @@ std::size_t GlobalCursorIdCache::timeoutCursors(OperationContext* opCtx, int mil // For each collection, time out its cursors under the collection lock (to prevent the // collection from going away during the erase). for (unsigned i = 0; i < todo.size(); i++) { - AutoGetCollectionOrViewForRead ctx(opCtx, NamespaceString(todo[i])); + AutoGetCollectionOrViewForReadCommand ctx(opCtx, NamespaceString(todo[i])); if (!ctx.getDb()) { continue; } diff --git a/src/mongo/db/catalog/database.cpp b/src/mongo/db/catalog/database.cpp index 1f68f3256ee..a5287efea20 100644 --- a/src/mongo/db/catalog/database.cpp +++ b/src/mongo/db/catalog/database.cpp @@ -47,6 +47,7 @@ #include "mongo/db/catalog/database_catalog_entry.h" #include "mongo/db/catalog/database_holder.h" #include "mongo/db/clientcursor.h" +#include "mongo/db/concurrency/d_concurrency.h" #include "mongo/db/concurrency/write_conflict_exception.h" #include "mongo/db/dbhelpers.h" #include "mongo/db/index/index_access_method.h" @@ -581,8 +582,7 @@ const DatabaseCatalogEntry* Database::getDatabaseCatalogEntry() const { } void dropAllDatabasesExceptLocal(OperationContext* opCtx) { - ScopedTransaction transaction(opCtx, MODE_X); - Lock::GlobalWrite lk(opCtx->lockState()); + Lock::GlobalWrite lk(opCtx); vector<string> n; StorageEngine* storageEngine = getGlobalServiceContext()->getGlobalStorageEngine(); diff --git a/src/mongo/db/catalog/drop_collection.cpp b/src/mongo/db/catalog/drop_collection.cpp index 3699f1a76ad..70ced6c5e05 100644 --- a/src/mongo/db/catalog/drop_collection.cpp +++ b/src/mongo/db/catalog/drop_collection.cpp @@ -59,8 +59,6 @@ Status dropCollection(OperationContext* opCtx, const std::string dbname = collectionName.db().toString(); MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { - ScopedTransaction transaction(opCtx, MODE_IX); - AutoGetDb autoDb(opCtx, dbname, MODE_X); Database* const db = autoDb.getDb(); Collection* coll = db ? db->getCollection(collectionName) : nullptr; diff --git a/src/mongo/db/catalog/drop_database.cpp b/src/mongo/db/catalog/drop_database.cpp index 4c20d20ffa9..1819f05b72d 100644 --- a/src/mongo/db/catalog/drop_database.cpp +++ b/src/mongo/db/catalog/drop_database.cpp @@ -60,8 +60,7 @@ Status dropDatabase(OperationContext* opCtx, const std::string& dbName) { } MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { - ScopedTransaction transaction(opCtx, MODE_X); - Lock::GlobalWrite lk(opCtx->lockState()); + Lock::GlobalWrite lk(opCtx); AutoGetDb autoDB(opCtx, dbName, MODE_X); Database* const db = autoDB.getDb(); if (!db) { diff --git a/src/mongo/db/catalog/drop_indexes.cpp b/src/mongo/db/catalog/drop_indexes.cpp index 7f3ee19710b..152c2d1243c 100644 --- a/src/mongo/db/catalog/drop_indexes.cpp +++ b/src/mongo/db/catalog/drop_indexes.cpp @@ -160,7 +160,6 @@ Status dropIndexes(OperationContext* opCtx, const BSONObj& cmdObj, BSONObjBuilder* result) { MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { - ScopedTransaction transaction(opCtx, MODE_IX); AutoGetDb autoDb(opCtx, nss.db(), MODE_X); bool userInitiatedWritesAndNotPrimary = opCtx->writesAreReplicated() && diff --git a/src/mongo/db/catalog/index_catalog_entry.cpp b/src/mongo/db/catalog/index_catalog_entry.cpp index 9c540e4a102..ae22ff4d633 100644 --- a/src/mongo/db/catalog/index_catalog_entry.cpp +++ b/src/mongo/db/catalog/index_catalog_entry.cpp @@ -38,6 +38,7 @@ #include "mongo/db/catalog/collection_catalog_entry.h" #include "mongo/db/catalog/head_manager.h" +#include "mongo/db/concurrency/d_concurrency.h" #include "mongo/db/concurrency/write_conflict_exception.h" #include "mongo/db/index/index_access_method.h" #include "mongo/db/index/index_descriptor.h" diff --git a/src/mongo/db/catalog/rename_collection.cpp b/src/mongo/db/catalog/rename_collection.cpp index 86676854c4e..b0c5e6b3aa0 100644 --- a/src/mongo/db/catalog/rename_collection.cpp +++ b/src/mongo/db/catalog/rename_collection.cpp @@ -68,8 +68,7 @@ Status renameCollection(OperationContext* opCtx, bool stayTemp) { DisableDocumentValidation validationDisabler(opCtx); - ScopedTransaction transaction(opCtx, MODE_X); - Lock::GlobalWrite globalWriteLock(opCtx->lockState()); + Lock::GlobalWrite globalWriteLock(opCtx); // We stay in source context the whole time. This is mostly to set the CurOp namespace. OldClientContext ctx(opCtx, source.ns()); diff --git a/src/mongo/db/cloner.cpp b/src/mongo/db/cloner.cpp index 20455ad7c22..9c3252b83d6 100644 --- a/src/mongo/db/cloner.cpp +++ b/src/mongo/db/cloner.cpp @@ -144,8 +144,7 @@ struct Cloner::Fun { invariant(from_collection.coll() != "system.indexes"); // XXX: can probably take dblock instead - unique_ptr<ScopedTransaction> scopedXact(new ScopedTransaction(opCtx, MODE_X)); - unique_ptr<Lock::GlobalWrite> globalWriteLock(new Lock::GlobalWrite(opCtx->lockState())); + unique_ptr<Lock::GlobalWrite> globalWriteLock(new Lock::GlobalWrite(opCtx)); uassert( ErrorCodes::NotMaster, str::stream() << "Not primary while cloning collection " << from_collection.ns() @@ -198,13 +197,11 @@ struct Cloner::Fun { } opCtx->checkForInterrupt(); - scopedXact.reset(); globalWriteLock.reset(); CurOp::get(opCtx)->yielded(); - scopedXact.reset(new ScopedTransaction(opCtx, MODE_X)); - globalWriteLock.reset(new Lock::GlobalWrite(opCtx->lockState())); + globalWriteLock.reset(new Lock::GlobalWrite(opCtx)); // Check if everything is still all right. if (opCtx->writesAreReplicated()) { @@ -479,8 +476,7 @@ bool Cloner::copyCollection(OperationContext* opCtx, auto sourceIndexes = _conn->getIndexSpecs(nss.ns(), QueryOption_SlaveOk); auto idIndexSpec = getIdIndexSpec(sourceIndexes); - ScopedTransaction transaction(opCtx, MODE_IX); - Lock::DBLock dbWrite(opCtx->lockState(), dbname, MODE_X); + Lock::DBLock dbWrite(opCtx, dbname, MODE_X); uassert(ErrorCodes::PrimarySteppedDown, str::stream() << "Not primary while copying collection " << ns << " (Cloner)", diff --git a/src/mongo/db/commands/clone.cpp b/src/mongo/db/commands/clone.cpp index 8548152087d..e5979d6d41b 100644 --- a/src/mongo/db/commands/clone.cpp +++ b/src/mongo/db/commands/clone.cpp @@ -35,6 +35,7 @@ #include "mongo/db/catalog/document_validation.h" #include "mongo/db/cloner.h" #include "mongo/db/commands.h" +#include "mongo/db/concurrency/d_concurrency.h" #include "mongo/db/jsobj.h" #include "mongo/s/grid.h" @@ -119,8 +120,7 @@ public: set<string> clonedColls; - ScopedTransaction transaction(opCtx, MODE_IX); - Lock::DBLock dbXLock(opCtx->lockState(), dbname, MODE_X); + Lock::DBLock dbXLock(opCtx, dbname, MODE_X); Cloner cloner; Status status = cloner.copyDb(opCtx, dbname, from, opts, &clonedColls); diff --git a/src/mongo/db/commands/collection_to_capped.cpp b/src/mongo/db/commands/collection_to_capped.cpp index 222e6d8887f..121d7d0a04a 100644 --- a/src/mongo/db/commands/collection_to_capped.cpp +++ b/src/mongo/db/commands/collection_to_capped.cpp @@ -118,7 +118,6 @@ public: return false; } - ScopedTransaction transaction(opCtx, MODE_IX); AutoGetDb autoDb(opCtx, dbname, MODE_X); NamespaceString nss(dbname, to); diff --git a/src/mongo/db/commands/compact.cpp b/src/mongo/db/commands/compact.cpp index e93b94a5892..c1b9a3d0a6c 100644 --- a/src/mongo/db/commands/compact.cpp +++ b/src/mongo/db/commands/compact.cpp @@ -144,7 +144,6 @@ public: if (cmdObj.hasElement("validate")) compactOptions.validateDocuments = cmdObj["validate"].trueValue(); - ScopedTransaction transaction(opCtx, MODE_IX); AutoGetDb autoDb(opCtx, db, MODE_X); Database* const collDB = autoDb.getDb(); diff --git a/src/mongo/db/commands/copydb.cpp b/src/mongo/db/commands/copydb.cpp index b13066949df..b665bcefb12 100644 --- a/src/mongo/db/commands/copydb.cpp +++ b/src/mongo/db/commands/copydb.cpp @@ -38,6 +38,7 @@ #include "mongo/db/commands.h" #include "mongo/db/commands/copydb.h" #include "mongo/db/commands/copydb_start_commands.h" +#include "mongo/db/concurrency/d_concurrency.h" #include "mongo/db/jsobj.h" #include "mongo/db/namespace_string.h" @@ -226,12 +227,10 @@ public: if (fromSelf) { // SERVER-4328 todo lock just the two db's not everything for the fromself case - ScopedTransaction transaction(opCtx, MODE_X); - Lock::GlobalWrite lk(opCtx->lockState()); + Lock::GlobalWrite lk(opCtx); uassertStatusOK(cloner.copyDb(opCtx, todb, fromhost, cloneOptions, NULL)); } else { - ScopedTransaction transaction(opCtx, MODE_IX); - Lock::DBLock lk(opCtx->lockState(), todb, MODE_X); + Lock::DBLock lk(opCtx, todb, MODE_X); uassertStatusOK(cloner.copyDb(opCtx, todb, fromhost, cloneOptions, NULL)); } diff --git a/src/mongo/db/commands/count_cmd.cpp b/src/mongo/db/commands/count_cmd.cpp index b8418b0bff3..e5c7827ae0e 100644 --- a/src/mongo/db/commands/count_cmd.cpp +++ b/src/mongo/db/commands/count_cmd.cpp @@ -122,7 +122,7 @@ public: } // Acquire the db read lock. - AutoGetCollectionOrViewForRead ctx(opCtx, request.getValue().getNs()); + AutoGetCollectionOrViewForReadCommand ctx(opCtx, request.getValue().getNs()); Collection* collection = ctx.getCollection(); if (ctx.getView()) { @@ -187,7 +187,7 @@ public: "http://dochub.mongodb.org/core/3.4-feature-compatibility.")); } - AutoGetCollectionOrViewForRead ctx(opCtx, request.getValue().getNs()); + AutoGetCollectionOrViewForReadCommand ctx(opCtx, request.getValue().getNs()); Collection* collection = ctx.getCollection(); if (ctx.getView()) { diff --git a/src/mongo/db/commands/cpuprofile.cpp b/src/mongo/db/commands/cpuprofile.cpp index 608a626aa92..00cddd59397 100644 --- a/src/mongo/db/commands/cpuprofile.cpp +++ b/src/mongo/db/commands/cpuprofile.cpp @@ -140,8 +140,7 @@ bool CpuProfilerStartCommand::run(OperationContext* opCtx, std::string& errmsg, BSONObjBuilder& result) { // The DB lock here is just so we have IX on the global lock in order to prevent shutdown - ScopedTransaction transaction(opCtx, MODE_IX); - Lock::DBLock dbXLock(opCtx->lockState(), db, MODE_X); + Lock::DBLock dbXLock(opCtx, db, MODE_X); OldClientContext ctx(opCtx, db, false /* no shard version checking */); std::string profileFilename = cmdObj[commandName]["profileFilename"].String(); @@ -159,8 +158,7 @@ bool CpuProfilerStopCommand::run(OperationContext* opCtx, std::string& errmsg, BSONObjBuilder& result) { // The DB lock here is just so we have IX on the global lock in order to prevent shutdown - ScopedTransaction transaction(opCtx, MODE_IX); - Lock::DBLock dbXLock(opCtx->lockState(), db, MODE_X); + Lock::DBLock dbXLock(opCtx, db, MODE_X); OldClientContext ctx(opCtx, db, false /* no shard version checking */); ::ProfilerStop(); diff --git a/src/mongo/db/commands/create_indexes.cpp b/src/mongo/db/commands/create_indexes.cpp index 26901b5043e..93833f09b8e 100644 --- a/src/mongo/db/commands/create_indexes.cpp +++ b/src/mongo/db/commands/create_indexes.cpp @@ -40,6 +40,7 @@ #include "mongo/db/catalog/index_key_validate.h" #include "mongo/db/client.h" #include "mongo/db/commands.h" +#include "mongo/db/concurrency/d_concurrency.h" #include "mongo/db/concurrency/write_conflict_exception.h" #include "mongo/db/curop.h" #include "mongo/db/index/index_descriptor.h" @@ -247,8 +248,7 @@ public: // now we know we have to create index(es) // Note: createIndexes command does not currently respect shard versioning. - ScopedTransaction transaction(opCtx, MODE_IX); - Lock::DBLock dbLock(opCtx->lockState(), ns.db(), MODE_X); + Lock::DBLock dbLock(opCtx, ns.db(), MODE_X); if (!repl::getGlobalReplicationCoordinator()->canAcceptWritesFor(opCtx, ns)) { return appendCommandStatus( result, diff --git a/src/mongo/db/commands/dbcommands.cpp b/src/mongo/db/commands/dbcommands.cpp index 0831a974ecc..10c75252cd2 100644 --- a/src/mongo/db/commands/dbcommands.cpp +++ b/src/mongo/db/commands/dbcommands.cpp @@ -293,8 +293,7 @@ public: } // Closing a database requires a global lock. - ScopedTransaction transaction(opCtx, MODE_X); - Lock::GlobalWrite lk(opCtx->lockState()); + Lock::GlobalWrite lk(opCtx); if (!dbHolder().get(opCtx, dbname)) { // If the name doesn't make an exact match, check for a case insensitive match. std::set<std::string> otherCasing = dbHolder().getNamesWithConflictingCasing(dbname); @@ -399,11 +398,9 @@ public: const bool readOnly = (profilingLevel < 0 || profilingLevel > 2); const LockMode dbMode = readOnly ? MODE_S : MODE_X; - const LockMode transactionMode = readOnly ? MODE_IS : MODE_IX; Status status = Status::OK(); - ScopedTransaction transaction(opCtx, transactionMode); AutoGetDb ctx(opCtx, dbname, dbMode); Database* db = ctx.getDb(); @@ -482,9 +479,7 @@ public: // 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(opCtx, MODE_IX); - Lock::DBLock dbXLock(opCtx->lockState(), dbname, MODE_X); + Lock::DBLock dbXLock(opCtx, dbname, MODE_X); // TODO (Kal): OldClientContext legacy, needs to be removed { @@ -773,7 +768,8 @@ public: // Check shard version at startup. // This will throw before we've done any work if shard version is outdated // We drop and re-acquire these locks every document because md5'ing is expensive - unique_ptr<AutoGetCollectionForRead> ctx(new AutoGetCollectionForRead(opCtx, nss)); + unique_ptr<AutoGetCollectionForReadCommand> ctx( + new AutoGetCollectionForReadCommand(opCtx, nss)); Collection* coll = ctx->getCollection(); auto statusWithPlanExecutor = getExecutor(opCtx, @@ -819,7 +815,7 @@ public: try { // RELOCKED - ctx.reset(new AutoGetCollectionForRead(opCtx, nss)); + ctx.reset(new AutoGetCollectionForReadCommand(opCtx, nss)); } catch (const SendStaleConfigException& ex) { LOG(1) << "chunk metadata changed during filemd5, will retarget and continue"; break; @@ -919,7 +915,7 @@ public: BSONObj keyPattern = jsobj.getObjectField("keyPattern"); bool estimate = jsobj["estimate"].trueValue(); - AutoGetCollectionForRead ctx(opCtx, NamespaceString(ns)); + AutoGetCollectionForReadCommand ctx(opCtx, NamespaceString(ns)); Collection* collection = ctx.getCollection(); long long numRecords = 0; @@ -1168,7 +1164,6 @@ public: // We lock the entire database in S-mode in order to ensure that the contents will not // change for the stats snapshot. This might be unnecessary and if it becomes a // performance issue, we can take IS lock and then lock collection-by-collection. - ScopedTransaction scopedXact(opCtx, MODE_IS); AutoGetDb autoDb(opCtx, ns, MODE_S); result.append("db", ns); diff --git a/src/mongo/db/commands/dbhash.cpp b/src/mongo/db/commands/dbhash.cpp index 0da2752a28d..d1761d1f103 100644 --- a/src/mongo/db/commands/dbhash.cpp +++ b/src/mongo/db/commands/dbhash.cpp @@ -109,7 +109,6 @@ public: // We lock the entire database in S-mode in order to ensure that the contents will not // change for the snapshot. - ScopedTransaction scopedXact(opCtx, MODE_IS); AutoGetDb autoDb(opCtx, ns, MODE_S); Database* db = autoDb.getDb(); if (db) { diff --git a/src/mongo/db/commands/distinct.cpp b/src/mongo/db/commands/distinct.cpp index cec31d5f9a5..fee7ac17c58 100644 --- a/src/mongo/db/commands/distinct.cpp +++ b/src/mongo/db/commands/distinct.cpp @@ -134,7 +134,7 @@ public: "http://dochub.mongodb.org/core/3.4-feature-compatibility."); } - AutoGetCollectionOrViewForRead ctx(opCtx, nss); + AutoGetCollectionOrViewForReadCommand ctx(opCtx, nss); Collection* collection = ctx.getCollection(); if (ctx.getView()) { @@ -189,7 +189,7 @@ public: "http://dochub.mongodb.org/core/3.4-feature-compatibility.")); } - AutoGetCollectionOrViewForRead ctx(opCtx, nss); + AutoGetCollectionOrViewForReadCommand ctx(opCtx, nss); Collection* collection = ctx.getCollection(); if (ctx.getView()) { diff --git a/src/mongo/db/commands/drop_indexes.cpp b/src/mongo/db/commands/drop_indexes.cpp index 86082761cce..0857c0b025b 100644 --- a/src/mongo/db/commands/drop_indexes.cpp +++ b/src/mongo/db/commands/drop_indexes.cpp @@ -128,8 +128,7 @@ public: LOG(0) << "CMD: reIndex " << toReIndexNs; - ScopedTransaction transaction(opCtx, MODE_IX); - Lock::DBLock dbXLock(opCtx->lockState(), dbname, MODE_X); + Lock::DBLock dbXLock(opCtx, dbname, MODE_X); OldClientContext ctx(opCtx, toReIndexNs.ns()); Collection* collection = ctx.db()->getCollection(toReIndexNs.ns()); diff --git a/src/mongo/db/commands/eval.cpp b/src/mongo/db/commands/eval.cpp index 20945eb4828..cec1369e4ad 100644 --- a/src/mongo/db/commands/eval.cpp +++ b/src/mongo/db/commands/eval.cpp @@ -181,8 +181,7 @@ public: return dbEval(opCtx, dbname, cmdObj, result, errmsg); } - ScopedTransaction transaction(opCtx, MODE_X); - Lock::GlobalWrite lk(opCtx->lockState()); + Lock::GlobalWrite lk(opCtx); OldClientContext ctx(opCtx, dbname, false /* no shard version checking */); diff --git a/src/mongo/db/commands/feature_compatibility_version.cpp b/src/mongo/db/commands/feature_compatibility_version.cpp index d97f5cf0c54..e636c8f9987 100644 --- a/src/mongo/db/commands/feature_compatibility_version.cpp +++ b/src/mongo/db/commands/feature_compatibility_version.cpp @@ -211,7 +211,6 @@ void FeatureCompatibilityVersion::set(OperationContext* opCtx, StringData versio std::vector<BSONObj> indexSpecs{k32IncompatibleIndexSpec}; { - ScopedTransaction transaction(opCtx, MODE_IX); AutoGetOrCreateDb autoDB(opCtx, nss.db(), MODE_X); uassert(ErrorCodes::NotMaster, @@ -303,7 +302,6 @@ void FeatureCompatibilityVersion::setIfCleanStartup(OperationContext* opCtx, std::vector<BSONObj> indexSpecs{k32IncompatibleIndexSpec}; { - ScopedTransaction transaction(opCtx, MODE_IX); AutoGetOrCreateDb autoDB(opCtx, nss.db(), MODE_X); IndexBuilder builder(k32IncompatibleIndexSpec, false); diff --git a/src/mongo/db/commands/find_cmd.cpp b/src/mongo/db/commands/find_cmd.cpp index 5bb043d438a..d43e991950c 100644 --- a/src/mongo/db/commands/find_cmd.cpp +++ b/src/mongo/db/commands/find_cmd.cpp @@ -169,7 +169,7 @@ public: // Acquire locks. If the namespace is a view, we release our locks and convert the query // request into an aggregation command. - AutoGetCollectionOrViewForRead ctx(opCtx, nss); + AutoGetCollectionOrViewForReadCommand ctx(opCtx, nss); if (ctx.getView()) { // Relinquish locks. The aggregation command will re-acquire them. ctx.releaseLocksForView(); @@ -297,7 +297,7 @@ public: // Acquire locks. If the query is on a view, we release our locks and convert the query // request into an aggregation command. - AutoGetCollectionOrViewForRead ctx(opCtx, nss); + AutoGetCollectionOrViewForReadCommand ctx(opCtx, nss); Collection* collection = ctx.getCollection(); if (ctx.getView()) { // Relinquish locks. The aggregation command will re-acquire them. diff --git a/src/mongo/db/commands/fsync.cpp b/src/mongo/db/commands/fsync.cpp index dfe417b6c06..1cae66a6b5f 100644 --- a/src/mongo/db/commands/fsync.cpp +++ b/src/mongo/db/commands/fsync.cpp @@ -138,8 +138,7 @@ public: // the simple fsync command case if (sync) { // can this be GlobalRead? and if it can, it should be nongreedy. - ScopedTransaction transaction(opCtx, MODE_X); - Lock::GlobalWrite w(opCtx->lockState()); + Lock::GlobalWrite w(opCtx); // TODO SERVER-26822: Replace MMAPv1 specific calls with ones that are storage // engine agnostic. getDur().commitNow(opCtx); @@ -148,7 +147,7 @@ public: } // Take a global IS lock to ensure the storage engine is not shutdown - Lock::GlobalLock global(opCtx->lockState(), MODE_IS, UINT_MAX); + Lock::GlobalLock global(opCtx, MODE_IS, UINT_MAX); StorageEngine* storageEngine = getGlobalServiceContext()->getGlobalStorageEngine(); result.append("numFiles", storageEngine->flushAllFiles(opCtx, sync)); return true; @@ -345,8 +344,7 @@ void FSyncLockThread::run() { try { const ServiceContext::UniqueOperationContext opCtxPtr = cc().makeOperationContext(); OperationContext& opCtx = *opCtxPtr; - ScopedTransaction transaction(&opCtx, MODE_X); - Lock::GlobalWrite global(opCtx.lockState()); // No WriteUnitOfWork needed + Lock::GlobalWrite global(&opCtx); // No WriteUnitOfWork needed try { // TODO SERVER-26822: Replace MMAPv1 specific calls with ones that are storage engine diff --git a/src/mongo/db/commands/geo_near_cmd.cpp b/src/mongo/db/commands/geo_near_cmd.cpp index 3c26005121b..8345c82c9fb 100644 --- a/src/mongo/db/commands/geo_near_cmd.cpp +++ b/src/mongo/db/commands/geo_near_cmd.cpp @@ -111,7 +111,7 @@ public: } const NamespaceString nss(parseNsCollectionRequired(dbname, cmdObj)); - AutoGetCollectionForRead ctx(opCtx, nss); + AutoGetCollectionForReadCommand ctx(opCtx, nss); Collection* collection = ctx.getCollection(); if (!collection) { diff --git a/src/mongo/db/commands/getmore_cmd.cpp b/src/mongo/db/commands/getmore_cmd.cpp index ed4b43a81a2..78c7d822404 100644 --- a/src/mongo/db/commands/getmore_cmd.cpp +++ b/src/mongo/db/commands/getmore_cmd.cpp @@ -185,7 +185,7 @@ public: // Note that we declare our locks before our ClientCursorPin, in order to ensure that // the pin's destructor is called before the lock destructors (so that the unpin occurs // under the lock). - std::unique_ptr<AutoGetCollectionForRead> ctx; + std::unique_ptr<AutoGetCollectionForReadCommand> ctx; std::unique_ptr<Lock::DBLock> unpinDBLock; std::unique_ptr<Lock::CollectionLock> unpinCollLock; @@ -193,8 +193,8 @@ public: if (request.nss.isListIndexesCursorNS() || request.nss.isListCollectionsCursorNS()) { cursorManager = CursorManager::getGlobalCursorManager(); } else { - ctx = stdx::make_unique<AutoGetCollectionOrViewForRead>(opCtx, request.nss); - auto viewCtx = static_cast<AutoGetCollectionOrViewForRead*>(ctx.get()); + ctx = stdx::make_unique<AutoGetCollectionOrViewForReadCommand>(opCtx, request.nss); + auto viewCtx = static_cast<AutoGetCollectionOrViewForReadCommand*>(ctx.get()); Collection* collection = ctx->getCollection(); if (!collection) { // Rewrite a getMore on a view to a getMore on the original underlying collection. @@ -251,7 +251,7 @@ public: invariant(!unpinCollLock); sleepFor(Milliseconds(10)); ctx.reset(); - ctx = stdx::make_unique<AutoGetCollectionForRead>(opCtx, request.nss); + ctx = stdx::make_unique<AutoGetCollectionForReadCommand>(opCtx, request.nss); } if (request.nss.ns() != cursor->ns()) { @@ -402,7 +402,7 @@ public: // CappedInsertNotifier. curOp->setExpectedLatencyMs(durationCount<Milliseconds>(timeout)); - ctx.reset(new AutoGetCollectionForRead(opCtx, request.nss)); + ctx.reset(new AutoGetCollectionForReadCommand(opCtx, request.nss)); exec->restoreState(); // We woke up because either the timed_wait expired, or there was more data. Either @@ -463,7 +463,7 @@ public: // earlier and need to reacquire it in order to clean up our ClientCursorPin. if (cursor->isAggCursor()) { invariant(NULL == ctx.get()); - unpinDBLock.reset(new Lock::DBLock(opCtx->lockState(), request.nss.db(), MODE_IS)); + unpinDBLock.reset(new Lock::DBLock(opCtx, request.nss.db(), MODE_IS)); unpinCollLock.reset( new Lock::CollectionLock(opCtx->lockState(), request.nss.ns(), MODE_IS)); } @@ -567,7 +567,7 @@ public: std::unique_ptr<Lock::CollectionLock> unpinCollLock; if (cursor->isAggCursor()) { - unpinDBLock.reset(new Lock::DBLock(opCtx->lockState(), request.nss.db(), MODE_IS)); + unpinDBLock.reset(new Lock::DBLock(opCtx, request.nss.db(), MODE_IS)); unpinCollLock.reset( new Lock::CollectionLock(opCtx->lockState(), request.nss.ns(), MODE_IS)); } diff --git a/src/mongo/db/commands/group_cmd.cpp b/src/mongo/db/commands/group_cmd.cpp index a9e6eeca6ca..4b41fc9e42c 100644 --- a/src/mongo/db/commands/group_cmd.cpp +++ b/src/mongo/db/commands/group_cmd.cpp @@ -134,7 +134,7 @@ private: groupRequest.explain = true; - AutoGetCollectionForRead ctx(opCtx, groupRequest.ns); + AutoGetCollectionForReadCommand ctx(opCtx, groupRequest.ns); Collection* coll = ctx.getCollection(); auto statusWithPlanExecutor = @@ -166,7 +166,7 @@ private: return appendCommandStatus(result, parseRequestStatus); } - AutoGetCollectionForRead ctx(opCtx, groupRequest.ns); + AutoGetCollectionForReadCommand ctx(opCtx, groupRequest.ns); Collection* coll = ctx.getCollection(); auto statusWithPlanExecutor = diff --git a/src/mongo/db/commands/haystack.cpp b/src/mongo/db/commands/haystack.cpp index d760ee9b866..f9a41f0ccd2 100644 --- a/src/mongo/db/commands/haystack.cpp +++ b/src/mongo/db/commands/haystack.cpp @@ -103,7 +103,7 @@ public: BSONObjBuilder& result) { const NamespaceString nss = parseNsCollectionRequired(dbname, cmdObj); - AutoGetCollectionForRead ctx(opCtx, nss); + AutoGetCollectionForReadCommand ctx(opCtx, nss); Collection* collection = ctx.getCollection(); if (!collection) { diff --git a/src/mongo/db/commands/index_filter_commands.cpp b/src/mongo/db/commands/index_filter_commands.cpp index 68230d587af..d85565ab49c 100644 --- a/src/mongo/db/commands/index_filter_commands.cpp +++ b/src/mongo/db/commands/index_filter_commands.cpp @@ -165,7 +165,7 @@ Status ListFilters::runIndexFilterCommand(OperationContext* opCtx, BSONObj& cmdObj, BSONObjBuilder* bob) { // This is a read lock. The query settings is owned by the collection. - AutoGetCollectionForRead ctx(opCtx, NamespaceString(ns)); + AutoGetCollectionForReadCommand ctx(opCtx, NamespaceString(ns)); QuerySettings* querySettings; PlanCache* unused; @@ -233,7 +233,7 @@ Status ClearFilters::runIndexFilterCommand(OperationContext* opCtx, BSONObj& cmdObj, BSONObjBuilder* bob) { // This is a read lock. The query settings is owned by the collection. - AutoGetCollectionForRead ctx(opCtx, NamespaceString(ns)); + AutoGetCollectionForReadCommand ctx(opCtx, NamespaceString(ns)); QuerySettings* querySettings; PlanCache* planCache; @@ -335,7 +335,7 @@ Status SetFilter::runIndexFilterCommand(OperationContext* opCtx, BSONObjBuilder* bob) { // This is a read lock. The query settings is owned by the collection. const NamespaceString nss(ns); - AutoGetCollectionForRead ctx(opCtx, nss); + AutoGetCollectionForReadCommand ctx(opCtx, nss); QuerySettings* querySettings; PlanCache* planCache; diff --git a/src/mongo/db/commands/killcursors_cmd.cpp b/src/mongo/db/commands/killcursors_cmd.cpp index e51e4d65f8a..c1526d990b5 100644 --- a/src/mongo/db/commands/killcursors_cmd.cpp +++ b/src/mongo/db/commands/killcursors_cmd.cpp @@ -48,7 +48,7 @@ private: Status _killCursor(OperationContext* opCtx, const NamespaceString& nss, CursorId cursorId) final { - std::unique_ptr<AutoGetCollectionOrViewForRead> ctx; + std::unique_ptr<AutoGetCollectionOrViewForReadCommand> ctx; CursorManager* cursorManager; if (nss.isListIndexesCursorNS() || nss.isListCollectionsCursorNS()) { @@ -57,7 +57,7 @@ private: // data within a collection. cursorManager = CursorManager::getGlobalCursorManager(); } else { - ctx = stdx::make_unique<AutoGetCollectionOrViewForRead>(opCtx, nss); + ctx = stdx::make_unique<AutoGetCollectionOrViewForReadCommand>(opCtx, nss); Collection* collection = ctx->getCollection(); ViewDefinition* view = ctx->getView(); if (view) { diff --git a/src/mongo/db/commands/list_collections.cpp b/src/mongo/db/commands/list_collections.cpp index a0f998fe346..da72422b4eb 100644 --- a/src/mongo/db/commands/list_collections.cpp +++ b/src/mongo/db/commands/list_collections.cpp @@ -255,7 +255,6 @@ public: return appendCommandStatus(result, parseCursorStatus); } - ScopedTransaction scopedXact(opCtx, MODE_IS); AutoGetDb autoDb(opCtx, dbname, MODE_S); Database* db = autoDb.getDb(); diff --git a/src/mongo/db/commands/list_databases.cpp b/src/mongo/db/commands/list_databases.cpp index ccc2f82cc49..ffe00a55362 100644 --- a/src/mongo/db/commands/list_databases.cpp +++ b/src/mongo/db/commands/list_databases.cpp @@ -114,8 +114,7 @@ public: vector<string> dbNames; StorageEngine* storageEngine = getGlobalServiceContext()->getGlobalStorageEngine(); { - ScopedTransaction transaction(opCtx, MODE_IS); - Lock::GlobalLock lk(opCtx->lockState(), MODE_IS, UINT_MAX); + Lock::GlobalLock lk(opCtx, MODE_IS, UINT_MAX); storageEngine->listDatabases(&dbNames); } @@ -135,8 +134,7 @@ public: if (filterNameOnly && !filter->matchesBSON(b.asTempObj())) continue; - ScopedTransaction transaction(opCtx, MODE_IS); - Lock::DBLock dbLock(opCtx->lockState(), dbname, MODE_IS); + Lock::DBLock dbLock(opCtx, dbname, MODE_IS); Database* db = dbHolder().get(opCtx, dbname); if (!db) diff --git a/src/mongo/db/commands/list_indexes.cpp b/src/mongo/db/commands/list_indexes.cpp index 940edb13eda..73e3d19289e 100644 --- a/src/mongo/db/commands/list_indexes.cpp +++ b/src/mongo/db/commands/list_indexes.cpp @@ -132,7 +132,7 @@ public: return appendCommandStatus(result, parseCursorStatus); } - AutoGetCollectionForRead autoColl(opCtx, ns); + AutoGetCollectionForReadCommand autoColl(opCtx, ns); if (!autoColl.getDb()) { return appendCommandStatus(result, Status(ErrorCodes::NamespaceNotFound, "no database")); diff --git a/src/mongo/db/commands/mr.cpp b/src/mongo/db/commands/mr.cpp index 9d36a06731b..ffeecffaca5 100644 --- a/src/mongo/db/commands/mr.cpp +++ b/src/mongo/db/commands/mr.cpp @@ -369,7 +369,6 @@ Config::Config(const string& _dbname, const BSONObj& cmdObj) { void State::dropTempCollections() { if (!_config.tempNamespace.isEmpty()) { MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { - ScopedTransaction scopedXact(_opCtx, MODE_IX); AutoGetDb autoDb(_opCtx, _config.tempNamespace.db(), MODE_X); if (auto db = autoDb.getDb()) { WriteUnitOfWork wunit(_opCtx); @@ -392,8 +391,7 @@ void State::dropTempCollections() { repl::UnreplicatedWritesBlock uwb(_opCtx); MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { - ScopedTransaction scopedXact(_opCtx, MODE_IX); - Lock::DBLock lk(_opCtx->lockState(), _config.incLong.db(), MODE_X); + Lock::DBLock lk(_opCtx, _config.incLong.db(), MODE_X); if (Database* db = dbHolder().get(_opCtx, _config.incLong.ns())) { WriteUnitOfWork wunit(_opCtx); db->dropCollection(_opCtx, _config.incLong.ns()); @@ -611,9 +609,8 @@ long long State::postProcessCollection(OperationContext* opCtx, invariant(!opCtx->lockState()->isLocked()); - ScopedTransaction transaction(opCtx, MODE_X); // This must be global because we may write across different databases. - Lock::GlobalWrite lock(opCtx->lockState()); + Lock::GlobalWrite lock(opCtx); holdingGlobalLock = true; return postProcessCollectionNonAtomic(opCtx, curOp, pm, holdingGlobalLock); } @@ -626,10 +623,10 @@ unsigned long long _collectionCount(OperationContext* opCtx, const NamespaceString& nss, bool callerHoldsGlobalLock) { Collection* coll = nullptr; - boost::optional<AutoGetCollectionForRead> ctx; + boost::optional<AutoGetCollectionForReadCommand> ctx; - // If the global write lock is held, we must avoid using AutoGetCollectionForRead as it may lead - // to deadlock when waiting for a majority snapshot to be committed. See SERVER-24596. + // If the global write lock is held, we must avoid using AutoGetCollectionForReadCommand as it + // may lead to deadlock when waiting for a majority snapshot to be committed. See SERVER-24596. if (callerHoldsGlobalLock) { Database* db = dbHolder().get(opCtx, nss.ns()); if (db) { @@ -654,9 +651,8 @@ long long State::postProcessCollectionNonAtomic(OperationContext* opCtx, if (_config.outputOptions.outType == Config::REPLACE || _collectionCount(opCtx, _config.outputOptions.finalNamespace, callerHoldsGlobalLock) == 0) { - ScopedTransaction transaction(opCtx, MODE_X); // This must be global because we may write across different databases. - Lock::GlobalWrite lock(opCtx->lockState()); + Lock::GlobalWrite lock(opCtx); // replace: just rename from temp to final collection name, dropping previous collection _db.dropCollection(_config.outputOptions.finalNamespace.ns()); BSONObj info; @@ -682,9 +678,7 @@ long long State::postProcessCollectionNonAtomic(OperationContext* opCtx, } unique_ptr<DBClientCursor> cursor = _db.query(_config.tempNamespace.ns(), BSONObj()); while (cursor->more()) { - ScopedTransaction scopedXact(opCtx, MODE_X); - Lock::DBLock lock( - opCtx->lockState(), _config.outputOptions.finalNamespace.db(), MODE_X); + Lock::DBLock lock(opCtx, _config.outputOptions.finalNamespace.db(), MODE_X); BSONObj o = cursor->nextSafe(); Helpers::upsert(opCtx, _config.outputOptions.finalNamespace.ns(), o); pm.hit(); @@ -704,9 +698,8 @@ long long State::postProcessCollectionNonAtomic(OperationContext* opCtx, } unique_ptr<DBClientCursor> cursor = _db.query(_config.tempNamespace.ns(), BSONObj()); while (cursor->more()) { - ScopedTransaction transaction(opCtx, MODE_X); // This must be global because we may write across different databases. - Lock::GlobalWrite lock(opCtx->lockState()); + Lock::GlobalWrite lock(opCtx); BSONObj temp = cursor->nextSafe(); BSONObj old; @@ -1088,7 +1081,8 @@ void State::finalReduce(OperationContext* opCtx, CurOp* curOp, ProgressMeterHold } MONGO_WRITE_CONFLICT_RETRY_LOOP_END(_opCtx, "finalReduce", _config.incLong.ns()); - unique_ptr<AutoGetCollectionForRead> ctx(new AutoGetCollectionForRead(_opCtx, _config.incLong)); + unique_ptr<AutoGetCollectionForReadCommand> ctx( + new AutoGetCollectionForReadCommand(_opCtx, _config.incLong)); BSONObj prev; BSONList all; @@ -1143,7 +1137,7 @@ void State::finalReduce(OperationContext* opCtx, CurOp* curOp, ProgressMeterHold // reduce a finalize array finalReduce(all); - ctx.reset(new AutoGetCollectionForRead(_opCtx, _config.incLong)); + ctx.reset(new AutoGetCollectionForReadCommand(_opCtx, _config.incLong)); all.clear(); prev = o; @@ -1163,7 +1157,7 @@ void State::finalReduce(OperationContext* opCtx, CurOp* curOp, ProgressMeterHold ctx.reset(); // reduce and finalize last array finalReduce(all); - ctx.reset(new AutoGetCollectionForRead(_opCtx, _config.incLong)); + ctx.reset(new AutoGetCollectionForReadCommand(_opCtx, _config.incLong)); pm.finished(); } @@ -1405,7 +1399,7 @@ public: unique_ptr<RangePreserver> rangePreserver; ScopedCollectionMetadata collMetadata; { - AutoGetCollectionForRead ctx(opCtx, config.nss); + AutoGetCollectionForReadCommand ctx(opCtx, config.nss); Collection* collection = ctx.getCollection(); if (collection) { @@ -1424,8 +1418,8 @@ public: // be done under the lock. ON_BLOCK_EXIT([opCtx, &config, &rangePreserver] { if (rangePreserver) { - // Be sure not to use AutoGetCollectionForRead here, since that has side-effects - // other than lock acquisition. + // Be sure not to use AutoGetCollectionForReadCommand here, since that has + // side-effects other than lock acquisition. AutoGetCollection ctx(opCtx, config.nss, MODE_IS); rangePreserver.reset(); } @@ -1489,7 +1483,6 @@ public: // useful cursor. // Need lock and context to use it - unique_ptr<ScopedTransaction> scopedXact(new ScopedTransaction(opCtx, MODE_IS)); unique_ptr<AutoGetDb> scopedAutoDb(new AutoGetDb(opCtx, config.nss.db(), MODE_S)); auto qr = stdx::make_unique<QueryRequest>(config.nss); @@ -1565,11 +1558,9 @@ public: exec->saveState(); scopedAutoDb.reset(); - scopedXact.reset(); state.reduceAndSpillInMemoryStateIfNeeded(); - scopedXact.reset(new ScopedTransaction(opCtx, MODE_IS)); scopedAutoDb.reset(new AutoGetDb(opCtx, config.nss.db(), MODE_S)); if (!exec->restoreState()) { diff --git a/src/mongo/db/commands/oplog_note.cpp b/src/mongo/db/commands/oplog_note.cpp index 39d3d175ff0..0c59dca849a 100644 --- a/src/mongo/db/commands/oplog_note.cpp +++ b/src/mongo/db/commands/oplog_note.cpp @@ -33,6 +33,7 @@ #include "mongo/db/auth/authorization_session.h" #include "mongo/db/auth/resource_pattern.h" #include "mongo/db/commands.h" +#include "mongo/db/concurrency/d_concurrency.h" #include "mongo/db/jsobj.h" #include "mongo/db/op_observer.h" #include "mongo/db/operation_context.h" @@ -87,8 +88,7 @@ public: return appendCommandStatus(result, status); } - ScopedTransaction scopedXact(opCtx, MODE_X); - Lock::GlobalWrite globalWrite(opCtx->lockState()); + Lock::GlobalWrite globalWrite(opCtx); WriteUnitOfWork wuow(opCtx); getGlobalServiceContext()->getOpObserver()->onOpMessage(opCtx, dataElement.Obj()); diff --git a/src/mongo/db/commands/parallel_collection_scan.cpp b/src/mongo/db/commands/parallel_collection_scan.cpp index df783b46062..8ff2e100a58 100644 --- a/src/mongo/db/commands/parallel_collection_scan.cpp +++ b/src/mongo/db/commands/parallel_collection_scan.cpp @@ -93,7 +93,7 @@ public: BSONObjBuilder& result) { const NamespaceString ns(parseNsCollectionRequired(dbname, cmdObj)); - AutoGetCollectionForRead ctx(opCtx, ns); + AutoGetCollectionForReadCommand ctx(opCtx, ns); Collection* collection = ctx.getCollection(); if (!collection) diff --git a/src/mongo/db/commands/plan_cache_commands.cpp b/src/mongo/db/commands/plan_cache_commands.cpp index ff9bd872cf3..bb4eebcb998 100644 --- a/src/mongo/db/commands/plan_cache_commands.cpp +++ b/src/mongo/db/commands/plan_cache_commands.cpp @@ -227,7 +227,7 @@ Status PlanCacheListQueryShapes::runPlanCacheCommand(OperationContext* opCtx, BSONObj& cmdObj, BSONObjBuilder* bob) { // This is a read lock. The query cache is owned by the collection. - AutoGetCollectionForRead ctx(opCtx, NamespaceString(ns)); + AutoGetCollectionForReadCommand ctx(opCtx, NamespaceString(ns)); PlanCache* planCache; Status status = getPlanCache(opCtx, ctx.getCollection(), ns, &planCache); @@ -279,7 +279,7 @@ Status PlanCacheClear::runPlanCacheCommand(OperationContext* opCtx, BSONObj& cmdObj, BSONObjBuilder* bob) { // This is a read lock. The query cache is owned by the collection. - AutoGetCollectionForRead ctx(opCtx, NamespaceString(ns)); + AutoGetCollectionForReadCommand ctx(opCtx, NamespaceString(ns)); PlanCache* planCache; Status status = getPlanCache(opCtx, ctx.getCollection(), ns, &planCache); @@ -355,7 +355,7 @@ Status PlanCacheListPlans::runPlanCacheCommand(OperationContext* opCtx, const std::string& ns, BSONObj& cmdObj, BSONObjBuilder* bob) { - AutoGetCollectionForRead ctx(opCtx, NamespaceString(ns)); + AutoGetCollectionForReadCommand ctx(opCtx, NamespaceString(ns)); PlanCache* planCache; Status status = getPlanCache(opCtx, ctx.getCollection(), ns, &planCache); diff --git a/src/mongo/db/commands/repair_cursor.cpp b/src/mongo/db/commands/repair_cursor.cpp index b5d7c2fde6f..ac6155cc394 100644 --- a/src/mongo/db/commands/repair_cursor.cpp +++ b/src/mongo/db/commands/repair_cursor.cpp @@ -75,7 +75,7 @@ public: BSONObjBuilder& result) { NamespaceString ns(parseNs(dbname, cmdObj)); - AutoGetCollectionForRead ctx(opCtx, ns); + AutoGetCollectionForReadCommand ctx(opCtx, ns); Collection* collection = ctx.getCollection(); if (!collection) { diff --git a/src/mongo/db/commands/run_aggregate.cpp b/src/mongo/db/commands/run_aggregate.cpp index 684b954b0c5..35164560c16 100644 --- a/src/mongo/db/commands/run_aggregate.cpp +++ b/src/mongo/db/commands/run_aggregate.cpp @@ -309,7 +309,7 @@ Status runAggregate(OperationContext* opCtx, // same sharding version that we synchronize on here. This is also why we always need to // create a ClientCursor even when we aren't outputting to a cursor. See the comment on // ShardFilterStage for more details. - AutoGetCollectionOrViewForRead ctx(opCtx, nss); + AutoGetCollectionOrViewForReadCommand ctx(opCtx, nss); Collection* collection = ctx.getCollection(); // If this is a view, resolve it by finding the underlying collection and stitching view @@ -487,7 +487,7 @@ Status runAggregate(OperationContext* opCtx, // AutoGetCollectionForRead. AutoGetCollectionForRead will throw if the // sharding version is out of date, and we don't care if the sharding version // has changed. - Lock::DBLock dbLock(opCtx->lockState(), nss.db(), MODE_IS); + Lock::DBLock dbLock(opCtx, nss.db(), MODE_IS); Lock::CollectionLock collLock(opCtx->lockState(), nss.ns(), MODE_IS); if (keepCursor) { pin->release(); @@ -498,7 +498,7 @@ Status runAggregate(OperationContext* opCtx, } catch (...) { // On our way out of scope, we clean up our ClientCursorPin if needed. if (pin) { - Lock::DBLock dbLock(opCtx->lockState(), nss.db(), MODE_IS); + Lock::DBLock dbLock(opCtx, nss.db(), MODE_IS); Lock::CollectionLock collLock(opCtx->lockState(), nss.ns(), MODE_IS); pin->deleteUnderlying(); } diff --git a/src/mongo/db/commands/snapshot_management.cpp b/src/mongo/db/commands/snapshot_management.cpp index 8ab963eb71e..1eb6e2c2126 100644 --- a/src/mongo/db/commands/snapshot_management.cpp +++ b/src/mongo/db/commands/snapshot_management.cpp @@ -32,6 +32,7 @@ #include "mongo/base/init.h" #include "mongo/db/commands.h" +#include "mongo/db/concurrency/d_concurrency.h" #include "mongo/db/operation_context.h" #include "mongo/db/repl/replication_coordinator.h" #include "mongo/db/service_context.h" @@ -75,8 +76,7 @@ public: return appendCommandStatus(result, {ErrorCodes::CommandNotSupported, ""}); } - ScopedTransaction st(opCtx, MODE_IX); - Lock::GlobalLock lk(opCtx->lockState(), MODE_IX, UINT_MAX); + Lock::GlobalLock lk(opCtx, MODE_IX, UINT_MAX); auto status = snapshotManager->prepareForCreateSnapshot(opCtx); if (status.isOK()) { @@ -126,8 +126,7 @@ public: return appendCommandStatus(result, {ErrorCodes::CommandNotSupported, ""}); } - ScopedTransaction st(opCtx, MODE_IX); - Lock::GlobalLock lk(opCtx->lockState(), MODE_IX, UINT_MAX); + Lock::GlobalLock lk(opCtx, MODE_IX, UINT_MAX); auto name = SnapshotName(cmdObj.firstElement().Long()); snapshotManager->setCommittedSnapshot(name); return true; diff --git a/src/mongo/db/commands/test_commands.cpp b/src/mongo/db/commands/test_commands.cpp index 34bc757d554..685e8e7a013 100644 --- a/src/mongo/db/commands/test_commands.cpp +++ b/src/mongo/db/commands/test_commands.cpp @@ -85,8 +85,7 @@ public: log() << "test only command godinsert invoked coll:" << nss.coll(); BSONObj obj = cmdObj["obj"].embeddedObjectUserCheck(); - ScopedTransaction transaction(opCtx, MODE_IX); - Lock::DBLock lk(opCtx->lockState(), dbname, MODE_X); + Lock::DBLock lk(opCtx, dbname, MODE_X); OldClientContext ctx(opCtx, nss.ns()); Database* db = ctx.db(); @@ -141,14 +140,12 @@ public: std::vector<Privilege>* out) {} void _sleepInReadLock(mongo::OperationContext* opCtx, long long millis) { - ScopedTransaction transaction(opCtx, MODE_S); - Lock::GlobalRead lk(opCtx->lockState()); + Lock::GlobalRead lk(opCtx); sleepmillis(millis); } void _sleepInWriteLock(mongo::OperationContext* opCtx, long long millis) { - ScopedTransaction transaction(opCtx, MODE_X); - Lock::GlobalWrite lk(opCtx->lockState()); + Lock::GlobalWrite lk(opCtx); sleepmillis(millis); } diff --git a/src/mongo/db/commands/touch.cpp b/src/mongo/db/commands/touch.cpp index 1f28da9e3fc..7cae0f979ee 100644 --- a/src/mongo/db/commands/touch.cpp +++ b/src/mongo/db/commands/touch.cpp @@ -102,7 +102,7 @@ public: return false; } - AutoGetCollectionForRead context(opCtx, nss); + AutoGetCollectionForReadCommand context(opCtx, nss); Collection* collection = context.getCollection(); if (!collection) { diff --git a/src/mongo/db/commands/write_commands/write_commands.cpp b/src/mongo/db/commands/write_commands/write_commands.cpp index 3c30ddc9e66..b6896022583 100644 --- a/src/mongo/db/commands/write_commands/write_commands.cpp +++ b/src/mongo/db/commands/write_commands/write_commands.cpp @@ -328,7 +328,6 @@ public: // Explains of write commands are read-only, but we take write locks so that timing // info is more accurate. - ScopedTransaction scopedXact(opCtx, MODE_IX); AutoGetCollection collection(opCtx, batch.ns, MODE_IX); auto exec = uassertStatusOK(getExecutorUpdate( @@ -396,7 +395,6 @@ public: // Explains of write commands are read-only, but we take write locks so that timing // info is more accurate. - ScopedTransaction scopedXact(opCtx, MODE_IX); AutoGetCollection collection(opCtx, batch.ns, MODE_IX); // Explain the plan tree. diff --git a/src/mongo/db/concurrency/SConscript b/src/mongo/db/concurrency/SConscript index 16a254db7aa..6a41d6e8564 100644 --- a/src/mongo/db/concurrency/SConscript +++ b/src/mongo/db/concurrency/SConscript @@ -45,6 +45,7 @@ env.CppUnitTest( ], LIBDEPS=[ '$BUILD_DIR/mongo/util/progress_meter', + '$BUILD_DIR/mongo/db/service_context_noop_init', 'lock_manager', ] ) diff --git a/src/mongo/db/concurrency/d_concurrency.cpp b/src/mongo/db/concurrency/d_concurrency.cpp index e12f38a13fe..5360ca958f2 100644 --- a/src/mongo/db/concurrency/d_concurrency.cpp +++ b/src/mongo/db/concurrency/d_concurrency.cpp @@ -135,51 +135,53 @@ bool Lock::ResourceMutex::isAtLeastReadLocked(Locker* locker) { return locker->isLockHeldForMode(_rid, MODE_IS); } -Lock::GlobalLock::GlobalLock(Locker* locker, LockMode lockMode, unsigned timeoutMs) - : GlobalLock(locker, lockMode, EnqueueOnly()) { +Lock::GlobalLock::GlobalLock(OperationContext* opCtx, LockMode lockMode, unsigned timeoutMs) + : GlobalLock(opCtx, lockMode, EnqueueOnly()) { waitForLock(timeoutMs); } -Lock::GlobalLock::GlobalLock(Locker* locker, LockMode lockMode, EnqueueOnly enqueueOnly) - : _locker(locker), _result(LOCK_INVALID), _pbwm(locker, resourceIdParallelBatchWriterMode) { +Lock::GlobalLock::GlobalLock(OperationContext* opCtx, LockMode lockMode, EnqueueOnly enqueueOnly) + : _opCtx(opCtx), + _result(LOCK_INVALID), + _pbwm(opCtx->lockState(), resourceIdParallelBatchWriterMode) { _enqueue(lockMode); } void Lock::GlobalLock::_enqueue(LockMode lockMode) { - if (_locker->shouldConflictWithSecondaryBatchApplication()) { + if (_opCtx->lockState()->shouldConflictWithSecondaryBatchApplication()) { _pbwm.lock(MODE_IS); } - _result = _locker->lockGlobalBegin(lockMode); + _result = _opCtx->lockState()->lockGlobalBegin(lockMode); } void Lock::GlobalLock::waitForLock(unsigned timeoutMs) { if (_result == LOCK_WAITING) { - _result = _locker->lockGlobalComplete(timeoutMs); + _result = _opCtx->lockState()->lockGlobalComplete(timeoutMs); } - if (_result != LOCK_OK && _locker->shouldConflictWithSecondaryBatchApplication()) { + if (_result != LOCK_OK && _opCtx->lockState()->shouldConflictWithSecondaryBatchApplication()) { _pbwm.unlock(); } } void Lock::GlobalLock::_unlock() { if (isLocked()) { - _locker->unlockGlobal(); + _opCtx->lockState()->unlockGlobal(); _result = LOCK_INVALID; } } -Lock::DBLock::DBLock(Locker* locker, StringData db, LockMode mode) +Lock::DBLock::DBLock(OperationContext* opCtx, StringData db, LockMode mode) : _id(RESOURCE_DATABASE, db), - _locker(locker), + _opCtx(opCtx), _mode(mode), - _globalLock(locker, isSharedLockMode(_mode) ? MODE_IS : MODE_IX, UINT_MAX) { + _globalLock(opCtx, isSharedLockMode(_mode) ? MODE_IS : MODE_IX, UINT_MAX) { massert(28539, "need a valid database name", !db.empty() && nsIsDbOnly(db)); // Need to acquire the flush lock - _locker->lockMMAPV1Flush(); + _opCtx->lockState()->lockMMAPV1Flush(); // The check for the admin db is to ensure direct writes to auth collections // are serialized (see SERVER-16092). @@ -187,24 +189,24 @@ Lock::DBLock::DBLock(Locker* locker, StringData db, LockMode mode) _mode = MODE_X; } - invariant(LOCK_OK == _locker->lock(_id, _mode)); + invariant(LOCK_OK == _opCtx->lockState()->lock(_id, _mode)); } Lock::DBLock::~DBLock() { - _locker->unlock(_id); + _opCtx->lockState()->unlock(_id); } void Lock::DBLock::relockWithMode(LockMode newMode) { // 2PL would delay the unlocking - invariant(!_locker->inAWriteUnitOfWork()); + invariant(!_opCtx->lockState()->inAWriteUnitOfWork()); // Not allowed to change global intent invariant(!isSharedLockMode(_mode) || isSharedLockMode(newMode)); - _locker->unlock(_id); + _opCtx->lockState()->unlock(_id); _mode = newMode; - invariant(LOCK_OK == _locker->lock(_id, _mode)); + invariant(LOCK_OK == _opCtx->lockState()->lock(_id, _mode)); } diff --git a/src/mongo/db/concurrency/d_concurrency.h b/src/mongo/db/concurrency/d_concurrency.h index 0d93b3ef2d0..5eb5de3a5e2 100644 --- a/src/mongo/db/concurrency/d_concurrency.h +++ b/src/mongo/db/concurrency/d_concurrency.h @@ -31,6 +31,7 @@ #include <climits> // For UINT_MAX #include "mongo/db/concurrency/locker.h" +#include "mongo/db/operation_context.h" #include "mongo/util/timer.h" namespace mongo { @@ -161,23 +162,30 @@ public: * Global lock. * * Grabs global resource lock. Allows further (recursive) acquisition of the global lock - * in any mode, see LockMode. + * in any mode, see LockMode. An outermost GlobalLock calls abandonSnapshot() 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 when releasing the GlobalLock. + * * NOTE: Does not acquire flush lock. */ class GlobalLock { public: class EnqueueOnly {}; - GlobalLock(Locker* locker, LockMode lockMode, unsigned timeoutMs); + GlobalLock(OperationContext* opCtx, LockMode lockMode, unsigned timeoutMs); /** * Enqueues lock but does not block on lock acquisition. * Call waitForLock() to complete locking process. */ - GlobalLock(Locker* locker, LockMode lockMode, EnqueueOnly enqueueOnly); + GlobalLock(OperationContext* opCtx, LockMode lockMode, EnqueueOnly enqueueOnly); ~GlobalLock() { _unlock(); + if (!_opCtx->lockState()->isLocked()) { + _opCtx->recoveryUnit()->abandonSnapshot(); + } } /** @@ -193,7 +201,7 @@ public: void _enqueue(LockMode lockMode); void _unlock(); - Locker* const _locker; + OperationContext* const _opCtx; LockResult _result; ResourceLock _pbwm; }; @@ -208,10 +216,10 @@ public: */ class GlobalWrite : public GlobalLock { public: - explicit GlobalWrite(Locker* locker, unsigned timeoutMs = UINT_MAX) - : GlobalLock(locker, MODE_X, timeoutMs) { + explicit GlobalWrite(OperationContext* opCtx, unsigned timeoutMs = UINT_MAX) + : GlobalLock(opCtx, MODE_X, timeoutMs) { if (isLocked()) { - locker->lockMMAPV1Flush(); + opCtx->lockState()->lockMMAPV1Flush(); } } }; @@ -226,10 +234,10 @@ public: */ class GlobalRead : public GlobalLock { public: - explicit GlobalRead(Locker* locker, unsigned timeoutMs = UINT_MAX) - : GlobalLock(locker, MODE_S, timeoutMs) { + explicit GlobalRead(OperationContext* opCtx, unsigned timeoutMs = UINT_MAX) + : GlobalLock(opCtx, MODE_S, timeoutMs) { if (isLocked()) { - locker->lockMMAPV1Flush(); + opCtx->lockState()->lockMMAPV1Flush(); } } }; @@ -251,7 +259,7 @@ public: */ class DBLock { public: - DBLock(Locker* locker, StringData db, LockMode mode); + DBLock(OperationContext* opCtx, StringData db, LockMode mode); ~DBLock(); /** @@ -264,7 +272,7 @@ public: private: const ResourceId _id; - Locker* const _locker; + OperationContext* const _opCtx; // May be changed through relockWithMode. The global lock mode won't change though, // because we never change from IS/S to IX/X or vice versa, just convert locks from diff --git a/src/mongo/db/concurrency/d_concurrency_test.cpp b/src/mongo/db/concurrency/d_concurrency_test.cpp index 1058d8a0163..2c497e4fa84 100644 --- a/src/mongo/db/concurrency/d_concurrency_test.cpp +++ b/src/mongo/db/concurrency/d_concurrency_test.cpp @@ -36,6 +36,7 @@ #include "mongo/db/concurrency/d_concurrency.h" #include "mongo/db/concurrency/lock_manager_test_help.h" #include "mongo/stdx/functional.h" +#include "mongo/stdx/memory.h" #include "mongo/stdx/thread.h" #include "mongo/unittest/unittest.h" #include "mongo/util/debug_util.h" @@ -69,53 +70,94 @@ private: bool _oldSupportsDocLocking; }; -/** - * Calls fn the given number of iterations, spread out over up to maxThreads threads. - * The threadNr passed is an integer between 0 and maxThreads exclusive. Logs timing - * statistics for for all power-of-two thread counts from 1 up to maxThreds. - */ -void perfTest(stdx::function<void(int threadNr)> fn, int maxThreads) { - for (int numThreads = 1; numThreads <= maxThreads; numThreads *= 2) { - std::vector<stdx::thread> threads; - - AtomicInt32 ready{0}; - AtomicInt64 elapsedNanos{0}; - AtomicInt64 timedIters{0}; - - for (int threadId = 0; threadId < numThreads; threadId++) - threads.emplace_back([&, threadId]() { - // Busy-wait until everybody is ready - ready.fetchAndAdd(1); - while (ready.load() < numThreads) { - } - uint64_t micros = 0; - int iters; - // Ensure at least 16 iterations are done and at least 25 milliseconds is timed - for (iters = 16; iters < (1 << 30) && micros < kMinPerfMillis * 1000; iters *= 2) { - // Measure the number of loops - Timer t; +class DConcurrencyTestFixture : public unittest::Test { +public: + DConcurrencyTestFixture() : _client(getGlobalServiceContext()->makeClient("testClient")) {} + + /** + * Constructs and returns a new OperationContext. + */ + ServiceContext::UniqueOperationContext makeOpCtx() const { + auto opCtx = _client->makeOperationContext(); + opCtx->releaseLockState(); + return opCtx; + } + + /** + * Returns a vector of Clients of length 'k', each of which has an OperationContext with its + * lockState set to a DefaultLockerImpl. + */ + template <typename LockerType> + std::vector<std::pair<ServiceContext::UniqueClient, ServiceContext::UniqueOperationContext>> + makeKClientsWithLockers(int k) { + std::vector<std::pair<ServiceContext::UniqueClient, ServiceContext::UniqueOperationContext>> + clients; + clients.reserve(k); + for (int i = 0; i < k; ++i) { + auto client = getGlobalServiceContext()->makeClient( + str::stream() << "test client for thread " << i); + auto opCtx = client->makeOperationContext(); + opCtx->releaseLockState(); + opCtx->setLockState(stdx::make_unique<LockerType>()); + clients.emplace_back(std::move(client), std::move(opCtx)); + } + return clients; + } + + /** + * Calls fn the given number of iterations, spread out over up to maxThreads threads. + * The threadNr passed is an integer between 0 and maxThreads exclusive. Logs timing + * statistics for for all power-of-two thread counts from 1 up to maxThreds. + */ + void perfTest(stdx::function<void(int threadNr)> fn, int maxThreads) { + for (int numThreads = 1; numThreads <= maxThreads; numThreads *= 2) { + std::vector<stdx::thread> threads; + + AtomicInt32 ready{0}; + AtomicInt64 elapsedNanos{0}; + AtomicInt64 timedIters{0}; + + for (int threadId = 0; threadId < numThreads; threadId++) + threads.emplace_back([&, threadId]() { + // Busy-wait until everybody is ready + ready.fetchAndAdd(1); + while (ready.load() < numThreads) { + } - for (int i = 0; i < iters; i++) - fn(threadId); + uint64_t micros = 0; + int iters; + // Ensure at least 16 iterations are done and at least 25 milliseconds is timed + for (iters = 16; iters < (1 << 30) && micros < kMinPerfMillis * 1000; + iters *= 2) { + // Measure the number of loops + Timer t; - micros = t.micros(); - } + for (int i = 0; i < iters; i++) + fn(threadId); - elapsedNanos.fetchAndAdd(micros * 1000); - timedIters.fetchAndAdd(iters); - }); + micros = t.micros(); + } + + elapsedNanos.fetchAndAdd(micros * 1000); + timedIters.fetchAndAdd(iters); + }); - for (auto& thread : threads) - thread.join(); + for (auto& thread : threads) + thread.join(); - log() << numThreads - << " threads took: " << elapsedNanos.load() / static_cast<double>(timedIters.load()) - << " ns per call" << (kDebugBuild ? " (DEBUG BUILD!)" : ""); + log() << numThreads << " threads took: " + << elapsedNanos.load() / static_cast<double>(timedIters.load()) << " ns per call" + << (kDebugBuild ? " (DEBUG BUILD!)" : ""); + } } -} -TEST(DConcurrency, ResourceMutex) { +private: + ServiceContext::UniqueClient _client; +}; + + +TEST_F(DConcurrencyTestFixture, ResourceMutex) { Lock::ResourceMutex mtx("testMutex"); DefaultLockerImpl locker1; DefaultLockerImpl locker2; @@ -197,284 +239,292 @@ TEST(DConcurrency, ResourceMutex) { t3.join(); } -TEST(DConcurrency, GlobalRead) { - MMAPV1LockerImpl ls; - Lock::GlobalRead globalRead(&ls); - ASSERT(ls.isR()); +TEST_F(DConcurrencyTestFixture, GlobalRead) { + auto opCtx = makeOpCtx(); + opCtx->setLockState(stdx::make_unique<MMAPV1LockerImpl>()); + Lock::GlobalRead globalRead(opCtx.get()); + ASSERT(opCtx->lockState()->isR()); } -TEST(DConcurrency, GlobalWrite) { - MMAPV1LockerImpl ls; - Lock::GlobalWrite globalWrite(&ls); - ASSERT(ls.isW()); +TEST_F(DConcurrencyTestFixture, GlobalWrite) { + auto opCtx = makeOpCtx(); + opCtx->setLockState(stdx::make_unique<MMAPV1LockerImpl>()); + Lock::GlobalWrite globalWrite(opCtx.get()); + ASSERT(opCtx->lockState()->isW()); } -TEST(DConcurrency, GlobalWriteAndGlobalRead) { - MMAPV1LockerImpl ls; +TEST_F(DConcurrencyTestFixture, GlobalWriteAndGlobalRead) { + auto opCtx = makeOpCtx(); + opCtx->setLockState(stdx::make_unique<MMAPV1LockerImpl>()); + auto lockState = opCtx->lockState(); - Lock::GlobalWrite globalWrite(&ls); - ASSERT(ls.isW()); + Lock::GlobalWrite globalWrite(opCtx.get()); + ASSERT(lockState->isW()); { - Lock::GlobalRead globalRead(&ls); - ASSERT(ls.isW()); + Lock::GlobalRead globalRead(opCtx.get()); + ASSERT(lockState->isW()); } - ASSERT(ls.isW()); + ASSERT(lockState->isW()); } -TEST(DConcurrency, GlobalLockS_Timeout) { - MMAPV1LockerImpl ls; - Lock::GlobalLock globalWrite(&ls, MODE_X, 0); +TEST_F(DConcurrencyTestFixture, GlobalLockS_Timeout) { + auto clients = makeKClientsWithLockers<MMAPV1LockerImpl>(2); + + Lock::GlobalLock globalWrite(clients[0].second.get(), MODE_X, 0); ASSERT(globalWrite.isLocked()); - { - MMAPV1LockerImpl lsTry; - Lock::GlobalLock globalReadTry(&lsTry, MODE_S, 1); - ASSERT(!globalReadTry.isLocked()); - } + Lock::GlobalLock globalReadTry(clients[1].second.get(), MODE_S, 1); + ASSERT(!globalReadTry.isLocked()); } -TEST(DConcurrency, GlobalLockX_Timeout) { - MMAPV1LockerImpl ls; - Lock::GlobalLock globalWrite(&ls, MODE_X, 0); +TEST_F(DConcurrencyTestFixture, GlobalLockX_Timeout) { + auto clients = makeKClientsWithLockers<MMAPV1LockerImpl>(2); + Lock::GlobalLock globalWrite(clients[0].second.get(), MODE_X, 0); ASSERT(globalWrite.isLocked()); - { - MMAPV1LockerImpl lsTry; - Lock::GlobalLock globalWriteTry(&lsTry, MODE_X, 1); - ASSERT(!globalWriteTry.isLocked()); - } + Lock::GlobalLock globalWriteTry(clients[1].second.get(), MODE_X, 1); + ASSERT(!globalWriteTry.isLocked()); } -TEST(DConcurrency, GlobalLockS_NoTimeoutDueToGlobalLockS) { - MMAPV1LockerImpl ls; - Lock::GlobalRead globalRead(&ls); +TEST_F(DConcurrencyTestFixture, GlobalLockS_NoTimeoutDueToGlobalLockS) { + auto clients = makeKClientsWithLockers<MMAPV1LockerImpl>(2); - MMAPV1LockerImpl lsTry; - Lock::GlobalLock globalReadTry(&lsTry, MODE_S, 1); + Lock::GlobalRead globalRead(clients[0].second.get()); + Lock::GlobalLock globalReadTry(clients[1].second.get(), MODE_S, 1); ASSERT(globalReadTry.isLocked()); } -TEST(DConcurrency, GlobalLockX_TimeoutDueToGlobalLockS) { - MMAPV1LockerImpl ls; - Lock::GlobalRead globalRead(&ls); +TEST_F(DConcurrencyTestFixture, GlobalLockX_TimeoutDueToGlobalLockS) { + auto clients = makeKClientsWithLockers<MMAPV1LockerImpl>(2); - MMAPV1LockerImpl lsTry; - Lock::GlobalLock globalWriteTry(&lsTry, MODE_X, 1); + Lock::GlobalRead globalRead(clients[0].second.get()); + Lock::GlobalLock globalWriteTry(clients[1].second.get(), MODE_X, 1); ASSERT(!globalWriteTry.isLocked()); } -TEST(DConcurrency, GlobalLockS_TimeoutDueToGlobalLockX) { - MMAPV1LockerImpl ls; - Lock::GlobalWrite globalWrite(&ls); +TEST_F(DConcurrencyTestFixture, GlobalLockS_TimeoutDueToGlobalLockX) { + auto clients = makeKClientsWithLockers<MMAPV1LockerImpl>(2); - MMAPV1LockerImpl lsTry; - Lock::GlobalLock globalReadTry(&lsTry, MODE_S, 1); + Lock::GlobalWrite globalWrite(clients[0].second.get()); + Lock::GlobalLock globalReadTry(clients[1].second.get(), MODE_S, 1); ASSERT(!globalReadTry.isLocked()); } -TEST(DConcurrency, GlobalLockX_TimeoutDueToGlobalLockX) { - MMAPV1LockerImpl ls; - Lock::GlobalWrite globalWrite(&ls); +TEST_F(DConcurrencyTestFixture, GlobalLockX_TimeoutDueToGlobalLockX) { + auto clients = makeKClientsWithLockers<MMAPV1LockerImpl>(2); - MMAPV1LockerImpl lsTry; - Lock::GlobalLock globalWriteTry(&lsTry, MODE_X, 1); + Lock::GlobalWrite globalWrite(clients[0].second.get()); + Lock::GlobalLock globalWriteTry(clients[1].second.get(), MODE_X, 1); ASSERT(!globalWriteTry.isLocked()); } -TEST(DConcurrency, TempReleaseGlobalWrite) { - MMAPV1LockerImpl ls; - Lock::GlobalWrite globalWrite(&ls); +TEST_F(DConcurrencyTestFixture, TempReleaseGlobalWrite) { + auto opCtx = makeOpCtx(); + opCtx->setLockState(stdx::make_unique<MMAPV1LockerImpl>()); + auto lockState = opCtx->lockState(); + Lock::GlobalWrite globalWrite(opCtx.get()); { - Lock::TempRelease tempRelease(&ls); - ASSERT(!ls.isLocked()); + Lock::TempRelease tempRelease(lockState); + ASSERT(!lockState->isLocked()); } - ASSERT(ls.isW()); + ASSERT(lockState->isW()); } -TEST(DConcurrency, TempReleaseRecursive) { - MMAPV1LockerImpl ls; - Lock::GlobalWrite globalWrite(&ls); - Lock::DBLock lk(&ls, "SomeDBName", MODE_X); +TEST_F(DConcurrencyTestFixture, TempReleaseRecursive) { + auto opCtx = makeOpCtx(); + opCtx->setLockState(stdx::make_unique<MMAPV1LockerImpl>()); + auto lockState = opCtx->lockState(); + Lock::GlobalWrite globalWrite(opCtx.get()); + Lock::DBLock lk(opCtx.get(), "SomeDBName", MODE_X); { - Lock::TempRelease tempRelease(&ls); - ASSERT(ls.isW()); - ASSERT(ls.isDbLockedForMode("SomeDBName", MODE_X)); + Lock::TempRelease tempRelease(lockState); + ASSERT(lockState->isW()); + ASSERT(lockState->isDbLockedForMode("SomeDBName", MODE_X)); } - ASSERT(ls.isW()); + ASSERT(lockState->isW()); } -TEST(DConcurrency, DBLockTakesS) { - MMAPV1LockerImpl ls; - - Lock::DBLock dbRead(&ls, "db", MODE_S); +TEST_F(DConcurrencyTestFixture, DBLockTakesS) { + auto opCtx = makeOpCtx(); + opCtx->setLockState(stdx::make_unique<MMAPV1LockerImpl>()); + Lock::DBLock dbRead(opCtx.get(), "db", MODE_S); const ResourceId resIdDb(RESOURCE_DATABASE, std::string("db")); - ASSERT(ls.getLockMode(resIdDb) == MODE_S); + ASSERT(opCtx->lockState()->getLockMode(resIdDb) == MODE_S); } -TEST(DConcurrency, DBLockTakesX) { - MMAPV1LockerImpl ls; - - Lock::DBLock dbWrite(&ls, "db", MODE_X); +TEST_F(DConcurrencyTestFixture, DBLockTakesX) { + auto opCtx = makeOpCtx(); + opCtx->setLockState(stdx::make_unique<MMAPV1LockerImpl>()); + Lock::DBLock dbWrite(opCtx.get(), "db", MODE_X); const ResourceId resIdDb(RESOURCE_DATABASE, std::string("db")); - ASSERT(ls.getLockMode(resIdDb) == MODE_X); + ASSERT(opCtx->lockState()->getLockMode(resIdDb) == MODE_X); } -TEST(DConcurrency, DBLockTakesISForAdminIS) { - DefaultLockerImpl ls; - - Lock::DBLock dbRead(&ls, "admin", MODE_IS); +TEST_F(DConcurrencyTestFixture, DBLockTakesISForAdminIS) { + auto opCtx = makeOpCtx(); + opCtx->setLockState(stdx::make_unique<MMAPV1LockerImpl>()); + Lock::DBLock dbRead(opCtx.get(), "admin", MODE_IS); - ASSERT(ls.getLockMode(resourceIdAdminDB) == MODE_IS); + ASSERT(opCtx->lockState()->getLockMode(resourceIdAdminDB) == MODE_IS); } -TEST(DConcurrency, DBLockTakesSForAdminS) { - DefaultLockerImpl ls; +TEST_F(DConcurrencyTestFixture, DBLockTakesSForAdminS) { + auto opCtx = makeOpCtx(); + opCtx->setLockState(stdx::make_unique<MMAPV1LockerImpl>()); + Lock::DBLock dbRead(opCtx.get(), "admin", MODE_S); - Lock::DBLock dbRead(&ls, "admin", MODE_S); - - ASSERT(ls.getLockMode(resourceIdAdminDB) == MODE_S); + ASSERT(opCtx->lockState()->getLockMode(resourceIdAdminDB) == MODE_S); } -TEST(DConcurrency, DBLockTakesXForAdminIX) { - DefaultLockerImpl ls; - - Lock::DBLock dbWrite(&ls, "admin", MODE_IX); +TEST_F(DConcurrencyTestFixture, DBLockTakesXForAdminIX) { + auto opCtx = makeOpCtx(); + opCtx->setLockState(stdx::make_unique<MMAPV1LockerImpl>()); + Lock::DBLock dbWrite(opCtx.get(), "admin", MODE_IX); - ASSERT(ls.getLockMode(resourceIdAdminDB) == MODE_X); + ASSERT(opCtx->lockState()->getLockMode(resourceIdAdminDB) == MODE_X); } -TEST(DConcurrency, DBLockTakesXForAdminX) { - DefaultLockerImpl ls; +TEST_F(DConcurrencyTestFixture, DBLockTakesXForAdminX) { + auto opCtx = makeOpCtx(); + opCtx->setLockState(stdx::make_unique<MMAPV1LockerImpl>()); + Lock::DBLock dbWrite(opCtx.get(), "admin", MODE_X); - Lock::DBLock dbWrite(&ls, "admin", MODE_X); - - ASSERT(ls.getLockMode(resourceIdAdminDB) == MODE_X); + ASSERT(opCtx->lockState()->getLockMode(resourceIdAdminDB) == MODE_X); } -TEST(DConcurrency, MultipleWriteDBLocksOnSameThread) { - MMAPV1LockerImpl ls; - - Lock::DBLock r1(&ls, "db1", MODE_X); - Lock::DBLock r2(&ls, "db1", MODE_X); +TEST_F(DConcurrencyTestFixture, MultipleWriteDBLocksOnSameThread) { + auto opCtx = makeOpCtx(); + opCtx->setLockState(stdx::make_unique<MMAPV1LockerImpl>()); + Lock::DBLock r1(opCtx.get(), "db1", MODE_X); + Lock::DBLock r2(opCtx.get(), "db1", MODE_X); - ASSERT(ls.isDbLockedForMode("db1", MODE_X)); + ASSERT(opCtx->lockState()->isDbLockedForMode("db1", MODE_X)); } -TEST(DConcurrency, MultipleConflictingDBLocksOnSameThread) { - MMAPV1LockerImpl ls; - - Lock::DBLock r1(&ls, "db1", MODE_X); - Lock::DBLock r2(&ls, "db1", MODE_S); +TEST_F(DConcurrencyTestFixture, MultipleConflictingDBLocksOnSameThread) { + auto opCtx = makeOpCtx(); + opCtx->setLockState(stdx::make_unique<MMAPV1LockerImpl>()); + auto lockState = opCtx->lockState(); + Lock::DBLock r1(opCtx.get(), "db1", MODE_X); + Lock::DBLock r2(opCtx.get(), "db1", MODE_S); - ASSERT(ls.isDbLockedForMode("db1", MODE_X)); - ASSERT(ls.isDbLockedForMode("db1", MODE_S)); + ASSERT(lockState->isDbLockedForMode("db1", MODE_X)); + ASSERT(lockState->isDbLockedForMode("db1", MODE_S)); } -TEST(DConcurrency, IsDbLockedForSMode) { +TEST_F(DConcurrencyTestFixture, IsDbLockedForSMode) { const std::string dbName("db"); - MMAPV1LockerImpl ls; + auto opCtx = makeOpCtx(); + opCtx->setLockState(stdx::make_unique<MMAPV1LockerImpl>()); + auto lockState = opCtx->lockState(); + Lock::DBLock dbLock(opCtx.get(), dbName, MODE_S); - Lock::DBLock dbLock(&ls, dbName, MODE_S); - - ASSERT(ls.isDbLockedForMode(dbName, MODE_IS)); - ASSERT(!ls.isDbLockedForMode(dbName, MODE_IX)); - ASSERT(ls.isDbLockedForMode(dbName, MODE_S)); - ASSERT(!ls.isDbLockedForMode(dbName, MODE_X)); + ASSERT(lockState->isDbLockedForMode(dbName, MODE_IS)); + ASSERT(!lockState->isDbLockedForMode(dbName, MODE_IX)); + ASSERT(lockState->isDbLockedForMode(dbName, MODE_S)); + ASSERT(!lockState->isDbLockedForMode(dbName, MODE_X)); } -TEST(DConcurrency, IsDbLockedForXMode) { +TEST_F(DConcurrencyTestFixture, IsDbLockedForXMode) { const std::string dbName("db"); - MMAPV1LockerImpl ls; - - Lock::DBLock dbLock(&ls, dbName, MODE_X); + auto opCtx = makeOpCtx(); + opCtx->setLockState(stdx::make_unique<MMAPV1LockerImpl>()); + auto lockState = opCtx->lockState(); + Lock::DBLock dbLock(opCtx.get(), dbName, MODE_X); - ASSERT(ls.isDbLockedForMode(dbName, MODE_IS)); - ASSERT(ls.isDbLockedForMode(dbName, MODE_IX)); - ASSERT(ls.isDbLockedForMode(dbName, MODE_S)); - ASSERT(ls.isDbLockedForMode(dbName, MODE_X)); + ASSERT(lockState->isDbLockedForMode(dbName, MODE_IS)); + ASSERT(lockState->isDbLockedForMode(dbName, MODE_IX)); + ASSERT(lockState->isDbLockedForMode(dbName, MODE_S)); + ASSERT(lockState->isDbLockedForMode(dbName, MODE_X)); } -TEST(DConcurrency, IsCollectionLocked_DB_Locked_IS) { +TEST_F(DConcurrencyTestFixture, IsCollectionLocked_DB_Locked_IS) { const std::string ns("db1.coll"); - MMAPV1LockerImpl ls; + auto opCtx = makeOpCtx(); + opCtx->setLockState(stdx::make_unique<MMAPV1LockerImpl>()); + auto lockState = opCtx->lockState(); - Lock::DBLock dbLock(&ls, "db1", MODE_IS); + Lock::DBLock dbLock(opCtx.get(), "db1", MODE_IS); { - Lock::CollectionLock collLock(&ls, ns, MODE_IS); + Lock::CollectionLock collLock(lockState, ns, MODE_IS); - ASSERT(ls.isCollectionLockedForMode(ns, MODE_IS)); - ASSERT(!ls.isCollectionLockedForMode(ns, MODE_IX)); + ASSERT(lockState->isCollectionLockedForMode(ns, MODE_IS)); + ASSERT(!lockState->isCollectionLockedForMode(ns, MODE_IX)); // TODO: This is TRUE because Lock::CollectionLock converts IS lock to S - ASSERT(ls.isCollectionLockedForMode(ns, MODE_S)); + ASSERT(lockState->isCollectionLockedForMode(ns, MODE_S)); - ASSERT(!ls.isCollectionLockedForMode(ns, MODE_X)); + ASSERT(!lockState->isCollectionLockedForMode(ns, MODE_X)); } { - Lock::CollectionLock collLock(&ls, ns, MODE_S); + Lock::CollectionLock collLock(lockState, ns, MODE_S); - ASSERT(ls.isCollectionLockedForMode(ns, MODE_IS)); - ASSERT(!ls.isCollectionLockedForMode(ns, MODE_IX)); - ASSERT(ls.isCollectionLockedForMode(ns, MODE_S)); - ASSERT(!ls.isCollectionLockedForMode(ns, MODE_X)); + ASSERT(lockState->isCollectionLockedForMode(ns, MODE_IS)); + ASSERT(!lockState->isCollectionLockedForMode(ns, MODE_IX)); + ASSERT(lockState->isCollectionLockedForMode(ns, MODE_S)); + ASSERT(!lockState->isCollectionLockedForMode(ns, MODE_X)); } } -TEST(DConcurrency, IsCollectionLocked_DB_Locked_IX) { +TEST_F(DConcurrencyTestFixture, IsCollectionLocked_DB_Locked_IX) { const std::string ns("db1.coll"); - MMAPV1LockerImpl ls; + auto opCtx = makeOpCtx(); + opCtx->setLockState(stdx::make_unique<MMAPV1LockerImpl>()); + auto lockState = opCtx->lockState(); - Lock::DBLock dbLock(&ls, "db1", MODE_IX); + Lock::DBLock dbLock(opCtx.get(), "db1", MODE_IX); { - Lock::CollectionLock collLock(&ls, ns, MODE_IX); + Lock::CollectionLock collLock(lockState, ns, MODE_IX); // TODO: This is TRUE because Lock::CollectionLock converts IX lock to X - ASSERT(ls.isCollectionLockedForMode(ns, MODE_IS)); + ASSERT(lockState->isCollectionLockedForMode(ns, MODE_IS)); - ASSERT(ls.isCollectionLockedForMode(ns, MODE_IX)); - ASSERT(ls.isCollectionLockedForMode(ns, MODE_S)); - ASSERT(ls.isCollectionLockedForMode(ns, MODE_X)); + ASSERT(lockState->isCollectionLockedForMode(ns, MODE_IX)); + ASSERT(lockState->isCollectionLockedForMode(ns, MODE_S)); + ASSERT(lockState->isCollectionLockedForMode(ns, MODE_X)); } { - Lock::CollectionLock collLock(&ls, ns, MODE_X); + Lock::CollectionLock collLock(lockState, ns, MODE_X); - ASSERT(ls.isCollectionLockedForMode(ns, MODE_IS)); - ASSERT(ls.isCollectionLockedForMode(ns, MODE_IX)); - ASSERT(ls.isCollectionLockedForMode(ns, MODE_S)); - ASSERT(ls.isCollectionLockedForMode(ns, MODE_X)); + ASSERT(lockState->isCollectionLockedForMode(ns, MODE_IS)); + ASSERT(lockState->isCollectionLockedForMode(ns, MODE_IX)); + ASSERT(lockState->isCollectionLockedForMode(ns, MODE_S)); + ASSERT(lockState->isCollectionLockedForMode(ns, MODE_X)); } } -TEST(DConcurrency, Stress) { +TEST_F(DConcurrencyTestFixture, Stress) { const int kNumIterations = 5000; ProgressMeter progressMeter(kNumIterations * kMaxStressThreads); - std::array<DefaultLockerImpl, kMaxStressThreads> locker; + std::vector<std::pair<ServiceContext::UniqueClient, ServiceContext::UniqueOperationContext>> + clients = makeKClientsWithLockers<DefaultLockerImpl>(kMaxStressThreads); AtomicInt32 ready{0}; std::vector<stdx::thread> threads; - for (int threadId = 0; threadId < kMaxStressThreads; threadId++) + + for (int threadId = 0; threadId < kMaxStressThreads; threadId++) { threads.emplace_back([&, threadId]() { // Busy-wait until everybody is ready ready.fetchAndAdd(1); @@ -485,119 +535,119 @@ TEST(DConcurrency, Stress) { const bool sometimes = (std::rand() % 15 == 0); if (i % 7 == 0 && threadId == 0 /* Only one upgrader legal */) { - Lock::GlobalWrite w(&locker[threadId]); + Lock::GlobalWrite w(clients[threadId].second.get()); if (i % 7 == 2) { - Lock::TempRelease t(&locker[threadId]); + Lock::TempRelease t(clients[threadId].second->lockState()); } - ASSERT(locker[threadId].isW()); + ASSERT(clients[threadId].second->lockState()->isW()); } else if (i % 7 == 1) { - Lock::GlobalRead r(&locker[threadId]); - ASSERT(locker[threadId].isReadLocked()); + Lock::GlobalRead r(clients[threadId].second.get()); + ASSERT(clients[threadId].second->lockState()->isReadLocked()); } else if (i % 7 == 2) { - Lock::GlobalWrite w(&locker[threadId]); + Lock::GlobalWrite w(clients[threadId].second.get()); if (sometimes) { - Lock::TempRelease t(&locker[threadId]); + Lock::TempRelease t(clients[threadId].second->lockState()); } - ASSERT(locker[threadId].isW()); + ASSERT(clients[threadId].second->lockState()->isW()); } else if (i % 7 == 3) { - Lock::GlobalWrite w(&locker[threadId]); - { Lock::TempRelease t(&locker[threadId]); } + Lock::GlobalWrite w(clients[threadId].second.get()); + { Lock::TempRelease t(clients[threadId].second->lockState()); } - Lock::GlobalRead r(&locker[threadId]); + Lock::GlobalRead r(clients[threadId].second.get()); if (sometimes) { - Lock::TempRelease t(&locker[threadId]); + Lock::TempRelease t(clients[threadId].second->lockState()); } - ASSERT(locker[threadId].isW()); + ASSERT(clients[threadId].second->lockState()->isW()); } else if (i % 7 == 4) { - Lock::GlobalRead r(&locker[threadId]); - Lock::GlobalRead r2(&locker[threadId]); - ASSERT(locker[threadId].isReadLocked()); + Lock::GlobalRead r(clients[threadId].second.get()); + Lock::GlobalRead r2(clients[threadId].second.get()); + ASSERT(clients[threadId].second->lockState()->isReadLocked()); } else if (i % 7 == 5) { - { Lock::DBLock r(&locker[threadId], "foo", MODE_S); } - { Lock::DBLock r(&locker[threadId], "bar", MODE_S); } + { Lock::DBLock r(clients[threadId].second.get(), "foo", MODE_S); } + { Lock::DBLock r(clients[threadId].second.get(), "bar", MODE_S); } } else if (i % 7 == 6) { if (i > kNumIterations / 2) { int q = i % 11; if (q == 0) { - Lock::DBLock r(&locker[threadId], "foo", MODE_S); - ASSERT(locker[threadId].isDbLockedForMode("foo", MODE_S)); - - Lock::DBLock r2(&locker[threadId], "foo", MODE_S); - ASSERT(locker[threadId].isDbLockedForMode("foo", MODE_S)); - - Lock::DBLock r3(&locker[threadId], "local", MODE_S); - ASSERT(locker[threadId].isDbLockedForMode("foo", MODE_S)); - ASSERT(locker[threadId].isDbLockedForMode("local", MODE_S)); + Lock::DBLock r(clients[threadId].second.get(), "foo", MODE_S); + ASSERT(clients[threadId].second->lockState()->isDbLockedForMode( + "foo", MODE_S)); + + Lock::DBLock r2(clients[threadId].second.get(), "foo", MODE_S); + ASSERT(clients[threadId].second->lockState()->isDbLockedForMode( + "foo", MODE_S)); + + Lock::DBLock r3(clients[threadId].second.get(), "local", MODE_S); + ASSERT(clients[threadId].second->lockState()->isDbLockedForMode( + "foo", MODE_S)); + ASSERT(clients[threadId].second->lockState()->isDbLockedForMode( + "local", MODE_S)); } else if (q == 1) { // test locking local only -- with no preceding lock - { Lock::DBLock x(&locker[threadId], "local", MODE_S); } + { Lock::DBLock x(clients[threadId].second.get(), "local", MODE_S); } - Lock::DBLock x(&locker[threadId], "local", MODE_X); + Lock::DBLock x(clients[threadId].second.get(), "local", MODE_X); if (sometimes) { - Lock::TempRelease t(&locker[threadId]); + Lock::TempRelease t(clients[threadId].second.get()->lockState()); } } else if (q == 2) { - { Lock::DBLock x(&locker[threadId], "admin", MODE_S); } - { Lock::DBLock x(&locker[threadId], "admin", MODE_X); } + { Lock::DBLock x(clients[threadId].second.get(), "admin", MODE_S); } + { Lock::DBLock x(clients[threadId].second.get(), "admin", MODE_X); } } else if (q == 3) { - Lock::DBLock x(&locker[threadId], "foo", MODE_X); - Lock::DBLock y(&locker[threadId], "admin", MODE_S); + Lock::DBLock x(clients[threadId].second.get(), "foo", MODE_X); + Lock::DBLock y(clients[threadId].second.get(), "admin", MODE_S); } else if (q == 4) { - Lock::DBLock x(&locker[threadId], "foo2", MODE_S); - Lock::DBLock y(&locker[threadId], "admin", MODE_S); + Lock::DBLock x(clients[threadId].second.get(), "foo2", MODE_S); + Lock::DBLock y(clients[threadId].second.get(), "admin", MODE_S); } else if (q == 5) { - Lock::DBLock x(&locker[threadId], "foo", MODE_IS); + Lock::DBLock x(clients[threadId].second.get(), "foo", MODE_IS); } else if (q == 6) { - Lock::DBLock x(&locker[threadId], "foo", MODE_IX); - Lock::DBLock y(&locker[threadId], "local", MODE_IX); + Lock::DBLock x(clients[threadId].second.get(), "foo", MODE_IX); + Lock::DBLock y(clients[threadId].second.get(), "local", MODE_IX); } else { - Lock::DBLock w(&locker[threadId], "foo", MODE_X); + Lock::DBLock w(clients[threadId].second.get(), "foo", MODE_X); - { Lock::TempRelease t(&locker[threadId]); } + { Lock::TempRelease t(clients[threadId].second->lockState()); } - Lock::DBLock r2(&locker[threadId], "foo", MODE_S); - Lock::DBLock r3(&locker[threadId], "local", MODE_S); + Lock::DBLock r2(clients[threadId].second.get(), "foo", MODE_S); + Lock::DBLock r3(clients[threadId].second.get(), "local", MODE_S); } } else { - Lock::DBLock r(&locker[threadId], "foo", MODE_S); - Lock::DBLock r2(&locker[threadId], "foo", MODE_S); - Lock::DBLock r3(&locker[threadId], "local", MODE_S); + Lock::DBLock r(clients[threadId].second.get(), "foo", MODE_S); + Lock::DBLock r2(clients[threadId].second.get(), "foo", MODE_S); + Lock::DBLock r3(clients[threadId].second.get(), "local", MODE_S); } } progressMeter.hit(); } }); + } for (auto& thread : threads) thread.join(); - { - MMAPV1LockerImpl ls; - Lock::GlobalWrite w(&ls); - } - - { - MMAPV1LockerImpl ls; - Lock::GlobalRead r(&ls); - } + auto newClients = makeKClientsWithLockers<MMAPV1LockerImpl>(2); + { Lock::GlobalWrite w(newClients[0].second.get()); } + { Lock::GlobalRead r(newClients[1].second.get()); } } -TEST(DConcurrency, StressPartitioned) { +TEST_F(DConcurrencyTestFixture, StressPartitioned) { const int kNumIterations = 5000; ProgressMeter progressMeter(kNumIterations * kMaxStressThreads); - std::array<DefaultLockerImpl, kMaxStressThreads> locker; + std::vector<std::pair<ServiceContext::UniqueClient, ServiceContext::UniqueOperationContext>> + clients = makeKClientsWithLockers<DefaultLockerImpl>(kMaxStressThreads); AtomicInt32 ready{0}; std::vector<stdx::thread> threads; - for (int threadId = 0; threadId < kMaxStressThreads; threadId++) + for (int threadId = 0; threadId < kMaxStressThreads; threadId++) { threads.emplace_back([&, threadId]() { // Busy-wait until everybody is ready ready.fetchAndAdd(1); @@ -607,10 +657,10 @@ TEST(DConcurrency, StressPartitioned) { for (int i = 0; i < kNumIterations; i++) { if (threadId == 0) { if (i % 100 == 0) { - Lock::GlobalWrite w(&locker[threadId]); + Lock::GlobalWrite w(clients[threadId].second.get()); continue; } else if (i % 100 == 1) { - Lock::GlobalRead w(&locker[threadId]); + Lock::GlobalRead w(clients[threadId].second.get()); continue; } @@ -618,31 +668,26 @@ TEST(DConcurrency, StressPartitioned) { } if (i % 2 == 0) { - Lock::DBLock x(&locker[threadId], "foo", MODE_IS); + Lock::DBLock x(clients[threadId].second.get(), "foo", MODE_IS); } else { - Lock::DBLock x(&locker[threadId], "foo", MODE_IX); - Lock::DBLock y(&locker[threadId], "local", MODE_IX); + Lock::DBLock x(clients[threadId].second.get(), "foo", MODE_IX); + Lock::DBLock y(clients[threadId].second.get(), "local", MODE_IX); } progressMeter.hit(); } }); + } for (auto& thread : threads) thread.join(); - { - MMAPV1LockerImpl ls; - Lock::GlobalWrite w(&ls); - } - - { - MMAPV1LockerImpl ls; - Lock::GlobalRead r(&ls); - } + auto newClients = makeKClientsWithLockers<MMAPV1LockerImpl>(2); + { Lock::GlobalWrite w(newClients[0].second.get()); } + { Lock::GlobalRead r(newClients[1].second.get()); } } -TEST(DConcurrency, ResourceMutexLabels) { +TEST_F(DConcurrencyTestFixture, ResourceMutexLabels) { Lock::ResourceMutex mutex("label"); ASSERT(mutex.getName() == "label"); Lock::ResourceMutex mutex2("label2"); @@ -653,64 +698,68 @@ TEST(DConcurrency, ResourceMutexLabels) { // These tests exercise single- and multi-threaded performance of uncontended lock acquisition. It // is neither practical nor useful to run them on debug builds. -TEST(Locker, PerformanceStdMutex) { +TEST_F(DConcurrencyTestFixture, PerformanceStdMutex) { stdx::mutex mtx; perfTest([&](int threadId) { stdx::unique_lock<stdx::mutex> lk(mtx); }, kMaxPerfThreads); } -TEST(Locker, PerformanceResourceMutexShared) { +TEST_F(DConcurrencyTestFixture, PerformanceResourceMutexShared) { Lock::ResourceMutex mtx("testMutex"); std::array<DefaultLockerImpl, kMaxPerfThreads> locker; perfTest([&](int threadId) { Lock::SharedLock lk(&locker[threadId], mtx); }, kMaxPerfThreads); } -TEST(Locker, PerformanceResourceMutexExclusive) { +TEST_F(DConcurrencyTestFixture, PerformanceResourceMutexExclusive) { Lock::ResourceMutex mtx("testMutex"); std::array<DefaultLockerImpl, kMaxPerfThreads> locker; perfTest([&](int threadId) { Lock::ExclusiveLock lk(&locker[threadId], mtx); }, kMaxPerfThreads); } -TEST(Locker, PerformanceCollectionIntentSharedLock) { - std::array<DefaultLockerImpl, kMaxPerfThreads> locker; +TEST_F(DConcurrencyTestFixture, PerformanceCollectionIntentSharedLock) { + std::vector<std::pair<ServiceContext::UniqueClient, ServiceContext::UniqueOperationContext>> + clients = makeKClientsWithLockers<DefaultLockerImpl>(kMaxPerfThreads); ForceSupportsDocLocking supported(true); perfTest( [&](int threadId) { - Lock::DBLock dlk(&locker[threadId], "test", MODE_IS); - Lock::CollectionLock clk(&locker[threadId], "test.coll", MODE_IS); + Lock::DBLock dlk(clients[threadId].second.get(), "test", MODE_IS); + Lock::CollectionLock clk(clients[threadId].second->lockState(), "test.coll", MODE_IS); }, kMaxPerfThreads); } -TEST(Locker, PerformanceCollectionIntentExclusiveLock) { - std::array<DefaultLockerImpl, kMaxPerfThreads> locker; +TEST_F(DConcurrencyTestFixture, PerformanceCollectionIntentExclusiveLock) { + std::vector<std::pair<ServiceContext::UniqueClient, ServiceContext::UniqueOperationContext>> + clients = makeKClientsWithLockers<DefaultLockerImpl>(kMaxPerfThreads); ForceSupportsDocLocking supported(true); perfTest( [&](int threadId) { - Lock::DBLock dlk(&locker[threadId], "test", MODE_IX); - Lock::CollectionLock clk(&locker[threadId], "test.coll", MODE_IX); + Lock::DBLock dlk(clients[threadId].second.get(), "test", MODE_IX); + Lock::CollectionLock clk(clients[threadId].second->lockState(), "test.coll", MODE_IX); }, kMaxPerfThreads); } -TEST(Locker, PerformanceMMAPv1CollectionSharedLock) { - std::array<MMAPV1LockerImpl, kMaxPerfThreads> locker; +TEST_F(DConcurrencyTestFixture, PerformanceMMAPv1CollectionSharedLock) { + std::vector<std::pair<ServiceContext::UniqueClient, ServiceContext::UniqueOperationContext>> + clients = makeKClientsWithLockers<DefaultLockerImpl>(kMaxPerfThreads); ForceSupportsDocLocking supported(false); perfTest( [&](int threadId) { - Lock::DBLock dlk(&locker[threadId], "test", MODE_IS); - Lock::CollectionLock clk(&locker[threadId], "test.coll", MODE_S); + Lock::DBLock dlk(clients[threadId].second.get(), "test", MODE_IS); + Lock::CollectionLock clk(clients[threadId].second->lockState(), "test.coll", MODE_S); }, kMaxPerfThreads); } -TEST(Locker, PerformanceMMAPv1CollectionExclusive) { - std::array<MMAPV1LockerImpl, kMaxPerfThreads> locker; +TEST_F(DConcurrencyTestFixture, PerformanceMMAPv1CollectionExclusive) { + std::vector<std::pair<ServiceContext::UniqueClient, ServiceContext::UniqueOperationContext>> + clients = makeKClientsWithLockers<DefaultLockerImpl>(kMaxPerfThreads); ForceSupportsDocLocking supported(false); perfTest( [&](int threadId) { - Lock::DBLock dlk(&locker[threadId], "test", MODE_IX); - Lock::CollectionLock clk(&locker[threadId], "test.coll", MODE_X); + Lock::DBLock dlk(clients[threadId].second.get(), "test", MODE_IX); + Lock::CollectionLock clk(clients[threadId].second->lockState(), "test.coll", MODE_X); }, kMaxPerfThreads); } diff --git a/src/mongo/db/db.cpp b/src/mongo/db/db.cpp index 02294c9c71a..e6ae63880e3 100644 --- a/src/mongo/db/db.cpp +++ b/src/mongo/db/db.cpp @@ -197,8 +197,7 @@ void logStartup(OperationContext* opCtx) { BSONObj o = toLog.obj(); - ScopedTransaction transaction(opCtx, MODE_X); - Lock::GlobalWrite lk(opCtx->lockState()); + Lock::GlobalWrite lk(opCtx); AutoGetOrCreateDb autoDb(opCtx, startupLogCollectionName.db(), mongo::MODE_X); Database* db = autoDb.getDb(); Collection* collection = db->getCollection(startupLogCollectionName); @@ -255,6 +254,8 @@ void checkForIdIndexes(OperationContext* opCtx, Database* db) { * --replset. */ unsigned long long checkIfReplMissingFromCommandLine(OperationContext* opCtx) { + // This is helpful for the query below to work as you can't open files when readlocked + Lock::GlobalWrite lk(opCtx); if (!repl::getGlobalReplicationCoordinator()->getSettings().usingReplSets()) { DBDirectClient c(opCtx); return c.count(kSystemReplSetCollection.ns()); @@ -280,8 +281,7 @@ void checkForCappedOplog(OperationContext* opCtx, Database* db) { void repairDatabasesAndCheckVersion(OperationContext* opCtx) { LOG(1) << "enter repairDatabases (to check pdfile version #)"; - ScopedTransaction transaction(opCtx, MODE_X); - Lock::GlobalWrite lk(opCtx->lockState()); + Lock::GlobalWrite lk(opCtx); vector<string> dbNames; @@ -308,7 +308,7 @@ void repairDatabasesAndCheckVersion(OperationContext* opCtx) { // yet, then it will be created. If the mongod is running in a read-only mode, then it is // fine to not open the "local" database and populate the catalog entries because we won't // attempt to drop the temporary collections anyway. - Lock::DBLock dbLock(opCtx->lockState(), kSystemReplSetCollection.db(), MODE_X); + Lock::DBLock dbLock(opCtx, kSystemReplSetCollection.db(), MODE_X); dbHolder().openDb(opCtx, kSystemReplSetCollection.db()); } @@ -697,8 +697,7 @@ ExitCode _initAndListen(int listenPort) { if (!replSettings.usingReplSets() && !replSettings.isSlave() && storageGlobalParams.engine != "devnull") { - ScopedTransaction transaction(startupOpCtx.get(), MODE_X); - Lock::GlobalWrite lk(startupOpCtx.get()->lockState()); + Lock::GlobalWrite lk(startupOpCtx.get()); FeatureCompatibilityVersion::setIfCleanStartup( startupOpCtx.get(), repl::StorageInterface::get(getGlobalServiceContext())); } @@ -1020,8 +1019,7 @@ static void shutdownTask() { // // TODO: This call chain uses the locker directly, because we do not want to start an // operation context, which also instantiates a recovery unit. Also, using the - // lockGlobalBegin/lockGlobalComplete sequence, we avoid taking the flush lock. This will - // all go away if we start acquiring the global/flush lock as part of ScopedTransaction. + // lockGlobalBegin/lockGlobalComplete sequence, we avoid taking the flush lock. // // For a Windows service, dbexit does not call exit(), so we must leak the lock outside // of this function to prevent any operations from running that need a lock. diff --git a/src/mongo/db/db_raii.cpp b/src/mongo/db/db_raii.cpp index 051d9141ebf..84b6584b540 100644 --- a/src/mongo/db/db_raii.cpp +++ b/src/mongo/db/db_raii.cpp @@ -42,7 +42,7 @@ namespace mongo { AutoGetDb::AutoGetDb(OperationContext* opCtx, StringData ns, LockMode mode) - : _dbLock(opCtx->lockState(), ns, mode), _db(dbHolder().get(opCtx, ns)) {} + : _dbLock(opCtx, ns, mode), _db(dbHolder().get(opCtx, ns)) {} AutoGetCollection::AutoGetCollection(OperationContext* opCtx, const NamespaceString& nss, @@ -62,9 +62,7 @@ AutoGetCollection::AutoGetCollection(OperationContext* opCtx, } AutoGetOrCreateDb::AutoGetOrCreateDb(OperationContext* opCtx, StringData ns, LockMode mode) - : _transaction(opCtx, MODE_IX), - _dbLock(opCtx->lockState(), ns, mode), - _db(dbHolder().get(opCtx, ns)) { + : _dbLock(opCtx, ns, mode), _db(dbHolder().get(opCtx, ns)) { invariant(mode == MODE_IX || mode == MODE_X); _justCreated = false; // If the database didn't exist, relock in MODE_X @@ -79,36 +77,14 @@ AutoGetOrCreateDb::AutoGetOrCreateDb(OperationContext* opCtx, StringData ns, Loc AutoGetCollectionForRead::AutoGetCollectionForRead(OperationContext* opCtx, const NamespaceString& nss, - AutoGetCollection::ViewMode viewMode) - : _opCtx(opCtx), _transaction(opCtx, MODE_IS) { - { - _autoColl.emplace(opCtx, nss, MODE_IS, MODE_IS, viewMode); - - auto curOp = CurOp::get(_opCtx); - stdx::lock_guard<Client> lk(*_opCtx->getClient()); - - // TODO: OldClientContext legacy, needs to be removed - curOp->ensureStarted(); - curOp->setNS_inlock(nss.ns()); - - // At this point, we are locked in shared mode for the database by the DB lock in the - // constructor, so it is safe to load the DB pointer. - if (_autoColl->getDb()) { - // TODO: OldClientContext legacy, needs to be removed - curOp->enter_inlock(nss.ns().c_str(), _autoColl->getDb()->getProfilingLevel()); - } - } + AutoGetCollection::ViewMode viewMode) { + _autoColl.emplace(opCtx, nss, MODE_IS, MODE_IS, viewMode); // Note: this can yield. - _ensureMajorityCommittedSnapshotIsValid(nss); - - // We have both the DB and collection locked, which is the prerequisite to do a stable shard - // version check, but we'd like to do the check after we have a satisfactory snapshot. - auto css = CollectionShardingState::get(opCtx, nss); - css->checkShardVersionOrThrow(opCtx); + _ensureMajorityCommittedSnapshotIsValid(nss, opCtx); } -AutoGetCollectionForRead::~AutoGetCollectionForRead() { +AutoGetCollectionForReadCommand::~AutoGetCollectionForReadCommand() { // Report time spent in read lock auto currentOp = CurOp::get(_opCtx); Top::get(_opCtx->getClient()->getServiceContext()) @@ -121,7 +97,8 @@ AutoGetCollectionForRead::~AutoGetCollectionForRead() { currentOp->getReadWriteType()); } -void AutoGetCollectionForRead::_ensureMajorityCommittedSnapshotIsValid(const NamespaceString& nss) { +void AutoGetCollectionForRead::_ensureMajorityCommittedSnapshotIsValid(const NamespaceString& nss, + OperationContext* opCtx) { while (true) { auto coll = _autoColl->getCollection(); if (!coll) { @@ -131,7 +108,7 @@ void AutoGetCollectionForRead::_ensureMajorityCommittedSnapshotIsValid(const Nam if (!minSnapshot) { return; } - auto mySnapshot = _opCtx->recoveryUnit()->getMajorityCommittedSnapshot(); + auto mySnapshot = opCtx->recoveryUnit()->getMajorityCommittedSnapshot(); if (!mySnapshot) { return; } @@ -142,31 +119,58 @@ void AutoGetCollectionForRead::_ensureMajorityCommittedSnapshotIsValid(const Nam // Yield locks. _autoColl = boost::none; - repl::ReplicationCoordinator::get(_opCtx)->waitUntilSnapshotCommitted(_opCtx, *minSnapshot); + repl::ReplicationCoordinator::get(opCtx)->waitUntilSnapshotCommitted(opCtx, *minSnapshot); - uassertStatusOK(_opCtx->recoveryUnit()->setReadFromMajorityCommittedSnapshot()); + uassertStatusOK(opCtx->recoveryUnit()->setReadFromMajorityCommittedSnapshot()); { - stdx::lock_guard<Client> lk(*_opCtx->getClient()); - CurOp::get(_opCtx)->yielded(); + stdx::lock_guard<Client> lk(*opCtx->getClient()); + CurOp::get(opCtx)->yielded(); } // Relock. - _autoColl.emplace(_opCtx, nss, MODE_IS); + _autoColl.emplace(opCtx, nss, MODE_IS); + } +} + +AutoGetCollectionForReadCommand::AutoGetCollectionForReadCommand( + OperationContext* opCtx, const NamespaceString& nss, AutoGetCollection::ViewMode viewMode) + : _opCtx(opCtx) { + { + _autoCollForRead.emplace(opCtx, nss, viewMode); + + auto curOp = CurOp::get(_opCtx); + stdx::lock_guard<Client> lk(*_opCtx->getClient()); + + // TODO: OldClientContext legacy, needs to be removed + curOp->ensureStarted(); + curOp->setNS_inlock(nss.ns()); + + // At this point, we are locked in shared mode for the database by the DB lock in the + // constructor, so it is safe to load the DB pointer. + if (_autoCollForRead->getDb()) { + // TODO: OldClientContext legacy, needs to be removed + curOp->enter_inlock(nss.ns().c_str(), _autoCollForRead->getDb()->getProfilingLevel()); + } } + + // We have both the DB and collection locked, which is the prerequisite to do a stable shard + // version check, but we'd like to do the check after we have a satisfactory snapshot. + auto css = CollectionShardingState::get(opCtx, nss); + css->checkShardVersionOrThrow(opCtx); } -AutoGetCollectionOrViewForRead::AutoGetCollectionOrViewForRead(OperationContext* opCtx, - const NamespaceString& nss) - : AutoGetCollectionForRead(opCtx, nss, AutoGetCollection::ViewMode::kViewsPermitted), - _view(_autoColl->getDb() && !getCollection() - ? _autoColl->getDb()->getViewCatalog()->lookup(opCtx, nss.ns()) +AutoGetCollectionOrViewForReadCommand::AutoGetCollectionOrViewForReadCommand( + OperationContext* opCtx, const NamespaceString& nss) + : AutoGetCollectionForReadCommand(opCtx, nss, AutoGetCollection::ViewMode::kViewsPermitted), + _view(_autoCollForRead->getDb() && !getCollection() + ? _autoCollForRead->getDb()->getViewCatalog()->lookup(opCtx, nss.ns()) : nullptr) {} -void AutoGetCollectionOrViewForRead::releaseLocksForView() noexcept { +void AutoGetCollectionOrViewForReadCommand::releaseLocksForView() noexcept { invariant(_view); _view = nullptr; - _autoColl = boost::none; + _autoCollForRead = boost::none; } OldClientContext::OldClientContext(OperationContext* opCtx, diff --git a/src/mongo/db/db_raii.h b/src/mongo/db/db_raii.h index 04d1658b24d..8060d06f000 100644 --- a/src/mongo/db/db_raii.h +++ b/src/mongo/db/db_raii.h @@ -46,6 +46,9 @@ class Collection; * RAII-style class, which acquires a lock on the specified database in the requested mode and * obtains a reference to the database. Used as a shortcut for calls to dbHolder().get(). * + * Use this when you want to do a database-level operation, like read a list of all collections, or + * drop a collection. + * * It is guaranteed that the lock will be released when this object goes out of scope, therefore * the database reference returned by this class should not be retained. */ @@ -68,6 +71,10 @@ private: * RAII-style class, which acquires a locks on the specified database and collection in the * requested mode and obtains references to both. * + * Use this when you want to access something at the collection level, but do not want to do any of + * the tasks associated with the 'ForRead' variants below. For example, you can use this to access a + * Collection's CursorManager, or to remove a document. + * * It is guaranteed that locks will be released when this object goes out of scope, therefore * the database and the collection references returned by this class should not be retained. */ @@ -87,10 +94,10 @@ public: : AutoGetCollection(opCtx, nss, modeDB, modeColl, ViewMode::kViewsForbidden) {} /** - * This constructor is inteded for internal use and should not be used outside this file. - * AutoGetCollectionForRead and AutoGetCollectionOrViewForRead use ViewMode to determine whether - * or not it is permissible to obtain a handle on a view namespace. Use another constructor or - * another AutoGet class instead. + * This constructor is intended for internal use and should not be used outside this file. + * AutoGetCollectionForReadCommand and AutoGetCollectionOrViewForReadCommand use 'viewMode' to + * determine whether or not it is permissible to obtain a handle on a view namespace. Use + * another constructor or another 'AutoGet' class instead. */ AutoGetCollection(OperationContext* opCtx, const NamespaceString& nss, @@ -98,10 +105,16 @@ public: LockMode modeColl, ViewMode viewMode); + /** + * Returns nullptr if the database didn't exist. + */ Database* getDb() const { return _autoDb.getDb(); } + /** + * Returns nullptr if the collection didn't exist. + */ Collection* getCollection() const { return _coll; } @@ -115,7 +128,8 @@ private: Collection* const _coll; friend class AutoGetCollectionForRead; - friend class AutoGetCollectionOrViewForRead; + friend class AutoGetCollectionForReadCommand; + friend class AutoGetCollectionOrViewForReadCommand; }; /** @@ -125,6 +139,9 @@ private: * MODE_IX or MODE_X. If the database needs to be created, the lock will automatically be * reacquired as MODE_X. * + * Use this when you are about to perform a write, and want to create the database if it doesn't + * already exist. + * * It is guaranteed that locks will be released when this object goes out of scope, therefore * the database reference returned by this class should not be retained. */ @@ -147,17 +164,20 @@ public: } private: - ScopedTransaction _transaction; Lock::DBLock _dbLock; // not const, as we may need to relock for implicit create Database* _db; bool _justCreated; }; /** - * RAII-style class, which would acquire the appropritate hierarchy of locks for obtaining + * RAII-style class, which would acquire the appropriate hierarchy of locks for obtaining * a particular collection and would retrieve a reference to the collection. In addition, this - * utility validates the shard version for the specified namespace and sets the current operation's - * namespace for the duration while this object is alive. + * utility will ensure that the read will be performed against an appropriately committed snapshot + * if the operation is using a readConcern of 'majority'. + * + * Use this when you want to read the contents of a collection, but you are not at the top-level of + * some command. This will ensure your reads obey any requested readConcern, but will not update the + * status of CurrentOp, or add a Top entry. * * It is guaranteed that locks will be released when this object goes out of scope, therefore * database and collection references returned by this class should not be retained. @@ -169,7 +189,15 @@ public: AutoGetCollectionForRead(OperationContext* opCtx, const NamespaceString& nss) : AutoGetCollectionForRead(opCtx, nss, AutoGetCollection::ViewMode::kViewsForbidden) {} - ~AutoGetCollectionForRead(); + /** + * This constructor is intended for internal use and should not be used outside this file. + * AutoGetCollectionForReadCommand and AutoGetCollectionOrViewForReadCommand use 'viewMode' to + * determine whether or not it is permissible to obtain a handle on a view namespace. Use + * another constructor or another 'AutoGet' class instead. + */ + AutoGetCollectionForRead(OperationContext* opCtx, + const NamespaceString& nss, + AutoGetCollection::ViewMode viewMode); Database* getDb() const { return _autoColl->getDb(); @@ -180,34 +208,73 @@ public: } private: - void _ensureMajorityCommittedSnapshotIsValid(const NamespaceString& nss); + void _ensureMajorityCommittedSnapshotIsValid(const NamespaceString& nss, + OperationContext* opCtx); - const Timer _timer; + boost::optional<AutoGetCollection> _autoColl; +}; + +/** + * RAII-style class, which would acquire the appropriate hierarchy of locks for obtaining + * a particular collection and would retrieve a reference to the collection. In addition, this + * utility validates the shard version for the specified namespace and sets the current operation's + * namespace for the duration while this object is alive. + * + * Use this when you are a read-only command and you know that your target namespace is a collection + * (not a view). In addition to ensuring your read obeys any requested readConcern, this will add a + * Top entry upon destruction and ensure the CurrentOp object has the right namespace and has + * started its timer. + * + * It is guaranteed that locks will be released when this object goes out of scope, therefore + * database and collection references returned by this class should not be retained. + */ +class AutoGetCollectionForReadCommand { + MONGO_DISALLOW_COPYING(AutoGetCollectionForReadCommand); + +public: + AutoGetCollectionForReadCommand(OperationContext* opCtx, const NamespaceString& nss) + : AutoGetCollectionForReadCommand( + opCtx, nss, AutoGetCollection::ViewMode::kViewsForbidden) {} + + ~AutoGetCollectionForReadCommand(); + + Database* getDb() const { + return _autoCollForRead->getDb(); + } + + Collection* getCollection() const { + return _autoCollForRead->getCollection(); + } + +private: OperationContext* const _opCtx; - const ScopedTransaction _transaction; + const Timer _timer; protected: - AutoGetCollectionForRead(OperationContext* opCtx, - const NamespaceString& nss, - AutoGetCollection::ViewMode viewMode); + AutoGetCollectionForReadCommand(OperationContext* opCtx, + const NamespaceString& nss, + AutoGetCollection::ViewMode viewMode); /** * This protected section must come after the private section because * AutoGetCollectionOrViewForRead needs access to _autoColl, but _autoColl must be initialized * after _transaction. */ - boost::optional<AutoGetCollection> _autoColl; + boost::optional<AutoGetCollectionForRead> _autoCollForRead; }; /** * RAII-style class for obtaining a collection or view for reading. The pointer to a view definition * is nullptr if it does not exist. + * + * Use this when you are a read-only command, but have not yet determined if the namespace is a view + * or a collection. */ -class AutoGetCollectionOrViewForRead final : public AutoGetCollectionForRead { - MONGO_DISALLOW_COPYING(AutoGetCollectionOrViewForRead); +class AutoGetCollectionOrViewForReadCommand final : public AutoGetCollectionForReadCommand { + MONGO_DISALLOW_COPYING(AutoGetCollectionOrViewForReadCommand); public: - AutoGetCollectionOrViewForRead(OperationContext* opCtx, const NamespaceString& nss); + AutoGetCollectionOrViewForReadCommand(OperationContext* opCtx, const NamespaceString& nss); ViewDefinition* getView() const { return _view.get(); diff --git a/src/mongo/db/dbhelpers.cpp b/src/mongo/db/dbhelpers.cpp index 265687697ff..ae26b591272 100644 --- a/src/mongo/db/dbhelpers.cpp +++ b/src/mongo/db/dbhelpers.cpp @@ -209,7 +209,7 @@ RecordId Helpers::findById(OperationContext* opCtx, } bool Helpers::getSingleton(OperationContext* opCtx, const char* ns, BSONObj& result) { - AutoGetCollectionForRead ctx(opCtx, NamespaceString(ns)); + AutoGetCollectionForReadCommand ctx(opCtx, NamespaceString(ns)); unique_ptr<PlanExecutor> exec(InternalPlanner::collectionScan( opCtx, ns, ctx.getCollection(), PlanExecutor::YIELD_MANUAL)); PlanExecutor::ExecState state = exec->getNext(&result, NULL); @@ -228,7 +228,7 @@ bool Helpers::getSingleton(OperationContext* opCtx, const char* ns, BSONObj& res } bool Helpers::getLast(OperationContext* opCtx, const char* ns, BSONObj& result) { - AutoGetCollectionForRead autoColl(opCtx, NamespaceString(ns)); + AutoGetCollectionForReadCommand autoColl(opCtx, NamespaceString(ns)); unique_ptr<PlanExecutor> exec(InternalPlanner::collectionScan(opCtx, ns, autoColl.getCollection(), @@ -319,7 +319,7 @@ long long Helpers::removeRange(OperationContext* opCtx, BSONObj max; { - AutoGetCollectionForRead ctx(opCtx, nss); + AutoGetCollectionForReadCommand ctx(opCtx, nss); Collection* collection = ctx.getCollection(); if (!collection) { warning(LogComponent::kSharding) diff --git a/src/mongo/db/exec/stagedebug_cmd.cpp b/src/mongo/db/exec/stagedebug_cmd.cpp index 8fd48430e7a..82642010760 100644 --- a/src/mongo/db/exec/stagedebug_cmd.cpp +++ b/src/mongo/db/exec/stagedebug_cmd.cpp @@ -164,7 +164,6 @@ public: // 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(opCtx, MODE_IX); AutoGetCollection autoColl(opCtx, nss, MODE_IX); // Make sure the collection is valid. diff --git a/src/mongo/db/ftdc/collector.cpp b/src/mongo/db/ftdc/collector.cpp index 4441f2ef126..78e4f0de60a 100644 --- a/src/mongo/db/ftdc/collector.cpp +++ b/src/mongo/db/ftdc/collector.cpp @@ -83,10 +83,7 @@ std::tuple<BSONObj, Date_t> FTDCCollectorCollection::collect(Client* client) { subObjBuilder.appendDate(kFTDCCollectStartField, now); - { - ScopedTransaction st(opCtx.get(), MODE_IS); - collector->collect(opCtx.get(), subObjBuilder); - } + collector->collect(opCtx.get(), subObjBuilder); end = client->getServiceContext()->getPreciseClockSource()->now(); subObjBuilder.appendDate(kFTDCCollectEndField, end); diff --git a/src/mongo/db/index_builder.cpp b/src/mongo/db/index_builder.cpp index 6cbfd6e4ae6..599f81bac74 100644 --- a/src/mongo/db/index_builder.cpp +++ b/src/mongo/db/index_builder.cpp @@ -94,8 +94,7 @@ void IndexBuilder::run() { } NamespaceString ns(_index["ns"].String()); - ScopedTransaction transaction(&opCtx, MODE_IX); - Lock::DBLock dlk(opCtx.lockState(), ns.db(), MODE_X); + Lock::DBLock dlk(&opCtx, ns.db(), MODE_X); OldClientContext ctx(&opCtx, ns.getSystemIndexesCollection()); Database* db = dbHolder().get(&opCtx, ns.db().toString()); diff --git a/src/mongo/db/index_builder.h b/src/mongo/db/index_builder.h index 926fd32a5cc..02c11695eb8 100644 --- a/src/mongo/db/index_builder.h +++ b/src/mongo/db/index_builder.h @@ -32,6 +32,7 @@ #include "mongo/base/status.h" #include "mongo/db/catalog/index_catalog.h" +#include "mongo/db/concurrency/d_concurrency.h" #include "mongo/db/jsobj.h" #include "mongo/platform/atomic_word.h" #include "mongo/util/background.h" diff --git a/src/mongo/db/index_rebuilder.cpp b/src/mongo/db/index_rebuilder.cpp index 17db2f26b64..94663701223 100644 --- a/src/mongo/db/index_rebuilder.cpp +++ b/src/mongo/db/index_rebuilder.cpp @@ -63,10 +63,8 @@ void checkNS(OperationContext* opCtx, const std::list<std::string>& nsToCheck) { LOG(3) << "IndexRebuilder::checkNS: " << ns; - // This write lock is held throughout the index building process - // for this namespace. - ScopedTransaction transaction(opCtx, MODE_IX); - Lock::DBLock lk(opCtx->lockState(), nsToDatabaseSubstring(ns), MODE_X); + // This write lock is held throughout the index building process for this namespace. + Lock::DBLock lk(opCtx, nsToDatabaseSubstring(ns), MODE_X); OldClientContext ctx(opCtx, ns); Collection* collection = ctx.db()->getCollection(ns); @@ -155,7 +153,6 @@ void restartInProgressIndexesFromLastShutdown(OperationContext* opCtx) { for (std::vector<std::string>::const_iterator dbName = dbNames.begin(); dbName < dbNames.end(); ++dbName) { - ScopedTransaction scopedXact(opCtx, MODE_IS); AutoGetDb autoDb(opCtx, *dbName, MODE_S); Database* db = autoDb.getDb(); diff --git a/src/mongo/db/introspect.cpp b/src/mongo/db/introspect.cpp index 9fe9dd117cd..f1e94735d5e 100644 --- a/src/mongo/db/introspect.cpp +++ b/src/mongo/db/introspect.cpp @@ -118,8 +118,6 @@ void profile(OperationContext* opCtx, NetworkOp op) { try { bool acquireDbXLock = false; while (true) { - ScopedTransaction scopedXact(opCtx, MODE_IX); - std::unique_ptr<AutoGetDb> autoGetDb; if (acquireDbXLock) { autoGetDb.reset(new AutoGetDb(opCtx, dbName, MODE_X)); diff --git a/src/mongo/db/matcher/expression_text.cpp b/src/mongo/db/matcher/expression_text.cpp index 9dcf093e591..a3d100bda9d 100644 --- a/src/mongo/db/matcher/expression_text.cpp +++ b/src/mongo/db/matcher/expression_text.cpp @@ -52,7 +52,6 @@ Status TextMatchExpression::init(OperationContext* opCtx, fts::TextIndexVersion version; { // Find text index. - ScopedTransaction transaction(opCtx, MODE_IS); AutoGetDb autoDb(opCtx, nss.db(), MODE_IS); Lock::CollectionLock collLock(opCtx->lockState(), nss.ns(), MODE_IS); Database* db = autoDb.getDb(); diff --git a/src/mongo/db/operation_context.h b/src/mongo/db/operation_context.h index ac558d668ab..87c0f159a7f 100644 --- a/src/mongo/db/operation_context.h +++ b/src/mongo/db/operation_context.h @@ -33,7 +33,8 @@ #include "mongo/base/disallow_copying.h" #include "mongo/base/status.h" #include "mongo/db/client.h" -#include "mongo/db/concurrency/d_concurrency.h" +#include "mongo/db/concurrency/locker.h" +#include "mongo/db/storage/recovery_unit.h" #include "mongo/db/storage/recovery_unit.h" #include "mongo/db/storage/storage_options.h" #include "mongo/db/write_concern_options.h" @@ -48,7 +49,6 @@ namespace mongo { class Client; class CurOp; -class Locker; class ProgressMeter; class ServiceContext; class StringData; @@ -504,37 +504,6 @@ private: bool _toplevel; }; - -/** - * RAII-style class to mark the scope of a transaction. ScopedTransactions may be nested. - * An outermost ScopedTransaction calls abandonSnapshot() 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* opCtx, LockMode mode) : _opCtx(opCtx) {} - - ~ScopedTransaction() { - if (!_opCtx->lockState()->isLocked()) { - _opCtx->recoveryUnit()->abandonSnapshot(); - } - } - -private: - OperationContext* _opCtx; -}; - namespace repl { /** * RAII-style class to turn off replicated writes. Writes do not create oplog entries while the diff --git a/src/mongo/db/ops/update.cpp b/src/mongo/db/ops/update.cpp index 4a02a753a78..9540b4f7ac3 100644 --- a/src/mongo/db/ops/update.cpp +++ b/src/mongo/db/ops/update.cpp @@ -87,8 +87,7 @@ UpdateResult update(OperationContext* opCtx, Database* db, const UpdateRequest& locker->isLockHeldForMode(ResourceId(RESOURCE_DATABASE, nsString.db()), MODE_X)); MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { - ScopedTransaction transaction(opCtx, MODE_IX); - Lock::DBLock lk(opCtx->lockState(), nsString.db(), MODE_X); + Lock::DBLock lk(opCtx, nsString.db(), MODE_X); const bool userInitiatedWritesAndNotPrimary = opCtx->writesAreReplicated() && !repl::getGlobalReplicationCoordinator()->canAcceptWritesFor(opCtx, nsString); diff --git a/src/mongo/db/ops/write_ops_exec.cpp b/src/mongo/db/ops/write_ops_exec.cpp index a0d0f067333..60f0b7c79b6 100644 --- a/src/mongo/db/ops/write_ops_exec.cpp +++ b/src/mongo/db/ops/write_ops_exec.cpp @@ -506,7 +506,6 @@ static WriteResult::SingleResult performSingleUpdateOp(OperationContext* opCtx, ParsedUpdate parsedUpdate(opCtx, &request); uassertStatusOK(parsedUpdate.parseRequest()); - ScopedTransaction scopedXact(opCtx, MODE_IX); boost::optional<AutoGetCollection> collection; while (true) { opCtx->checkForInterrupt(); @@ -631,7 +630,6 @@ static WriteResult::SingleResult performSingleDeleteOp(OperationContext* opCtx, uasserted(ErrorCodes::InternalError, "failAllRemoves failpoint active!"); } - ScopedTransaction scopedXact(opCtx, MODE_IX); AutoGetCollection collection(opCtx, ns, MODE_IX, // DB is always IX, even if collection is X. diff --git a/src/mongo/db/pipeline/pipeline_d.cpp b/src/mongo/db/pipeline/pipeline_d.cpp index c1d6dc743ac..262deeb140b 100644 --- a/src/mongo/db/pipeline/pipeline_d.cpp +++ b/src/mongo/db/pipeline/pipeline_d.cpp @@ -96,7 +96,7 @@ public: } bool isSharded(const NamespaceString& nss) final { - AutoGetCollectionForRead autoColl(_ctx->opCtx, nss); + AutoGetCollectionForReadCommand autoColl(_ctx->opCtx, nss); // TODO SERVER-24960: Use CollectionShardingState::collectionIsSharded() to confirm sharding // state. auto css = CollectionShardingState::get(_ctx->opCtx, nss); @@ -114,7 +114,7 @@ public: CollectionIndexUsageMap getIndexStats(OperationContext* opCtx, const NamespaceString& ns) final { - AutoGetCollectionForRead autoColl(opCtx, ns); + AutoGetCollectionForReadCommand autoColl(opCtx, ns); Collection* collection = autoColl.getCollection(); if (!collection) { @@ -149,7 +149,7 @@ public: const NamespaceString& targetNs, const BSONObj& originalCollectionOptions, const std::list<BSONObj>& originalIndexes) final { - Lock::GlobalWrite globalLock(_ctx->opCtx->lockState()); + Lock::GlobalWrite globalLock(_ctx->opCtx); if (SimpleBSONObjComparator::kInstance.evaluate(originalCollectionOptions != getCollectionOptions(targetNs))) { @@ -193,7 +193,7 @@ public: pipeline.getValue()->optimizePipeline(); - AutoGetCollectionForRead autoColl(expCtx->opCtx, expCtx->ns); + AutoGetCollectionForReadCommand autoColl(expCtx->opCtx, expCtx->ns); // makePipeline() is only called to perform secondary aggregation requests and expects the // collection representing the document source to be not-sharded. We confirm sharding state @@ -269,7 +269,7 @@ StatusWith<unique_ptr<PlanExecutor>> createRandomCursorExecutor(Collection* coll } { - AutoGetCollection autoColl(opCtx, collection->ns(), MODE_IS); + AutoGetCollectionForRead autoColl(opCtx, collection->ns()); // If we're in a sharded environment, we need to filter out documents we don't own. if (ShardingState::get(opCtx)->needCollectionMetadata(opCtx, collection->ns().ns())) { diff --git a/src/mongo/db/prefetch.cpp b/src/mongo/db/prefetch.cpp index 48d36f427d6..043f9bdd478 100644 --- a/src/mongo/db/prefetch.cpp +++ b/src/mongo/db/prefetch.cpp @@ -35,6 +35,7 @@ #include "mongo/db/catalog/collection.h" #include "mongo/db/catalog/database.h" #include "mongo/db/commands/server_status_metric.h" +#include "mongo/db/concurrency/d_concurrency.h" #include "mongo/db/dbhelpers.h" #include "mongo/db/index/index_access_method.h" #include "mongo/db/jsobj.h" diff --git a/src/mongo/db/query/find.cpp b/src/mongo/db/query/find.cpp index 9f709bd8485..44f69823096 100644 --- a/src/mongo/db/query/find.cpp +++ b/src/mongo/db/query/find.cpp @@ -256,7 +256,7 @@ Message getMore(OperationContext* opCtx, // Note that we declare our locks before our ClientCursorPin, in order to ensure that the // pin's destructor is called before the lock destructors (so that the unpin occurs under // the lock). - unique_ptr<AutoGetCollectionForRead> ctx; + unique_ptr<AutoGetCollectionForReadCommand> ctx; unique_ptr<Lock::DBLock> unpinDBLock; unique_ptr<Lock::CollectionLock> unpinCollLock; @@ -267,8 +267,8 @@ Message getMore(OperationContext* opCtx, // the data within a collection. cursorManager = CursorManager::getGlobalCursorManager(); } else { - ctx = stdx::make_unique<AutoGetCollectionOrViewForRead>(opCtx, nss); - auto viewCtx = static_cast<AutoGetCollectionOrViewForRead*>(ctx.get()); + ctx = stdx::make_unique<AutoGetCollectionOrViewForReadCommand>(opCtx, nss); + auto viewCtx = static_cast<AutoGetCollectionOrViewForReadCommand*>(ctx.get()); if (viewCtx->getView()) { uasserted( ErrorCodes::CommandNotSupportedOnView, @@ -414,7 +414,7 @@ Message getMore(OperationContext* opCtx, curOp.setExpectedLatencyMs(durationCount<Milliseconds>(timeout)); // Reacquiring locks. - ctx = make_unique<AutoGetCollectionForRead>(opCtx, nss); + ctx = make_unique<AutoGetCollectionForReadCommand>(opCtx, nss); exec->restoreState(); // We woke up because either the timed_wait expired, or there was more data. Either @@ -449,7 +449,7 @@ Message getMore(OperationContext* opCtx, // if the cursor is aggregation, we release these locks. if (cc->isAggCursor()) { invariant(NULL == ctx.get()); - unpinDBLock = make_unique<Lock::DBLock>(opCtx->lockState(), nss.db(), MODE_IS); + unpinDBLock = make_unique<Lock::DBLock>(opCtx, nss.db(), MODE_IS); unpinCollLock = make_unique<Lock::CollectionLock>(opCtx->lockState(), nss.ns(), MODE_IS); } @@ -531,7 +531,7 @@ std::string runQuery(OperationContext* opCtx, LOG(2) << "Running query: " << redact(cq->toStringShort()); // Parse, canonicalize, plan, transcribe, and get a plan executor. - AutoGetCollectionOrViewForRead ctx(opCtx, nss); + AutoGetCollectionOrViewForReadCommand ctx(opCtx, nss); Collection* collection = ctx.getCollection(); if (ctx.getView()) { diff --git a/src/mongo/db/read_concern.cpp b/src/mongo/db/read_concern.cpp index 2ae0cc45aee..80602ff2fce 100644 --- a/src/mongo/db/read_concern.cpp +++ b/src/mongo/db/read_concern.cpp @@ -35,6 +35,7 @@ #include "mongo/base/status.h" #include "mongo/base/status_with.h" #include "mongo/db/commands.h" +#include "mongo/db/concurrency/d_concurrency.h" #include "mongo/db/concurrency/write_conflict_exception.h" #include "mongo/db/curop.h" #include "mongo/db/op_observer.h" @@ -136,8 +137,7 @@ Status waitForLinearizableReadConcern(OperationContext* opCtx) { repl::ReplicationCoordinator::get(opCtx->getClient()->getServiceContext()); { - ScopedTransaction transaction(opCtx, MODE_IX); - Lock::DBLock lk(opCtx->lockState(), "local", MODE_IX); + Lock::DBLock lk(opCtx, "local", MODE_IX); Lock::CollectionLock lock(opCtx->lockState(), "local.oplog.rs", MODE_IX); if (!replCoord->canAcceptWritesForDatabase(opCtx, "admin")) { diff --git a/src/mongo/db/repl/bgsync.cpp b/src/mongo/db/repl/bgsync.cpp index c0211a21022..86cc962c926 100644 --- a/src/mongo/db/repl/bgsync.cpp +++ b/src/mongo/db/repl/bgsync.cpp @@ -660,8 +660,7 @@ OpTimeWithHash BackgroundSync::_readLastAppliedOpTimeWithHash(OperationContext* BSONObj oplogEntry; try { MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { - ScopedTransaction transaction(opCtx, MODE_IX); - Lock::DBLock lk(opCtx->lockState(), "local", MODE_X); + Lock::DBLock lk(opCtx, "local", MODE_X); bool success = Helpers::getLast(opCtx, rsOplogName.c_str(), oplogEntry); if (!success) { // This can happen when we are to do an initial sync. lastHash will be set diff --git a/src/mongo/db/repl/database_task.cpp b/src/mongo/db/repl/database_task.cpp index 5c4f9422ea9..41f29aff342 100644 --- a/src/mongo/db/repl/database_task.cpp +++ b/src/mongo/db/repl/database_task.cpp @@ -46,8 +46,7 @@ DatabaseTask::Task DatabaseTask::makeGlobalExclusiveLockTask(const Task& task) { return task(opCtx, status); } MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { - ScopedTransaction transaction(opCtx, MODE_X); - Lock::GlobalWrite lock(opCtx->lockState()); + Lock::GlobalWrite lock(opCtx); return task(opCtx, status); } MONGO_WRITE_CONFLICT_RETRY_LOOP_END(opCtx, "globalExclusiveLockTask", "global"); @@ -66,9 +65,7 @@ DatabaseTask::Task DatabaseTask::makeDatabaseLockTask(const Task& task, return task(opCtx, status); } MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { - LockMode permissiveLockMode = isSharedLockMode(mode) ? MODE_IS : MODE_IX; - ScopedTransaction transaction(opCtx, permissiveLockMode); - Lock::DBLock lock(opCtx->lockState(), databaseName, mode); + Lock::DBLock lock(opCtx, databaseName, mode); return task(opCtx, status); } MONGO_WRITE_CONFLICT_RETRY_LOOP_END(opCtx, "databaseLockTask", databaseName); @@ -88,8 +85,7 @@ DatabaseTask::Task DatabaseTask::makeCollectionLockTask(const Task& task, } MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { LockMode permissiveLockMode = isSharedLockMode(mode) ? MODE_IS : MODE_IX; - ScopedTransaction transaction(opCtx, permissiveLockMode); - Lock::DBLock lock(opCtx->lockState(), nss.db(), permissiveLockMode); + Lock::DBLock lock(opCtx, nss.db(), permissiveLockMode); Lock::CollectionLock collectionLock(opCtx->lockState(), nss.toString(), mode); return task(opCtx, status); } diff --git a/src/mongo/db/repl/master_slave.cpp b/src/mongo/db/repl/master_slave.cpp index f76856d2802..8b11676d9b1 100644 --- a/src/mongo/db/repl/master_slave.cpp +++ b/src/mongo/db/repl/master_slave.cpp @@ -196,8 +196,7 @@ void ReplSource::ensureMe(OperationContext* opCtx) { bool exists = Helpers::getSingleton(opCtx, "local.me", _me); if (!exists || !_me.hasField("host") || _me["host"].String() != myname) { - ScopedTransaction transaction(opCtx, MODE_IX); - Lock::DBLock dblk(opCtx->lockState(), "local", MODE_X); + Lock::DBLock dblk(opCtx, "local", MODE_X); WriteUnitOfWork wunit(opCtx); // clean out local.me Helpers::emptyCollection(opCtx, "local.me"); @@ -771,7 +770,7 @@ void ReplSource::_sync_pullOpLog_applyOperation(OperationContext* opCtx, } } - unique_ptr<Lock::GlobalWrite> lk(alreadyLocked ? 0 : new Lock::GlobalWrite(opCtx->lockState())); + unique_ptr<Lock::GlobalWrite> lk(alreadyLocked ? 0 : new Lock::GlobalWrite(opCtx)); if (replAllDead) { // hmmm why is this check here and not at top of this function? does it get set between top @@ -914,8 +913,7 @@ int ReplSource::_sync_pullOpLog(OperationContext* opCtx, int& nApplied) { } // obviously global isn't ideal, but non-repl set is old so // keeping it simple - ScopedTransaction transaction(opCtx, MODE_X); - Lock::GlobalWrite lk(opCtx->lockState()); + Lock::GlobalWrite lk(opCtx); save(opCtx); } @@ -977,8 +975,7 @@ int ReplSource::_sync_pullOpLog(OperationContext* opCtx, int& nApplied) { log() << ns << " oplog is empty" << endl; } { - ScopedTransaction transaction(opCtx, MODE_X); - Lock::GlobalWrite lk(opCtx->lockState()); + Lock::GlobalWrite lk(opCtx); save(opCtx); } return okResultCode; @@ -1045,8 +1042,7 @@ int ReplSource::_sync_pullOpLog(OperationContext* opCtx, int& nApplied) { const bool moreInitialSyncsPending = !addDbNextPass.empty() && n; if (moreInitialSyncsPending || !oplogReader.more()) { - ScopedTransaction transaction(opCtx, MODE_X); - Lock::GlobalWrite lk(opCtx->lockState()); + Lock::GlobalWrite lk(opCtx); if (tailing) { okResultCode = restartSync; // don't sleep @@ -1060,8 +1056,7 @@ int ReplSource::_sync_pullOpLog(OperationContext* opCtx, int& nApplied) { 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(opCtx, MODE_X); - Lock::GlobalWrite lk(opCtx->lockState()); + Lock::GlobalWrite lk(opCtx); syncedTo = nextOpTime; // can't update local log ts since there are pending operations from our peer save(opCtx); @@ -1075,8 +1070,7 @@ int ReplSource::_sync_pullOpLog(OperationContext* opCtx, int& nApplied) { int b = replApplyBatchSize.load(); bool justOne = b == 1; - unique_ptr<Lock::GlobalWrite> lk(justOne ? 0 - : new Lock::GlobalWrite(opCtx->lockState())); + unique_ptr<Lock::GlobalWrite> lk(justOne ? 0 : new Lock::GlobalWrite(opCtx)); while (1) { BSONElement ts = op.getField("ts"); if (!(ts.type() == Date || ts.type() == bsonTimestamp)) { @@ -1108,8 +1102,7 @@ int ReplSource::_sync_pullOpLog(OperationContext* opCtx, int& nApplied) { oplogReader.putBack(op); _sleepAdviceTime = nextOpTime.getSecs() + durationCount<Seconds>(replSettings.getSlaveDelaySecs()) + 1; - ScopedTransaction transaction(opCtx, MODE_X); - Lock::GlobalWrite lk(opCtx->lockState()); + Lock::GlobalWrite lk(opCtx); if (n > 0) { syncedTo = last; save(opCtx); @@ -1191,8 +1184,7 @@ _ reuse that cursor when we can int _replMain(OperationContext* opCtx, ReplSource::SourceVector& sources, int& nApplied) { { ReplInfo r("replMain load sources"); - ScopedTransaction transaction(opCtx, MODE_X); - Lock::GlobalWrite lk(opCtx->lockState()); + Lock::GlobalWrite lk(opCtx); ReplSource::loadAll(opCtx, sources); // only need this param for initial reset @@ -1254,8 +1246,7 @@ static void replMain(OperationContext* opCtx) { while (1) { auto s = restartSync; { - ScopedTransaction transaction(opCtx, MODE_X); - Lock::GlobalWrite lk(opCtx->lockState()); + Lock::GlobalWrite lk(opCtx); if (replAllDead) { // throttledForceResyncDead can throw if (!getGlobalReplicationCoordinator()->getSettings().isAutoResyncEnabled() || @@ -1288,8 +1279,7 @@ static void replMain(OperationContext* opCtx) { } { - ScopedTransaction transaction(opCtx, MODE_X); - Lock::GlobalWrite lk(opCtx->lockState()); + Lock::GlobalWrite lk(opCtx); invariant(syncing.swap(0) == 1); } @@ -1324,7 +1314,7 @@ static void replMasterThread() { OperationContext& opCtx = *opCtxPtr; AuthorizationSession::get(opCtx.getClient())->grantInternalAuthorization(); - Lock::GlobalWrite globalWrite(opCtx.lockState(), 1); + Lock::GlobalWrite globalWrite(&opCtx, 1); if (globalWrite.isLocked()) { toSleep = 10; @@ -1405,9 +1395,8 @@ void pretouchN(vector<BSONObj>& v, unsigned a, unsigned b) { Client::initThreadIfNotAlready("pretouchN"); const ServiceContext::UniqueOperationContext opCtxPtr = cc().makeOperationContext(); - OperationContext& opCtx = *opCtxPtr; - ScopedTransaction transaction(&opCtx, MODE_S); - Lock::GlobalRead lk(opCtx.lockState()); + OperationContext& opCtx = *opCtxPtr; // XXX + Lock::GlobalRead lk(&opCtx); for (unsigned i = a; i <= b; i++) { const BSONObj& op = v[i]; @@ -1464,7 +1453,7 @@ void pretouchOperation(OperationContext* opCtx, const BSONObj& op) { BSONObjBuilder b; b.append(_id); BSONObj result; - AutoGetCollectionForRead ctx(opCtx, NamespaceString(ns)); + AutoGetCollectionForReadCommand ctx(opCtx, NamespaceString(ns)); if (Helpers::findById(opCtx, ctx.getDb(), ns, b.done(), result)) { _dummy_z += result.objsize(); // touch } diff --git a/src/mongo/db/repl/noop_writer.cpp b/src/mongo/db/repl/noop_writer.cpp index f127b236614..926db4aff07 100644 --- a/src/mongo/db/repl/noop_writer.cpp +++ b/src/mongo/db/repl/noop_writer.cpp @@ -31,6 +31,7 @@ #include "mongo/platform/basic.h" #include "mongo/db/commands.h" +#include "mongo/db/concurrency/d_concurrency.h" #include "mongo/db/concurrency/write_conflict_exception.h" #include "mongo/db/curop.h" #include "mongo/db/op_observer.h" @@ -136,10 +137,9 @@ void NoopWriter::stopWritingPeriodicNoops() { } void NoopWriter::_writeNoop(OperationContext* opCtx) { - ScopedTransaction transaction(opCtx, MODE_IX); // Use GlobalLock + lockMMAPV1Flush instead of DBLock to allow return when the lock is not // available. It may happen when the primary steps down and a shared global lock is acquired. - Lock::GlobalLock lock(opCtx->lockState(), MODE_IX, 1); + Lock::GlobalLock lock(opCtx, MODE_IX, 1); if (!lock.isLocked()) { LOG(1) << "Global lock is not available skipping noopWrite"; return; diff --git a/src/mongo/db/repl/oplog.cpp b/src/mongo/db/repl/oplog.cpp index 3d5547ed526..258180af98a 100644 --- a/src/mongo/db/repl/oplog.cpp +++ b/src/mongo/db/repl/oplog.cpp @@ -298,7 +298,6 @@ OplogDocWriter _logOpWriter(OperationContext* opCtx, // Truncates the oplog after and including the "truncateTimestamp" entry. void truncateOplogTo(OperationContext* opCtx, Timestamp truncateTimestamp) { const NamespaceString oplogNss(rsOplogName); - ScopedTransaction transaction(opCtx, MODE_IX); AutoGetDb autoDb(opCtx, oplogNss.db(), MODE_IX); Lock::CollectionLock oplogCollectionLoc(opCtx->lockState(), oplogNss.ns(), MODE_X); Collection* oplogCollection = autoDb.getDb()->getCollection(oplogNss); @@ -402,7 +401,7 @@ void logOp(OperationContext* opCtx, ReplicationCoordinator* replCoord = getGlobalReplicationCoordinator(); Collection* oplog = getLocalOplogCollection(opCtx, _oplogCollectionName); - Lock::DBLock lk(opCtx->lockState(), "local", MODE_IX); + Lock::DBLock lk(opCtx, "local", MODE_IX); Lock::CollectionLock lock(opCtx->lockState(), _oplogCollectionName, MODE_IX); OplogSlot slot; getNextOpTime(opCtx, oplog, replCoord, replMode, 1, &slot); @@ -428,7 +427,7 @@ void logOps(OperationContext* opCtx, std::vector<OplogDocWriter> writers; writers.reserve(count); Collection* oplog = getLocalOplogCollection(opCtx, _oplogCollectionName); - Lock::DBLock lk(opCtx->lockState(), "local", MODE_IX); + Lock::DBLock lk(opCtx, "local", MODE_IX); Lock::CollectionLock lock(opCtx->lockState(), _oplogCollectionName, MODE_IX); std::unique_ptr<OplogSlot[]> slots(new OplogSlot[count]); getNextOpTime(opCtx, oplog, replCoord, replMode, count, slots.get()); @@ -490,8 +489,7 @@ long long getNewOplogSizeBytes(OperationContext* opCtx, const ReplSettings& repl } // namespace void createOplog(OperationContext* opCtx, const std::string& oplogCollectionName, bool isReplSet) { - ScopedTransaction transaction(opCtx, MODE_X); - Lock::GlobalWrite lk(opCtx->lockState()); + Lock::GlobalWrite lk(opCtx); const ReplSettings& replSettings = ReplicationCoordinator::get(opCtx)->getSettings(); @@ -1221,7 +1219,7 @@ void SnapshotThread::run() { try { auto opCtx = client.makeOperationContext(); - Lock::GlobalLock globalLock(opCtx->lockState(), MODE_IS, UINT_MAX); + Lock::GlobalLock globalLock(opCtx.get(), MODE_IS, UINT_MAX); if (!replCoord->getMemberState().readable()) { // If our MemberState isn't readable, we may not be in a consistent state so don't @@ -1253,7 +1251,7 @@ void SnapshotThread::run() { auto opTimeOfSnapshot = OpTime(); { - AutoGetCollectionForRead oplog(opCtx.get(), NamespaceString(rsOplogName)); + AutoGetCollectionForReadCommand oplog(opCtx.get(), NamespaceString(rsOplogName)); invariant(oplog.getCollection()); // Read the latest op from the oplog. auto cursor = oplog.getCollection()->getCursor(opCtx.get(), /*forward*/ false); diff --git a/src/mongo/db/repl/oplog_buffer_collection_test.cpp b/src/mongo/db/repl/oplog_buffer_collection_test.cpp index 1ee2c3ccc8c..3e7d172b7c8 100644 --- a/src/mongo/db/repl/oplog_buffer_collection_test.cpp +++ b/src/mongo/db/repl/oplog_buffer_collection_test.cpp @@ -71,8 +71,8 @@ void OplogBufferCollectionTest::setUp() { ServiceContextMongoDTest::setUp(); auto service = getServiceContext(); - // AutoGetCollectionForRead requires a valid replication coordinator in order to check the shard - // version. + // AutoGetCollectionForReadCommand requires a valid replication coordinator in order to check + // the shard version. ReplSettings replSettings; replSettings.setOplogSizeBytes(5 * 1024 * 1024); ReplicationCoordinator::set( @@ -137,10 +137,10 @@ void testStartupCreatesCollection(OperationContext* opCtx, OplogBufferCollection oplogBuffer(storageInterface, nss); // Collection should not exist until startup() is called. - ASSERT_FALSE(AutoGetCollectionForRead(opCtx, nss).getCollection()); + ASSERT_FALSE(AutoGetCollectionForReadCommand(opCtx, nss).getCollection()); oplogBuffer.startup(opCtx); - ASSERT_TRUE(AutoGetCollectionForRead(opCtx, nss).getCollection()); + ASSERT_TRUE(AutoGetCollectionForReadCommand(opCtx, nss).getCollection()); } TEST_F(OplogBufferCollectionTest, StartupWithDefaultNamespaceCreatesCollection) { @@ -158,7 +158,7 @@ TEST_F(OplogBufferCollectionTest, StartupDropsExistingCollectionBeforeCreatingNe ASSERT_OK(_storageInterface->createCollection(_opCtx.get(), nss, CollectionOptions())); OplogBufferCollection oplogBuffer(_storageInterface, nss); oplogBuffer.startup(_opCtx.get()); - ASSERT_TRUE(AutoGetCollectionForRead(_opCtx.get(), nss).getCollection()); + ASSERT_TRUE(AutoGetCollectionForReadCommand(_opCtx.get(), nss).getCollection()); } DEATH_TEST_F(OplogBufferCollectionTest, @@ -172,9 +172,9 @@ TEST_F(OplogBufferCollectionTest, ShutdownDropsCollection) { OplogBufferCollection oplogBuffer(_storageInterface, nss); oplogBuffer.startup(_opCtx.get()); - ASSERT_TRUE(AutoGetCollectionForRead(_opCtx.get(), nss).getCollection()); + ASSERT_TRUE(AutoGetCollectionForReadCommand(_opCtx.get(), nss).getCollection()); oplogBuffer.shutdown(_opCtx.get()); - ASSERT_FALSE(AutoGetCollectionForRead(_opCtx.get(), nss).getCollection()); + ASSERT_FALSE(AutoGetCollectionForReadCommand(_opCtx.get(), nss).getCollection()); } TEST_F(OplogBufferCollectionTest, extractEmbeddedOplogDocumentChangesIdToTimestamp) { @@ -542,7 +542,7 @@ TEST_F(OplogBufferCollectionTest, ClearClearsCollection) { _assertDocumentsInCollectionEquals(_opCtx.get(), nss, {oplog, sentinel, oplog2}); oplogBuffer.clear(_opCtx.get()); - ASSERT_TRUE(AutoGetCollectionForRead(_opCtx.get(), nss).getCollection()); + ASSERT_TRUE(AutoGetCollectionForReadCommand(_opCtx.get(), nss).getCollection()); ASSERT_EQUALS(oplogBuffer.getCount(), 0UL); ASSERT_EQUALS(oplogBuffer.getSize(), 0UL); ASSERT_EQUALS(0U, oplogBuffer.getSentinelCount_forTest()); diff --git a/src/mongo/db/repl/oplog_interface_local.cpp b/src/mongo/db/repl/oplog_interface_local.cpp index a68fd8db0d6..c27e8ea798e 100644 --- a/src/mongo/db/repl/oplog_interface_local.cpp +++ b/src/mongo/db/repl/oplog_interface_local.cpp @@ -48,7 +48,6 @@ public: StatusWith<Value> next() override; private: - ScopedTransaction _transaction; Lock::DBLock _dbLock; Lock::CollectionLock _collectionLock; OldClientContext _ctx; @@ -56,8 +55,7 @@ private: }; OplogIteratorLocal::OplogIteratorLocal(OperationContext* opCtx, const std::string& collectionName) - : _transaction(opCtx, MODE_IS), - _dbLock(opCtx->lockState(), nsToDatabase(collectionName), MODE_IS), + : _dbLock(opCtx, nsToDatabase(collectionName), MODE_IS), _collectionLock(opCtx->lockState(), collectionName, MODE_S), _ctx(opCtx, collectionName), _exec(InternalPlanner::collectionScan(opCtx, diff --git a/src/mongo/db/repl/repl_set_commands.cpp b/src/mongo/db/repl/repl_set_commands.cpp index ab756559784..dec36e4d1af 100644 --- a/src/mongo/db/repl/repl_set_commands.cpp +++ b/src/mongo/db/repl/repl_set_commands.cpp @@ -429,8 +429,7 @@ public: status = getGlobalReplicationCoordinator()->processReplSetReconfig(opCtx, parsedArgs, &result); - ScopedTransaction scopedXact(opCtx, MODE_X); - Lock::GlobalWrite globalWrite(opCtx->lockState()); + Lock::GlobalWrite globalWrite(opCtx); WriteUnitOfWork wuow(opCtx); if (status.isOK() && !parsedArgs.force) { diff --git a/src/mongo/db/repl/replication_coordinator_external_state_impl.cpp b/src/mongo/db/repl/replication_coordinator_external_state_impl.cpp index c2619816034..e85ec3c8095 100644 --- a/src/mongo/db/repl/replication_coordinator_external_state_impl.cpp +++ b/src/mongo/db/repl/replication_coordinator_external_state_impl.cpp @@ -365,9 +365,8 @@ OldThreadPool* ReplicationCoordinatorExternalStateImpl::getDbWorkThreadPool() co Status ReplicationCoordinatorExternalStateImpl::runRepairOnLocalDB(OperationContext* opCtx) { try { - ScopedTransaction scopedXact(opCtx, MODE_X); - Lock::GlobalWrite globalWrite(opCtx->lockState()); - StorageEngine* engine = _service->getGlobalStorageEngine(); + Lock::GlobalWrite globalWrite(opCtx); + StorageEngine* engine = getGlobalServiceContext()->getGlobalStorageEngine(); if (!engine->isMmapV1()) { return Status::OK(); @@ -390,8 +389,7 @@ Status ReplicationCoordinatorExternalStateImpl::initializeReplSetStorage(Operati createOplog(opCtx); MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { - ScopedTransaction scopedXact(opCtx, MODE_X); - Lock::GlobalWrite globalWrite(opCtx->lockState()); + Lock::GlobalWrite globalWrite(opCtx); WriteUnitOfWork wuow(opCtx); Helpers::putSingleton(opCtx, configCollectionName, config); @@ -436,8 +434,6 @@ OpTime ReplicationCoordinatorExternalStateImpl::onTransitionToPrimary(OperationC if (isV1ElectionProtocol) { MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { - ScopedTransaction scopedXact(opCtx, MODE_X); - WriteUnitOfWork wuow(opCtx); opCtx->getClient()->getServiceContext()->getOpObserver()->onOpMessage( opCtx, @@ -466,8 +462,7 @@ OID ReplicationCoordinatorExternalStateImpl::ensureMe(OperationContext* opCtx) { std::string myname = getHostName(); OID myRID; { - ScopedTransaction transaction(opCtx, MODE_IX); - Lock::DBLock lock(opCtx->lockState(), meDatabaseName, MODE_X); + Lock::DBLock lock(opCtx, meDatabaseName, MODE_X); BSONObj me; // local.me is an identifier for a server for getLastError w:2+ @@ -514,8 +509,7 @@ Status ReplicationCoordinatorExternalStateImpl::storeLocalConfigDocument(Operati const BSONObj& config) { try { MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { - ScopedTransaction transaction(opCtx, MODE_IX); - Lock::DBLock dbWriteLock(opCtx->lockState(), configDatabaseName, MODE_X); + Lock::DBLock dbWriteLock(opCtx, configDatabaseName, MODE_X); Helpers::putSingleton(opCtx, configCollectionName, config); return Status::OK(); } @@ -550,8 +544,7 @@ Status ReplicationCoordinatorExternalStateImpl::storeLocalLastVoteDocument( BSONObj lastVoteObj = lastVote.toBSON(); try { MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { - ScopedTransaction transaction(opCtx, MODE_IX); - Lock::DBLock dbWriteLock(opCtx->lockState(), lastVoteDatabaseName, MODE_X); + Lock::DBLock dbWriteLock(opCtx, lastVoteDatabaseName, MODE_X); // If there is no last vote document, we want to store one. Otherwise, we only want to // replace it if the new last vote document would have a higher term. We both check diff --git a/src/mongo/db/repl/replication_coordinator_impl.cpp b/src/mongo/db/repl/replication_coordinator_impl.cpp index 18a25b08f26..963672cc67e 100644 --- a/src/mongo/db/repl/replication_coordinator_impl.cpp +++ b/src/mongo/db/repl/replication_coordinator_impl.cpp @@ -938,8 +938,7 @@ void ReplicationCoordinatorImpl::signalDrainComplete(OperationContext* opCtx, } } - ScopedTransaction transaction(opCtx, MODE_X); - Lock::GlobalWrite globalWriteLock(opCtx->lockState()); + Lock::GlobalWrite globalWriteLock(opCtx); lk.lock(); // Exit drain mode when the buffer is empty in the current term and we're in Draining mode. @@ -1806,7 +1805,7 @@ Status ReplicationCoordinatorImpl::stepDown(OperationContext* opCtx, return {ErrorCodes::NotMaster, "not primary so can't step down"}; } - Lock::GlobalLock globalReadLock(opCtx->lockState(), MODE_S, Lock::GlobalLock::EnqueueOnly()); + Lock::GlobalLock globalReadLock(opCtx, MODE_S, Lock::GlobalLock::EnqueueOnly()); // We've requested the global shared lock which will stop new writes from coming in, // but existing writes could take a long time to finish, so kill all user operations diff --git a/src/mongo/db/repl/replication_coordinator_impl_elect_v1_test.cpp b/src/mongo/db/repl/replication_coordinator_impl_elect_v1_test.cpp index be2370b7108..34bb0a9c101 100644 --- a/src/mongo/db/repl/replication_coordinator_impl_elect_v1_test.cpp +++ b/src/mongo/db/repl/replication_coordinator_impl_elect_v1_test.cpp @@ -1431,7 +1431,7 @@ TEST_F(PrimaryCatchUpTest, PrimaryDoNotNeedToCatchUp) { ASSERT_EQUALS(1, countLogLinesContaining("My optime is most up-to-date, skipping catch-up")); auto opCtx = makeOperationContext(); getReplCoord()->signalDrainComplete(opCtx.get(), getReplCoord()->getTerm()); - Lock::GlobalLock lock(opCtx->lockState(), MODE_IX, 1); + Lock::GlobalLock lock(opCtx.get(), MODE_IX, 1); ASSERT_TRUE(getReplCoord()->canAcceptWritesForDatabase(opCtx.get(), "test")); } @@ -1455,7 +1455,7 @@ TEST_F(PrimaryCatchUpTest, PrimaryFreshnessScanTimeout) { ASSERT_EQUALS(1, countLogLinesContaining("Could not access any nodes within timeout")); auto opCtx = makeOperationContext(); getReplCoord()->signalDrainComplete(opCtx.get(), getReplCoord()->getTerm()); - Lock::GlobalLock lock(opCtx->lockState(), MODE_IX, 1); + Lock::GlobalLock lock(opCtx.get(), MODE_IX, 1); ASSERT_TRUE(getReplCoord()->canAcceptWritesForDatabase(opCtx.get(), "test")); } @@ -1485,7 +1485,7 @@ TEST_F(PrimaryCatchUpTest, PrimaryCatchUpSucceeds) { ASSERT_EQUALS(1, countLogLinesContaining("Finished catch-up oplog after becoming primary.")); auto opCtx = makeOperationContext(); getReplCoord()->signalDrainComplete(opCtx.get(), getReplCoord()->getTerm()); - Lock::GlobalLock lock(opCtx->lockState(), MODE_IX, 1); + Lock::GlobalLock lock(opCtx.get(), MODE_IX, 1); ASSERT_TRUE(getReplCoord()->canAcceptWritesForDatabase(opCtx.get(), "test")); } @@ -1509,7 +1509,7 @@ TEST_F(PrimaryCatchUpTest, PrimaryCatchUpTimeout) { ASSERT_EQUALS(1, countLogLinesContaining("Cannot catch up oplog after becoming primary")); auto opCtx = makeOperationContext(); getReplCoord()->signalDrainComplete(opCtx.get(), getReplCoord()->getTerm()); - Lock::GlobalLock lock(opCtx->lockState(), MODE_IX, 1); + Lock::GlobalLock lock(opCtx.get(), MODE_IX, 1); ASSERT_TRUE(getReplCoord()->canAcceptWritesForDatabase(opCtx.get(), "test")); } @@ -1537,7 +1537,7 @@ TEST_F(PrimaryCatchUpTest, PrimaryStepsDownDuringFreshnessScan) { stopCapturingLogMessages(); ASSERT_EQUALS(1, countLogLinesContaining("Stopped transition to primary")); auto opCtx = makeOperationContext(); - Lock::GlobalLock lock(opCtx->lockState(), MODE_IX, 1); + Lock::GlobalLock lock(opCtx.get(), MODE_IX, 1); ASSERT_FALSE(getReplCoord()->canAcceptWritesForDatabase(opCtx.get(), "test")); } @@ -1571,7 +1571,7 @@ TEST_F(PrimaryCatchUpTest, PrimaryStepsDownDuringCatchUp) { ASSERT(getReplCoord()->getApplierState() == ApplierState::Running); stopCapturingLogMessages(); ASSERT_EQUALS(1, countLogLinesContaining("Cannot catch up oplog after becoming primary")); - Lock::GlobalLock lock(opCtx->lockState(), MODE_IX, 1); + Lock::GlobalLock lock(opCtx.get(), MODE_IX, 1); ASSERT_FALSE(getReplCoord()->canAcceptWritesForDatabase(opCtx.get(), "test")); } @@ -1620,11 +1620,11 @@ TEST_F(PrimaryCatchUpTest, PrimaryStepsDownDuringDrainMode) { ASSERT(replCoord->getApplierState() == ApplierState::Draining); auto opCtx = makeOperationContext(); { - Lock::GlobalLock lock(opCtx->lockState(), MODE_IX, 1); + Lock::GlobalLock lock(opCtx.get(), MODE_IX, 1); ASSERT_FALSE(replCoord->canAcceptWritesForDatabase(opCtx.get(), "test")); } replCoord->signalDrainComplete(opCtx.get(), replCoord->getTerm()); - Lock::GlobalLock lock(opCtx->lockState(), MODE_IX, 1); + Lock::GlobalLock lock(opCtx.get(), MODE_IX, 1); ASSERT(replCoord->getApplierState() == ApplierState::Stopped); ASSERT_TRUE(replCoord->canAcceptWritesForDatabase(opCtx.get(), "test")); } diff --git a/src/mongo/db/repl/replication_coordinator_impl_test.cpp b/src/mongo/db/repl/replication_coordinator_impl_test.cpp index ae8d5b5fe92..e69c85d57d1 100644 --- a/src/mongo/db/repl/replication_coordinator_impl_test.cpp +++ b/src/mongo/db/repl/replication_coordinator_impl_test.cpp @@ -1605,7 +1605,7 @@ TEST_F(StepDownTest, const auto opCtx = makeOperationContext(); // Make sure stepDown cannot grab the global shared lock - Lock::GlobalWrite lk(opCtx->lockState()); + Lock::GlobalWrite lk(opCtx.get()); Status status = getReplCoord()->stepDown(opCtx.get(), false, Milliseconds(0), Milliseconds(1000)); diff --git a/src/mongo/db/repl/replication_info.cpp b/src/mongo/db/repl/replication_info.cpp index e0a49f5849f..28bc80d04c8 100644 --- a/src/mongo/db/repl/replication_info.cpp +++ b/src/mongo/db/repl/replication_info.cpp @@ -95,7 +95,7 @@ void appendReplicationInfo(OperationContext* opCtx, BSONObjBuilder& result, int list<BSONObj> src; { const NamespaceString localSources{"local.sources"}; - AutoGetCollectionForRead ctx(opCtx, localSources); + AutoGetCollectionForReadCommand ctx(opCtx, localSources); unique_ptr<PlanExecutor> exec(InternalPlanner::collectionScan( opCtx, localSources.ns(), ctx.getCollection(), PlanExecutor::YIELD_MANUAL)); BSONObj obj; diff --git a/src/mongo/db/repl/resync.cpp b/src/mongo/db/repl/resync.cpp index 848700d215a..67b230af0af 100644 --- a/src/mongo/db/repl/resync.cpp +++ b/src/mongo/db/repl/resync.cpp @@ -105,8 +105,7 @@ public: } // Master/Slave resync. - ScopedTransaction transaction(opCtx, MODE_X); - Lock::GlobalWrite globalWriteLock(opCtx->lockState()); + Lock::GlobalWrite globalWriteLock(opCtx); // below this comment pertains only to master/slave replication if (cmdObj.getBoolField("force")) { if (!waitForSyncToFinish(opCtx, errmsg)) diff --git a/src/mongo/db/repl/rs_initialsync.cpp b/src/mongo/db/repl/rs_initialsync.cpp index 32d03e31902..7c882dbe3c4 100644 --- a/src/mongo/db/repl/rs_initialsync.cpp +++ b/src/mongo/db/repl/rs_initialsync.cpp @@ -144,8 +144,7 @@ bool _initialSyncClone(OperationContext* opCtx, options.createCollections = false; // Make database stable - ScopedTransaction transaction(opCtx, MODE_IX); - Lock::DBLock dbWrite(opCtx->lockState(), db, MODE_X); + Lock::DBLock dbWrite(opCtx, db, MODE_X); Status status = cloner.copyDb(opCtx, db, host, options, nullptr, collections); if (!status.isOK()) { @@ -360,8 +359,7 @@ Status _initialSync(OperationContext* opCtx, BackgroundSync* bgsync) { createCollectionParams.push_back(params); } - ScopedTransaction transaction(opCtx, MODE_IX); - Lock::DBLock dbWrite(opCtx->lockState(), db, MODE_X); + Lock::DBLock dbWrite(opCtx, db, MODE_X); auto createStatus = cloner.createCollectionsForDb(opCtx, createCollectionParams, db); if (!createStatus.isOK()) { diff --git a/src/mongo/db/repl/rs_rollback.cpp b/src/mongo/db/repl/rs_rollback.cpp index 88fbf63f036..d32404132e4 100644 --- a/src/mongo/db/repl/rs_rollback.cpp +++ b/src/mongo/db/repl/rs_rollback.cpp @@ -438,8 +438,7 @@ void syncFixUp(OperationContext* opCtx, { - ScopedTransaction transaction(opCtx, MODE_IX); - Lock::DBLock dbLock(opCtx->lockState(), nss.db(), MODE_X); + Lock::DBLock dbLock(opCtx, nss.db(), MODE_X); Database* db = dbHolder().openDb(opCtx, nss.db().toString()); invariant(db); WriteUnitOfWork wunit(opCtx); @@ -454,8 +453,7 @@ void syncFixUp(OperationContext* opCtx, log() << "rollback 4.1.2 coll metadata resync " << ns; const NamespaceString nss(ns); - ScopedTransaction transaction(opCtx, MODE_IX); - Lock::DBLock dbLock(opCtx->lockState(), nss.db(), MODE_X); + Lock::DBLock dbLock(opCtx, nss.db(), MODE_X); auto db = dbHolder().openDb(opCtx, nss.db().toString()); invariant(db); auto collection = db->getCollection(ns); @@ -534,9 +532,8 @@ void syncFixUp(OperationContext* opCtx, invariant(!fixUpInfo.indexesToDrop.count(*it)); - ScopedTransaction transaction(opCtx, MODE_IX); const NamespaceString nss(*it); - Lock::DBLock dbLock(opCtx->lockState(), nss.db(), MODE_X); + Lock::DBLock dbLock(opCtx, nss.db(), MODE_X); Database* db = dbHolder().get(opCtx, nsToDatabaseSubstring(*it)); if (db) { Helpers::RemoveSaver removeSaver("rollback", "", *it); @@ -580,8 +577,7 @@ void syncFixUp(OperationContext* opCtx, const string& indexName = it->second; log() << "rollback drop index: collection: " << nss.toString() << ". index: " << indexName; - ScopedTransaction transaction(opCtx, MODE_IX); - Lock::DBLock dbLock(opCtx->lockState(), nss.db(), MODE_X); + Lock::DBLock dbLock(opCtx, nss.db(), MODE_X); auto db = dbHolder().get(opCtx, nss.db()); if (!db) { continue; @@ -641,8 +637,7 @@ void syncFixUp(OperationContext* opCtx, // TODO: Lots of overhead in context. This can be faster. const NamespaceString docNss(doc.ns); - ScopedTransaction transaction(opCtx, MODE_IX); - Lock::DBLock docDbLock(opCtx->lockState(), docNss.db(), MODE_X); + Lock::DBLock docDbLock(opCtx, docNss.db(), MODE_X); OldClientContext ctx(opCtx, doc.ns); Collection* collection = ctx.db()->getCollection(doc.ns); @@ -761,8 +756,7 @@ void syncFixUp(OperationContext* opCtx, LOG(2) << "rollback truncate oplog after " << fixUpInfo.commonPoint.toString(); { const NamespaceString oplogNss(rsOplogName); - ScopedTransaction transaction(opCtx, MODE_IX); - Lock::DBLock oplogDbLock(opCtx->lockState(), oplogNss.db(), MODE_IX); + Lock::DBLock oplogDbLock(opCtx, oplogNss.db(), MODE_IX); Lock::CollectionLock oplogCollectionLoc(opCtx->lockState(), oplogNss.ns(), MODE_X); OldClientContext ctx(opCtx, rsOplogName); Collection* oplogCollection = ctx.db()->getCollection(rsOplogName); @@ -895,7 +889,7 @@ void rollback(OperationContext* opCtx, // then. { log() << "rollback 0"; - Lock::GlobalWrite globalWrite(opCtx->lockState()); + Lock::GlobalWrite globalWrite(opCtx); if (!replCoord->setFollowerMode(MemberState::RS_ROLLBACK)) { log() << "Cannot transition from " << replCoord->getMemberState().toString() << " to " << MemberState(MemberState::RS_ROLLBACK).toString(); diff --git a/src/mongo/db/repl/rs_rollback_test.cpp b/src/mongo/db/repl/rs_rollback_test.cpp index 5df25a37427..90843d9a445 100644 --- a/src/mongo/db/repl/rs_rollback_test.cpp +++ b/src/mongo/db/repl/rs_rollback_test.cpp @@ -292,7 +292,7 @@ TEST_F(RSRollbackTest, BothOplogsAtCommonPoint) { Collection* _createCollection(OperationContext* opCtx, const NamespaceString& nss, const CollectionOptions& options) { - Lock::DBLock dbLock(opCtx->lockState(), nss.db(), MODE_X); + Lock::DBLock dbLock(opCtx, nss.db(), MODE_X); mongo::WriteUnitOfWork wuow(opCtx); auto db = dbHolder().openDb(opCtx, nss.db()); ASSERT_TRUE(db); @@ -355,7 +355,7 @@ int _testRollbackDelete(OperationContext* opCtx, storageInterface)); ASSERT_TRUE(rollbackSource.called); - Lock::DBLock dbLock(opCtx->lockState(), "test", MODE_S); + Lock::DBLock dbLock(opCtx, "test", MODE_S); Lock::CollectionLock collLock(opCtx->lockState(), "test.t", MODE_S); auto db = dbHolder().get(opCtx, "test"); ASSERT_TRUE(db); @@ -451,7 +451,7 @@ TEST_F(RSRollbackTest, RollbackCreateIndexCommand) { << "v" << static_cast<int>(kIndexVersion)); { - Lock::DBLock dbLock(_opCtx->lockState(), "test", MODE_X); + Lock::DBLock dbLock(_opCtx.get(), "test", MODE_X); MultiIndexBlock indexer(_opCtx.get(), collection); ASSERT_OK(indexer.init(indexSpec).getStatus()); WriteUnitOfWork wunit(_opCtx.get()); @@ -502,7 +502,7 @@ TEST_F(RSRollbackTest, RollbackCreateIndexCommand) { countLogLinesContaining("rollback drop index: collection: test.t. index: a_1")); ASSERT_FALSE(rollbackSource.called); { - Lock::DBLock dbLock(_opCtx->lockState(), "test", MODE_S); + Lock::DBLock dbLock(_opCtx.get(), "test", MODE_S); auto indexCatalog = collection->getIndexCatalog(); ASSERT(indexCatalog); ASSERT_EQUALS(1, indexCatalog->numIndexesReady(_opCtx.get())); @@ -520,7 +520,7 @@ TEST_F(RSRollbackTest, RollbackCreateIndexCommandIndexNotInCatalog) { << "a_1"); // Skip index creation to trigger warning during rollback. { - Lock::DBLock dbLock(_opCtx->lockState(), "test", MODE_S); + Lock::DBLock dbLock(_opCtx.get(), "test", MODE_S); auto indexCatalog = collection->getIndexCatalog(); ASSERT(indexCatalog); ASSERT_EQUALS(1, indexCatalog->numIndexesReady(_opCtx.get())); @@ -564,7 +564,7 @@ TEST_F(RSRollbackTest, RollbackCreateIndexCommandIndexNotInCatalog) { ASSERT_EQUALS(1, countLogLinesContaining("rollback failed to drop index a_1 in test.t")); ASSERT_FALSE(rollbackSource.called); { - Lock::DBLock dbLock(_opCtx->lockState(), "test", MODE_S); + Lock::DBLock dbLock(_opCtx.get(), "test", MODE_S); auto indexCatalog = collection->getIndexCatalog(); ASSERT(indexCatalog); ASSERT_EQUALS(1, indexCatalog->numIndexesReady(_opCtx.get())); @@ -619,7 +619,7 @@ TEST_F(RSRollbackTest, RollbackDropIndexCommandWithOneIndex) { createOplog(_opCtx.get()); auto collection = _createCollection(_opCtx.get(), "test.t", CollectionOptions()); { - Lock::DBLock dbLock(_opCtx->lockState(), "test", MODE_S); + Lock::DBLock dbLock(_opCtx.get(), "test", MODE_S); auto indexCatalog = collection->getIndexCatalog(); ASSERT(indexCatalog); ASSERT_EQUALS(1, indexCatalog->numIndexesReady(_opCtx.get())); @@ -677,7 +677,7 @@ TEST_F(RSRollbackTest, RollbackDropIndexCommandWithMultipleIndexes) { createOplog(_opCtx.get()); auto collection = _createCollection(_opCtx.get(), "test.t", CollectionOptions()); { - Lock::DBLock dbLock(_opCtx->lockState(), "test", MODE_S); + Lock::DBLock dbLock(_opCtx.get(), "test", MODE_S); auto indexCatalog = collection->getIndexCatalog(); ASSERT(indexCatalog); ASSERT_EQUALS(1, indexCatalog->numIndexesReady(_opCtx.get())); @@ -860,7 +860,7 @@ TEST_F(RSRollbackTest, RollbackUnknownCommand) { << "t")), RecordId(2)); { - Lock::DBLock dbLock(_opCtx->lockState(), "test", MODE_X); + Lock::DBLock dbLock(_opCtx.get(), "test", MODE_X); mongo::WriteUnitOfWork wuow(_opCtx.get()); auto db = dbHolder().openDb(_opCtx.get(), "test"); ASSERT_TRUE(db); @@ -1083,7 +1083,7 @@ TEST_F(RSRollbackTest, RollbackApplyOpsCommand) { ASSERT_EQUALS(1U, rollbackSource.searchedIds.count(3)); ASSERT_EQUALS(1U, rollbackSource.searchedIds.count(4)); - AutoGetCollectionForRead acr(_opCtx.get(), NamespaceString("test.t")); + AutoGetCollectionForReadCommand acr(_opCtx.get(), NamespaceString("test.t")); BSONObj result; ASSERT(Helpers::findOne(_opCtx.get(), acr.getCollection(), BSON("_id" << 1), result)); ASSERT_EQUALS(1, result["v"].numberInt()) << result; @@ -1119,7 +1119,7 @@ TEST_F(RSRollbackTest, RollbackCreateCollectionCommand) { _coordinator, &_storageInterface)); { - Lock::DBLock dbLock(_opCtx->lockState(), "test", MODE_S); + Lock::DBLock dbLock(_opCtx.get(), "test", MODE_S); auto db = dbHolder().get(_opCtx.get(), "test"); ASSERT_TRUE(db); ASSERT_FALSE(db->getCollection("test.t")); diff --git a/src/mongo/db/repl/storage_interface_impl.cpp b/src/mongo/db/repl/storage_interface_impl.cpp index bece9cedeb6..b98af9c8537 100644 --- a/src/mongo/db/repl/storage_interface_impl.cpp +++ b/src/mongo/db/repl/storage_interface_impl.cpp @@ -104,8 +104,7 @@ NamespaceString StorageInterfaceImpl::getMinValidNss() const { BSONObj StorageInterfaceImpl::getMinValidDocument(OperationContext* opCtx) const { MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { - ScopedTransaction transaction(opCtx, MODE_IS); - Lock::DBLock dblk(opCtx->lockState(), _minValidNss.db(), MODE_IS); + Lock::DBLock dblk(opCtx, _minValidNss.db(), MODE_IS); Lock::CollectionLock lk(opCtx->lockState(), _minValidNss.ns(), MODE_IS); BSONObj doc; bool found = Helpers::getSingleton(opCtx, _minValidNss.ns().c_str(), doc); @@ -121,9 +120,8 @@ BSONObj StorageInterfaceImpl::getMinValidDocument(OperationContext* opCtx) const void StorageInterfaceImpl::updateMinValidDocument(OperationContext* opCtx, const BSONObj& updateSpec) { MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { - ScopedTransaction transaction(opCtx, MODE_IX); // For now this needs to be MODE_X because it sometimes creates the collection. - Lock::DBLock dblk(opCtx->lockState(), _minValidNss.db(), MODE_X); + Lock::DBLock dblk(opCtx, _minValidNss.db(), MODE_X); Helpers::putSingleton(opCtx, _minValidNss.ns().c_str(), updateSpec); } MONGO_WRITE_CONFLICT_RETRY_LOOP_END( @@ -263,7 +261,6 @@ StorageInterfaceImpl::createCollectionForBulkLoading( // Retry if WCE. MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { // Get locks and create the collection. - ScopedTransaction transaction(opCtx, MODE_IX); auto db = stdx::make_unique<AutoGetOrCreateDb>(opCtx, nss.db(), MODE_IX); auto coll = stdx::make_unique<AutoGetCollection>(opCtx, nss, MODE_X); collection = coll->getCollection(); @@ -321,7 +318,6 @@ Status insertDocumentsSingleBatch(OperationContext* opCtx, const NamespaceString& nss, std::vector<BSONObj>::const_iterator begin, std::vector<BSONObj>::const_iterator end) { - ScopedTransaction transaction(opCtx, MODE_IX); AutoGetCollection autoColl(opCtx, nss, MODE_IX); auto collection = autoColl.getCollection(); if (!collection) { @@ -384,7 +380,7 @@ Status StorageInterfaceImpl::createOplog(OperationContext* opCtx, const Namespac StatusWith<size_t> StorageInterfaceImpl::getOplogMaxSize(OperationContext* opCtx, const NamespaceString& nss) { - AutoGetCollectionForRead collection(opCtx, nss); + AutoGetCollectionForReadCommand collection(opCtx, nss); if (!collection.getCollection()) { return {ErrorCodes::NamespaceNotFound, str::stream() << "Your oplog doesn't exist: " << nss.ns()}; @@ -401,7 +397,6 @@ Status StorageInterfaceImpl::createCollection(OperationContext* opCtx, const NamespaceString& nss, const CollectionOptions& options) { MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { - ScopedTransaction transaction(opCtx, MODE_IX); AutoGetOrCreateDb databaseWriteGuard(opCtx, nss.db(), MODE_X); auto db = databaseWriteGuard.getDb(); invariant(db); @@ -424,7 +419,6 @@ Status StorageInterfaceImpl::createCollection(OperationContext* opCtx, Status StorageInterfaceImpl::dropCollection(OperationContext* opCtx, const NamespaceString& nss) { MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { - ScopedTransaction transaction(opCtx, MODE_IX); AutoGetDb autoDB(opCtx, nss.db(), MODE_X); if (!autoDB.getDb()) { // Database does not exist - nothing to do. @@ -470,7 +464,6 @@ StatusWith<std::vector<BSONObj>> _findOrDeleteDocuments( MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { auto collectionAccessMode = isFind ? MODE_IS : MODE_IX; - ScopedTransaction transaction(opCtx, collectionAccessMode); AutoGetCollection collectionGuard(opCtx, nss, collectionAccessMode); auto collection = collectionGuard.getCollection(); if (!collection) { @@ -607,7 +600,6 @@ StatusWith<std::vector<BSONObj>> StorageInterfaceImpl::deleteDocuments( } Status StorageInterfaceImpl::isAdminDbValid(OperationContext* opCtx) { - ScopedTransaction transaction(opCtx, MODE_IX); AutoGetDb autoDB(opCtx, "admin", MODE_X); return checkAdminDatabase(opCtx, autoDB.getDb()); } diff --git a/src/mongo/db/repl/storage_interface_impl_test.cpp b/src/mongo/db/repl/storage_interface_impl_test.cpp index e94761e5d35..6ca1058cf5c 100644 --- a/src/mongo/db/repl/storage_interface_impl_test.cpp +++ b/src/mongo/db/repl/storage_interface_impl_test.cpp @@ -89,8 +89,7 @@ NamespaceString makeNamespace(const T& t, const char* suffix = "") { */ BSONObj getMinValidDocument(OperationContext* opCtx, const NamespaceString& minValidNss) { MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { - ScopedTransaction transaction(opCtx, MODE_IS); - Lock::DBLock dblk(opCtx->lockState(), minValidNss.db(), MODE_IS); + Lock::DBLock dblk(opCtx, minValidNss.db(), MODE_IS); Lock::CollectionLock lk(opCtx->lockState(), minValidNss.ns(), MODE_IS); BSONObj mv; if (Helpers::getSingleton(opCtx, minValidNss.ns().c_str(), mv)) { @@ -120,8 +119,7 @@ void createCollection(OperationContext* opCtx, const NamespaceString& nss, const CollectionOptions& options = CollectionOptions()) { MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { - ScopedTransaction transaction(opCtx, MODE_IX); - Lock::DBLock dblk(opCtx->lockState(), nss.db(), MODE_X); + Lock::DBLock dblk(opCtx, nss.db(), MODE_X); OldClientContext ctx(opCtx, nss.ns()); auto db = ctx.db(); ASSERT_TRUE(db); @@ -449,7 +447,7 @@ TEST_F(StorageInterfaceImplWithReplCoordTest, InsertMissingDocWorksOnExistingCap opts.cappedSize = 1024 * 1024; createCollection(opCtx, nss, opts); ASSERT_OK(storage.insertDocument(opCtx, nss, BSON("_id" << 1))); - AutoGetCollectionForRead autoColl(opCtx, nss); + AutoGetCollectionForReadCommand autoColl(opCtx, nss); ASSERT_TRUE(autoColl.getCollection()); } @@ -459,7 +457,7 @@ TEST_F(StorageInterfaceImplWithReplCoordTest, InsertMissingDocWorksOnExistingCol NamespaceString nss("foo.bar"); createCollection(opCtx, nss); ASSERT_OK(storage.insertDocument(opCtx, nss, BSON("_id" << 1))); - AutoGetCollectionForRead autoColl(opCtx, nss); + AutoGetCollectionForReadCommand autoColl(opCtx, nss); ASSERT_TRUE(autoColl.getCollection()); } @@ -487,7 +485,7 @@ TEST_F(StorageInterfaceImplWithReplCoordTest, CreateCollectionWithIDIndexCommits ASSERT_OK(loader->insertDocuments(docs.begin(), docs.end())); ASSERT_OK(loader->commit()); - AutoGetCollectionForRead autoColl(opCtx, nss); + AutoGetCollectionForReadCommand autoColl(opCtx, nss); auto coll = autoColl.getCollection(); ASSERT(coll); ASSERT_EQ(coll->getRecordStore()->numRecords(opCtx), 2LL); @@ -516,7 +514,7 @@ void _testDestroyUncommitedCollectionBulkLoader( // Collection and ID index should not exist after 'loader' is destroyed. destroyLoaderFn(std::move(loader)); - AutoGetCollectionForRead autoColl(opCtx, nss); + AutoGetCollectionForReadCommand autoColl(opCtx, nss); auto coll = autoColl.getCollection(); // Bulk loader is used to create indexes. The collection is not dropped when the bulk loader is @@ -590,12 +588,12 @@ TEST_F(StorageInterfaceImplWithReplCoordTest, CreateOplogCreateCappedCollection) StorageInterfaceImpl storage; NamespaceString nss("local.oplog.X"); { - AutoGetCollectionForRead autoColl(opCtx, nss); + AutoGetCollectionForReadCommand autoColl(opCtx, nss); ASSERT_FALSE(autoColl.getCollection()); } ASSERT_OK(storage.createOplog(opCtx, nss)); { - AutoGetCollectionForRead autoColl(opCtx, nss); + AutoGetCollectionForReadCommand autoColl(opCtx, nss); ASSERT_TRUE(autoColl.getCollection()); ASSERT_EQ(nss.toString(), autoColl.getCollection()->ns().toString()); ASSERT_TRUE(autoColl.getCollection()->isCapped()); @@ -608,7 +606,7 @@ TEST_F(StorageInterfaceImplWithReplCoordTest, StorageInterfaceImpl storage; NamespaceString nss("local.oplog.Y"); { - AutoGetCollectionForRead autoColl(opCtx, nss); + AutoGetCollectionForReadCommand autoColl(opCtx, nss); ASSERT_FALSE(autoColl.getCollection()); } @@ -622,12 +620,12 @@ TEST_F(StorageInterfaceImplWithReplCoordTest, CreateCollectionFailsIfCollectionE StorageInterfaceImpl storage; auto nss = makeNamespace(_agent); { - AutoGetCollectionForRead autoColl(opCtx, nss); + AutoGetCollectionForReadCommand autoColl(opCtx, nss); ASSERT_FALSE(autoColl.getCollection()); } ASSERT_OK(storage.createCollection(opCtx, nss, CollectionOptions())); { - AutoGetCollectionForRead autoColl(opCtx, nss); + AutoGetCollectionForReadCommand autoColl(opCtx, nss); ASSERT_TRUE(autoColl.getCollection()); ASSERT_EQ(nss.toString(), autoColl.getCollection()->ns().toString()); } @@ -652,7 +650,7 @@ TEST_F(StorageInterfaceImplWithReplCoordTest, DropCollectionWorksWithExistingEmp NamespaceString nss("foo.bar"); createCollection(opCtx, nss); ASSERT_OK(storage.dropCollection(opCtx, nss)); - AutoGetCollectionForRead autoColl(opCtx, nss); + AutoGetCollectionForReadCommand autoColl(opCtx, nss); ASSERT_FALSE(autoColl.getCollection()); } @@ -662,7 +660,7 @@ TEST_F(StorageInterfaceImplWithReplCoordTest, DropCollectionWorksWithMissingColl NamespaceString nss("foo.bar"); ASSERT_FALSE(AutoGetDb(opCtx, nss.db(), MODE_IS).getDb()); ASSERT_OK(storage.dropCollection(opCtx, nss)); - ASSERT_FALSE(AutoGetCollectionForRead(opCtx, nss).getCollection()); + ASSERT_FALSE(AutoGetCollectionForReadCommand(opCtx, nss).getCollection()); // Database should not be created after running dropCollection. ASSERT_FALSE(AutoGetDb(opCtx, nss.db(), MODE_IS).getDb()); } diff --git a/src/mongo/db/repl/sync_tail.cpp b/src/mongo/db/repl/sync_tail.cpp index c42b51905b2..105f40bcd5a 100644 --- a/src/mongo/db/repl/sync_tail.cpp +++ b/src/mongo/db/repl/sync_tail.cpp @@ -312,7 +312,7 @@ Status SyncTail::syncApply(OperationContext* opCtx, MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { // a command may need a global write lock. so we will conservatively go // ahead and grab one here. suboptimal. :-( - Lock::GlobalWrite globalWriteLock(opCtx->lockState()); + Lock::GlobalWrite globalWriteLock(opCtx); // special case apply for commands to avoid implicit database creation Status status = applyCommandInLock(opCtx, op, inSteadyStateReplication); @@ -339,7 +339,7 @@ Status SyncTail::syncApply(OperationContext* opCtx, if (isNoOp || (opType[0] == 'i' && nsToCollectionSubstring(ns) == "system.indexes")) { auto opStr = isNoOp ? "syncApply_noop" : "syncApply_indexBuild"; MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { - Lock::DBLock dbLock(opCtx->lockState(), nsToDatabaseSubstring(ns), MODE_X); + Lock::DBLock dbLock(opCtx, nsToDatabaseSubstring(ns), MODE_X); OldClientContext ctx(opCtx, ns); return applyOp(ctx.db()); } @@ -361,7 +361,7 @@ Status SyncTail::syncApply(OperationContext* opCtx, // drop the DB lock before acquiring // the upgraded one. dbLock.reset(); - dbLock.reset(new Lock::DBLock(opCtx->lockState(), dbName, mode)); + dbLock.reset(new Lock::DBLock(opCtx, dbName, mode)); collectionLock.reset(new Lock::CollectionLock(opCtx->lockState(), ns, mode)); }; @@ -418,7 +418,7 @@ void prefetchOp(const BSONObj& op) { // for multiple prefetches if they are for the same database. const ServiceContext::UniqueOperationContext opCtxPtr = cc().makeOperationContext(); OperationContext& opCtx = *opCtxPtr; - AutoGetCollectionForRead ctx(&opCtx, NamespaceString(ns)); + AutoGetCollectionForReadCommand ctx(&opCtx, NamespaceString(ns)); Database* db = ctx.getDb(); if (db) { prefetchPagesForReplicatedOp(&opCtx, db, op); @@ -478,8 +478,8 @@ void scheduleWritesToOplog(OperationContext* opCtx, // guarantees that 'ops' will stay in scope until the spawned threads complete. return [&ops, begin, end] { initializeWriterThread(); - const auto txnHolder = cc().makeOperationContext(); - const auto opCtx = txnHolder.get(); + const auto opCtxHolder = cc().makeOperationContext(); + const auto opCtx = opCtxHolder.get(); opCtx->lockState()->setShouldConflictWithSecondaryBatchApplication(false); UnreplicatedWritesBlock uwb(opCtx); @@ -552,7 +552,7 @@ private: CollectionProperties getCollectionPropertiesImpl(OperationContext* opCtx, StringData ns) { CollectionProperties collProperties; - Lock::DBLock dbLock(opCtx->lockState(), nsToDatabaseSubstring(ns), MODE_IS); + Lock::DBLock dbLock(opCtx, nsToDatabaseSubstring(ns), MODE_IS); auto db = dbHolder().get(opCtx, ns); if (!db) { return collProperties; @@ -640,8 +640,7 @@ void tryToGoLiveAsASecondary(OperationContext* opCtx, ReplicationCoordinator* re // This needs to happen after the attempt so readers can be sure we've already tried. ON_BLOCK_EXIT([] { attemptsToBecomeSecondary.increment(); }); - ScopedTransaction transaction(opCtx, MODE_S); - Lock::GlobalRead readLock(opCtx->lockState()); + Lock::GlobalRead readLock(opCtx); if (replCoord->getMaintenanceMode()) { LOG(1) << "Can't go live (tryToGoLiveAsASecondary) as maintenance mode is active."; diff --git a/src/mongo/db/repl/sync_tail_test.cpp b/src/mongo/db/repl/sync_tail_test.cpp index b1e62a2efa5..7e2cda18fe9 100644 --- a/src/mongo/db/repl/sync_tail_test.cpp +++ b/src/mongo/db/repl/sync_tail_test.cpp @@ -177,8 +177,7 @@ void createCollection(OperationContext* opCtx, const NamespaceString& nss, const CollectionOptions& options) { MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { - ScopedTransaction transaction(opCtx, MODE_IX); - Lock::DBLock dblk(opCtx->lockState(), nss.db(), MODE_X); + Lock::DBLock dblk(opCtx, nss.db(), MODE_X); OldClientContext ctx(opCtx, nss.ns()); auto db = ctx.db(); ASSERT_TRUE(db); @@ -363,7 +362,7 @@ TEST_F(SyncTailTest, SyncApplyInsertDocumentDatabaseMissing) { TEST_F(SyncTailTest, SyncApplyInsertDocumentCollectionMissing) { { - Lock::GlobalWrite globalLock(_opCtx->lockState()); + Lock::GlobalWrite globalLock(_opCtx.get()); bool justCreated = false; Database* db = dbHolder().openDb(_opCtx.get(), "test", &justCreated); ASSERT_TRUE(db); @@ -374,7 +373,7 @@ TEST_F(SyncTailTest, SyncApplyInsertDocumentCollectionMissing) { TEST_F(SyncTailTest, SyncApplyInsertDocumentCollectionExists) { { - Lock::GlobalWrite globalLock(_opCtx->lockState()); + Lock::GlobalWrite globalLock(_opCtx.get()); bool justCreated = false; Database* db = dbHolder().openDb(_opCtx.get(), "test", &justCreated); ASSERT_TRUE(db); @@ -614,7 +613,7 @@ TEST_F(SyncTailTest, MultiSyncApplyUsesSyncApplyToApplyOperation) { multiSyncApply(&ops, nullptr); // Collection should be created after SyncTail::syncApply() processes operation. _opCtx = cc().makeOperationContext(); - ASSERT_TRUE(AutoGetCollectionForRead(_opCtx.get(), nss).getCollection()); + ASSERT_TRUE(AutoGetCollectionForReadCommand(_opCtx.get(), nss).getCollection()); } TEST_F(SyncTailTest, MultiSyncApplyDisablesDocumentValidationWhileApplyingOperations) { @@ -866,7 +865,7 @@ TEST_F(SyncTailTest, // Since the missing document is not found on the sync source, the collection referenced by // the failed operation should not be automatically created. - ASSERT_FALSE(AutoGetCollectionForRead(_opCtx.get(), nss).getCollection()); + ASSERT_FALSE(AutoGetCollectionForReadCommand(_opCtx.get(), nss).getCollection()); ASSERT_EQUALS(fetchCount.load(), 1U); } @@ -1007,14 +1006,14 @@ OplogEntry IdempotencyTest::dropIndex(const std::string& indexName) { } std::string IdempotencyTest::validate() { - auto collection = AutoGetCollectionForRead(_opCtx.get(), nss).getCollection(); + auto collection = AutoGetCollectionForReadCommand(_opCtx.get(), nss).getCollection(); if (!collection) { return "CollectionNotFound"; } ValidateResults validateResults; BSONObjBuilder bob; - Lock::DBLock lk(_opCtx->lockState(), nss.db(), MODE_IS); + Lock::DBLock lk(_opCtx.get(), nss.db(), MODE_IS); Lock::CollectionLock lock(_opCtx->lockState(), nss.ns(), MODE_IS); ASSERT_OK(collection->validate(_opCtx.get(), kValidateFull, &validateResults, &bob)); ASSERT_TRUE(validateResults.valid); diff --git a/src/mongo/db/restapi.cpp b/src/mongo/db/restapi.cpp index 532f0c81213..1869858f223 100644 --- a/src/mongo/db/restapi.cpp +++ b/src/mongo/db/restapi.cpp @@ -40,6 +40,7 @@ #include "mongo/db/auth/user_name.h" #include "mongo/db/background.h" #include "mongo/db/clientcursor.h" +#include "mongo/db/concurrency/d_concurrency.h" #include "mongo/db/dbdirectclient.h" #include "mongo/db/dbhelpers.h" #include "mongo/db/dbwebserver.h" @@ -306,7 +307,7 @@ public: virtual void run(OperationContext* opCtx, stringstream& ss) { Timer t; - Lock::GlobalLock globalSLock(opCtx->lockState(), MODE_S, 300); + Lock::GlobalLock globalSLock(opCtx, MODE_S, 300); if (globalSLock.isLocked()) { _gotLock(t.millis(), ss); } else { diff --git a/src/mongo/db/s/migration_chunk_cloner_source_legacy.cpp b/src/mongo/db/s/migration_chunk_cloner_source_legacy.cpp index fda5fffdcfb..ff635fb59ff 100644 --- a/src/mongo/db/s/migration_chunk_cloner_source_legacy.cpp +++ b/src/mongo/db/s/migration_chunk_cloner_source_legacy.cpp @@ -472,7 +472,6 @@ void MigrationChunkClonerSourceLegacy::_cleanup(OperationContext* opCtx) { } if (_deleteNotifyExec) { - ScopedTransaction scopedXact(opCtx, MODE_IS); AutoGetCollection autoColl(opCtx, _args.getNss(), MODE_IS); _deleteNotifyExec.reset(); @@ -510,7 +509,6 @@ StatusWith<BSONObj> MigrationChunkClonerSourceLegacy::_callRecipient(const BSONO } Status MigrationChunkClonerSourceLegacy::_storeCurrentLocs(OperationContext* opCtx) { - ScopedTransaction scopedXact(opCtx, MODE_IS); AutoGetCollection autoColl(opCtx, _args.getNss(), MODE_IS); Collection* const collection = autoColl.getCollection(); diff --git a/src/mongo/db/s/migration_chunk_cloner_source_legacy_commands.cpp b/src/mongo/db/s/migration_chunk_cloner_source_legacy_commands.cpp index a51ef083521..955d834941d 100644 --- a/src/mongo/db/s/migration_chunk_cloner_source_legacy_commands.cpp +++ b/src/mongo/db/s/migration_chunk_cloner_source_legacy_commands.cpp @@ -57,8 +57,7 @@ class AutoGetActiveCloner { MONGO_DISALLOW_COPYING(AutoGetActiveCloner); public: - AutoGetActiveCloner(OperationContext* opCtx, const MigrationSessionId& migrationSessionId) - : _scopedXact(opCtx, MODE_IS) { + AutoGetActiveCloner(OperationContext* opCtx, const MigrationSessionId& migrationSessionId) { ShardingState* const gss = ShardingState::get(opCtx); const auto nss = gss->getActiveDonateChunkNss(); @@ -105,9 +104,6 @@ public: } private: - // Scoped transaction to reset the WT snapshot - ScopedTransaction _scopedXact; - // Scoped database + collection lock boost::optional<AutoGetCollection> _autoColl; diff --git a/src/mongo/db/s/migration_destination_manager.cpp b/src/mongo/db/s/migration_destination_manager.cpp index 8239842289f..f013b1baa91 100644 --- a/src/mongo/db/s/migration_destination_manager.cpp +++ b/src/mongo/db/s/migration_destination_manager.cpp @@ -527,8 +527,7 @@ void MigrationDestinationManager::_migrateDriver(OperationContext* opCtx, { // 1. copy indexes - ScopedTransaction scopedXact(opCtx, MODE_IX); - Lock::DBLock lk(opCtx->lockState(), _nss.db(), MODE_X); + Lock::DBLock lk(opCtx, _nss.db(), MODE_X); OldClientContext ctx(opCtx, _nss.ns()); if (!repl::getGlobalReplicationCoordinator()->canAcceptWritesFor(opCtx, _nss)) { @@ -888,8 +887,7 @@ bool MigrationDestinationManager::_applyMigrateOp(OperationContext* opCtx, bool didAnything = false; if (xfer["deleted"].isABSONObj()) { - ScopedTransaction scopedXact(opCtx, MODE_IX); - Lock::DBLock dlk(opCtx->lockState(), nsToDatabaseSubstring(ns), MODE_IX); + Lock::DBLock dlk(opCtx, nsToDatabaseSubstring(ns), MODE_IX); Helpers::RemoveSaver rs("moveChunk", ns, "removedDuring"); BSONObjIterator i(xfer["deleted"].Obj()); // deleted documents @@ -985,8 +983,7 @@ bool MigrationDestinationManager::_flushPendingWrites(OperationContext* opCtx, { // Get global lock to wait for write to be commited to journal. - ScopedTransaction scopedXact(opCtx, MODE_S); - Lock::GlobalRead lk(opCtx->lockState()); + Lock::GlobalRead lk(opCtx); // if durability is on, force a write to journal if (getDur().commitNow(opCtx)) { @@ -1003,7 +1000,6 @@ Status MigrationDestinationManager::_notePending(OperationContext* opCtx, const BSONObj& min, const BSONObj& max, const OID& epoch) { - ScopedTransaction scopedXact(opCtx, MODE_IX); AutoGetCollection autoColl(opCtx, nss, MODE_IX, MODE_X); auto css = CollectionShardingState::get(opCtx, nss); @@ -1046,7 +1042,6 @@ Status MigrationDestinationManager::_forgetPending(OperationContext* opCtx, _chunkMarkedPending = false; } - ScopedTransaction scopedXact(opCtx, MODE_IX); AutoGetCollection autoColl(opCtx, nss, MODE_IX, MODE_X); auto css = CollectionShardingState::get(opCtx, nss); diff --git a/src/mongo/db/s/migration_source_manager.cpp b/src/mongo/db/s/migration_source_manager.cpp index 5fb64445a75..fdb92230763 100644 --- a/src/mongo/db/s/migration_source_manager.cpp +++ b/src/mongo/db/s/migration_source_manager.cpp @@ -117,7 +117,6 @@ MigrationSourceManager::MigrationSourceManager(OperationContext* opCtx, // Snapshot the committed metadata from the time the migration starts { - ScopedTransaction scopedXact(opCtx, MODE_IS); AutoGetCollection autoColl(opCtx, getNss(), MODE_IS); _collectionMetadata = CollectionShardingState::get(opCtx, getNss())->getMetadata(); @@ -183,7 +182,6 @@ Status MigrationSourceManager::startClone(OperationContext* opCtx) { { // Register for notifications from the replication subsystem - ScopedTransaction scopedXact(opCtx, MODE_IX); AutoGetCollection autoColl(opCtx, getNss(), MODE_IX, MODE_X); auto css = CollectionShardingState::get(opCtx, getNss().ns()); @@ -232,7 +230,6 @@ Status MigrationSourceManager::enterCriticalSection(OperationContext* opCtx) { // The critical section must be entered with collection X lock in order to ensure there are // no writes which could have entered and passed the version check just before we entered // the crticial section, but managed to complete after we left it. - ScopedTransaction scopedXact(opCtx, MODE_IX); AutoGetCollection autoColl(opCtx, getNss(), MODE_IX, MODE_X); // Check that the collection has not been dropped or recreated since the migration began. @@ -379,7 +376,6 @@ Status MigrationSourceManager::commitChunkMetadataOnConfig(OperationContext* opC ShardingState::get(opCtx)->refreshMetadataNow(opCtx, getNss(), &unusedShardVersion); if (refreshStatus.isOK()) { - ScopedTransaction scopedXact(opCtx, MODE_IS); AutoGetCollection autoColl(opCtx, getNss(), MODE_IS); auto refreshedMetadata = CollectionShardingState::get(opCtx, getNss())->getMetadata(); @@ -402,7 +398,6 @@ Status MigrationSourceManager::commitChunkMetadataOnConfig(OperationContext* opC log() << "Migration succeeded and updated collection version to " << refreshedMetadata->getCollVersion(); } else { - ScopedTransaction scopedXact(opCtx, MODE_IX); AutoGetCollection autoColl(opCtx, getNss(), MODE_IX, MODE_X); CollectionShardingState::get(opCtx, getNss())->refreshMetadata(opCtx, nullptr); @@ -458,7 +453,6 @@ void MigrationSourceManager::_cleanup(OperationContext* opCtx) { auto cloneDriver = [&]() { // Unregister from the collection's sharding state - ScopedTransaction scopedXact(opCtx, MODE_IX); AutoGetCollection autoColl(opCtx, getNss(), MODE_IX, MODE_X); auto css = CollectionShardingState::get(opCtx, getNss().ns()); diff --git a/src/mongo/db/s/sharding_state.cpp b/src/mongo/db/s/sharding_state.cpp index 5bbb6d9c925..1320ee15465 100644 --- a/src/mongo/db/s/sharding_state.cpp +++ b/src/mongo/db/s/sharding_state.cpp @@ -552,7 +552,6 @@ StatusWith<ChunkVersion> ShardingState::_refreshMetadata( } // Exclusive collection lock needed since we're now changing the metadata - ScopedTransaction transaction(opCtx, MODE_IX); AutoGetCollection autoColl(opCtx, nss, MODE_IX, MODE_X); auto css = CollectionShardingState::get(opCtx, nss); diff --git a/src/mongo/db/service_context_d_test_fixture.cpp b/src/mongo/db/service_context_d_test_fixture.cpp index 7c24ce66ff5..efa54fdd1a4 100644 --- a/src/mongo/db/service_context_d_test_fixture.cpp +++ b/src/mongo/db/service_context_d_test_fixture.cpp @@ -87,8 +87,7 @@ ServiceContext* ServiceContextMongoDTest::getServiceContext() { void ServiceContextMongoDTest::_dropAllDBs(OperationContext* opCtx) { dropAllDatabasesExceptLocal(opCtx); - ScopedTransaction transaction(opCtx, MODE_X); - Lock::GlobalWrite lk(opCtx->lockState()); + Lock::GlobalWrite lk(opCtx); AutoGetDb autoDBLocal(opCtx, "local", MODE_X); const auto localDB = autoDBLocal.getDb(); if (localDB) { diff --git a/src/mongo/db/stats/storage_stats.cpp b/src/mongo/db/stats/storage_stats.cpp index 8a9a343f31a..fca73b4a473 100644 --- a/src/mongo/db/stats/storage_stats.cpp +++ b/src/mongo/db/stats/storage_stats.cpp @@ -54,7 +54,7 @@ Status appendCollectionStorageStats(OperationContext* opCtx, bool verbose = param["verbose"].trueValue(); - AutoGetCollectionForRead ctx(opCtx, nss); + AutoGetCollectionForReadCommand ctx(opCtx, nss); if (!ctx.getDb()) { return {ErrorCodes::BadValue, str::stream() << "Database [" << nss.db().toString() << "] not found."}; diff --git a/src/mongo/db/storage/mmap_v1/dur_recover.cpp b/src/mongo/db/storage/mmap_v1/dur_recover.cpp index 7a2b05a379f..0fcd359dd0d 100644 --- a/src/mongo/db/storage/mmap_v1/dur_recover.cpp +++ b/src/mongo/db/storage/mmap_v1/dur_recover.cpp @@ -41,6 +41,7 @@ #include <sys/stat.h> #include "mongo/db/client.h" +#include "mongo/db/concurrency/d_concurrency.h" #include "mongo/db/operation_context.h" #include "mongo/db/storage/mmap_v1/compress.h" #include "mongo/db/storage/mmap_v1/dur_commitjob.h" @@ -647,8 +648,7 @@ void replayJournalFilesAtStartup() { // we use a lock so that exitCleanly will wait for us // to finish (or at least to notice what is up and stop) auto opCtx = cc().makeOperationContext(); - ScopedTransaction transaction(opCtx.get(), MODE_X); - Lock::GlobalWrite lk(opCtx->lockState()); + Lock::GlobalWrite lk(opCtx.get()); _recover(opCtx.get()); // throws on interruption } diff --git a/src/mongo/db/storage/mmap_v1/mmap_v1_extent_manager.cpp b/src/mongo/db/storage/mmap_v1/mmap_v1_extent_manager.cpp index 29d7952bf22..7fc0c855dcc 100644 --- a/src/mongo/db/storage/mmap_v1/mmap_v1_extent_manager.cpp +++ b/src/mongo/db/storage/mmap_v1/mmap_v1_extent_manager.cpp @@ -37,6 +37,7 @@ #include "mongo/base/counter.h" #include "mongo/db/audit.h" #include "mongo/db/client.h" +#include "mongo/db/concurrency/d_concurrency.h" #include "mongo/db/operation_context.h" #include "mongo/db/service_context.h" #include "mongo/db/storage/mmap_v1/data_file.h" diff --git a/src/mongo/db/storage/wiredtiger/wiredtiger_record_store_mongod.cpp b/src/mongo/db/storage/wiredtiger/wiredtiger_record_store_mongod.cpp index ef85a84bb4f..954317fb017 100644 --- a/src/mongo/db/storage/wiredtiger/wiredtiger_record_store_mongod.cpp +++ b/src/mongo/db/storage/wiredtiger/wiredtiger_record_store_mongod.cpp @@ -81,8 +81,6 @@ public: OperationContext& opCtx = *opCtxPtr; try { - ScopedTransaction transaction(&opCtx, MODE_IX); - AutoGetDb autoDb(&opCtx, _ns.db(), MODE_IX); Database* db = autoDb.getDb(); if (!db) { diff --git a/src/mongo/db/ttl.cpp b/src/mongo/db/ttl.cpp index c5ce7c49101..f9c1d9459d6 100644 --- a/src/mongo/db/ttl.cpp +++ b/src/mongo/db/ttl.cpp @@ -130,7 +130,6 @@ private: // Get all TTL indexes from every collection. for (const std::string& collectionNS : ttlCollections) { - ScopedTransaction st(&opCtx, MODE_IS); NamespaceString collectionNSS(collectionNS); AutoGetCollection autoGetCollection(&opCtx, collectionNSS, MODE_IS); Collection* coll = autoGetCollection.getCollection(); diff --git a/src/mongo/db/views/durable_view_catalog.cpp b/src/mongo/db/views/durable_view_catalog.cpp index 3034a82a453..757952ec598 100644 --- a/src/mongo/db/views/durable_view_catalog.cpp +++ b/src/mongo/db/views/durable_view_catalog.cpp @@ -37,6 +37,7 @@ #include "mongo/db/catalog/collection.h" #include "mongo/db/catalog/database.h" #include "mongo/db/catalog/database_holder.h" +#include "mongo/db/concurrency/d_concurrency.h" #include "mongo/db/dbhelpers.h" #include "mongo/db/namespace_string.h" #include "mongo/db/operation_context.h" diff --git a/src/mongo/dbtests/counttests.cpp b/src/mongo/dbtests/counttests.cpp index e20410a3f6c..72eef6f6097 100644 --- a/src/mongo/dbtests/counttests.cpp +++ b/src/mongo/dbtests/counttests.cpp @@ -51,8 +51,7 @@ const auto kIndexVersion = IndexDescriptor::IndexVersion::kV2; class Base { public: Base() - : _scopedXact(&_opCtx, MODE_IX), - _lk(_opCtx.lockState(), nsToDatabaseSubstring(ns()), MODE_X), + : _lk(&_opCtx, nsToDatabaseSubstring(ns()), MODE_X), _context(&_opCtx, ns()), _client(&_opCtx) { _database = _context.db(); @@ -112,9 +111,8 @@ protected: } - const ServiceContext::UniqueOperationContext _txnPtr = cc().makeOperationContext(); - OperationContext& _opCtx = *_txnPtr; - ScopedTransaction _scopedXact; + const ServiceContext::UniqueOperationContext _opCtxPtr = cc().makeOperationContext(); + OperationContext& _opCtx = *_opCtxPtr; Lock::DBLock _lk; OldClientContext _context; diff --git a/src/mongo/dbtests/dbhelper_tests.cpp b/src/mongo/dbtests/dbhelper_tests.cpp index 0d2255ebea9..29d89c9cc08 100644 --- a/src/mongo/dbtests/dbhelper_tests.cpp +++ b/src/mongo/dbtests/dbhelper_tests.cpp @@ -70,8 +70,7 @@ public: { // Remove _id range [_min, _max). - ScopedTransaction transaction(&opCtx, MODE_IX); - Lock::DBLock lk(opCtx.lockState(), nsToDatabaseSubstring(ns), MODE_X); + Lock::DBLock lk(&opCtx, nsToDatabaseSubstring(ns), MODE_X); OldClientContext ctx(&opCtx, ns); KeyRange range(ns, BSON("_id" << _min), BSON("_id" << _max), BSON("_id" << 1)); diff --git a/src/mongo/dbtests/indexcatalogtests.cpp b/src/mongo/dbtests/indexcatalogtests.cpp index fd1f10f8a55..a30fa5cc82f 100644 --- a/src/mongo/dbtests/indexcatalogtests.cpp +++ b/src/mongo/dbtests/indexcatalogtests.cpp @@ -40,8 +40,7 @@ public: IndexIteratorTests() { const ServiceContext::UniqueOperationContext opCtxPtr = cc().makeOperationContext(); OperationContext& opCtx = *opCtxPtr; - ScopedTransaction transaction(&opCtx, MODE_IX); - Lock::DBLock lk(opCtx.lockState(), nsToDatabaseSubstring(_ns), MODE_X); + Lock::DBLock lk(&opCtx, nsToDatabaseSubstring(_ns), MODE_X); OldClientContext ctx(&opCtx, _ns); WriteUnitOfWork wuow(&opCtx); @@ -54,8 +53,7 @@ public: ~IndexIteratorTests() { const ServiceContext::UniqueOperationContext opCtxPtr = cc().makeOperationContext(); OperationContext& opCtx = *opCtxPtr; - ScopedTransaction transaction(&opCtx, MODE_IX); - Lock::DBLock lk(opCtx.lockState(), nsToDatabaseSubstring(_ns), MODE_X); + Lock::DBLock lk(&opCtx, nsToDatabaseSubstring(_ns), MODE_X); OldClientContext ctx(&opCtx, _ns); WriteUnitOfWork wuow(&opCtx); @@ -109,8 +107,7 @@ public: RefreshEntry() { const ServiceContext::UniqueOperationContext opCtxPtr = cc().makeOperationContext(); OperationContext& opCtx = *opCtxPtr; - ScopedTransaction transaction(&opCtx, MODE_IX); - Lock::DBLock lk(opCtx.lockState(), nsToDatabaseSubstring(_ns), MODE_X); + Lock::DBLock lk(&opCtx, nsToDatabaseSubstring(_ns), MODE_X); OldClientContext ctx(&opCtx, _ns); WriteUnitOfWork wuow(&opCtx); @@ -123,8 +120,7 @@ public: ~RefreshEntry() { const ServiceContext::UniqueOperationContext opCtxPtr = cc().makeOperationContext(); OperationContext& opCtx = *opCtxPtr; - ScopedTransaction transaction(&opCtx, MODE_IX); - Lock::DBLock lk(opCtx.lockState(), nsToDatabaseSubstring(_ns), MODE_X); + Lock::DBLock lk(&opCtx, nsToDatabaseSubstring(_ns), MODE_X); OldClientContext ctx(&opCtx, _ns); WriteUnitOfWork wuow(&opCtx); diff --git a/src/mongo/dbtests/matchertests.cpp b/src/mongo/dbtests/matchertests.cpp index 9a762f017a0..9e60daa9eaf 100644 --- a/src/mongo/dbtests/matchertests.cpp +++ b/src/mongo/dbtests/matchertests.cpp @@ -234,7 +234,7 @@ public: const ServiceContext::UniqueOperationContext opCtxPtr = cc().makeOperationContext(); OperationContext& opCtx = *opCtxPtr; const NamespaceString nss("unittests.matchertests"); - AutoGetCollectionForRead ctx(&opCtx, nss); + AutoGetCollectionForReadCommand ctx(&opCtx, nss); const CollatorInterface* collator = nullptr; M m(BSON("$where" diff --git a/src/mongo/dbtests/mmaptests.cpp b/src/mongo/dbtests/mmaptests.cpp index b0afc3e916f..351019df663 100644 --- a/src/mongo/dbtests/mmaptests.cpp +++ b/src/mongo/dbtests/mmaptests.cpp @@ -75,9 +75,8 @@ public: } catch (...) { } - MMAPV1LockerImpl lockState; - Lock::GlobalWrite lk(&lockState); auto opCtx = cc().makeOperationContext(); + Lock::GlobalWrite lk(opCtx.get()); { DurableMappedFile f(opCtx.get()); diff --git a/src/mongo/dbtests/namespacetests.cpp b/src/mongo/dbtests/namespacetests.cpp index 81c6b3125b0..5a861b35ae8 100644 --- a/src/mongo/dbtests/namespacetests.cpp +++ b/src/mongo/dbtests/namespacetests.cpp @@ -547,8 +547,7 @@ public: const ServiceContext::UniqueOperationContext opCtxPtr = cc().makeOperationContext(); OperationContext& opCtx = *opCtxPtr; - ScopedTransaction transaction(&opCtx, MODE_IX); - Lock::DBLock lk(opCtx.lockState(), dbName, MODE_X); + Lock::DBLock lk(&opCtx, dbName, MODE_X); bool justCreated; Database* db = dbHolder().openDb(&opCtx, dbName, &justCreated); @@ -592,8 +591,7 @@ public: const ServiceContext::UniqueOperationContext opCtxPtr = cc().makeOperationContext(); OperationContext& opCtx = *opCtxPtr; - ScopedTransaction transaction(&opCtx, MODE_IX); - Lock::DBLock lk(opCtx.lockState(), dbName, MODE_X); + Lock::DBLock lk(&opCtx, dbName, MODE_X); bool justCreated; Database* db = dbHolder().openDb(&opCtx, dbName, &justCreated); diff --git a/src/mongo/dbtests/oplogstarttests.cpp b/src/mongo/dbtests/oplogstarttests.cpp index 4070d0b5440..de5c365f421 100644 --- a/src/mongo/dbtests/oplogstarttests.cpp +++ b/src/mongo/dbtests/oplogstarttests.cpp @@ -44,11 +44,7 @@ static const NamespaceString nss("unittests.oplogstarttests"); class Base { public: - Base() - : _scopedXact(&_opCtx, MODE_X), - _lk(_opCtx.lockState()), - _context(&_opCtx, nss.ns()), - _client(&_opCtx) { + Base() : _lk(&_opCtx), _context(&_opCtx, nss.ns()), _client(&_opCtx) { Collection* c = _context.db()->getCollection(nss.ns()); if (!c) { WriteUnitOfWork wuow(&_opCtx); @@ -99,9 +95,8 @@ protected: private: // The order of these is important in order to ensure order of destruction - const ServiceContext::UniqueOperationContext _txnPtr = cc().makeOperationContext(); - OperationContext& _opCtx = *_txnPtr; - ScopedTransaction _scopedXact; + const ServiceContext::UniqueOperationContext _opCtxPtr = cc().makeOperationContext(); + OperationContext& _opCtx = *_opCtxPtr; Lock::GlobalWrite _lk; OldClientContext _context; diff --git a/src/mongo/dbtests/pdfiletests.cpp b/src/mongo/dbtests/pdfiletests.cpp index 59eb024b5c5..65ed6a714cf 100644 --- a/src/mongo/dbtests/pdfiletests.cpp +++ b/src/mongo/dbtests/pdfiletests.cpp @@ -44,7 +44,7 @@ namespace PdfileTests { namespace Insert { class Base { public: - Base() : _scopedXact(&_opCtx, MODE_X), _lk(_opCtx.lockState()), _context(&_opCtx, ns()) {} + Base() : _lk(&_opCtx), _context(&_opCtx, ns()) {} virtual ~Base() { if (!collection()) @@ -62,9 +62,8 @@ protected: return _context.db()->getCollection(ns()); } - const ServiceContext::UniqueOperationContext _txnPtr = cc().makeOperationContext(); - OperationContext& _opCtx = *_txnPtr; - ScopedTransaction _scopedXact; + const ServiceContext::UniqueOperationContext _opCtxPtr = cc().makeOperationContext(); + OperationContext& _opCtx = *_opCtxPtr; Lock::GlobalWrite _lk; OldClientContext _context; }; diff --git a/src/mongo/dbtests/plan_ranking.cpp b/src/mongo/dbtests/plan_ranking.cpp index 44e2ddfba31..bbcd0b6a2d0 100644 --- a/src/mongo/dbtests/plan_ranking.cpp +++ b/src/mongo/dbtests/plan_ranking.cpp @@ -107,7 +107,7 @@ public: * Does NOT take ownership of 'cq'. Caller DOES NOT own the returned QuerySolution*. */ QuerySolution* pickBestPlan(CanonicalQuery* cq) { - AutoGetCollectionForRead ctx(&_opCtx, nss); + AutoGetCollectionForReadCommand ctx(&_opCtx, nss); Collection* collection = ctx.getCollection(); QueryPlannerParams plannerParams; diff --git a/src/mongo/dbtests/query_plan_executor.cpp b/src/mongo/dbtests/query_plan_executor.cpp index 7265c0e8dbc..5fbc726b51a 100644 --- a/src/mongo/dbtests/query_plan_executor.cpp +++ b/src/mongo/dbtests/query_plan_executor.cpp @@ -175,7 +175,7 @@ public: } size_t numCursors() { - AutoGetCollectionForRead ctx(&_opCtx, nss); + AutoGetCollectionForReadCommand ctx(&_opCtx, nss); Collection* collection = ctx.getCollection(); if (!collection) return 0; @@ -184,7 +184,7 @@ public: void registerExec(PlanExecutor* exec) { // TODO: This is not correct (create collection under S-lock) - AutoGetCollectionForRead ctx(&_opCtx, nss); + AutoGetCollectionForReadCommand ctx(&_opCtx, nss); WriteUnitOfWork wunit(&_opCtx); Collection* collection = ctx.getDb()->getOrCreateCollection(&_opCtx, nss.ns()); collection->getCursorManager()->registerExecutor(exec); @@ -193,7 +193,7 @@ public: void deregisterExec(PlanExecutor* exec) { // TODO: This is not correct (create collection under S-lock) - AutoGetCollectionForRead ctx(&_opCtx, nss); + AutoGetCollectionForReadCommand ctx(&_opCtx, nss); WriteUnitOfWork wunit(&_opCtx); Collection* collection = ctx.getDb()->getOrCreateCollection(&_opCtx, nss.ns()); collection->getCursorManager()->deregisterExecutor(exec); @@ -201,8 +201,8 @@ public: } protected: - const ServiceContext::UniqueOperationContext _txnPtr = cc().makeOperationContext(); - OperationContext& _opCtx = *_txnPtr; + const ServiceContext::UniqueOperationContext _opCtxPtr = cc().makeOperationContext(); + OperationContext& _opCtx = *_opCtxPtr; private: IndexDescriptor* getIndex(Database* db, const BSONObj& obj) { @@ -515,7 +515,7 @@ public: } { - AutoGetCollectionForRead ctx(&_opCtx, nss); + AutoGetCollectionForReadCommand ctx(&_opCtx, nss); Collection* collection = ctx.getCollection(); BSONObj filterObj = fromjson("{_id: {$gt: 0}, b: {$gt: 0}}"); diff --git a/src/mongo/dbtests/query_stage_cached_plan.cpp b/src/mongo/dbtests/query_stage_cached_plan.cpp index ed69f451117..48e9da129a1 100644 --- a/src/mongo/dbtests/query_stage_cached_plan.cpp +++ b/src/mongo/dbtests/query_stage_cached_plan.cpp @@ -78,8 +78,7 @@ public: } void dropCollection() { - ScopedTransaction transaction(&_opCtx, MODE_X); - Lock::DBLock dbLock(_opCtx.lockState(), nss.db(), MODE_X); + Lock::DBLock dbLock(&_opCtx, nss.db(), MODE_X); Database* database = dbHolder().get(&_opCtx, nss.db()); if (!database) { return; @@ -104,8 +103,8 @@ public: } protected: - const ServiceContext::UniqueOperationContext _txnPtr = cc().makeOperationContext(); - OperationContext& _opCtx = *_txnPtr; + const ServiceContext::UniqueOperationContext _opCtxPtr = cc().makeOperationContext(); + OperationContext& _opCtx = *_opCtxPtr; WorkingSet _ws; }; @@ -116,7 +115,7 @@ protected: class QueryStageCachedPlanFailure : public QueryStageCachedPlanBase { public: void run() { - AutoGetCollectionForRead ctx(&_opCtx, nss); + AutoGetCollectionForReadCommand ctx(&_opCtx, nss); Collection* collection = ctx.getCollection(); ASSERT(collection); @@ -184,7 +183,7 @@ public: class QueryStageCachedPlanHitMaxWorks : public QueryStageCachedPlanBase { public: void run() { - AutoGetCollectionForRead ctx(&_opCtx, nss); + AutoGetCollectionForReadCommand ctx(&_opCtx, nss); Collection* collection = ctx.getCollection(); ASSERT(collection); diff --git a/src/mongo/dbtests/query_stage_collscan.cpp b/src/mongo/dbtests/query_stage_collscan.cpp index e74ba02f361..e2db62bc4f4 100644 --- a/src/mongo/dbtests/query_stage_collscan.cpp +++ b/src/mongo/dbtests/query_stage_collscan.cpp @@ -84,7 +84,7 @@ public: } int countResults(CollectionScanParams::Direction direction, const BSONObj& filterObj) { - AutoGetCollectionForRead ctx(&_opCtx, nss); + AutoGetCollectionForReadCommand ctx(&_opCtx, nss); // Configure the scan. CollectionScanParams params; @@ -206,7 +206,7 @@ public: class QueryStageCollscanObjectsInOrderForward : public QueryStageCollectionScanBase { public: void run() { - AutoGetCollectionForRead ctx(&_opCtx, nss); + AutoGetCollectionForReadCommand ctx(&_opCtx, nss); // Configure the scan. CollectionScanParams params; @@ -242,7 +242,7 @@ public: class QueryStageCollscanObjectsInOrderBackward : public QueryStageCollectionScanBase { public: void run() { - AutoGetCollectionForRead ctx(&_opCtx, nss); + AutoGetCollectionForReadCommand ctx(&_opCtx, nss); CollectionScanParams params; params.collection = ctx.getCollection(); diff --git a/src/mongo/dbtests/query_stage_count.cpp b/src/mongo/dbtests/query_stage_count.cpp index 6a851dc9258..3f6e8fc3dc0 100644 --- a/src/mongo/dbtests/query_stage_count.cpp +++ b/src/mongo/dbtests/query_stage_count.cpp @@ -31,6 +31,7 @@ #include "mongo/platform/basic.h" #include "mongo/db/client.h" +#include "mongo/db/concurrency/d_concurrency.h" #include "mongo/db/db_raii.h" #include "mongo/db/exec/collection_scan.h" #include "mongo/db/exec/collection_scan_common.h" @@ -54,10 +55,7 @@ const int kInterjections = kDocuments; class CountStageTest { public: CountStageTest() - : _scopedXact(&_opCtx, MODE_IX), - _dbLock(_opCtx.lockState(), nsToDatabaseSubstring(ns()), MODE_X), - _ctx(&_opCtx, ns()), - _coll(NULL) {} + : _dbLock(&_opCtx, nsToDatabaseSubstring(ns()), MODE_X), _ctx(&_opCtx, ns()), _coll(NULL) {} virtual ~CountStageTest() {} @@ -233,9 +231,8 @@ public: protected: vector<RecordId> _recordIds; - const ServiceContext::UniqueOperationContext _txnPtr = cc().makeOperationContext(); - OperationContext& _opCtx = *_txnPtr; - ScopedTransaction _scopedXact; + const ServiceContext::UniqueOperationContext _opCtxPtr = cc().makeOperationContext(); + OperationContext& _opCtx = *_opCtxPtr; Lock::DBLock _dbLock; OldClientContext _ctx; Collection* _coll; diff --git a/src/mongo/dbtests/query_stage_distinct.cpp b/src/mongo/dbtests/query_stage_distinct.cpp index f5b2ac7bf48..e350e7cfd15 100644 --- a/src/mongo/dbtests/query_stage_distinct.cpp +++ b/src/mongo/dbtests/query_stage_distinct.cpp @@ -121,7 +121,7 @@ public: // Make an index on a:1 addIndex(BSON("a" << 1)); - AutoGetCollectionForRead ctx(&_opCtx, nss); + AutoGetCollectionForReadCommand ctx(&_opCtx, nss); Collection* coll = ctx.getCollection(); // Set up the distinct stage. @@ -188,7 +188,7 @@ public: // Make an index on a:1 addIndex(BSON("a" << 1)); - AutoGetCollectionForRead ctx(&_opCtx, nss); + AutoGetCollectionForReadCommand ctx(&_opCtx, nss); Collection* coll = ctx.getCollection(); // Set up the distinct stage. @@ -257,7 +257,7 @@ public: addIndex(BSON("a" << 1 << "b" << 1)); - AutoGetCollectionForRead ctx(&_opCtx, nss); + AutoGetCollectionForReadCommand ctx(&_opCtx, nss); Collection* coll = ctx.getCollection(); std::vector<IndexDescriptor*> indices; diff --git a/src/mongo/dbtests/query_stage_fetch.cpp b/src/mongo/dbtests/query_stage_fetch.cpp index 709e2d1b760..f44c03d7e26 100644 --- a/src/mongo/dbtests/query_stage_fetch.cpp +++ b/src/mongo/dbtests/query_stage_fetch.cpp @@ -82,8 +82,8 @@ public: } protected: - const ServiceContext::UniqueOperationContext _txnPtr = cc().makeOperationContext(); - OperationContext& _opCtx = *_txnPtr; + const ServiceContext::UniqueOperationContext _opCtxPtr = cc().makeOperationContext(); + OperationContext& _opCtx = *_opCtxPtr; DBDirectClient _client; }; @@ -158,8 +158,7 @@ public: class FetchStageFilter : public QueryStageFetchBase { public: void run() { - ScopedTransaction transaction(&_opCtx, MODE_IX); - Lock::DBLock lk(_opCtx.lockState(), nsToDatabaseSubstring(ns()), MODE_X); + Lock::DBLock lk(&_opCtx, nsToDatabaseSubstring(ns()), MODE_X); OldClientContext ctx(&_opCtx, ns()); Database* db = ctx.db(); Collection* coll = db->getCollection(ns()); diff --git a/src/mongo/dbtests/query_stage_ixscan.cpp b/src/mongo/dbtests/query_stage_ixscan.cpp index 7ee19d8f352..b2727d223d8 100644 --- a/src/mongo/dbtests/query_stage_ixscan.cpp +++ b/src/mongo/dbtests/query_stage_ixscan.cpp @@ -46,10 +46,7 @@ const auto kIndexVersion = IndexDescriptor::IndexVersion::kV2; class IndexScanTest { public: IndexScanTest() - : _scopedXact(&_opCtx, MODE_IX), - _dbLock(_opCtx.lockState(), nsToDatabaseSubstring(ns()), MODE_X), - _ctx(&_opCtx, ns()), - _coll(NULL) {} + : _dbLock(&_opCtx, nsToDatabaseSubstring(ns()), MODE_X), _ctx(&_opCtx, ns()), _coll(NULL) {} virtual ~IndexScanTest() {} @@ -147,10 +144,9 @@ public: } protected: - const ServiceContext::UniqueOperationContext _txnPtr = cc().makeOperationContext(); - OperationContext& _opCtx = *_txnPtr; + const ServiceContext::UniqueOperationContext _opCtxPtr = cc().makeOperationContext(); + OperationContext& _opCtx = *_opCtxPtr; - ScopedTransaction _scopedXact; Lock::DBLock _dbLock; OldClientContext _ctx; Collection* _coll; diff --git a/src/mongo/dbtests/query_stage_multiplan.cpp b/src/mongo/dbtests/query_stage_multiplan.cpp index 90185fd529d..59d06e93d05 100644 --- a/src/mongo/dbtests/query_stage_multiplan.cpp +++ b/src/mongo/dbtests/query_stage_multiplan.cpp @@ -133,7 +133,7 @@ public: addIndex(BSON("foo" << 1)); - AutoGetCollectionForRead ctx(&_opCtx, nss); + AutoGetCollectionForReadCommand ctx(&_opCtx, nss); const Collection* coll = ctx.getCollection(); // Plan 0: IXScan over foo == 7 @@ -227,7 +227,7 @@ public: addIndex(BSON("a" << 1)); addIndex(BSON("b" << 1)); - AutoGetCollectionForRead ctx(&_opCtx, nss); + AutoGetCollectionForReadCommand ctx(&_opCtx, nss); Collection* collection = ctx.getCollection(); // Query for both 'a' and 'b' and sort on 'b'. @@ -335,7 +335,7 @@ public: secondPlan->pushBack(PlanStage::NEED_TIME); } - AutoGetCollectionForRead ctx(&_opCtx, nss); + AutoGetCollectionForReadCommand ctx(&_opCtx, nss); auto qr = stdx::make_unique<QueryRequest>(nss); qr->setFilter(BSON("x" << 1)); @@ -413,7 +413,7 @@ public: addIndex(BSON("foo" << 1)); addIndex(BSON("foo" << -1 << "bar" << 1)); - AutoGetCollectionForRead ctx(&_opCtx, nss); + AutoGetCollectionForReadCommand ctx(&_opCtx, nss); Collection* coll = ctx.getCollection(); // Create the executor (Matching all documents). diff --git a/src/mongo/dbtests/query_stage_tests.cpp b/src/mongo/dbtests/query_stage_tests.cpp index 55326de7c63..852058ac005 100644 --- a/src/mongo/dbtests/query_stage_tests.cpp +++ b/src/mongo/dbtests/query_stage_tests.cpp @@ -79,7 +79,7 @@ public: } int countResults(const IndexScanParams& params, BSONObj filterObj = BSONObj()) { - AutoGetCollectionForRead ctx(&_opCtx, NamespaceString(ns())); + AutoGetCollectionForReadCommand ctx(&_opCtx, NamespaceString(ns())); const CollatorInterface* collator = nullptr; StatusWithMatchExpression statusWithMatcher = MatchExpressionParser::parse( @@ -117,7 +117,7 @@ public: } IndexDescriptor* getIndex(const BSONObj& obj) { - AutoGetCollectionForRead ctx(&_opCtx, NamespaceString(ns())); + AutoGetCollectionForReadCommand ctx(&_opCtx, NamespaceString(ns())); Collection* collection = ctx.getCollection(); std::vector<IndexDescriptor*> indexes; collection->getIndexCatalog()->findIndexesByKeyPattern(&_opCtx, obj, false, &indexes); diff --git a/src/mongo/dbtests/query_stage_update.cpp b/src/mongo/dbtests/query_stage_update.cpp index da49550c73a..3153037c9ed 100644 --- a/src/mongo/dbtests/query_stage_update.cpp +++ b/src/mongo/dbtests/query_stage_update.cpp @@ -227,7 +227,7 @@ public: // Verify the contents of the resulting collection. { - AutoGetCollectionForRead ctx(&_opCtx, nss); + AutoGetCollectionForReadCommand ctx(&_opCtx, nss); Collection* collection = ctx.getCollection(); vector<BSONObj> objs; @@ -336,7 +336,7 @@ public: // Check the contents of the collection. { - AutoGetCollectionForRead ctx(&_opCtx, nss); + AutoGetCollectionForReadCommand ctx(&_opCtx, nss); Collection* collection = ctx.getCollection(); vector<BSONObj> objs; diff --git a/src/mongo/dbtests/querytests.cpp b/src/mongo/dbtests/querytests.cpp index 83765c6ecd4..8171cb96cbe 100644 --- a/src/mongo/dbtests/querytests.cpp +++ b/src/mongo/dbtests/querytests.cpp @@ -65,7 +65,7 @@ const auto kIndexVersion = IndexDescriptor::IndexVersion::kV2; class Base { public: - Base() : _scopedXact(&_opCtx, MODE_X), _lk(_opCtx.lockState()), _context(&_opCtx, ns()) { + Base() : _lk(&_opCtx), _context(&_opCtx, ns()) { { WriteUnitOfWork wunit(&_opCtx); _database = _context.db(); @@ -121,9 +121,8 @@ protected: } - const ServiceContext::UniqueOperationContext _txnPtr = cc().makeOperationContext(); - OperationContext& _opCtx = *_txnPtr; - ScopedTransaction _scopedXact; + const ServiceContext::UniqueOperationContext _opCtxPtr = cc().makeOperationContext(); + OperationContext& _opCtx = *_opCtxPtr; Lock::GlobalWrite _lk; OldClientContext _context; @@ -188,8 +187,7 @@ public: 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(&_opCtx, MODE_X); - Lock::GlobalWrite lk(_opCtx.lockState()); + Lock::GlobalWrite lk(&_opCtx); OldClientContext ctx(&_opCtx, "unittests.querytests"); { @@ -336,7 +334,7 @@ public: // Check that the cursor has been removed. { - AutoGetCollectionForRead ctx(&_opCtx, NamespaceString(ns)); + AutoGetCollectionForReadCommand ctx(&_opCtx, NamespaceString(ns)); ASSERT(0 == ctx.getCollection()->getCursorManager()->numCursors()); } @@ -384,7 +382,7 @@ public: // Check that the cursor still exists { - AutoGetCollectionForRead ctx(&_opCtx, NamespaceString(ns)); + AutoGetCollectionForReadCommand ctx(&_opCtx, NamespaceString(ns)); ASSERT(1 == ctx.getCollection()->getCursorManager()->numCursors()); ASSERT_OK(ctx.getCollection()->getCursorManager()->pinCursor(cursorId).getStatus()); } @@ -661,8 +659,7 @@ public: _client.dropCollection(ns); _client.createCollection(ns, 10, true); - ScopedTransaction transaction(&_opCtx, MODE_IX); - Lock::DBLock lk(_opCtx.lockState(), "unittests", MODE_X); + Lock::DBLock lk(&_opCtx, "unittests", MODE_X); OldClientContext ctx(&_opCtx, ns); BSONObj info; @@ -1137,8 +1134,7 @@ private: class DirectLocking : public ClientBase { public: void run() { - ScopedTransaction transaction(&_opCtx, MODE_X); - Lock::GlobalWrite lk(_opCtx.lockState()); + Lock::GlobalWrite lk(&_opCtx); OldClientContext ctx(&_opCtx, "unittests.DirectLocking"); _client.remove("a.b", BSONObj()); ASSERT_EQUALS("unittests", ctx.db()->name()); @@ -1252,7 +1248,7 @@ public: } size_t numCursorsOpen() { - AutoGetCollectionForRead ctx(&_opCtx, NamespaceString(_ns)); + AutoGetCollectionForReadCommand ctx(&_opCtx, NamespaceString(_ns)); Collection* collection = ctx.getCollection(); if (!collection) return 0; @@ -1600,13 +1596,9 @@ public: class CollectionInternalBase : public CollectionBase { public: CollectionInternalBase(const char* nsLeaf) - : CollectionBase(nsLeaf), - _scopedXact(&_opCtx, MODE_IX), - _lk(_opCtx.lockState(), "unittests", MODE_X), - _ctx(&_opCtx, ns()) {} + : CollectionBase(nsLeaf), _lk(&_opCtx, "unittests", MODE_X), _ctx(&_opCtx, ns()) {} private: - ScopedTransaction _scopedXact; Lock::DBLock _lk; OldClientContext _ctx; }; @@ -1656,7 +1648,7 @@ public: ClientCursor* clientCursor = 0; { - AutoGetCollectionForRead ctx(&_opCtx, NamespaceString(ns())); + AutoGetCollectionForReadCommand ctx(&_opCtx, NamespaceString(ns())); auto clientCursorPin = unittest::assertGet(ctx.getCollection()->getCursorManager()->pinCursor(cursorId)); clientCursor = clientCursorPin.getCursor(); diff --git a/src/mongo/dbtests/repltests.cpp b/src/mongo/dbtests/repltests.cpp index cb2032f8ccc..637429b4921 100644 --- a/src/mongo/dbtests/repltests.cpp +++ b/src/mongo/dbtests/repltests.cpp @@ -68,8 +68,8 @@ BSONObj f(const char* s) { class Base { protected: - const ServiceContext::UniqueOperationContext _txnPtr = cc().makeOperationContext(); - OperationContext& _opCtx = *_txnPtr; + const ServiceContext::UniqueOperationContext _opCtxPtr = cc().makeOperationContext(); + OperationContext& _opCtx = *_opCtxPtr; mutable DBDirectClient _client; public: @@ -145,8 +145,7 @@ protected: return _client.findOne(cllNS(), BSONObj()); } int count() const { - ScopedTransaction transaction(&_opCtx, MODE_X); - Lock::GlobalWrite lk(_opCtx.lockState()); + Lock::GlobalWrite lk(&_opCtx); OldClientContext ctx(&_opCtx, ns()); Database* db = ctx.db(); Collection* coll = db->getCollection(ns()); @@ -167,8 +166,7 @@ protected: return DBDirectClient(&_opCtx).query(cllNS(), BSONObj())->itcount(); } void applyAllOperations() { - ScopedTransaction transaction(&_opCtx, MODE_X); - Lock::GlobalWrite lk(_opCtx.lockState()); + Lock::GlobalWrite lk(&_opCtx); vector<BSONObj> ops; { DBDirectClient db(&_opCtx); @@ -193,8 +191,7 @@ protected: } } void printAll(const char* ns) { - ScopedTransaction transaction(&_opCtx, MODE_X); - Lock::GlobalWrite lk(_opCtx.lockState()); + Lock::GlobalWrite lk(&_opCtx); OldClientContext ctx(&_opCtx, ns); Database* db = ctx.db(); @@ -213,8 +210,7 @@ protected: } // These deletes don't get logged. void deleteAll(const char* ns) const { - ScopedTransaction transaction(&_opCtx, MODE_X); - Lock::GlobalWrite lk(_opCtx.lockState()); + Lock::GlobalWrite lk(&_opCtx); OldClientContext ctx(&_opCtx, ns); WriteUnitOfWork wunit(&_opCtx); Database* db = ctx.db(); @@ -227,8 +223,7 @@ protected: wunit.commit(); } void insert(const BSONObj& o) const { - ScopedTransaction transaction(&_opCtx, MODE_X); - Lock::GlobalWrite lk(_opCtx.lockState()); + Lock::GlobalWrite lk(&_opCtx); OldClientContext ctx(&_opCtx, ns()); WriteUnitOfWork wunit(&_opCtx); Database* db = ctx.db(); @@ -1404,8 +1399,7 @@ public: << "foo" << "bar")); - ScopedTransaction transaction(&_opCtx, MODE_X); - Lock::GlobalWrite lk(_opCtx.lockState()); + Lock::GlobalWrite lk(&_opCtx); // this should fail because we can't connect try { diff --git a/src/mongo/dbtests/rollbacktests.cpp b/src/mongo/dbtests/rollbacktests.cpp index d9e70651178..50a7440fdb8 100644 --- a/src/mongo/dbtests/rollbacktests.cpp +++ b/src/mongo/dbtests/rollbacktests.cpp @@ -51,8 +51,7 @@ namespace { const auto kIndexVersion = IndexDescriptor::IndexVersion::kV2; void dropDatabase(OperationContext* opCtx, const NamespaceString& nss) { - ScopedTransaction transaction(opCtx, MODE_X); - Lock::GlobalWrite globalWriteLock(opCtx->lockState()); + Lock::GlobalWrite globalWriteLock(opCtx); Database* db = dbHolder().get(opCtx, nss.db()); if (db) { @@ -66,8 +65,7 @@ bool collectionExists(OldClientContext* ctx, const string& ns) { return std::find(names.begin(), names.end(), ns) != names.end(); } void createCollection(OperationContext* opCtx, const NamespaceString& nss) { - ScopedTransaction transaction(opCtx, MODE_IX); - Lock::DBLock dbXLock(opCtx->lockState(), nss.db(), MODE_X); + Lock::DBLock dbXLock(opCtx, nss.db(), MODE_X); OldClientContext ctx(opCtx, nss.ns()); { WriteUnitOfWork uow(opCtx); @@ -155,8 +153,7 @@ public: NamespaceString nss(ns); dropDatabase(&opCtx, nss); - ScopedTransaction transaction(&opCtx, MODE_IX); - Lock::DBLock dbXLock(opCtx.lockState(), nss.db(), MODE_X); + Lock::DBLock dbXLock(&opCtx, nss.db(), MODE_X); OldClientContext ctx(&opCtx, ns); { WriteUnitOfWork uow(&opCtx); @@ -187,8 +184,7 @@ public: NamespaceString nss(ns); dropDatabase(&opCtx, nss); - ScopedTransaction transaction(&opCtx, MODE_IX); - Lock::DBLock dbXLock(opCtx.lockState(), nss.db(), MODE_X); + Lock::DBLock dbXLock(&opCtx, nss.db(), MODE_X); OldClientContext ctx(&opCtx, ns); { WriteUnitOfWork uow(&opCtx); @@ -231,8 +227,7 @@ public: dropDatabase(&opCtx, source); dropDatabase(&opCtx, target); - ScopedTransaction transaction(&opCtx, MODE_X); - Lock::GlobalWrite globalWriteLock(opCtx.lockState()); + Lock::GlobalWrite globalWriteLock(&opCtx); OldClientContext ctx(&opCtx, source.ns()); { @@ -283,8 +278,7 @@ public: dropDatabase(&opCtx, source); dropDatabase(&opCtx, target); - ScopedTransaction transaction(&opCtx, MODE_X); - Lock::GlobalWrite globalWriteLock(opCtx.lockState()); + Lock::GlobalWrite globalWriteLock(&opCtx); OldClientContext ctx(&opCtx, source.ns()); BSONObj sourceDoc = BSON("_id" @@ -354,8 +348,7 @@ public: OperationContext& opCtx = *opCtxPtr; dropDatabase(&opCtx, nss); - ScopedTransaction transaction(&opCtx, MODE_IX); - Lock::DBLock dbXLock(opCtx.lockState(), nss.db(), MODE_X); + Lock::DBLock dbXLock(&opCtx, nss.db(), MODE_X); OldClientContext ctx(&opCtx, nss.ns()); BSONObj oldDoc = BSON("_id" @@ -415,8 +408,7 @@ public: OperationContext& opCtx = *opCtxPtr; dropDatabase(&opCtx, nss); - ScopedTransaction transaction(&opCtx, MODE_IX); - Lock::DBLock dbXLock(opCtx.lockState(), nss.db(), MODE_X); + Lock::DBLock dbXLock(&opCtx, nss.db(), MODE_X); OldClientContext ctx(&opCtx, nss.ns()); BSONObj doc = BSON("_id" @@ -456,8 +448,7 @@ public: OperationContext& opCtx = *opCtxPtr; dropDatabase(&opCtx, nss); - ScopedTransaction transaction(&opCtx, MODE_IX); - Lock::DBLock dbXLock(opCtx.lockState(), nss.db(), MODE_X); + Lock::DBLock dbXLock(&opCtx, nss.db(), MODE_X); OldClientContext ctx(&opCtx, nss.ns()); BSONObj doc = BSON("_id" @@ -513,7 +504,6 @@ public: dropDatabase(&opCtx, nss); createCollection(&opCtx, nss); - ScopedTransaction transaction(&opCtx, MODE_IX); AutoGetDb autoDb(&opCtx, nss.db(), MODE_X); Collection* coll = autoDb.getDb()->getCollection(ns); @@ -555,7 +545,6 @@ public: dropDatabase(&opCtx, nss); createCollection(&opCtx, nss); - ScopedTransaction transaction(&opCtx, MODE_IX); AutoGetDb autoDb(&opCtx, nss.db(), MODE_X); Collection* coll = autoDb.getDb()->getCollection(ns); @@ -609,7 +598,6 @@ public: dropDatabase(&opCtx, nss); createCollection(&opCtx, nss); - ScopedTransaction transaction(&opCtx, MODE_IX); AutoGetDb autoDb(&opCtx, nss.db(), MODE_X); Collection* coll = autoDb.getDb()->getCollection(ns); @@ -654,7 +642,6 @@ public: dropDatabase(&opCtx, nss); createCollection(&opCtx, nss); - ScopedTransaction transaction(&opCtx, MODE_IX); AutoGetDb autoDb(&opCtx, nss.db(), MODE_X); Collection* coll = autoDb.getDb()->getCollection(ns); @@ -717,8 +704,7 @@ public: NamespaceString nss(ns); dropDatabase(&opCtx, nss); - ScopedTransaction transaction(&opCtx, MODE_IX); - Lock::DBLock dbXLock(opCtx.lockState(), nss.db(), MODE_X); + Lock::DBLock dbXLock(&opCtx, nss.db(), MODE_X); OldClientContext ctx(&opCtx, nss.ns()); string idxNameA = "indexA"; diff --git a/src/mongo/s/catalog/sharding_catalog_config_initialization_test.cpp b/src/mongo/s/catalog/sharding_catalog_config_initialization_test.cpp index cb35f46c2df..6d5ee674f5c 100644 --- a/src/mongo/s/catalog/sharding_catalog_config_initialization_test.cpp +++ b/src/mongo/s/catalog/sharding_catalog_config_initialization_test.cpp @@ -221,7 +221,6 @@ TEST_F(ConfigInitializationTest, ReRunsIfDocRolledBackThenReElected) { repl::UnreplicatedWritesBlock uwb(opCtx); auto nss = NamespaceString(VersionType::ConfigNS); MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { - ScopedTransaction transaction(opCtx, MODE_IX); AutoGetCollection autoColl(opCtx, nss, MODE_IX); auto coll = autoColl.getCollection(); ASSERT_TRUE(coll); |