summaryrefslogtreecommitdiff
path: root/jstests/replsets/tenant_migration_abort_forget_retry.js
blob: 96d0459f26395963ddd23ad709a10057c4a97570 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
/**
 * Starts a tenant migration that aborts, either due to the
 * abortTenantMigrationBeforeLeavingBlockingState failpoint or due to receiving donorAbortMigration,
 * and then issues a donorForgetMigration command. Finally, starts a second tenant migration with
 * the same tenantId as the aborted migration, and expects this second migration to go through.
 *
 * @tags: [requires_fcv_49, 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");
load("jstests/libs/parallelTester.js");
load("jstests/libs/uuid_util.js");
load("jstests/replsets/libs/tenant_migration_test.js");
load("jstests/replsets/libs/tenant_migration_util.js");

const kTenantIdPrefix = "testTenantId";
let testNum = 0;

function makeTenantId() {
    return kTenantIdPrefix + testNum++;
}

const tenantMigrationTest = new TenantMigrationTest({name: jsTestName()});
if (!tenantMigrationTest.isFeatureFlagEnabled()) {
    jsTestLog("Skipping test because the tenant migrations feature flag is disabled");
    return;
}

(() => {
    const migrationId1 = extractUUIDFromObject(UUID());
    const migrationId2 = extractUUIDFromObject(UUID());
    const tenantId = makeTenantId();

    // Start a migration with the "abortTenantMigrationBeforeLeavingBlockingState" failPoint
    // enabled. The migration will abort as a result, and a status of "kAborted" should be returned.
    jsTestLog(
        "Starting a migration that is expected to abort due to setting abortTenantMigrationBeforeLeavingBlockingState failpoint. migrationId: " +
        migrationId1 + ", tenantId: " + tenantId);
    const donorPrimary = tenantMigrationTest.getDonorPrimary();
    const abortFp =
        configureFailPoint(donorPrimary, "abortTenantMigrationBeforeLeavingBlockingState");
    const abortRes = assert.commandWorked(
        tenantMigrationTest.runMigration({migrationIdString: migrationId1, tenantId: tenantId},
                                         false /* retryOnRetryableErrors */,
                                         false /* automaticForgetMigration */));
    assert.eq(abortRes.state, TenantMigrationTest.DonorState.kAborted);
    abortFp.off();

    // Forget the aborted migration.
    jsTestLog("Forgetting aborted migration with migrationId: " + migrationId1);
    assert.commandWorked(tenantMigrationTest.forgetMigration(migrationId1));

    // Try running a new migration with the same tenantId. It should succeed, since the previous
    // migration with the same tenantId was aborted.
    jsTestLog("Attempting to run a new migration with the same tenantId. New migrationId: " +
              migrationId2 + ", tenantId: " + tenantId);
    const commitRes = assert.commandWorked(
        tenantMigrationTest.runMigration({migrationIdString: migrationId2, tenantId: tenantId}));
    assert.eq(commitRes.state, TenantMigrationTest.DonorState.kCommitted);
})();

(() => {
    const migrationId1 = extractUUIDFromObject(UUID());
    const migrationId2 = extractUUIDFromObject(UUID());
    const tenantId = makeTenantId();

    jsTestLog(
        "Starting a migration that is expected to abort in blocking state due to receiving donorAbortMigration. migrationId: " +
        migrationId1 + ", tenantId: " + tenantId);

    const donorPrimary = tenantMigrationTest.getDonorPrimary();
    let fp = configureFailPoint(donorPrimary, "pauseTenantMigrationBeforeLeavingBlockingState");
    assert.commandWorked(
        tenantMigrationTest.startMigration({migrationIdString: migrationId1, tenantId: tenantId}));

    fp.wait();

    const donorRstArgs = TenantMigrationUtil.createRstArgs(tenantMigrationTest.getDonorRst());
    const tryAbortThread = new Thread(TenantMigrationUtil.tryAbortMigrationAsync,
                                      {migrationIdString: migrationId1, tenantId: tenantId},
                                      donorRstArgs,
                                      TenantMigrationUtil.runTenantMigrationCommand);
    tryAbortThread.start();

    // Wait for donorAbortMigration command to start.
    assert.soon(() => {
        const res = assert.commandWorked(donorPrimary.adminCommand(
            {currentOp: true, desc: "tenant donor migration", tenantId: tenantId}));
        return res.inprog[0].receivedCancelation;
    });

    fp.off();

    tryAbortThread.join();
    assert.commandWorked(tryAbortThread.returnData());

    const stateRes = assert.commandWorked(tenantMigrationTest.waitForMigrationToComplete(
        {migrationIdString: migrationId1, tenantId: tenantId}));
    assert.eq(stateRes.state, TenantMigrationTest.DonorState.kAborted);

    // Forget the aborted migration.
    jsTestLog("Forgetting aborted migration with migrationId: " + migrationId1);
    assert.commandWorked(tenantMigrationTest.forgetMigration(migrationId1));

    // Try running a new migration with the same tenantId. It should succeed, since the previous
    // migration with the same tenantId was aborted.
    jsTestLog("Attempting to run a new migration with the same tenantId. New migrationId: " +
              migrationId2 + ", tenantId: " + tenantId);
    const commitRes = assert.commandWorked(
        tenantMigrationTest.runMigration({migrationIdString: migrationId2, tenantId: tenantId}));
    assert.eq(commitRes.state, TenantMigrationTest.DonorState.kCommitted);
})();

tenantMigrationTest.stop();
})();