jstests/replsets/tenant_migration_concurrent_reads_on_recipient.js
/**
 * Tests that after the recipient has reached the rejectReadsBeforeTimestamp and
 * after the migration commits, it only rejects reads with atClusterTime <
 * rejectReadsBeforeTimestamp.
 */
Tests that after the recipient has reached the rejectReadsBeforeTimestamp and
after the migration commits, it only rejects reads with atClusterTime <
rejectReadsBeforeTimestamp.
Tests that after the recipient has reached the rejectReadsBeforeTimestamp and after the migration commits it only rejects reads with atClusterTime < rejectReadsBeforeTimestamp .
function testRejectOnlyReadsWithAtClusterTimeLessThanRejectReadsBeforeTimestamp(
    {testCase, dbName, collName, tenantMigrationTest}) {
    const tenantId = dbName.split('_')[0];
    const migrationOpts = {
        migrationIdString: extractUUIDFromObject(UUID()),
        tenantId,
        recipientConnString: tenantMigrationTest.getRecipientConnString(),
    };
    const donorRst = tenantMigrationTest.getDonorRst();
    const donorPrimary = donorRst.getPrimary();
    const recipientRst = tenantMigrationTest.getRecipientRst();
    const recipientPrimary = recipientRst.getPrimary();
    const preMigrationTimestamp = getLastOpTime(donorPrimary).ts;
    let waitForRejectReadsBeforeTsFp = configureFailPoint(
        recipientPrimary, "fpAfterWaitForRejectReadsBeforeTimestamp", {action: "hang"});
    const donorRstArgs = TenantMigrationUtil.createRstArgs(donorRst);
    const runMigrationThread =
        new Thread(TenantMigrationUtil.runMigrationAsync, migrationOpts, donorRstArgs);
    runMigrationThread.start();
    waitForRejectReadsBeforeTsFp.wait();
    recipientRst.awaitLastOpCommitted();
    const recipientDoc =
        recipientPrimary.getCollection(TenantMigrationTest.kConfigRecipientsNS).findOne({
            tenantId: tenantId
        });
    assert.lt(preMigrationTimestamp, recipientDoc.rejectReadsBeforeTimestamp);
    const nodes = testCase.isSupportedOnSecondaries ? recipientRst.nodes : [recipientPrimary];
    nodes.forEach(node => {
        const db = node.getDB(dbName);
        if (testCase.requiresReadTimestamp) {
            runCommand(
                db, testCase.command(collName, preMigrationTimestamp), ErrorCodes.SnapshotTooOld);
            runCommand(
                db, testCase.command(collName, recipientDoc.rejectReadsBeforeTimestamp), null);
        } else {
            runCommand(db, testCase.command(collName), null);
        }
    });
    waitForRejectReadsBeforeTsFp.off();
    TenantMigrationTest.assertCommitted(runMigrationThread.returnData());
    nodes.forEach(node => {
        const db = node.getDB(dbName);
        if (testCase.requiresReadTimestamp) {
            runCommand(
                db, testCase.command(collName, preMigrationTimestamp), ErrorCodes.SnapshotTooOld);
            runCommand(
                db, testCase.command(collName, recipientDoc.rejectReadsBeforeTimestamp), null);
        } else {
            runCommand(db, testCase.command(collName), null);
        }
    });
    assert.commandWorked(tenantMigrationTest.forgetMigration(migrationOpts.migrationIdString));
    tenantMigrationTest.waitForMigrationGarbageCollection(migrationOpts.migrationIdString);
}
function testRejectOnlyReadsWithAtClusterTimeLessThanRejectReadsBeforeTimestamp ( { testCase , dbName , collName , tenantMigrationTest } ) { const tenantId = dbName . split ( '_' ) [ 0 ] ; const migrationOpts = { migrationIdString : extractUUIDFromObject ( UUID ( ) ) , tenantId , recipientConnString : tenantMigrationTest . getRecipientConnString ( ) , } ; const donorRst = tenantMigrationTest . getDonorRst ( ) ; const donorPrimary = donorRst . getPrimary ( ) ; const recipientRst = tenantMigrationTest . getRecipientRst ( ) ; const recipientPrimary = recipientRst . getPrimary ( ) ; const preMigrationTimestamp = getLastOpTime ( donorPrimary ) . ts ; let waitForRejectReadsBeforeTsFp = configureFailPoint ( recipientPrimary , "fpAfterWaitForRejectReadsBeforeTimestamp" , { action : "hang" } ) ; const donorRstArgs = TenantMigrationUtil . createRstArgs ( donorRst ) ; const runMigrationThread = new Thread ( TenantMigrationUtil . runMigrationAsync , migrationOpts , donorRstArgs ) ; runMigrationThread . start ( ) ; waitForRejectReadsBeforeTsFp . wait ( ) ; recipientRst . awaitLastOpCommitted ( ) ; const recipientDoc = recipientPrimary . getCollection ( TenantMigrationTest . kConfigRecipientsNS ) . findOne ( { tenantId : tenantId } ) ; assert . lt ( preMigrationTimestamp , recipientDoc . rejectReadsBeforeTimestamp ) ; const nodes = testCase . isSupportedOnSecondaries ? recipientRst . nodes : [ recipientPrimary ] ; nodes . forEach ( node => { const db = node . getDB ( dbName ) ; if ( testCase . requiresReadTimestamp ) { runCommand ( db , testCase . command ( collName , preMigrationTimestamp ) , ErrorCodes . SnapshotTooOld ) ; runCommand ( db , testCase . command ( collName , recipientDoc . rejectReadsBeforeTimestamp ) , null ) ; } else { runCommand ( db , testCase . command ( collName ) , null ) ; } } ) ; waitForRejectReadsBeforeTsFp . off ( ) ; TenantMigrationTest . assertCommitted ( runMigrationThread . returnData ( ) ) ; nodes . forEach ( node => { const db = node . getDB ( dbName ) ; if ( testCase . requiresReadTimestamp ) { runCommand ( db , testCase . command ( collName , preMigrationTimestamp ) , ErrorCodes . SnapshotTooOld ) ; runCommand ( db , testCase . command ( collName , recipientDoc . rejectReadsBeforeTimestamp ) , null ) ; } else { runCommand ( db , testCase . command ( collName ) , null ) ; } } ) ; assert . commandWorked ( tenantMigrationTest . forgetMigration ( migrationOpts . migrationIdString ) ) ; tenantMigrationTest . waitForMigrationGarbageCollection ( migrationOpts . migrationIdString ) ; }
Tests that after the recipient has reached the rejectReadsBeforeTimestamp and
 after the migration commits, it only rejects reads with atClusterTime <
 rejectReadsBeforeTimestamp.
Tests that after the recipient has reached the rejectReadsBeforeTimestamp and after the migration commits it only rejects reads with atClusterTime < rejectReadsBeforeTimestamp .
// Select a read timestamp < rejectReadsBeforeTimestamp. // Wait for the last oplog entry on the primary to be visible in the committed snapshot view of // the oplog on all the secondaries. This is to ensure that snapshot reads on secondaries with // unspecified atClusterTime have read timestamp >= rejectReadsBeforeTimestamp. // Untimestamped reads are not rejected after the recipient has applied data past the // rejectReadsBeforeTimestamp. Snapshot reads with unspecified atClusterTime should have // read timestamp >= rejectReadsBeforeTimestamp so are also not rejected. // Untimestamped reads are not rejected after the recipient has committed. Snapshot // reads with unspecified atClusterTime should have read timestamp >= // rejectReadsBeforeTimestamp so are also not rejected.