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
|
// @tags: [requires_replication, uses_transactions, uses_atclustertime]
// 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);
});
assert.commandWorked(session.commitTransaction_forTesting());
}
// 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();
}());
|