summaryrefslogtreecommitdiff
path: root/jstests/core/tailable_getmore_batch_size.js
blob: be3e21f0a67d25c1f561bbb7a7ae3f70cbcd3365 (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
// 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]}));
}());