summaryrefslogtreecommitdiff
path: root/jstests/sharding/resharding_prohibited_commands.js
blob: 6cbaf338ca5cbc6a259f9d324e31182c4c383d28 (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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
/**
 * Tests that chunk migrations, collMod, createIndexes, and dropIndexes are prohibited on a
 * collection that is undergoing a resharding operation. Also tests that concurrent resharding
 * operations are prohibited.
 *
 * @tags: [
 *   uses_atclustertime,
 * ]
 */
(function() {
"use strict";

load("jstests/libs/discover_topology.js");
load("jstests/sharding/libs/resharding_test_fixture.js");
load("jstests/libs/fail_point_util.js");
load('jstests/libs/parallel_shell_helpers.js');

const databaseName = "reshardingDb";
const collectionName = "coll";

const otherDatabaseName = 'reshardingDb2';
const otherCollectionName = 'coll2';
const otherNamespace = `${otherDatabaseName}.${otherCollectionName}`;

const donorOperationNamespace = 'config.localReshardingOperations.donor';

const indexCreatedByTest = {
    newKey: 1,
    oldKey: 1
};
const indexDroppedByTest = {
    x: 1
};

const prohibitedCommands = [
    {collMod: collectionName},
    {createIndexes: collectionName, indexes: [{name: "idx1", key: indexCreatedByTest}]},
    {dropIndexes: collectionName, index: indexDroppedByTest},
];

/**
 * @summary Goes through each of the commands specified in the prohibitedCommands array, executes
 * the command against the provided database and asserts that the command succeeded.
 * @param {*} database
 */
const assertCommandsSucceedAfterReshardingOpFinishes = (database) => {
    prohibitedCommands.forEach((command) => {
        jsTest.log(
            `Testing that ${tojson(command)} succeeds after the resharding operation finishes.`);
        assert.commandWorked(database.runCommand(command));
    });
};

/**
 * @summary Goes through each of the commands specified in the prohibitedCommands array,
 * executes the commands and asserts that the command failed with ReshardCollectionInProgress.
 * - In order for the dropIndexes command to fail correctly, the index its attempting to drop must
 * exist.
 * - In order for the createIndexes command to fail correctly, the index its attempting to create
 * must not exist already.
 * @param {*} database
 */
const assertCommandsFailDuringReshardingOp = (database) => {
    prohibitedCommands.forEach((command) => {
        jsTest.log(`Testing that ${tojson(command)} fails during resharding operation`);
        assert.commandFailedWithCode(database.runCommand(command),
                                     ErrorCodes.ReshardCollectionInProgress);
    });
};

const reshardingTest = new ReshardingTest({numDonors: 2});
reshardingTest.setup();

const donorShardNames = reshardingTest.donorShardNames;
const recipientShardNames = reshardingTest.recipientShardNames;

const sourceCollection = reshardingTest.createShardedCollection({
    ns: `${databaseName}.${collectionName}`,
    shardKeyPattern: {oldKey: 1},
    chunks: [
        {min: {oldKey: MinKey}, max: {oldKey: 0}, shard: donorShardNames[0]},
        {min: {oldKey: 0}, max: {oldKey: MaxKey}, shard: donorShardNames[1]}
    ],
});

const mongos = sourceCollection.getMongo();
const topology = DiscoverTopology.findConnectedNodes(mongos);
const sourceNamespace = sourceCollection.getFullName();

const waitUntilReshardingInitializedOnDonor = () => {
    const donor = new Mongo(topology.shards[donorShardNames[0]].primary);
    assert.soon(() => {
        let res = donor.getCollection(donorOperationNamespace).find().toArray();
        return res.length === 1;
    }, "timed out waiting for resharding initialization on donor shard");
};

/**
 * @summary The function that gets passed into reshardingTest.withReshardingInBackground
 * @callback DuringReshardingCallback
 * @param {String} tempNs - The temporary namespace used during resharding operations.
 */

/**
 * @summary A function that defines the surrounding environment for the tests surrounding the
 * prohibited commands during resharding. It sets up the resharding configuration and asserts that
 * the prohibited commands succeed once the resharding operation has completed.
 * @param {DuringReshardingCallback} duringReshardingFn
 * @param {Object} config
 * @param {number} config.expectedErrorCode
 * @param {Function} config.setup
 */
const withReshardingInBackground = (duringReshardingFn,
                                    {setup = () => {}, expectedErrorCode} = {}) => {
    assert.commandWorked(sourceCollection.createIndex(indexDroppedByTest));
    setup();

    reshardingTest.withReshardingInBackground({
        newShardKeyPattern: {newKey: 1},
        newChunks: [{min: {newKey: MinKey}, max: {newKey: MaxKey}, shard: recipientShardNames[0]}],
    },
                                              duringReshardingFn,
                                              {
                                                  expectedErrorCode: expectedErrorCode,
                                              });

    assertCommandsSucceedAfterReshardingOpFinishes(mongos.getDB(databaseName));
    assert.commandWorked(sourceCollection.dropIndex(indexCreatedByTest));
};

// Tests that the prohibited commands work if the resharding operation is aborted.
withReshardingInBackground(() => {
    waitUntilReshardingInitializedOnDonor();

    assert.commandWorked(mongos.adminCommand({abortReshardCollection: sourceNamespace}));
}, {
    expectedErrorCode: ErrorCodes.ReshardCollectionAborted,
});

// Tests that the prohibited commands succeed if the resharding operation succeeds. During the
// operation it makes sures that the prohibited commands are rejected during the resharding
// operation.
withReshardingInBackground(() => {
    waitUntilReshardingInitializedOnDonor();

    jsTest.log(
        "About to test that the admin commands do not work while the resharding operation is in progress.");
    assert.commandFailedWithCode(
        mongos.adminCommand(
            {moveChunk: sourceNamespace, find: {oldKey: -10}, to: donorShardNames[1]}),
        ErrorCodes.LockBusy);
    assert.commandFailedWithCode(
        mongos.adminCommand({reshardCollection: otherNamespace, key: {newKey: 1}}),
        ErrorCodes.ReshardCollectionInProgress);

    assertCommandsFailDuringReshardingOp(sourceCollection.getDB());
}, {
    setup: () => {
        assert.commandWorked(mongos.adminCommand({enableSharding: otherDatabaseName}));
        assert.commandWorked(
            mongos.adminCommand({shardCollection: otherNamespace, key: {oldKey: 1}}));
    }
});

reshardingTest.teardown();
})();