From 36df326d54d7d97c67d9be778c70b7fcb18ef9b3 Mon Sep 17 00:00:00 2001 From: Pierlauro Sciarelli Date: Mon, 5 Jul 2021 14:17:02 +0000 Subject: SERVER-58167 Use scoped database critical section during dropDatabase --- src/mongo/db/s/database_sharding_state.cpp | 2 +- src/mongo/db/s/drop_database_coordinator.cpp | 124 +++++++++++++++++---------- 2 files changed, 82 insertions(+), 44 deletions(-) (limited to 'src/mongo') diff --git a/src/mongo/db/s/database_sharding_state.cpp b/src/mongo/db/s/database_sharding_state.cpp index 79b9db6a2cb..d1d1a3f8746 100644 --- a/src/mongo/db/s/database_sharding_state.cpp +++ b/src/mongo/db/s/database_sharding_state.cpp @@ -187,7 +187,7 @@ void DatabaseShardingState::checkDbVersion(OperationContext* opCtx, DSSLock&) co criticalSectionSignal); uasserted(StaleDbRoutingVersion(_dbName, *clientDbVersion, boost::none), - "movePrimary critical section active"); + "database critical section active"); } uassert(StaleDbRoutingVersion(_dbName, *clientDbVersion, boost::none), diff --git a/src/mongo/db/s/drop_database_coordinator.cpp b/src/mongo/db/s/drop_database_coordinator.cpp index 6e12a4ff7e7..772765c01be 100644 --- a/src/mongo/db/s/drop_database_coordinator.cpp +++ b/src/mongo/db/s/drop_database_coordinator.cpp @@ -33,6 +33,7 @@ #include "mongo/db/api_parameters.h" #include "mongo/db/persistent_task_store.h" +#include "mongo/db/s/database_sharding_state.h" #include "mongo/db/s/sharding_ddl_util.h" #include "mongo/db/s/sharding_logging.h" #include "mongo/db/s/sharding_state.h" @@ -71,6 +72,33 @@ void removeDatabaseMetadataFromConfig(OperationContext* opCtx, << dbName << "'."); } +class ScopedDatabaseCriticalSection { +public: + ScopedDatabaseCriticalSection(OperationContext* opCtx, + const std::string dbName, + const BSONObj reason) + : _opCtx(opCtx), _dbName(std::move(dbName)), _reason(std::move(reason)) { + Lock::DBLock dbLock(_opCtx, _dbName, MODE_X); + auto dss = DatabaseShardingState::get(_opCtx, _dbName); + auto dssLock = DatabaseShardingState::DSSLock::lockExclusive(_opCtx, dss); + dss->enterCriticalSectionCatchUpPhase(_opCtx, dssLock, _reason); + dss->enterCriticalSectionCommitPhase(_opCtx, dssLock, _reason); + } + + ~ScopedDatabaseCriticalSection() { + UninterruptibleLockGuard guard(_opCtx->lockState()); + Lock::DBLock dbLock(_opCtx, _dbName, MODE_X); + auto dss = DatabaseShardingState::get(_opCtx, _dbName); + dss->exitCriticalSection(_opCtx, _reason); + } + +private: + OperationContext* _opCtx; + const std::string _dbName; + const BSONObj _reason; +}; + + } // namespace void DropDatabaseCoordinator::_performNoopRetryableWriteOnParticipants( @@ -208,52 +236,62 @@ ExecutorFuture DropDatabaseCoordinator::_runImpl( _dropShardedCollection(opCtx, coll, executor); } - auto dropDatabaseParticipantCmd = ShardsvrDropDatabaseParticipant(); - dropDatabaseParticipantCmd.setDbName(_dbName); - const auto cmdObj = CommandHelpers::appendMajorityWriteConcern( - dropDatabaseParticipantCmd.toBSON({})); - - // The database needs to be dropped first on the db primary shard - // because otherwise changestreams won't receive the drop event. - { - DBDirectClient dbDirectClient(opCtx); - const auto commandResponse = - dbDirectClient.runCommand(OpMsgRequest::fromDBAndBody(_dbName, cmdObj)); - uassertStatusOK(getStatusFromCommandResult(commandResponse->getCommandReply())); - - WriteConcernResult ignoreResult; - const auto latestOpTime = - repl::ReplClientInfo::forClient(opCtx->getClient()).getLastOp(); - uassertStatusOK( - waitForWriteConcern(opCtx, - latestOpTime, - ShardingCatalogClient::kMajorityWriteConcern, - &ignoreResult)); - } - const auto allShardIds = Grid::get(opCtx)->shardRegistry()->getAllShardIds(opCtx); - // Remove primary shard from participants - const auto primaryShardId = ShardingState::get(opCtx)->shardId(); - auto participants = allShardIds; - participants.erase( - std::remove(participants.begin(), participants.end(), primaryShardId), - participants.end()); - // Drop DB on all other shards, attaching the dbVersion to the request to ensure - // idempotency. - try { - sharding_ddl_util::sendAuthenticatedCommandToShards( - opCtx, - _dbName, - appendDbVersionIfPresent(cmdObj, *metadata().getDatabaseVersion()), - participants, - **executor); - } catch (ExceptionFor&) { - // The DB metadata could have been removed by a network-partitioned former - // primary + { + // Acquire the database critical section in order to disallow implicit + // collection creations from happening concurrently with dropDatabase + const auto critSecReason = BSON("dropDatabase" << _dbName); + auto scopedCritSec = ScopedDatabaseCriticalSection( + opCtx, _dbName.toString(), std::move(critSecReason)); + + auto dropDatabaseParticipantCmd = ShardsvrDropDatabaseParticipant(); + dropDatabaseParticipantCmd.setDbName(_dbName); + const auto cmdObj = CommandHelpers::appendMajorityWriteConcern( + dropDatabaseParticipantCmd.toBSON({})); + + // The database needs to be dropped first on the db primary shard + // because otherwise changestreams won't receive the drop event. + { + DBDirectClient dbDirectClient(opCtx); + const auto commandResponse = + dbDirectClient.runCommand(OpMsgRequest::fromDBAndBody(_dbName, cmdObj)); + uassertStatusOK( + getStatusFromCommandResult(commandResponse->getCommandReply())); + + WriteConcernResult ignoreResult; + const auto latestOpTime = + repl::ReplClientInfo::forClient(opCtx->getClient()).getLastOp(); + uassertStatusOK( + waitForWriteConcern(opCtx, + latestOpTime, + ShardingCatalogClient::kMajorityWriteConcern, + &ignoreResult)); + } + + // Remove primary shard from participants + const auto primaryShardId = ShardingState::get(opCtx)->shardId(); + auto participants = allShardIds; + participants.erase( + std::remove(participants.begin(), participants.end(), primaryShardId), + participants.end()); + // Drop DB on all other shards, attaching the dbVersion to the request to ensure + // idempotency. + try { + sharding_ddl_util::sendAuthenticatedCommandToShards( + opCtx, + _dbName, + appendDbVersionIfPresent(cmdObj, *metadata().getDatabaseVersion()), + participants, + **executor); + } catch (ExceptionFor&) { + // The DB metadata could have been removed by a network-partitioned former + // primary + } + + removeDatabaseMetadataFromConfig( + opCtx, _dbName, *metadata().getDatabaseVersion()); } - removeDatabaseMetadataFromConfig(opCtx, _dbName, *metadata().getDatabaseVersion()); - { // Send _flushDatabaseCacheUpdates to all shards auto flushDbCacheUpdatesCmd = -- cgit v1.2.1