mongo/jstests/sharding/drop_database.js

399 lines
14 KiB
JavaScript

/**
* Test dropDatabase command in a sharded cluster.
*/
import {ShardingTest} from "jstests/libs/shardingtest.js";
let st = new ShardingTest({shards: 2});
let configDB = st.s.getDB("config");
const dbNamePrefix = "testDropDB";
let dbCounter = 0;
function getNewDb() {
return st.s.getDB(dbNamePrefix + "_" + dbCounter++);
}
function getPrefixRegExp(prefix) {
return RegExp("^" + RegExp.escape(prefix) + ".*");
}
function getDbPrefixRegExp(dbName) {
return getPrefixRegExp(dbName + ".");
}
function listDatabases(options) {
return assert.commandWorked(st.s.adminCommand(Object.assign({listDatabases: 1}, options))).databases;
}
function assertDatabaseExists(dbName) {
// Check that listDatabase return the db
assert.gte(1, listDatabases({nameOnly: true, filter: {name: dbName}}).length);
// Database entry exists
assert.eq(1, configDB.databases.countDocuments({_id: dbName}));
}
function assertDatabaseDropped(dbName) {
// Check that listDatabase doesn't return the db
assert.eq(0, listDatabases({nameOnly: true, filter: {name: dbName}}).length);
// No more database entry
assert.eq(0, configDB.databases.countDocuments({_id: dbName}));
// No more tags for this database
assert.eq(0, configDB.tags.countDocuments({ns: getDbPrefixRegExp(dbName)}));
// Check dropped collections.
assert.eq(0, configDB.collections.countDocuments({_id: getDbPrefixRegExp(dbName)}));
}
jsTest.log("Test that dropping admin/config DB is illegal");
{
assert.commandFailedWithCode(st.s.getDB("admin").dropDatabase(), ErrorCodes.IllegalOperation);
assert.commandFailedWithCode(st.s.getDB("config").dropDatabase(), ErrorCodes.IllegalOperation);
}
jsTest.log("Test dropping unexistent database");
{
const db = getNewDb();
// Dropping a database that doesn't exist will result in an info field in the response.
const res = assert.commandWorked(db.dropDatabase());
assertDatabaseDropped(db.getName());
}
jsTest.log("Test dropping unsharded database");
{
const db = getNewDb();
// Create the database
assert.commandWorked(db.foo.insert({}));
assertDatabaseExists(db.getName());
// Drop the database
assert.commandWorked(db.dropDatabase());
assertDatabaseDropped(db.getName());
// Test drop database idempotency
assert.commandWorked(db.dropDatabase());
assertDatabaseDropped(db.getName());
}
jsTest.log("Test dropping unsharded database with multiple collections");
{
const db = getNewDb();
// Create 3 unsharded collection
const colls = Array.from({length: 3}, (_, i) => db["unshardedColl_" + i]);
colls.forEach((coll) => coll.insert({}));
// Create the database
assertDatabaseExists(db.getName());
// Drop the database
assert.commandWorked(db.dropDatabase());
assertDatabaseDropped(db.getName());
}
jsTest.log("Test dropping sharded database");
{
const db = getNewDb();
// Create the database
st.s.adminCommand({enableSharding: db.getName()});
assertDatabaseExists(db.getName());
// Drop the database
assert.commandWorked(db.dropDatabase());
assertDatabaseDropped(db.getName());
// Test drop database idempotency
assert.commandWorked(db.dropDatabase());
assertDatabaseDropped(db.getName());
}
jsTest.log("Test dropping database that contains regex characters");
// Original bugs [SERVER-4954, SERVER-4955]
{
const db = st.s.getDB("onlysmallcaseletters");
assert.commandWorked(st.s.adminCommand({enablesharding: db.getName(), primaryShard: st.shard1.shardName}));
st.shardColl(db["data"], {num: 1});
assertDatabaseExists(db.getName());
const specialDB = st.s.getDB("[a-z]+");
const specialColl = db["special"];
assert.commandWorked(st.s.adminCommand({enablesharding: specialDB.getName(), primaryShard: st.shard0.shardName}));
assertDatabaseExists(specialDB.getName());
st.shardColl(specialColl, {num: 1});
assert(specialColl.exists());
// Drop special database
assert.commandWorked(specialDB.dropDatabase());
assertDatabaseDropped(specialDB.getName());
// The normal database still exists
assertDatabaseExists(db.getName());
// Drop also the normal database
assert.commandWorked(db.dropDatabase());
assertDatabaseDropped(db.getName());
}
jsTest.log("Test dropping sharded database with multiple collections");
{
const db = getNewDb();
const unshardedColls = Array.from({length: 3}, (_, i) => db["unshardedColl_" + i]);
unshardedColls.forEach((coll) => coll.insert({}));
const shardedColls = Array.from({length: 3}, (_, i) => db["shardedColl_" + i]);
shardedColls.forEach((coll) => st.shardColl(coll, {_id: 1}));
// Create the database
st.s.adminCommand({enableSharding: db.getName()});
assertDatabaseExists(db.getName());
// Drop the database
assert.commandWorked(db.dropDatabase());
assertDatabaseDropped(db.getName());
}
jsTest.log("Tests that dropping a database also removes the zones associated with the collections in the database.");
{
const db = getNewDb();
const coll = db["sharededColl"];
const zoneName = "zone";
assert.commandWorked(st.s.adminCommand({addShardToZone: st.shard0.shardName, zone: zoneName}));
st.shardColl(coll, {x: 1});
assertDatabaseExists(db.getName());
assert.commandWorked(
st.s.adminCommand({updateZoneKeyRange: coll.getFullName(), min: {x: 0}, max: {x: 10}, zone: zoneName}),
);
assert.eq(1, configDB.tags.countDocuments({ns: getDbPrefixRegExp(db.getName())}));
// Drop the database
assert.commandWorked(db.dropDatabase());
assertDatabaseDropped(db.getName());
}
{
const db = getNewDb();
const conn = st.rs0.getPrimary().getDB(db.getName());
const fcvDoc = conn.adminCommand({getParameter: 1, featureCompatibilityVersion: 1});
if (MongoRunner.compareBinVersions(fcvDoc.featureCompatibilityVersion.version, "6.3") >= 0) {
jsTest.log(
"Tests that dropping a database also removes all associated zones for nonexisting and " +
"unsharded collections.",
);
{
const coll = db["shardedColl"];
const unshardedColl = db["unshardedColl"];
const zoneName = "zone";
st.shardColl(coll, {x: 1});
assertDatabaseExists(db.getName());
// Create an unsharded collection
assert.commandWorked(unshardedColl.insert({x: 3}));
// Append zones for a sharded collection, unsharded collection, a nonexisting collection
// and a collection from another database.
st.addShardTag(st.shard0.shardName, zoneName);
assert.commandWorked(
st.s.adminCommand({
updateZoneKeyRange: coll.getFullName(),
min: {x: 0},
max: {x: 10},
zone: zoneName,
}),
);
assert.commandWorked(
st.s.adminCommand({
updateZoneKeyRange: unshardedColl.getFullName(),
min: {x: 10},
max: {x: 15},
zone: zoneName,
}),
);
assert.commandWorked(
st.s.adminCommand({
updateZoneKeyRange: db.getName() + ".nonexisting",
min: {x: 15},
max: {x: 20},
zone: zoneName,
}),
);
assert.commandWorked(
st.s.adminCommand({updateZoneKeyRange: "otherDb.coll", min: {x: 20}, max: {x: 25}, zone: zoneName}),
);
// Assert that has been added some entries on 'config.tags'
assert.eq(3, configDB.tags.countDocuments({ns: getDbPrefixRegExp(db.getName())}));
// Drop the database
assert.commandWorked(db.dropDatabase());
assertDatabaseDropped(db.getName());
// Assert that there are no zones left for database
assert.eq(0, configDB.tags.countDocuments({ns: getDbPrefixRegExp(db.getName())}));
// Assert that there is one zone from another database that has not been deleted.
assert.eq(1, configDB.tags.countDocuments({ns: getDbPrefixRegExp("otherDb")}));
}
}
}
{
const db = st.s.getDB("db[a-z]+");
const conn = st.rs0.getPrimary().getDB(db.getName());
const fcvDoc = conn.adminCommand({getParameter: 1, featureCompatibilityVersion: 1});
if (MongoRunner.compareBinVersions(fcvDoc.featureCompatibilityVersion.version, "6.3") >= 0) {
jsTest.log(
"Tests that dropping a database with regex characters also removes all associated " +
"zones for nonexisting and unsharded collections.",
);
{
const coll = db["shardedColl"];
const unshardedColl = db["unshardedColl"];
const zoneName = "zone";
st.shardColl(coll, {x: 1});
assertDatabaseExists(db.getName());
// Create an unsharded collection
assert.commandWorked(unshardedColl.insert({x: 3}));
// Append zones for a sharded collection, unsharded collection, a nonexisting collection
// and a collection from another database.
st.addShardTag(st.shard0.shardName, zoneName);
assert.commandWorked(
st.s.adminCommand({
updateZoneKeyRange: coll.getFullName(),
min: {x: 0},
max: {x: 10},
zone: zoneName,
}),
);
assert.commandWorked(
st.s.adminCommand({
updateZoneKeyRange: unshardedColl.getFullName(),
min: {x: 10},
max: {x: 15},
zone: zoneName,
}),
);
assert.commandWorked(
st.s.adminCommand({
updateZoneKeyRange: db.getName() + ".nonexisting",
min: {x: 15},
max: {x: 20},
zone: zoneName,
}),
);
assert.commandWorked(
st.s.adminCommand({
updateZoneKeyRange: "otherDbRegex.coll",
min: {x: 20},
max: {x: 25},
zone: zoneName,
}),
);
// Assert that has been added some entries on 'config.tags'
assert.eq(3, configDB.tags.countDocuments({ns: getDbPrefixRegExp(db.getName())}));
// Drop the database
assert.commandWorked(db.dropDatabase());
assertDatabaseDropped(db.getName());
// Assert that there are no zones left for database
assert.eq(0, configDB.tags.countDocuments({ns: getDbPrefixRegExp(db.getName())}));
// Assert that there is one zone from another database that has not been deleted.
assert.eq(1, configDB.tags.countDocuments({ns: getDbPrefixRegExp("otherDbRegex")}));
}
}
}
jsTest.log("Tests that dropping a database doesn't affects other database with the same prefix.");
// Original bug SERVER-3471
{
// Create 3 DBs
// - SomePrefix
// - SomePrefix_A
// - SomePrefix_b
const dbPrefix = dbNamePrefix + "Prefix";
const databases = [st.s.getDB(dbPrefix), st.s.getDB(dbPrefix + "_A"), st.s.getDB(dbPrefix + "_B")];
// Assert all database have the same prefix
assert.containsPrefix(
dbNamePrefix,
databases.map((db) => db.getName()),
);
const collPrefix = "coll_";
const numColls = 3;
const numDocs = 3;
// Create 3 colls with 3 documents on each database
databases.forEach((db) => {
for (let collID = 0; collID < numColls; collID++) {
let coll = db[collPrefix + collID];
// Create 3 documents for each collection
for (let docID = 0; docID < numDocs; docID++) {
coll.insert({_id: docID});
}
// shard the collection
st.shardColl(coll, {_id: 1});
}
assertDatabaseExists(db.getName());
});
// Insert a document to an unsharded collection and make sure that the document is there.
const unshardedColl = databases[0]["unshardedColl"];
assert.commandWorked(unshardedColl.insert({dummy: 1}));
assert.eq(1, unshardedColl.countDocuments({dummy: 1}));
// Drop the non-suffixed db
assert.commandWorked(databases[0].dropDatabase());
assertDatabaseDropped(databases[0].getName());
assert.eq(0, unshardedColl.countDocuments({}));
// Ensure that the others databases exists and still contains all the collections
databases.slice(1).forEach((db) => {
assertDatabaseExists(db.getName());
assert.eq(numColls, configDB.collections.countDocuments({_id: getDbPrefixRegExp(db.getName())}));
// Assert that all the collections still have all the documents
for (let collID = 0; collID < numColls; collID++) {
assert.eq(numDocs, db[collPrefix + collID].countDocuments({}));
}
});
}
jsTest.log("Test that dropping a non-sharded database, relevant events are properly logged on CSRS");
{
// Create a non-sharded database
const db = getNewDb();
assert.commandWorked(db.foo.insert({}));
// Drop the database
assert.commandWorked(db.dropDatabase());
// Verify that the drop database start event has been logged
const startLogCount = configDB.changelog.countDocuments({what: "dropDatabase.start", ns: db.getName()});
assert.gte(startLogCount, 1, "dropDatabase start event not found in changelog");
// Verify that the drop database end event has been logged
const endLogCount = configDB.changelog.countDocuments({what: "dropDatabase", ns: db.getName()});
assert.gte(endLogCount, 1, "dropDatabase end event not found in changelog");
}
jsTest.log("Test that dropping a sharded database, relevant events are properly logged on CSRS");
{
// Create a sharded database
const db = getNewDb();
st.s.adminCommand({enableSharding: db.getName()});
// Drop the database
assert.commandWorked(db.dropDatabase());
// Verify that the drop database start event has been logged
const startLogCount = configDB.changelog.countDocuments({what: "dropDatabase.start", ns: db.getName()});
assert.gte(startLogCount, 1, "dropDatabase start event not found in changelog");
// Verify that the drop database end event has been logged
const endLogCount = configDB.changelog.countDocuments({what: "dropDatabase", ns: db.getName()});
assert.gte(endLogCount, 1, "dropDatabase end event not found in changelog");
}
st.stop();