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
|
/**
* Tests that an updateLookup change stream doesn't throw ChangeStreamFatalError or
* TooManyMatchingDocuments after fixing SERVER-44598.
*
* @tags: [
* uses_change_streams,
* ]
*/
(function() {
"use strict";
load("jstests/multiVersion/libs/multi_cluster.js"); // For ShardingTest.waitUntilStable.
// The UUID consistency check can hit NotPrimaryNoSecondaryOk when it attempts to obtain a list of
// collections from the shard Primaries through mongoS at the end of this test.
TestData.skipCheckingUUIDsConsistentAcrossCluster = true;
// Start a new sharded cluster with 2 nodes and obtain references to the test DB and collection.
const st = new ShardingTest({
shards: 2,
mongos: 1,
rs: {nodes: 3, setParameter: {writePeriodicNoops: true, periodicNoopIntervalSecs: 5}}
});
let mongosDB = st.s.getDB(jsTestName());
let mongosColl = mongosDB.test;
let shard0 = st.rs0;
// Enable sharding on the the test database and ensure that the primary is shard0.
assert.commandWorked(mongosDB.adminCommand({enableSharding: mongosDB.getName()}));
st.ensurePrimaryShard(mongosDB.getName(), shard0.getURL());
// Shard the source collection on {a: 1}, split across the shards at {a: 0}.
st.shardColl(mongosColl, {a: 1}, {a: 0}, {a: 1});
// Open a change stream on the collection.
let csCursor = mongosColl.watch();
// Write one document onto shard0 and obtain its resume token.
assert.commandWorked(mongosColl.insert({_id: 0, a: -100}));
assert.soon(() => csCursor.hasNext());
const resumeToken = csCursor.next()._id;
// Obtain a reference to any secondary.
const newPrimary = shard0.getSecondary();
// Step up one of the Secondaries, which will not have any sharding metadata loaded.
shard0.stepUp(newPrimary);
// Make sure the mongoS and both shards sees shard0's new primary.
st.waitUntilStable();
// Refresh our reference to the test collection.
mongosColl = st.s.getDB(mongosDB.getName())[mongosColl.getName()];
// Do a {multi:true} update. This will scatter to all shards and update the document on shard0.
// Because no metadata is loaded, the shard will return a StaleShardVersion and fetch it, and
// the operation will be retried until it completes successfully.
assert.soonNoExcept(
() => assert.commandWorked(mongosColl.update({_id: 0}, {$set: {updated: true}}, false, true)));
// Resume the change stream with {fullDocument: 'updateLookup'}. Update lookup can successfully
// identify the document based on its _id alone so long as the _id is unique in the collection, so
// this alone does not prove that the multi-update actually wrote its shard key into the oplog.
csCursor = mongosColl.watch([], {resumeAfter: resumeToken, fullDocument: "updateLookup"});
assert.soon(() => csCursor.hasNext());
assert.docEq(csCursor.next().fullDocument, {_id: 0, a: -100, updated: true});
// Now insert a new document with the same _id on the other shard. Update lookup will be able to
// distinguish between the two, proving that they both have full shard keys available.
assert.commandWorked(mongosColl.insert({_id: 0, a: 100}));
csCursor = mongosColl.watch([], {resumeAfter: resumeToken, fullDocument: "updateLookup"});
assert.soon(() => csCursor.hasNext());
assert.docEq(csCursor.next().fullDocument, {_id: 0, a: -100, updated: true});
st.stop();
})();
|