mongo/jstests/replsets/dbcheck/dbcheck_missing_key_range_c...

125 lines
5.1 KiB
JavaScript

/**
* Tests missing index keys check in dbCheck with ranges specified. Primary and secondary will have
* index inconsistencies for different docs, and dbCheck will miss detecting these inconsistencies
* if the doc is outside of the range specified in the dbCheck invocation.
*
* @tags: [
* requires_fcv_80
* ]
*/
import {configureFailPoint} from "jstests/libs/fail_point_util.js";
import {ReplSetTest} from "jstests/libs/replsettest.js";
import {checkHealthLog, clearHealthLog, runDbCheck} from "jstests/replsets/libs/dbcheck_utils.js";
// Skipping data consistency checks because data is inserted into primary and secondary separately.
TestData.skipCollectionAndIndexValidation = true;
TestData.skipCheckDBHashes = true;
const rst = new ReplSetTest({name: jsTestName(), nodes: 2});
rst.startSet();
rst.initiate();
const dbName = "dbCheckRangeMissingKeys";
const collName = "testColl";
const primary = rst.getPrimary();
const primaryDb = primary.getDB(dbName);
const secondary = rst.getSecondary();
const secondaryDb = secondary.getDB(dbName);
const primaryHealthLog = primary.getDB("local").system.healthlog;
const secondaryHealthLog = secondary.getDB("local").system.healthlog;
const errQuery = {
operation: "dbCheckBatch",
severity: "error",
};
const missingKeyErrQuery = {
...errQuery,
msg: "Document has missing index keys",
};
function runTestWithCollOpts(collOpts) {
jsTestLog("Running dbcheck missing key range check with collection options: " + tojson(collOpts));
primaryDb[collName].drop();
assert.commandWorked(primaryDb.createCollection(collName, collOpts));
assert.commandWorked(
primaryDb.runCommand({
createIndexes: collName,
indexes: [{key: {a: 1}, name: "a_1"}],
}),
);
rst.awaitReplication();
// Insert docs with _id from 0 to 100. The doc with _id: 25 will be missing index keys on the
// primary and the doc with _id: 75 will be missing index keys on the secondary.
const numDocs = 100;
let skipIndexingFp;
for (let i = 0; i < numDocs; i++) {
if (i === 25) {
// Skip indexing the doc with _id: 25 on the primary.
skipIndexingFp = configureFailPoint(primaryDb, "skipIndexNewRecords", {skipIdIndex: false});
} else if (i === 75) {
// Skip indexing the doc with _id: 75 on the primary.
skipIndexingFp = configureFailPoint(secondaryDb, "skipIndexNewRecords", {skipIdIndex: false});
}
assert.commandWorked(primaryDb[collName].insert({_id: i, a: i}));
// We need to wait the insert to be applied on secondary to make sure there is exactly one
// index skipped.
rst.awaitReplication();
if (skipIndexingFp) {
skipIndexingFp.off();
skipIndexingFp = null;
}
}
rst.awaitReplication();
function runTest(start, end, numExpectedErrorsPrimary, numExpectedErrorsSecondary) {
// Run dbCheck on the specified range.
runDbCheck(rst, primaryDb, collName, {
maxDocsPerBatch: 10,
validateMode: "dataConsistencyAndMissingIndexKeysCheck",
start: {_id: start},
end: {_id: end},
});
// Inconsistency detected on primary but not secondary.
checkHealthLog(primaryHealthLog, errQuery, numExpectedErrorsPrimary);
checkHealthLog(primaryHealthLog, missingKeyErrQuery, numExpectedErrorsPrimary);
checkHealthLog(secondaryHealthLog, errQuery, numExpectedErrorsSecondary);
checkHealthLog(secondaryHealthLog, missingKeyErrQuery, numExpectedErrorsSecondary);
clearHealthLog(rst);
}
jsTestLog("Run dbCheck on the full range");
runTest(0, 100, 1 /* numExpectedErrorsPrimary */, 1 /* numExpectedErrorsSecondary */);
jsTestLog("Run dbCheck on a range without any inconsistencies.");
runTest(0, 24, 0 /* numExpectedErrorsPrimary */, 0 /* numExpectedErrorsSecondary */);
jsTestLog("Run dbCheck on a range that would detect only the primary inconsistency.");
runTest(0, 50, 1 /* numExpectedErrorsPrimary */, 0 /* numExpectedErrorsSecondary */);
jsTestLog("Run dbCheck on a range that would detect only the secondary inconsistency.");
runTest(50, 100, 0 /* numExpectedErrorsPrimary */, 1 /* numExpectedErrorsSecondary */);
jsTestLog("Run dbCheck with the range specified starting/ending with the missing index key on primary");
runTest(24, 25, 1 /* numExpectedErrorsPrimary */, 0 /* numExpectedErrorsSecondary */);
jsTestLog("Run dbCheck with the range specified starting/ending with the missing index key on secondary");
runTest(74, 75, 0 /* numExpectedErrorsPrimary */, 1 /* numExpectedErrorsSecondary */);
jsTestLog("Run dbCheck when the start/end range does not exist in the collection");
runTest(-1, 50, 1 /* numExpectedErrorsPrimary */, 0 /* numExpectedErrorsSecondary */);
runTest(50, 101, 0 /* numExpectedErrorsPrimary */, 1 /* numExpectedErrorsSecondary */);
runTest(101, 201, 0 /* numExpectedErrorsPrimary */, 0 /* numExpectedErrorsSecondary */);
}
[{}, {clusteredIndex: {key: {_id: 1}, unique: true}}].forEach((collOpts) => {
runTestWithCollOpts(collOpts);
});
rst.stopSet();