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 that the mongo shell gossips the greater of the client's clusterTime and the session's
* clusterTime.
* @tags: [requires_replication]
*/
(function() {
"use strict";
load("jstests/replsets/rslib.js");
const rst = new ReplSetTest({nodes: 1});
rst.startSet();
rst.initiate();
const primary = rst.getPrimary();
const session1 = primary.startSession();
const session2 = primary.startSession();
const db = primary.getDB("test");
const coll = db.shell_gossip_cluster_time;
function testCommandGossipedWithClusterTime(func, expectedClusterTime) {
const mongoRunCommandOriginal = Mongo.prototype.runCommand;
const sentinel = {};
let cmdObjSeen = sentinel;
Mongo.prototype.runCommand = function runCommandSpy(dbName, cmdObj, options) {
cmdObjSeen = cmdObj;
return mongoRunCommandOriginal.apply(this, arguments);
};
try {
assert.doesNotThrow(func);
} finally {
Mongo.prototype.runCommand = mongoRunCommandOriginal;
}
if (cmdObjSeen === sentinel) {
throw new Error("Mongo.prototype.runCommand() was never called: " + func.toString());
}
if (expectedClusterTime === undefined) {
assert(!cmdObjSeen.hasOwnProperty("$clusterTime"),
"Expected operation " + tojson(cmdObjSeen) +
" to not have a $clusterTime object: " + func.toString());
} else {
assert(cmdObjSeen.hasOwnProperty("$clusterTime"),
"Expected operation " + tojson(cmdObjSeen) +
" to have a $clusterTime object: " + func.toString());
assert(bsonBinaryEqual(expectedClusterTime, cmdObjSeen.$clusterTime));
}
}
assert(session1.getClusterTime() === undefined,
"session1 has yet to be used, but has clusterTime: " + tojson(session1.getClusterTime()));
assert(session2.getClusterTime() === undefined,
"session2 has yet to be used, but has clusterTime: " + tojson(session2.getClusterTime()));
// Advance the clusterTime outside of either of the sessions.
testCommandGossipedWithClusterTime(function() {
assert.commandWorked(coll.insert({}));
}, primary.getClusterTime());
assert(session1.getClusterTime() === undefined,
"session1 has yet to be used, but has clusterTime: " + tojson(session1.getClusterTime()));
assert(session2.getClusterTime() === undefined,
"session2 has yet to be used, but has clusterTime: " + tojson(session2.getClusterTime()));
// Performing an operation with session1 should use the highest clusterTime seen by the client
// since session1 hasn't been used yet.
testCommandGossipedWithClusterTime(function() {
const coll = session1.getDatabase("test").mycoll;
assert.commandWorked(coll.insert({}));
}, primary.getClusterTime());
assert.eq(session1.getClusterTime(), primary.getClusterTime());
testCommandGossipedWithClusterTime(function() {
const coll = session1.getDatabase("test").mycoll;
assert.commandWorked(coll.insert({}));
}, session1.getClusterTime());
assert(session2.getClusterTime() === undefined,
"session2 has yet to be used, but has clusterTime: " + tojson(session2.getClusterTime()));
primary.resetClusterTime_forTesting();
assert(primary.getClusterTime() === undefined,
"client's cluster time should have been reset, but has clusterTime: " +
tojson(primary.getClusterTime()));
// Performing an operation with session2 should use the highest clusterTime seen by session2
// since the client's clusterTime has been reset.
session2.advanceClusterTime(session1.getClusterTime());
testCommandGossipedWithClusterTime(function() {
const coll = session2.getDatabase("test").mycoll;
assert.commandWorked(coll.insert({}));
}, session2.getClusterTime());
assert.eq(session2.getClusterTime(), primary.getClusterTime());
primary.resetClusterTime_forTesting();
assert(primary.getClusterTime() === undefined,
"client's cluster time should have been reset, but has clusterTime: " +
tojson(primary.getClusterTime()));
// Performing an operation with session2 should use the highest clusterTime seen by session2
// since the highest clusterTime seen by session1 is behind that of session2's.
primary.advanceClusterTime(session1.getClusterTime());
testCommandGossipedWithClusterTime(function() {
const coll = session2.getDatabase("test").mycoll;
assert.commandWorked(coll.insert({}));
}, session2.getClusterTime());
rst.stopSet();
})();
|