diff options
author | Benety Goh <benety@mongodb.com> | 2017-06-27 00:06:17 -0400 |
---|---|---|
committer | Benety Goh <benety@mongodb.com> | 2017-06-29 11:17:45 -0400 |
commit | 560b3f562832664c1cb09cdbf3a257493bad6ba8 (patch) | |
tree | 657b5739d5e601ae8515501a74b9298e7870a46d /src/mongo/db | |
parent | f0110e2682e3a787df062ee3feb7637add694978 (diff) | |
download | mongo-560b3f562832664c1cb09cdbf3a257493bad6ba8.tar.gz |
SERVER-29876 dropDatabase() waits for pending collection drops to complete
Diffstat (limited to 'src/mongo/db')
-rw-r--r-- | src/mongo/db/catalog/drop_database.cpp | 58 | ||||
-rw-r--r-- | src/mongo/db/catalog/drop_database_test.cpp | 29 |
2 files changed, 74 insertions, 13 deletions
diff --git a/src/mongo/db/catalog/drop_database.cpp b/src/mongo/db/catalog/drop_database.cpp index 8ccc1c8f944..2c3aecf31a4 100644 --- a/src/mongo/db/catalog/drop_database.cpp +++ b/src/mongo/db/catalog/drop_database.cpp @@ -32,6 +32,8 @@ #include "mongo/db/catalog/drop_database.h" +#include <algorithm> + #include "mongo/db/background.h" #include "mongo/db/catalog/database.h" #include "mongo/db/client.h" @@ -91,6 +93,10 @@ Status dropDatabase(OperationContext* opCtx, const std::string& dbName) { auto replCoord = repl::ReplicationCoordinator::get(opCtx); std::size_t numCollectionsToDrop = 0; + // We have to wait for the last drop-pending collection to be removed if there are no + // collections to drop. + repl::OpTime latestDropPendingOpTime; + MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { Lock::GlobalWrite lk(opCtx); AutoGetDb autoDB(opCtx, dbName, MODE_X); @@ -118,6 +124,13 @@ Status dropDatabase(OperationContext* opCtx, const std::string& dbName) { for (auto collection : *db) { const auto& nss = collection->ns(); + if (nss.isDropPendingNamespace() && replCoord->isReplEnabled() && + opCtx->writesAreReplicated()) { + log() << "dropDatabase " << dbName << " - found drop-pending collection: " << nss; + latestDropPendingOpTime = std::max( + latestDropPendingOpTime, uassertStatusOK(nss.getDropPendingNamespaceOpTime())); + continue; + } if (replCoord->isOplogDisabledFor(opCtx, nss) || nss.isSystemDotIndexes()) { continue; } @@ -130,7 +143,7 @@ Status dropDatabase(OperationContext* opCtx, const std::string& dbName) { dropPendingGuard.Dismiss(); // If there are no collection drops to wait for, we complete the drop database operation. - if (numCollectionsToDrop == 0U) { + if (numCollectionsToDrop == 0U && latestDropPendingOpTime.isNull()) { return _finishDropDatabase(opCtx, dbName, db); } } @@ -146,18 +159,39 @@ Status dropDatabase(OperationContext* opCtx, const std::string& dbName) { } }); - 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()); - } + if (numCollectionsToDrop > 0U) { + 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()); + } - log() << "dropDatabase " << dbName << " - successfully dropped " << numCollectionsToDrop - << " collections. dropping database"; + log() << "dropDatabase " << dbName << " - successfully dropped " << numCollectionsToDrop + << " collections. dropping database"; + } else { + invariant(!latestDropPendingOpTime.isNull()); + auto status = + replCoord->awaitReplication(opCtx, latestDropPendingOpTime, kDropDatabaseWriteConcern) + .status; + if (!status.isOK()) { + return Status( + status.code(), + str::stream() + << "dropDatabase " + << dbName + << " failed waiting for pending collection drops (most recent drop optime: " + << latestDropPendingOpTime.toString() + << ") to replicate: " + << status.reason()); + } + + log() << "dropDatabase " << dbName + << " - pending collection drops completed. dropping database"; + } dropPendingGuardWhileAwaitingReplication.Dismiss(); MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { diff --git a/src/mongo/db/catalog/drop_database_test.cpp b/src/mongo/db/catalog/drop_database_test.cpp index ee552ad1c78..f26323898c9 100644 --- a/src/mongo/db/catalog/drop_database_test.cpp +++ b/src/mongo/db/catalog/drop_database_test.cpp @@ -246,10 +246,37 @@ TEST_F(DropDatabaseTest, DropDatabaseNotifiesOpObserverOfDroppedReplicatedSystem _testDropDatabase(_opCtx.get(), _opObserver, replicatedSystemNss, true); } -TEST_F(DropDatabaseTest, DropDatabaseSkipsDropPendingCollectionWhenDroppingCollections) { +TEST_F(DropDatabaseTest, DropDatabaseWaitsForDropPendingCollectionOpTimeIfNoCollectionsAreDropped) { + repl::OpTime clientLastOpTime; + + // Update ReplicationCoordinatorMock so that we record the optime passed to awaitReplication(). + _replCoord->setAwaitReplicationReturnValueFunction( + [&clientLastOpTime, this](const repl::OpTime& opTime) { + clientLastOpTime = opTime; + ASSERT_GREATER_THAN(clientLastOpTime, repl::OpTime()); + return repl::ReplicationCoordinator::StatusAndDuration(Status::OK(), Milliseconds(0)); + }); + repl::OpTime dropOpTime(Timestamp(Seconds(100), 0), 1LL); auto dpns = _nss.makeDropPendingNamespace(dropOpTime); _testDropDatabase(_opCtx.get(), _opObserver, dpns, false); + + ASSERT_EQUALS(dropOpTime, clientLastOpTime); +} + +TEST_F(DropDatabaseTest, DropDatabasePassedThroughAwaitReplicationErrorForDropPendingCollection) { + // Update ReplicationCoordinatorMock so that we record the optime passed to awaitReplication(). + _replCoord->setAwaitReplicationReturnValueFunction([this](const repl::OpTime& opTime) { + ASSERT_GREATER_THAN(opTime, repl::OpTime()); + return repl::ReplicationCoordinator::StatusAndDuration( + Status(ErrorCodes::WriteConcernFailed, ""), Milliseconds(0)); + }); + + repl::OpTime dropOpTime(Timestamp(Seconds(100), 0), 1LL); + auto dpns = _nss.makeDropPendingNamespace(dropOpTime); + _createCollection(_opCtx.get(), dpns); + + ASSERT_EQUALS(ErrorCodes::WriteConcernFailed, dropDatabase(_opCtx.get(), _nss.db().toString())); } TEST_F(DropDatabaseTest, DropDatabaseSkipsSystemDotIndexesCollectionWhenDroppingCollections) { |