Details
Description
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() {}
|