summaryrefslogtreecommitdiff
path: root/src/mongo
diff options
context:
space:
mode:
authorGregory Wlodarek <gregory.wlodarek@mongodb.com>2019-08-22 21:11:29 -0400
committerGregory Wlodarek <gregory.wlodarek@mongodb.com>2019-08-22 22:13:45 -0400
commitb6b81f34516ba7b1472cb1dd319da8785f24ae58 (patch)
treeb769955851c46b08aa3145e6aeaab27fff706ef3 /src/mongo
parentd743246d3c0e35c21b4f1d954bc138df60c47a5a (diff)
downloadmongo-b6b81f34516ba7b1472cb1dd319da8785f24ae58.tar.gz
SERVER-33272 Proactively close newly empty databases
Diffstat (limited to 'src/mongo')
-rw-r--r--src/mongo/db/catalog/collection_catalog.h9
-rw-r--r--src/mongo/db/catalog/collection_catalog_test.cpp3
-rw-r--r--src/mongo/db/catalog/drop_collection.cpp26
-rw-r--r--src/mongo/dbtests/plan_executor_invalidation_test.cpp8
-rw-r--r--src/mongo/dbtests/rollbacktests.cpp8
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()));