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
127
128
|
/*
* This test exercises the "linearizable" readConcern option on a simple sharded cluster.
* Note that a full linearizable read concern test exists in
* "replsets/linearizable_read_concern.js". This test exists mainly to affirm that a
* readConcern "linearizable" propagates correctly through a sharded cluster i.e. we
* execute database commands only through a mongos, not directly on a replica set.
*
* There is one mongos and two shards (each a 3-node replica set). We put one
* chunk on each shard, each containing five documents. We then execute a
* linearizable read targeting both shards with readPreference "secondary", to
* make sure it fails. We next execute a linearizable read targeting both
* shards with readPreference "primary" to make sure it succeeds. The primary
* is then partitioned from the other two secondaries in the first shard, and
* we make sure that a linearizable read targeting primaries in both shards
* times out, since the partitioned primary can no longer communicate with a
* majority of nodes.
*
* NOTE: Linearizability guarantees only apply when a query specifies a unique
* document. This test is mainly trying to ensure that system behavior is
* reasonable when executing linearizable reads in a sharded cluster, so as to
* exercise possible (invalid) user behavior.
*/
load("jstests/replsets/rslib.js");
load("jstests/libs/write_concern_util.js");
(function() {
"use strict";
// Skip db hash check and shard replication since this test leaves a replica set shard
// partitioned.
TestData.skipCheckDBHashes = true;
TestData.skipAwaitingReplicationOnShardsBeforeCheckingUUIDs = true;
var testName = "linearizable_read_concern";
var st = new ShardingTest({
name: testName,
shards: 2,
other: {rs0: {nodes: 3}, rs1: {nodes: 3}, useBridge: true},
mongos: 1,
config: 1,
enableBalancer: false
});
jsTestLog("Setting up sharded cluster.");
// Set up the sharded cluster.
var dbName = testName;
var collName = "test";
var collNamespace = dbName + "." + collName;
var shard0ReplTest = st.rs0;
var shard1ReplTest = st.rs1;
var testDB = st.s.getDB(dbName);
// Set high election timeout so that primary doesn't step down during linearizable read test.
var cfg = shard0ReplTest.getReplSetConfigFromNode(0);
cfg.settings.electionTimeoutMillis = shard0ReplTest.kDefaultTimeoutMS;
reconfig(shard0ReplTest, cfg, true);
// Set up sharded collection. Put 5 documents on each shard, with keys {x: 0...9}.
var numDocs = 10;
shardCollectionWithChunks(st, testDB[collName], numDocs);
// Make sure the 'shardIdentity' document on each shard is replicated to all secondary nodes
// before issuing reads against them.
shard0ReplTest.awaitReplication();
shard1ReplTest.awaitReplication();
// Print current sharding stats for debugging.
st.printShardingStatus(5);
// Filter to target one document in each shard.
var shard0DocKey = 2;
var shard1DocKey = 7;
var dualShardQueryFilter = {$or: [{x: shard0DocKey}, {x: shard1DocKey}]};
jsTestLog("Testing linearizable read from secondaries");
// Execute a linearizable read from secondaries (targeting both shards) which should fail.
st.s.setReadPref("secondary");
var res = assert.commandFailed(testDB.runReadCommand({
find: collName,
filter: dualShardQueryFilter,
readConcern: {level: "linearizable"},
maxTimeMS: shard0ReplTest.kDefaultTimeoutMS
}));
assert.eq(res.code, ErrorCodes.NotMaster);
jsTestLog("Testing linearizable read from primaries.");
// Execute a linearizable read from primaries (targeting both shards) which should succeed.
st.s.setReadPref("primary");
var res = assert.writeOK(testDB.runReadCommand({
find: collName,
sort: {x: 1},
filter: dualShardQueryFilter,
readConcern: {level: "linearizable"},
maxTimeMS: shard0ReplTest.kDefaultTimeoutMS
}));
// Make sure data was returned from both shards correctly.
assert.eq(res.cursor.firstBatch[0].x, shard0DocKey);
assert.eq(res.cursor.firstBatch[1].x, shard1DocKey);
jsTestLog("Testing linearizable read targeting partitioned primary.");
var primary = shard0ReplTest.getPrimary();
var secondaries = shard0ReplTest.getSecondaries();
// Partition the primary in the first shard.
secondaries[0].disconnect(primary);
secondaries[1].disconnect(primary);
jsTestLog("Current Replica Set Topology of First Shard: [Secondary-Secondary] [Primary]");
// Execute a linearizable read targeting the partitioned primary in first shard, and good
// primary in the second shard. This should time out due to partitioned primary.
var result = testDB.runReadCommand({
find: collName,
filter: dualShardQueryFilter,
readConcern: {level: "linearizable"},
maxTimeMS: 3000
});
assert.commandFailedWithCode(result, ErrorCodes.MaxTimeMSExpired);
st.stop();
})();
|