From befb3ab22daa1f6e0db54af4caa426cfca1b7cd2 Mon Sep 17 00:00:00 2001 From: Matthew Russotto Date: Fri, 3 Mar 2017 11:25:44 -0500 Subject: SERVER-26965 Use RAII type for turning off replicated writes. --- src/mongo/db/catalog/apply_ops.cpp | 2 +- src/mongo/db/catalog/capped_utils.cpp | 4 +-- src/mongo/db/catalog/coll_mod.cpp | 2 +- src/mongo/db/catalog/create_collection.cpp | 2 +- src/mongo/db/catalog/drop_collection.cpp | 2 +- src/mongo/db/catalog/drop_database.cpp | 2 +- src/mongo/db/catalog/drop_indexes.cpp | 2 +- src/mongo/db/catalog/index_catalog.cpp | 2 +- src/mongo/db/catalog/rename_collection.cpp | 2 +- src/mongo/db/cloner.cpp | 31 +++++++++---------- src/mongo/db/commands/collection_to_capped.cpp | 2 +- src/mongo/db/commands/create_indexes.cpp | 8 ++--- src/mongo/db/commands/dbcommands.cpp | 4 +-- src/mongo/db/commands/explain_cmd.cpp | 2 +- .../db/commands/feature_compatibility_version.cpp | 2 +- src/mongo/db/commands/find_and_modify.cpp | 10 +++---- src/mongo/db/commands/mr.cpp | 10 ++++--- src/mongo/db/dbhelpers.cpp | 2 +- src/mongo/db/exec/delete.cpp | 2 +- src/mongo/db/exec/update.cpp | 2 +- src/mongo/db/index/index_access_method.cpp | 2 +- src/mongo/db/ops/update.cpp | 2 +- src/mongo/db/ops/write_ops_exec.cpp | 7 +++-- src/mongo/db/query/find.cpp | 5 ++-- src/mongo/db/query/get_executor.cpp | 4 +-- src/mongo/db/read_concern.cpp | 2 +- src/mongo/db/repl/noop_writer.cpp | 2 +- src/mongo/db/repl/oplog.cpp | 4 +-- src/mongo/db/repl/replication_coordinator.h | 29 ++++++++++++++++-- src/mongo/db/repl/replication_coordinator_impl.cpp | 35 ++++++++++++++++++---- src/mongo/db/repl/replication_coordinator_impl.h | 11 +++++-- .../replication_coordinator_impl_elect_v1_test.cpp | 27 ++++++++++++----- src/mongo/db/repl/replication_coordinator_mock.cpp | 29 ++++++++++++++---- src/mongo/db/repl/replication_coordinator_mock.h | 13 ++++++-- src/mongo/db/s/collection_range_deleter.cpp | 2 +- src/mongo/db/s/collection_sharding_state.cpp | 2 +- src/mongo/db/s/metadata_loader.cpp | 4 +-- src/mongo/db/s/migration_destination_manager.cpp | 4 +-- src/mongo/db/s/set_shard_version_command.cpp | 15 +++++----- src/mongo/db/ttl.cpp | 2 +- src/mongo/db/views/view_sharding_check.cpp | 2 +- 41 files changed, 196 insertions(+), 102 deletions(-) (limited to 'src/mongo') 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 scopedXact(new ScopedTransaction(txn, MODE_X)); unique_ptr 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 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> 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> 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 b70ac1906c1..2fa1f8240ba 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. @@ -274,13 +288,22 @@ public: const NamespaceString& ns, 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 3aeb75b4326..b4b2b7cf3db 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 0b357e70d49..698e3052035 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 8fd94ed8d00..c25e4462cb2 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 b037d333018..9bb69775072 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 640aac82254..296652f5607 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 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 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(); -- cgit v1.2.1