summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/mongo/db/catalog/rename_collection.cpp4
-rw-r--r--src/mongo/db/catalog_raii.cpp8
-rw-r--r--src/mongo/db/commands/create_indexes.cpp11
-rw-r--r--src/mongo/db/index_builds_coordinator.cpp4
-rw-r--r--src/mongo/db/s/active_migrations_registry.cpp2
-rw-r--r--src/mongo/db/s/collection_sharding_runtime.cpp20
-rw-r--r--src/mongo/db/s/collection_sharding_runtime.h43
-rw-r--r--src/mongo/db/s/database_sharding_state.cpp27
-rw-r--r--src/mongo/db/s/database_sharding_state.h38
-rw-r--r--src/mongo/db/s/flush_database_cache_updates_command.cpp9
-rw-r--r--src/mongo/db/s/get_database_version_command.cpp5
-rw-r--r--src/mongo/db/s/migration_chunk_cloner_source_legacy_commands.cpp6
-rw-r--r--src/mongo/db/s/migration_source_manager.cpp4
-rw-r--r--src/mongo/db/s/migration_source_manager.h2
-rw-r--r--src/mongo/db/s/move_primary_source_manager.cpp32
-rw-r--r--src/mongo/db/s/op_observer_sharding_impl.cpp8
-rw-r--r--src/mongo/db/s/shard_filtering_metadata_refresh.cpp10
-rw-r--r--src/mongo/db/s/shard_server_op_observer.cpp8
-rw-r--r--src/mongo/db/s/sharding_state_lock.h97
19 files changed, 223 insertions, 115 deletions
diff --git a/src/mongo/db/catalog/rename_collection.cpp b/src/mongo/db/catalog/rename_collection.cpp
index a6b71b91e7d..cb32f5c9349 100644
--- a/src/mongo/db/catalog/rename_collection.cpp
+++ b/src/mongo/db/catalog/rename_collection.cpp
@@ -157,7 +157,9 @@ Status renameCollectionCommon(OperationContext* opCtx,
auto databaseHolder = DatabaseHolder::get(opCtx);
auto sourceDB = databaseHolder->getDb(opCtx, source.db());
if (sourceDB) {
- DatabaseShardingState::get(sourceDB).checkDbVersion(opCtx);
+ auto& dss = DatabaseShardingState::get(sourceDB);
+ auto dssLock = DatabaseShardingState::DSSLock::lock(opCtx, &dss);
+ dss.checkDbVersion(opCtx, dssLock);
}
Collection* const sourceColl = sourceDB ? sourceDB->getCollection(opCtx, source) : nullptr;
if (!sourceColl) {
diff --git a/src/mongo/db/catalog_raii.cpp b/src/mongo/db/catalog_raii.cpp
index 342c4d60a61..fdefc58956a 100644
--- a/src/mongo/db/catalog_raii.cpp
+++ b/src/mongo/db/catalog_raii.cpp
@@ -59,7 +59,9 @@ AutoGetDb::AutoGetDb(OperationContext* opCtx, StringData dbName, LockMode mode,
return databaseHolder->getDb(opCtx, dbName);
}()) {
if (_db) {
- DatabaseShardingState::get(_db).checkDbVersion(opCtx);
+ auto& dss = DatabaseShardingState::get(_db);
+ auto dssLock = DatabaseShardingState::DSSLock::lock(opCtx, &dss);
+ dss.checkDbVersion(opCtx, dssLock);
}
}
@@ -171,7 +173,9 @@ AutoGetOrCreateDb::AutoGetOrCreateDb(OperationContext* opCtx,
_db = databaseHolder->openDb(opCtx, dbName, &_justCreated);
}
- DatabaseShardingState::get(_db).checkDbVersion(opCtx);
+ auto& dss = DatabaseShardingState::get(_db);
+ auto dssLock = DatabaseShardingState::DSSLock::lock(opCtx, &dss);
+ dss.checkDbVersion(opCtx, dssLock);
}
ConcealUUIDCatalogChangesBlock::ConcealUUIDCatalogChangesBlock(OperationContext* opCtx)
diff --git a/src/mongo/db/commands/create_indexes.cpp b/src/mongo/db/commands/create_indexes.cpp
index f3238ab69a1..040870f1f97 100644
--- a/src/mongo/db/commands/create_indexes.cpp
+++ b/src/mongo/db/commands/create_indexes.cpp
@@ -251,7 +251,12 @@ bool runCreateIndexes(OperationContext* opCtx,
if (!db) {
db = databaseHolder->openDb(opCtx, ns.db());
}
- DatabaseShardingState::get(db).checkDbVersion(opCtx);
+
+ {
+ auto& dss = DatabaseShardingState::get(db);
+ auto dssLock = DatabaseShardingState::DSSLock::lock(opCtx, &dss);
+ dss.checkDbVersion(opCtx, dssLock);
+ }
Collection* collection = db->getCollection(opCtx, ns);
if (collection) {
@@ -380,7 +385,9 @@ bool runCreateIndexes(OperationContext* opCtx,
auto db = databaseHolder->getDb(opCtx, ns.db());
if (db) {
- DatabaseShardingState::get(db).checkDbVersion(opCtx);
+ auto& dss = DatabaseShardingState::get(db);
+ auto dssLock = DatabaseShardingState::DSSLock::lock(opCtx, &dss);
+ dss.checkDbVersion(opCtx, dssLock);
}
invariant(db);
diff --git a/src/mongo/db/index_builds_coordinator.cpp b/src/mongo/db/index_builds_coordinator.cpp
index c610e4f9c0d..e77d4b1e046 100644
--- a/src/mongo/db/index_builds_coordinator.cpp
+++ b/src/mongo/db/index_builds_coordinator.cpp
@@ -536,7 +536,9 @@ void IndexBuildsCoordinator::_runIndexBuild(OperationContext* opCtx,
auto databaseHolder = DatabaseHolder::get(opCtx);
auto db = databaseHolder->getDb(opCtx, nss.db());
if (db) {
- DatabaseShardingState::get(db).checkDbVersion(opCtx);
+ auto& dss = DatabaseShardingState::get(db);
+ auto dssLock = DatabaseShardingState::DSSLock::lock(opCtx, &dss);
+ dss.checkDbVersion(opCtx, dssLock);
}
invariant(db,
diff --git a/src/mongo/db/s/active_migrations_registry.cpp b/src/mongo/db/s/active_migrations_registry.cpp
index 6f12e0119ec..d070142ec16 100644
--- a/src/mongo/db/s/active_migrations_registry.cpp
+++ b/src/mongo/db/s/active_migrations_registry.cpp
@@ -122,7 +122,7 @@ BSONObj ActiveMigrationsRegistry::getActiveMigrationStatusReport(OperationContex
// Lock the collection so nothing changes while we're getting the migration report.
AutoGetCollection autoColl(opCtx, nss.get(), MODE_IS);
auto csr = CollectionShardingRuntime::get(opCtx, nss.get());
- auto csrLock = CollectionShardingRuntimeLock::lock(opCtx, csr);
+ auto csrLock = CollectionShardingRuntime::CSRLock::lock(opCtx, csr);
if (auto msm = MigrationSourceManager::get(csr, csrLock)) {
return msm->getMigrationStatusReport();
diff --git a/src/mongo/db/s/collection_sharding_runtime.cpp b/src/mongo/db/s/collection_sharding_runtime.cpp
index 2eff2a8f609..2990e877dd2 100644
--- a/src/mongo/db/s/collection_sharding_runtime.cpp
+++ b/src/mongo/db/s/collection_sharding_runtime.cpp
@@ -185,26 +185,6 @@ boost::optional<ScopedCollectionMetadata> CollectionShardingRuntime::_getMetadat
return _metadataManager->getActiveMetadata(_metadataManager, atClusterTime);
}
-CollectionShardingRuntimeLock::CollectionShardingRuntimeLock(OperationContext* opCtx,
- CollectionShardingRuntime* csr,
- LockMode lockMode)
- : _lock([&]() -> CSRLock {
- invariant(lockMode == MODE_IS || lockMode == MODE_X);
- return (lockMode == MODE_IS
- ? CSRLock(Lock::SharedLock(opCtx->lockState(), csr->_stateChangeMutex))
- : CSRLock(Lock::ExclusiveLock(opCtx->lockState(), csr->_stateChangeMutex)));
- }()) {}
-
-CollectionShardingRuntimeLock CollectionShardingRuntimeLock::lock(OperationContext* opCtx,
- CollectionShardingRuntime* csr) {
- return CollectionShardingRuntimeLock(opCtx, csr, MODE_IS);
-}
-
-CollectionShardingRuntimeLock CollectionShardingRuntimeLock::lockExclusive(
- OperationContext* opCtx, CollectionShardingRuntime* csr) {
- return CollectionShardingRuntimeLock(opCtx, csr, MODE_X);
-}
-
CollectionCriticalSection::CollectionCriticalSection(OperationContext* opCtx, NamespaceString ns)
: _nss(std::move(ns)), _opCtx(opCtx) {
AutoGetCollection autoColl(_opCtx,
diff --git a/src/mongo/db/s/collection_sharding_runtime.h b/src/mongo/db/s/collection_sharding_runtime.h
index 89171876643..1cd77d7fde6 100644
--- a/src/mongo/db/s/collection_sharding_runtime.h
+++ b/src/mongo/db/s/collection_sharding_runtime.h
@@ -35,14 +35,13 @@
#include "mongo/db/namespace_string.h"
#include "mongo/db/s/collection_sharding_state.h"
#include "mongo/db/s/metadata_manager.h"
+#include "mongo/db/s/sharding_state_lock.h"
#include "mongo/platform/atomic_word.h"
#include "mongo/stdx/variant.h"
#include "mongo/util/decorable.h"
namespace mongo {
-class CollectionShardingRuntimeLock;
-
extern AtomicWord<int> migrationLockAcquisitionMaxWaitMS;
/**
@@ -54,6 +53,8 @@ class CollectionShardingRuntime final : public CollectionShardingState,
MONGO_DISALLOW_COPYING(CollectionShardingRuntime);
public:
+ using CSRLock = ShardingStateLock<CollectionShardingRuntime>;
+
CollectionShardingRuntime(ServiceContext* sc,
NamespaceString nss,
executor::TaskExecutor* rangeDeleterExecutor);
@@ -149,7 +150,7 @@ public:
}
private:
- friend CollectionShardingRuntimeLock;
+ friend CSRLock;
friend boost::optional<Date_t> CollectionRangeDeleter::cleanUpNextRange(
OperationContext*, NamespaceString const&, OID const&, int, CollectionRangeDeleter*);
@@ -169,42 +170,6 @@ private:
};
/**
- * RAII-style class that locks the CollectionShardingRuntime using the CollectionShardingRuntime's
- * ResourceMutex. The lock will be created and acquired on construction. The lock will be dismissed
- * upon destruction of the CollectionShardingRuntimeLock object.
- */
-class CollectionShardingRuntimeLock {
-
-public:
- using CSRLock = stdx::variant<Lock::SharedLock, Lock::ExclusiveLock>;
-
- /**
- * Locks the sharding runtime state for the specified collection with the
- * CollectionShardingRuntime object's ResourceMutex in MODE_IS. When the object goes out of
- * scope, the ResourceMutex will be unlocked.
- */
- static CollectionShardingRuntimeLock lock(OperationContext* opCtx,
- CollectionShardingRuntime* csr);
-
- /**
- * Follows the same functionality as the CollectionShardingRuntimeLock lock method, except
- * that lockExclusive takes the ResourceMutex in MODE_X.
- */
- static CollectionShardingRuntimeLock lockExclusive(OperationContext* opCtx,
- CollectionShardingRuntime* csr);
-
-private:
- CollectionShardingRuntimeLock(OperationContext* opCtx,
- CollectionShardingRuntime* csr,
- LockMode lockMode);
-
- // The lock created and locked upon construction of a CollectionShardingRuntimeLock object.
- // It locks the ResourceMutex taken from the CollectionShardingRuntime class, passed in on
- // construction.
- CSRLock _lock;
-};
-
-/**
* RAII-style class, which obtains a reference to the critical section for the specified collection.
*/
class CollectionCriticalSection {
diff --git a/src/mongo/db/s/database_sharding_state.cpp b/src/mongo/db/s/database_sharding_state.cpp
index 3c8d81010a5..37893af7df6 100644
--- a/src/mongo/db/s/database_sharding_state.cpp
+++ b/src/mongo/db/s/database_sharding_state.cpp
@@ -48,25 +48,26 @@ const Database::Decoration<DatabaseShardingState> DatabaseShardingState::get =
DatabaseShardingState::DatabaseShardingState() = default;
-void DatabaseShardingState::enterCriticalSectionCatchUpPhase(OperationContext* opCtx) {
+void DatabaseShardingState::enterCriticalSectionCatchUpPhase(OperationContext* opCtx, DSSLock&) {
invariant(opCtx->lockState()->isDbLockedForMode(get.owner(this)->name(), MODE_X));
_critSec.enterCriticalSectionCatchUpPhase();
}
-void DatabaseShardingState::enterCriticalSectionCommitPhase(OperationContext* opCtx) {
+void DatabaseShardingState::enterCriticalSectionCommitPhase(OperationContext* opCtx, DSSLock&) {
invariant(opCtx->lockState()->isDbLockedForMode(get.owner(this)->name(), MODE_X));
_critSec.enterCriticalSectionCommitPhase();
}
void DatabaseShardingState::exitCriticalSection(OperationContext* opCtx,
- boost::optional<DatabaseVersion> newDbVersion) {
- invariant(opCtx->lockState()->isDbLockedForMode(get.owner(this)->name(), MODE_X));
+ boost::optional<DatabaseVersion> newDbVersion,
+ DSSLock&) {
+ invariant(opCtx->lockState()->isDbLockedForMode(get.owner(this)->name(), MODE_IX));
_critSec.exitCriticalSection();
_dbVersion = newDbVersion;
}
-boost::optional<DatabaseVersion> DatabaseShardingState::getDbVersion(
- OperationContext* opCtx) const {
+boost::optional<DatabaseVersion> DatabaseShardingState::getDbVersion(OperationContext* opCtx,
+ DSSLock&) const {
if (!opCtx->lockState()->isDbLockedForMode(get.owner(this)->name(), MODE_X)) {
invariant(opCtx->lockState()->isDbLockedForMode(get.owner(this)->name(), MODE_IS));
}
@@ -74,14 +75,15 @@ boost::optional<DatabaseVersion> DatabaseShardingState::getDbVersion(
}
void DatabaseShardingState::setDbVersion(OperationContext* opCtx,
- boost::optional<DatabaseVersion> newDbVersion) {
+ boost::optional<DatabaseVersion> newDbVersion,
+ DSSLock&) {
invariant(opCtx->lockState()->isDbLockedForMode(get.owner(this)->name(), MODE_X));
log() << "setting this node's cached database version for " << get.owner(this)->name() << " to "
<< (newDbVersion ? newDbVersion->toBSON() : BSONObj());
_dbVersion = newDbVersion;
}
-void DatabaseShardingState::checkDbVersion(OperationContext* opCtx) const {
+void DatabaseShardingState::checkDbVersion(OperationContext* opCtx, DSSLock&) const {
invariant(opCtx->lockState()->isLocked());
const auto dbName = get.owner(this)->name();
@@ -109,12 +111,13 @@ void DatabaseShardingState::checkDbVersion(OperationContext* opCtx) const {
databaseVersion::equal(*clientDbVersion, *_dbVersion));
}
-MovePrimarySourceManager* DatabaseShardingState::getMovePrimarySourceManager() {
+MovePrimarySourceManager* DatabaseShardingState::getMovePrimarySourceManager(DSSLock&) {
return _sourceMgr;
}
void DatabaseShardingState::setMovePrimarySourceManager(OperationContext* opCtx,
- MovePrimarySourceManager* sourceMgr) {
+ MovePrimarySourceManager* sourceMgr,
+ DSSLock&) {
invariant(opCtx->lockState()->isDbLockedForMode(get.owner(this)->name(), MODE_X));
invariant(sourceMgr);
invariant(!_sourceMgr);
@@ -122,8 +125,8 @@ void DatabaseShardingState::setMovePrimarySourceManager(OperationContext* opCtx,
_sourceMgr = sourceMgr;
}
-void DatabaseShardingState::clearMovePrimarySourceManager(OperationContext* opCtx) {
- invariant(opCtx->lockState()->isDbLockedForMode(get.owner(this)->name(), MODE_X));
+void DatabaseShardingState::clearMovePrimarySourceManager(OperationContext* opCtx, DSSLock&) {
+ invariant(opCtx->lockState()->isDbLockedForMode(get.owner(this)->name(), MODE_IX));
_sourceMgr = nullptr;
}
diff --git a/src/mongo/db/s/database_sharding_state.h b/src/mongo/db/s/database_sharding_state.h
index 3033fb27ea4..f00157183f0 100644
--- a/src/mongo/db/s/database_sharding_state.h
+++ b/src/mongo/db/s/database_sharding_state.h
@@ -33,6 +33,7 @@
#include "mongo/base/disallow_copying.h"
#include "mongo/db/catalog/database.h"
#include "mongo/db/s/sharding_migration_critical_section.h"
+#include "mongo/db/s/sharding_state_lock.h"
#include "mongo/s/database_version_gen.h"
namespace mongo {
@@ -47,6 +48,12 @@ class DatabaseShardingState {
MONGO_DISALLOW_COPYING(DatabaseShardingState);
public:
+ /**
+ * A ShardingStateLock is used on DatabaseShardingState operations in order to ensure
+ * synchronization across operations.
+ */
+ using DSSLock = ShardingStateLock<DatabaseShardingState>;
+
static const Database::Decoration<DatabaseShardingState> get;
DatabaseShardingState();
@@ -56,12 +63,13 @@ public:
* Methods to control the databases's critical section. Must be called with the database X lock
* held.
*/
- void enterCriticalSectionCatchUpPhase(OperationContext* opCtx);
- void enterCriticalSectionCommitPhase(OperationContext* opCtx);
+ void enterCriticalSectionCatchUpPhase(OperationContext* opCtx, DSSLock&);
+ void enterCriticalSectionCommitPhase(OperationContext* opCtx, DSSLock&);
void exitCriticalSection(OperationContext* opCtx,
- boost::optional<DatabaseVersion> newDbVersion);
+ boost::optional<DatabaseVersion> newDbVersion,
+ DSSLock&);
- auto getCriticalSectionSignal(ShardingMigrationCriticalSection::Operation op) const {
+ auto getCriticalSectionSignal(ShardingMigrationCriticalSection::Operation op, DSSLock&) const {
return _critSec.getSignal(op);
}
@@ -70,42 +78,52 @@ public:
*
* Invariants that the caller holds the DBLock in X or IS.
*/
- boost::optional<DatabaseVersion> getDbVersion(OperationContext* opCtx) const;
+ boost::optional<DatabaseVersion> getDbVersion(OperationContext* opCtx, DSSLock&) const;
/**
* Sets this shard server's cached dbVersion to newVersion.
*
* Invariants that the caller holds the DBLock in X mode.
*/
- void setDbVersion(OperationContext* opCtx, boost::optional<DatabaseVersion> newVersion);
+ void setDbVersion(OperationContext* opCtx,
+ boost::optional<DatabaseVersion> newVersion,
+ DSSLock&);
/**
* If _critSecSignal is non-null, always throws StaleDbVersion.
* Otherwise, if there is a client dbVersion on the OperationContext, compares it with this
* shard server's cached dbVersion and throws StaleDbVersion if they do not match.
*/
- void checkDbVersion(OperationContext* opCtx) const;
+ void checkDbVersion(OperationContext* opCtx, DSSLock&) const;
/**
* Returns the active movePrimary source manager, if one is available.
*/
- MovePrimarySourceManager* getMovePrimarySourceManager();
+ MovePrimarySourceManager* getMovePrimarySourceManager(DSSLock&);
/**
* Attaches a movePrimary source manager to this database's sharding state. Must be called with
* the database lock in X mode. May not be called if there is a movePrimary source manager
* already installed. Must be followed by a call to clearMovePrimarySourceManager.
*/
- void setMovePrimarySourceManager(OperationContext* opCtx, MovePrimarySourceManager* sourceMgr);
+ void setMovePrimarySourceManager(OperationContext* opCtx,
+ MovePrimarySourceManager* sourceMgr,
+ DSSLock&);
/**
* Removes a movePrimary source manager from this database's sharding state. Must be called with
* with the database lock in X mode. May not be called if there isn't a movePrimary source
* manager installed already through a previous call to setMovePrimarySourceManager.
*/
- void clearMovePrimarySourceManager(OperationContext* opCtx);
+ void clearMovePrimarySourceManager(OperationContext* opCtx, DSSLock&);
private:
+ friend DSSLock;
+
+ // Object-wide ResourceMutex to protect changes to the DatabaseShardingState or objects held
+ // within.
+ Lock::ResourceMutex _stateChangeMutex{"DatabaseShardingState"};
+
// Modifying the state below requires holding the DBLock in X mode; holding the DBLock in any
// mode is acceptable for reading it. (Note: accessing this class at all requires holding the
// DBLock in some mode, since it requires having a pointer to the Database).
diff --git a/src/mongo/db/s/flush_database_cache_updates_command.cpp b/src/mongo/db/s/flush_database_cache_updates_command.cpp
index 41bbe0dd749..2afcdba3d9d 100644
--- a/src/mongo/db/s/flush_database_cache_updates_command.cpp
+++ b/src/mongo/db/s/flush_database_cache_updates_command.cpp
@@ -129,10 +129,11 @@ public:
// inclusive of the commit (and new writes to the committed chunk) that hasn't yet
// propagated back to this shard. This ensures the read your own writes causal
// consistency guarantee.
- auto criticalSectionSignal =
- DatabaseShardingState::get(autoDb.getDb())
- .getCriticalSectionSignal(ShardingMigrationCriticalSection::kRead);
- if (criticalSectionSignal) {
+ auto& dss = DatabaseShardingState::get(autoDb.getDb());
+ auto dssLock = DatabaseShardingState::DSSLock::lock(opCtx, &dss);
+
+ if (auto criticalSectionSignal = dss.getCriticalSectionSignal(
+ ShardingMigrationCriticalSection::kRead, dssLock)) {
oss.setMigrationCriticalSectionSignal(criticalSectionSignal);
}
}
diff --git a/src/mongo/db/s/get_database_version_command.cpp b/src/mongo/db/s/get_database_version_command.cpp
index 51c7118661c..af4a116e0f1 100644
--- a/src/mongo/db/s/get_database_version_command.cpp
+++ b/src/mongo/db/s/get_database_version_command.cpp
@@ -80,7 +80,10 @@ public:
BSONObj versionObj;
AutoGetDb autoDb(opCtx, _targetDb(), MODE_IS);
if (auto db = autoDb.getDb()) {
- if (auto dbVersion = DatabaseShardingState::get(db).getDbVersion(opCtx)) {
+ auto& dss = DatabaseShardingState::get(db);
+ auto dssLock = DatabaseShardingState::DSSLock::lock(opCtx, &dss);
+
+ if (auto dbVersion = dss.getDbVersion(opCtx, dssLock)) {
versionObj = dbVersion->toBSON();
}
}
diff --git a/src/mongo/db/s/migration_chunk_cloner_source_legacy_commands.cpp b/src/mongo/db/s/migration_chunk_cloner_source_legacy_commands.cpp
index 423158365a4..d103d39e144 100644
--- a/src/mongo/db/s/migration_chunk_cloner_source_legacy_commands.cpp
+++ b/src/mongo/db/s/migration_chunk_cloner_source_legacy_commands.cpp
@@ -73,7 +73,7 @@ public:
_autoColl->getCollection());
auto csr = CollectionShardingRuntime::get(opCtx, *nss);
- _csrLock.emplace(CollectionShardingRuntimeLock::lock(opCtx, csr));
+ _csrLock.emplace(CollectionShardingRuntime::CSRLock::lock(opCtx, csr));
if (auto msm = MigrationSourceManager::get(csr, *_csrLock)) {
// It is now safe to access the cloner
@@ -113,9 +113,9 @@ private:
// Scoped database + collection lock
boost::optional<AutoGetCollection> _autoColl;
- // The CollectionShardingRuntimeLock corresponding to the collection to which this
+ // The CollectionShardingRuntime::CSRLock corresponding to the collection to which this
// migration belongs.
- boost::optional<CollectionShardingRuntimeLock> _csrLock;
+ boost::optional<CollectionShardingRuntime::CSRLock> _csrLock;
// Contains the active cloner for the namespace
MigrationChunkClonerSourceLegacy* _chunkCloner;
diff --git a/src/mongo/db/s/migration_source_manager.cpp b/src/mongo/db/s/migration_source_manager.cpp
index 5031490ba21..f3eb6bb825c 100644
--- a/src/mongo/db/s/migration_source_manager.cpp
+++ b/src/mongo/db/s/migration_source_manager.cpp
@@ -122,7 +122,7 @@ MONGO_FAIL_POINT_DEFINE(hangBeforeLeavingCriticalSection);
MONGO_FAIL_POINT_DEFINE(migrationCommitNetworkError);
MigrationSourceManager* MigrationSourceManager::get(CollectionShardingRuntime* csr,
- CollectionShardingRuntimeLock& csrLock) {
+ CollectionShardingRuntime::CSRLock& csrLock) {
return msmForCsr(csr);
}
@@ -255,7 +255,7 @@ Status MigrationSourceManager::startClone(OperationContext* opCtx) {
opCtx->getServiceContext()->getPreciseClockSource()->now() +
Milliseconds(migrationLockAcquisitionMaxWaitMS.load()));
auto csr = CollectionShardingRuntime::get(opCtx, getNss());
- auto lockedCsr = CollectionShardingRuntimeLock::lockExclusive(opCtx, csr);
+ auto lockedCsr = CollectionShardingRuntime::CSRLock::lockExclusive(opCtx, csr);
invariant(nullptr == std::exchange(msmForCsr(csr), this));
}
diff --git a/src/mongo/db/s/migration_source_manager.h b/src/mongo/db/s/migration_source_manager.h
index b2c8546b265..cb6c0d7e7ea 100644
--- a/src/mongo/db/s/migration_source_manager.h
+++ b/src/mongo/db/s/migration_source_manager.h
@@ -77,7 +77,7 @@ public:
* a CollectionShardingRuntime that has its ResourceMutex locked.
*/
static MigrationSourceManager* get(CollectionShardingRuntime* csr,
- CollectionShardingRuntimeLock& csrLock);
+ CollectionShardingRuntime::CSRLock& csrLock);
/**
* Instantiates a new migration source manager with the specified migration parameters. Must be
diff --git a/src/mongo/db/s/move_primary_source_manager.cpp b/src/mongo/db/s/move_primary_source_manager.cpp
index 5b3206c4352..dff9d0a7727 100644
--- a/src/mongo/db/s/move_primary_source_manager.cpp
+++ b/src/mongo/db/s/move_primary_source_manager.cpp
@@ -89,7 +89,11 @@ Status MovePrimarySourceManager::clone(OperationContext* opCtx) {
// We use AutoGetOrCreateDb the first time just in case movePrimary was called before any
// data was inserted into the database.
AutoGetOrCreateDb autoDb(opCtx, getNss().toString(), MODE_X);
- DatabaseShardingState::get(autoDb.getDb()).setMovePrimarySourceManager(opCtx, this);
+
+ auto& dss = DatabaseShardingState::get(autoDb.getDb());
+ auto dssLock = DatabaseShardingState::DSSLock::lockExclusive(opCtx, &dss);
+
+ dss.setMovePrimarySourceManager(opCtx, this, dssLock);
}
_state = kCloning;
@@ -146,8 +150,11 @@ Status MovePrimarySourceManager::enterCriticalSection(OperationContext* opCtx) {
<< " was dropped during the movePrimary operation.");
}
+ auto& dss = DatabaseShardingState::get(autoDb.getDb());
+ auto dssLock = DatabaseShardingState::DSSLock::lockExclusive(opCtx, &dss);
+
// IMPORTANT: After this line, the critical section is in place and needs to be signaled
- DatabaseShardingState::get(autoDb.getDb()).enterCriticalSectionCatchUpPhase(opCtx);
+ dss.enterCriticalSectionCatchUpPhase(opCtx, dssLock);
}
_state = kCriticalSection;
@@ -195,9 +202,12 @@ Status MovePrimarySourceManager::commitOnConfig(OperationContext* opCtx) {
<< " was dropped during the movePrimary operation.");
}
+ auto& dss = DatabaseShardingState::get(autoDb.getDb());
+ auto dssLock = DatabaseShardingState::DSSLock::lockExclusive(opCtx, &dss);
+
// Read operations must begin to wait on the critical section just before we send the
// commit operation to the config server
- DatabaseShardingState::get(autoDb.getDb()).enterCriticalSectionCommitPhase(opCtx);
+ dss.enterCriticalSectionCommitPhase(opCtx, dssLock);
}
auto configShard = Grid::get(opCtx)->shardRegistry()->getConfigShard();
@@ -244,7 +254,7 @@ Status MovePrimarySourceManager::commitOnConfig(OperationContext* opCtx) {
// this node can accept writes for this collection as a proxy for it being primary.
if (!validateStatus.isOK()) {
UninterruptibleLockGuard noInterrupt(opCtx->lockState());
- AutoGetDb autoDb(opCtx, getNss().toString(), MODE_X);
+ AutoGetDb autoDb(opCtx, getNss().toString(), MODE_IX);
if (!autoDb.getDb()) {
uasserted(ErrorCodes::ConflictingOperationInProgress,
@@ -253,7 +263,10 @@ Status MovePrimarySourceManager::commitOnConfig(OperationContext* opCtx) {
}
if (!repl::ReplicationCoordinator::get(opCtx)->canAcceptWritesFor(opCtx, getNss())) {
- DatabaseShardingState::get(autoDb.getDb()).setDbVersion(opCtx, boost::none);
+ auto& dss = DatabaseShardingState::get(autoDb.getDb());
+ auto dssLock = DatabaseShardingState::DSSLock::lockExclusive(opCtx, &dss);
+
+ dss.setDbVersion(opCtx, boost::none, dssLock);
uassertStatusOK(validateStatus.withContext(
str::stream() << "Unable to verify movePrimary commit for database: "
<< getNss().ns()
@@ -345,13 +358,16 @@ void MovePrimarySourceManager::_cleanup(OperationContext* opCtx) {
{
// Unregister from the database's sharding state if we're still registered.
UninterruptibleLockGuard noInterrupt(opCtx->lockState());
- AutoGetDb autoDb(opCtx, getNss().toString(), MODE_X);
+ AutoGetDb autoDb(opCtx, getNss().toString(), MODE_IX);
if (autoDb.getDb()) {
- DatabaseShardingState::get(autoDb.getDb()).clearMovePrimarySourceManager(opCtx);
+ auto& dss = DatabaseShardingState::get(autoDb.getDb());
+ auto dssLock = DatabaseShardingState::DSSLock::lockExclusive(opCtx, &dss);
+
+ dss.clearMovePrimarySourceManager(opCtx, dssLock);
// Leave the critical section if we're still registered.
- DatabaseShardingState::get(autoDb.getDb()).exitCriticalSection(opCtx, boost::none);
+ dss.exitCriticalSection(opCtx, boost::none, dssLock);
}
}
diff --git a/src/mongo/db/s/op_observer_sharding_impl.cpp b/src/mongo/db/s/op_observer_sharding_impl.cpp
index 134727d46b9..786aed87d3e 100644
--- a/src/mongo/db/s/op_observer_sharding_impl.cpp
+++ b/src/mongo/db/s/op_observer_sharding_impl.cpp
@@ -61,7 +61,7 @@ bool OpObserverShardingImpl::isMigrating(OperationContext* opCtx,
NamespaceString const& nss,
BSONObj const& docToDelete) {
auto csr = CollectionShardingRuntime::get(opCtx, nss);
- auto csrLock = CollectionShardingRuntimeLock::lock(opCtx, csr);
+ auto csrLock = CollectionShardingRuntime::CSRLock::lock(opCtx, csr);
auto msm = MigrationSourceManager::get(csr, csrLock);
return msm && msm->getCloner()->isDocumentInMigratingChunk(docToDelete);
}
@@ -86,7 +86,7 @@ void OpObserverShardingImpl::shardObserveInsertOp(OperationContext* opCtx,
{
auto csr = CollectionShardingRuntime::get(opCtx, nss);
- auto csrLock = CollectionShardingRuntimeLock::lock(opCtx, csr);
+ auto csrLock = CollectionShardingRuntime::CSRLock::lock(opCtx, csr);
auto msm = MigrationSourceManager::get(csr, csrLock);
if (msm) {
@@ -112,7 +112,7 @@ void OpObserverShardingImpl::shardObserveUpdateOp(OperationContext* opCtx,
{
auto csr = CollectionShardingRuntime::get(opCtx, nss);
- auto csrLock = CollectionShardingRuntimeLock::lock(opCtx, csr);
+ auto csrLock = CollectionShardingRuntime::CSRLock::lock(opCtx, csr);
auto msm = MigrationSourceManager::get(csr, csrLock);
if (msm) {
@@ -137,7 +137,7 @@ void OpObserverShardingImpl::shardObserveDeleteOp(OperationContext* opCtx,
{
auto csr = CollectionShardingRuntime::get(opCtx, nss);
- auto csrLock = CollectionShardingRuntimeLock::lock(opCtx, csr);
+ auto csrLock = CollectionShardingRuntime::CSRLock::lock(opCtx, csr);
auto msm = MigrationSourceManager::get(csr, csrLock);
if (msm && isMigrating) {
diff --git a/src/mongo/db/s/shard_filtering_metadata_refresh.cpp b/src/mongo/db/s/shard_filtering_metadata_refresh.cpp
index 4fd28b98032..f5422a48a38 100644
--- a/src/mongo/db/s/shard_filtering_metadata_refresh.cpp
+++ b/src/mongo/db/s/shard_filtering_metadata_refresh.cpp
@@ -249,7 +249,10 @@ void forceDatabaseRefresh(OperationContext* opCtx, const StringData dbName) {
return;
}
- const auto cachedDbVersion = DatabaseShardingState::get(db).getDbVersion(opCtx);
+ auto& dss = DatabaseShardingState::get(db);
+ auto dssLock = DatabaseShardingState::DSSLock::lock(opCtx, &dss);
+
+ const auto cachedDbVersion = dss.getDbVersion(opCtx, dssLock);
if (cachedDbVersion && cachedDbVersion->getUuid() == refreshedDbVersion.getUuid() &&
cachedDbVersion->getLastMod() >= refreshedDbVersion.getLastMod()) {
LOG(2) << "Skipping setting cached databaseVersion for " << dbName
@@ -269,7 +272,10 @@ void forceDatabaseRefresh(OperationContext* opCtx, const StringData dbName) {
return;
}
- DatabaseShardingState::get(db).setDbVersion(opCtx, std::move(refreshedDbVersion));
+ auto& dss = DatabaseShardingState::get(db);
+ auto dssLock = DatabaseShardingState::DSSLock::lockExclusive(opCtx, &dss);
+
+ dss.setDbVersion(opCtx, std::move(refreshedDbVersion), dssLock);
}
} // namespace mongo
diff --git a/src/mongo/db/s/shard_server_op_observer.cpp b/src/mongo/db/s/shard_server_op_observer.cpp
index c211377f998..863a9f844c7 100644
--- a/src/mongo/db/s/shard_server_op_observer.cpp
+++ b/src/mongo/db/s/shard_server_op_observer.cpp
@@ -322,7 +322,9 @@ void ShardServerOpObserver::onUpdate(OperationContext* opCtx, const OplogUpdateE
if (setField.hasField(ShardDatabaseType::enterCriticalSectionCounter.name())) {
AutoGetDb autoDb(opCtx, db, MODE_X);
if (autoDb.getDb()) {
- DatabaseShardingState::get(autoDb.getDb()).setDbVersion(opCtx, boost::none);
+ auto& dss = DatabaseShardingState::get(autoDb.getDb());
+ auto dssLock = DatabaseShardingState::DSSLock::lockExclusive(opCtx, &dss);
+ dss.setDbVersion(opCtx, boost::none, dssLock);
}
}
}
@@ -368,7 +370,9 @@ void ShardServerOpObserver::onDelete(OperationContext* opCtx,
AutoGetDb autoDb(opCtx, deletedDatabase, MODE_X);
if (autoDb.getDb()) {
- DatabaseShardingState::get(autoDb.getDb()).setDbVersion(opCtx, boost::none);
+ auto& dss = DatabaseShardingState::get(autoDb.getDb());
+ auto dssLock = DatabaseShardingState::DSSLock::lockExclusive(opCtx, &dss);
+ dss.setDbVersion(opCtx, boost::none, dssLock);
}
}
diff --git a/src/mongo/db/s/sharding_state_lock.h b/src/mongo/db/s/sharding_state_lock.h
new file mode 100644
index 00000000000..ec2408618ca
--- /dev/null
+++ b/src/mongo/db/s/sharding_state_lock.h
@@ -0,0 +1,97 @@
+
+/**
+ * Copyright (C) 2018-present MongoDB, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the Server Side Public License, version 1,
+ * as published by MongoDB, Inc.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * Server Side Public License for more details.
+ *
+ * You should have received a copy of the Server Side Public License
+ * along with this program. If not, see
+ * <http://www.mongodb.com/licensing/server-side-public-license>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the Server Side Public License in all respects for
+ * all of the code used other than as permitted herein. If you modify file(s)
+ * with this exception, you may extend this exception to your version of the
+ * file(s), but you are not obligated to do so. If you do not wish to do so,
+ * delete this exception statement from your version. If you delete this
+ * exception statement from all source files in the program, then also delete
+ * it in the license file.
+ */
+
+#pragma once
+
+#include "mongo/base/disallow_copying.h"
+#include "mongo/db/concurrency/d_concurrency.h"
+#include "mongo/stdx/variant.h"
+
+namespace mongo {
+
+/**
+ * RAII-style class that locks a sharding state object using the state object's ResourceMutex. The
+ * lock will be created and acquired on construction. The lock will be dismissed upon destruction
+ * of the sharding state object.
+ */
+template <class ShardingState>
+class ShardingStateLock {
+
+public:
+ /**
+ * Locks the sharding state object with the sharding state object's ResourceMutex in MODE_IS.
+ * When the object goes out of scope, the ResourceMutex will be unlocked.
+ */
+ static ShardingStateLock<ShardingState> lock(OperationContext* opCtx, ShardingState* state);
+
+ /**
+ * Follows the same functionality as the ShardingStateLock lock method, except that
+ * lockExclusive takes the ResourceMutex in MODE_X.
+ */
+ static ShardingStateLock<ShardingState> lockExclusive(OperationContext* opCtx,
+ ShardingState* state);
+
+private:
+ using StateLock = stdx::variant<Lock::SharedLock, Lock::ExclusiveLock>;
+
+ ShardingStateLock<ShardingState>(OperationContext* opCtx,
+ ShardingState* state,
+ LockMode lockMode);
+
+ // The lock created and locked upon construction of a ShardingStateLock object. It locks the
+ // ResourceMutex taken from the ShardingState class, passed in on construction.
+ StateLock _lock;
+};
+
+template <class ShardingState>
+ShardingStateLock<ShardingState>::ShardingStateLock(OperationContext* opCtx,
+ ShardingState* state,
+ LockMode lockMode)
+ : _lock([&]() -> StateLock {
+ invariant(lockMode == MODE_IS || lockMode == MODE_X);
+ return (
+ lockMode == MODE_IS
+ ? StateLock(Lock::SharedLock(opCtx->lockState(), state->_stateChangeMutex))
+ : StateLock(Lock::ExclusiveLock(opCtx->lockState(), state->_stateChangeMutex)));
+ }()) {}
+
+template <class ShardingState>
+ShardingStateLock<ShardingState> ShardingStateLock<ShardingState>::lock(OperationContext* opCtx,
+ ShardingState* state) {
+ return ShardingStateLock(opCtx, state, MODE_IS);
+}
+
+template <class ShardingState>
+ShardingStateLock<ShardingState> ShardingStateLock<ShardingState>::lockExclusive(
+ OperationContext* opCtx, ShardingState* state) {
+ return ShardingStateLock(opCtx, state, MODE_X);
+}
+
+} // namespace mongo \ No newline at end of file