Files
mongo/jstests/sharding/clone_catalog_data.js

183 lines
6.7 KiB
JavaScript

'use strict';
// Test that the 'cloneCatalogData' command works correctly.
// Eventually, _shardsvrMovePrimary will use this command.
(() => {
function sortByName(a, b) {
if (a.name < b.name)
return -1;
if (a.name > b.name)
return 1;
return 0;
}
var st = new ShardingTest({shards: 2}), testDB = st.s.getDB('test');
// Enable sharding on the test DB.
assert.commandWorked(st.s.adminCommand({enableSharding: 'test'}));
// Create two collections with non-default options.
var coll1Options = {capped: true, size: 500},
coll2Options = {validator: {$jsonSchema: {required: ['a']}}};
assert.commandWorked(testDB.createCollection('coll1', coll1Options));
assert.commandWorked(testDB.createCollection('coll2', coll2Options));
// Create some test documents and put them in each collection.
[{a: 1, b: 2, c: 4}, {a: 2, b: 4, c: 8}, {a: 3, b: 6, c: 12}].forEach(d => {
assert.commandWorked(testDB.coll1.insert(d));
assert.commandWorked(testDB.coll2.insert(d));
});
// Create indexes on each collection.
var coll1Indexes =
[
{key: {a: 1}, name: 'index1', sparse: true},
{key: {b: -1}, name: 'index2', unique: true},
],
coll2Indexes = [
{key: {a: 1, b: 1}, name: 'index3'},
{key: {c: 1}, name: 'index4'},
];
assert.commandWorked(testDB.runCommand({createIndexes: 'coll1', indexes: coll1Indexes}));
assert.commandWorked(testDB.runCommand({createIndexes: 'coll2', indexes: coll2Indexes}));
// Shard coll2, but leave coll1 unsharded.
assert.commandWorked(st.s.adminCommand({shardCollection: 'test.coll2', key: {_id: 1}}));
// Wait for the write to config.collections to be visible in the majority snapshot on all config
// secondaries, since the test directly talks to shards and so does not gossip the configOpTime
// to those shards.
st.configRS.awaitLastOpCommitted();
// Get the primary shard, and the non-primary shard.
var fromShard = st.getPrimaryShard('test');
var toShard = st.getOther(fromShard);
var res = fromShard.getDB('test').runCommand({listCollections: 1});
assert.commandWorked(res);
var collections = res.cursor.firstBatch;
collections.sort(sortByName);
var coll2uuid = collections[1].info.uuid;
// Have the other shard clone the DB from the primary.
assert.commandWorked(toShard.adminCommand(
{_shardsvrCloneCatalogData: 'test', from: fromShard.host, writeConcern: {w: "majority"}}));
// Ask the shard that just called _shardsvrCloneCatalogData for the collections.
res = toShard.getDB('test').runCommand({listCollections: 1});
assert.commandWorked(res);
collections = res.cursor.firstBatch;
// There should be 2 collections: coll1, coll2
assert.eq(collections.length, 2);
collections.sort(sortByName);
var c1, c2;
[c1, c2] = collections;
function checkName(c, expectedName) {
assert.eq(
c.name, expectedName, 'Expected collection to be ' + expectedName + ', got ' + c.name);
}
function checkOptions(c, expectedOptions) {
assert.hasFields(c, ['options'], 'Missing options field for collection ' + c.name);
assert.hasFields(
c.options, expectedOptions, 'Missing expected option(s) for collection ' + c.name);
}
function checkUUID(c, expectedUUID) {
assert.hasFields(c, ['info'], 'Missing info field for collection ' + c.name);
assert.hasFields(c.info, ['uuid'], 'Missing uuid field for collection ' + c.name);
assert.eq(c.info.uuid, expectedUUID, 'Incorrect uuid for collection ' + c.name);
}
// c1 should be coll1.
checkName(c1, 'coll1');
checkOptions(c1, Object.keys(coll1Options));
// c2 should be coll2.
checkName(c2, 'coll2');
checkOptions(c2, Object.keys(coll2Options));
checkUUID(c2, coll2uuid);
function checkIndexes(collName, expectedIndexes) {
var res = toShard.getDB('test').runCommand({listIndexes: collName});
assert.commandWorked(res, 'Failed to get indexes for collection ' + collName);
var indexes = res.cursor.firstBatch;
indexes.sort(sortByName);
// There should be 3 indexes on each collection - the _id one, and the 2 we created.
assert.eq(indexes.length, 3);
indexes.forEach((index, i) => {
var expected;
if (i == 0)
expected = {name: "_id_", key: {_id: 1}};
else
expected = expectedIndexes[i - 1];
Object.keys(expected).forEach(k => {
assert.eq(index[k], expected[k]);
});
});
}
checkIndexes('coll1', coll1Indexes);
checkIndexes('coll2', coll2Indexes);
// Verify that the data from the unsharded collections resides on the new primary shard, and was
// copied as part of the clone.
function checkCount(shard, collName, count) {
var res = shard.getDB('test').runCommand({count: collName});
assert.commandWorked(res);
assert.eq(res.n, count);
}
checkCount(fromShard, 'coll1', 3);
checkCount(fromShard, 'coll2', 3);
checkCount(toShard, 'coll1', 3);
checkCount(toShard, 'coll2', 0);
// Check that the command fails without writeConcern majority.
assert.commandFailedWithCode(
toShard.adminCommand({_shardsvrCloneCatalogData: 'test', from: fromShard.host}),
ErrorCodes.InvalidOptions);
// Check that the command fails when attempting to clone the admin database.
assert.commandFailedWithCode(toShard.adminCommand({
_shardsvrCloneCatalogData: 'admin',
from: fromShard.host,
writeConcern: {w: "majority"}
}),
ErrorCodes.InvalidOptions);
// Check that the command fails when attempting to run on the config server.
assert.commandFailedWithCode(st.configRS.getPrimary().adminCommand({
_shardsvrCloneCatalogData: 'test',
from: fromShard.host,
writeConcern: {w: "majority"}
}),
ErrorCodes.NoShardingEnabled);
// Check that the command fails when failing to specify a source.
assert.commandFailedWithCode(
toShard.adminCommand(
{_shardsvrCloneCatalogData: 'test', from: '', writeConcern: {w: "majority"}}),
ErrorCodes.InvalidOptions);
// Check that clone errors when the collection already exists on the destination.
assert.commandFailedWithCode(toShard.adminCommand({
_shardsvrCloneCatalogData: 'test',
from: fromShard.host,
writeConcern: {w: "majority"}
}),
ErrorCodes.NamespaceExists);
st.stop();
})();