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
|
// Tests that if a mongoS cursor exceeds the maxTimeMs timeout, the cursors on the shards will be
// cleaned up. Exercises the fix for the bug described in SERVER-62710.
//
// @tags: []
(function() {
"use strict";
load("jstests/libs/fail_point_util.js"); // for 'configureFailPoint()'
function getIdleCursors(conn, collName) {
return conn.getDB('admin')
.aggregate([
{$currentOp: {idleCursors: true}},
{$match: {$and: [{type: "idleCursor"}, {"cursor.originatingCommand.find": collName}]}}
])
.toArray();
}
function assertNoIdleCursors(conn, collName) {
const sleepTimeMS = 10 * 1000;
const retries = 2;
assert.soon(() => (getIdleCursors(conn, collName).length === 0),
() => tojson(getIdleCursors(conn, collName)),
retries * sleepTimeMS,
sleepTimeMS,
{runHangAnalyzer: false});
}
const st = new ShardingTest({shards: 1, mongos: 1, config: 1});
const dbName = "test";
const collName = jsTestName();
const coll = st.s.getCollection(dbName + "." + collName);
// Insert some data (1000 simple documents) into the collection.
assert.commandWorked(coll.insert(Array.from({length: 1000}, _ => ({a: 1}))));
// Ensure there are no idle cursors on shart0 before tests begin.
assertNoIdleCursors(st.shard0, collName);
// Ensure the timeout happens on the shard after on exit from 'getMore' call. The query might
// occasionally return the 'NetworkInterfaceExceededTimeLimit' error.
{
const curs = coll.find().batchSize(2).maxTimeMS(100);
const fp = configureFailPoint(st.shard0,
"waitBeforeUnpinningOrDeletingCursorAfterGetMoreBatch",
{shouldCheckForInterrupt: true});
assert.throwsWithCode(
() => curs.itcount(),
[ErrorCodes.MaxTimeMSExpired, ErrorCodes.NetworkInterfaceExceededTimeLimit]);
fp.off();
assertNoIdleCursors(st.shard0, collName);
}
// Perform a query that sleeps after retrieving each document. This is guaranteed to exceed the
// specified maxTimeMS limit. The timeout may happen either on mongoS or on shard. The query might
// occasionally return the 'NetworkInterfaceExceededTimeLimit' error.
{
const curs = coll.find({
$where: function() {
sleep(1);
return true;
}
})
.batchSize(2)
.maxTimeMS(100);
assert.eq(getIdleCursors(st.shard0, collName).length, 0);
assert.throwsWithCode(
() => curs.itcount(),
[ErrorCodes.MaxTimeMSExpired, ErrorCodes.NetworkInterfaceExceededTimeLimit]);
assertNoIdleCursors(st.shard0, collName);
}
// Ensure the timeout happens on mongoS.
{
const curs = coll.find({}).batchSize(2).maxTimeMS(100);
const fp = configureFailPoint(st.s, "maxTimeAlwaysTimeOut", {}, "alwaysOn");
assert.throwsWithCode(() => curs.itcount(), ErrorCodes.MaxTimeMSExpired);
fp.off();
assertNoIdleCursors(st.shard0, collName);
}
// Ensure the timeout happens on the shard.
{
const curs = coll.find({}).batchSize(2).maxTimeMS(100);
const fp = configureFailPoint(st.shard0, "maxTimeAlwaysTimeOut", {}, "alwaysOn");
assert.throwsWithCode(() => curs.itcount(), ErrorCodes.MaxTimeMSExpired);
fp.off();
assertNoIdleCursors(st.shard0, collName);
}
st.stop();
})();
|