summaryrefslogtreecommitdiff
path: root/jstests/core/tailable_getmore_batch_size.js
blob: 466fa25a6862ec9b2b36e1bb9ea2541f3261a060 (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
// @tags: [requires_getmore, requires_capped]

// 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]}));
}());