summaryrefslogtreecommitdiff
path: root/jstests
diff options
context:
space:
mode:
authorGregory Wlodarek <gregory.wlodarek@mongodb.com>2022-02-28 17:33:25 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2022-03-10 00:50:28 +0000
commit92eee57af61b300246aabe70e7a5ea192af5c447 (patch)
treefed1d864b02d0bdd4a904a56d76950c3a96ea71b /jstests
parent0c242cb6ac5d61100cdcaee7f4533de7c2307d25 (diff)
downloadmongo-92eee57af61b300246aabe70e7a5ea192af5c447.tar.gz
SERVER-62613 Implement _configsvrRunRestore to remove documents in the config server for collections not restored
Diffstat (limited to 'jstests')
-rw-r--r--jstests/core/views/views_all_commands.js1
-rw-r--r--jstests/replsets/db_reads_while_recovering_all_commands.js1
-rw-r--r--jstests/sharding/read_write_concern_defaults_application.js1
-rw-r--r--jstests/sharding/run_restore.js162
4 files changed, 165 insertions, 0 deletions
diff --git a/jstests/core/views/views_all_commands.js b/jstests/core/views/views_all_commands.js
index 8996ec0243d..d55c4f07f1f 100644
--- a/jstests/core/views/views_all_commands.js
+++ b/jstests/core/views/views_all_commands.js
@@ -114,6 +114,7 @@ let viewsCommandTests = {
_configsvrRemoveTags: {skip: isAnInternalCommand},
_configsvrRepairShardedCollectionChunksHistory: {skip: isAnInternalCommand},
_configsvrReshardCollection: {skip: isAnInternalCommand},
+ _configsvrRunRestore: {skip: isAnInternalCommand},
_configsvrSetAllowMigrations: {skip: isAnInternalCommand},
_configsvrSetClusterParameter: {skip: isAnInternalCommand},
_configsvrSetUserWriteBlockMode: {skip: isAnInternalCommand},
diff --git a/jstests/replsets/db_reads_while_recovering_all_commands.js b/jstests/replsets/db_reads_while_recovering_all_commands.js
index eca3081b7b9..8c884d6e9c5 100644
--- a/jstests/replsets/db_reads_while_recovering_all_commands.js
+++ b/jstests/replsets/db_reads_while_recovering_all_commands.js
@@ -51,6 +51,7 @@ const allCommands = {
_configsvrRepairShardedCollectionChunksHistory: {skip: isPrimaryOnly},
_configsvrRenameCollectionMetadata: {skip: isPrimaryOnly},
_configsvrReshardCollection: {skip: isPrimaryOnly},
+ _configsvrRunRestore: {skip: isPrimaryOnly},
_configsvrSetAllowMigrations: {skip: isPrimaryOnly},
_configsvrSetClusterParameter: {skip: isPrimaryOnly},
_configsvrSetUserWriteBlockMode: {skip: isPrimaryOnly},
diff --git a/jstests/sharding/read_write_concern_defaults_application.js b/jstests/sharding/read_write_concern_defaults_application.js
index 97ab87c0de1..b43c17181c4 100644
--- a/jstests/sharding/read_write_concern_defaults_application.js
+++ b/jstests/sharding/read_write_concern_defaults_application.js
@@ -117,6 +117,7 @@ let testCases = {
_configsvrRenameCollectionMetadata: {skip: "internal command"},
_configsvrRepairShardedCollectionChunksHistory: {skip: "internal command"},
_configsvrReshardCollection: {skip: "internal command"},
+ _configsvrRunRestore: {skip: "internal command"},
_configsvrSetAllowMigrations: {skip: "internal command"},
_configsvrSetClusterParameter: {skip: "internal command"},
_configsvrSetUserWriteBlockMode: {skip: "internal command"},
diff --git a/jstests/sharding/run_restore.js b/jstests/sharding/run_restore.js
new file mode 100644
index 00000000000..a314c2bca58
--- /dev/null
+++ b/jstests/sharding/run_restore.js
@@ -0,0 +1,162 @@
+/**
+ * Tests that the "_configsvrRunRestore" command removes documents in config collections not
+ * referenced in the "local.system.collections_to_restore" collection.
+ */
+(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(db, "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("locks").find({_id: "test"}).count());
+assert.eq(1, mongos.getDB("config").getCollection("locks").find({_id: "test.a"}).count());
+assert.eq(1, mongos.getDB("config").getCollection("locks").find({_id: "test.b"}).count());
+assert.eq(1, mongos.getDB("config").getCollection("locks").find({_id: "unusedDB"}).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);
+
+// Create the "local.system.collections_to_restore" collection and insert "test.a".
+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("locks").find({_id: "test"}).count());
+assert.eq(1, conn.getDB("config").getCollection("locks").find({_id: "test.a"}).count());
+assert.eq(0, conn.getDB("config").getCollection("locks").find({_id: "test.b"}).count());
+assert.eq(0, conn.getDB("config").getCollection("locks").find({_id: "unusedDB"}).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);
+}());