summaryrefslogtreecommitdiff
path: root/src/mongo/db/catalog/drop_database.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/db/catalog/drop_database.cpp')
-rw-r--r--src/mongo/db/catalog/drop_database.cpp89
1 files changed, 80 insertions, 9 deletions
diff --git a/src/mongo/db/catalog/drop_database.cpp b/src/mongo/db/catalog/drop_database.cpp
index 90e9adb34f7..8ccc1c8f944 100644
--- a/src/mongo/db/catalog/drop_database.cpp
+++ b/src/mongo/db/catalog/drop_database.cpp
@@ -41,11 +41,42 @@
#include "mongo/db/op_observer.h"
#include "mongo/db/repl/replication_coordinator.h"
#include "mongo/db/service_context.h"
+#include "mongo/db/write_concern_options.h"
#include "mongo/util/log.h"
#include "mongo/util/scopeguard.h"
namespace mongo {
+namespace {
+
+// This is used to wait for the collection drops to replicate to a majority of the replica set.
+// Note: Even though we're setting UNSET here, kMajority implies JOURNAL if journaling is supported
+// by mongod and writeConcernMajorityJournalDefault is set to true in the ReplSetConfig.
+const WriteConcernOptions kDropDatabaseWriteConcern(WriteConcernOptions::kMajority,
+ WriteConcernOptions::SyncMode::UNSET,
+ Minutes(10));
+
+/**
+ * Removes database from catalog and writes dropDatabase entry to oplog.
+ */
+Status _finishDropDatabase(OperationContext* opCtx, const std::string& dbName, Database* db) {
+ // If Database::dropDatabase() fails, we should reset the drop-pending state on Database.
+ auto dropPendingGuard = MakeGuard([db, opCtx] { db->setDropPending(opCtx, false); });
+
+ Database::dropDatabase(opCtx, db);
+ dropPendingGuard.Dismiss();
+
+ log() << "dropDatabase " << dbName << " - finished";
+
+ WriteUnitOfWork wunit(opCtx);
+ getGlobalServiceContext()->getOpObserver()->onDropDatabase(opCtx, dbName);
+ wunit.commit();
+
+ return Status::OK();
+}
+
+} // namespace
+
Status dropDatabase(OperationContext* opCtx, const std::string& dbName) {
uassert(ErrorCodes::IllegalOperation,
"Cannot drop a database in read-only mode",
@@ -57,6 +88,9 @@ Status dropDatabase(OperationContext* opCtx, const std::string& dbName) {
CurOp::get(opCtx)->setNS_inlock(dbName);
}
+ auto replCoord = repl::ReplicationCoordinator::get(opCtx);
+ std::size_t numCollectionsToDrop = 0;
+
MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN {
Lock::GlobalWrite lk(opCtx);
AutoGetDb autoDB(opCtx, dbName, MODE_X);
@@ -67,7 +101,6 @@ Status dropDatabase(OperationContext* opCtx, const std::string& dbName) {
<< " because it does not exist");
}
- auto replCoord = repl::ReplicationCoordinator::get(opCtx);
bool userInitiatedWritesAndNotPrimary =
opCtx->writesAreReplicated() && !replCoord->canAcceptWritesForDatabase(opCtx, dbName);
@@ -79,7 +112,8 @@ Status dropDatabase(OperationContext* opCtx, const std::string& dbName) {
log() << "dropDatabase " << dbName << " - starting";
db->setDropPending(opCtx, true);
- // If Database::dropDatabase() fails, we should reset the drop-pending state on Database.
+ // If Database::dropCollectionEventIfSystem() fails, we should reset the drop-pending state
+ // on Database.
auto dropPendingGuard = MakeGuard([&db, opCtx] { db->setDropPending(opCtx, false); });
for (auto collection : *db) {
@@ -91,20 +125,57 @@ Status dropDatabase(OperationContext* opCtx, const std::string& dbName) {
WriteUnitOfWork wunit(opCtx);
fassertStatusOK(40476, db->dropCollectionEvenIfSystem(opCtx, nss));
wunit.commit();
+ numCollectionsToDrop++;
}
- Database::dropDatabase(opCtx, db);
dropPendingGuard.Dismiss();
- log() << "dropDatabase " << dbName << " - finished";
- WriteUnitOfWork wunit(opCtx);
+ // If there are no collection drops to wait for, we complete the drop database operation.
+ if (numCollectionsToDrop == 0U) {
+ return _finishDropDatabase(opCtx, dbName, db);
+ }
+ }
+ 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.
+ auto dropPendingGuardWhileAwaitingReplication = MakeGuard([dbName, opCtx] {
+ Lock::GlobalWrite lk(opCtx);
+ AutoGetDb autoDB(opCtx, dbName, MODE_X);
+ if (auto db = autoDB.getDb()) {
+ db->setDropPending(opCtx, false);
+ }
+ });
+
+ auto status =
+ replCoord->awaitReplicationOfLastOpForClient(opCtx, kDropDatabaseWriteConcern).status;
+ if (!status.isOK()) {
+ return Status(status.code(),
+ str::stream() << "dropDatabase " << dbName << " failed waiting for "
+ << numCollectionsToDrop
+ << " collection drops to replicate: "
+ << status.reason());
+ }
- getGlobalServiceContext()->getOpObserver()->onDropDatabase(opCtx, dbName);
+ log() << "dropDatabase " << dbName << " - successfully dropped " << numCollectionsToDrop
+ << " collections. dropping database";
+ dropPendingGuardWhileAwaitingReplication.Dismiss();
- wunit.commit();
+ MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN {
+ Lock::GlobalWrite lk(opCtx);
+ AutoGetDb autoDB(opCtx, dbName, MODE_X);
+ if (auto db = autoDB.getDb()) {
+ return _finishDropDatabase(opCtx, dbName, db);
+ }
+
+ return Status(ErrorCodes::NamespaceNotFound,
+ str::stream() << "Could not drop database " << dbName
+ << " because it does not exist after dropping "
+ << numCollectionsToDrop
+ << " collection(s).");
}
- MONGO_WRITE_CONFLICT_RETRY_LOOP_END(opCtx, "dropDatabase", dbName);
+ MONGO_WRITE_CONFLICT_RETRY_LOOP_END(opCtx, "dropDatabase_database", dbName);
- return Status::OK();
+ MONGO_UNREACHABLE;
}
} // namespace mongo