summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/mongo/db/s/SConscript1
-rw-r--r--src/mongo/db/s/collection_sharding_state.cpp35
-rw-r--r--src/mongo/db/s/collection_sharding_state.h18
-rw-r--r--src/mongo/db/s/database_sharding_state.cpp23
-rw-r--r--src/mongo/db/s/database_sharding_state.h27
-rw-r--r--src/mongo/db/s/flush_routing_table_cache_updates_command.cpp12
-rw-r--r--src/mongo/db/s/migration_source_manager.cpp22
-rw-r--r--src/mongo/db/s/migration_source_manager.h26
-rw-r--r--src/mongo/db/s/set_shard_version_command.cpp34
-rw-r--r--src/mongo/db/s/sharding_migration_critical_section.cpp70
-rw-r--r--src/mongo/db/s/sharding_migration_critical_section.h91
11 files changed, 244 insertions, 115 deletions
diff --git a/src/mongo/db/s/SConscript b/src/mongo/db/s/SConscript
index 4dbfef30d60..9d361d32ad0 100644
--- a/src/mongo/db/s/SConscript
+++ b/src/mongo/db/s/SConscript
@@ -15,6 +15,7 @@ env.Library(
'database_sharding_state.cpp',
'operation_sharding_state.cpp',
'sharded_connection_info.cpp',
+ 'sharding_migration_critical_section.cpp',
],
LIBDEPS=[
'$BUILD_DIR/mongo/base',
diff --git a/src/mongo/db/s/collection_sharding_state.cpp b/src/mongo/db/s/collection_sharding_state.cpp
index a6a6765d754..9fd8c6c887e 100644
--- a/src/mongo/db/s/collection_sharding_state.cpp
+++ b/src/mongo/db/s/collection_sharding_state.cpp
@@ -37,7 +37,6 @@
#include "mongo/db/catalog_raii.h"
#include "mongo/db/client.h"
#include "mongo/db/operation_context.h"
-#include "mongo/db/s/migration_chunk_cloner_source.h"
#include "mongo/db/s/migration_source_manager.h"
#include "mongo/db/s/operation_sharding_state.h"
#include "mongo/db/s/sharded_connection_info.h"
@@ -221,9 +220,19 @@ std::vector<ScopedCollectionMetadata> CollectionShardingState::overlappingMetada
return _metadataManager->overlappingMetadata(_metadataManager, range);
}
+void CollectionShardingState::enterCriticalSectionCatchUpPhase(OperationContext* opCtx) {
+ invariant(opCtx->lockState()->isCollectionLockedForMode(_nss.ns(), MODE_X));
+ _critSec.enterCriticalSectionCatchUpPhase();
+}
+
+void CollectionShardingState::enterCriticalSectionCommitPhase(OperationContext* opCtx) {
+ invariant(opCtx->lockState()->isCollectionLockedForMode(_nss.ns(), MODE_X));
+ _critSec.enterCriticalSectionCommitPhase();
+}
-MigrationSourceManager* CollectionShardingState::getMigrationSourceManager() {
- return _sourceMgr;
+void CollectionShardingState::exitCriticalSection(OperationContext* opCtx) {
+ invariant(opCtx->lockState()->isCollectionLockedForMode(_nss.ns(), MODE_X));
+ _critSec.exitCriticalSection();
}
void CollectionShardingState::setMigrationSourceManager(OperationContext* opCtx,
@@ -401,18 +410,16 @@ bool CollectionShardingState::_checkShardVersionOk(OperationContext* opCtx,
auto metadata = getMetadata();
*actualShardVersion = metadata ? metadata->getShardVersion() : ChunkVersion::UNSHARDED();
- if (_sourceMgr) {
- const bool isReader = !opCtx->lockState()->isWriteLocked();
-
- auto criticalSectionSignal = _sourceMgr->getMigrationCriticalSectionSignal(isReader);
- if (criticalSectionSignal) {
- *errmsg = str::stream() << "migration commit in progress for " << _nss.ns();
+ auto criticalSectionSignal = _critSec.getSignal(opCtx->lockState()->isWriteLocked()
+ ? ShardingMigrationCriticalSection::kWrite
+ : ShardingMigrationCriticalSection::kRead);
+ if (criticalSectionSignal) {
+ *errmsg = str::stream() << "migration commit in progress for " << _nss.ns();
- // Set migration critical section on operation sharding state: operation will wait for
- // the migration to finish before returning failure and retrying.
- oss.setMigrationCriticalSectionSignal(criticalSectionSignal);
- return false;
- }
+ // Set migration critical section on operation sharding state: operation will wait for
+ // the migration to finish before returning failure and retrying.
+ oss.setMigrationCriticalSectionSignal(criticalSectionSignal);
+ return false;
}
if (expectedShardVersion->isWriteCompatibleWith(*actualShardVersion)) {
diff --git a/src/mongo/db/s/collection_sharding_state.h b/src/mongo/db/s/collection_sharding_state.h
index 14b403cd93f..51ff7d26435 100644
--- a/src/mongo/db/s/collection_sharding_state.h
+++ b/src/mongo/db/s/collection_sharding_state.h
@@ -35,6 +35,7 @@
#include "mongo/bson/bsonobj.h"
#include "mongo/db/namespace_string.h"
#include "mongo/db/s/metadata_manager.h"
+#include "mongo/db/s/sharding_migration_critical_section.h"
namespace mongo {
@@ -153,9 +154,16 @@ public:
std::vector<ScopedCollectionMetadata> overlappingMetadata(ChunkRange const& range) const;
/**
- * Returns the active migration source manager, if one is available.
+ * Methods to control the collection's critical section. Must be called with the collection X
+ * lock held.
*/
- MigrationSourceManager* getMigrationSourceManager();
+ void enterCriticalSectionCatchUpPhase(OperationContext* opCtx);
+ void enterCriticalSectionCommitPhase(OperationContext* opCtx);
+ void exitCriticalSection(OperationContext* opCtx);
+
+ auto getCriticalSectionSignal(ShardingMigrationCriticalSection::Operation op) const {
+ return _critSec.getSignal(op);
+ }
/**
* Attaches a migration source manager to this collection's sharding state. Must be called with
@@ -164,6 +172,10 @@ public:
*/
void setMigrationSourceManager(OperationContext* opCtx, MigrationSourceManager* sourceMgr);
+ auto getMigrationSourceManager() const {
+ return _sourceMgr;
+ }
+
/**
* Removes a migration source manager from this collection's sharding state. Must be called with
* collection X lock. May not be called if there isn't a migration source manager installed
@@ -255,6 +267,8 @@ private:
// Contains all the metadata associated with this collection.
std::shared_ptr<MetadataManager> _metadataManager;
+ ShardingMigrationCriticalSection _critSec;
+
// If this collection is serving as a source shard for chunk migration, this value will be
// non-null. To write this value there needs to be X-lock on the collection in order to
// synchronize with other callers, which read it.
diff --git a/src/mongo/db/s/database_sharding_state.cpp b/src/mongo/db/s/database_sharding_state.cpp
index a08d5dbcca6..ccd642527fc 100644
--- a/src/mongo/db/s/database_sharding_state.cpp
+++ b/src/mongo/db/s/database_sharding_state.cpp
@@ -45,28 +45,26 @@ const Database::Decoration<DatabaseShardingState> DatabaseShardingState::get =
DatabaseShardingState::DatabaseShardingState() = default;
-void DatabaseShardingState::enterCriticalSection(OperationContext* opCtx) {
+void DatabaseShardingState::enterCriticalSectionCatchUpPhase(OperationContext* opCtx) {
invariant(opCtx->lockState()->isDbLockedForMode(get.owner(this)->name(), MODE_X));
- invariant(!_critSecSignal);
- _critSecSignal = std::make_shared<Notification<void>>();
+ _critSec.enterCriticalSectionCatchUpPhase();
// TODO (SERVER-33313): call CursorManager::invalidateAll() on all collections in this database
// with 'fromMovePrimary=true' and a predicate to only invalidate the cursor if the opCtx on its
// PlanExecutor has a client dbVersion.
}
+void DatabaseShardingState::enterCriticalSectionCommitPhase(OperationContext* opCtx) {
+ 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));
- invariant(_critSecSignal);
- _critSecSignal->set();
- _critSecSignal.reset();
+ _critSec.exitCriticalSection();
_dbVersion = newDbVersion;
}
-std::shared_ptr<Notification<void>> DatabaseShardingState::getCriticalSectionSignal() const {
- return _critSecSignal;
-}
-
void DatabaseShardingState::setDbVersion(OperationContext* opCtx,
boost::optional<DatabaseVersion> newDbVersion) {
invariant(opCtx->lockState()->isDbLockedForMode(get.owner(this)->name(), MODE_X));
@@ -88,7 +86,10 @@ void DatabaseShardingState::checkDbVersion(OperationContext* opCtx) const {
return;
}
- if (_critSecSignal) {
+ auto criticalSectionSignal = _critSec.getSignal(opCtx->lockState()->isWriteLocked()
+ ? ShardingMigrationCriticalSection::kWrite
+ : ShardingMigrationCriticalSection::kRead);
+ if (criticalSectionSignal) {
// TODO (SERVER-33773): Set movePrimary critical section signal on the
// OperationShardingState (so that the operation can wait outside the DBLock for the
// movePrimary critical section to end before returning to the client).
diff --git a/src/mongo/db/s/database_sharding_state.h b/src/mongo/db/s/database_sharding_state.h
index 50e6e0239eb..d5e09aa55f0 100644
--- a/src/mongo/db/s/database_sharding_state.h
+++ b/src/mongo/db/s/database_sharding_state.h
@@ -30,6 +30,7 @@
#include "mongo/base/disallow_copying.h"
#include "mongo/db/catalog/database.h"
+#include "mongo/db/s/sharding_migration_critical_section.h"
#include "mongo/s/database_version_gen.h"
namespace mongo {
@@ -49,25 +50,17 @@ public:
~DatabaseShardingState() = default;
/**
- * Assigns a new Notification to _critSecSignal and invalidates all yielded readers and writers
- * on collections in Database that have a client dbVersion on their OperationContext.
- *
- * Invariants that _critSecSignal was null and that the caller holds the DBLock in X mode.
- */
- void enterCriticalSection(OperationContext* opCtx);
-
- /**
- * Signals and clears _critSecSignal, and sets _dbVersion to 'newDbVersion'.
- *
- * Invariants that _critSecSignal was not null and that the caller holds the DBLock in X mode.
+ * 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 exitCriticalSection(OperationContext* opCtx,
boost::optional<DatabaseVersion> newDbVersion);
- /**
- * Returns a shared_ptr to _critSecSignal if it's non-null, otherwise nullptr.
- */
- std::shared_ptr<Notification<void>> getCriticalSectionSignal() const;
+ auto getCriticalSectionSignal(ShardingMigrationCriticalSection::Operation op) const {
+ return _critSec.getSignal(op);
+ }
/**
* Sets this shard server's cached dbVersion to newVersion.
@@ -88,9 +81,7 @@ private:
// 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).
- // Is non-null if this shard server is in a movePrimary critical section for the database.
- // Stored as shared_ptr rather than boost::optional so callers can wait on it outside a DBLock.
- std::shared_ptr<Notification<void>> _critSecSignal;
+ ShardingMigrationCriticalSection _critSec;
// This shard server's cached dbVersion. If boost::none, indicates this shard server does not
// know the dbVersion.
diff --git a/src/mongo/db/s/flush_routing_table_cache_updates_command.cpp b/src/mongo/db/s/flush_routing_table_cache_updates_command.cpp
index 660e86ee436..bd3d203ea53 100644
--- a/src/mongo/db/s/flush_routing_table_cache_updates_command.cpp
+++ b/src/mongo/db/s/flush_routing_table_cache_updates_command.cpp
@@ -129,13 +129,11 @@ public:
// finish on the primary in case a secondary's caller has an afterClusterTime 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 css = CollectionShardingState::get(opCtx, nss);
- if (css->getMigrationSourceManager()) {
- auto criticalSectionSignal =
- css->getMigrationSourceManager()->getMigrationCriticalSectionSignal(true);
- if (criticalSectionSignal) {
- oss.setMigrationCriticalSectionSignal(criticalSectionSignal);
- }
+ auto const css = CollectionShardingState::get(opCtx, nss);
+ auto criticalSectionSignal =
+ css->getCriticalSectionSignal(ShardingMigrationCriticalSection::kRead);
+ if (criticalSectionSignal) {
+ oss.setMigrationCriticalSectionSignal(criticalSectionSignal);
}
}
diff --git a/src/mongo/db/s/migration_source_manager.cpp b/src/mongo/db/s/migration_source_manager.cpp
index a7d0ed12d44..8f113193f1e 100644
--- a/src/mongo/db/s/migration_source_manager.cpp
+++ b/src/mongo/db/s/migration_source_manager.cpp
@@ -320,7 +320,8 @@ Status MigrationSourceManager::enterCriticalSection(OperationContext* opCtx) {
AutoGetCollection autoColl(opCtx, getNss(), MODE_IX, MODE_X);
// IMPORTANT: After this line, the critical section is in place and needs to be signaled
- _critSecSignal = std::make_shared<Notification<void>>();
+ CollectionShardingState::get(opCtx, _args.getNss())
+ ->enterCriticalSectionCatchUpPhase(opCtx);
}
_state = kCriticalSection;
@@ -423,7 +424,7 @@ Status MigrationSourceManager::commitChunkMetadataOnConfig(OperationContext* opC
{
UninterruptibleLockGuard noInterrupt(opCtx->lockState());
AutoGetCollection autoColl(opCtx, getNss(), MODE_IX, MODE_X);
- _readsShouldWaitOnCritSec = true;
+ CollectionShardingState::get(opCtx, _args.getNss())->enterCriticalSectionCommitPhase(opCtx);
}
Timer t;
@@ -692,9 +693,7 @@ void MigrationSourceManager::_cleanup(OperationContext* opCtx) {
css->clearMigrationSourceManager(opCtx);
// Leave the critical section.
- if (_critSecSignal) {
- _critSecSignal->set();
- }
+ CollectionShardingState::get(opCtx, _args.getNss())->exitCriticalSection(opCtx);
return std::move(_cloneDriver);
}();
@@ -731,19 +730,6 @@ void MigrationSourceManager::_cleanup(OperationContext* opCtx) {
_state = kDone;
}
-std::shared_ptr<Notification<void>> MigrationSourceManager::getMigrationCriticalSectionSignal(
- bool isForReadOnlyOperation) const {
- if (!isForReadOnlyOperation) {
- return _critSecSignal;
- }
-
- if (_readsShouldWaitOnCritSec) {
- return _critSecSignal;
- }
-
- return nullptr;
-}
-
BSONObj MigrationSourceManager::getMigrationStatusReport() const {
return migrationutil::makeMigrationStatusDocument(getNss(),
_args.getFromShardId(),
diff --git a/src/mongo/db/s/migration_source_manager.h b/src/mongo/db/s/migration_source_manager.h
index cb24599e519..9c37802441e 100644
--- a/src/mongo/db/s/migration_source_manager.h
+++ b/src/mongo/db/s/migration_source_manager.h
@@ -32,13 +32,12 @@
#include "mongo/base/disallow_copying.h"
#include "mongo/db/s/collection_sharding_state.h"
+#include "mongo/db/s/migration_chunk_cloner_source.h"
#include "mongo/s/request_types/move_chunk_request.h"
-#include "mongo/util/concurrency/notification.h"
#include "mongo/util/timer.h"
namespace mongo {
-class MigrationChunkClonerSource;
class OperationContext;
struct ShardingStatistics;
@@ -168,16 +167,6 @@ public:
}
/**
- * Retrieves a critical section object to wait on. Will return nullptr if the migration is not
- * yet in the critical section or if the caller is a reader and the migration is still in the
- * process of transferring the last batch of chunk modifications.
- *
- * Must be called with some form of lock on the collection namespace.
- */
- std::shared_ptr<Notification<void>> getMigrationCriticalSectionSignal(
- bool isForReadOnlyOperation) const;
-
- /**
* Returns a report on the active migration.
*
* Must be called with some form of lock on the collection namespace.
@@ -238,19 +227,6 @@ private:
// completed.
std::unique_ptr<MigrationChunkClonerSource> _cloneDriver;
- // Whether the source manager is in a critical section. Tracked as a shared pointer so that
- // callers don't have to hold collection lock in order to wait on it. Available after the
- // critical section stage has completed.
- std::shared_ptr<Notification<void>> _critSecSignal;
-
- // Used to delay blocking reads up until the commit of the metadata on the config server needs
- // to happen. This allows the shard to serve reads during transfer of the last batch of mods in
- // the migration critical section.
- //
- // The transition from false to true is protected by the collection X-lock, which happens just
- // before the config server metadata commit is scheduled.
- bool _readsShouldWaitOnCritSec{false};
-
// The statistics about a chunk migration to be included in moveChunk.commit
BSONObj _recipientCloneCounts;
};
diff --git a/src/mongo/db/s/set_shard_version_command.cpp b/src/mongo/db/s/set_shard_version_command.cpp
index 076c00a820d..63818e7fe89 100644
--- a/src/mongo/db/s/set_shard_version_command.cpp
+++ b/src/mongo/db/s/set_shard_version_command.cpp
@@ -292,16 +292,13 @@ public:
// TODO: Refactor all of this
if (requestedVersion < collectionShardVersion &&
requestedVersion.epoch() == collectionShardVersion.epoch()) {
- if (css->getMigrationSourceManager()) {
- auto critSecSignal =
- css->getMigrationSourceManager()->getMigrationCriticalSectionSignal(
- false);
- if (critSecSignal) {
- collLock.reset();
- autoDb.reset();
- log() << "waiting till out of critical section";
- critSecSignal->waitFor(opCtx, Seconds(10));
- }
+ auto critSecSignal =
+ css->getCriticalSectionSignal(ShardingMigrationCriticalSection::kWrite);
+ if (critSecSignal) {
+ collLock.reset();
+ autoDb.reset();
+ log() << "waiting till out of critical section";
+ critSecSignal->waitFor(opCtx, Seconds(10));
}
errmsg = str::stream() << "shard global version for collection is higher "
@@ -316,16 +313,13 @@ public:
if (!collectionShardVersion.isSet() && !authoritative) {
// Needed b/c when the last chunk is moved off a shard, the version gets reset
// to zero, which should require a reload.
- if (css->getMigrationSourceManager()) {
- auto critSecSignal =
- css->getMigrationSourceManager()->getMigrationCriticalSectionSignal(
- false);
- if (critSecSignal) {
- collLock.reset();
- autoDb.reset();
- log() << "waiting till out of critical section";
- critSecSignal->waitFor(opCtx, Seconds(10));
- }
+ auto critSecSignal =
+ css->getCriticalSectionSignal(ShardingMigrationCriticalSection::kWrite);
+ if (critSecSignal) {
+ collLock.reset();
+ autoDb.reset();
+ log() << "waiting till out of critical section";
+ critSecSignal->waitFor(opCtx, Seconds(10));
}
// need authoritative for first look
diff --git a/src/mongo/db/s/sharding_migration_critical_section.cpp b/src/mongo/db/s/sharding_migration_critical_section.cpp
new file mode 100644
index 00000000000..210b9218c90
--- /dev/null
+++ b/src/mongo/db/s/sharding_migration_critical_section.cpp
@@ -0,0 +1,70 @@
+/**
+ * Copyright (C) 2018 MongoDB Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * 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
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * 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 GNU Affero General 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.
+ */
+
+#include "mongo/platform/basic.h"
+
+#include "mongo/db/s/sharding_migration_critical_section.h"
+
+namespace mongo {
+
+ShardingMigrationCriticalSection::ShardingMigrationCriticalSection() = default;
+
+ShardingMigrationCriticalSection::~ShardingMigrationCriticalSection() {
+ invariant(!_critSecSignal);
+}
+
+void ShardingMigrationCriticalSection::enterCriticalSectionCatchUpPhase() {
+ invariant(!_critSecSignal);
+ _critSecSignal = std::make_shared<Notification<void>>();
+ _readsShouldWaitOnCritSec = false;
+}
+
+void ShardingMigrationCriticalSection::enterCriticalSectionCommitPhase() {
+ invariant(_critSecSignal);
+ _readsShouldWaitOnCritSec = true;
+}
+
+void ShardingMigrationCriticalSection::exitCriticalSection() {
+ if (_critSecSignal) {
+ _critSecSignal->set();
+ _critSecSignal.reset();
+ }
+}
+
+std::shared_ptr<Notification<void>> ShardingMigrationCriticalSection::getSignal(
+ Operation op) const {
+ if (!_critSecSignal)
+ return nullptr;
+
+ if (op == kWrite || _readsShouldWaitOnCritSec)
+ return _critSecSignal;
+
+ return nullptr;
+}
+
+} // namespace mongo
diff --git a/src/mongo/db/s/sharding_migration_critical_section.h b/src/mongo/db/s/sharding_migration_critical_section.h
new file mode 100644
index 00000000000..32aa32f3b36
--- /dev/null
+++ b/src/mongo/db/s/sharding_migration_critical_section.h
@@ -0,0 +1,91 @@
+/**
+ * Copyright (C) 2018 MongoDB Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * 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
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * 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 GNU Affero General 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/util/concurrency/notification.h"
+
+namespace mongo {
+
+/**
+ * Implements the critical section logic for particular collection or database in the sharding
+ * subsystem. It supports two phases - catch-up and commit. During the catch-up phase, only writes
+ * are disallowed, but reads can still proceed. In the commit phase, both reads and writes are
+ * disallowed.
+ *
+ * Currently, only collections stay in the catch-up phase while the last batch of mods is
+ * transferred to the recipient shard. Databases effectively only support the commit phase.
+ */
+class ShardingMigrationCriticalSection {
+ MONGO_DISALLOW_COPYING(ShardingMigrationCriticalSection);
+
+public:
+ ShardingMigrationCriticalSection();
+ ~ShardingMigrationCriticalSection();
+
+ /**
+ * Enters the critical section in a mode, which still allows reads.
+ *
+ * NOTE: Must be called under the appropriate X lock (collection or database).
+ */
+ void enterCriticalSectionCatchUpPhase();
+
+ /**
+ * Sets the critical section in a mode, which disallows reads.
+ */
+ void enterCriticalSectionCommitPhase();
+
+ /**
+ * Leaves the critical section.
+ */
+ void exitCriticalSection();
+
+ /**
+ * Retrieves a critical section notification to wait on. Will return nullptr if the migration is
+ * not yet in the critical section or if the caller is a reader and the migration is not yet in
+ * the commit phase.
+ */
+ enum Operation { kRead, kWrite };
+ std::shared_ptr<Notification<void>> getSignal(Operation op) const;
+
+private:
+ // Whether the migration source is in a critical section. Tracked as a shared pointer so that
+ // callers don't have to hold metadata locks in order to wait on it.
+ std::shared_ptr<Notification<void>> _critSecSignal;
+
+ // Used to delay blocking reads up until the commit of the metadata on the config server needs
+ // to happen. This allows the shard to serve reads up until the config server metadata update
+ // needs to be committed.
+ //
+ // The transition from false to true is protected by the database or collection X-lock, which
+ // happens just before the config server metadata commit is scheduled.
+ bool _readsShouldWaitOnCritSec{false};
+};
+
+} // namespace mongo