[SERVER-30848] getMore requests do not use a session in the mongo shell Created: 25/Aug/17  Updated: 30/Oct/23  Resolved: 03/Oct/17

Status: Closed
Project: Core Server
Component/s: Shell
Affects Version/s: None
Fix Version/s: 3.6.0-rc0

Type: Bug Priority: Major - P3
Reporter: Max Hirschhorn Assignee: Mira Carey
Resolution: Fixed Votes: 0
Labels: todo_in_code
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Related
related to SERVER-33284 Garbage collection of DBCommandCursor... Closed
related to SERVER-43517 Remove special casing for getMore in ... Closed
related to SERVER-30959 session_jscore_passthrough.yml test s... Closed
is related to SERVER-28343 Enforce that GETMORE operations can o... Closed
Backwards Compatibility: Fully Compatible
Operating System: ALL
Steps To Reproduce:

/**
 * Tests that "getMore" commands use the same session id as the original "find" command when a
 * cursor is created in the mongo shell.
 */
(function() {
    "use strict";
 
    load("jstests/libs/parallelTester.js");
 
    const conn = MongoRunner.runMongod({});
 
    const db = conn.startSession().getDatabase("test");
    const coll = db.repro_nosession_getmore;
 
    const insertRes = coll.insert([{}, {}, {}, {}, {}]);
    assert.writeOK(insertRes);
    assert.eq(5, insertRes.nInserted);
 
    const triggeredFind = new CountDownLatch(1);
    const triggerGetMore = new CountDownLatch(1);
 
    function runFindAndThenGetMore(host, triggeredFind, triggerGetMore) {
        try {
            const conn = new Mongo(host);
            const db = conn.startSession().getDatabase("test");
            const coll = db.repro_nosession_getmore;
 
            const cursor = coll.find().batchSize(2);
            cursor.next();
            cursor.next();
 
            triggeredFind.countDown();
            triggerGetMore.await();
 
            cursor.next();
            return {ok: 1};
        } catch (e) {
            return {ok: 0, error: e.toString(), stack: e.stack};
        }
    }
 
    assert.commandWorked(conn.adminCommand({setParameter: 1, internalQueryExecYieldIterations: 1}));
    assert.commandWorked(
        conn.adminCommand({configureFailPoint: "setYieldAllLocksHang", mode: "alwaysOn"}));
 
    //
    // Run a "find" command and verify that it has a session id.
    //
 
    const cursorThread =
        new ScopedThread(runFindAndThenGetMore, conn.host, triggeredFind, triggerGetMore);
    cursorThread.start();
 
    let op;
    let currentOpRes;
 
    assert.soon(
        function() {
            currentOpRes = assert.commandWorked(db.currentOp({ns: coll.getFullName()}));
            if (currentOpRes.inprog.length === 1 && currentOpRes.inprog[0].numYields > 0) {
                op = currentOpRes.inprog[0];
                return true;
            }
            return false;
        },
        function() {
            return "Failed to find operation in currentOp() output: " + tojson(currentOpRes);
        });
 
    assert(op.hasOwnProperty("lsid"),
           "Expected 'find' command to have a session id: " + tojson(op));
    const sessionId = op.lsid;
 
    // Disable the failpoint and wait until 'cursorThread' has consumed the documents returned in
    // the "find" command's initial batch.
    assert.commandWorked(
        conn.adminCommand({configureFailPoint: "setYieldAllLocksHang", mode: "off"}));
 
    triggeredFind.await();
 
    assert.commandWorked(
        conn.adminCommand({configureFailPoint: "setYieldAllLocksHang", mode: "alwaysOn"}));
 
    triggerGetMore.countDown();
 
    //
    // Run a "getMore" command and verify that it has the same session id as the "find" command.
    //
 
    assert.soon(
        function() {
            currentOpRes = assert.commandWorked(db.currentOp({ns: coll.getFullName()}));
            if (currentOpRes.inprog.length === 1 && currentOpRes.inprog[0].numYields > 0) {
                op = currentOpRes.inprog[0];
                return true;
            }
            return false;
        },
        function() {
            return "Failed to find operation in currentOp() output: " + tojson(currentOpRes);
        });
 
    assert.eq(sessionId,
              op.lsid,
              "Expected 'getMore' command to have the same session id: " + tojson(op));
 
    // Disable the failpoint and wait for 'cursorThread' to exit.
    assert.commandWorked(
        conn.adminCommand({configureFailPoint: "setYieldAllLocksHang", mode: "off"}));
 
    cursorThread.join();
    assert.commandWorked(cursorThread.returnData());
 
    MongoRunner.stopMongod(conn);
})();

Sprint: Platforms 2017-10-02, Platforms 2017-10-23
Participants:
Linked BF Score: 21

 Description   

The DBCommandCursor object wraps a Mongo connection object, which doesn't have a notion of being associated with a ServerSession object. This causes "getMore" operations on the cursor to not be sent with a logical session id associated with them.



 Comments   
Comment by Githook User [ 03/Oct/17 ]

Author:

{'email': 'jcarey@argv.me', 'name': 'Jason Carey', 'username': 'hanumantmk'}

Message: SERVER-30848 make shell getMores use sessions

The shell should attach the logical session used to initiate cursors
(via find or aggregate) and use it for successive getMores.
Branch: master
https://github.com/mongodb/mongo/commit/f23002e965d29158505575d09432faf403efcb56

Comment by ADAM Martin (Inactive) [ 08/Sep/17 ]

Because the cursor session checking is not enforced when auth is off or when the user has impersonate or system-level privileges, no existing tests should break. Getmore should use a session in the shell, but existing tests are fine.

Generated at Thu Feb 08 04:25:13 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.