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
129
130
131
132
133
134
135
136
137
|
/**
* Tests that the 'allowPartialResults' option to find is respected, and that aggregation does not
* accept the 'allowPartialResults' option.
*/
// This test shuts down a shard.
TestData.skipCheckingUUIDsConsistentAcrossCluster = true;
(function() {
"use strict";
const dbName = "test";
const collName = "foo";
const ns = dbName + "." + collName;
const isLastStable = (jsTestOptions().mongosBinVersion == "last-stable");
const st = new ShardingTest({shards: 2});
jsTest.log("Insert some data.");
const nDocs = 100;
const coll = st.s0.getDB(dbName)[collName];
let bulk = coll.initializeUnorderedBulkOp();
for (let i = -50; i < 50; i++) {
bulk.insert({_id: i});
}
assert.commandWorked(bulk.execute());
jsTest.log("Create a sharded collection with one chunk on each of the two shards.");
st.ensurePrimaryShard(dbName, st.shard0.shardName);
assert.commandWorked(st.s.adminCommand({enableSharding: dbName}));
assert.commandWorked(st.s.adminCommand({shardCollection: ns, key: {_id: 1}}));
assert.commandWorked(st.s.adminCommand({split: ns, middle: {_id: 0}}));
assert.commandWorked(st.s.adminCommand({moveChunk: ns, find: {_id: 0}, to: st.shard1.shardName}));
let findRes;
jsTest.log("Without 'allowPartialResults', if all shards are up, find returns all docs.");
findRes = coll.runCommand({find: collName});
assert.commandWorked(findRes);
assert.eq(nDocs, findRes.cursor.firstBatch.length);
assert.eq(undefined, findRes.cursor.partialResultsReturned);
jsTest.log("With 'allowPartialResults: false', if all shards are up, find returns all docs.");
findRes = coll.runCommand({find: collName, allowPartialResults: false});
assert.commandWorked(findRes);
assert.eq(nDocs, findRes.cursor.firstBatch.length);
assert.eq(undefined, findRes.cursor.partialResultsReturned);
// Find with batch size less than the number of documents on each shard so getMore can be run.
let nRemainingDocs = nDocs;
const batchSize = 10;
jsTest.log("With 'allowPartialResults: true', if all shards are up, find returns all docs.");
findRes = coll.runCommand({find: collName, allowPartialResults: true, batchSize: batchSize});
assert.commandWorked(findRes);
assert.eq(batchSize, findRes.cursor.firstBatch.length);
assert.eq(undefined, findRes.cursor.partialResultsReturned);
nRemainingDocs -= batchSize;
jsTest.log("Stopping " + st.shard0.shardName);
st.rs0.stopSet();
nRemainingDocs -= nDocs / 2 - batchSize;
// Do getMore with the returned cursor.
jsTest.log(
"When no getMores are issued to the unreachable shard because mongos has loaded 'batchSize' " +
"docs from each shard in the initial find, getMore does not return partialResultsReturned.");
let getMoreRes =
coll.runCommand({getMore: findRes.cursor.id, collection: collName, batchSize: batchSize});
assert.commandWorked(getMoreRes);
assert.eq(batchSize, getMoreRes.cursor.nextBatch.length);
assert.eq(undefined, getMoreRes.cursor.partialResultsReturned);
nRemainingDocs -= batchSize;
jsTest.log(
"When getMores are issued to the unreachable shard, getMore returns partialResultsReturned: 1");
// Use batch size of nRemainingDocs + 1 so that the getMore will wait for the scheduled getMores to
// all the shards.
getMoreRes = coll.runCommand(
{getMore: findRes.cursor.id, collection: collName, batchSize: nRemainingDocs + 1});
assert.commandWorked(getMoreRes);
assert.eq(nRemainingDocs, getMoreRes.cursor.nextBatch.length);
assert.eq(isLastStable ? undefined : true, getMoreRes.cursor.partialResultsReturned);
jsTest.log("Without 'allowPartialResults', if some shards are down, find fails.");
assert.commandFailed(coll.runCommand({find: collName}));
jsTest.log("With 'allowPartialResults: false', if some shards are down, find fails.");
assert.commandFailed(coll.runCommand({find: collName, allowPartialResults: false}));
if (isLastStable) {
// In v4.4, mongos was updated to swallow FailedToSatisfyReadPreference errors if
// allowPartialResults is true, allowing allowPartialResults to work with replica set shards
// (see SERVER-33597 for details). So when the mongos version is v4.2, the command should
// fail.
jsTest.log(
"With 'allowPartialResults: true', if some shards are down and mongos is v4.2, find fails");
assert.commandFailedWithCode(coll.runCommand({find: collName, allowPartialResults: true}),
ErrorCodes.FailedToSatisfyReadPreference);
} else {
nRemainingDocs = nDocs / 2;
jsTest.log(
"With 'allowPartialResults: true', if some shards are down, find returns partial results");
findRes = coll.runCommand({find: collName, allowPartialResults: true, batchSize: batchSize});
assert.commandWorked(findRes);
assert.eq(batchSize, findRes.cursor.firstBatch.length);
assert.eq(true, findRes.cursor.partialResultsReturned);
nRemainingDocs -= batchSize;
jsTest.log(
"getMore after a find that returns partial results returns partialResultsReturned: 1");
getMoreRes =
coll.runCommand({getMore: findRes.cursor.id, collection: collName, batchSize: batchSize});
assert.commandWorked(getMoreRes);
assert.eq(batchSize, getMoreRes.cursor.nextBatch.length);
assert.eq(true, getMoreRes.cursor.partialResultsReturned);
nRemainingDocs -= batchSize;
jsTest.log(
"Subsequent getMores should return partialResultsReturned: 1 regardless of the batch size.");
getMoreRes = coll.runCommand({getMore: findRes.cursor.id, collection: collName});
assert.commandWorked(getMoreRes);
assert.eq(nRemainingDocs, getMoreRes.cursor.nextBatch.length);
assert.eq(true, getMoreRes.cursor.partialResultsReturned);
}
jsTest.log("The allowPartialResults option does not currently apply to aggregation.");
assert.commandFailedWithCode(coll.runCommand({
aggregate: collName,
pipeline: [{$project: {_id: 1}}],
cursor: {},
allowPartialResults: true
}),
ErrorCodes.FailedToParse);
st.stop();
}());
|