summaryrefslogtreecommitdiff
path: root/jstests/sharding/run_restore.js
blob: d16560f8725286c6c00a46a8679015f6fe70bc90 (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
167
168
169
/**
 * Tests that the "_configsvrRunRestore" command removes documents in config collections not
 * referenced in the "local.system.collections_to_restore" collection.
 *
 * @tags: [
 *      requires_persistence,
 * ]
 */
(function() {
"use strict";

load("jstests/libs/feature_flag_util.js");

const s =
    new ShardingTest({name: "runRestore", shards: 2, mongos: 1, config: 1, other: {chunkSize: 1}});

let mongos = s.s0;
let db = s.getDB("test");
if (!FeatureFlagUtil.isEnabled(s.configRS.getPrimary().getDB("test"), "SelectiveBackup")) {
    jsTestLog("Skipping as featureFlagSelectiveBackup is not enabled");
    s.stop();
    return;
}

s.adminCommand({enablesharding: "test"});
s.ensurePrimaryShard("test", s.shard1.shardName);
s.adminCommand({shardcollection: "test.a", key: {x: 1}});
s.adminCommand({shardcollection: "test.b", key: {x: 1}});

s.adminCommand({enablesharding: "unusedDB"});
s.ensurePrimaryShard("unusedDB", s.shard0.shardName);

let primary = s.getPrimaryShard("test").getDB("test");
let primaryName = s.getPrimaryShard("test").shardName;

let secondary = s.getOther(primary).getDB("test");
let secondaryName = s.getOther(primary).shardName;

for (let i = 0; i < 6; i++) {
    assert.commandWorked(db.getCollection("a").insert({x: i}));
    assert.commandWorked(db.getCollection("b").insert({x: i}));

    // Split chunks we just inserted.
    assert.commandWorked(mongos.adminCommand({split: "test.a", middle: {x: i}}));
    assert.commandWorked(mongos.adminCommand({split: "test.b", middle: {x: i}}));
}

const aCollUUID =
    mongos.getDB("config").getCollection("collections").find({_id: "test.a"}).toArray()[0].uuid;
const bCollUUID =
    mongos.getDB("config").getCollection("collections").find({_id: "test.b"}).toArray()[0].uuid;

for (const uuid of [aCollUUID, bCollUUID]) {
    assert.eq(7,
              mongos.getDB("config")
                  .getCollection("chunks")
                  .find({uuid: uuid, shard: primaryName})
                  .count());
    assert.eq(0,
              mongos.getDB("config")
                  .getCollection("chunks")
                  .find({uuid: uuid, shard: secondaryName})
                  .count());
}

// Move chunks between shards.
for (const x of [0, 2, 4]) {
    assert.commandWorked(s.s0.adminCommand(
        {moveChunk: "test.a", find: {x: x}, to: secondary.getMongo().name, _waitForDelete: true}));
    assert.commandWorked(s.s0.adminCommand(
        {moveChunk: "test.b", find: {x: x}, to: secondary.getMongo().name, _waitForDelete: true}));
}

// Check config collection counts.
for (const uuid of [aCollUUID, bCollUUID]) {
    assert.eq(4,
              mongos.getDB("config")
                  .getCollection("chunks")
                  .find({uuid: uuid, shard: primaryName})
                  .count());
    assert.eq(3,
              mongos.getDB("config")
                  .getCollection("chunks")
                  .find({uuid: uuid, shard: secondaryName})
                  .count());
}

assert.eq(1, mongos.getDB("config").getCollection("collections").find({_id: "test.a"}).count());
assert.eq(1, mongos.getDB("config").getCollection("collections").find({_id: "test.b"}).count());

assert.eq(1, mongos.getDB("config").getCollection("databases").find({_id: "test"}).count());

assert.eq(1, mongos.getDB("config").getCollection("databases").find({_id: "unusedDB"}).count());

s.stop({noCleanData: true});

const configDbPath = s.c0.dbpath;

// Start the config server in standalone mode.
let conn = MongoRunner.runMongod({noCleanData: true, dbpath: configDbPath});
assert(conn);

// Can't run the "_configsvrRunRestore" command without --restore.
assert.commandFailedWithCode(conn.getDB("admin").runCommand({_configsvrRunRestore: 1}),
                             ErrorCodes.CommandFailed);

MongoRunner.stopMongod(conn);

// Start the config server in standalone restore mode.
conn = MongoRunner.runMongod({noCleanData: true, dbpath: configDbPath, restore: ""});
assert(conn);

assert.commandWorked(conn.getDB("admin").runCommand({setParameter: 1, logLevel: 1}));

// Can't run if the "local.system.collections_to_restore" collection is missing.
assert.commandFailedWithCode(conn.getDB("admin").runCommand({_configsvrRunRestore: 1}),
                             ErrorCodes.NamespaceNotFound);

let [_, uuidStr] = aCollUUID.toString().match(/"((?:\\.|[^"\\])*)"/);
assert.commandWorked(conn.getDB("local").getCollection("system.collections_to_restore").insert({
    ns: "test.a",
    uuid: uuidStr
}));

// The "local.system.collections_to_restore" collection must have UUID as the correct type.
assert.commandFailedWithCode(conn.getDB("admin").runCommand({_configsvrRunRestore: 1}),
                             ErrorCodes.BadValue);

// Recreate the "local.system.collections_to_restore" collection and insert 'test.a'.
assert(conn.getDB("local").getCollection("system.collections_to_restore").drop());
assert.commandWorked(conn.getDB("local").createCollection("system.collections_to_restore"));

assert.commandWorked(conn.getDB("local").getCollection("system.collections_to_restore").insert({
    ns: "test.a",
    uuid: aCollUUID
}));

assert.commandWorked(conn.getDB("admin").runCommand({_configsvrRunRestore: 1}));

assert.eq(4,
          conn.getDB("config")
              .getCollection("chunks")
              .find({uuid: aCollUUID, shard: primaryName})
              .count());
assert.eq(3,
          conn.getDB("config")
              .getCollection("chunks")
              .find({uuid: aCollUUID, shard: secondaryName})
              .count());

assert.eq(0,
          conn.getDB("config")
              .getCollection("chunks")
              .find({uuid: bCollUUID, shard: primaryName})
              .count());
assert.eq(0,
          conn.getDB("config")
              .getCollection("chunks")
              .find({uuid: bCollUUID, shard: secondaryName})
              .count());

assert.eq(1, conn.getDB("config").getCollection("collections").find({_id: "test.a"}).count());
assert.eq(0, conn.getDB("config").getCollection("collections").find({_id: "test.b"}).count());

assert.eq(1, conn.getDB("config").getCollection("databases").find({_id: "test"}).count());
assert.eq(0, conn.getDB("config").getCollection("databases").find({_id: "unusedDB"}).count());

MongoRunner.stopMongod(conn);
}());