diff options
author | Gregory Noma <gregory.noma@gmail.com> | 2020-04-07 17:18:01 -0400 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2020-04-07 21:48:45 +0000 |
commit | 257b35c81481ec49590202080e7ad354f0890761 (patch) | |
tree | 99fb01d3c286275207e9e654b3753eb137e65a36 /src/mongo | |
parent | 242d86b0e9a4091466682bbb97d2298839a91569 (diff) | |
download | mongo-257b35c81481ec49590202080e7ad354f0890761.tar.gz |
SERVER-47176 Make update.cpp not take database MODE_X lock
Diffstat (limited to 'src/mongo')
-rw-r--r-- | src/mongo/db/ops/update.cpp | 49 |
1 files changed, 22 insertions, 27 deletions
diff --git a/src/mongo/db/ops/update.cpp b/src/mongo/db/ops/update.cpp index 81683541275..74e8756c29a 100644 --- a/src/mongo/db/ops/update.cpp +++ b/src/mongo/db/ops/update.cpp @@ -38,7 +38,6 @@ #include "mongo/db/catalog/database_holder.h" #include "mongo/db/client.h" #include "mongo/db/clientcursor.h" -#include "mongo/db/concurrency/d_concurrency.h" #include "mongo/db/concurrency/write_conflict_exception.h" #include "mongo/db/exec/update_stage.h" #include "mongo/db/matcher/extensions_callback_real.h" @@ -61,35 +60,31 @@ UpdateResult update(OperationContext* opCtx, Database* db, const UpdateRequest& invariant(!request.isExplain()); const NamespaceString& nsString = request.getNamespaceString(); - Collection* collection = - CollectionCatalog::get(opCtx).lookupCollectionByNamespace(opCtx, nsString); + invariant(opCtx->lockState()->isCollectionLockedForMode(nsString, MODE_IX)); + + Collection* collection; // The update stage does not create its own collection. As such, if the update is // an upsert, create the collection that the update stage inserts into beforehand. - if (!collection && request.isUpsert()) { - // We have to have an exclusive lock on the db to be allowed to create the collection. - // Callers should either get an X or create the collection. - const Locker* locker = opCtx->lockState(); - invariant(locker->isW() || - locker->isLockHeldForMode(ResourceId(RESOURCE_DATABASE, nsString.db()), MODE_IX)); - - writeConflictRetry(opCtx, "createCollection", nsString.ns(), [&] { - Lock::DBLock lk(opCtx, nsString.db(), MODE_X); - - const bool userInitiatedWritesAndNotPrimary = opCtx->writesAreReplicated() && - !repl::ReplicationCoordinator::get(opCtx)->canAcceptWritesFor(opCtx, nsString); - - if (userInitiatedWritesAndNotPrimary) { - uassertStatusOK(Status(ErrorCodes::PrimarySteppedDown, - str::stream() << "Not primary while creating collection " - << nsString << " during upsert")); - } - WriteUnitOfWork wuow(opCtx); - collection = db->createCollection(opCtx, nsString, CollectionOptions()); - invariant(collection); - wuow.commit(); - }); - } + writeConflictRetry(opCtx, "createCollection", nsString.ns(), [&] { + collection = CollectionCatalog::get(opCtx).lookupCollectionByNamespace(opCtx, nsString); + if (collection || !request.isUpsert()) { + return; + } + + const bool userInitiatedWritesAndNotPrimary = opCtx->writesAreReplicated() && + !repl::ReplicationCoordinator::get(opCtx)->canAcceptWritesFor(opCtx, nsString); + + if (userInitiatedWritesAndNotPrimary) { + uassertStatusOK(Status(ErrorCodes::PrimarySteppedDown, + str::stream() << "Not primary while creating collection " + << nsString << " during upsert")); + } + WriteUnitOfWork wuow(opCtx); + collection = db->createCollection(opCtx, nsString, CollectionOptions()); + invariant(collection); + wuow.commit(); + }); // Parse the update, get an executor for it, run the executor, get stats out. const ExtensionsCallbackReal extensionsCallback(opCtx, &request.getNamespaceString()); |