diff options
author | Lingzhi Deng <lingzhi.deng@mongodb.com> | 2021-06-11 22:34:12 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2021-06-11 22:58:04 +0000 |
commit | 2c316c7197b5dd8885c91f4ff27d9327e986db7c (patch) | |
tree | 62454cc10e138087f5102d74d7acd2d367db12fc /jstests/replsets/tenant_migration_recipient_retry_forget_migration.js | |
parent | 3880c1fd25963f72038122382b665d402b178cf1 (diff) | |
download | mongo-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.js | 118 |
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(); +})(); |