diff options
author | Ian Kuehne <ian.kuehne@mongodb.com> | 2017-07-03 13:10:24 -0400 |
---|---|---|
committer | Ian Kuehne <ian.kuehne@mongodb.com> | 2017-07-03 15:58:06 -0400 |
commit | acd196d77043d007b07b48b6e2c4fb13cfa5b938 (patch) | |
tree | ffd83f977e02211f7867bed6dc67d4efed71b0fe /src/mongo/db | |
parent | d362678ea9a9e4e948bfda0bc60e2fefdd1eb045 (diff) | |
download | mongo-acd196d77043d007b07b48b6e2c4fb13cfa5b938.tar.gz |
SERVER-29544 Remove deprecated macro calls.
Diffstat (limited to 'src/mongo/db')
36 files changed, 484 insertions, 501 deletions
diff --git a/src/mongo/db/catalog/create_collection.cpp b/src/mongo/db/catalog/create_collection.cpp index 9af83620ab6..283e10f267c 100644 --- a/src/mongo/db/catalog/create_collection.cpp +++ b/src/mongo/db/catalog/create_collection.cpp @@ -78,7 +78,7 @@ Status createCollection(OperationContext* opCtx, !options["capped"].trueValue() || options["size"].isNumber() || options.hasField("$nExtents")); - MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { + return writeConflictRetry(opCtx, "create", nss.ns(), [&] { Lock::DBLock dbXLock(opCtx, nss.db(), MODE_X); OldClientContext ctx(opCtx, nss.ns()); if (opCtx->writesAreReplicated() && @@ -93,14 +93,15 @@ Status createCollection(OperationContext* opCtx, const bool createDefaultIndexes = true; status = userCreateNS(opCtx, ctx.db(), nss.ns(), options, kind, createDefaultIndexes, idIndex); + if (!status.isOK()) { return status; } wunit.commit(); - } - MONGO_WRITE_CONFLICT_RETRY_LOOP_END(opCtx, "create", nss.ns()); - return Status::OK(); + + return Status::OK(); + }); } } // namespace @@ -132,72 +133,88 @@ Status createCollectionForApplyOps(OperationContext* opCtx, // create a database on MMAPv1, which could result in createCollection failing if the database // does not yet exist. if (ui.ok()) { - MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { - WriteUnitOfWork wunit(opCtx); - // Options need the field to be named "uuid", so parse/recreate. - auto uuid = uassertStatusOK(UUID::parse(ui)); - uassert(ErrorCodes::InvalidUUID, - "Invalid UUID in applyOps create command: " + uuid.toString(), - uuid.isRFC4122v4()); - - auto& catalog = UUIDCatalog::get(opCtx); - auto currentName = catalog.lookupNSSByUUID(uuid); - OpObserver* opObserver = getGlobalServiceContext()->getOpObserver(); - if (currentName == newCollName) - return Status::OK(); - - // In the case of oplog replay, a future command may have created or renamed a - // collection with that same name. In that case, renaming this future collection to a - // random temporary name is correct: once all entries are replayed no temporary names - // will remain. - // On MMAPv1 the rename can result in index names that are too long. However this should - // only happen for initial sync and "resync collection" for rollback, so we can let the - // error propagate resulting in an abort and restart of the initial sync or result in - // rollback to fassert, requiring a resync of that node. - const bool stayTemp = true; - if (auto futureColl = db ? db->getCollection(opCtx, newCollName) : nullptr) { - auto tmpName = NamespaceString(newCollName.db(), "tmp" + UUID::gen().toString()); - Status status = - db->renameCollection(opCtx, newCollName.ns(), tmpName.ns(), stayTemp); - if (!status.isOK()) - return status; - opObserver->onRenameCollection(opCtx, - newCollName, - tmpName, - futureColl->uuid(), - /*dropTarget*/ false, - /*dropTargetUUID*/ {}, - /*dropSourceUUID*/ {}, - stayTemp); - } - - // If the collection with the requested UUID already exists, but with a different name, - // just rename it to 'newCollName'. - if (catalog.lookupCollectionByUUID(uuid)) { - Status status = - db->renameCollection(opCtx, currentName.ns(), newCollName.ns(), stayTemp); - if (!status.isOK()) - return status; - opObserver->onRenameCollection(opCtx, - currentName, - newCollName, - uuid, - /*dropTarget*/ false, - /*dropTargetUUID*/ {}, - /*dropSourceUUID*/ {}, - stayTemp); - + // Return an optional, indicating whether we need to early return (if the collection already + // exists, or in case of an error). + using Result = boost::optional<Status>; + auto result = + writeConflictRetry(opCtx, "createCollectionForApplyOps", newCollName.ns(), [&] { + WriteUnitOfWork wunit(opCtx); + // Options need the field to be named "uuid", so parse/recreate. + auto uuid = uassertStatusOK(UUID::parse(ui)); + uassert(ErrorCodes::InvalidUUID, + "Invalid UUID in applyOps create command: " + uuid.toString(), + uuid.isRFC4122v4()); + + auto& catalog = UUIDCatalog::get(opCtx); + auto currentName = catalog.lookupNSSByUUID(uuid); + OpObserver* opObserver = getGlobalServiceContext()->getOpObserver(); + if (currentName == newCollName) + return Result(Status::OK()); + + // In the case of oplog replay, a future command may have created or renamed a + // collection with that same name. In that case, renaming this future collection to + // a + // random temporary name is correct: once all entries are replayed no temporary + // names + // will remain. + // On MMAPv1 the rename can result in index names that are too long. However this + // should + // only happen for initial sync and "resync collection" for rollback, so we can let + // the + // error propagate resulting in an abort and restart of the initial sync or result + // in + // rollback to fassert, requiring a resync of that node. + const bool stayTemp = true; + if (auto futureColl = db ? db->getCollection(opCtx, newCollName) : nullptr) { + auto tmpName = + NamespaceString(newCollName.db(), "tmp" + UUID::gen().toString()); + Status status = + db->renameCollection(opCtx, newCollName.ns(), tmpName.ns(), stayTemp); + if (!status.isOK()) + return Result(status); + opObserver->onRenameCollection(opCtx, + newCollName, + tmpName, + futureColl->uuid(), + /*dropTarget*/ false, + /*dropTargetUUID*/ {}, + /*dropSourceUUID*/ {}, + stayTemp); + } + + // If the collection with the requested UUID already exists, but with a different + // name, + // just rename it to 'newCollName'. + if (catalog.lookupCollectionByUUID(uuid)) { + Status status = + db->renameCollection(opCtx, currentName.ns(), newCollName.ns(), stayTemp); + if (!status.isOK()) + return Result(status); + opObserver->onRenameCollection(opCtx, + currentName, + newCollName, + uuid, + /*dropTarget*/ false, + /*dropTargetUUID*/ {}, + /*dropSourceUUID*/ {}, + stayTemp); + + wunit.commit(); + return Result(Status::OK()); + } + + // A new collection with the specific UUID must be created, so add the UUID to the + // creation options. Regular user collection creation commands cannot do this. + auto uuidObj = uuid.toBSON(); + newCmd = cmdObj.addField(uuidObj.firstElement()); wunit.commit(); - return Status::OK(); - } - - // A new collection with the specific UUID must be created, so add the UUID to the - // creation options. Regular user collection creation commands cannot do this. - auto uuidObj = uuid.toBSON(); - newCmd = cmdObj.addField(uuidObj.firstElement()); - wunit.commit(); + + return Result(boost::none); + }); + + if (result) { + return *result; } - MONGO_WRITE_CONFLICT_RETRY_LOOP_END(opCtx, "createCollectionForApplyOps", newCollName.ns()); } return createCollection( diff --git a/src/mongo/db/catalog/database_impl.cpp b/src/mongo/db/catalog/database_impl.cpp index 9933ea6f36c..e96bd7325d6 100644 --- a/src/mongo/db/catalog/database_impl.cpp +++ b/src/mongo/db/catalog/database_impl.cpp @@ -764,13 +764,12 @@ void DatabaseImpl::dropDatabase(OperationContext* opCtx, Database* db) { dbHolder().close(opCtx, name, "database dropped"); - MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { + writeConflictRetry(opCtx, "dropDatabase", name, [&] { getGlobalServiceContext() ->getGlobalStorageEngine() ->dropDatabase(opCtx, name) .transitional_ignore(); - } - MONGO_WRITE_CONFLICT_RETRY_LOOP_END(opCtx, "dropDatabase", name); + }); } namespace { @@ -803,20 +802,19 @@ void mongo::dropAllDatabasesExceptLocalImpl(OperationContext* opCtx) { repl::getGlobalReplicationCoordinator()->dropAllSnapshots(); - for (vector<string>::iterator i = n.begin(); i != n.end(); i++) { - if (*i != "local") { - MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { - Database* db = dbHolder().get(opCtx, *i); + for (const auto& dbName : n) { + if (dbName != "local") { + writeConflictRetry(opCtx, "dropAllDatabasesExceptLocal", dbName, [&opCtx, &dbName] { + Database* db = dbHolder().get(opCtx, dbName); // This is needed since dropDatabase can't be rolled back. // This is safe be replaced by "invariant(db);dropDatabase(opCtx, db);" once fixed if (db == nullptr) { - log() << "database disappeared after listDatabases but before drop: " << *i; + log() << "database disappeared after listDatabases but before drop: " << dbName; } else { DatabaseImpl::dropDatabase(opCtx, db); } - } - MONGO_WRITE_CONFLICT_RETRY_LOOP_END(opCtx, "dropAllDatabasesExceptLocal", *i); + }); } } } diff --git a/src/mongo/db/catalog/drop_collection.cpp b/src/mongo/db/catalog/drop_collection.cpp index 154d599fb49..46cd73e0766 100644 --- a/src/mongo/db/catalog/drop_collection.cpp +++ b/src/mongo/db/catalog/drop_collection.cpp @@ -60,7 +60,7 @@ Status dropCollection(OperationContext* opCtx, const std::string dbname = collectionName.db().toString(); - MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { + return writeConflictRetry(opCtx, "drop", collectionName.ns(), [&] { AutoGetDb autoDb(opCtx, dbname, MODE_X); Database* const db = autoDb.getDb(); Collection* coll = db ? db->getCollection(opCtx, collectionName) : nullptr; @@ -110,10 +110,9 @@ Status dropCollection(OperationContext* opCtx, } } wunit.commit(); - } - MONGO_WRITE_CONFLICT_RETRY_LOOP_END(opCtx, "drop", collectionName.ns()); - return Status::OK(); + return Status::OK(); + }); } } // namespace mongo diff --git a/src/mongo/db/catalog/drop_database.cpp b/src/mongo/db/catalog/drop_database.cpp index ef9bc6f8aa5..1df925e5b49 100644 --- a/src/mongo/db/catalog/drop_database.cpp +++ b/src/mongo/db/catalog/drop_database.cpp @@ -98,22 +98,25 @@ Status dropDatabase(OperationContext* opCtx, const std::string& dbName) { // collections to drop. repl::OpTime latestDropPendingOpTime; - MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { + using Result = boost::optional<Status>; + // Get an optional result--if it's there, early return; otherwise, wait for collections to drop. + auto result = writeConflictRetry(opCtx, "dropDatabase_collection", dbName, [&] { Lock::GlobalWrite lk(opCtx); AutoGetDb autoDB(opCtx, dbName, MODE_X); Database* const db = autoDB.getDb(); if (!db) { - return Status(ErrorCodes::NamespaceNotFound, - str::stream() << "Could not drop database " << dbName - << " because it does not exist"); + return Result(Status(ErrorCodes::NamespaceNotFound, + str::stream() << "Could not drop database " << dbName + << " because it does not exist")); } bool userInitiatedWritesAndNotPrimary = opCtx->writesAreReplicated() && !replCoord->canAcceptWritesForDatabase(opCtx, dbName); if (userInitiatedWritesAndNotPrimary) { - return Status(ErrorCodes::NotMaster, - str::stream() << "Not primary while dropping database " << dbName); + return Result( + Status(ErrorCodes::NotMaster, + str::stream() << "Not primary while dropping database " << dbName)); } log() << "dropDatabase " << dbName << " - starting"; @@ -145,10 +148,15 @@ Status dropDatabase(OperationContext* opCtx, const std::string& dbName) { // If there are no collection drops to wait for, we complete the drop database operation. if (numCollectionsToDrop == 0U && latestDropPendingOpTime.isNull()) { - return _finishDropDatabase(opCtx, dbName, db); + return Result(_finishDropDatabase(opCtx, dbName, db)); } + + return Result(boost::none); + }); + + if (result) { + return *result; } - MONGO_WRITE_CONFLICT_RETRY_LOOP_END(opCtx, "dropDatabase_collection", dbName); // If waitForWriteConcern() returns an error or throws an exception, we should reset the // drop-pending state on Database. @@ -214,7 +222,7 @@ Status dropDatabase(OperationContext* opCtx, const std::string& dbName) { dropPendingGuardWhileAwaitingReplication.Dismiss(); - MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { + return writeConflictRetry(opCtx, "dropDatabase_database", dbName, [&] { Lock::GlobalWrite lk(opCtx); AutoGetDb autoDB(opCtx, dbName, MODE_X); if (auto db = autoDB.getDb()) { @@ -226,10 +234,7 @@ Status dropDatabase(OperationContext* opCtx, const std::string& dbName) { << " because it does not exist after dropping " << numCollectionsToDrop << " collection(s)."); - } - MONGO_WRITE_CONFLICT_RETRY_LOOP_END(opCtx, "dropDatabase_database", dbName); - - MONGO_UNREACHABLE; + }); } } // namespace mongo diff --git a/src/mongo/db/catalog/drop_indexes.cpp b/src/mongo/db/catalog/drop_indexes.cpp index 2081f58d6ae..650a2acf32f 100644 --- a/src/mongo/db/catalog/drop_indexes.cpp +++ b/src/mongo/db/catalog/drop_indexes.cpp @@ -138,46 +138,47 @@ Status dropIndexes(OperationContext* opCtx, const NamespaceString& nss, const BSONObj& idxDescriptor, BSONObjBuilder* result) { - MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { - AutoGetDb autoDb(opCtx, nss.db(), MODE_X); + return writeConflictRetry( + opCtx, "dropIndexes", nss.db(), [opCtx, &nss, &idxDescriptor, result] { + AutoGetDb autoDb(opCtx, nss.db(), MODE_X); - bool userInitiatedWritesAndNotPrimary = opCtx->writesAreReplicated() && - !repl::getGlobalReplicationCoordinator()->canAcceptWritesFor(opCtx, nss); + bool userInitiatedWritesAndNotPrimary = opCtx->writesAreReplicated() && + !repl::getGlobalReplicationCoordinator()->canAcceptWritesFor(opCtx, nss); - if (userInitiatedWritesAndNotPrimary) { - return {ErrorCodes::NotMaster, - str::stream() << "Not primary while dropping indexes in " << nss.ns()}; - } - - if (!serverGlobalParams.quiet.load()) { - LOG(0) << "CMD: dropIndexes " << nss; - } + if (userInitiatedWritesAndNotPrimary) { + return Status(ErrorCodes::NotMaster, + str::stream() << "Not primary while dropping indexes in " + << nss.ns()); + } - // If db/collection does not exist, short circuit and return. - Database* db = autoDb.getDb(); - Collection* collection = db ? db->getCollection(opCtx, nss) : nullptr; - if (!db || !collection) { - if (db && db->getViewCatalog()->lookup(opCtx, nss.ns())) { - return {ErrorCodes::CommandNotSupportedOnView, - str::stream() << "Cannot drop indexes on view " << nss.ns()}; + if (!serverGlobalParams.quiet.load()) { + LOG(0) << "CMD: dropIndexes " << nss; } - return Status(ErrorCodes::NamespaceNotFound, "ns not found"); - } + // If db/collection does not exist, short circuit and return. + Database* db = autoDb.getDb(); + Collection* collection = db ? db->getCollection(opCtx, nss) : nullptr; + if (!db || !collection) { + if (db && db->getViewCatalog()->lookup(opCtx, nss.ns())) { + return Status(ErrorCodes::CommandNotSupportedOnView, + str::stream() << "Cannot drop indexes on view " << nss.ns()); + } - WriteUnitOfWork wunit(opCtx); - OldClientContext ctx(opCtx, nss.ns()); - BackgroundOperation::assertNoBgOpInProgForNs(nss); + return Status(ErrorCodes::NamespaceNotFound, "ns not found"); + } - Status status = wrappedRun(opCtx, collection, idxDescriptor, result); - if (!status.isOK()) { - return status; - } + WriteUnitOfWork wunit(opCtx); + OldClientContext ctx(opCtx, nss.ns()); + BackgroundOperation::assertNoBgOpInProgForNs(nss); - wunit.commit(); - } - MONGO_WRITE_CONFLICT_RETRY_LOOP_END(opCtx, "dropIndexes", nss.db()); - return Status::OK(); + Status status = wrappedRun(opCtx, collection, idxDescriptor, result); + if (!status.isOK()) { + return status; + } + + wunit.commit(); + return Status::OK(); + }); } } // namespace mongo diff --git a/src/mongo/db/catalog/rename_collection.cpp b/src/mongo/db/catalog/rename_collection.cpp index 2e71e2be1a0..604e0b8c6ea 100644 --- a/src/mongo/db/catalog/rename_collection.cpp +++ b/src/mongo/db/catalog/rename_collection.cpp @@ -164,7 +164,7 @@ Status renameCollection(OperationContext* opCtx, auto sourceUUID = sourceColl->uuid(); // If we are renaming in the same database, just rename the namespace and we're done. if (sourceDB == targetDB) { - MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { + return writeConflictRetry(opCtx, "renameCollection", target.ns(), [&] { WriteUnitOfWork wunit(opCtx); OptionalCollectionUUID dropTargetUUID; if (targetColl) { @@ -192,9 +192,8 @@ Status renameCollection(OperationContext* opCtx, stayTemp); wunit.commit(); - } - MONGO_WRITE_CONFLICT_RETRY_LOOP_END(opCtx, "renameCollection", target.ns()); - return Status::OK(); + return Status::OK(); + }); } @@ -218,7 +217,7 @@ Status renameCollection(OperationContext* opCtx, options.uuid = newUUID; } - MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { + writeConflictRetry(opCtx, "renameCollection", tmpName.ns(), [&] { WriteUnitOfWork wunit(opCtx); // No logOp necessary because the entire renameCollection command is one logOp. @@ -229,8 +228,7 @@ Status renameCollection(OperationContext* opCtx, false); // _id index build with others later. wunit.commit(); - } - MONGO_WRITE_CONFLICT_RETRY_LOOP_END(opCtx, "renameCollection", tmpName.ns()); + }); } // Dismissed on success @@ -270,7 +268,7 @@ Status renameCollection(OperationContext* opCtx, const auto obj = record->data.releaseToBson(); - MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { + status = writeConflictRetry(opCtx, "renameCollection", tmpName.ns(), [&] { WriteUnitOfWork wunit(opCtx); // No logOp necessary because the entire renameCollection command is one logOp. repl::UnreplicatedWritesBlock uwb(opCtx); @@ -278,8 +276,12 @@ Status renameCollection(OperationContext* opCtx, if (!status.isOK()) return status; wunit.commit(); + return Status::OK(); + }); + + if (!status.isOK()) { + return status; } - MONGO_WRITE_CONFLICT_RETRY_LOOP_END(opCtx, "renameCollection", tmpName.ns()); } } @@ -290,7 +292,7 @@ Status renameCollection(OperationContext* opCtx, // Getting here means we successfully built the target copy. We now do the final // in-place rename and remove the source collection. - MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { + status = writeConflictRetry(opCtx, "renameCollection", tmpName.ns(), [&] { WriteUnitOfWork wunit(opCtx); indexer.commit(); OptionalCollectionUUID dropTargetUUID; @@ -311,18 +313,15 @@ Status renameCollection(OperationContext* opCtx, } getGlobalServiceContext()->getOpObserver()->onRenameCollection( - opCtx, - source, - target, - newUUID, - dropTarget, - dropTargetUUID, - /*dropSourceUUID*/ sourceUUID, - stayTemp); + opCtx, source, target, newUUID, dropTarget, dropTargetUUID, sourceUUID, stayTemp); wunit.commit(); + return Status::OK(); + }); + + if (!status.isOK()) { + return status; } - MONGO_WRITE_CONFLICT_RETRY_LOOP_END(opCtx, "renameCollection", tmpName.ns()); tmpCollectionDropper.Dismiss(); return Status::OK(); diff --git a/src/mongo/db/cloner.cpp b/src/mongo/db/cloner.cpp index 0d294656632..a160d1fe383 100644 --- a/src/mongo/db/cloner.cpp +++ b/src/mongo/db/cloner.cpp @@ -162,7 +162,7 @@ struct Cloner::Fun { str::stream() << "collection dropped during clone [" << to_collection.ns() << "]", !createdCollection); - MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { + writeConflictRetry(opCtx, "createCollection", to_collection.ns(), [&] { opCtx->checkForInterrupt(); WriteUnitOfWork wunit(opCtx); @@ -177,8 +177,7 @@ struct Cloner::Fun { verify(s.isOK()); wunit.commit(); collection = db->getCollection(opCtx, to_collection); - } - MONGO_WRITE_CONFLICT_RETRY_LOOP_END(opCtx, "createCollection", to_collection.ns()); + }); } const bool isSystemViewsClone = to_collection.isSystemDotViews(); @@ -258,7 +257,8 @@ struct Cloner::Fun { verify(collection); ++numSeen; - MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { + + writeConflictRetry(opCtx, "cloner insert", to_collection.ns(), [&] { opCtx->checkForInterrupt(); WriteUnitOfWork wunit(opCtx); @@ -274,8 +274,8 @@ struct Cloner::Fun { if (status.isOK()) { wunit.commit(); } - } - MONGO_WRITE_CONFLICT_RETRY_LOOP_END(opCtx, "cloner insert", to_collection.ns()); + }); + RARELY if (time(0) - saveLast > 60) { log() << numSeen << " objects cloned so far from collection " << from_collection; saveLast = time(0); @@ -370,7 +370,7 @@ void Cloner::copyIndexes(OperationContext* opCtx, Collection* collection = db->getCollection(opCtx, to_collection); if (!collection) { - MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { + writeConflictRetry(opCtx, "createCollection", to_collection.ns(), [&] { opCtx->checkForInterrupt(); WriteUnitOfWork wunit(opCtx); @@ -387,8 +387,7 @@ void Cloner::copyIndexes(OperationContext* opCtx, collection = db->getCollection(opCtx, to_collection); invariant(collection); wunit.commit(); - } - MONGO_WRITE_CONFLICT_RETRY_LOOP_END(opCtx, "createCollection", to_collection.ns()); + }); } // TODO pass the MultiIndexBlock when inserting into the collection rather than building the @@ -469,7 +468,7 @@ bool Cloner::copyCollection(OperationContext* opCtx, Database* db = dbHolder().openDb(opCtx, dbname); if (shouldCreateCollection) { - MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { + bool result = writeConflictRetry(opCtx, "createCollection", ns, [&] { opCtx->checkForInterrupt(); WriteUnitOfWork wunit(opCtx); @@ -486,9 +485,14 @@ bool Cloner::copyCollection(OperationContext* opCtx, // abort write unit of work return false; } + wunit.commit(); + return true; + }); + + if (!result) { + return result; } - MONGO_WRITE_CONFLICT_RETRY_LOOP_END(opCtx, "createCollection", ns); } else { LOG(1) << "No collection info found for ns:" << nss.toString() << ", host:" << _conn->getServerAddress(); @@ -565,7 +569,7 @@ Status Cloner::createCollectionsForDb( const NamespaceString nss(dbName, params.collectionName); uassertStatusOK(userAllowedCreateNS(dbName, params.collectionName)); - MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { + Status status = writeConflictRetry(opCtx, "createCollection", nss.ns(), [&] { opCtx->checkForInterrupt(); WriteUnitOfWork wunit(opCtx); @@ -583,9 +587,15 @@ Status Cloner::createCollectionsForDb( } wunit.commit(); + return Status::OK(); + }); + + // Break early if one of the creations fails. + if (!status.isOK()) { + return status; } - MONGO_WRITE_CONFLICT_RETRY_LOOP_END(opCtx, "createCollection", nss.ns()); } + return Status::OK(); } diff --git a/src/mongo/db/commands/create_indexes.cpp b/src/mongo/db/commands/create_indexes.cpp index 77feecc13a0..4134c300cd0 100644 --- a/src/mongo/db/commands/create_indexes.cpp +++ b/src/mongo/db/commands/create_indexes.cpp @@ -267,13 +267,12 @@ public: return appendCommandStatus(result, {ErrorCodes::CommandNotSupportedOnView, errmsg}); } - MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { + writeConflictRetry(opCtx, kCommandName, ns.ns(), [&] { WriteUnitOfWork wunit(opCtx); collection = db->createCollection(opCtx, ns.ns(), CollectionOptions()); invariant(collection); wunit.commit(); - } - MONGO_WRITE_CONFLICT_RETRY_LOOP_END(opCtx, kCommandName, ns.ns()); + }); result.appendBool("createdCollectionAutomatically", true); } @@ -321,11 +320,10 @@ public: } } - std::vector<BSONObj> indexInfoObjs; - MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { - indexInfoObjs = uassertStatusOK(indexer.init(specs)); - } - MONGO_WRITE_CONFLICT_RETRY_LOOP_END(opCtx, kCommandName, ns.ns()); + std::vector<BSONObj> indexInfoObjs = + writeConflictRetry(opCtx, kCommandName, ns.ns(), [&indexer, &specs] { + return uassertStatusOK(indexer.init(specs)); + }); // If we're a background index, replace exclusive db lock with an intent lock, so that // other readers and writers can proceed during this phase. @@ -383,7 +381,7 @@ public: uassert(28552, "collection dropped during index build", db->getCollection(opCtx, ns)); } - MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { + writeConflictRetry(opCtx, kCommandName, ns.ns(), [&] { WriteUnitOfWork wunit(opCtx); indexer.commit(); @@ -394,8 +392,7 @@ public: } wunit.commit(); - } - MONGO_WRITE_CONFLICT_RETRY_LOOP_END(opCtx, kCommandName, ns.ns()); + }); result.append("numIndexesAfter", collection->getIndexCatalog()->numIndexesTotal(opCtx)); diff --git a/src/mongo/db/commands/dbcommands.cpp b/src/mongo/db/commands/dbcommands.cpp index 1c443cab40d..b1010263699 100644 --- a/src/mongo/db/commands/dbcommands.cpp +++ b/src/mongo/db/commands/dbcommands.cpp @@ -697,7 +697,7 @@ public: BSONObj query = BSON("files_id" << jsobj["filemd5"] << "n" << GTE << n); BSONObj sort = BSON("files_id" << 1 << "n" << 1); - MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { + return writeConflictRetry(opCtx, "filemd5", dbname, [&] { auto qr = stdx::make_unique<QueryRequest>(nss); qr->setFilter(query); qr->setSort(sort); @@ -706,7 +706,7 @@ public: opCtx, std::move(qr), ExtensionsCallbackDisallowExtensions()); if (!statusWithCQ.isOK()) { uasserted(17240, "Can't canonicalize query " + query.toString()); - return 0; + return false; } unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue()); @@ -724,7 +724,7 @@ public: QueryPlannerParams::NO_TABLE_SCAN); if (!statusWithPlanExecutor.isOK()) { uasserted(17241, "Can't get executor for query " + query.toString()); - return 0; + return false; } auto exec = std::move(statusWithPlanExecutor.getValue()); @@ -788,9 +788,9 @@ public: result.append("numChunks", n); result.append("md5", digestToString(d)); - } - MONGO_WRITE_CONFLICT_RETRY_LOOP_END(opCtx, "filemd5", dbname); - return true; + + return true; + }); } void dumpChunks(OperationContext* opCtx, diff --git a/src/mongo/db/commands/find_and_modify.cpp b/src/mongo/db/commands/find_and_modify.cpp index 202bbdbf8f6..07d8dd7eaea 100644 --- a/src/mongo/db/commands/find_and_modify.cpp +++ b/src/mongo/db/commands/find_and_modify.cpp @@ -379,7 +379,7 @@ public: // Although usually the PlanExecutor handles WCE internally, it will throw WCEs when it is // executing a findAndModify. This is done to ensure that we can always match, modify, and // return the document under concurrency, if a matching document exists. - MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { + bool success = writeConflictRetry(opCtx, "findAndModify", nsString.ns(), [&] { if (args.isRemove()) { DeleteRequest request(nsString); const bool isExplain = false; @@ -388,7 +388,8 @@ public: ParsedDelete parsedDelete(opCtx, &request); Status parsedDeleteStatus = parsedDelete.parseRequest(); if (!parsedDeleteStatus.isOK()) { - return appendCommandStatus(result, parsedDeleteStatus); + appendCommandStatus(result, parsedDeleteStatus); + return false; } AutoGetOrCreateDb autoDb(opCtx, dbName, MODE_IX); @@ -406,19 +407,22 @@ public: Status isPrimary = checkCanAcceptWritesForDatabase(opCtx, nsString); if (!isPrimary.isOK()) { - return appendCommandStatus(result, isPrimary); + appendCommandStatus(result, isPrimary); + return false; } Collection* const collection = autoDb.getDb()->getCollection(opCtx, nsString); if (!collection && autoDb.getDb()->getViewCatalog()->lookup(opCtx, nsString.ns())) { - return appendCommandStatus(result, - {ErrorCodes::CommandNotSupportedOnView, - "findAndModify not supported on a view"}); + appendCommandStatus(result, + {ErrorCodes::CommandNotSupportedOnView, + "findAndModify not supported on a view"}); + return false; } auto statusWithPlanExecutor = getExecutorDelete(opCtx, opDebug, collection, &parsedDelete); if (!statusWithPlanExecutor.isOK()) { - return appendCommandStatus(result, statusWithPlanExecutor.getStatus()); + appendCommandStatus(result, statusWithPlanExecutor.getStatus()); + return false; } const auto exec = std::move(statusWithPlanExecutor.getValue()); @@ -430,7 +434,8 @@ public: StatusWith<boost::optional<BSONObj>> advanceStatus = advanceExecutor(opCtx, exec.get(), args.isRemove()); if (!advanceStatus.isOK()) { - return appendCommandStatus(result, advanceStatus.getStatus()); + appendCommandStatus(result, advanceStatus.getStatus()); + return false; } // Nothing after advancing the plan executor should throw a WriteConflictException, // so the following bookkeeping with execution stats won't end up being done @@ -464,7 +469,8 @@ public: ParsedUpdate parsedUpdate(opCtx, &request); Status parsedUpdateStatus = parsedUpdate.parseRequest(); if (!parsedUpdateStatus.isOK()) { - return appendCommandStatus(result, parsedUpdateStatus); + appendCommandStatus(result, parsedUpdateStatus); + return false; } AutoGetOrCreateDb autoDb(opCtx, dbName, MODE_IX); @@ -482,14 +488,16 @@ public: Status isPrimary = checkCanAcceptWritesForDatabase(opCtx, nsString); if (!isPrimary.isOK()) { - return appendCommandStatus(result, isPrimary); + appendCommandStatus(result, isPrimary); + return false; } Collection* collection = autoDb.getDb()->getCollection(opCtx, nsString.ns()); if (!collection && autoDb.getDb()->getViewCatalog()->lookup(opCtx, nsString.ns())) { - return appendCommandStatus(result, - {ErrorCodes::CommandNotSupportedOnView, - "findAndModify not supported on a view"}); + appendCommandStatus(result, + {ErrorCodes::CommandNotSupportedOnView, + "findAndModify not supported on a view"}); + return false; } // Create the collection if it does not exist when performing an upsert @@ -501,7 +509,8 @@ public: collection = autoDb.getDb()->getCollection(opCtx, nsString); Status isPrimaryAfterRelock = checkCanAcceptWritesForDatabase(opCtx, nsString); if (!isPrimaryAfterRelock.isOK()) { - return appendCommandStatus(result, isPrimaryAfterRelock); + appendCommandStatus(result, isPrimaryAfterRelock); + return false; } if (collection) { @@ -511,7 +520,8 @@ public: Status createCollStatus = userCreateNS(opCtx, autoDb.getDb(), nsString.ns(), BSONObj()); if (!createCollStatus.isOK()) { - return appendCommandStatus(result, createCollStatus); + appendCommandStatus(result, createCollStatus); + return false; } wuow.commit(); @@ -523,7 +533,8 @@ public: auto statusWithPlanExecutor = getExecutorUpdate(opCtx, opDebug, collection, &parsedUpdate); if (!statusWithPlanExecutor.isOK()) { - return appendCommandStatus(result, statusWithPlanExecutor.getStatus()); + appendCommandStatus(result, statusWithPlanExecutor.getStatus()); + return false; } const auto exec = std::move(statusWithPlanExecutor.getValue()); @@ -535,7 +546,8 @@ public: StatusWith<boost::optional<BSONObj>> advanceStatus = advanceExecutor(opCtx, exec.get(), args.isRemove()); if (!advanceStatus.isOK()) { - return appendCommandStatus(result, advanceStatus.getStatus()); + appendCommandStatus(result, advanceStatus.getStatus()); + return false; } // Nothing after advancing the plan executor should throw a WriteConflictException, // so the following bookkeeping with execution stats won't end up being done @@ -559,8 +571,12 @@ public: boost::optional<BSONObj> value = advanceStatus.getValue(); appendCommandResponse(exec.get(), args.isRemove(), value, result); } + return true; + }); + + if (!success) { + return false; } - MONGO_WRITE_CONFLICT_RETRY_LOOP_END(opCtx, "findAndModify", nsString.ns()); if (repl::ReplClientInfo::forClient(client).getLastOp() != lastOpAtOperationStart) { // If this operation has already generated a new lastOp, don't bother setting it here. diff --git a/src/mongo/db/commands/fsync.cpp b/src/mongo/db/commands/fsync.cpp index 5359963d381..e776b10a451 100644 --- a/src/mongo/db/commands/fsync.cpp +++ b/src/mongo/db/commands/fsync.cpp @@ -366,10 +366,9 @@ void FSyncLockThread::run() { return; } try { - MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { + writeConflictRetry(&opCtx, "beginBackup", "global", [&storageEngine, &opCtx] { uassertStatusOK(storageEngine->beginBackup(&opCtx)); - } - MONGO_WRITE_CONFLICT_RETRY_LOOP_END(&opCtx, "beginBackup", "global"); + }); } catch (const DBException& e) { error() << "storage engine unable to begin backup : " << e.toString(); fsyncCmd.threadStatus = e.toStatus(); diff --git a/src/mongo/db/commands/list_indexes.cpp b/src/mongo/db/commands/list_indexes.cpp index bada0092be4..557390465f1 100644 --- a/src/mongo/db/commands/list_indexes.cpp +++ b/src/mongo/db/commands/list_indexes.cpp @@ -148,21 +148,19 @@ public: invariant(cce); vector<string> indexNames; - MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { + writeConflictRetry(opCtx, "listIndexes", ns.ns(), [&indexNames, &cce, &opCtx] { indexNames.clear(); cce->getAllIndexes(opCtx, &indexNames); - } - MONGO_WRITE_CONFLICT_RETRY_LOOP_END(opCtx, "listIndexes", ns.ns()); + }); auto ws = make_unique<WorkingSet>(); auto root = make_unique<QueuedDataStage>(opCtx, ws.get()); for (size_t i = 0; i < indexNames.size(); i++) { - BSONObj indexSpec; - MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { - indexSpec = cce->getIndexSpec(opCtx, indexNames[i]); - } - MONGO_WRITE_CONFLICT_RETRY_LOOP_END(opCtx, "listIndexes", ns.ns()); + BSONObj indexSpec = + writeConflictRetry(opCtx, "listIndexes", ns.ns(), [&cce, &opCtx, &indexNames, i] { + return cce->getIndexSpec(opCtx, indexNames[i]); + }); WorkingSetID id = ws->allocate(); WorkingSetMember* member = ws->get(id); diff --git a/src/mongo/db/commands/mr.cpp b/src/mongo/db/commands/mr.cpp index 02eb08c1aab..4f4460df780 100644 --- a/src/mongo/db/commands/mr.cpp +++ b/src/mongo/db/commands/mr.cpp @@ -368,7 +368,7 @@ Config::Config(const string& _dbname, const BSONObj& cmdObj) { */ void State::dropTempCollections() { if (!_config.tempNamespace.isEmpty()) { - MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { + writeConflictRetry(_opCtx, "M/R dropTempCollections", _config.tempNamespace.ns(), [this] { AutoGetDb autoDb(_opCtx, _config.tempNamespace.db(), MODE_X); if (auto db = autoDb.getDb()) { WriteUnitOfWork wunit(_opCtx); @@ -379,9 +379,7 @@ void State::dropTempCollections() { db->dropCollection(_opCtx, _config.tempNamespace.ns()).transitional_ignore(); wunit.commit(); } - } - MONGO_WRITE_CONFLICT_RETRY_LOOP_END( - _opCtx, "M/R dropTempCollections", _config.tempNamespace.ns()); + }); // Always forget about temporary namespaces, so we don't cache lots of them ShardConnection::forgetNS(_config.tempNamespace.ns()); } @@ -390,16 +388,14 @@ void State::dropTempCollections() { // harmless, this would lead to a scary looking warning on the secondaries. repl::UnreplicatedWritesBlock uwb(_opCtx); - MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { + writeConflictRetry(_opCtx, "M/R dropTempCollections", _config.incLong.ns(), [this] { 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()).transitional_ignore(); wunit.commit(); } - } - MONGO_WRITE_CONFLICT_RETRY_LOOP_END( - _opCtx, "M/R dropTempCollections", _config.incLong.ns()); + }); ShardConnection::forgetNS(_config.incLong.ns()); } @@ -418,7 +414,7 @@ void State::prepTempCollection() { // Intentionally not replicating the inc collection to secondaries. repl::UnreplicatedWritesBlock uwb(_opCtx); - MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { + writeConflictRetry(_opCtx, "M/R prepTempCollection", _config.incLong.ns(), [this] { OldClientWriteContext incCtx(_opCtx, _config.incLong.ns()); WriteUnitOfWork wuow(_opCtx); Collection* incColl = incCtx.getCollection(); @@ -450,8 +446,7 @@ void State::prepTempCollection() { << status.code()); } wuow.commit(); - } - MONGO_WRITE_CONFLICT_RETRY_LOOP_END(_opCtx, "M/R prepTempCollection", _config.incLong.ns()); + }); } CollectionOptions finalOptions; @@ -485,7 +480,7 @@ void State::prepTempCollection() { } } - MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { + writeConflictRetry(_opCtx, "M/R prepTempCollection", _config.tempNamespace.ns(), [&] { // create temp collection and insert the indexes from temporary storage OldClientWriteContext tempCtx(_opCtx, _config.tempNamespace.ns()); WriteUnitOfWork wuow(_opCtx); @@ -519,9 +514,7 @@ void State::prepTempCollection() { _opCtx, _config.tempNamespace, uuid, *it, false); } wuow.commit(); - } - MONGO_WRITE_CONFLICT_RETRY_LOOP_END( - _opCtx, "M/R prepTempCollection", _config.tempNamespace.ns()); + }); } /** @@ -741,7 +734,7 @@ long long State::postProcessCollectionNonAtomic(OperationContext* opCtx, void State::insert(const NamespaceString& nss, const BSONObj& o) { verify(_onDisk); - MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { + writeConflictRetry(_opCtx, "M/R insert", nss.ns(), [this, &nss, &o] { OldClientWriteContext ctx(_opCtx, nss.ns()); WriteUnitOfWork wuow(_opCtx); uassert(ErrorCodes::PrimarySteppedDown, @@ -766,8 +759,7 @@ void State::insert(const NamespaceString& nss, const BSONObj& o) { OpDebug* const nullOpDebug = nullptr; uassertStatusOK(coll->insertDocument(_opCtx, bo, nullOpDebug, true)); wuow.commit(); - } - MONGO_WRITE_CONFLICT_RETRY_LOOP_END(_opCtx, "M/R insert", nss.ns()); + }); } /** @@ -776,7 +768,7 @@ void State::insert(const NamespaceString& nss, const BSONObj& o) { void State::_insertToInc(BSONObj& o) { verify(_onDisk); - MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { + writeConflictRetry(_opCtx, "M/R insertToInc", _config.incLong.ns(), [this, &o] { OldClientWriteContext ctx(_opCtx, _config.incLong.ns()); WriteUnitOfWork wuow(_opCtx); Collection* coll = getCollectionOrUassert(_opCtx, ctx.db(), _config.incLong); @@ -799,8 +791,7 @@ void State::_insertToInc(BSONObj& o) { OpDebug* const nullOpDebug = nullptr; uassertStatusOK(coll->insertDocument(_opCtx, o, nullOpDebug, true, false)); wuow.commit(); - } - MONGO_WRITE_CONFLICT_RETRY_LOOP_END(_opCtx, "M/R insertToInc", _config.incLong.ns()); + }); } State::State(OperationContext* opCtx, const Config& c) @@ -1066,7 +1057,7 @@ void State::finalReduce(OperationContext* opCtx, CurOp* curOp, ProgressMeterHold verify(_temp->size() == 0); BSONObj sortKey = BSON("0" << 1); - MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { + writeConflictRetry(_opCtx, "finalReduce", _config.incLong.ns(), [&] { OldClientWriteContext incCtx(_opCtx, _config.incLong.ns()); WriteUnitOfWork wuow(_opCtx); Collection* incColl = getCollectionOrUassert(_opCtx, incCtx.db(), _config.incLong); @@ -1085,8 +1076,7 @@ void State::finalReduce(OperationContext* opCtx, CurOp* curOp, ProgressMeterHold verify(foundIndex); wuow.commit(); - } - MONGO_WRITE_CONFLICT_RETRY_LOOP_END(_opCtx, "finalReduce", _config.incLong.ns()); + }); unique_ptr<AutoGetCollectionForReadCommand> ctx( new AutoGetCollectionForReadCommand(_opCtx, _config.incLong)); diff --git a/src/mongo/db/commands/oplog_note.cpp b/src/mongo/db/commands/oplog_note.cpp index 371057a68fa..d1edfcbdfb9 100644 --- a/src/mongo/db/commands/oplog_note.cpp +++ b/src/mongo/db/commands/oplog_note.cpp @@ -69,12 +69,11 @@ Status _performNoopWrite(OperationContext* opCtx, BSONObj msgObj, StringData not return {ErrorCodes::NotMaster, "Not a primary"}; } - MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { + writeConflictRetry(opCtx, note, repl::rsOplogName, [&opCtx, &msgObj] { WriteUnitOfWork uow(opCtx); opCtx->getClient()->getServiceContext()->getOpObserver()->onOpMessage(opCtx, msgObj); uow.commit(); - } - MONGO_WRITE_CONFLICT_RETRY_LOOP_END(opCtx, note, repl::rsOplogName); + }); return Status::OK(); } diff --git a/src/mongo/db/concurrency/write_conflict_exception.h b/src/mongo/db/concurrency/write_conflict_exception.h index 5a053502727..a15086ae83c 100644 --- a/src/mongo/db/concurrency/write_conflict_exception.h +++ b/src/mongo/db/concurrency/write_conflict_exception.h @@ -36,30 +36,6 @@ #include "mongo/db/curop.h" #include "mongo/util/assert_util.h" -// Use of this macro is deprecated. Prefer the writeConflictRetry template, below, instead. - -// clang-format off - -#define MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN \ - do { \ - int WCR_attempts = 0; \ - do { \ - try -#define MONGO_WRITE_CONFLICT_RETRY_LOOP_END(PTXN, OPSTR, NSSTR) \ - catch (const ::mongo::WriteConflictException& WCR_wce) { \ - OperationContext const* WCR_opCtx = (PTXN); \ - ++CurOp::get(WCR_opCtx)->debug().writeConflicts; \ - WCR_wce.logAndBackoff(WCR_attempts, (OPSTR), (NSSTR)); \ - ++WCR_attempts; \ - WCR_opCtx->recoveryUnit()->abandonSnapshot(); \ - continue; \ - } \ - break; \ - } while (true); \ - } while (false) - -// clang-format on - namespace mongo { /** diff --git a/src/mongo/db/exec/update.cpp b/src/mongo/db/exec/update.cpp index c3dae9389fb..879a5c7db05 100644 --- a/src/mongo/db/exec/update.cpp +++ b/src/mongo/db/exec/update.cpp @@ -476,7 +476,8 @@ void UpdateStage::doInsert() { if (request->isExplain()) { return; } - MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { + + writeConflictRetry(getOpCtx(), "upsert", _collection->ns().ns(), [&] { WriteUnitOfWork wunit(getOpCtx()); invariant(_collection); const bool enforceQuota = !request->isGod(); @@ -486,8 +487,7 @@ void UpdateStage::doInsert() { // Technically, we should save/restore state here, but since we are going to return // immediately after, it would just be wasted work. wunit.commit(); - } - MONGO_WRITE_CONFLICT_RETRY_LOOP_END(getOpCtx(), "upsert", _collection->ns().ns()); + }); } bool UpdateStage::doneUpdating() { diff --git a/src/mongo/db/index/index_access_method.cpp b/src/mongo/db/index/index_access_method.cpp index b52092a6cb0..80d031a680c 100644 --- a/src/mongo/db/index/index_access_method.cpp +++ b/src/mongo/db/index/index_access_method.cpp @@ -475,7 +475,7 @@ Status IndexAccessMethod::commitBulk(OperationContext* opCtx, std::unique_ptr<SortedDataBuilderInterface> builder; - MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { + writeConflictRetry(opCtx, "setting index multikey flag", "", [&] { WriteUnitOfWork wunit(opCtx); if (bulk->_everGeneratedMultipleKeys || isMultikeyFromPaths(bulk->_indexMultikeyPaths)) { @@ -484,8 +484,7 @@ Status IndexAccessMethod::commitBulk(OperationContext* opCtx, builder.reset(_newInterface->getBulkBuilder(opCtx, dupsAllowed)); wunit.commit(); - } - MONGO_WRITE_CONFLICT_RETRY_LOOP_END(opCtx, "setting index multikey flag", ""); + }); while (i->more()) { if (mayInterrupt) { diff --git a/src/mongo/db/ops/update.cpp b/src/mongo/db/ops/update.cpp index 078d2f30f25..86822feef00 100644 --- a/src/mongo/db/ops/update.cpp +++ b/src/mongo/db/ops/update.cpp @@ -86,7 +86,7 @@ UpdateResult update(OperationContext* opCtx, Database* db, const UpdateRequest& invariant(locker->isW() || locker->isLockHeldForMode(ResourceId(RESOURCE_DATABASE, nsString.db()), MODE_X)); - MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { + writeConflictRetry(opCtx, "createCollection", nsString.ns(), [&] { Lock::DBLock lk(opCtx, nsString.db(), MODE_X); const bool userInitiatedWritesAndNotPrimary = opCtx->writesAreReplicated() && @@ -102,8 +102,7 @@ UpdateResult update(OperationContext* opCtx, Database* db, const UpdateRequest& collection = db->createCollection(opCtx, nsString.ns(), CollectionOptions()); invariant(collection); wuow.commit(); - } - MONGO_WRITE_CONFLICT_RETRY_LOOP_END(opCtx, "createCollection", nsString.ns()); + }); } // Parse the update, get an executor for it, run the executor, get stats out. diff --git a/src/mongo/db/ops/write_ops_exec.cpp b/src/mongo/db/ops/write_ops_exec.cpp index 3c3b9394296..8991ab15224 100644 --- a/src/mongo/db/ops/write_ops_exec.cpp +++ b/src/mongo/db/ops/write_ops_exec.cpp @@ -175,7 +175,7 @@ void assertCanWrite_inlock(OperationContext* opCtx, const NamespaceString& ns) { } void makeCollection(OperationContext* opCtx, const NamespaceString& ns) { - MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { + writeConflictRetry(opCtx, "implicit collection creation", ns.ns(), [&opCtx, &ns] { AutoGetOrCreateDb db(opCtx, ns.db(), MODE_X); assertCanWrite_inlock(opCtx, ns); if (!db.getDb()->getCollection(opCtx, ns)) { // someone else may have beat us to it. @@ -183,8 +183,7 @@ void makeCollection(OperationContext* opCtx, const NamespaceString& ns) { uassertStatusOK(userCreateNS(opCtx, db.getDb(), ns.ns(), BSONObj())); wuow.commit(); } - } - MONGO_WRITE_CONFLICT_RETRY_LOOP_END(opCtx, "implicit collection creation", ns.ns()); + }); } /** @@ -371,7 +370,7 @@ static bool insertBatchAndHandleErrors(OperationContext* opCtx, for (auto it = batch.begin(); it != batch.end(); ++it) { globalOpCounters.gotInsert(); try { - MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { + writeConflictRetry(opCtx, "insert", wholeOp.ns.ns(), [&] { try { if (!collection) acquireCollection(); @@ -388,8 +387,7 @@ static bool insertBatchAndHandleErrors(OperationContext* opCtx, collection.reset(); throw; } - } - MONGO_WRITE_CONFLICT_RETRY_LOOP_END(opCtx, "insert", wholeOp.ns.ns()); + }); } catch (const DBException& ex) { bool canContinue = handleError(opCtx, ex, wholeOp, out); if (!canContinue) diff --git a/src/mongo/db/query/plan_yield_policy.cpp b/src/mongo/db/query/plan_yield_policy.cpp index b7a8f0225ea..52633ea0185 100644 --- a/src/mongo/db/query/plan_yield_policy.cpp +++ b/src/mongo/db/query/plan_yield_policy.cpp @@ -86,8 +86,7 @@ bool PlanYieldPolicy::yield(RecordFetcher* fetcher) { invariant(opCtx); invariant(!opCtx->lockState()->inAWriteUnitOfWork()); - // Can't use MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN/END since we need to call saveState - // before reseting the transaction. + // Can't use writeConflictRetry since we need to call saveState before reseting the transaction. for (int attempt = 1; true; attempt++) { try { // All YIELD_AUTO plans will get here eventually when the elapsed tracker triggers diff --git a/src/mongo/db/read_concern.cpp b/src/mongo/db/read_concern.cpp index a2f79eeea95..b0266a169af 100644 --- a/src/mongo/db/read_concern.cpp +++ b/src/mongo/db/read_concern.cpp @@ -245,17 +245,14 @@ Status waitForLinearizableReadConcern(OperationContext* opCtx) { "No longer primary when waiting for linearizable read concern"}; } - MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { - + writeConflictRetry(opCtx, "waitForLinearizableReadConcern", "local.rs.oplog", [&opCtx] { WriteUnitOfWork uow(opCtx); opCtx->getClient()->getServiceContext()->getOpObserver()->onOpMessage( opCtx, BSON("msg" << "linearizable read")); uow.commit(); - } - MONGO_WRITE_CONFLICT_RETRY_LOOP_END( - opCtx, "waitForLinearizableReadConcern", "local.rs.oplog"); + }); } WriteConcernOptions wc = WriteConcernOptions( WriteConcernOptions::kMajority, WriteConcernOptions::SyncMode::UNSET, 0); diff --git a/src/mongo/db/repl/apply_ops.cpp b/src/mongo/db/repl/apply_ops.cpp index 446133b79ad..d08cff9f8a5 100644 --- a/src/mongo/db/repl/apply_ops.cpp +++ b/src/mongo/db/repl/apply_ops.cpp @@ -145,7 +145,7 @@ Status _applyOps(OperationContext* opCtx, return status; } else { try { - MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { + writeConflictRetry(opCtx, "applyOps", ns, [&] { if (*opType == 'c') { status = repl::applyCommand_inlock(opCtx, opObj, true); } else { @@ -181,8 +181,7 @@ Status _applyOps(OperationContext* opCtx, repl::applyOperation_inlock(opCtx, ctx.db(), opObj, alwaysUpsert); } } - } - MONGO_WRITE_CONFLICT_RETRY_LOOP_END(opCtx, "applyOps", ns); + }); } catch (const DBException& ex) { ab.append(false); result->append("applied", ++(*numApplied)); @@ -288,7 +287,7 @@ mongo::Status mongo::applyOps(OperationContext* opCtx, // Perform write ops atomically try { - MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { + writeConflictRetry(opCtx, "applyOps", dbName, [&] { BSONObjBuilder intermediateResult; WriteUnitOfWork wunit(opCtx); numApplied = 0; @@ -322,8 +321,7 @@ mongo::Status mongo::applyOps(OperationContext* opCtx, } wunit.commit(); result->appendElements(intermediateResult.obj()); - } - MONGO_WRITE_CONFLICT_RETRY_LOOP_END(opCtx, "applyOps", dbName); + }); } catch (const DBException& ex) { if (ex.getCode() == ErrorCodes::NamespaceNotFound) { // Retry in non-atomic mode, since MMAP cannot implicitly create a new database diff --git a/src/mongo/db/repl/bgsync.cpp b/src/mongo/db/repl/bgsync.cpp index 5eeb0136c16..e0b2e7a9be7 100644 --- a/src/mongo/db/repl/bgsync.cpp +++ b/src/mongo/db/repl/bgsync.cpp @@ -837,16 +837,16 @@ void BackgroundSync::clearBuffer(OperationContext* opCtx) { OpTimeWithHash BackgroundSync::_readLastAppliedOpTimeWithHash(OperationContext* opCtx) { BSONObj oplogEntry; try { - MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { + bool success = writeConflictRetry(opCtx, "readLastAppliedHash", rsOplogName, [&] { 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 - // after the initial sync is complete. - return OpTimeWithHash(0); - } + return Helpers::getLast(opCtx, rsOplogName.c_str(), oplogEntry); + }); + + if (!success) { + // This can happen when we are to do an initial sync. lastHash will be set + // after the initial sync is complete. + return OpTimeWithHash(0); } - MONGO_WRITE_CONFLICT_RETRY_LOOP_END(opCtx, "readLastAppliedHash", rsOplogName); } catch (const DBException& ex) { severe() << "Problem reading " << rsOplogName << ": " << redact(ex); fassertFailed(18904); diff --git a/src/mongo/db/repl/collection_bulk_loader_impl.cpp b/src/mongo/db/repl/collection_bulk_loader_impl.cpp index abfe67a63cb..c7118429ba9 100644 --- a/src/mongo/db/repl/collection_bulk_loader_impl.cpp +++ b/src/mongo/db/repl/collection_bulk_loader_impl.cpp @@ -152,30 +152,37 @@ Status CollectionBulkLoaderImpl::insertDocuments(const std::vector<BSONObj>::con if (_secondaryIndexesBlock) { indexers.push_back(_secondaryIndexesBlock.get()); } - MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { - WriteUnitOfWork wunit(_opCtx.get()); - if (!indexers.empty()) { - // This flavor of insertDocument will not update any pre-existing indexes, only - // the indexers passed in. - const auto status = _autoColl->getCollection()->insertDocument( - _opCtx.get(), *iter, indexers, false); - if (!status.isOK()) { - return status; - } - } else { - // For capped collections, we use regular insertDocument, which will update - // pre-existing indexes. - const auto status = _autoColl->getCollection()->insertDocument( - _opCtx.get(), *iter, nullptr, false); - if (!status.isOK()) { - return status; + + Status status = writeConflictRetry( + _opCtx.get(), "CollectionBulkLoaderImpl::insertDocuments", _nss.ns(), [&] { + WriteUnitOfWork wunit(_opCtx.get()); + if (!indexers.empty()) { + // This flavor of insertDocument will not update any pre-existing indexes, + // only + // the indexers passed in. + const auto status = _autoColl->getCollection()->insertDocument( + _opCtx.get(), *iter, indexers, false); + if (!status.isOK()) { + return status; + } + } else { + // For capped collections, we use regular insertDocument, which will update + // pre-existing indexes. + const auto status = _autoColl->getCollection()->insertDocument( + _opCtx.get(), *iter, nullptr, false); + if (!status.isOK()) { + return status; + } } - } - wunit.commit(); + wunit.commit(); + + return Status::OK(); + }); + + if (!status.isOK()) { + return status; } - MONGO_WRITE_CONFLICT_RETRY_LOOP_END( - _opCtx.get(), "CollectionBulkLoaderImpl::insertDocuments", _nss.ns()); ++count; } @@ -203,13 +210,11 @@ Status CollectionBulkLoaderImpl::commit() { << " duplicates on secondary index(es) even though " "MultiIndexBlock::ignoreUniqueConstraint set."}; } - MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { + writeConflictRetry(_opCtx.get(), "CollectionBulkLoaderImpl::commit", _nss.ns(), [this] { WriteUnitOfWork wunit(_opCtx.get()); _secondaryIndexesBlock->commit(); wunit.commit(); - } - MONGO_WRITE_CONFLICT_RETRY_LOOP_END( - _opCtx.get(), "CollectionBulkLoaderImpl::commit", _nss.ns()); + }); } if (_idIndexBlock) { @@ -222,27 +227,24 @@ Status CollectionBulkLoaderImpl::commit() { } for (auto&& it : dups) { - MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { - WriteUnitOfWork wunit(_opCtx.get()); - _autoColl->getCollection()->deleteDocument(_opCtx.get(), - it, - nullptr /** OpDebug **/, - false /* fromMigrate */, - true /* noWarn */); - wunit.commit(); - } - MONGO_WRITE_CONFLICT_RETRY_LOOP_END( - _opCtx.get(), "CollectionBulkLoaderImpl::commit", _nss.ns()); + writeConflictRetry( + _opCtx.get(), "CollectionBulkLoaderImpl::commit", _nss.ns(), [this, &it] { + WriteUnitOfWork wunit(_opCtx.get()); + _autoColl->getCollection()->deleteDocument(_opCtx.get(), + it, + nullptr /** OpDebug **/, + false /* fromMigrate */, + true /* noWarn */); + wunit.commit(); + }); } // Commit _id index, without dups. - MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { + writeConflictRetry(_opCtx.get(), "CollectionBulkLoaderImpl::commit", _nss.ns(), [this] { WriteUnitOfWork wunit(_opCtx.get()); _idIndexBlock->commit(); wunit.commit(); - } - MONGO_WRITE_CONFLICT_RETRY_LOOP_END( - _opCtx.get(), "CollectionBulkLoaderImpl::commit", _nss.ns()); + }); } _stats.endBuildingIndexes = Date_t::now(); LOG(2) << "Done creating indexes for ns: " << _nss.ns() << ", stats: " << _stats.toString(); diff --git a/src/mongo/db/repl/noop_writer.cpp b/src/mongo/db/repl/noop_writer.cpp index c82eb575ae1..76603129a83 100644 --- a/src/mongo/db/repl/noop_writer.cpp +++ b/src/mongo/db/repl/noop_writer.cpp @@ -167,13 +167,12 @@ void NoopWriter::_writeNoop(OperationContext* opCtx) { LOG(logLevel) << "Writing noop to oplog as there has been no writes to this replica set in over " << _writeInterval; - MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { + writeConflictRetry(opCtx, "writeNoop", rsOplogName, [&opCtx] { WriteUnitOfWork uow(opCtx); opCtx->getClient()->getServiceContext()->getOpObserver()->onOpMessage(opCtx, kMsgObj); uow.commit(); - } - MONGO_WRITE_CONFLICT_RETRY_LOOP_END(opCtx, "writeNoop", rsOplogName); + }); } } diff --git a/src/mongo/db/repl/oplog.cpp b/src/mongo/db/repl/oplog.cpp index 9baa4b211cc..b82fb22629a 100644 --- a/src/mongo/db/repl/oplog.cpp +++ b/src/mongo/db/repl/oplog.cpp @@ -534,14 +534,13 @@ void createOplog(OperationContext* opCtx, const std::string& oplogCollectionName options.cappedSize = sz; options.autoIndexId = CollectionOptions::NO; - MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { + writeConflictRetry(opCtx, "createCollection", oplogCollectionName, [&] { WriteUnitOfWork uow(opCtx); invariant(ctx.db()->createCollection(opCtx, oplogCollectionName, options)); if (!isReplSet) getGlobalServiceContext()->getOpObserver()->onOpMessage(opCtx, BSONObj()); uow.commit(); - } - MONGO_WRITE_CONFLICT_RETRY_LOOP_END(opCtx, "createCollection", oplogCollectionName); + }); /* sync here so we don't get any surprising lag later when we try to sync */ StorageEngine* storageEngine = getGlobalServiceContext()->getGlobalStorageEngine(); 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 4d328f5f1de..9ae171ccaec 100644 --- a/src/mongo/db/repl/replication_coordinator_external_state_impl.cpp +++ b/src/mongo/db/repl/replication_coordinator_external_state_impl.cpp @@ -379,17 +379,17 @@ Status ReplicationCoordinatorExternalStateImpl::initializeReplSetStorage(Operati try { createOplog(opCtx); - MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { - Lock::GlobalWrite globalWrite(opCtx); - - WriteUnitOfWork wuow(opCtx); - Helpers::putSingleton(opCtx, configCollectionName, config); - const auto msgObj = BSON("msg" - << "initiating set"); - _service->getOpObserver()->onOpMessage(opCtx, msgObj); - wuow.commit(); - } - MONGO_WRITE_CONFLICT_RETRY_LOOP_END(opCtx, "initiate oplog entry", "local.oplog.rs"); + writeConflictRetry( + opCtx, "initiate oplog entry", "local.oplog.rs", [this, &opCtx, &config] { + Lock::GlobalWrite globalWrite(opCtx); + + WriteUnitOfWork wuow(opCtx); + Helpers::putSingleton(opCtx, configCollectionName, config); + const auto msgObj = BSON("msg" + << "initiating set"); + _service->getOpObserver()->onOpMessage(opCtx, msgObj); + wuow.commit(); + }); FeatureCompatibilityVersion::setIfCleanStartup(opCtx, _storageInterface); } catch (const DBException& ex) { @@ -420,16 +420,14 @@ OpTime ReplicationCoordinatorExternalStateImpl::onTransitionToPrimary(OperationC _replicationProcess->getConsistencyMarkers()->setAppliedThrough(opCtx, {}); if (isV1ElectionProtocol) { - MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { + writeConflictRetry(opCtx, "logging transition to primary to oplog", "local.oplog.rs", [&] { WriteUnitOfWork wuow(opCtx); opCtx->getClient()->getServiceContext()->getOpObserver()->onOpMessage( opCtx, BSON("msg" << "new primary")); wuow.commit(); - } - MONGO_WRITE_CONFLICT_RETRY_LOOP_END( - opCtx, "logging transition to primary to oplog", "local.oplog.rs"); + }); } const auto opTimeToReturn = fassertStatusOK(28665, loadLastOpTime(opCtx)); @@ -476,7 +474,7 @@ OID ReplicationCoordinatorExternalStateImpl::ensureMe(OperationContext* opCtx) { StatusWith<BSONObj> ReplicationCoordinatorExternalStateImpl::loadLocalConfigDocument( OperationContext* opCtx) { try { - MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { + return writeConflictRetry(opCtx, "load replica set config", configCollectionName, [opCtx] { BSONObj config; if (!Helpers::getSingleton(opCtx, configCollectionName, config)) { return StatusWith<BSONObj>( @@ -485,8 +483,7 @@ StatusWith<BSONObj> ReplicationCoordinatorExternalStateImpl::loadLocalConfigDocu << configCollectionName); } return StatusWith<BSONObj>(config); - } - MONGO_WRITE_CONFLICT_RETRY_LOOP_END(opCtx, "load replica set config", configCollectionName); + }); } catch (const DBException& ex) { return StatusWith<BSONObj>(ex.toStatus()); } @@ -495,12 +492,12 @@ StatusWith<BSONObj> ReplicationCoordinatorExternalStateImpl::loadLocalConfigDocu Status ReplicationCoordinatorExternalStateImpl::storeLocalConfigDocument(OperationContext* opCtx, const BSONObj& config) { try { - MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { + writeConflictRetry(opCtx, "save replica set config", configCollectionName, [&] { Lock::DBLock dbWriteLock(opCtx, configDatabaseName, MODE_X); Helpers::putSingleton(opCtx, configCollectionName, config); - return Status::OK(); - } - MONGO_WRITE_CONFLICT_RETRY_LOOP_END(opCtx, "save replica set config", configCollectionName); + }); + + return Status::OK(); } catch (const DBException& ex) { return ex.toStatus(); } @@ -509,18 +506,17 @@ Status ReplicationCoordinatorExternalStateImpl::storeLocalConfigDocument(Operati StatusWith<LastVote> ReplicationCoordinatorExternalStateImpl::loadLocalLastVoteDocument( OperationContext* opCtx) { try { - MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { - BSONObj lastVoteObj; - if (!Helpers::getSingleton(opCtx, lastVoteCollectionName, lastVoteObj)) { - return StatusWith<LastVote>(ErrorCodes::NoMatchingDocument, - str::stream() - << "Did not find replica set lastVote document in " - << lastVoteCollectionName); - } - return LastVote::readFromLastVote(lastVoteObj); - } - MONGO_WRITE_CONFLICT_RETRY_LOOP_END( - opCtx, "load replica set lastVote", lastVoteCollectionName); + return writeConflictRetry( + opCtx, "load replica set lastVote", lastVoteCollectionName, [opCtx] { + BSONObj lastVoteObj; + if (!Helpers::getSingleton(opCtx, lastVoteCollectionName, lastVoteObj)) { + return StatusWith<LastVote>( + ErrorCodes::NoMatchingDocument, + str::stream() << "Did not find replica set lastVote document in " + << lastVoteCollectionName); + } + return LastVote::readFromLastVote(lastVoteObj); + }); } catch (const DBException& ex) { return StatusWith<LastVote>(ex.toStatus()); } @@ -530,30 +526,37 @@ Status ReplicationCoordinatorExternalStateImpl::storeLocalLastVoteDocument( OperationContext* opCtx, const LastVote& lastVote) { BSONObj lastVoteObj = lastVote.toBSON(); try { - MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { - 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 - // the term of the current last vote document and insert the new document under the - // DBLock to synchronize the two operations. - BSONObj result; - bool exists = Helpers::getSingleton(opCtx, lastVoteCollectionName, result); - if (!exists) { - Helpers::putSingleton(opCtx, lastVoteCollectionName, lastVoteObj); - } else { - StatusWith<LastVote> oldLastVoteDoc = LastVote::readFromLastVote(result); - if (!oldLastVoteDoc.isOK()) { - return oldLastVoteDoc.getStatus(); - } - if (lastVote.getTerm() > oldLastVoteDoc.getValue().getTerm()) { + Status status = + writeConflictRetry(opCtx, "save replica set lastVote", lastVoteCollectionName, [&] { + 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 the term of the current last vote document and insert the new document + // under the DBLock to synchronize the two operations. + BSONObj result; + bool exists = Helpers::getSingleton(opCtx, lastVoteCollectionName, result); + if (!exists) { Helpers::putSingleton(opCtx, lastVoteCollectionName, lastVoteObj); + } else { + StatusWith<LastVote> oldLastVoteDoc = LastVote::readFromLastVote(result); + if (!oldLastVoteDoc.isOK()) { + return oldLastVoteDoc.getStatus(); + } + if (lastVote.getTerm() > oldLastVoteDoc.getValue().getTerm()) { + Helpers::putSingleton(opCtx, lastVoteCollectionName, lastVoteObj); + } } - } + + return Status::OK(); + }); + + if (!status.isOK()) { + return status; } - MONGO_WRITE_CONFLICT_RETRY_LOOP_END( - opCtx, "save replica set lastVote", lastVoteCollectionName); + opCtx->recoveryUnit()->waitUntilDurable(); + return Status::OK(); } catch (const DBException& ex) { return ex.toStatus(); diff --git a/src/mongo/db/repl/rs_rollback.cpp b/src/mongo/db/repl/rs_rollback.cpp index 4531276bfd2..8054c31c5e3 100644 --- a/src/mongo/db/repl/rs_rollback.cpp +++ b/src/mongo/db/repl/rs_rollback.cpp @@ -777,13 +777,12 @@ void syncFixUp(OperationContext* opCtx, } catch (const DBException& e) { if (e.getCode() == 13415) { // hack: need to just make cappedTruncate do this... - MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { - WriteUnitOfWork wunit(opCtx); - uassertStatusOK(collection->truncate(opCtx)); - wunit.commit(); - } - MONGO_WRITE_CONFLICT_RETRY_LOOP_END( - opCtx, "truncate", collection->ns().ns()); + writeConflictRetry( + opCtx, "truncate", collection->ns().ns(), [&] { + WriteUnitOfWork wunit(opCtx); + uassertStatusOK(collection->truncate(opCtx)); + wunit.commit(); + }); } else { throw e; } diff --git a/src/mongo/db/repl/rs_rollback_no_uuid.cpp b/src/mongo/db/repl/rs_rollback_no_uuid.cpp index 1e93966d027..d5391e8bda9 100644 --- a/src/mongo/db/repl/rs_rollback_no_uuid.cpp +++ b/src/mongo/db/repl/rs_rollback_no_uuid.cpp @@ -758,13 +758,12 @@ void syncFixUp(OperationContext* opCtx, } catch (const DBException& e) { if (e.getCode() == 13415) { // hack: need to just make cappedTruncate do this... - MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { - WriteUnitOfWork wunit(opCtx); - uassertStatusOK(collection->truncate(opCtx)); - wunit.commit(); - } - MONGO_WRITE_CONFLICT_RETRY_LOOP_END( - opCtx, "truncate", collection->ns().ns()); + writeConflictRetry( + opCtx, "truncate", collection->ns().ns(), [&] { + WriteUnitOfWork wunit(opCtx); + uassertStatusOK(collection->truncate(opCtx)); + wunit.commit(); + }); } else { throw e; } diff --git a/src/mongo/db/repl/storage_interface_impl.cpp b/src/mongo/db/repl/storage_interface_impl.cpp index 7422b8c913d..251518cc1d0 100644 --- a/src/mongo/db/repl/storage_interface_impl.cpp +++ b/src/mongo/db/repl/storage_interface_impl.cpp @@ -196,7 +196,7 @@ StorageInterfaceImpl::createCollectionForBulkLoading( std::unique_ptr<AutoGetCollection> autoColl; // Retry if WCE. - MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { + Status status = writeConflictRetry(opCtx.get(), "beginCollectionClone", nss.ns(), [&] { UnreplicatedWritesBlock uwb(opCtx.get()); // Get locks and create the collection. @@ -204,8 +204,8 @@ StorageInterfaceImpl::createCollectionForBulkLoading( AutoGetCollection coll(opCtx.get(), nss, MODE_IX); if (coll.getCollection()) { - return {ErrorCodes::NamespaceExists, - str::stream() << "Collection " << nss.ns() << " already exists."}; + return Status(ErrorCodes::NamespaceExists, + str::stream() << "Collection " << nss.ns() << " already exists."); } { // Create the collection. @@ -239,8 +239,13 @@ StorageInterfaceImpl::createCollectionForBulkLoading( } wunit.commit(); } + + return Status::OK(); + }); + + if (!status.isOK()) { + return status; } - MONGO_WRITE_CONFLICT_RETRY_LOOP_END(opCtx.get(), "beginCollectionClone", nss.ns()); // Move locks into loader, so it now controls their lifetime. auto loader = @@ -249,7 +254,7 @@ StorageInterfaceImpl::createCollectionForBulkLoading( std::move(autoColl), options.capped ? BSONObj() : idIndexSpec); - auto status = loader->init(options.capped ? std::vector<BSONObj>() : secondaryIndexSpecs); + status = loader->init(options.capped ? std::vector<BSONObj>() : secondaryIndexSpecs); if (!status.isOK()) { return status; } @@ -328,14 +333,19 @@ Status StorageInterfaceImpl::insertDocuments(OperationContext* opCtx, // Try to insert the batch one-at-a-time because the batch failed all-at-once inserting. for (auto it = docs.cbegin(); it != docs.cend(); ++it) { - MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { - auto status = insertDocumentsSingleBatch(opCtx, nss, it, it + 1); - if (!status.isOK()) { - return status; - } + auto status = + writeConflictRetry(opCtx, "StorageInterfaceImpl::insertDocuments", nss.ns(), [&] { + auto status = insertDocumentsSingleBatch(opCtx, nss, it, it + 1); + if (!status.isOK()) { + return status; + } + + return Status::OK(); + }); + + if (!status.isOK()) { + return status; } - MONGO_WRITE_CONFLICT_RETRY_LOOP_END( - opCtx, "StorageInterfaceImpl::insertDocuments", nss.ns()); } return Status::OK(); @@ -370,13 +380,13 @@ StatusWith<size_t> StorageInterfaceImpl::getOplogMaxSize(OperationContext* opCtx Status StorageInterfaceImpl::createCollection(OperationContext* opCtx, const NamespaceString& nss, const CollectionOptions& options) { - MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { + return writeConflictRetry(opCtx, "StorageInterfaceImpl::createCollection", nss.ns(), [&] { AutoGetOrCreateDb databaseWriteGuard(opCtx, nss.db(), MODE_X); auto db = databaseWriteGuard.getDb(); invariant(db); if (db->getCollection(opCtx, nss)) { - return {ErrorCodes::NamespaceExists, - str::stream() << "Collection " << nss.ns() << " already exists."}; + return Status(ErrorCodes::NamespaceExists, + str::stream() << "Collection " << nss.ns() << " already exists."); } WriteUnitOfWork wuow(opCtx); try { @@ -386,13 +396,13 @@ Status StorageInterfaceImpl::createCollection(OperationContext* opCtx, return ex.toStatus(); } wuow.commit(); - } - MONGO_WRITE_CONFLICT_RETRY_LOOP_END(opCtx, "StorageInterfaceImpl::createCollection", nss.ns()); - return Status::OK(); + + return Status::OK(); + }); } Status StorageInterfaceImpl::dropCollection(OperationContext* opCtx, const NamespaceString& nss) { - MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { + return writeConflictRetry(opCtx, "StorageInterfaceImpl::dropCollection", nss.ns(), [&] { AutoGetDb autoDB(opCtx, nss.db(), MODE_X); if (!autoDB.getDb()) { // Database does not exist - nothing to do. @@ -404,8 +414,7 @@ Status StorageInterfaceImpl::dropCollection(OperationContext* opCtx, const Names wunit.commit(); } return status; - } - MONGO_WRITE_CONFLICT_RETRY_LOOP_END(opCtx, "StorageInterfaceImpl::dropCollection", nss.ns()); + }); } Status StorageInterfaceImpl::renameCollection(OperationContext* opCtx, @@ -420,7 +429,7 @@ Status StorageInterfaceImpl::renameCollection(OperationContext* opCtx, << toNS.ns()); } - MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { + return writeConflictRetry(opCtx, "StorageInterfaceImpl::renameCollection", fromNS.ns(), [&] { AutoGetDb autoDB(opCtx, fromNS.db(), MODE_X); if (!autoDB.getDb()) { return Status(ErrorCodes::NamespaceNotFound, @@ -443,9 +452,7 @@ Status StorageInterfaceImpl::renameCollection(OperationContext* opCtx, } wunit.commit(); return status; - } - MONGO_WRITE_CONFLICT_RETRY_LOOP_END( - opCtx, "StorageInterfaceImpl::renameCollection", fromNS.ns()); + }); } namespace { @@ -478,13 +485,18 @@ StatusWith<std::vector<BSONObj>> _findOrDeleteDocuments( auto isFind = mode == FindDeleteMode::kFind; auto opStr = isFind ? "StorageInterfaceImpl::find" : "StorageInterfaceImpl::delete"; - MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { + + return writeConflictRetry(opCtx, opStr, nss.ns(), [&] { + // We need to explicitly use this in a few places to help the type inference. Use a + // shorthand. + using Result = StatusWith<std::vector<BSONObj>>; + auto collectionAccessMode = isFind ? MODE_IS : MODE_IX; AutoGetCollection autoColl(opCtx, nss, collectionAccessMode); auto collectionResult = getCollection( autoColl, nss, str::stream() << "Unable to proceed with " << opStr << "."); if (!collectionResult.isOK()) { - return collectionResult.getStatus(); + return Result(collectionResult.getStatus()); } auto collection = collectionResult.getValue(); @@ -494,13 +506,13 @@ StatusWith<std::vector<BSONObj>> _findOrDeleteDocuments( std::unique_ptr<PlanExecutor, PlanExecutor::Deleter> planExecutor; if (!indexName) { if (!startKey.isEmpty()) { - return {ErrorCodes::NoSuchKey, - "non-empty startKey not allowed for collection scan"}; + return Result(ErrorCodes::NoSuchKey, + "non-empty startKey not allowed for collection scan"); } if (boundInclusion != BoundInclusion::kIncludeStartKeyOnly) { - return {ErrorCodes::InvalidOptions, - "bound inclusion must be BoundInclusion::kIncludeStartKeyOnly for " - "collection scan"}; + return Result(ErrorCodes::InvalidOptions, + "bound inclusion must be BoundInclusion::kIncludeStartKeyOnly for " + "collection scan"); } // Use collection scan. planExecutor = isFind @@ -520,16 +532,17 @@ StatusWith<std::vector<BSONObj>> _findOrDeleteDocuments( IndexDescriptor* indexDescriptor = indexCatalog->findIndexByName(opCtx, *indexName, includeUnfinishedIndexes); if (!indexDescriptor) { - return {ErrorCodes::IndexNotFound, - str::stream() << "Index not found, ns:" << nss.ns() << ", index: " - << *indexName}; + return Result(ErrorCodes::IndexNotFound, + str::stream() << "Index not found, ns:" << nss.ns() << ", index: " + << *indexName); } if (indexDescriptor->isPartial()) { - return {ErrorCodes::IndexOptionsConflict, - str::stream() << "Partial index is not allowed for this operation, ns:" - << nss.ns() - << ", index: " - << *indexName}; + return Result(ErrorCodes::IndexOptionsConflict, + str::stream() + << "Partial index is not allowed for this operation, ns:" + << nss.ns() + << ", index: " + << *indexName); } KeyPattern keyPattern(indexDescriptor->keyPattern()); @@ -575,10 +588,8 @@ StatusWith<std::vector<BSONObj>> _findOrDeleteDocuments( break; } } - return docs; - } - MONGO_WRITE_CONFLICT_RETRY_LOOP_END(opCtx, opStr, nss.ns()); - MONGO_UNREACHABLE; + return Result(docs); + }); } StatusWith<BSONObj> _findOrDeleteById(OperationContext* opCtx, @@ -714,7 +725,7 @@ Status _upsertWithQuery(OperationContext* opCtx, invariant(!request.shouldReturnAnyDocs()); invariant(PlanExecutor::NO_YIELD == request.getYieldPolicy()); - MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { + return writeConflictRetry(opCtx, "_upsertWithQuery", nss.ns(), [&] { // ParsedUpdate needs to be inside the write conflict retry loop because it may create a // CanonicalQuery whose ownership will be transferred to the plan executor in // getExecutorUpdate(). @@ -743,10 +754,7 @@ Status _upsertWithQuery(OperationContext* opCtx, auto planExecutor = std::move(planExecutorResult.getValue()); return planExecutor->executePlan(); - } - MONGO_WRITE_CONFLICT_RETRY_LOOP_END(opCtx, "_upsertWithQuery", nss.ns()); - - MONGO_UNREACHABLE; + }); } } // namespace @@ -771,7 +779,7 @@ Status StorageInterfaceImpl::upsertById(OperationContext* opCtx, invariant(!request.shouldReturnAnyDocs()); invariant(PlanExecutor::NO_YIELD == request.getYieldPolicy()); - MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { + return writeConflictRetry(opCtx, "StorageInterfaceImpl::upsertById", nss.ns(), [&] { // ParsedUpdate needs to be inside the write conflict retry loop because it contains // the UpdateDriver whose state may be modified while we are applying the update. ParsedUpdate parsedUpdate(opCtx, &request); @@ -791,8 +799,8 @@ Status StorageInterfaceImpl::upsertById(OperationContext* opCtx, // without an _id index. auto descriptor = collection->getIndexCatalog()->findIdIndex(opCtx); if (!descriptor) { - return {ErrorCodes::IndexNotFound, - "Unable to update document in a collection without an _id index."}; + return Status(ErrorCodes::IndexNotFound, + "Unable to update document in a collection without an _id index."); } UpdateStageParams updateStageParams( @@ -805,10 +813,7 @@ Status StorageInterfaceImpl::upsertById(OperationContext* opCtx, parsedUpdate.yieldPolicy()); return planExecutor->executePlan(); - } - MONGO_WRITE_CONFLICT_RETRY_LOOP_END(opCtx, "StorageInterfaceImpl::upsertById", nss.ns()); - - MONGO_UNREACHABLE; + }); } Status StorageInterfaceImpl::putSingleton(OperationContext* opCtx, @@ -829,7 +834,7 @@ Status StorageInterfaceImpl::deleteByFilter(OperationContext* opCtx, // disallow client deletes from unrecognized system collections. request.setGod(); - MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { + return writeConflictRetry(opCtx, "StorageInterfaceImpl::deleteByFilter", nss.ns(), [&] { // ParsedDelete needs to be inside the write conflict retry loop because it may create a // CanonicalQuery whose ownership will be transferred to the plan executor in // getExecutorDelete(). @@ -858,10 +863,7 @@ Status StorageInterfaceImpl::deleteByFilter(OperationContext* opCtx, auto planExecutor = std::move(planExecutorResult.getValue()); return planExecutor->executePlan(); - } - MONGO_WRITE_CONFLICT_RETRY_LOOP_END(opCtx, "StorageInterfaceImpl::deleteByFilter", nss.ns()); - - MONGO_UNREACHABLE; + }); } StatusWith<StorageInterface::CollectionSize> StorageInterfaceImpl::getCollectionSize( diff --git a/src/mongo/db/repl/storage_interface_impl_test.cpp b/src/mongo/db/repl/storage_interface_impl_test.cpp index 8affb72dccd..9f98851679a 100644 --- a/src/mongo/db/repl/storage_interface_impl_test.cpp +++ b/src/mongo/db/repl/storage_interface_impl_test.cpp @@ -101,7 +101,7 @@ CollectionOptions createOplogCollectionOptions() { void createCollection(OperationContext* opCtx, const NamespaceString& nss, const CollectionOptions& options = CollectionOptions()) { - MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { + writeConflictRetry(opCtx, "createCollection", nss.ns(), [&] { Lock::DBLock dblk(opCtx, nss.db(), MODE_X); OldClientContext ctx(opCtx, nss.ns()); auto db = ctx.db(); @@ -110,8 +110,7 @@ void createCollection(OperationContext* opCtx, auto coll = db->createCollection(opCtx, nss.ns(), options); ASSERT_TRUE(coll); wuow.commit(); - } - MONGO_WRITE_CONFLICT_RETRY_LOOP_END(opCtx, "createCollection", nss.ns()); + }); } /** diff --git a/src/mongo/db/repl/sync_tail.cpp b/src/mongo/db/repl/sync_tail.cpp index f22201d213c..ed39314544d 100644 --- a/src/mongo/db/repl/sync_tail.cpp +++ b/src/mongo/db/repl/sync_tail.cpp @@ -313,16 +313,15 @@ Status SyncTail::syncApply(OperationContext* opCtx, auto opStr = isNoOp ? "syncApply_noop" : "syncApply_indexBuild"; if (isNoOp && nss.db() == "") return Status::OK(); - MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { + return writeConflictRetry(opCtx, opStr, nss.ns(), [&] { Lock::DBLock dbLock(opCtx, nss.db(), MODE_X); OldClientContext ctx(opCtx, nss.ns()); return applyOp(ctx.db()); - } - MONGO_WRITE_CONFLICT_RETRY_LOOP_END(opCtx, opStr, nss.ns()); + }); } if (isCrudOpType(opType)) { - MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { + return writeConflictRetry(opCtx, "syncApply_CRUD", nss.ns(), [&] { // DB lock always acquires the global lock std::unique_ptr<Lock::DBLock> dbLock; std::unique_ptr<Lock::CollectionLock> collectionLock; @@ -357,12 +356,11 @@ Status SyncTail::syncApply(OperationContext* opCtx, } return applyOp(ctx->db()); - } - MONGO_WRITE_CONFLICT_RETRY_LOOP_END(opCtx, "syncApply_CRUD", nss.ns()); + }); } if (opType[0] == 'c') { - MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { + return writeConflictRetry(opCtx, "syncApply_command", nss.ns(), [&] { // a command may need a global write lock. so we will conservatively go // ahead and grab one here. suboptimal. :-( Lock::GlobalWrite globalWriteLock(opCtx); @@ -371,8 +369,7 @@ Status SyncTail::syncApply(OperationContext* opCtx, Status status = applyCommandInLock(opCtx, op, inSteadyStateReplication); incrementOpsAppliedStats(); return status; - } - MONGO_WRITE_CONFLICT_RETRY_LOOP_END(opCtx, "syncApply_command", nss.ns()); + }); } // unknown opType @@ -989,7 +986,7 @@ BSONObj SyncTail::getMissingDoc(OperationContext* opCtx, Database* db, const BSO bool SyncTail::shouldRetry(OperationContext* opCtx, const BSONObj& o) { const NamespaceString nss(o.getStringField("ns")); - MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { + return writeConflictRetry(opCtx, "InsertRetry", nss.ns(), [&] { // Take an X lock on the database in order to preclude other modifications. // Also, the database might not exist yet, so create it. AutoGetOrCreateDb autoDb(opCtx, nss.db(), MODE_X); @@ -1024,11 +1021,7 @@ bool SyncTail::shouldRetry(OperationContext* opCtx, const BSONObj& o) { wunit.commit(); return true; } - } - MONGO_WRITE_CONFLICT_RETRY_LOOP_END(opCtx, "InsertRetry", nss.ns()); - - // fixes compile errors on GCC - see SERVER-18219 for details - MONGO_UNREACHABLE; + }); } // This free function is used by the writer threads to apply each op diff --git a/src/mongo/db/repl/sync_tail_test.cpp b/src/mongo/db/repl/sync_tail_test.cpp index 705497240c4..6d056e27183 100644 --- a/src/mongo/db/repl/sync_tail_test.cpp +++ b/src/mongo/db/repl/sync_tail_test.cpp @@ -291,7 +291,7 @@ CollectionOptions createOplogCollectionOptions() { void createCollection(OperationContext* opCtx, const NamespaceString& nss, const CollectionOptions& options) { - MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { + writeConflictRetry(opCtx, "createCollection", nss.ns(), [&] { Lock::DBLock dblk(opCtx, nss.db(), MODE_X); OldClientContext ctx(opCtx, nss.ns()); auto db = ctx.db(); @@ -300,8 +300,7 @@ void createCollection(OperationContext* opCtx, auto coll = db->createCollection(opCtx, nss.ns(), options); ASSERT_TRUE(coll); wuow.commit(); - } - MONGO_WRITE_CONFLICT_RETRY_LOOP_END(opCtx, "createCollection", nss.ns()); + }); } /** diff --git a/src/mongo/db/s/collection_range_deleter.cpp b/src/mongo/db/s/collection_range_deleter.cpp index e3fc81f9940..5635a888b1d 100644 --- a/src/mongo/db/s/collection_range_deleter.cpp +++ b/src/mongo/db/s/collection_range_deleter.cpp @@ -302,16 +302,14 @@ StatusWith<int> CollectionRangeDeleter::_doDeletion(OperationContext* opCtx, } invariant(PlanExecutor::ADVANCED == state); - MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { + writeConflictRetry(opCtx, "delete range", nss.ns(), [&] { WriteUnitOfWork wuow(opCtx); if (saver) { saver->goingToDelete(obj).transitional_ignore(); } collection->deleteDocument(opCtx, rloc, nullptr, true); wuow.commit(); - } - MONGO_WRITE_CONFLICT_RETRY_LOOP_END(opCtx, "delete range", nss.ns()); - + }); } while (++numDeleted < maxToDelete); return numDeleted; diff --git a/src/mongo/db/service_context_d_test_fixture.cpp b/src/mongo/db/service_context_d_test_fixture.cpp index dd18629eb05..eb35a212569 100644 --- a/src/mongo/db/service_context_d_test_fixture.cpp +++ b/src/mongo/db/service_context_d_test_fixture.cpp @@ -91,11 +91,10 @@ void ServiceContextMongoDTest::_dropAllDBs(OperationContext* opCtx) { AutoGetDb autoDBLocal(opCtx, "local", MODE_X); const auto localDB = autoDBLocal.getDb(); if (localDB) { - MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { + writeConflictRetry(opCtx, "_dropAllDBs", "local", [&] { // Do not wrap in a WriteUnitOfWork until SERVER-17103 is addressed. autoDBLocal.getDb()->dropDatabase(opCtx, localDB); - } - MONGO_WRITE_CONFLICT_RETRY_LOOP_END(opCtx, "_dropAllDBs", "local"); + }); } // dropAllDatabasesExceptLocal() does not close empty databases. However the holder still diff --git a/src/mongo/db/system_index.cpp b/src/mongo/db/system_index.cpp index a46b1bf45eb..0c07a4e46ad 100644 --- a/src/mongo/db/system_index.cpp +++ b/src/mongo/db/system_index.cpp @@ -118,21 +118,19 @@ void generateSystemIndexForExistingCollection(OperationContext* opCtx, MultiIndexBlock indexer(opCtx, collection); - MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { + writeConflictRetry(opCtx, "authorization index regeneration", ns.ns(), [&] { fassertStatusOK(40453, indexer.init(indexSpec)); - } - MONGO_WRITE_CONFLICT_RETRY_LOOP_END(opCtx, "authorization index regeneration", ns.ns()); + }); fassertStatusOK(40454, indexer.insertAllDocumentsInCollection()); - MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { + writeConflictRetry(opCtx, "authorization index regeneration", ns.ns(), [&] { WriteUnitOfWork wunit(opCtx); indexer.commit(); wunit.commit(); - } - MONGO_WRITE_CONFLICT_RETRY_LOOP_END(opCtx, "authorization index regeneration", ns.ns()); + }); log() << "Authorization index construction on " << ns << " is complete"; } catch (const DBException& e) { |