Skip to content

Commit 5c6fda1

Browse files
committed
fix: ensure implicit sessions are ended consistently
This is a fix and a refator, which ensures that implicit sessions are ended as soon as possible when cursor commands are executed. The current code path calls `_endSessions` in a confusing number of locations, and in some cases can accidentally call the method twice in a row. Reducing the number of calls to the method, and ensuring its called only after server command responses and the `close` method should prevent these errors NODE-2630
1 parent 0394f9d commit 5c6fda1

File tree

3 files changed

+28
-50
lines changed

3 files changed

+28
-50
lines changed

lib/core/cursor.js

+16-15
Original file line numberDiff line numberDiff line change
@@ -411,7 +411,15 @@ class CoreCursor extends Readable {
411411
batchSize = this.cursorState.limit - this.cursorState.currentLimit;
412412
}
413413

414-
this.server.getMore(this.ns, this.cursorState, batchSize, this.options, callback);
414+
const cursorState = this.cursorState;
415+
this.server.getMore(this.ns, cursorState, batchSize, this.options, (err, result, conn) => {
416+
// NOTE: `getMore` modifies `cursorState`, would be very ideal not to do so in the future
417+
if (err || (cursorState.cursorId && cursorState.cursorId.isZero())) {
418+
this._endSession();
419+
}
420+
421+
callback(err, result, conn);
422+
});
415423
}
416424

417425
_initializeCursor(callback) {
@@ -432,18 +440,15 @@ class CoreCursor extends Readable {
432440
}
433441

434442
function done(err, result) {
435-
if (
436-
cursor.cursorState.cursorId &&
437-
cursor.cursorState.cursorId.isZero() &&
438-
cursor._endSession
439-
) {
443+
const cursorState = cursor.cursorState;
444+
if (err || (cursorState.cursorId && cursorState.cursorId.isZero())) {
440445
cursor._endSession();
441446
}
442447

443448
if (
444-
cursor.cursorState.documents.length === 0 &&
445-
cursor.cursorState.cursorId &&
446-
cursor.cursorState.cursorId.isZero() &&
449+
cursorState.documents.length === 0 &&
450+
cursorState.cursorId &&
451+
cursorState.cursorId.isZero() &&
447452
!cursor.cmd.tailable &&
448453
!cursor.cmd.awaitData
449454
) {
@@ -689,8 +694,8 @@ function _setCursorNotifiedImpl(self, callback) {
689694
self.cursorState.documents = [];
690695
self.cursorState.cursorIndex = 0;
691696

692-
if (self._endSession) {
693-
self._endSession(undefined, () => callback());
697+
if (self.cursorState.session) {
698+
self._endSession(callback);
694699
return;
695700
}
696701

@@ -776,10 +781,6 @@ function nextFunction(self, callback) {
776781
return handleCallback(callback, err);
777782
}
778783

779-
if (self.cursorState.cursorId && self.cursorState.cursorId.isZero() && self._endSession) {
780-
self._endSession();
781-
}
782-
783784
// Save the returned connection to ensure all getMore's fire over the same connection
784785
self.connection = connection;
785786

lib/cursor.js

+10-32
Original file line numberDiff line numberDiff line change
@@ -832,9 +832,7 @@ class Cursor extends CoreCursor {
832832
const fetchDocs = () => {
833833
cursor._next((err, doc) => {
834834
if (err) {
835-
return cursor._endSession
836-
? cursor._endSession(() => handleCallback(cb, err))
837-
: handleCallback(cb, err);
835+
return handleCallback(cb, err);
838836
}
839837

840838
if (doc == null) {
@@ -914,38 +912,18 @@ class Cursor extends CoreCursor {
914912
if (typeof options === 'function') (callback = options), (options = {});
915913
options = Object.assign({}, { skipKillCursors: false }, options);
916914

917-
this.s.state = CursorState.CLOSED;
918-
if (!options.skipKillCursors) {
919-
// Kill the cursor
920-
this.kill();
921-
}
922-
923-
const completeClose = () => {
924-
// Emit the close event for the cursor
925-
this.emit('close');
926-
927-
// Callback if provided
928-
if (typeof callback === 'function') {
929-
return handleCallback(callback, null, this);
930-
}
931-
932-
// Return a Promise
933-
return new this.s.promiseLibrary(resolve => {
934-
resolve();
935-
});
936-
};
937-
938-
if (this.cursorState.session) {
939-
if (typeof callback === 'function') {
940-
return this._endSession(() => completeClose());
915+
return maybePromise(this, callback, cb => {
916+
this.s.state = CursorState.CLOSED;
917+
if (!options.skipKillCursors) {
918+
// Kill the cursor
919+
this.kill();
941920
}
942921

943-
return new this.s.promiseLibrary(resolve => {
944-
this._endSession(() => completeClose().then(resolve));
922+
this._endSession(() => {
923+
this.emit('close');
924+
cb(null, this);
945925
});
946-
}
947-
948-
return completeClose();
926+
});
949927
}
950928

951929
/**

lib/operations/cursor_ops.js

+2-3
Original file line numberDiff line numberDiff line change
@@ -134,10 +134,9 @@ function toArray(cursor, callback) {
134134
const fetchDocs = () => {
135135
cursor._next((err, doc) => {
136136
if (err) {
137-
return cursor._endSession
138-
? cursor._endSession(() => handleCallback(callback, err))
139-
: handleCallback(callback, err);
137+
return handleCallback(callback, err);
140138
}
139+
141140
if (doc == null) {
142141
return cursor.close({ skipKillCursors: true }, () => handleCallback(callback, null, items));
143142
}

0 commit comments

Comments
 (0)