summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--jstests/serverless/create_indexes_with_tenant_migration.js134
-rw-r--r--jstests/serverless/findAndModify_with_tenant_migration.js6
-rw-r--r--src/mongo/s/cluster_commands_helpers.cpp7
3 files changed, 144 insertions, 3 deletions
diff --git a/jstests/serverless/create_indexes_with_tenant_migration.js b/jstests/serverless/create_indexes_with_tenant_migration.js
new file mode 100644
index 00000000000..0eb49bdbaa0
--- /dev/null
+++ b/jstests/serverless/create_indexes_with_tenant_migration.js
@@ -0,0 +1,134 @@
+/**
+ * Tests createIndexes returns the expected tenant migration error or succeeds when sent through
+ * mongos after a tenant migration commits or aborts.
+ *
+ * @tags: [requires_fcv_52]
+ */
+
+(function() {
+"use strict";
+
+load("jstests/libs/fail_point_util.js");
+
+// A function, not a constant, to ensure unique UUIDs.
+function donorStartMigrationCmd(tenantID, realConnUrl) {
+ return {
+ donorStartMigration: 1,
+ tenantId: tenantID.str,
+ migrationId: UUID(),
+ recipientConnectionString: realConnUrl,
+ readPreference: {mode: "primary"}
+ };
+}
+
+let createIndexesCmd = {createIndexes: "foo", indexes: [{key: {x: 1}, name: "x_1"}]};
+
+let st = new ShardingTest({
+ shards: 2,
+ mongosOptions: {setParameter: {tenantMigrationDisableX509Auth: true}},
+ shardOptions: {setParameter: {tenantMigrationDisableX509Auth: true}}
+});
+
+let donor = st.rs0;
+let recipient = st.rs1;
+let mongos = st.s0;
+let adminDB = donor.getPrimary().getDB('admin');
+
+(() => {
+ jsTest.log("Starting test calling createIndexes after the migration has committed.");
+ const kTenantID = ObjectId();
+ const kDbName = kTenantID.str + "_testDB";
+ let db = mongos.getDB(kDbName);
+
+ assert.commandWorked(mongos.adminCommand({enableSharding: kDbName}));
+ st.ensurePrimaryShard(kDbName, st.shard0.shardName);
+
+ // Run donorStartMigration command to start migration and poll the migration status with the
+ // same command object.
+ let startMigrationCmd = donorStartMigrationCmd(kTenantID, recipient.getURL());
+ assert.soon(function() {
+ let res = assert.commandWorked(adminDB.runCommand(startMigrationCmd));
+ return res['state'] == "committed";
+ }, "migration not in committed state", 1 * 10000, 1 * 1000);
+
+ assert.commandFailedWithCode(db.runCommand(createIndexesCmd),
+ ErrorCodes.TenantMigrationCommitted);
+})();
+
+(() => {
+ jsTest.log("Starting test calling createIndexes after the migration has aborted.");
+ const kTenantID = ObjectId();
+ const kDbName = kTenantID.str + "_testDB";
+ let db = mongos.getDB(kDbName);
+
+ assert.commandWorked(mongos.adminCommand({enableSharding: kDbName}));
+ st.ensurePrimaryShard(kDbName, st.shard0.shardName);
+
+ let abortFailPoint =
+ configureFailPoint(adminDB, "abortTenantMigrationBeforeLeavingBlockingState");
+
+ let startMigrationCmd = donorStartMigrationCmd(kTenantID, recipient.getURL());
+ assert.soon(function() {
+ let res = assert.commandWorked(adminDB.runCommand(startMigrationCmd));
+ return res['state'] == "aborted";
+ }, "migration not in aborted state", 1 * 10000, 1 * 1000);
+
+ assert.commandWorked(db.runCommand(createIndexesCmd));
+
+ abortFailPoint.off();
+})();
+
+(() => {
+ jsTest.log("Starting test calling createIndexes during migration blocking state then aborts.");
+ const kTenantID = ObjectId();
+ const kDbName = kTenantID.str + "_testDB";
+
+ assert.commandWorked(mongos.adminCommand({enableSharding: kDbName}));
+ st.ensurePrimaryShard(kDbName, st.shard0.shardName);
+
+ let blockingFailPoint =
+ configureFailPoint(adminDB, "pauseTenantMigrationBeforeLeavingBlockingState");
+ let abortFailPoint =
+ configureFailPoint(adminDB, "abortTenantMigrationBeforeLeavingBlockingState");
+
+ // Start the migration asynchronously and then immediately return the current state of the
+ // migration.
+ let startMigrationCmd = donorStartMigrationCmd(kTenantID, recipient.getURL());
+ assert.commandWorked(adminDB.runCommand(startMigrationCmd));
+
+ blockingFailPoint.wait();
+
+ // Send createIndexes command to mongos in an individual thread.
+ let createIndexesThread = new Thread((mongosConnString, kDbName, createIndexesCmd) => {
+ let mongosConn = new Mongo(mongosConnString);
+ // Expect to receive an ok response for the createIndexes command.
+ assert.commandWorked(mongosConn.getDB(kDbName).runCommand(createIndexesCmd));
+ }, st.s0.host, kDbName, createIndexesCmd);
+ createIndexesThread.start();
+
+ // Poll the numBlockedWrites of tenant migration access blocker from donor and expect it's
+ // increased by the blocked createIndexes command.
+ assert.soon(function() {
+ let mtab = donor.getPrimary()
+ .getDB('admin')
+ .adminCommand({serverStatus: 1})
+ .tenantMigrationAccessBlocker[kTenantID.str]
+ .donor;
+ return mtab.numBlockedWrites > 0;
+ }, "no blocked writes found", 1 * 10000, 1 * 1000);
+
+ blockingFailPoint.off();
+
+ // Expect to get aborted state when polling the migration state from donor.
+ assert.soon(function() {
+ let res = assert.commandWorked(adminDB.runCommand(startMigrationCmd));
+ return res['state'] == "aborted";
+ }, "migration not in aborted state", 1 * 10000, 1 * 1000);
+
+ createIndexesThread.join();
+
+ abortFailPoint.off();
+})();
+
+st.stop();
+})();
diff --git a/jstests/serverless/findAndModify_with_tenant_migration.js b/jstests/serverless/findAndModify_with_tenant_migration.js
index 7e30989159b..817de1f15de 100644
--- a/jstests/serverless/findAndModify_with_tenant_migration.js
+++ b/jstests/serverless/findAndModify_with_tenant_migration.js
@@ -9,12 +9,12 @@
load("jstests/libs/fail_point_util.js");
-function donorStartMigrationCmd(_tenantID, _realConnUrl) {
+function donorStartMigrationCmd(tenantID, realConnUrl) {
return {
donorStartMigration: 1,
- tenantId: _tenantID.str,
+ tenantId: tenantID.str,
migrationId: UUID(),
- recipientConnectionString: _realConnUrl,
+ recipientConnectionString: realConnUrl,
readPreference: {mode: "primary"}
};
}
diff --git a/src/mongo/s/cluster_commands_helpers.cpp b/src/mongo/s/cluster_commands_helpers.cpp
index 0b6759c211c..44241865243 100644
--- a/src/mongo/s/cluster_commands_helpers.cpp
+++ b/src/mongo/s/cluster_commands_helpers.cpp
@@ -223,6 +223,13 @@ std::vector<AsyncRequestsSender::Response> gatherResponsesImpl(
if (ErrorCodes::CommandOnShardedViewNotSupportedOnMongod == status) {
uassertStatusOK(status);
}
+
+ if (ErrorCodes::TenantMigrationAborted == status) {
+ uassertStatusOK(status.withContext(
+ str::stream() << "got TenantMigrationAborted response from shard "
+ << response.shardId << " at host "
+ << response.shardHostAndPort->toString()));
+ }
}
responses.push_back(std::move(response));
}