summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJack Mulrow <jack.mulrow@mongodb.com>2021-06-16 22:20:15 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2021-06-21 03:48:47 +0000
commita82b5eed3bea4e8fb63e6d2b5b29a40cd585a80e (patch)
tree0b6feb62f1997871a053e9ce51667390fe069237
parent0b39a23e1f9a8ed0a15c38aa270971e1a4fe83a7 (diff)
downloadmongo-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/SConscript1
-rw-r--r--src/mongo/db/commands/run_aggregate.cpp2
-rw-r--r--src/mongo/db/read_concern.cpp3
-rw-r--r--src/mongo/db/read_concern.h2
-rw-r--r--src/mongo/db/read_concern_mongod.cpp31
-rw-r--r--src/mongo/db/s/migration_source_manager.cpp3
-rw-r--r--src/mongo/db/service_entry_point_mongod.cpp6
-rw-r--r--src/mongo/embedded/read_concern_embedded.cpp1
-rw-r--r--src/mongo/embedded/service_entry_point_embedded.cpp6
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);
}