diff options
author | Jack Mulrow <jack.mulrow@mongodb.com> | 2021-06-16 22:20:15 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2021-06-21 03:48:47 +0000 |
commit | a82b5eed3bea4e8fb63e6d2b5b29a40cd585a80e (patch) | |
tree | 0b6feb62f1997871a053e9ce51667390fe069237 | |
parent | 0b39a23e1f9a8ed0a15c38aa270971e1a4fe83a7 (diff) | |
download | mongo-a82b5eed3bea4e8fb63e6d2b5b29a40cd585a80e.tar.gz |
SERVER-57769 Allow tenant migration recipients to advance cluster time with noops
(cherry picked from commit fca4506a72e32e2346ddaa7e0a7d9d59f2138d8e)
-rw-r--r-- | src/mongo/db/SConscript | 1 | ||||
-rw-r--r-- | src/mongo/db/commands/run_aggregate.cpp | 2 | ||||
-rw-r--r-- | src/mongo/db/read_concern.cpp | 3 | ||||
-rw-r--r-- | src/mongo/db/read_concern.h | 2 | ||||
-rw-r--r-- | src/mongo/db/read_concern_mongod.cpp | 31 | ||||
-rw-r--r-- | src/mongo/db/s/migration_source_manager.cpp | 3 | ||||
-rw-r--r-- | src/mongo/db/service_entry_point_mongod.cpp | 6 | ||||
-rw-r--r-- | src/mongo/embedded/read_concern_embedded.cpp | 1 | ||||
-rw-r--r-- | src/mongo/embedded/service_entry_point_embedded.cpp | 6 |
9 files changed, 37 insertions, 18 deletions
diff --git a/src/mongo/db/SConscript b/src/mongo/db/SConscript index b6036db8e53..6060fad1faa 100644 --- a/src/mongo/db/SConscript +++ b/src/mongo/db/SConscript @@ -1068,6 +1068,7 @@ env.Library( 'read_concern_mongod.idl', ], LIBDEPS_PRIVATE=[ + "$BUILD_DIR/mongo/db/repl/tenant_migration_access_blocker", "$BUILD_DIR/mongo/idl/server_parameter", "$BUILD_DIR/mongo/s/grid", "catalog_raii", diff --git a/src/mongo/db/commands/run_aggregate.cpp b/src/mongo/db/commands/run_aggregate.cpp index ab8ff389252..ea677237211 100644 --- a/src/mongo/db/commands/run_aggregate.cpp +++ b/src/mongo/db/commands/run_aggregate.cpp @@ -493,7 +493,7 @@ void _adjustChangeStreamReadConcern(OperationContext* opCtx) { } // Wait for read concern again since we changed the original read concern. - uassertStatusOK(waitForReadConcern(opCtx, readConcernArgs, true)); + uassertStatusOK(waitForReadConcern(opCtx, readConcernArgs, StringData(), true)); setPrepareConflictBehaviorForReadConcern( opCtx, readConcernArgs, PrepareConflictBehavior::kIgnoreConflicts); } diff --git a/src/mongo/db/read_concern.cpp b/src/mongo/db/read_concern.cpp index 07944dd56df..fe9fd208c04 100644 --- a/src/mongo/db/read_concern.cpp +++ b/src/mongo/db/read_concern.cpp @@ -42,9 +42,10 @@ void setPrepareConflictBehaviorForReadConcern(OperationContext* opCtx, Status waitForReadConcern(OperationContext* opCtx, const repl::ReadConcernArgs& readConcernArgs, + StringData dbName, bool allowAfterClusterTime) { static auto w = MONGO_WEAK_FUNCTION_DEFINITION(waitForReadConcern); - return w(opCtx, readConcernArgs, allowAfterClusterTime); + return w(opCtx, readConcernArgs, dbName, allowAfterClusterTime); } Status waitForLinearizableReadConcern(OperationContext* opCtx, int readConcernTimeout) { diff --git a/src/mongo/db/read_concern.h b/src/mongo/db/read_concern.h index 6168b393954..e12915870cf 100644 --- a/src/mongo/db/read_concern.h +++ b/src/mongo/db/read_concern.h @@ -37,6 +37,7 @@ class Status; template <typename T> class StatusWith; enum class PrepareConflictBehavior; +class StringData; namespace repl { class ReadConcernArgs; class SpeculativeMajorityReadInfo; @@ -64,6 +65,7 @@ void setPrepareConflictBehaviorForReadConcern(OperationContext* opCtx, */ Status waitForReadConcern(OperationContext* opCtx, const repl::ReadConcernArgs& readConcernArgs, + StringData dbName, bool allowAfterClusterTime); /* diff --git a/src/mongo/db/read_concern_mongod.cpp b/src/mongo/db/read_concern_mongod.cpp index 8cc004b8f64..f35d31c80cd 100644 --- a/src/mongo/db/read_concern_mongod.cpp +++ b/src/mongo/db/read_concern_mongod.cpp @@ -42,6 +42,7 @@ #include "mongo/db/repl/optime.h" #include "mongo/db/repl/repl_client_info.h" #include "mongo/db/repl/speculative_majority_read_info.h" +#include "mongo/db/repl/tenant_migration_access_blocker_registry.h" #include "mongo/db/s/sharding_state.h" #include "mongo/db/server_options.h" #include "mongo/db/storage/recovery_unit.h" @@ -104,10 +105,21 @@ private: std::map<Timestamp, std::shared_ptr<Notification<Status>>> _writeRequests; }; +bool hasActiveTenantMigrationRecipient(OperationContext* opCtx, StringData dbName) { + if (dbName.empty()) { + return false; + } + + auto mtab = TenantMigrationAccessBlockerRegistry::get(opCtx->getServiceContext()) + .getTenantMigrationAccessBlockerForDbName( + dbName, TenantMigrationAccessBlocker::BlockerType::kRecipient); + return bool(mtab); +} + /** * Schedule a write via appendOplogNote command to the primary of this replica set. */ -Status makeNoopWriteIfNeeded(OperationContext* opCtx, LogicalTime clusterTime) { +Status makeNoopWriteIfNeeded(OperationContext* opCtx, LogicalTime clusterTime, StringData dbName) { repl::ReplicationCoordinator* const replCoord = repl::ReplicationCoordinator::get(opCtx); invariant(replCoord->isReplEnabled()); @@ -139,18 +151,14 @@ Status makeNoopWriteIfNeeded(OperationContext* opCtx, LogicalTime clusterTime) { // one that waits for the notification gets the later clusterTime, so when the request finishes // it needs to be repeated with the later time. while (clusterTime > lastAppliedOpTime) { - // standalone replica set, so there is no need to advance the OpLog on the primary. - if (serverGlobalParams.clusterRole == ClusterRole::None) { + // Standalone replica set, so there is no need to advance the OpLog on the primary. The only + // exception is after a tenant migration because the target time may be from the donor + // replica set and is not guaranteed to be in the recipient's oplog. + if (serverGlobalParams.clusterRole == ClusterRole::None && + !hasActiveTenantMigrationRecipient(opCtx, dbName)) { return Status::OK(); } - bool isConfig = (serverGlobalParams.clusterRole == ClusterRole::ConfigServer); - - if (!isConfig && !ShardingState::get(opCtx)->enabled()) { - return {ErrorCodes::ShardingStateNotInitialized, - "Failed noop write because sharding state has not been initialized"}; - } - if (!remainingAttempts--) { std::stringstream ss; ss << "Requested clusterTime " << clusterTime.toString() @@ -282,6 +290,7 @@ void setPrepareConflictBehaviorForReadConcernImpl(OperationContext* opCtx, Status waitForReadConcernImpl(OperationContext* opCtx, const repl::ReadConcernArgs& readConcernArgs, + StringData dbName, bool allowAfterClusterTime) { // If we are in a direct client within a transaction, then we may be holding locks, so it is // illegal to wait for read concern. This is fine, since the outer operation should have handled @@ -373,7 +382,7 @@ Status waitForReadConcernImpl(OperationContext* opCtx, << "; current clusterTime: " << clusterTime.toString()}; } - auto status = makeNoopWriteIfNeeded(opCtx, *targetClusterTime); + auto status = makeNoopWriteIfNeeded(opCtx, *targetClusterTime, dbName); if (!status.isOK()) { LOGV2(20990, "Failed noop write at clusterTime: {targetClusterTime} due to {error}", diff --git a/src/mongo/db/s/migration_source_manager.cpp b/src/mongo/db/s/migration_source_manager.cpp index 62aa6843250..13deb093da8 100644 --- a/src/mongo/db/s/migration_source_manager.cpp +++ b/src/mongo/db/s/migration_source_manager.cpp @@ -271,7 +271,8 @@ Status MigrationSourceManager::startClone() { auto const readConcernArgs = repl::ReadConcernArgs( replCoord->getMyLastAppliedOpTime(), repl::ReadConcernLevel::kLocalReadConcern); - auto waitForReadConcernStatus = waitForReadConcern(_opCtx, readConcernArgs, false); + auto waitForReadConcernStatus = + waitForReadConcern(_opCtx, readConcernArgs, StringData(), false); if (!waitForReadConcernStatus.isOK()) { return waitForReadConcernStatus; } diff --git a/src/mongo/db/service_entry_point_mongod.cpp b/src/mongo/db/service_entry_point_mongod.cpp index fd48254d9af..f6b22b26899 100644 --- a/src/mongo/db/service_entry_point_mongod.cpp +++ b/src/mongo/db/service_entry_point_mongod.cpp @@ -75,8 +75,10 @@ public: void waitForReadConcern(OperationContext* opCtx, const CommandInvocation* invocation, const OpMsgRequest& request) const override { - Status rcStatus = mongo::waitForReadConcern( - opCtx, repl::ReadConcernArgs::get(opCtx), invocation->allowsAfterClusterTime()); + Status rcStatus = mongo::waitForReadConcern(opCtx, + repl::ReadConcernArgs::get(opCtx), + request.getDatabase(), + invocation->allowsAfterClusterTime()); if (!rcStatus.isOK()) { if (ErrorCodes::isExceededTimeLimitError(rcStatus.code())) { diff --git a/src/mongo/embedded/read_concern_embedded.cpp b/src/mongo/embedded/read_concern_embedded.cpp index d6fc2a0cbe7..708b41bc279 100644 --- a/src/mongo/embedded/read_concern_embedded.cpp +++ b/src/mongo/embedded/read_concern_embedded.cpp @@ -42,6 +42,7 @@ void setPrepareConflictBehaviorForReadConcernImpl( Status waitForReadConcernImpl(OperationContext* opCtx, const repl::ReadConcernArgs& readConcernArgs, + StringData dbName, bool allowAfterClusterTime) { if (readConcernArgs.getLevel() == repl::ReadConcernLevel::kLinearizableReadConcern) { return {ErrorCodes::NotImplemented, "linearizable read concern not supported on embedded"}; diff --git a/src/mongo/embedded/service_entry_point_embedded.cpp b/src/mongo/embedded/service_entry_point_embedded.cpp index 0ff33bc12c0..428d15e2d8a 100644 --- a/src/mongo/embedded/service_entry_point_embedded.cpp +++ b/src/mongo/embedded/service_entry_point_embedded.cpp @@ -82,8 +82,10 @@ public: void waitForReadConcern(OperationContext* opCtx, const CommandInvocation* invocation, const OpMsgRequest& request) const override { - auto rcStatus = mongo::waitForReadConcern( - opCtx, repl::ReadConcernArgs::get(opCtx), invocation->allowsAfterClusterTime()); + auto rcStatus = mongo::waitForReadConcern(opCtx, + repl::ReadConcernArgs::get(opCtx), + request.getDatabase(), + invocation->allowsAfterClusterTime()); uassertStatusOK(rcStatus); } |