mongo/jstests/sharding/all_collection_stats.js

204 lines
7.7 KiB
JavaScript

/*
* Test to validate the $_internalAllCollectionStats stage for storageStats.
*
* @tags: [
* requires_fcv_60,
* ]
*/
import {ShardingTest} from "jstests/libs/shardingtest.js";
function checkResults(aggregationPipeline, checksToDo) {
assert.soon(() => {
const results = adminDb.aggregate(aggregationPipeline).toArray();
assert.lte(numCollections, results.length);
for (let i = 0; i < numCollections; i++) {
try {
const coll = "coll" + i;
// To check that the data retrieve from $_internalAllCollectionStats is correct we
// will call $collStats for each namespace to retrieve its storage stats and compare
// the two outputs.
const expectedResults = testDb
.getCollection(coll)
.aggregate([{$collStats: {storageStats: {}}}])
.toArray();
assert.neq(null, expectedResults);
assert.eq(1, expectedResults.length);
let exists = false;
for (const data of results) {
const ns = data.ns;
if (dbName + "." + coll === ns) {
checksToDo(data, expectedResults);
exists = true;
break;
}
}
assert(exists, "Expected to have $_internalAllCollectionStats results for coll" + i);
} catch (e) {
// As we perform two logical executions of $collStats they might return different
// storageSizes since WT may have rewritten the file during a checkpoint or
// background compaction. We retry the operation as it is a transient error.
jsTest.log(e);
return false;
}
}
return true;
});
}
// Configure initial sharding cluster
const st = new ShardingTest({shards: 2});
const mongos = st.s;
const dbName = "test";
const testDb = mongos.getDB(dbName);
const adminDb = mongos.getDB("admin");
const numCollections = 4;
// Insert sharded collections to validate the aggregation stage
for (let i = 0; i < numCollections / 2; i++) {
const coll = "coll" + i;
assert(st.adminCommand({shardcollection: dbName + "." + coll, key: {skey: 1}}));
assert.commandWorked(testDb.getCollection(coll).insert({skey: i}));
}
// Insert some unsharded collections to validate the aggregation stage
for (let i = numCollections / 2; i < numCollections; i++) {
const coll = "coll" + i;
assert.commandWorked(testDb.getCollection(coll).insert({skey: i}));
}
// Testing for comparing each collection returned from $_internalAllCollectionStats to $collStats
(function testInternalAllCollectionStats() {
const aggregationPipeline = [{$_internalAllCollectionStats: {stats: {storageStats: {}}}}];
const checksToDo = (left, right) => {
const msg = "Expected same output from $_internalAllCollectionStats and $collStats " + "for same namespace";
assert.eq(left.host, right[0].host, msg);
assert.eq(left.shard, right[0].shard, msg);
assert.eq(left.storageStats.size, right[0].storageStats.size, msg);
assert.eq(left.storageStats.count, right[0].storageStats.count, msg);
assert.eq(left.storageStats.avgObjSize, right[0].storageStats.avgObjSize, msg);
assert.eq(left.storageStats.storageSize, right[0].storageStats.storageSize, msg);
assert.eq(left.storageStats.freeStorageSize, right[0].storageStats.freeStorageSize, msg);
assert.eq(left.storageStats.nindexes, right[0].storageStats.nindexes, msg);
assert.eq(left.storageStats.totalIndexSize, right[0].storageStats.totalIndexSize, msg);
assert.eq(left.storageStats.totalSize, right[0].storageStats.totalSize, msg);
};
checkResults(aggregationPipeline, checksToDo);
})();
// Tests to check the correct behaviour of a $project stage after $_internalAllCollectionStats
(function testNumOrphanDocsFieldProject() {
const aggregationPipeline = [
{$_internalAllCollectionStats: {stats: {storageStats: {}}}},
{$project: {"ns": 1, "storageStats.numOrphanDocs": 1}},
];
const checksToDo = (left, right) => {
assert.eq(
left.storageStats.numOrphanDocs,
right[0].storageStats.numOrphanDocs,
"Expected same output after a projection with storageStats.numOrphanDocs field",
);
};
checkResults(aggregationPipeline, checksToDo);
})();
(function testStorageSizeFieldProject() {
const aggregationPipeline = [
{$_internalAllCollectionStats: {stats: {storageStats: {}}}},
{$project: {"ns": 1, "storageStats.storageSize": 1}},
];
const checksToDo = (left, right) => {
assert.eq(
left.storageStats.storageSize,
right[0].storageStats.storageSize,
"Expected same output after a projection with storageStats.storageSize field",
);
};
checkResults(aggregationPipeline, checksToDo);
})();
(function testNIndexesFieldProject() {
const aggregationPipeline = [
{$_internalAllCollectionStats: {stats: {storageStats: {}}}},
{$project: {"ns": 1, "storageStats.nindexes": 1}},
];
const checksToDo = (left, right) => {
assert.eq(
left.storageStats.nindexes,
right[0].storageStats.nindexes,
"Expected same output after a projection with storageStats.nindexes field",
);
};
checkResults(aggregationPipeline, checksToDo);
})();
(function testTotalSizeFieldProject() {
const aggregationPipeline = [
{$_internalAllCollectionStats: {stats: {storageStats: {}}}},
{$project: {"ns": 1, "storageStats.totalSize": 1}},
];
const checksToDo = (left, right) => {
assert.eq(
left.storageStats.totalSize,
right[0].storageStats.totalSize,
"Expected same output after a projection with storageStats.totalSize field",
);
};
checkResults(aggregationPipeline, checksToDo);
})();
(function testProjectingDifferentFields() {
const aggregationPipeline = [
{$_internalAllCollectionStats: {stats: {storageStats: {}}}},
{
$project: {
"ns": 1,
"storageStats.numOrphanDocs": 1,
"storageStats.storageSize": 1,
"storageStats.nindexes": 1,
"storageStats.totalSize": 1,
},
},
];
const checksToDo = (left, right) => {
const msg = "Expected same output after a projection with fields from different storage " + "stats groups";
assert.eq(left.storageStats.numOrphanDocs, right[0].storageStats.numOrphanDocs, msg);
assert.eq(left.storageStats.storageSize, right[0].storageStats.storageSize, msg);
assert.eq(left.storageStats.nindexes, right[0].storageStats.nindexes, msg);
assert.eq(left.storageStats.totalSize, right[0].storageStats.totalSize, msg);
};
checkResults(aggregationPipeline, checksToDo);
})();
// Test valid query with empty specification
assert.commandWorked(adminDb.runCommand({aggregate: 1, pipeline: [{$_internalAllCollectionStats: {}}], cursor: {}}));
// Test invalid queries/values.
assert.commandFailedWithCode(
adminDb.runCommand({aggregate: 1, pipeline: [{$_internalAllCollectionStats: 3}], cursor: {}}),
6789103,
);
const response = assert.commandFailedWithCode(
testDb.runCommand({
aggregate: "foo",
pipeline: [{$_internalAllCollectionStats: {stats: {storageStats: {}}}}],
cursor: {},
}),
6789104,
);
assert.neq(-1, response.errmsg.indexOf("$_internalAllCollectionStats"), response.errmsg);
assert.neq(-1, response.errmsg.indexOf("admin database"), response.errmsg);
st.stop();