summaryrefslogtreecommitdiff
path: root/jstests/replsets/tenant_migration_recipient_retry_forget_migration.js
diff options
context:
space:
mode:
authorLingzhi Deng <lingzhi.deng@mongodb.com>2021-06-11 22:34:12 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2021-06-11 22:58:04 +0000
commit2c316c7197b5dd8885c91f4ff27d9327e986db7c (patch)
tree62454cc10e138087f5102d74d7acd2d367db12fc /jstests/replsets/tenant_migration_recipient_retry_forget_migration.js
parent3880c1fd25963f72038122382b665d402b178cf1 (diff)
downloadmongo-2c316c7197b5dd8885c91f4ff27d9327e986db7c.tar.gz
SERVER-57491: Do not recreate recipient mtab if recipientForgetMigration is received after the state doc is deleted
Diffstat (limited to 'jstests/replsets/tenant_migration_recipient_retry_forget_migration.js')
-rw-r--r--jstests/replsets/tenant_migration_recipient_retry_forget_migration.js118
1 files changed, 118 insertions, 0 deletions
diff --git a/jstests/replsets/tenant_migration_recipient_retry_forget_migration.js b/jstests/replsets/tenant_migration_recipient_retry_forget_migration.js
new file mode 100644
index 00000000000..1fe81d70a80
--- /dev/null
+++ b/jstests/replsets/tenant_migration_recipient_retry_forget_migration.js
@@ -0,0 +1,118 @@
+/**
+ * Tests that a recipientForgetMigration is received after the recipient state doc has been deleted.
+ *
+ * @tags: [requires_fcv_50, requires_majority_read_concern, incompatible_with_windows_tls,
+ * incompatible_with_eft, incompatible_with_macos, requires_persistence]
+ */
+
+(function() {
+
+"use strict";
+load("jstests/libs/fail_point_util.js"); // For configureFailPoint().
+load("jstests/libs/parallelTester.js"); // For Thread()
+load("jstests/libs/uuid_util.js"); // For extractUUIDFromObject().
+load("jstests/replsets/libs/tenant_migration_test.js");
+load("jstests/replsets/libs/tenant_migration_util.js");
+
+const tenantMigrationTest = new TenantMigrationTest({name: jsTestName()});
+
+if (!tenantMigrationTest.isFeatureFlagEnabled()) {
+ jsTestLog("Skipping test because the tenant migrations feature flag is disabled");
+ return;
+}
+
+const migrationId = UUID();
+const tenantId = 'testTenantId';
+const recipientCertificateForDonor =
+ TenantMigrationUtil.getCertificateAndPrivateKey("jstests/libs/tenant_migration_recipient.pem");
+
+const dbName = tenantMigrationTest.tenantDB(tenantId, "test");
+const collName = "coll";
+
+const recipientPrimary = tenantMigrationTest.getRecipientPrimary();
+
+// Not doing a migration before writing to the recipient to mimic that a migration has completed and
+// the state doc has been garbage collected.
+assert.commandWorked(recipientPrimary.getDB(dbName)[collName].insert({_id: 1}));
+
+function runRecipientForgetMigration(host, {
+ migrationIdString,
+ donorConnectionString,
+ tenantId,
+ readPreference,
+ recipientCertificateForDonor
+}) {
+ const db = new Mongo(host);
+ return db.adminCommand({
+ recipientForgetMigration: 1,
+ migrationId: UUID(migrationIdString),
+ donorConnectionString,
+ tenantId,
+ readPreference,
+ recipientCertificateForDonor
+ });
+}
+
+const fp = configureFailPoint(recipientPrimary, "hangBeforeTaskCompletion");
+
+const recipientForgetMigrationThread =
+ new Thread(runRecipientForgetMigration, recipientPrimary.host, {
+ migrationIdString: extractUUIDFromObject(migrationId),
+ donorConnectionString: tenantMigrationTest.getDonorRst().getURL(),
+ tenantId,
+ readPreference: {mode: "primary"},
+ recipientCertificateForDonor
+ });
+
+// Run a delayed/retried recipientForgetMigration command after the state doc has been deleted.
+recipientForgetMigrationThread.start();
+
+// Block the recipient before it updates the state doc with an expireAt field.
+fp.wait();
+
+let currOp = assert
+ .commandWorked(recipientPrimary.adminCommand(
+ {currentOp: true, desc: "tenant recipient migration"}))
+ .inprog[0];
+assert.eq(currOp.state, 3 /* kDone */, currOp);
+assert(!currOp.hasOwnProperty("expireAt"), currOp);
+
+// Test that we can still read from the recipient.
+assert.eq(1, recipientPrimary.getDB(dbName)[collName].find().itcount());
+
+const newRecipientPrimary = tenantMigrationTest.getRecipientRst().getSecondary();
+const newPrimaryFp = configureFailPoint(newRecipientPrimary, "hangBeforeTaskCompletion");
+
+// Step up a new recipient primary before the state doc is truly marked as garbage collectable.
+assert.commandWorked(newRecipientPrimary.adminCommand({replSetStepUp: 1}));
+fp.off();
+
+// The new primary should skip all tenant migration steps but wait for another
+// recipientForgetMigration command.
+newPrimaryFp.wait();
+
+assert.commandFailedWithCode(recipientForgetMigrationThread.returnData(),
+ ErrorCodes.InterruptedDueToReplStateChange);
+
+// Test that we can still read from the recipient.
+assert.eq(1, newRecipientPrimary.getDB(dbName)[collName].find().itcount());
+
+// Test that we can retry the recipientForgetMigration on the new primary.
+newPrimaryFp.off();
+assert.commandWorked(runRecipientForgetMigration(newRecipientPrimary.host, {
+ migrationIdString: extractUUIDFromObject(migrationId),
+ donorConnectionString: tenantMigrationTest.getDonorRst().getURL(),
+ tenantId,
+ readPreference: {mode: "primary"},
+ recipientCertificateForDonor
+}));
+
+currOp = assert
+ .commandWorked(newRecipientPrimary.adminCommand(
+ {currentOp: true, desc: "tenant recipient migration"}))
+ .inprog[0];
+assert.eq(currOp.state, 3 /* kDone */, currOp);
+assert(currOp.hasOwnProperty("expireAt"), currOp);
+
+tenantMigrationTest.stop();
+})();