1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
|
// @tags: [requires_persistence, requires_journaling]
(function() {
"use strict";
const name = "query_yields_catch_index_corruption";
const dbpath = MongoRunner.dataPath + name + "/";
resetDbpath(dbpath);
let mongod = MongoRunner.runMongod({dbpath: dbpath});
assert.neq(null, mongod, "mongod failed to start.");
let db = mongod.getDB("test");
assert.commandWorked(db.adminCommand({
configureFailPoint: "skipUnindexingDocumentWhenDeleted",
mode: "alwaysOn",
data: {indexName: "a_1"}
}));
let coll = db.getCollection(name);
coll.drop();
assert.commandWorked(coll.createIndex({a: 1}));
// Corrupt the collection by inserting a document and then deleting it without deleting its index
// entry (thanks to the "skipUnindexingDocumentWhenDeleted" failpoint).
function createDanglingIndexEntry(doc) {
assert.commandWorked(coll.insert(doc));
assert.commandWorked(coll.remove(doc));
// Validation should now fail.
const validateRes = assert.commandWorked(coll.validate());
assert.eq(false, validateRes.valid);
// A query that accesses the now dangling index entry should fail with a
// "DataCorruptionDetected" error.
const error = assert.throws(() => coll.find(doc).toArray());
assert.eq(error.code, ErrorCodes.DataCorruptionDetected, error);
}
createDanglingIndexEntry({a: 1});
// Fix the index by rebuilding it, and ensure that it validates.
assert.commandWorked(coll.dropIndex({a: 1}));
assert.commandWorked(coll.createIndex({a: 1}));
let validateRes = assert.commandWorked(coll.validate());
assert.eq(true, validateRes.valid, tojson(validateRes));
// Reintroduce the dangling index entry, and this time fix it using the "repair" flag.
createDanglingIndexEntry({a: 1});
MongoRunner.stopMongod(mongod, MongoRunner.EXIT_CLEAN, {skipValidation: true});
mongod = MongoRunner.runMongod({dbpath: dbpath, noCleanData: true, repair: ""});
assert.eq(null, mongod, "Expect this to exit cleanly");
// Verify that the server starts up successfully after the repair and that validate() now succeeds.
mongod = MongoRunner.runMongod({dbpath: dbpath, noCleanData: true});
assert.neq(null, mongod, "mongod failed to start after repair");
db = mongod.getDB("test");
coll = db.getCollection(name);
validateRes = assert.commandWorked(coll.validate());
assert.eq(true, validateRes.valid, tojson(validateRes));
MongoRunner.stopMongod(mongod);
})();
|