summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthew Russotto <matthew.russotto@10gen.com>2017-03-06 17:51:46 -0500
committerMatthew Russotto <matthew.russotto@10gen.com>2017-03-06 17:51:46 -0500
commita271833d0edd7ca4aac67f3e7be55e102c631a93 (patch)
tree0a778dc3fd99a4df25505dbf49c724afcd4dff81
parent3e5314c3f2be49666ca5d7aa766c934ba7d6cbe9 (diff)
downloadmongo-a271833d0edd7ca4aac67f3e7be55e102c631a93.tar.gz
SERVER-27914 Verify canAcceptWritesForDatabase() is called while the caller holds the global lock
This reverts commit 3e5314c3f2be49666ca5d7aa766c934ba7d6cbe9.
-rw-r--r--src/mongo/db/catalog/apply_ops.cpp2
-rw-r--r--src/mongo/db/catalog/capped_utils.cpp4
-rw-r--r--src/mongo/db/catalog/coll_mod.cpp2
-rw-r--r--src/mongo/db/catalog/create_collection.cpp2
-rw-r--r--src/mongo/db/catalog/drop_collection.cpp2
-rw-r--r--src/mongo/db/catalog/drop_database.cpp2
-rw-r--r--src/mongo/db/catalog/drop_indexes.cpp2
-rw-r--r--src/mongo/db/catalog/index_catalog.cpp2
-rw-r--r--src/mongo/db/catalog/rename_collection.cpp2
-rw-r--r--src/mongo/db/cloner.cpp31
-rw-r--r--src/mongo/db/commands/collection_to_capped.cpp2
-rw-r--r--src/mongo/db/commands/create_indexes.cpp8
-rw-r--r--src/mongo/db/commands/dbcommands.cpp4
-rw-r--r--src/mongo/db/commands/explain_cmd.cpp2
-rw-r--r--src/mongo/db/commands/feature_compatibility_version.cpp2
-rw-r--r--src/mongo/db/commands/find_and_modify.cpp10
-rw-r--r--src/mongo/db/commands/mr.cpp10
-rw-r--r--src/mongo/db/dbhelpers.cpp2
-rw-r--r--src/mongo/db/exec/delete.cpp2
-rw-r--r--src/mongo/db/exec/update.cpp2
-rw-r--r--src/mongo/db/index/index_access_method.cpp2
-rw-r--r--src/mongo/db/ops/update.cpp2
-rw-r--r--src/mongo/db/ops/write_ops_exec.cpp7
-rw-r--r--src/mongo/db/query/find.cpp5
-rw-r--r--src/mongo/db/query/get_executor.cpp4
-rw-r--r--src/mongo/db/read_concern.cpp2
-rw-r--r--src/mongo/db/repl/noop_writer.cpp2
-rw-r--r--src/mongo/db/repl/oplog.cpp4
-rw-r--r--src/mongo/db/repl/replication_coordinator.h29
-rw-r--r--src/mongo/db/repl/replication_coordinator_impl.cpp35
-rw-r--r--src/mongo/db/repl/replication_coordinator_impl.h11
-rw-r--r--src/mongo/db/repl/replication_coordinator_impl_elect_v1_test.cpp27
-rw-r--r--src/mongo/db/repl/replication_coordinator_mock.cpp29
-rw-r--r--src/mongo/db/repl/replication_coordinator_mock.h13
-rw-r--r--src/mongo/db/s/collection_range_deleter.cpp2
-rw-r--r--src/mongo/db/s/collection_sharding_state.cpp2
-rw-r--r--src/mongo/db/s/metadata_loader.cpp4
-rw-r--r--src/mongo/db/s/migration_destination_manager.cpp4
-rw-r--r--src/mongo/db/s/set_shard_version_command.cpp15
-rw-r--r--src/mongo/db/ttl.cpp2
-rw-r--r--src/mongo/db/views/view_sharding_check.cpp2
41 files changed, 196 insertions, 102 deletions
diff --git a/src/mongo/db/catalog/apply_ops.cpp b/src/mongo/db/catalog/apply_ops.cpp
index 7ddff58db32..12729f3fa31 100644
--- a/src/mongo/db/catalog/apply_ops.cpp
+++ b/src/mongo/db/catalog/apply_ops.cpp
@@ -313,7 +313,7 @@ Status applyOps(OperationContext* txn,
Lock::GlobalWrite globalWriteLock(txn->lockState());
bool userInitiatedWritesAndNotPrimary = txn->writesAreReplicated() &&
- !repl::getGlobalReplicationCoordinator()->canAcceptWritesForDatabase(dbName);
+ !repl::getGlobalReplicationCoordinator()->canAcceptWritesForDatabase(txn, dbName);
if (userInitiatedWritesAndNotPrimary)
return Status(ErrorCodes::NotMaster,
diff --git a/src/mongo/db/catalog/capped_utils.cpp b/src/mongo/db/catalog/capped_utils.cpp
index 71f74628f01..d6b11fe50dc 100644
--- a/src/mongo/db/catalog/capped_utils.cpp
+++ b/src/mongo/db/catalog/capped_utils.cpp
@@ -57,7 +57,7 @@ Status emptyCapped(OperationContext* txn, const NamespaceString& collectionName)
AutoGetDb autoDb(txn, collectionName.db(), MODE_X);
bool userInitiatedWritesAndNotPrimary = txn->writesAreReplicated() &&
- !repl::getGlobalReplicationCoordinator()->canAcceptWritesFor(collectionName);
+ !repl::getGlobalReplicationCoordinator()->canAcceptWritesFor(txn, collectionName);
if (userInitiatedWritesAndNotPrimary) {
return Status(ErrorCodes::NotMaster,
@@ -244,7 +244,7 @@ Status convertToCapped(OperationContext* txn, const NamespaceString& collectionN
AutoGetDb autoDb(txn, collectionName.db(), MODE_X);
bool userInitiatedWritesAndNotPrimary = txn->writesAreReplicated() &&
- !repl::getGlobalReplicationCoordinator()->canAcceptWritesFor(collectionName);
+ !repl::getGlobalReplicationCoordinator()->canAcceptWritesFor(txn, collectionName);
if (userInitiatedWritesAndNotPrimary) {
return Status(ErrorCodes::NotMaster,
diff --git a/src/mongo/db/catalog/coll_mod.cpp b/src/mongo/db/catalog/coll_mod.cpp
index 1cdcdc373dc..61f2abc1e3f 100644
--- a/src/mongo/db/catalog/coll_mod.cpp
+++ b/src/mongo/db/catalog/coll_mod.cpp
@@ -246,7 +246,7 @@ Status collMod(OperationContext* txn,
OldClientContext ctx(txn, nss.ns());
bool userInitiatedWritesAndNotPrimary = txn->writesAreReplicated() &&
- !repl::getGlobalReplicationCoordinator()->canAcceptWritesFor(nss);
+ !repl::getGlobalReplicationCoordinator()->canAcceptWritesFor(txn, nss);
if (userInitiatedWritesAndNotPrimary) {
return Status(ErrorCodes::NotMaster,
diff --git a/src/mongo/db/catalog/create_collection.cpp b/src/mongo/db/catalog/create_collection.cpp
index 227481c4104..abb1e1d8c16 100644
--- a/src/mongo/db/catalog/create_collection.cpp
+++ b/src/mongo/db/catalog/create_collection.cpp
@@ -77,7 +77,7 @@ Status createCollection(OperationContext* txn,
Lock::DBLock dbXLock(txn->lockState(), dbName, MODE_X);
OldClientContext ctx(txn, nss.ns());
if (txn->writesAreReplicated() &&
- !repl::getGlobalReplicationCoordinator()->canAcceptWritesFor(nss)) {
+ !repl::getGlobalReplicationCoordinator()->canAcceptWritesFor(txn, nss)) {
return Status(ErrorCodes::NotMaster,
str::stream() << "Not primary while creating collection " << nss.ns());
}
diff --git a/src/mongo/db/catalog/drop_collection.cpp b/src/mongo/db/catalog/drop_collection.cpp
index e2fc90f8273..ae5d0fed3d7 100644
--- a/src/mongo/db/catalog/drop_collection.cpp
+++ b/src/mongo/db/catalog/drop_collection.cpp
@@ -74,7 +74,7 @@ Status dropCollection(OperationContext* txn,
OldClientContext context(txn, collectionName.ns(), shardVersionCheck);
bool userInitiatedWritesAndNotPrimary = txn->writesAreReplicated() &&
- !repl::getGlobalReplicationCoordinator()->canAcceptWritesFor(collectionName);
+ !repl::getGlobalReplicationCoordinator()->canAcceptWritesFor(txn, collectionName);
if (userInitiatedWritesAndNotPrimary) {
return Status(ErrorCodes::NotMaster,
diff --git a/src/mongo/db/catalog/drop_database.cpp b/src/mongo/db/catalog/drop_database.cpp
index c0698f10821..e1a4ce63e33 100644
--- a/src/mongo/db/catalog/drop_database.cpp
+++ b/src/mongo/db/catalog/drop_database.cpp
@@ -71,7 +71,7 @@ Status dropDatabase(OperationContext* txn, const std::string& dbName) {
}
bool userInitiatedWritesAndNotPrimary = txn->writesAreReplicated() &&
- !repl::getGlobalReplicationCoordinator()->canAcceptWritesForDatabase(dbName);
+ !repl::getGlobalReplicationCoordinator()->canAcceptWritesForDatabase(txn, dbName);
if (userInitiatedWritesAndNotPrimary) {
return Status(ErrorCodes::NotMaster,
diff --git a/src/mongo/db/catalog/drop_indexes.cpp b/src/mongo/db/catalog/drop_indexes.cpp
index a0bb7a22e0d..78739b6e4da 100644
--- a/src/mongo/db/catalog/drop_indexes.cpp
+++ b/src/mongo/db/catalog/drop_indexes.cpp
@@ -152,7 +152,7 @@ Status dropIndexes(OperationContext* txn,
AutoGetDb autoDb(txn, dbName, MODE_X);
bool userInitiatedWritesAndNotPrimary = txn->writesAreReplicated() &&
- !repl::getGlobalReplicationCoordinator()->canAcceptWritesFor(nss);
+ !repl::getGlobalReplicationCoordinator()->canAcceptWritesFor(txn, nss);
if (userInitiatedWritesAndNotPrimary) {
return {ErrorCodes::NotMaster,
diff --git a/src/mongo/db/catalog/index_catalog.cpp b/src/mongo/db/catalog/index_catalog.cpp
index ffbfea515fd..a34baf61c28 100644
--- a/src/mongo/db/catalog/index_catalog.cpp
+++ b/src/mongo/db/catalog/index_catalog.cpp
@@ -1369,7 +1369,7 @@ void IndexCatalog::prepareInsertDeleteOptions(OperationContext* txn,
const IndexDescriptor* desc,
InsertDeleteOptions* options) {
auto replCoord = repl::ReplicationCoordinator::get(txn);
- if (replCoord->shouldRelaxIndexConstraints(NamespaceString(desc->parentNS()))) {
+ if (replCoord->shouldRelaxIndexConstraints(txn, NamespaceString(desc->parentNS()))) {
options->getKeysMode = IndexAccessMethod::GetKeysMode::kRelaxConstraints;
} else {
options->getKeysMode = IndexAccessMethod::GetKeysMode::kEnforceConstraints;
diff --git a/src/mongo/db/catalog/rename_collection.cpp b/src/mongo/db/catalog/rename_collection.cpp
index 6ec4e9348e4..fd8b6819df6 100644
--- a/src/mongo/db/catalog/rename_collection.cpp
+++ b/src/mongo/db/catalog/rename_collection.cpp
@@ -74,7 +74,7 @@ Status renameCollection(OperationContext* txn,
OldClientContext ctx(txn, source.ns());
bool userInitiatedWritesAndNotPrimary = txn->writesAreReplicated() &&
- !repl::getGlobalReplicationCoordinator()->canAcceptWritesFor(source);
+ !repl::getGlobalReplicationCoordinator()->canAcceptWritesFor(txn, source);
if (userInitiatedWritesAndNotPrimary) {
return Status(ErrorCodes::NotMaster,
diff --git a/src/mongo/db/cloner.cpp b/src/mongo/db/cloner.cpp
index 7ea8669ec4f..6aa2f1cdb33 100644
--- a/src/mongo/db/cloner.cpp
+++ b/src/mongo/db/cloner.cpp
@@ -145,12 +145,13 @@ struct Cloner::Fun {
// XXX: can probably take dblock instead
unique_ptr<ScopedTransaction> scopedXact(new ScopedTransaction(txn, MODE_X));
unique_ptr<Lock::GlobalWrite> globalWriteLock(new Lock::GlobalWrite(txn->lockState()));
- uassert(ErrorCodes::NotMaster,
- str::stream() << "Not primary while cloning collection " << from_collection.ns()
- << " to "
- << to_collection.ns(),
- !txn->writesAreReplicated() ||
- repl::getGlobalReplicationCoordinator()->canAcceptWritesFor(to_collection));
+ uassert(
+ ErrorCodes::NotMaster,
+ str::stream() << "Not primary while cloning collection " << from_collection.ns()
+ << " to "
+ << to_collection.ns(),
+ !txn->writesAreReplicated() ||
+ repl::getGlobalReplicationCoordinator()->canAcceptWritesFor(txn, to_collection));
// Make sure database still exists after we resume from the temp release
Database* db = dbHolder().openDb(txn, _dbName);
@@ -204,11 +205,11 @@ struct Cloner::Fun {
// Check if everything is still all right.
if (txn->writesAreReplicated()) {
- uassert(
- 28592,
- str::stream() << "Cannot write to ns: " << to_collection.ns()
- << " after yielding",
- repl::getGlobalReplicationCoordinator()->canAcceptWritesFor(to_collection));
+ uassert(28592,
+ str::stream() << "Cannot write to ns: " << to_collection.ns()
+ << " after yielding",
+ repl::getGlobalReplicationCoordinator()->canAcceptWritesFor(
+ txn, to_collection));
}
// TODO: SERVER-16598 abort if original db or collection is gone.
@@ -349,7 +350,7 @@ void Cloner::copy(OperationContext* txn,
<< " with filter "
<< query.toString(),
!txn->writesAreReplicated() ||
- repl::getGlobalReplicationCoordinator()->canAcceptWritesFor(to_collection));
+ repl::getGlobalReplicationCoordinator()->canAcceptWritesFor(txn, to_collection));
}
void Cloner::copyIndexes(OperationContext* txn,
@@ -372,7 +373,7 @@ void Cloner::copyIndexes(OperationContext* txn,
<< to_collection.ns()
<< " (Cloner)",
!txn->writesAreReplicated() ||
- repl::getGlobalReplicationCoordinator()->canAcceptWritesFor(to_collection));
+ repl::getGlobalReplicationCoordinator()->canAcceptWritesFor(txn, to_collection));
if (indexesToBuild.empty())
@@ -479,7 +480,7 @@ bool Cloner::copyCollection(OperationContext* txn,
uassert(ErrorCodes::PrimarySteppedDown,
str::stream() << "Not primary while copying collection " << ns << " (Cloner)",
!txn->writesAreReplicated() ||
- repl::getGlobalReplicationCoordinator()->canAcceptWritesFor(nss));
+ repl::getGlobalReplicationCoordinator()->canAcceptWritesFor(txn, nss));
Database* db = dbHolder().openDb(txn, dbname);
@@ -704,7 +705,7 @@ Status Cloner::copyDb(OperationContext* txn,
str::stream() << "Not primary while cloning database " << opts.fromDB
<< " (after getting list of collections to clone)",
!txn->writesAreReplicated() ||
- repl::getGlobalReplicationCoordinator()->canAcceptWritesForDatabase(toDBName));
+ repl::getGlobalReplicationCoordinator()->canAcceptWritesForDatabase(txn, toDBName));
if (opts.syncData) {
if (opts.createCollections) {
diff --git a/src/mongo/db/commands/collection_to_capped.cpp b/src/mongo/db/commands/collection_to_capped.cpp
index fda2e9b687e..373147da069 100644
--- a/src/mongo/db/commands/collection_to_capped.cpp
+++ b/src/mongo/db/commands/collection_to_capped.cpp
@@ -122,7 +122,7 @@ public:
AutoGetDb autoDb(txn, dbname, MODE_X);
NamespaceString nss(dbname, to);
- if (!repl::getGlobalReplicationCoordinator()->canAcceptWritesFor(nss)) {
+ if (!repl::getGlobalReplicationCoordinator()->canAcceptWritesFor(txn, nss)) {
return appendCommandStatus(
result,
Status(ErrorCodes::NotMaster,
diff --git a/src/mongo/db/commands/create_indexes.cpp b/src/mongo/db/commands/create_indexes.cpp
index 4a1707b9124..681370348ce 100644
--- a/src/mongo/db/commands/create_indexes.cpp
+++ b/src/mongo/db/commands/create_indexes.cpp
@@ -248,7 +248,7 @@ public:
// Note: createIndexes command does not currently respect shard versioning.
ScopedTransaction transaction(txn, MODE_IX);
Lock::DBLock dbLock(txn->lockState(), ns.db(), MODE_X);
- if (!repl::getGlobalReplicationCoordinator()->canAcceptWritesFor(ns)) {
+ if (!repl::getGlobalReplicationCoordinator()->canAcceptWritesFor(txn, ns)) {
return appendCommandStatus(
result,
Status(ErrorCodes::NotMaster,
@@ -334,7 +334,7 @@ public:
if (indexer.getBuildInBackground()) {
txn->recoveryUnit()->abandonSnapshot();
dbLock.relockWithMode(MODE_IX);
- if (!repl::getGlobalReplicationCoordinator()->canAcceptWritesFor(ns)) {
+ if (!repl::getGlobalReplicationCoordinator()->canAcceptWritesFor(txn, ns)) {
return appendCommandStatus(
result,
Status(ErrorCodes::NotMaster,
@@ -356,7 +356,7 @@ public:
// that day, to avoid data corruption due to lack of index cleanup.
txn->recoveryUnit()->abandonSnapshot();
dbLock.relockWithMode(MODE_X);
- if (!repl::getGlobalReplicationCoordinator()->canAcceptWritesFor(ns)) {
+ if (!repl::getGlobalReplicationCoordinator()->canAcceptWritesFor(txn, ns)) {
return appendCommandStatus(
result,
Status(ErrorCodes::NotMaster,
@@ -378,7 +378,7 @@ public:
dbLock.relockWithMode(MODE_X);
uassert(ErrorCodes::NotMaster,
str::stream() << "Not primary while completing index build in " << dbname,
- repl::getGlobalReplicationCoordinator()->canAcceptWritesFor(ns));
+ repl::getGlobalReplicationCoordinator()->canAcceptWritesFor(txn, ns));
Database* db = dbHolder().get(txn, ns.db());
uassert(28551, "database dropped during index build", db);
diff --git a/src/mongo/db/commands/dbcommands.cpp b/src/mongo/db/commands/dbcommands.cpp
index 8c72e2050ae..9ba85e79f9f 100644
--- a/src/mongo/db/commands/dbcommands.cpp
+++ b/src/mongo/db/commands/dbcommands.cpp
@@ -1535,7 +1535,7 @@ void mongo::execCommandDatabase(OperationContext* txn,
repl::ReplicationCoordinator* replCoord =
repl::ReplicationCoordinator::get(txn->getClient()->getServiceContext());
- const bool iAmPrimary = replCoord->canAcceptWritesForDatabase(dbname);
+ const bool iAmPrimary = replCoord->canAcceptWritesForDatabase_UNSAFE(txn, dbname);
{
bool commandCanRunOnSecondary = command->slaveOk();
@@ -1556,7 +1556,7 @@ void mongo::execCommandDatabase(OperationContext* txn,
if (!command->maintenanceOk() &&
replCoord->getReplicationMode() == repl::ReplicationCoordinator::modeReplSet &&
- !replCoord->canAcceptWritesForDatabase(dbname) &&
+ !replCoord->canAcceptWritesForDatabase_UNSAFE(txn, dbname) &&
!replCoord->getMemberState().secondary()) {
uassert(ErrorCodes::NotMasterOrSecondary,
diff --git a/src/mongo/db/commands/explain_cmd.cpp b/src/mongo/db/commands/explain_cmd.cpp
index 1a53140e965..678fd7effa2 100644
--- a/src/mongo/db/commands/explain_cmd.cpp
+++ b/src/mongo/db/commands/explain_cmd.cpp
@@ -135,7 +135,7 @@ public:
// copied from Command::execCommand and should be abstracted. Until then, make
// sure to keep it up to date.
repl::ReplicationCoordinator* replCoord = repl::getGlobalReplicationCoordinator();
- bool iAmPrimary = replCoord->canAcceptWritesForDatabase(dbname);
+ bool iAmPrimary = replCoord->canAcceptWritesForDatabase_UNSAFE(txn, dbname);
bool commandCanRunOnSecondary = commToExplain->slaveOk();
bool commandIsOverriddenToRunOnSecondary = commToExplain->slaveOverrideOk() &&
diff --git a/src/mongo/db/commands/feature_compatibility_version.cpp b/src/mongo/db/commands/feature_compatibility_version.cpp
index 448e134de22..29d3a96513e 100644
--- a/src/mongo/db/commands/feature_compatibility_version.cpp
+++ b/src/mongo/db/commands/feature_compatibility_version.cpp
@@ -219,7 +219,7 @@ void FeatureCompatibilityVersion::set(OperationContext* txn, StringData version)
<< "'. Not primary while attempting to create index on: "
<< nss.ns(),
repl::ReplicationCoordinator::get(txn->getServiceContext())
- ->canAcceptWritesFor(nss));
+ ->canAcceptWritesFor(txn, nss));
IndexBuilder builder(k32IncompatibleIndexSpec, false);
auto status = builder.buildInForeground(txn, autoDB.getDb());
diff --git a/src/mongo/db/commands/find_and_modify.cpp b/src/mongo/db/commands/find_and_modify.cpp
index 79ee34203ce..d0a260164d4 100644
--- a/src/mongo/db/commands/find_and_modify.cpp
+++ b/src/mongo/db/commands/find_and_modify.cpp
@@ -191,8 +191,8 @@ void appendCommandResponse(PlanExecutor* exec,
}
}
-Status checkCanAcceptWritesForDatabase(const NamespaceString& nsString) {
- if (!repl::getGlobalReplicationCoordinator()->canAcceptWritesFor(nsString)) {
+Status checkCanAcceptWritesForDatabase(OperationContext* txn, const NamespaceString& nsString) {
+ if (!repl::getGlobalReplicationCoordinator()->canAcceptWritesFor(txn, nsString)) {
return Status(ErrorCodes::NotMaster,
str::stream()
<< "Not primary while running findAndModify command on collection "
@@ -407,7 +407,7 @@ public:
auto css = CollectionShardingState::get(txn, nsString);
css->checkShardVersionOrThrow(txn);
- Status isPrimary = checkCanAcceptWritesForDatabase(nsString);
+ Status isPrimary = checkCanAcceptWritesForDatabase(txn, nsString);
if (!isPrimary.isOK()) {
return appendCommandStatus(result, isPrimary);
}
@@ -484,7 +484,7 @@ public:
auto css = CollectionShardingState::get(txn, nsString);
css->checkShardVersionOrThrow(txn);
- Status isPrimary = checkCanAcceptWritesForDatabase(nsString);
+ Status isPrimary = checkCanAcceptWritesForDatabase(txn, nsString);
if (!isPrimary.isOK()) {
return appendCommandStatus(result, isPrimary);
}
@@ -503,7 +503,7 @@ public:
// in exclusive mode in order to create the collection.
collLock.relockAsDatabaseExclusive(autoDb.lock());
collection = autoDb.getDb()->getCollection(nsString.ns());
- Status isPrimaryAfterRelock = checkCanAcceptWritesForDatabase(nsString);
+ Status isPrimaryAfterRelock = checkCanAcceptWritesForDatabase(txn, nsString);
if (!isPrimaryAfterRelock.isOK()) {
return appendCommandStatus(result, isPrimaryAfterRelock);
}
diff --git a/src/mongo/db/commands/mr.cpp b/src/mongo/db/commands/mr.cpp
index 19a0a6eeabf..781c0d1d5af 100644
--- a/src/mongo/db/commands/mr.cpp
+++ b/src/mongo/db/commands/mr.cpp
@@ -379,7 +379,7 @@ void State::dropTempCollections() {
uassert(ErrorCodes::PrimarySteppedDown,
"no longer primary",
repl::getGlobalReplicationCoordinator()->canAcceptWritesFor(
- _config.tempNamespace));
+ _txn, _config.tempNamespace));
db->dropCollection(_txn, _config.tempNamespace.ns());
wunit.commit();
}
@@ -499,7 +499,8 @@ void State::prepTempCollection() {
WriteUnitOfWork wuow(_txn);
uassert(ErrorCodes::PrimarySteppedDown,
"no longer primary",
- repl::getGlobalReplicationCoordinator()->canAcceptWritesFor(_config.tempNamespace));
+ repl::getGlobalReplicationCoordinator()->canAcceptWritesFor(_txn,
+ _config.tempNamespace));
Collection* tempColl = tempCtx.getCollection();
invariant(!tempColl);
@@ -750,7 +751,7 @@ void State::insert(const NamespaceString& nss, const BSONObj& o) {
WriteUnitOfWork wuow(_txn);
uassert(ErrorCodes::PrimarySteppedDown,
"no longer primary",
- repl::getGlobalReplicationCoordinator()->canAcceptWritesFor(nss));
+ repl::getGlobalReplicationCoordinator()->canAcceptWritesFor(_txn, nss));
Collection* coll = getCollectionOrUassert(ctx.db(), nss);
BSONObjBuilder b;
@@ -1443,7 +1444,8 @@ public:
if (state.isOnDisk()) {
// this means that it will be doing a write operation, make sure we are on Master
// ideally this check should be in slaveOk(), but at that point config is not known
- if (!repl::getGlobalReplicationCoordinator()->canAcceptWritesFor(config.nss)) {
+ if (!repl::getGlobalReplicationCoordinator()->canAcceptWritesFor_UNSAFE(txn,
+ config.nss)) {
errmsg = "not master";
return false;
}
diff --git a/src/mongo/db/dbhelpers.cpp b/src/mongo/db/dbhelpers.cpp
index a030d2b579f..2dd6c2c7d1c 100644
--- a/src/mongo/db/dbhelpers.cpp
+++ b/src/mongo/db/dbhelpers.cpp
@@ -437,7 +437,7 @@ long long Helpers::removeRange(OperationContext* txn,
}
}
- if (!repl::getGlobalReplicationCoordinator()->canAcceptWritesFor(nss)) {
+ if (!repl::getGlobalReplicationCoordinator()->canAcceptWritesFor(txn, nss)) {
warning() << "stepped down from primary while deleting chunk; "
<< "orphaning data in " << nss.ns() << " in range [" << redact(min)
<< ", " << redact(max) << ")";
diff --git a/src/mongo/db/exec/delete.cpp b/src/mongo/db/exec/delete.cpp
index 0f3e09314e7..884e5f01538 100644
--- a/src/mongo/db/exec/delete.cpp
+++ b/src/mongo/db/exec/delete.cpp
@@ -269,7 +269,7 @@ void DeleteStage::doRestoreState() {
uassert(28537,
str::stream() << "Demoted from primary while removing from " << ns.ns(),
!getOpCtx()->writesAreReplicated() ||
- repl::getGlobalReplicationCoordinator()->canAcceptWritesFor(ns));
+ repl::getGlobalReplicationCoordinator()->canAcceptWritesFor(getOpCtx(), ns));
}
unique_ptr<PlanStageStats> DeleteStage::getStats() {
diff --git a/src/mongo/db/exec/update.cpp b/src/mongo/db/exec/update.cpp
index b5dbe6eff99..a1b43a2e21d 100644
--- a/src/mongo/db/exec/update.cpp
+++ b/src/mongo/db/exec/update.cpp
@@ -1003,7 +1003,7 @@ Status UpdateStage::restoreUpdateState() {
// We may have stepped down during the yield.
bool userInitiatedWritesAndNotPrimary = getOpCtx()->writesAreReplicated() &&
- !repl::getGlobalReplicationCoordinator()->canAcceptWritesFor(nsString);
+ !repl::getGlobalReplicationCoordinator()->canAcceptWritesFor(getOpCtx(), nsString);
if (userInitiatedWritesAndNotPrimary) {
return Status(ErrorCodes::PrimarySteppedDown,
diff --git a/src/mongo/db/index/index_access_method.cpp b/src/mongo/db/index/index_access_method.cpp
index df4071f6fe4..c787d1429dc 100644
--- a/src/mongo/db/index/index_access_method.cpp
+++ b/src/mongo/db/index/index_access_method.cpp
@@ -116,7 +116,7 @@ bool IndexAccessMethod::ignoreKeyTooLong(OperationContext* txn) {
// Ignore this error if we cannot write to the collection or if the user requested it
const auto shouldRelaxConstraints =
repl::ReplicationCoordinator::get(txn)->shouldRelaxIndexConstraints(
- NamespaceString(_btreeState->ns()));
+ txn, NamespaceString(_btreeState->ns()));
return shouldRelaxConstraints || !failIndexKeyTooLong.load();
}
diff --git a/src/mongo/db/ops/update.cpp b/src/mongo/db/ops/update.cpp
index 5e0763f9eac..54e66be6133 100644
--- a/src/mongo/db/ops/update.cpp
+++ b/src/mongo/db/ops/update.cpp
@@ -91,7 +91,7 @@ UpdateResult update(OperationContext* txn, Database* db, const UpdateRequest& re
Lock::DBLock lk(txn->lockState(), nsString.db(), MODE_X);
const bool userInitiatedWritesAndNotPrimary = txn->writesAreReplicated() &&
- !repl::getGlobalReplicationCoordinator()->canAcceptWritesFor(nsString);
+ !repl::getGlobalReplicationCoordinator()->canAcceptWritesFor(txn, nsString);
if (userInitiatedWritesAndNotPrimary) {
uassertStatusOK(Status(ErrorCodes::PrimarySteppedDown,
diff --git a/src/mongo/db/ops/write_ops_exec.cpp b/src/mongo/db/ops/write_ops_exec.cpp
index 98f32c928ac..f3f183a60fe 100644
--- a/src/mongo/db/ops/write_ops_exec.cpp
+++ b/src/mongo/db/ops/write_ops_exec.cpp
@@ -171,9 +171,10 @@ private:
};
void assertCanWrite_inlock(OperationContext* txn, const NamespaceString& ns) {
- uassert(ErrorCodes::PrimarySteppedDown,
- str::stream() << "Not primary while writing to " << ns.ns(),
- repl::ReplicationCoordinator::get(txn->getServiceContext())->canAcceptWritesFor(ns));
+ uassert(
+ ErrorCodes::PrimarySteppedDown,
+ str::stream() << "Not primary while writing to " << ns.ns(),
+ repl::ReplicationCoordinator::get(txn->getServiceContext())->canAcceptWritesFor(txn, ns));
CollectionShardingState::get(txn, ns)->checkShardVersionOrThrow(txn);
}
diff --git a/src/mongo/db/query/find.cpp b/src/mongo/db/query/find.cpp
index d3f7e80e2e7..9fcaa7cef02 100644
--- a/src/mongo/db/query/find.cpp
+++ b/src/mongo/db/query/find.cpp
@@ -289,7 +289,8 @@ Message getMore(OperationContext* txn,
// passing in a query object (necessary to check SlaveOK query option), the only state where
// reads are allowed is PRIMARY (or master in master/slave). This function uasserts if
// reads are not okay.
- Status status = repl::getGlobalReplicationCoordinator()->checkCanServeReadsFor(txn, nss, true);
+ Status status =
+ repl::getGlobalReplicationCoordinator()->checkCanServeReadsFor_UNSAFE(txn, nss, true);
uassertStatusOK(status);
// A pin performs a CC lookup and if there is a CC, increments the CC's pin value so it
@@ -583,7 +584,7 @@ std::string runQuery(OperationContext* txn,
// uassert if we are not on a primary, and not a secondary with SlaveOk query parameter set.
bool slaveOK = qr.isSlaveOk() || qr.hasReadPref();
Status serveReadsStatus =
- repl::getGlobalReplicationCoordinator()->checkCanServeReadsFor(txn, nss, slaveOK);
+ repl::getGlobalReplicationCoordinator()->checkCanServeReadsFor_UNSAFE(txn, nss, slaveOK);
uassertStatusOK(serveReadsStatus);
// Run the query.
diff --git a/src/mongo/db/query/get_executor.cpp b/src/mongo/db/query/get_executor.cpp
index 7a0c642cd49..eea6597cdce 100644
--- a/src/mongo/db/query/get_executor.cpp
+++ b/src/mongo/db/query/get_executor.cpp
@@ -706,7 +706,7 @@ StatusWith<unique_ptr<PlanExecutor>> getExecutorDelete(OperationContext* txn,
}
bool userInitiatedWritesAndNotPrimary = txn->writesAreReplicated() &&
- !repl::getGlobalReplicationCoordinator()->canAcceptWritesFor(nss);
+ !repl::getGlobalReplicationCoordinator()->canAcceptWritesFor(txn, nss);
if (userInitiatedWritesAndNotPrimary) {
return Status(ErrorCodes::PrimarySteppedDown,
@@ -872,7 +872,7 @@ StatusWith<unique_ptr<PlanExecutor>> getExecutorUpdate(OperationContext* txn,
// writes on a secondary. If this is an update to a secondary from the replication system,
// however, then we make an exception and let the write proceed.
bool userInitiatedWritesAndNotPrimary = txn->writesAreReplicated() &&
- !repl::getGlobalReplicationCoordinator()->canAcceptWritesFor(nsString);
+ !repl::getGlobalReplicationCoordinator()->canAcceptWritesFor(txn, nsString);
if (userInitiatedWritesAndNotPrimary) {
return Status(ErrorCodes::PrimarySteppedDown,
diff --git a/src/mongo/db/read_concern.cpp b/src/mongo/db/read_concern.cpp
index cc404cdbf82..f88d4ff2339 100644
--- a/src/mongo/db/read_concern.cpp
+++ b/src/mongo/db/read_concern.cpp
@@ -158,7 +158,7 @@ Status waitForLinearizableReadConcern(OperationContext* txn) {
Lock::DBLock lk(txn->lockState(), "local", MODE_IX);
Lock::CollectionLock lock(txn->lockState(), "local.oplog.rs", MODE_IX);
- if (!replCoord->canAcceptWritesForDatabase("admin")) {
+ if (!replCoord->canAcceptWritesForDatabase(txn, "admin")) {
return {ErrorCodes::NotMaster,
"No longer primary when waiting for linearizable read concern"};
}
diff --git a/src/mongo/db/repl/noop_writer.cpp b/src/mongo/db/repl/noop_writer.cpp
index 4bbf50269b7..c12425fd423 100644
--- a/src/mongo/db/repl/noop_writer.cpp
+++ b/src/mongo/db/repl/noop_writer.cpp
@@ -148,7 +148,7 @@ void NoopWriter::_writeNoop(OperationContext* txn) {
auto replCoord = ReplicationCoordinator::get(txn);
// Its a proxy for being a primary
- if (!replCoord->canAcceptWritesForDatabase("admin")) {
+ if (!replCoord->canAcceptWritesForDatabase(txn, "admin")) {
LOG(1) << "Not a primary, skipping the noop write";
return;
}
diff --git a/src/mongo/db/repl/oplog.cpp b/src/mongo/db/repl/oplog.cpp
index 908febd4c76..e394df05efd 100644
--- a/src/mongo/db/repl/oplog.cpp
+++ b/src/mongo/db/repl/oplog.cpp
@@ -366,7 +366,7 @@ void _logOpsInner(OperationContext* txn,
ReplicationCoordinator* replCoord = getGlobalReplicationCoordinator();
if (nss.size() && replicationMode == ReplicationCoordinator::modeReplSet &&
- !replCoord->canAcceptWritesFor(nss)) {
+ !replCoord->canAcceptWritesFor(txn, nss)) {
severe() << "logOp() but can't accept write to collection " << nss.ns();
fassertFailed(17405);
}
@@ -768,7 +768,7 @@ Status applyOperation_inlock(OperationContext* txn,
}
bool relaxIndexConstraints =
- ReplicationCoordinator::get(txn)->shouldRelaxIndexConstraints(indexNss);
+ ReplicationCoordinator::get(txn)->shouldRelaxIndexConstraints(txn, indexNss);
if (indexSpec["background"].trueValue()) {
Lock::TempRelease release(txn->lockState());
if (txn->lockState()->isLocked()) {
diff --git a/src/mongo/db/repl/replication_coordinator.h b/src/mongo/db/repl/replication_coordinator.h
index 4f106021714..1d3dda6f5b6 100644
--- a/src/mongo/db/repl/replication_coordinator.h
+++ b/src/mongo/db/repl/replication_coordinator.h
@@ -245,7 +245,14 @@ public:
* NOTE: This function can only be meaningfully called while the caller holds the global
* lock in some mode other than MODE_NONE.
*/
- virtual bool canAcceptWritesForDatabase(StringData dbName) = 0;
+ virtual bool canAcceptWritesForDatabase(OperationContext* txn, StringData dbName) = 0;
+
+ /**
+ * Version which does not check for the global lock. Do not use in new code.
+ * Without the global lock held, the return value may be inaccurate by the time
+ * the function returns.
+ */
+ virtual bool canAcceptWritesForDatabase_UNSAFE(OperationContext* txn, StringData dbName) = 0;
/**
* Returns true if it is valid for this node to accept writes on the given namespace.
@@ -253,7 +260,14 @@ public:
* The result of this function should be consistent with canAcceptWritesForDatabase()
* for the database the namespace refers to, with additional checks on the collection.
*/
- virtual bool canAcceptWritesFor(const NamespaceString& ns) = 0;
+ virtual bool canAcceptWritesFor(OperationContext* txn, const NamespaceString& ns) = 0;
+
+ /**
+ * Version which does not check for the global lock. Do not use in new code.
+ * Without the global lock held, the return value may be inaccurate by the time
+ * the function returns.
+ */
+ virtual bool canAcceptWritesFor_UNSAFE(OperationContext* txn, const NamespaceString& ns) = 0;
/**
* Checks if the current replica set configuration can satisfy the given write concern.
@@ -275,12 +289,21 @@ public:
bool slaveOk) = 0;
/**
+ * Version which does not check for the global lock. Do not use in new code.
+ * Without the global lock held, the return value may be inaccurate by the time
+ * the function returns.
+ */
+ virtual Status checkCanServeReadsFor_UNSAFE(OperationContext* txn,
+ const NamespaceString& ns,
+ bool slaveOk) = 0;
+
+ /**
* Returns true if this node should ignore index constraints for idempotency reasons.
*
* The namespace "ns" is passed in because the "local" database is usually writable
* and we need to enforce the constraints for it.
*/
- virtual bool shouldRelaxIndexConstraints(const NamespaceString& ns) = 0;
+ virtual bool shouldRelaxIndexConstraints(OperationContext* txn, const NamespaceString& ns) = 0;
/**
* Updates our internal tracking of the last OpTime applied for the given slave
diff --git a/src/mongo/db/repl/replication_coordinator_impl.cpp b/src/mongo/db/repl/replication_coordinator_impl.cpp
index 6f6f5f6853f..8ad99d7e24a 100644
--- a/src/mongo/db/repl/replication_coordinator_impl.cpp
+++ b/src/mongo/db/repl/replication_coordinator_impl.cpp
@@ -1864,7 +1864,15 @@ bool ReplicationCoordinatorImpl::isMasterForReportingPurposes() {
return false;
}
-bool ReplicationCoordinatorImpl::canAcceptWritesForDatabase(StringData dbName) {
+bool ReplicationCoordinatorImpl::canAcceptWritesForDatabase(OperationContext* txn,
+ StringData dbName) {
+ // The answer isn't meaningful unless we hold the global lock.
+ invariant(txn->lockState()->isLocked());
+ return canAcceptWritesForDatabase_UNSAFE(txn, dbName);
+}
+
+bool ReplicationCoordinatorImpl::canAcceptWritesForDatabase_UNSAFE(OperationContext* txn,
+ StringData dbName) {
// _canAcceptNonLocalWrites is always true for standalone nodes, always false for nodes
// started with --slave, and adjusted based on primary+drain state in replica sets.
//
@@ -1881,17 +1889,31 @@ bool ReplicationCoordinatorImpl::canAcceptWritesForDatabase(StringData dbName) {
return !replAllDead && _settings.isMaster();
}
-bool ReplicationCoordinatorImpl::canAcceptWritesFor(const NamespaceString& ns) {
+bool ReplicationCoordinatorImpl::canAcceptWritesFor(OperationContext* txn,
+ const NamespaceString& ns) {
+ invariant(txn->lockState()->isLocked());
+ return canAcceptWritesFor_UNSAFE(txn, ns);
+}
+
+bool ReplicationCoordinatorImpl::canAcceptWritesFor_UNSAFE(OperationContext* txn,
+ const NamespaceString& ns) {
if (_memberState.rollback() && ns.isOplog()) {
return false;
}
StringData dbName = ns.db();
- return canAcceptWritesForDatabase(dbName);
+ return canAcceptWritesForDatabase_UNSAFE(txn, dbName);
}
Status ReplicationCoordinatorImpl::checkCanServeReadsFor(OperationContext* txn,
const NamespaceString& ns,
bool slaveOk) {
+ invariant(txn->lockState()->isLocked());
+ return checkCanServeReadsFor_UNSAFE(txn, ns, slaveOk);
+}
+
+Status ReplicationCoordinatorImpl::checkCanServeReadsFor_UNSAFE(OperationContext* txn,
+ const NamespaceString& ns,
+ bool slaveOk) {
auto client = txn->getClient();
// Oplog reads are not allowed during STARTUP state, but we make an exception for internal
// reads and master-slave replication. Internel reads are required for cleaning up unfinished
@@ -1906,7 +1928,7 @@ Status ReplicationCoordinatorImpl::checkCanServeReadsFor(OperationContext* txn,
if (client->isInDirectClient()) {
return Status::OK();
}
- if (canAcceptWritesFor(ns)) {
+ if (canAcceptWritesFor_UNSAFE(txn, ns)) {
return Status::OK();
}
if (_settings.isSlave() || _settings.isMaster()) {
@@ -1926,8 +1948,9 @@ bool ReplicationCoordinatorImpl::isInPrimaryOrSecondaryState() const {
return _canServeNonLocalReads.loadRelaxed();
}
-bool ReplicationCoordinatorImpl::shouldRelaxIndexConstraints(const NamespaceString& ns) {
- return !canAcceptWritesFor(ns);
+bool ReplicationCoordinatorImpl::shouldRelaxIndexConstraints(OperationContext* txn,
+ const NamespaceString& ns) {
+ return !canAcceptWritesFor(txn, ns);
}
OID ReplicationCoordinatorImpl::getElectionId() {
diff --git a/src/mongo/db/repl/replication_coordinator_impl.h b/src/mongo/db/repl/replication_coordinator_impl.h
index 915f74ed58a..5b2722eaab2 100644
--- a/src/mongo/db/repl/replication_coordinator_impl.h
+++ b/src/mongo/db/repl/replication_coordinator_impl.h
@@ -136,17 +136,22 @@ public:
virtual bool isMasterForReportingPurposes();
- virtual bool canAcceptWritesForDatabase(StringData dbName);
+ virtual bool canAcceptWritesForDatabase(OperationContext* txn, StringData dbName);
+ virtual bool canAcceptWritesForDatabase_UNSAFE(OperationContext* txn, StringData dbName);
- bool canAcceptWritesFor(const NamespaceString& ns) override;
+ bool canAcceptWritesFor(OperationContext* txn, const NamespaceString& ns) override;
+ bool canAcceptWritesFor_UNSAFE(OperationContext* txn, const NamespaceString& ns) override;
virtual Status checkIfWriteConcernCanBeSatisfied(const WriteConcernOptions& writeConcern) const;
virtual Status checkCanServeReadsFor(OperationContext* txn,
const NamespaceString& ns,
bool slaveOk);
+ virtual Status checkCanServeReadsFor_UNSAFE(OperationContext* txn,
+ const NamespaceString& ns,
+ bool slaveOk);
- virtual bool shouldRelaxIndexConstraints(const NamespaceString& ns);
+ virtual bool shouldRelaxIndexConstraints(OperationContext* txn, const NamespaceString& ns);
virtual Status setLastOptimeForSlave(const OID& rid, const Timestamp& ts);
diff --git a/src/mongo/db/repl/replication_coordinator_impl_elect_v1_test.cpp b/src/mongo/db/repl/replication_coordinator_impl_elect_v1_test.cpp
index e5fa8aa73d1..e3660682e3c 100644
--- a/src/mongo/db/repl/replication_coordinator_impl_elect_v1_test.cpp
+++ b/src/mongo/db/repl/replication_coordinator_impl_elect_v1_test.cpp
@@ -1431,7 +1431,8 @@ TEST_F(PrimaryCatchUpTest, PrimaryDoNotNeedToCatchUp) {
ASSERT_EQUALS(1, countLogLinesContaining("My optime is most up-to-date, skipping catch-up"));
auto txn = makeOperationContext();
getReplCoord()->signalDrainComplete(txn.get(), getReplCoord()->getTerm());
- ASSERT_TRUE(getReplCoord()->canAcceptWritesForDatabase("test"));
+ Lock::GlobalLock lock(txn->lockState(), MODE_IX, 1);
+ ASSERT_TRUE(getReplCoord()->canAcceptWritesForDatabase(txn.get(), "test"));
}
TEST_F(PrimaryCatchUpTest, PrimaryFreshnessScanTimeout) {
@@ -1454,7 +1455,8 @@ TEST_F(PrimaryCatchUpTest, PrimaryFreshnessScanTimeout) {
ASSERT_EQUALS(1, countLogLinesContaining("Could not access any nodes within timeout"));
auto txn = makeOperationContext();
getReplCoord()->signalDrainComplete(txn.get(), getReplCoord()->getTerm());
- ASSERT_TRUE(getReplCoord()->canAcceptWritesForDatabase("test"));
+ Lock::GlobalLock lock(txn->lockState(), MODE_IX, 1);
+ ASSERT_TRUE(getReplCoord()->canAcceptWritesForDatabase(txn.get(), "test"));
}
TEST_F(PrimaryCatchUpTest, PrimaryCatchUpSucceeds) {
@@ -1483,7 +1485,8 @@ TEST_F(PrimaryCatchUpTest, PrimaryCatchUpSucceeds) {
ASSERT_EQUALS(1, countLogLinesContaining("Finished catch-up oplog after becoming primary."));
auto txn = makeOperationContext();
getReplCoord()->signalDrainComplete(txn.get(), getReplCoord()->getTerm());
- ASSERT_TRUE(getReplCoord()->canAcceptWritesForDatabase("test"));
+ Lock::GlobalLock lock(txn->lockState(), MODE_IX, 1);
+ ASSERT_TRUE(getReplCoord()->canAcceptWritesForDatabase(txn.get(), "test"));
}
TEST_F(PrimaryCatchUpTest, PrimaryCatchUpTimeout) {
@@ -1506,7 +1509,8 @@ TEST_F(PrimaryCatchUpTest, PrimaryCatchUpTimeout) {
ASSERT_EQUALS(1, countLogLinesContaining("Cannot catch up oplog after becoming primary"));
auto txn = makeOperationContext();
getReplCoord()->signalDrainComplete(txn.get(), getReplCoord()->getTerm());
- ASSERT_TRUE(getReplCoord()->canAcceptWritesForDatabase("test"));
+ Lock::GlobalLock lock(txn->lockState(), MODE_IX, 1);
+ ASSERT_TRUE(getReplCoord()->canAcceptWritesForDatabase(txn.get(), "test"));
}
TEST_F(PrimaryCatchUpTest, PrimaryStepsDownDuringFreshnessScan) {
@@ -1532,7 +1536,9 @@ TEST_F(PrimaryCatchUpTest, PrimaryStepsDownDuringFreshnessScan) {
ASSERT(getReplCoord()->getApplierState() == ApplierState::Running);
stopCapturingLogMessages();
ASSERT_EQUALS(1, countLogLinesContaining("Stopped transition to primary"));
- ASSERT_FALSE(getReplCoord()->canAcceptWritesForDatabase("test"));
+ auto txn = makeOperationContext();
+ Lock::GlobalLock lock(txn->lockState(), MODE_IX, 1);
+ ASSERT_FALSE(getReplCoord()->canAcceptWritesForDatabase(txn.get(), "test"));
}
TEST_F(PrimaryCatchUpTest, PrimaryStepsDownDuringCatchUp) {
@@ -1565,7 +1571,8 @@ TEST_F(PrimaryCatchUpTest, PrimaryStepsDownDuringCatchUp) {
ASSERT(getReplCoord()->getApplierState() == ApplierState::Running);
stopCapturingLogMessages();
ASSERT_EQUALS(1, countLogLinesContaining("Cannot catch up oplog after becoming primary"));
- ASSERT_FALSE(getReplCoord()->canAcceptWritesForDatabase("test"));
+ Lock::GlobalLock lock(txn->lockState(), MODE_IX, 1);
+ ASSERT_FALSE(getReplCoord()->canAcceptWritesForDatabase(txn.get(), "test"));
}
TEST_F(PrimaryCatchUpTest, PrimaryStepsDownDuringDrainMode) {
@@ -1611,11 +1618,15 @@ TEST_F(PrimaryCatchUpTest, PrimaryStepsDownDuringDrainMode) {
getNet()->scheduleResponse(noi, getNet()->now(), makeFreshnessScanResponse(OpTime()));
});
ASSERT(replCoord->getApplierState() == ApplierState::Draining);
- ASSERT_FALSE(replCoord->canAcceptWritesForDatabase("test"));
auto txn = makeOperationContext();
+ {
+ Lock::GlobalLock lock(txn->lockState(), MODE_IX, 1);
+ ASSERT_FALSE(replCoord->canAcceptWritesForDatabase(txn.get(), "test"));
+ }
replCoord->signalDrainComplete(txn.get(), replCoord->getTerm());
+ Lock::GlobalLock lock(txn->lockState(), MODE_IX, 1);
ASSERT(replCoord->getApplierState() == ApplierState::Stopped);
- ASSERT_TRUE(replCoord->canAcceptWritesForDatabase("test"));
+ ASSERT_TRUE(replCoord->canAcceptWritesForDatabase(txn.get(), "test"));
}
} // namespace
diff --git a/src/mongo/db/repl/replication_coordinator_mock.cpp b/src/mongo/db/repl/replication_coordinator_mock.cpp
index 1720b18bb00..e72083ef012 100644
--- a/src/mongo/db/repl/replication_coordinator_mock.cpp
+++ b/src/mongo/db/repl/replication_coordinator_mock.cpp
@@ -120,7 +120,8 @@ bool ReplicationCoordinatorMock::isMasterForReportingPurposes() {
return true;
}
-bool ReplicationCoordinatorMock::canAcceptWritesForDatabase(StringData dbName) {
+bool ReplicationCoordinatorMock::canAcceptWritesForDatabase(OperationContext* txn,
+ StringData dbName) {
// Return true if we allow writes explicitly even when not in primary state, as in sharding
// unit tests, so that the op observers can fire but the tests don't have to set all the states
// as if it's in primary.
@@ -130,9 +131,20 @@ bool ReplicationCoordinatorMock::canAcceptWritesForDatabase(StringData dbName) {
return dbName == "local" || _memberState.primary() || _settings.isMaster();
}
-bool ReplicationCoordinatorMock::canAcceptWritesFor(const NamespaceString& ns) {
+bool ReplicationCoordinatorMock::canAcceptWritesForDatabase_UNSAFE(OperationContext* txn,
+ StringData dbName) {
+ return canAcceptWritesForDatabase(txn, dbName);
+}
+
+bool ReplicationCoordinatorMock::canAcceptWritesFor(OperationContext* txn,
+ const NamespaceString& ns) {
// TODO
- return canAcceptWritesForDatabase(ns.db());
+ return canAcceptWritesForDatabase(txn, ns.db());
+}
+
+bool ReplicationCoordinatorMock::canAcceptWritesFor_UNSAFE(OperationContext* txn,
+ const NamespaceString& ns) {
+ return canAcceptWritesFor(txn, ns);
}
Status ReplicationCoordinatorMock::checkCanServeReadsFor(OperationContext* txn,
@@ -142,8 +154,15 @@ Status ReplicationCoordinatorMock::checkCanServeReadsFor(OperationContext* txn,
return Status::OK();
}
-bool ReplicationCoordinatorMock::shouldRelaxIndexConstraints(const NamespaceString& ns) {
- return !canAcceptWritesFor(ns);
+Status ReplicationCoordinatorMock::checkCanServeReadsFor_UNSAFE(OperationContext* txn,
+ const NamespaceString& ns,
+ bool slaveOk) {
+ return checkCanServeReadsFor(txn, ns, slaveOk);
+}
+
+bool ReplicationCoordinatorMock::shouldRelaxIndexConstraints(OperationContext* txn,
+ const NamespaceString& ns) {
+ return !canAcceptWritesFor(txn, ns);
}
Status ReplicationCoordinatorMock::setLastOptimeForSlave(const OID& rid, const Timestamp& ts) {
diff --git a/src/mongo/db/repl/replication_coordinator_mock.h b/src/mongo/db/repl/replication_coordinator_mock.h
index 86478a7131d..4b3fd99d3ce 100644
--- a/src/mongo/db/repl/replication_coordinator_mock.h
+++ b/src/mongo/db/repl/replication_coordinator_mock.h
@@ -90,17 +90,24 @@ public:
virtual bool isMasterForReportingPurposes();
- virtual bool canAcceptWritesForDatabase(StringData dbName);
+ virtual bool canAcceptWritesForDatabase(OperationContext* txn, StringData dbName);
- bool canAcceptWritesFor(const NamespaceString& ns) override;
+ virtual bool canAcceptWritesForDatabase_UNSAFE(OperationContext* txn, StringData dbName);
+
+ bool canAcceptWritesFor(OperationContext* txn, const NamespaceString& ns) override;
+
+ bool canAcceptWritesFor_UNSAFE(OperationContext* txn, const NamespaceString& ns) override;
virtual Status checkIfWriteConcernCanBeSatisfied(const WriteConcernOptions& writeConcern) const;
virtual Status checkCanServeReadsFor(OperationContext* txn,
const NamespaceString& ns,
bool slaveOk);
+ virtual Status checkCanServeReadsFor_UNSAFE(OperationContext* txn,
+ const NamespaceString& ns,
+ bool slaveOk);
- virtual bool shouldRelaxIndexConstraints(const NamespaceString& ns);
+ virtual bool shouldRelaxIndexConstraints(OperationContext* txn, const NamespaceString& ns);
virtual Status setLastOptimeForSlave(const OID& rid, const Timestamp& ts);
diff --git a/src/mongo/db/s/collection_range_deleter.cpp b/src/mongo/db/s/collection_range_deleter.cpp
index 71d9382b006..30855a9b210 100644
--- a/src/mongo/db/s/collection_range_deleter.cpp
+++ b/src/mongo/db/s/collection_range_deleter.cpp
@@ -199,7 +199,7 @@ int CollectionRangeDeleter::_doDeletion(OperationContext* txn,
invariant(PlanExecutor::ADVANCED == state);
WriteUnitOfWork wuow(txn);
- if (!repl::getGlobalReplicationCoordinator()->canAcceptWritesFor(_nss)) {
+ if (!repl::getGlobalReplicationCoordinator()->canAcceptWritesFor(txn, _nss)) {
warning() << "stepped down from primary while deleting chunk; orphaning data in "
<< _nss << " in range [" << min << ", " << max << ")";
break;
diff --git a/src/mongo/db/s/collection_sharding_state.cpp b/src/mongo/db/s/collection_sharding_state.cpp
index e10d654d4ef..e35c94e6352 100644
--- a/src/mongo/db/s/collection_sharding_state.cpp
+++ b/src/mongo/db/s/collection_sharding_state.cpp
@@ -297,7 +297,7 @@ bool CollectionShardingState::_checkShardVersionOk(OperationContext* txn,
return true;
}
- if (!repl::ReplicationCoordinator::get(txn)->canAcceptWritesForDatabase(_nss.db())) {
+ if (!repl::ReplicationCoordinator::get(txn)->canAcceptWritesForDatabase(txn, _nss.db())) {
// Right now connections to secondaries aren't versioned at all.
return true;
}
diff --git a/src/mongo/db/s/metadata_loader.cpp b/src/mongo/db/s/metadata_loader.cpp
index 2a57f654d84..f337e56224b 100644
--- a/src/mongo/db/s/metadata_loader.cpp
+++ b/src/mongo/db/s/metadata_loader.cpp
@@ -261,8 +261,8 @@ Status MetadataLoader::_writeNewChunksIfPrimary(OperationContext* txn,
// Only do the write(s) if this is a primary or standalone. Otherwise, return OK.
if (serverGlobalParams.clusterRole != ClusterRole::ShardServer ||
- !repl::ReplicationCoordinator::get(txn)->canAcceptWritesForDatabase(
- chunkMetadataNss.ns())) {
+ !repl::ReplicationCoordinator::get(txn)->canAcceptWritesForDatabase_UNSAFE(
+ txn, chunkMetadataNss.ns())) {
return Status::OK();
}
diff --git a/src/mongo/db/s/migration_destination_manager.cpp b/src/mongo/db/s/migration_destination_manager.cpp
index 4119f3617de..77f72f637e8 100644
--- a/src/mongo/db/s/migration_destination_manager.cpp
+++ b/src/mongo/db/s/migration_destination_manager.cpp
@@ -484,7 +484,7 @@ void MigrationDestinationManager::_migrateDriver(OperationContext* txn,
// 0. copy system.namespaces entry if collection doesn't already exist
OldClientWriteContext ctx(txn, _nss.ns());
- if (!repl::getGlobalReplicationCoordinator()->canAcceptWritesFor(_nss)) {
+ if (!repl::getGlobalReplicationCoordinator()->canAcceptWritesFor(txn, _nss)) {
_errmsg = str::stream() << "Not primary during migration: " << _nss.ns()
<< ": checking if collection exists";
warning() << _errmsg;
@@ -525,7 +525,7 @@ void MigrationDestinationManager::_migrateDriver(OperationContext* txn,
Lock::DBLock lk(txn->lockState(), _nss.db(), MODE_X);
OldClientContext ctx(txn, _nss.ns());
- if (!repl::getGlobalReplicationCoordinator()->canAcceptWritesFor(_nss)) {
+ if (!repl::getGlobalReplicationCoordinator()->canAcceptWritesFor(txn, _nss)) {
_errmsg = str::stream() << "Not primary during migration: " << _nss.ns();
warning() << _errmsg;
setState(FAIL);
diff --git a/src/mongo/db/s/set_shard_version_command.cpp b/src/mongo/db/s/set_shard_version_command.cpp
index 6261ebc0481..d4cc01f1d06 100644
--- a/src/mongo/db/s/set_shard_version_command.cpp
+++ b/src/mongo/db/s/set_shard_version_command.cpp
@@ -210,13 +210,6 @@ public:
// Step 4
- // we can run on a slave up to here
- if (!repl::getGlobalReplicationCoordinator()->canAcceptWritesForDatabase(nss.db())) {
- result.append("errmsg", "not master");
- result.append("note", "from post init in setShardVersion");
- return false;
- }
-
const ChunkVersion connectionVersion = info->getVersion(ns);
connectionVersion.addToBSON(result, "oldVersion");
@@ -224,6 +217,14 @@ public:
boost::optional<AutoGetDb> autoDb;
autoDb.emplace(txn, nss.db(), MODE_IS);
+ // we can run on a slave up to here
+ if (!repl::getGlobalReplicationCoordinator()->canAcceptWritesForDatabase(txn,
+ nss.db())) {
+ result.append("errmsg", "not master");
+ result.append("note", "from post init in setShardVersion");
+ return false;
+ }
+
// Views do not require a shard version check.
if (autoDb->getDb() && !autoDb->getDb()->getCollection(nss.ns()) &&
autoDb->getDb()->getViewCatalog()->lookup(txn, nss.ns())) {
diff --git a/src/mongo/db/ttl.cpp b/src/mongo/db/ttl.cpp
index 5c9c743b021..250663a98ad 100644
--- a/src/mongo/db/ttl.cpp
+++ b/src/mongo/db/ttl.cpp
@@ -189,7 +189,7 @@ private:
return;
}
- if (!repl::getGlobalReplicationCoordinator()->canAcceptWritesFor(collectionNSS)) {
+ if (!repl::getGlobalReplicationCoordinator()->canAcceptWritesFor(txn, collectionNSS)) {
return;
}
diff --git a/src/mongo/db/views/view_sharding_check.cpp b/src/mongo/db/views/view_sharding_check.cpp
index cc662ff2549..e2144d56dac 100644
--- a/src/mongo/db/views/view_sharding_check.cpp
+++ b/src/mongo/db/views/view_sharding_check.cpp
@@ -63,7 +63,7 @@ StatusWith<BSONObj> ViewShardingCheck::getResolvedViewIfSharded(OperationContext
const auto& sourceNss = resolvedView.getValue().getNamespace();
const auto isPrimary =
repl::ReplicationCoordinator::get(opCtx->getClient()->getServiceContext())
- ->canAcceptWritesForDatabase(db->name());
+ ->canAcceptWritesForDatabase(opCtx, db->name());
if (isPrimary && !collectionIsSharded(opCtx, sourceNss)) {
return BSONObj();