summaryrefslogtreecommitdiff
path: root/jstests/replsets/libs/tenant_migration_util.js
blob: 0a747da6237f3cab73d9cbd55cad45a4e8187753 (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
/**
 * Utilities for testing tenant migrations.
 */
var TenantMigrationUtil = (function() {
    // An object that mirrors the access states for the TenantMigrationAccessBlocker.
    const accessState = {kAllow: 0, kBlockingWrites: 1, kBlockingReadsAndWrites: 2, kReject: 3};

    /**
     * Runs the donorStartMigration command with the given migration options every 'intervalMS'
     * until the migration commits or aborts, or until the command fails. Returns the last command
     * response.
     */
    function startMigration(donorPrimaryHost, migrationOpts, intervalMS = 100) {
        const donorPrimary = new Mongo(donorPrimaryHost);
        const cmdObj = {
            donorStartMigration: 1,
            migrationId: UUID(migrationOpts.migrationIdString),
            recipientConnectionString: migrationOpts.recipientConnString,
            databasePrefix: migrationOpts.dbPrefix,
            readPreference: migrationOpts.readPreference
        };

        while (true) {
            const res = donorPrimary.adminCommand(cmdObj);
            if (!res.ok || res.state == "committed" || res.state == "aborted") {
                return res;
            }
            sleep(intervalMS);
        }
    }

    /**
     * Runs the donorForgetMigration command with the given migrationId and returns the response.
     */
    function forgetMigration(donorPrimaryHost, migrationIdString) {
        const donorPrimary = new Mongo(donorPrimaryHost);
        return donorPrimary.adminCommand(
            {donorForgetMigration: 1, migrationId: UUID(migrationIdString)});
    }

    /**
     * Returns true if the durable and in-memory state for the migration 'migrationId' and
     * 'dbPrefix' is in state "committed", and false otherwise.
     */
    function isMigrationCommitted(node, migrationId, dbPrefix) {
        const configDonorsColl = node.getCollection("config.tenantMigrationDonors");
        if (configDonorsColl.findOne({_id: migrationId}).state != "committed") {
            return false;
        }
        const mtabs = node.adminCommand({serverStatus: 1}).tenantMigrationAccessBlocker;
        return mtabs[dbPrefix].access === TenantMigrationUtil.accessState.kReject;
    }

    /**
     * Asserts that the migration 'migrationId' and 'dbPrefix' is in state "committed" on all the
     * given nodes.
     */
    function assertMigrationCommitted(nodes, migrationId, dbPrefix) {
        nodes.forEach(node => {
            assert(isMigrationCommitted(node, migrationId, dbPrefix));
        });
    }

    /**
     * Asserts that the migration 'migrationId' and 'dbPrefix' eventually goes to state "committed"
     * on all the given nodes.
     */
    function waitForMigrationToCommit(nodes, migrationId, dbPrefix) {
        nodes.forEach(node => {
            assert.soon(() => isMigrationCommitted(node, migrationId, dbPrefix));
        });
    }

    /**
     * Asserts that durable and in-memory state for the migration 'migrationId' and 'dbPrefix' is
     * eventually deleted from the given nodes.
     */
    function waitForMigrationGarbageCollection(nodes, migrationId, dbPrefix) {
        nodes.forEach(node => {
            const configDonorsColl = node.getCollection("config.tenantMigrationDonors");
            assert.soon(() => 0 === configDonorsColl.count({_id: migrationId}));

            assert.soon(() => 0 ===
                            node.adminCommand({serverStatus: 1})
                                .repl.primaryOnlyServices.TenantMigrationDonorService);

            let mtabs;
            assert.soon(() => {
                mtabs = node.adminCommand({serverStatus: 1}).tenantMigrationAccessBlocker;
                return !mtabs || !mtabs[dbPrefix];
            }, tojson(mtabs));
        });
    }

    return {
        accessState,
        startMigration,
        forgetMigration,
        assertMigrationCommitted,
        waitForMigrationToCommit,
        waitForMigrationGarbageCollection
    };
})();