summaryrefslogtreecommitdiff
path: root/jstests/disk/wt_repair_corrupt_files.js
blob: 2c0dcd7c67543681fc9745d863bf4ff9019ff6f8 (plain)
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
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
/**
 * Tests that --repair on WiredTiger correctly and gracefully handles corrupt data files and
 * directories.
 *
 * @tags: [requires_wiredtiger]
 */

(function() {

load('jstests/disk/libs/wt_file_helper.js');

const baseName = "wt_repair_corrupt_files";
const collName = "test";
const dbpath = MongoRunner.dataPath + baseName + "/";

/**
 * Run the test by supplying additional paramters to MongoRunner.runMongod with 'mongodOptions'.
 */
let runTest = function(mongodOptions) {
    resetDbpath(dbpath);
    jsTestLog("Running test with args: " + tojson(mongodOptions));

    /**
     * Test 1. Create a collection, corrupt its .wt file in an unrecoverable way, run repair.
     * Verify that repair succeeds at rebuilding it. An empty collection should be visible on
     * normal startup.
     */

    let mongod = startMongodOnExistingPath(dbpath, mongodOptions);
    let testColl = mongod.getDB(baseName)[collName];

    const doc = {a: 1};
    assert.commandWorked(testColl.insert(doc));

    let testCollUri = getUriForColl(testColl);
    let testCollFile = dbpath + testCollUri + ".wt";

    MongoRunner.stopMongod(mongod);

    jsTestLog("corrupting collection file: " + testCollFile);
    corruptFile(testCollFile);

    assertRepairSucceeds(dbpath, mongod.port, mongodOptions);

    mongod = startMongodOnExistingPath(dbpath, mongodOptions);
    testColl = mongod.getDB(baseName)[collName];

    assert.eq(testCollUri, getUriForColl(testColl));
    assert.eq(testColl.find({}).itcount(), 0);
    assert.eq(testColl.count(), 0);

    /**
     * Test 2. Corrupt an index file in an unrecoverable way. Verify that repair rebuilds and
     * allows MongoDB to start up normally.
     */

    assert.commandWorked(testColl.insert(doc));

    const indexName = "a_1";
    assert.commandWorked(testColl.createIndex({a: 1}, {name: indexName}));
    assertQueryUsesIndex(testColl, doc, indexName);

    let indexUri = getUriForIndex(testColl, indexName);

    MongoRunner.stopMongod(mongod);

    let indexFile = dbpath + indexUri + ".wt";
    jsTestLog("corrupting index file: " + indexFile);
    corruptFile(indexFile);

    assertRepairSucceeds(dbpath, mongod.port, mongodOptions);
    mongod = startMongodOnExistingPath(dbpath, mongodOptions);
    testColl = mongod.getDB(baseName)[collName];

    // Repair creates new idents.
    assert.neq(indexUri, getUriForIndex(testColl, indexName));

    assertQueryUsesIndex(testColl, doc, indexName);
    assert.eq(testColl.find(doc).itcount(), 1);
    assert.eq(testColl.count(), 1);

    MongoRunner.stopMongod(mongod);

    /**
     * Test 3. Corrupt the _mdb_catalog in an unrecoverable way. Verify that repair suceeds
     * in creating an empty catalog and recovers the orphaned testColl, which will still be
     * accessible in the 'local.orphan-' namespace.
     */

    let mdbCatalogFile = dbpath + "_mdb_catalog.wt";
    jsTestLog("corrupting catalog file: " + mdbCatalogFile);
    corruptFile(mdbCatalogFile);

    assertRepairSucceeds(dbpath, mongod.port, mongodOptions);

    mongod = startMongodOnExistingPath(dbpath, mongodOptions);
    testColl = mongod.getDB(baseName)[collName];
    assert.isnull(testColl.exists());
    assert.eq(testColl.find(doc).itcount(), 0);
    assert.eq(testColl.count(), 0);

    // Ensure the collection orphan was created with the existing document.
    const orphanCollName = "orphan." + testCollUri.replace(/-/g, "_");
    let orphanColl = mongod.getDB('local').getCollection(orphanCollName);
    assert(orphanColl.exists());
    assert.eq(orphanColl.find(doc).itcount(), 1);
    assert.eq(orphanColl.count(), 1);

    MongoRunner.stopMongod(mongod);

    /**
     * Test 4. Create two collections, and an index on each. Corrupt one collection's .wt file
     * in an unrecoverable way, leave the other as is, then run repair.
     * Verify that repair rebuilds the index on the corrupted collection but does not rebuild
     * the index on the unaffected collection.
     */

    let createIndexedColl = function(collName) {
        let coll = mongod.getDB(baseName)[collName];
        assert.commandWorked(coll.insert(doc));
        assert.commandWorked(coll.createIndex({a: 1}, {name: indexName}));
        assertQueryUsesIndex(coll, doc, indexName);
        return coll;
    };

    const corruptedCollName = "corrupted_coll";
    const healthyCollName = "healthy_coll";

    mongod = startMongodOnExistingPath(dbpath, mongodOptions);

    let corruptedColl = createIndexedColl(corruptedCollName);
    let corruptedOriginalIndexUri = getUriForIndex(corruptedColl, indexName);
    let corruptedCollUri = getUriForColl(corruptedColl);

    let healthyColl = createIndexedColl(healthyCollName);
    let healthyIndexUri = getUriForIndex(healthyColl, indexName);
    let healthyCollUri = getUriForColl(healthyColl);

    let corruptedCollFile = dbpath + corruptedCollUri + ".wt";

    MongoRunner.stopMongod(mongod);

    jsTestLog("corrupting collection file: " + corruptedCollFile);
    corruptFile(corruptedCollFile);

    assertRepairSucceeds(dbpath, mongod.port, mongodOptions);
    mongod = startMongodOnExistingPath(dbpath, mongodOptions);

    corruptedColl = mongod.getDB(baseName)[corruptedCollName];
    healthyColl = mongod.getDB(baseName)[healthyCollName];

    assert.neq(corruptedOriginalIndexUri, getUriForIndex(corruptedColl, indexName));
    assert.eq(healthyIndexUri, getUriForIndex(healthyColl, indexName));

    MongoRunner.stopMongod(mongod);

    /**
     * Test 5. Corrupt the WiredTigerHS file in an unrecoverable way. Run repair and verify that
     * MongoDB was rebuilt properly and starts up normally.
     */

    let corruptedWiredTigerHSFile = dbpath + "WiredTigerHS.wt";
    jsTestLog("corrupting WT History Store file: " + corruptedWiredTigerHSFile);
    corruptFile(corruptedWiredTigerHSFile);

    assertRepairFails(dbpath, mongod.port);
    assertErrorOnStartupAfterIncompleteRepair(dbpath, mongod.port);
};

runTest({});
runTest({directoryperdb: ""});
runTest({wiredTigerDirectoryForIndexes: ""});
})();