The DBCommandCursor constructor stores the cursor id received from the server as a native Javascript floating-point type, which can't represent large 64-bit integral values with integer-level precision. As a result, the shell will perform a getMore on the wrong cursor id, when the cursor id value it receives from the server is large.
Reproduce as follows:
> db.foo.drop() false > db.foo.insert({a:1}) WriteResult({ "nInserted" : 1 }) > db.foo.insert({a:2}) WriteResult({ "nInserted" : 1 }) > db.foo.insert({a:3}) WriteResult({ "nInserted" : 1 }) > db.foo.find().batchSize(2) { "_id" : ObjectId("55c3e66795f87f43db9384f2"), "a" : 1 } { "_id" : ObjectId("55c3e66a95f87f43db9384f3"), "a" : 2 } assert: command failed: { "ok" : 0, "errmsg" : "Cursor not found, cursor id: 4611686066194094000", "code" : 43 } : undefined
The following patch helps with reproducibility:
diff --git a/src/mongo/db/catalog/cursor_manager.cpp b/src/mongo/db/catalog/cursor_manager.cpp index 4adae4e..5aea2a0 100644 --- a/src/mongo/db/catalog/cursor_manager.cpp +++ b/src/mongo/db/catalog/cursor_manager.cpp @@ -139,7 +139,7 @@ MONGO_INITIALIZER_WITH_PREREQUISITES(GlobalCursorManager, ("GlobalCursorIdCache" return Status::OK(); } -GlobalCursorIdCache::GlobalCursorIdCache() : _nextId(0), _secureRandom() {} +GlobalCursorIdCache::GlobalCursorIdCache() : _nextId(2147483648), _secureRandom() {} GlobalCursorIdCache::~GlobalCursorIdCache() {}