ISSUE DESCRIPTION
The 3.0.0 driver added support for implicit sessions as well as a session pool.
This issue tracks several bugs with implicit session management that either caused sessions to be leaked, or did not use implicit sessions properly.
IMPACT
Applications that are exposed to this leak may first notice it by observing SERVER-33158. Messages like the ones below will appear in the server logs:
2018-02-06T13:18:44.855+0000 E - [thread70181] Assertion: 10334:BSONObj size: 19492699 (0x1296F5B) is invalid. Size must be between 0 and 16793600(16MB) First element: 0: { q: { _id: { id: UUID("5447911f-6c78-4238-aeae-c249bec5df73"), uid: BinData(0, F5748B71272004FF160A969FEE42869CBD48FD155B00AFD0EF604F431FFB2F4F) } }, u: { $currentDate: { lastUse: true }, $setOnInsert: { user: { name: "vocab@admin" } } }, upsert: true } src/mongo/bson/bsonobj.cpp 101 2018-02-06T13:18:44.925+0000 I CONTROL [thread70181] Failed to refresh session cache: Location10334: BSONObj size: 19492699 (0x1296F5B) is invalid. Size must be between 0 and 16793600(16MB) First element: 0: { q: { _id: { id: UUID("5447911f-6c78-4238-aeae-c249bec5df73"), uid: BinData(0, F5748B71272004FF160A969FEE42869CBD48FD155B00AFD0EF604F431FFB2F4F) } }, u: { $currentDate: { lastUse: true }, $setOnInsert: { user: { name: "vocab@admin" } } }, upsert: true }
EXAMPLES
A couple of examples which demonstrate the leaks can be found below.
Implicit Sessions would not be ended upon destruction of client
const {MongoClient} = require('mongodb'); const connectionString = ...; MongoClient.connect(connectionString, function(err, client) { client.db('test').collection('test').find({}).toArray(function(err, docs) { console.log(docs); client.close(); }); });
The above code will create an implicit session, but will not destroy when the client is destroyed. Since the client-side pool is destroyed when the client is destroyed, there is no way to end the server instance of the session.
This was fixed in driver version 3.0.3 with NODE-1333.
Implicit Sessions would not be ended if an asynchronous operation throws a synchronous error.
Some driver operations will synchronously throw errors. For example:
const {MongoClient} = require('mongodb'); const connectionString = ...; MongoClient.connect(connectionString, function(err, client) { try { client.db('test').collection('test').rename(5, function(err, collection) {}); } catch (err) { console.log(err.message); //'collection name must be a String' client.close(); } });
In this case, the implicit session will be created for the operation, but will not be cleaned up.
This was fixed in driver version 3.0.4 with NODE-1335
Operations that returned cursors will not create implicit sessions.
Operations that returned cursors are not using implicit sessions. For example:
const {MongoClient} = require('mongodb'); const connectionString = ...; MongoClient.connect(connectionString, function(err, client) { const cursor = client.db('test').collection('test').find({}); cursor.toArray(function(err, docs) { console.log(docs); client.close(); }); });
The above operation will not use implicit sessions.
This is being tracked with NODE-1326