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
|
/**
* Validates the operationTime value in the command response depends on the read/writeConcern of the
* the read/write commmand that produced it.
* @tags: [requires_majority_read_concern]
*/
(function() {
"use strict";
// Skip db hash check because replication is stopped on secondaries.
TestData.skipCheckDBHashes = true;
load("jstests/replsets/rslib.js"); // For startSetIfSupportsReadMajority.
load("jstests/libs/write_concern_util.js"); // For stopReplicationOnSecondaries,
// restartReplicationOnSecondaries
var name = "operation_time_read_and_write_concern";
var replTest = new ReplSetTest(
{name: name, nodes: 3, nodeOptions: {enableMajorityReadConcern: ""}, waitForKeys: true});
if (!startSetIfSupportsReadMajority(replTest)) {
jsTestLog("Skipping test since storage engine doesn't support majority read concern.");
replTest.stopSet();
return;
}
replTest.initiate();
var res;
var testDB = replTest.getPrimary().getDB(name);
var collectionName = "foo";
// readConcern level majority:
// operationTime is the cluster time of the last committed op in the oplog.
jsTestLog("Testing operationTime for readConcern level majority with afterClusterTime.");
var majorityDoc = {_id: 10, x: 1};
var localDoc = {_id: 15, x: 2};
res = assert.commandWorked(testDB.runCommand(
{insert: collectionName, documents: [majorityDoc], writeConcern: {w: "majority"}}));
var majorityWriteOperationTime = res.operationTime;
stopReplicationOnSecondaries(replTest);
res = assert.commandWorked(
testDB.runCommand({insert: collectionName, documents: [localDoc], writeConcern: {w: 1}}));
var localWriteOperationTime = res.operationTime;
assert.gt(localWriteOperationTime, majorityWriteOperationTime);
res = assert.commandWorked(testDB.runCommand({
find: collectionName,
readConcern: {level: "majority", afterClusterTime: majorityWriteOperationTime}
}));
var majorityReadOperationTime = res.operationTime;
assert.eq(res.cursor.firstBatch,
[majorityDoc],
"only the committed document, " + tojson(majorityDoc) +
", should be returned for the majority read with afterClusterTime: " +
majorityWriteOperationTime);
assert.eq(majorityReadOperationTime,
majorityWriteOperationTime,
"the operationTime of the majority read, " + majorityReadOperationTime +
", should be the cluster time of the last committed op in the oplog, " +
majorityWriteOperationTime);
// Validate that after replication, the local write data is now returned by the same query.
restartReplicationOnSecondaries(replTest);
replTest.awaitLastOpCommitted();
res = assert.commandWorked(testDB.runCommand({
find: collectionName,
sort: {_id: 1}, // So the order of the documents is defined for testing.
readConcern: {level: "majority", afterClusterTime: majorityWriteOperationTime}
}));
var secondMajorityReadOperationTime = res.operationTime;
assert.eq(res.cursor.firstBatch,
[majorityDoc, localDoc],
"expected both inserted documents, " + tojson([majorityDoc, localDoc]) +
", to be returned for the second majority read with afterClusterTime: " +
majorityWriteOperationTime);
assert.eq(secondMajorityReadOperationTime,
localWriteOperationTime,
"the operationTime of the second majority read, " + secondMajorityReadOperationTime +
", should be the cluster time of the replicated local write, " +
localWriteOperationTime);
// readConcern level linearizable is not currently supported.
jsTestLog("Verifying readConcern linearizable with afterClusterTime is not supported.");
res = assert.commandFailedWithCode(
testDB.runCommand({
find: collectionName,
filter: localDoc,
readConcern: {level: "linearizable", afterClusterTime: majorityReadOperationTime}
}),
ErrorCodes.InvalidOptions,
"linearizable reads with afterClusterTime are not supported and should not be allowed");
// writeConcern level majority:
// operationTime is the cluster time of the write if it succeeds, or of the previous successful
// write at the time the write was determined to have failed, or a no-op.
jsTestLog("Testing operationTime for writeConcern level majority.");
var successfulDoc = {_id: 1000, y: 1};
var failedDoc = {_id: 1000, y: 2};
res = assert.commandWorked(testDB.runCommand(
{insert: collectionName, documents: [successfulDoc], writeConcern: {w: "majority"}}));
var majorityWriteOperationTime = res.operationTime;
stopReplicationOnSecondaries(replTest);
res = testDB.runCommand({
insert: collectionName,
documents: [failedDoc],
writeConcern: {w: "majority", wtimeout: 1000}
});
assert.eq(res.writeErrors[0].code, ErrorCodes.DuplicateKey);
var failedWriteOperationTime = res.operationTime;
assert.eq(failedWriteOperationTime,
majorityWriteOperationTime,
"the operationTime of the failed majority write, " + failedWriteOperationTime +
", should be the cluster time of the last successful write at the time it failed, " +
majorityWriteOperationTime);
replTest.stopSet();
})();
|