summaryrefslogtreecommitdiff
path: root/jstests/noPassthrough/crud_timestamps.js
blob: 390a85727a26c48bd552ee503cc7d5d598726782 (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
// @tags: [requires_replication, uses_transactions]

// Test the correct timestamping of insert, update, and delete writes along with their accompanying
// index updates.
//

(function() {
    "use strict";

    const dbName = "test";
    const collName = "coll";

    const rst = new ReplSetTest({nodes: 1});
    rst.startSet();
    rst.initiate();
    const testDB = rst.getPrimary().getDB(dbName);
    const coll = testDB.getCollection(collName);

    if (!testDB.serverStatus().storageEngine.supportsSnapshotReadConcern) {
        rst.stopSet();
        return;
    }

    // Turn off timestamp reaping.
    assert.commandWorked(testDB.adminCommand({
        configureFailPoint: "WTPreserveSnapshotHistoryIndefinitely",
        mode: "alwaysOn",
    }));

    const session = testDB.getMongo().startSession({causalConsistency: false});
    const sessionDb = session.getDatabase(dbName);
    const response = assert.commandWorked(testDB.createCollection("coll"));
    const startTime = response.operationTime;

    function check(atClusterTime, expected) {
        session.startTransaction({readConcern: {level: "snapshot", atClusterTime: atClusterTime}});
        // Check both a collection scan and scanning the _id index.
        [{$natural: 1}, {_id: 1}].forEach(sort => {
            let response = assert.commandWorked(
                sessionDb.runCommand({find: collName, sort: sort, singleBatch: true}));
            assert.eq(expected, response.cursor.firstBatch);
        });
        session.commitTransaction();
    }

    // insert

    let request = {insert: coll.getName(), documents: [{_id: 1}, {_id: 2}], ordered: false};
    assert.commandWorked(coll.runCommand(request));

    const oplog = rst.getPrimary().getDB("local").getCollection("oplog.rs");
    let ts1 = oplog.findOne({o: {_id: 1}}).ts;
    let ts2 = oplog.findOne({o: {_id: 2}}).ts;

    check(startTime, []);
    check(ts1, [{_id: 1}]);
    check(ts2, [{_id: 1}, {_id: 2}]);

    // upsert

    request = {
        update: coll.getName(),
        updates: [
            {q: {_id: 3, a: 1}, u: {$set: {a: 2}}, upsert: true},
            {q: {_id: 4, a: 1}, u: {$set: {a: 3}}, upsert: true}
        ],
        ordered: true
    };
    assert.commandWorked(coll.runCommand(request));

    ts1 = oplog.findOne({o: {_id: 3, a: 2}}).ts;
    ts2 = oplog.findOne({o: {_id: 4, a: 3}}).ts;

    check(ts1, [{_id: 1}, {_id: 2}, {_id: 3, a: 2}]);
    check(ts2, [{_id: 1}, {_id: 2}, {_id: 3, a: 2}, {_id: 4, a: 3}]);

    // update

    request = {
        update: coll.getName(),
        updates: [{q: {_id: 3, a: 2}, u: {$set: {a: 4}}}, {q: {_id: 4, a: 3}, u: {$set: {a: 5}}}],
        ordered: true
    };
    assert.commandWorked(coll.runCommand(request));

    ts1 = oplog.findOne({op: 'u', o2: {_id: 3}}).ts;
    ts2 = oplog.findOne({op: 'u', o2: {_id: 4}}).ts;

    check(ts1, [{_id: 1}, {_id: 2}, {_id: 3, a: 4}, {_id: 4, a: 3}]);
    check(ts2, [{_id: 1}, {_id: 2}, {_id: 3, a: 4}, {_id: 4, a: 5}]);

    // delete

    request = {delete: coll.getName(), deletes: [{q: {}, limit: 0}], ordered: false};

    assert.commandWorked(coll.runCommand(request));

    ts1 = oplog.findOne({op: 'd', o: {_id: 1}}).ts;
    ts2 = oplog.findOne({op: 'd', o: {_id: 2}}).ts;
    let ts3 = oplog.findOne({op: 'd', o: {_id: 3}}).ts;
    let ts4 = oplog.findOne({op: 'd', o: {_id: 4}}).ts;

    check(ts1, [{_id: 2}, {_id: 3, a: 4}, {_id: 4, a: 5}]);
    check(ts2, [{_id: 3, a: 4}, {_id: 4, a: 5}]);
    check(ts3, [{_id: 4, a: 5}]);
    check(ts4, []);

    session.endSession();
    rst.stopSet();

}());