mirror of https://github.com/mongodb/mongo
125 lines
5.1 KiB
JavaScript
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();
|