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 for the behavior of combining the tailable and awaitData options to the getMore command
// with the batchSize option.
(function() {
"use strict";
const collName = "tailable_getmore_batch_size";
const coll = db[collName];
const batchSize = 2;
function dropAndRecreateColl({numDocs}) {
coll.drop();
assert.commandWorked(db.createCollection(collName, {capped: true, size: 1024}));
const bulk = coll.initializeUnorderedBulkOp();
for (let i = 0; i < numDocs; ++i) {
bulk.insert({_id: i});
}
assert.writeOK(bulk.execute());
}
// Test that running a find with the 'tailable' option will return results immediately, even if
// there are fewer than the specified batch size.
dropAndRecreateColl({numDocs: batchSize - 1});
let findRes =
assert.commandWorked(db.runCommand({find: collName, tailable: true, batchSize: batchSize}));
assert.eq(findRes.cursor.firstBatch.length, batchSize - 1);
assert.neq(findRes.cursor.id, 0);
// Test that the same is true for a find with the 'tailable' and 'awaitData' options set.
findRes = assert.commandWorked(
db.runCommand({find: collName, tailable: true, awaitData: true, batchSize: batchSize}));
assert.eq(findRes.cursor.firstBatch.length, batchSize - 1);
assert.neq(findRes.cursor.id, 0);
/**
* Runs a find command with a batchSize of 'batchSize' to establish a cursor. Asserts that the
* command worked and that the cursor id is not 0, then returns the cursor id.
*/
function openCursor({batchSize, tailable, awaitData}) {
const findRes = assert.commandWorked(db.runCommand(
{find: collName, tailable: tailable, awaitData: awaitData, batchSize: batchSize}));
assert.eq(findRes.cursor.firstBatch.length, batchSize);
assert.neq(findRes.cursor.id, 0);
assert.eq(findRes.cursor.ns, coll.getFullName());
return findRes.cursor.id;
}
// Test that specifying a batch size to a getMore on a tailable cursor produces a batch of the
// desired size when the number of results is larger than the batch size.
// One batch's worth for the find and one more than one batch's worth for the getMore.
dropAndRecreateColl({numDocs: batchSize + (batchSize + 1)});
let cursorId = openCursor({batchSize: batchSize, tailable: true, awaitData: false});
let getMoreRes = assert.commandWorked(
db.runCommand({getMore: cursorId, collection: collName, batchSize: batchSize}));
assert.eq(getMoreRes.cursor.nextBatch.length, batchSize);
// Test that the same is true for a tailable, *awaitData* cursor.
cursorId = openCursor({batchSize: batchSize, tailable: true, awaitData: true});
getMoreRes = assert.commandWorked(
db.runCommand({getMore: cursorId, collection: collName, batchSize: batchSize}));
assert.eq(getMoreRes.cursor.nextBatch.length, batchSize);
// Test that specifying a batch size to a getMore on a tailable cursor returns all
// new results immediately, even if the batch size is larger than the number of new results.
// One batch's worth for the find and one less than one batch's worth for the getMore.
dropAndRecreateColl({numDocs: batchSize + (batchSize - 1)});
cursorId = openCursor({batchSize: batchSize, tailable: true, awaitData: false});
getMoreRes = assert.commandWorked(
db.runCommand({getMore: cursorId, collection: collName, batchSize: batchSize}));
assert.eq(getMoreRes.cursor.nextBatch.length, batchSize - 1);
// Test that the same is true for a tailable, *awaitData* cursor.
cursorId = openCursor({batchSize: batchSize, tailable: true, awaitData: true});
getMoreRes = assert.commandWorked(
db.runCommand({getMore: cursorId, collection: collName, batchSize: batchSize}));
assert.eq(getMoreRes.cursor.nextBatch.length, batchSize - 1);
// Test that using a smaller batch size than there are results will return all results without
// empty batches in between (SERVER-30799).
dropAndRecreateColl({numDocs: batchSize * 3});
cursorId = openCursor({batchSize: batchSize, tailable: true, awaitData: false});
getMoreRes = assert.commandWorked(
db.runCommand({getMore: cursorId, collection: collName, batchSize: batchSize}));
assert.eq(getMoreRes.cursor.nextBatch.length, batchSize);
getMoreRes = assert.commandWorked(
db.runCommand({getMore: cursorId, collection: collName, batchSize: batchSize}));
assert.eq(getMoreRes.cursor.nextBatch.length, batchSize);
getMoreRes = assert.commandWorked(
db.runCommand({getMore: cursorId, collection: collName, batchSize: batchSize}));
assert.eq(getMoreRes.cursor.nextBatch.length, 0);
// Avoid leaving the cursor open. Cursors above are killed by drops, but we'll avoid dropping
// the collection at the end so other consistency checks like validate can be run against it.
assert.commandWorked(db.runCommand({killCursors: collName, cursors: [getMoreRes.cursor.id]}));
}());
|