summaryrefslogtreecommitdiff
path: root/jstests/replsets/tenant_migration_find_and_modify_retry.js
diff options
context:
space:
mode:
Diffstat (limited to 'jstests/replsets/tenant_migration_find_and_modify_retry.js')
-rw-r--r--jstests/replsets/tenant_migration_find_and_modify_retry.js103
1 files changed, 103 insertions, 0 deletions
diff --git a/jstests/replsets/tenant_migration_find_and_modify_retry.js b/jstests/replsets/tenant_migration_find_and_modify_retry.js
new file mode 100644
index 00000000000..1a77e92fc2c
--- /dev/null
+++ b/jstests/replsets/tenant_migration_find_and_modify_retry.js
@@ -0,0 +1,103 @@
+/**
+ * Tests a case where the retryable write oplog pre-fetch stage does not fetch the pre/post image
+ * for a findAndModify operation because there is a newer txnNumber started in the same session when
+ * the pre-fetch stage runs. As a newer transaction has started in the same session, the tenant
+ * migration does not need to support retrying the findAndModify. We test that the tenant migration
+ * can still succeed in this case.
+ *
+ * @tags: [requires_fcv_49, requires_majority_read_concern, incompatible_with_eft,
+ * incompatible_with_windows_tls, incompatible_with_macos, requires_persistence]
+ */
+
+(function() {
+"use strict";
+
+load("jstests/replsets/libs/tenant_migration_test.js");
+load("jstests/replsets/libs/tenant_migration_util.js");
+load("jstests/libs/uuid_util.js");
+load("jstests/libs/fail_point_util.js"); // For configureFailPoint().
+
+const tenantMigrationTest = new TenantMigrationTest({name: jsTestName()});
+
+if (!tenantMigrationTest.isFeatureFlagEnabled()) {
+ jsTestLog("Skipping test because the tenant migrations feature flag is disabled");
+ return;
+}
+const kTenantId = "testTenantId";
+const kDbName = tenantMigrationTest.tenantDB(kTenantId, "testDB");
+const kCollName = "testColl";
+
+tenantMigrationTest.insertDonorDB(kDbName, kCollName, [{x: 1}]);
+
+const recipientPrimary = tenantMigrationTest.getRecipientPrimary();
+const hangBeforeRetrievingStartOpTime =
+ configureFailPoint(recipientPrimary, "fpAfterComparingRecipientAndDonorFCV", {action: "hang"});
+const hangAfterRetrievingStartOpTime = configureFailPoint(
+ recipientPrimary, "fpAfterRetrievingStartOpTimesMigrationRecipientInstance", {action: "hang"});
+
+const migrationId = UUID();
+const migrationOpts = {
+ migrationIdString: extractUUIDFromObject(migrationId),
+ tenantId: kTenantId,
+};
+assert.commandWorked(tenantMigrationTest.startMigration(migrationOpts));
+
+hangBeforeRetrievingStartOpTime.wait();
+
+const donorDB = tenantMigrationTest.getDonorPrimary().getDB(kDbName);
+
+// Run a retryable findAndModify before the recipient gets the start fetching optime so that the
+// recipient would start fetching oplog from this findAndModify's oplog entry and the post-image
+// should be less than the startFetchingOpTime.
+const lsid = {
+ id: UUID()
+};
+let res = assert.commandWorked(donorDB.runCommand({
+ findAndModify: kCollName,
+ query: {x: 1},
+ update: {$set: {y: 1}},
+ new: true,
+ txnNumber: NumberLong(0),
+ lsid: lsid,
+ writeConcern: {w: "majority"}
+}));
+jsTestLog("First findAndModify: " + tojson(res));
+
+hangBeforeRetrievingStartOpTime.off();
+hangAfterRetrievingStartOpTime.wait();
+
+// Run another retryable findAndModify with a newer txnNumber using the same session before the
+// recipient's retryable write pre-fetch stage. After this, the pre-fetch stage would not fetch the
+// post-image of the last findAndModify because a newer txnNumber has started.
+res = assert.commandWorked(donorDB.runCommand({
+ findAndModify: kCollName,
+ query: {x: 1},
+ update: {$set: {y: 2}},
+ new: true,
+ txnNumber: NumberLong(1),
+ lsid: lsid,
+ writeConcern: {w: "majority"}
+}));
+jsTestLog("Second findAndModify: " + tojson(res));
+
+// Resume the tenant migration.
+hangAfterRetrievingStartOpTime.off();
+
+const stateRes =
+ assert.commandWorked(tenantMigrationTest.waitForMigrationToComplete(migrationOpts));
+assert.eq(stateRes.state, TenantMigrationTest.State.kCommitted);
+
+res = assert.commandWorked(recipientPrimary.getDB(kDbName).runCommand({
+ findAndModify: kCollName,
+ query: {x: 1},
+ update: {$set: {y: 2}},
+ new: true,
+ txnNumber: NumberLong(1),
+ lsid: lsid,
+ writeConcern: {w: "majority"}
+}));
+jsTestLog("Retry findAndModify on recipient: " + tojson(res));
+assert.eq(2, res.value.y);
+
+tenantMigrationTest.stop();
+})();