summaryrefslogtreecommitdiff
path: root/jstests/core/tailable_cursor_invalidation.js
blob: 97ea96bb8d00d8d63d5fcb22b4244f46f8a293ba (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
// @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);
}());