summaryrefslogtreecommitdiff
path: root/jstests/sharding/lookup_stale_mongos.js
blob: 2c74af07b283760f3e5d5904599e8ae41a21965a (plain)
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
// Tests the behavior of a $lookup when the mongos contains stale routing information for the
// local and/or foreign collections.  This includes when mongos thinks the collection is sharded
// when it's not, and likewise when mongos thinks the collection is unsharded but is actually
// sharded.
(function() {
"use strict";

load("jstests/noPassthrough/libs/server_parameter_helpers.js");  // For setParameterOnAllHosts.
load("jstests/libs/discover_topology.js");                       // For findDataBearingNodes.

const testName = "lookup_stale_mongos";
const st = new ShardingTest({
    shards: 2,
    mongos: 2,
});
setParameterOnAllHosts(DiscoverTopology.findNonConfigNodes(st.s0).concat([st.s1.host]),
                       "internalQueryAllowShardedLookup",
                       true);

const mongos0DB = st.s0.getDB(testName);
assert.commandWorked(mongos0DB.dropDatabase());
const mongos0LocalColl = mongos0DB[testName + "_local"];
const mongos0ForeignColl = mongos0DB[testName + "_foreign"];

const mongos1DB = st.s1.getDB(testName);
const mongos1LocalColl = mongos1DB[testName + "_local"];
const mongos1ForeignColl = mongos1DB[testName + "_foreign"];

const pipeline = [
    {$lookup: {localField: "a", foreignField: "b", from: mongos1ForeignColl.getName(), as: "same"}},
    {$sort: {_id: 1}}
];
const expectedResults = [
    {_id: 0, a: 1, "same": [{_id: 0, b: 1}]},
    {_id: 1, a: null, "same": [{_id: 1, b: null}, {_id: 2}]},
    {_id: 2, "same": [{_id: 1, b: null}, {_id: 2}]}
];

// Ensure that shard0 is the primary shard.
assert.commandWorked(mongos0DB.adminCommand({enableSharding: mongos0DB.getName()}));
st.ensurePrimaryShard(mongos0DB.getName(), st.shard0.shardName);

assert.commandWorked(mongos0LocalColl.insert({_id: 0, a: 1}));
assert.commandWorked(mongos0LocalColl.insert({_id: 1, a: null}));

assert.commandWorked(mongos0ForeignColl.insert({_id: 0, b: 1}));
assert.commandWorked(mongos0ForeignColl.insert({_id: 1, b: null}));

// Send writes through mongos1 such that it's aware of the collections and believes they are
// unsharded.
assert.commandWorked(mongos1LocalColl.insert({_id: 2}));
assert.commandWorked(mongos1ForeignColl.insert({_id: 2}));

//
// Test unsharded local and sharded foreign collections, with mongos unaware that the foreign
// collection is sharded.
//

// Shard the foreign collection through mongos0.
assert.commandWorked(
    mongos0DB.adminCommand({shardCollection: mongos0ForeignColl.getFullName(), key: {_id: 1}}));

// Split the collection into 2 chunks: [MinKey, 1), [1, MaxKey).
assert.commandWorked(
    mongos0DB.adminCommand({split: mongos0ForeignColl.getFullName(), middle: {_id: 1}}));

// Move the [minKey, 1) chunk to shard1.
assert.commandWorked(mongos0DB.adminCommand({
    moveChunk: mongos0ForeignColl.getFullName(),
    find: {_id: 0},
    to: st.shard1.shardName,
    _waitForDelete: true
}));

// Issue a $lookup through mongos1, which is unaware that the foreign collection is sharded.
assert.eq(mongos1LocalColl.aggregate(pipeline).toArray(), expectedResults);

//
// Test sharded local and sharded foreign collections, with mongos unaware that the local
// collection is sharded.
//

// Shard the local collection through mongos0.
assert.commandWorked(
    mongos0DB.adminCommand({shardCollection: mongos0LocalColl.getFullName(), key: {_id: 1}}));

// Split the collection into 2 chunks: [MinKey, 1), [1, MaxKey).
assert.commandWorked(
    mongos0DB.adminCommand({split: mongos0LocalColl.getFullName(), middle: {_id: 1}}));

// Move the [minKey, 1) chunk to shard1.
assert.commandWorked(mongos0DB.adminCommand({
    moveChunk: mongos0LocalColl.getFullName(),
    find: {_id: 0},
    to: st.shard1.shardName,
    _waitForDelete: true
}));

// Issue a $lookup through mongos1, which is unaware that the local collection is sharded.
assert.eq(mongos1LocalColl.aggregate(pipeline).toArray(), expectedResults);

//
// Test sharded local and unsharded foreign collections, with mongos unaware that the foreign
// collection is unsharded.
//

// Recreate the foreign collection as unsharded through mongos0.
mongos0ForeignColl.drop();
assert.commandWorked(mongos0ForeignColl.insert({_id: 0, b: 1}));
assert.commandWorked(mongos0ForeignColl.insert({_id: 1, b: null}));
assert.commandWorked(mongos0ForeignColl.insert({_id: 2}));

// Issue a $lookup through mongos1, which is unaware that the foreign collection is now
// unsharded.
assert.eq(mongos1LocalColl.aggregate(pipeline).toArray(), expectedResults);

//
// Test unsharded local and foreign collections, with mongos unaware that the local
// collection is unsharded.
//

// Recreate the local collection as unsharded through mongos0.
mongos0LocalColl.drop();
assert.commandWorked(mongos0LocalColl.insert({_id: 0, a: 1}));
assert.commandWorked(mongos0LocalColl.insert({_id: 1, a: null}));
assert.commandWorked(mongos0LocalColl.insert({_id: 2}));

// Issue a $lookup through mongos1, which is unaware that the local collection is now
// unsharded.
assert.eq(mongos1LocalColl.aggregate(pipeline).toArray(), expectedResults);

st.stop();
})();