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
|
// @tags: [requires_getmore, requires_capped]
// Tests for the behavior of tailable cursors when a collection is dropped or the cursor is
// otherwise invalidated.
(function() {
"use strict";
const collName = "tailable_cursor_invalidation";
const coll = db[collName];
coll.drop();
// Test that you cannot open a tailable cursor on a non-existent collection.
assert.eq(0, assert.commandWorked(db.runCommand({find: collName})).cursor.id);
assert.eq(0, assert.commandWorked(db.runCommand({find: collName, tailable: true})).cursor.id);
assert.eq(0,
assert.commandWorked(db.runCommand({find: collName, tailable: true, awaitData: true}))
.cursor.id);
const emptyBatchCursorId =
assert
.commandWorked(
db.runCommand({find: collName, tailable: true, awaitData: true, batchSize: 0}))
.cursor.id;
const isMongos = db.adminCommand({isdbgrid: 1}).isdbgrid;
if (isMongos) {
// Mongos will let you establish a cursor with batch size 0 and return to you before it
// realizes the shard's cursor is exhausted. The next getMore should return a 0 cursor id
// though.
assert.neq(emptyBatchCursorId, 0);
assert.eq(
0,
assert.commandWorked(db.runCommand({getMore: emptyBatchCursorId, collection: collName}))
.cursor.id);
} else {
// A mongod should know immediately that the collection doesn't exist, and return a 0 cursor
// id.
assert.eq(0, emptyBatchCursorId);
}
function dropAndRecreateColl() {
coll.drop();
assert.commandWorked(db.createCollection(collName, {capped: true, size: 1024}));
const numDocs = 4;
const bulk = coll.initializeUnorderedBulkOp();
for (let i = 0; i < numDocs; ++i) {
bulk.insert({_id: i});
}
assert.writeOK(bulk.execute());
}
dropAndRecreateColl();
/**
* Runs a find command to establish a cursor. Asserts that the command worked and that the
* cursor id is not 0, then returns the cursor id.
*/
function openCursor({tailable, awaitData}) {
const findRes = assert.commandWorked(
db.runCommand({find: collName, tailable: tailable, awaitData: awaitData}));
assert.neq(findRes.cursor.id, 0);
assert.eq(findRes.cursor.ns, coll.getFullName());
return findRes.cursor.id;
}
// Test that the cursor dies on getMore if the collection has been dropped.
let cursorId = openCursor({tailable: true, awaitData: false});
dropAndRecreateColl();
assert.commandFailedWithCode(db.runCommand({getMore: cursorId, collection: collName}),
ErrorCodes.QueryPlanKilled);
cursorId = openCursor({tailable: true, awaitData: true});
dropAndRecreateColl();
assert.commandFailedWithCode(db.runCommand({getMore: cursorId, collection: collName}),
ErrorCodes.QueryPlanKilled);
}());
|