summaryrefslogtreecommitdiff
path: root/src/mongo
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo')
-rw-r--r--src/mongo/db/SConscript3
-rw-r--r--src/mongo/db/catalog/database.h8
-rw-r--r--src/mongo/db/introspect.cpp49
3 files changed, 39 insertions, 21 deletions
diff --git a/src/mongo/db/SConscript b/src/mongo/db/SConscript
index cbe71aab431..8290ce6e36e 100644
--- a/src/mongo/db/SConscript
+++ b/src/mongo/db/SConscript
@@ -956,6 +956,9 @@ env.Library(
LIBDEPS=[
"db_raii",
],
+ LIBDEPS_PRIVATE=[
+ "concurrency/write_conflict_exception",
+ ],
)
env.Library(
diff --git a/src/mongo/db/catalog/database.h b/src/mongo/db/catalog/database.h
index bf8c12638d2..1de4fa3e09e 100644
--- a/src/mongo/db/catalog/database.h
+++ b/src/mongo/db/catalog/database.h
@@ -133,6 +133,14 @@ public:
virtual Status dropView(OperationContext* const opCtx, NamespaceString viewName) const = 0;
+ /**
+ * A MODE_IX collection lock must be held for this call. Throws a WriteConflictException error
+ * if the collection already exists (say if another thread raced to create it).
+ *
+ * Surrounding writeConflictRetry loops must encompass checking that the collection exists as
+ * well as creating it. Otherwise the loop will endlessly throw WCEs: the caller must check that
+ * the collection exists to break free.
+ */
virtual Collection* createCollection(OperationContext* const opCtx,
const NamespaceString& nss,
const CollectionOptions& options = CollectionOptions(),
diff --git a/src/mongo/db/introspect.cpp b/src/mongo/db/introspect.cpp
index 3efdcf57c3f..a67929ff9b4 100644
--- a/src/mongo/db/introspect.cpp
+++ b/src/mongo/db/introspect.cpp
@@ -39,6 +39,7 @@
#include "mongo/db/auth/user_set.h"
#include "mongo/db/catalog/collection.h"
#include "mongo/db/client.h"
+#include "mongo/db/concurrency/write_conflict_exception.h"
#include "mongo/db/curop.h"
#include "mongo/db/db_raii.h"
#include "mongo/db/jsobj.h"
@@ -184,32 +185,38 @@ Status createProfileCollection(OperationContext* opCtx, Database* db) {
invariant(!opCtx->shouldParticipateInFlowControl());
const auto dbProfilingNS = NamespaceString(db->name(), "system.profile");
- Collection* const collection =
- CollectionCatalog::get(opCtx).lookupCollectionByNamespace(opCtx, dbProfilingNS);
- if (collection) {
- if (!collection->isCapped()) {
- return Status(ErrorCodes::NamespaceExists,
- str::stream() << dbProfilingNS << " exists but isn't capped");
- }
- return Status::OK();
- }
+ // Checking the collection exists must also be done in the WCE retry loop. Only retrying
+ // collection creation would endlessly throw errors because the collection exists: must check
+ // and see the collection exists in order to break free.
+ return writeConflictRetry(opCtx, "createProfileCollection", dbProfilingNS.ns(), [&] {
+ Collection* const collection =
+ CollectionCatalog::get(opCtx).lookupCollectionByNamespace(opCtx, dbProfilingNS);
+ if (collection) {
+ if (!collection->isCapped()) {
+ return Status(ErrorCodes::NamespaceExists,
+ str::stream() << dbProfilingNS << " exists but isn't capped");
+ }
- // system.profile namespace doesn't exist; create it
- LOGV2(20701,
- "Creating profile collection: {dbProfilingNS}",
- "dbProfilingNS"_attr = dbProfilingNS);
+ return Status::OK();
+ }
+
+ // system.profile namespace doesn't exist; create it
+ LOGV2(20701,
+ "Creating profile collection: {dbProfilingNS}",
+ "dbProfilingNS"_attr = dbProfilingNS);
- CollectionOptions collectionOptions;
- collectionOptions.capped = true;
- collectionOptions.cappedSize = 1024 * 1024;
+ CollectionOptions collectionOptions;
+ collectionOptions.capped = true;
+ collectionOptions.cappedSize = 1024 * 1024;
- WriteUnitOfWork wunit(opCtx);
- repl::UnreplicatedWritesBlock uwb(opCtx);
- invariant(db->createCollection(opCtx, dbProfilingNS, collectionOptions));
- wunit.commit();
+ WriteUnitOfWork wunit(opCtx);
+ repl::UnreplicatedWritesBlock uwb(opCtx);
+ invariant(db->createCollection(opCtx, dbProfilingNS, collectionOptions));
+ wunit.commit();
- return Status::OK();
+ return Status::OK();
+ });
}
} // namespace mongo