diff options
Diffstat (limited to 'src/mongo')
-rw-r--r-- | src/mongo/db/catalog/collection_catalog.h | 9 | ||||
-rw-r--r-- | src/mongo/db/catalog/collection_catalog_test.cpp | 3 | ||||
-rw-r--r-- | src/mongo/db/catalog/drop_collection.cpp | 26 | ||||
-rw-r--r-- | src/mongo/dbtests/plan_executor_invalidation_test.cpp | 8 | ||||
-rw-r--r-- | src/mongo/dbtests/rollbacktests.cpp | 8 |
5 files changed, 51 insertions, 3 deletions
diff --git a/src/mongo/db/catalog/collection_catalog.h b/src/mongo/db/catalog/collection_catalog.h index f3886c3fea0..308c31173c5 100644 --- a/src/mongo/db/catalog/collection_catalog.h +++ b/src/mongo/db/catalog/collection_catalog.h @@ -216,7 +216,7 @@ public: void onCloseCatalog(OperationContext* opCtx); /** - * Puts the catatlog back in open state, removing the pre-close state. See onCloseCatalog. + * Puts the catalog back in open state, removing the pre-close state. See onCloseCatalog. * * Must be called with the global lock acquired in exclusive mode. */ @@ -226,6 +226,13 @@ public: iterator end() const; /** + * Returns whether the database contains any collections. + */ + bool empty(StringData db) const { + return begin(db) == end(); + } + + /** * Lookup the name of a resource by its ResourceId. If there are multiple namespaces mapped to * the same ResourceId entry, we return the boost::none for those namespaces until there is * only one namespace in the set. If the ResourceId is not found, boost::none is returned. diff --git a/src/mongo/db/catalog/collection_catalog_test.cpp b/src/mongo/db/catalog/collection_catalog_test.cpp index 205a5647e75..0ae2f578d5f 100644 --- a/src/mongo/db/catalog/collection_catalog_test.cpp +++ b/src/mongo/db/catalog/collection_catalog_test.cpp @@ -64,8 +64,11 @@ public: auto collection = std::make_unique<CollectionMock>(nss); col = collection.get(); + ASSERT_TRUE(catalog.empty(nss.db())); + // Register dummy collection in catalog. catalog.registerCollection(colUUID, std::move(collection)); + ASSERT_FALSE(catalog.empty(nss.db())); } protected: diff --git a/src/mongo/db/catalog/drop_collection.cpp b/src/mongo/db/catalog/drop_collection.cpp index b5f30ae2a3e..bcf17660ef4 100644 --- a/src/mongo/db/catalog/drop_collection.cpp +++ b/src/mongo/db/catalog/drop_collection.cpp @@ -34,6 +34,7 @@ #include "mongo/db/catalog/drop_collection.h" #include "mongo/db/background.h" +#include "mongo/db/catalog/database_holder.h" #include "mongo/db/catalog/index_catalog.h" #include "mongo/db/client.h" #include "mongo/db/concurrency/write_conflict_exception.h" @@ -160,7 +161,7 @@ Status dropCollection(OperationContext* opCtx, log() << "Hanging drop collection before lock acquisition while fail point is set"; MONGO_FAIL_POINT_PAUSE_WHILE_SET(hangDropCollectionBeforeLockAcquisition); } - return writeConflictRetry(opCtx, "drop", collectionName.ns(), [&] { + Status status = writeConflictRetry(opCtx, "drop", collectionName.ns(), [&] { AutoGetDb autoDb(opCtx, collectionName.db(), MODE_IX); Database* db = autoDb.getDb(); if (!db) { @@ -175,6 +176,29 @@ Status dropCollection(OperationContext* opCtx, opCtx, db, collectionName, dropOpTime, systemCollectionMode, result); } }); + + if (!status.isOK()) { + return status; + } + + // If this dropped the last collection in the database, we should close the database. + bool empty = CollectionCatalog::get(opCtx).empty(collectionName.db()); + if (!empty) { + return Status::OK(); + } + + Lock::DBLock dbLock(opCtx, collectionName.db(), MODE_X); + + // Double check that we're still empty. A new collection could've been created before we got the + // exclusive lock. + empty = CollectionCatalog::get(opCtx).empty(collectionName.db()); + if (!empty) { + return Status::OK(); + } + + DatabaseHolder::get(opCtx)->close(opCtx, collectionName.db()); + + return Status::OK(); } } // namespace mongo diff --git a/src/mongo/dbtests/plan_executor_invalidation_test.cpp b/src/mongo/dbtests/plan_executor_invalidation_test.cpp index 61eedeab72f..7a62f40afb8 100644 --- a/src/mongo/dbtests/plan_executor_invalidation_test.cpp +++ b/src/mongo/dbtests/plan_executor_invalidation_test.cpp @@ -59,6 +59,10 @@ static const NamespaceString nss("unittests.PlanExecutorInvalidationTest"); class PlanExecutorInvalidationTest : public unittest::Test { public: PlanExecutorInvalidationTest() : _client(&_opCtx) { + // Create an additional collection to prevent the database from closing when the other + // collection is dropped. + ASSERT_TRUE(_client.createCollection("unittests.PlanExecutorInvalidationTestUnused")); + _ctx.reset(new dbtests::WriteContextForTests(&_opCtx, nss.ns())); _client.dropCollection(nss.ns()); @@ -67,6 +71,10 @@ public: } } + ~PlanExecutorInvalidationTest() { + _client.dropCollection("unittests.PlanExecutorInvalidationTestUnused"); + } + /** * Return a plan executor that is going over the collection in nss.ns(). */ diff --git a/src/mongo/dbtests/rollbacktests.cpp b/src/mongo/dbtests/rollbacktests.cpp index fd48e6f46a3..d5e69fce2f3 100644 --- a/src/mongo/dbtests/rollbacktests.cpp +++ b/src/mongo/dbtests/rollbacktests.cpp @@ -53,7 +53,7 @@ namespace { const auto kIndexVersion = IndexDescriptor::IndexVersion::kV2; void dropDatabase(OperationContext* opCtx, const NamespaceString& nss) { - Lock::GlobalWrite globalWriteLock(opCtx); + AutoGetDb autoDB(opCtx, nss.db(), MODE_X); auto databaseHolder = DatabaseHolder::get(opCtx); auto db = databaseHolder->getDb(opCtx, nss.db()); @@ -394,6 +394,12 @@ public: assertGet(CollectionOptions::parse(BSONObj(), CollectionOptions::parseForCommand)); ASSERT_OK(ctx.db()->userCreateNS(&opCtx, nss, collectionOptions, defaultIndexes)); insertRecord(&opCtx, nss, oldDoc); + + // Create an additional collection to prevent the database from closing when the other + // collection is dropped. + NamespaceString unusedCollectionNSS("unittests.rollback_replace_collection_unused"); + ASSERT_OK(ctx.db()->userCreateNS( + &opCtx, unusedCollectionNSS, collectionOptions, defaultIndexes)); uow.commit(); } ASSERT(collectionExists(&opCtx, &ctx, nss.ns())); |