summaryrefslogtreecommitdiff
path: root/jstests/core/background_validation.js
blob: 3de41bd8032b3079951a0ceaa24f063d82836079 (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
/**
 * Tests the validate command with {background:true}.
 *
 * Checks that {full:true} cannot be run with {background:true}.
 * Checks that {background:true} runs.
 * Checks that {background:true} can run concurrently with CRUD ops on the same collection.
 *
 * @tags: [
 *   # A failpoint is set that only exists on the mongod.
 *   assumes_against_mongod_not_mongos,
 *   # A failpoint is set against the primary only.
 *   does_not_support_stepdowns,
 *   # Checkpoint cursors cannot be open in lsm.
 *   does_not_support_wiredtiger_lsm,
 *   # inMemory does not have checkpoints; background validation only runs on a checkpoint.
 *   requires_persistence,
 *   # Background validation is only supported by WT.
 *   requires_wiredtiger,
 *   uses_parallel_shell,
 * ]
 */

(function() {
'use strict';

load("jstests/libs/fail_point_util.js");

const forceCheckpoint = () => {
    assert.commandWorked(db.fsyncLock());
    assert.commandWorked(db.fsyncUnlock());
};

const dbName = "test_db_background_validation";
const collName = "test_coll_background_validation";
const testDB = db.getSiblingDB(dbName);
const testColl = testDB.getCollection(collName);
testColl.drop();

/*
 * Create some indexes and insert some data, so we can validate them more meaningfully.
 */

assert.commandWorked(testColl.createIndex({a: 1}));
assert.commandWorked(testColl.createIndex({b: 1}));
assert.commandWorked(testColl.createIndex({c: 1}));

const numDocs = 100;
for (let i = 0; i < numDocs; ++i) {
    assert.commandWorked(testColl.insert({a: i, b: i, c: i}));
}

/**
 * Ensure {full:true} and {background:true} cannot be run together.
 */
assert.commandFailedWithCode(testColl.validate({background: true, full: true}),
                             ErrorCodes.CommandNotSupported);

forceCheckpoint();

// Check that {backround:true} is successful.
let res = testColl.validate({background: true});
assert.commandWorked(res);
assert(res.valid, "Validate cmd with {background:true} failed: " + tojson(res));

/*
 * Test background validation with concurrent CRUD operations.
 */

// Set a failpoint in the background validation code to pause validation while holding a collection
// lock.
let failPoint = configureFailPoint(db, "pauseCollectionValidationWithLock");

// Start an asynchronous thread to run collection validation with {background:true}.
let awaitValidateCommand = startParallelShell(function() {
    let mycoll = db.getSiblingDB("test_db_background_validation")
                     .getCollection("test_coll_background_validation");
    let validateRes = mycoll.validate({background: true});
    assert.commandWorked(validateRes,
                         "asynchronous background validate command failed: " + tojson(validateRes));
    assert(validateRes.valid,
           "asynchronous background validate command was not valid: " + tojson(validateRes));
});

// Wait for background validation command to start.
failPoint.wait();

jsTest.log("Should start hanging now......");

// Check that CRUD ops are succesful while validation is in progress.
assert.commandWorked(testColl.remove({a: 1, b: 1, c: 1}));
assert.commandWorked(testColl.insert({a: 1, b: 1, c: 1, d: 100}));
assert.commandWorked(testColl.update({d: 100}, {"e": "updated"}));
let docRes = testColl.find({"e": "updated"});
assert.eq(1,
          docRes.toArray().length,
          "expected to find a single document, found: " + tojson(docRes.toArray()));

// Clear the failpoint and make sure the validate command was successful.
failPoint.off();
awaitValidateCommand();

/**
 * Verify everything is still OK by running foreground validation.
 */
res = testColl.validate({background: false});
assert.commandWorked(res);
assert(res.valid, "Validate cmd with {background:true} failed: " + tojson(res));
assert.eq(res.nIndexes, 4, "Expected 4 indexes: " + tojson(res));
assert.eq(res.nrecords, numDocs, "Expected " + numDocs + " collection records:" + tojson(res));
assert.eq(
    res.keysPerIndex._id_, numDocs, "Expected " + numDocs + " _id index records: " + tojson(res));
assert.eq(
    res.keysPerIndex.a_1, numDocs, "Expected " + numDocs + " a_1 index records: " + tojson(res));
assert.eq(
    res.keysPerIndex.b_1, numDocs, "Expected " + numDocs + " b_1 index records: " + tojson(res));
assert.eq(
    res.keysPerIndex.c_1, numDocs, "Expected " + numDocs + " c_1 index records: " + tojson(res));
})();