mongodb 6.11.0 → 6.12.0-dev.20241212.sha.f6d7868f
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -8
- package/lib/beta.d.ts +43 -85
- package/lib/bulk/common.js +5 -7
- package/lib/bulk/common.js.map +1 -1
- package/lib/change_stream.js +16 -26
- package/lib/change_stream.js.map +1 -1
- package/lib/cmap/connect.js +15 -28
- package/lib/cmap/connect.js.map +1 -1
- package/lib/cmap/connection.js +1 -1
- package/lib/cmap/connection.js.map +1 -1
- package/lib/cmap/connection_pool.js +83 -117
- package/lib/cmap/connection_pool.js.map +1 -1
- package/lib/collection.js +3 -0
- package/lib/collection.js.map +1 -1
- package/lib/encrypter.js +5 -9
- package/lib/encrypter.js.map +1 -1
- package/lib/error.js +37 -19
- package/lib/error.js.map +1 -1
- package/lib/index.js +3 -2
- package/lib/index.js.map +1 -1
- package/lib/mongo_client.js +20 -26
- package/lib/mongo_client.js.map +1 -1
- package/lib/operations/operation.js +4 -5
- package/lib/operations/operation.js.map +1 -1
- package/lib/sdam/monitor.js +25 -31
- package/lib/sdam/monitor.js.map +1 -1
- package/lib/sdam/server.js +1 -1
- package/lib/sdam/server.js.map +1 -1
- package/lib/sdam/server_description.js +3 -0
- package/lib/sdam/server_description.js.map +1 -1
- package/lib/sdam/topology.js +13 -16
- package/lib/sdam/topology.js.map +1 -1
- package/lib/sdam/topology_description.js +9 -3
- package/lib/sdam/topology_description.js.map +1 -1
- package/lib/sessions.js +24 -48
- package/lib/sessions.js.map +1 -1
- package/mongodb.d.ts +43 -85
- package/package.json +5 -5
- package/src/bulk/common.ts +6 -9
- package/src/change_stream.ts +21 -33
- package/src/cmap/connect.ts +33 -34
- package/src/cmap/connection.ts +1 -1
- package/src/cmap/connection_pool.ts +104 -142
- package/src/collection.ts +3 -0
- package/src/encrypter.ts +6 -11
- package/src/error.ts +48 -25
- package/src/index.ts +1 -0
- package/src/mongo_client.ts +26 -32
- package/src/operations/operation.ts +5 -7
- package/src/sdam/monitor.ts +30 -38
- package/src/sdam/server.ts +2 -2
- package/src/sdam/server_description.ts +3 -0
- package/src/sdam/topology.ts +15 -19
- package/src/sdam/topology_description.ts +13 -4
- package/src/sessions.ts +37 -58
package/src/sdam/topology.ts
CHANGED
|
@@ -88,11 +88,6 @@ const stateTransition = makeStateMachine({
|
|
|
88
88
|
[STATE_CLOSING]: [STATE_CLOSING, STATE_CLOSED]
|
|
89
89
|
});
|
|
90
90
|
|
|
91
|
-
/** @internal */
|
|
92
|
-
const kCancelled = Symbol('cancelled');
|
|
93
|
-
/** @internal */
|
|
94
|
-
const kWaitQueue = Symbol('waitQueue');
|
|
95
|
-
|
|
96
91
|
/** @internal */
|
|
97
92
|
export type ServerSelectionCallback = Callback<Server>;
|
|
98
93
|
|
|
@@ -105,7 +100,7 @@ export interface ServerSelectionRequest {
|
|
|
105
100
|
startTime: number;
|
|
106
101
|
resolve: (server: Server) => void;
|
|
107
102
|
reject: (error: MongoError) => void;
|
|
108
|
-
|
|
103
|
+
cancelled: boolean;
|
|
109
104
|
operationName: string;
|
|
110
105
|
waitingLogged: boolean;
|
|
111
106
|
previousServer?: ServerDescription;
|
|
@@ -208,7 +203,7 @@ export class Topology extends TypedEventEmitter<TopologyEvents> {
|
|
|
208
203
|
/** @internal */
|
|
209
204
|
s: TopologyPrivate;
|
|
210
205
|
/** @internal */
|
|
211
|
-
|
|
206
|
+
waitQueue: List<ServerSelectionRequest>;
|
|
212
207
|
/** @internal */
|
|
213
208
|
hello?: Document;
|
|
214
209
|
/** @internal */
|
|
@@ -293,7 +288,7 @@ export class Topology extends TypedEventEmitter<TopologyEvents> {
|
|
|
293
288
|
serverDescriptions.set(hostAddress.toString(), new ServerDescription(hostAddress));
|
|
294
289
|
}
|
|
295
290
|
|
|
296
|
-
this
|
|
291
|
+
this.waitQueue = new List();
|
|
297
292
|
this.s = {
|
|
298
293
|
// the id of this topology
|
|
299
294
|
id: topologyId,
|
|
@@ -506,7 +501,7 @@ export class Topology extends TypedEventEmitter<TopologyEvents> {
|
|
|
506
501
|
|
|
507
502
|
stateTransition(this, STATE_CLOSING);
|
|
508
503
|
|
|
509
|
-
drainWaitQueue(this
|
|
504
|
+
drainWaitQueue(this.waitQueue, new MongoTopologyClosedError());
|
|
510
505
|
|
|
511
506
|
if (this.s.srvPoller) {
|
|
512
507
|
this.s.srvPoller.stop();
|
|
@@ -601,13 +596,14 @@ export class Topology extends TypedEventEmitter<TopologyEvents> {
|
|
|
601
596
|
transaction,
|
|
602
597
|
resolve,
|
|
603
598
|
reject,
|
|
599
|
+
cancelled: false,
|
|
604
600
|
startTime: now(),
|
|
605
601
|
operationName: options.operationName,
|
|
606
602
|
waitingLogged: false,
|
|
607
603
|
previousServer: options.previousServer
|
|
608
604
|
};
|
|
609
605
|
|
|
610
|
-
this
|
|
606
|
+
this.waitQueue.push(waitQueueMember);
|
|
611
607
|
processWaitQueue(this);
|
|
612
608
|
|
|
613
609
|
try {
|
|
@@ -620,7 +616,7 @@ export class Topology extends TypedEventEmitter<TopologyEvents> {
|
|
|
620
616
|
} catch (error) {
|
|
621
617
|
if (TimeoutError.is(error)) {
|
|
622
618
|
// Timeout
|
|
623
|
-
waitQueueMember
|
|
619
|
+
waitQueueMember.cancelled = true;
|
|
624
620
|
const timeoutError = new MongoServerSelectionError(
|
|
625
621
|
`Server selection timed out after ${timeout?.duration} ms`,
|
|
626
622
|
this.description
|
|
@@ -721,7 +717,7 @@ export class Topology extends TypedEventEmitter<TopologyEvents> {
|
|
|
721
717
|
updateServers(this, serverDescription);
|
|
722
718
|
|
|
723
719
|
// attempt to resolve any outstanding server selection attempts
|
|
724
|
-
if (this
|
|
720
|
+
if (this.waitQueue.length > 0) {
|
|
725
721
|
processWaitQueue(this);
|
|
726
722
|
}
|
|
727
723
|
|
|
@@ -910,7 +906,7 @@ function drainWaitQueue(queue: List<ServerSelectionRequest>, drainError: MongoDr
|
|
|
910
906
|
continue;
|
|
911
907
|
}
|
|
912
908
|
|
|
913
|
-
if (!waitQueueMember
|
|
909
|
+
if (!waitQueueMember.cancelled) {
|
|
914
910
|
if (
|
|
915
911
|
waitQueueMember.mongoLogger?.willLog(
|
|
916
912
|
MongoLoggableComponent.SERVER_SELECTION,
|
|
@@ -934,20 +930,20 @@ function drainWaitQueue(queue: List<ServerSelectionRequest>, drainError: MongoDr
|
|
|
934
930
|
|
|
935
931
|
function processWaitQueue(topology: Topology) {
|
|
936
932
|
if (topology.s.state === STATE_CLOSED) {
|
|
937
|
-
drainWaitQueue(topology
|
|
933
|
+
drainWaitQueue(topology.waitQueue, new MongoTopologyClosedError());
|
|
938
934
|
return;
|
|
939
935
|
}
|
|
940
936
|
|
|
941
937
|
const isSharded = topology.description.type === TopologyType.Sharded;
|
|
942
938
|
const serverDescriptions = Array.from(topology.description.servers.values());
|
|
943
|
-
const membersToProcess = topology
|
|
939
|
+
const membersToProcess = topology.waitQueue.length;
|
|
944
940
|
for (let i = 0; i < membersToProcess; ++i) {
|
|
945
|
-
const waitQueueMember = topology
|
|
941
|
+
const waitQueueMember = topology.waitQueue.shift();
|
|
946
942
|
if (!waitQueueMember) {
|
|
947
943
|
continue;
|
|
948
944
|
}
|
|
949
945
|
|
|
950
|
-
if (waitQueueMember
|
|
946
|
+
if (waitQueueMember.cancelled) {
|
|
951
947
|
continue;
|
|
952
948
|
}
|
|
953
949
|
|
|
@@ -1006,7 +1002,7 @@ function processWaitQueue(topology: Topology) {
|
|
|
1006
1002
|
}
|
|
1007
1003
|
waitQueueMember.waitingLogged = true;
|
|
1008
1004
|
}
|
|
1009
|
-
topology
|
|
1005
|
+
topology.waitQueue.push(waitQueueMember);
|
|
1010
1006
|
continue;
|
|
1011
1007
|
} else if (selectedDescriptions.length === 1) {
|
|
1012
1008
|
selectedServer = topology.s.servers.get(selectedDescriptions[0].address);
|
|
@@ -1069,7 +1065,7 @@ function processWaitQueue(topology: Topology) {
|
|
|
1069
1065
|
waitQueueMember.resolve(selectedServer);
|
|
1070
1066
|
}
|
|
1071
1067
|
|
|
1072
|
-
if (topology
|
|
1068
|
+
if (topology.waitQueue.length > 0) {
|
|
1073
1069
|
// ensure all server monitors attempt monitoring soon
|
|
1074
1070
|
for (const [, server] of topology.s.servers) {
|
|
1075
1071
|
process.nextTick(function scheduleServerCheck() {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { EJSON, type ObjectId } from '../bson';
|
|
2
2
|
import * as WIRE_CONSTANTS from '../cmap/wire_protocol/constants';
|
|
3
|
-
import { type MongoError, MongoRuntimeError } from '../error';
|
|
3
|
+
import { type MongoError, MongoRuntimeError, MongoStalePrimaryError } from '../error';
|
|
4
4
|
import { compareObjectId, shuffle } from '../utils';
|
|
5
5
|
import { ServerType, TopologyType } from './common';
|
|
6
6
|
import { ServerDescription } from './server_description';
|
|
@@ -400,7 +400,9 @@ function updateRsFromPrimary(
|
|
|
400
400
|
// replace serverDescription with a default ServerDescription of type "Unknown"
|
|
401
401
|
serverDescriptions.set(
|
|
402
402
|
serverDescription.address,
|
|
403
|
-
new ServerDescription(serverDescription.address
|
|
403
|
+
new ServerDescription(serverDescription.address, undefined, {
|
|
404
|
+
error: new MongoStalePrimaryError(serverDescription, maxSetVersion, maxElectionId)
|
|
405
|
+
})
|
|
404
406
|
);
|
|
405
407
|
|
|
406
408
|
return [checkHasPrimary(serverDescriptions), setName, maxSetVersion, maxElectionId];
|
|
@@ -416,7 +418,9 @@ function updateRsFromPrimary(
|
|
|
416
418
|
// this primary is stale, we must remove it
|
|
417
419
|
serverDescriptions.set(
|
|
418
420
|
serverDescription.address,
|
|
419
|
-
new ServerDescription(serverDescription.address
|
|
421
|
+
new ServerDescription(serverDescription.address, undefined, {
|
|
422
|
+
error: new MongoStalePrimaryError(serverDescription, maxSetVersion, maxElectionId)
|
|
423
|
+
})
|
|
420
424
|
);
|
|
421
425
|
|
|
422
426
|
return [checkHasPrimary(serverDescriptions), setName, maxSetVersion, maxElectionId];
|
|
@@ -438,7 +442,12 @@ function updateRsFromPrimary(
|
|
|
438
442
|
for (const [address, server] of serverDescriptions) {
|
|
439
443
|
if (server.type === ServerType.RSPrimary && server.address !== serverDescription.address) {
|
|
440
444
|
// Reset old primary's type to Unknown.
|
|
441
|
-
serverDescriptions.set(
|
|
445
|
+
serverDescriptions.set(
|
|
446
|
+
address,
|
|
447
|
+
new ServerDescription(server.address, undefined, {
|
|
448
|
+
error: new MongoStalePrimaryError(serverDescription, maxSetVersion, maxElectionId)
|
|
449
|
+
})
|
|
450
|
+
);
|
|
442
451
|
|
|
443
452
|
// There can only be one primary
|
|
444
453
|
break;
|
package/src/sessions.ts
CHANGED
|
@@ -83,17 +83,6 @@ export type ClientSessionEvents = {
|
|
|
83
83
|
ended(session: ClientSession): void;
|
|
84
84
|
};
|
|
85
85
|
|
|
86
|
-
/** @internal */
|
|
87
|
-
const kServerSession = Symbol('serverSession');
|
|
88
|
-
/** @internal */
|
|
89
|
-
const kSnapshotTime = Symbol('snapshotTime');
|
|
90
|
-
/** @internal */
|
|
91
|
-
const kSnapshotEnabled = Symbol('snapshotEnabled');
|
|
92
|
-
/** @internal */
|
|
93
|
-
const kPinnedConnection = Symbol('pinnedConnection');
|
|
94
|
-
/** @internal Accumulates total number of increments to add to txnNumber when applying session to command */
|
|
95
|
-
const kTxnNumberIncrement = Symbol('txnNumberIncrement');
|
|
96
|
-
|
|
97
86
|
/** @public */
|
|
98
87
|
export interface EndSessionOptions {
|
|
99
88
|
/**
|
|
@@ -132,20 +121,22 @@ export class ClientSession
|
|
|
132
121
|
owner?: symbol | AbstractCursor;
|
|
133
122
|
defaultTransactionOptions: TransactionOptions;
|
|
134
123
|
transaction: Transaction;
|
|
135
|
-
/**
|
|
124
|
+
/**
|
|
125
|
+
* @internal
|
|
136
126
|
* Keeps track of whether or not the current transaction has attempted to be committed. Is
|
|
137
|
-
* initially undefined. Gets set to false when startTransaction is called. When commitTransaction is sent to server, if the commitTransaction succeeds, it is then set to undefined, otherwise, set to true
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
127
|
+
* initially undefined. Gets set to false when startTransaction is called. When commitTransaction is sent to server, if the commitTransaction succeeds, it is then set to undefined, otherwise, set to true
|
|
128
|
+
*/
|
|
129
|
+
private commitAttempted?: boolean;
|
|
130
|
+
public readonly snapshotEnabled: boolean;
|
|
131
|
+
|
|
141
132
|
/** @internal */
|
|
142
|
-
|
|
133
|
+
private _serverSession: ServerSession | null;
|
|
143
134
|
/** @internal */
|
|
144
|
-
|
|
135
|
+
public snapshotTime?: Timestamp;
|
|
145
136
|
/** @internal */
|
|
146
|
-
|
|
137
|
+
public pinnedConnection?: Connection;
|
|
147
138
|
/** @internal */
|
|
148
|
-
|
|
139
|
+
public txnNumberIncrement: number;
|
|
149
140
|
/**
|
|
150
141
|
* @experimental
|
|
151
142
|
* Specifies the time an operation in a given `ClientSession` will run until it throws a timeout error
|
|
@@ -183,13 +174,11 @@ export class ClientSession
|
|
|
183
174
|
|
|
184
175
|
options = options ?? {};
|
|
185
176
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
);
|
|
192
|
-
}
|
|
177
|
+
this.snapshotEnabled = options.snapshot === true;
|
|
178
|
+
if (options.causalConsistency === true && this.snapshotEnabled) {
|
|
179
|
+
throw new MongoInvalidArgumentError(
|
|
180
|
+
'Properties "causalConsistency" and "snapshot" are mutually exclusive'
|
|
181
|
+
);
|
|
193
182
|
}
|
|
194
183
|
|
|
195
184
|
this.client = client;
|
|
@@ -199,8 +188,8 @@ export class ClientSession
|
|
|
199
188
|
this.timeoutMS = options.defaultTimeoutMS ?? client.s.options?.timeoutMS;
|
|
200
189
|
|
|
201
190
|
this.explicit = !!options.explicit;
|
|
202
|
-
this
|
|
203
|
-
this
|
|
191
|
+
this._serverSession = this.explicit ? this.sessionPool.acquire() : null;
|
|
192
|
+
this.txnNumberIncrement = 0;
|
|
204
193
|
|
|
205
194
|
const defaultCausalConsistencyValue = this.explicit && options.snapshot !== true;
|
|
206
195
|
this.supports = {
|
|
@@ -218,11 +207,11 @@ export class ClientSession
|
|
|
218
207
|
|
|
219
208
|
/** The server id associated with this session */
|
|
220
209
|
get id(): ServerSessionId | undefined {
|
|
221
|
-
return this
|
|
210
|
+
return this.serverSession?.id;
|
|
222
211
|
}
|
|
223
212
|
|
|
224
213
|
get serverSession(): ServerSession {
|
|
225
|
-
let serverSession = this
|
|
214
|
+
let serverSession = this._serverSession;
|
|
226
215
|
if (serverSession == null) {
|
|
227
216
|
if (this.explicit) {
|
|
228
217
|
throw new MongoRuntimeError('Unexpected null serverSession for an explicit session');
|
|
@@ -231,32 +220,22 @@ export class ClientSession
|
|
|
231
220
|
throw new MongoRuntimeError('Unexpected null serverSession for an ended implicit session');
|
|
232
221
|
}
|
|
233
222
|
serverSession = this.sessionPool.acquire();
|
|
234
|
-
this
|
|
223
|
+
this._serverSession = serverSession;
|
|
235
224
|
}
|
|
236
225
|
return serverSession;
|
|
237
226
|
}
|
|
238
227
|
|
|
239
|
-
/** Whether or not this session is configured for snapshot reads */
|
|
240
|
-
get snapshotEnabled(): boolean {
|
|
241
|
-
return this[kSnapshotEnabled];
|
|
242
|
-
}
|
|
243
|
-
|
|
244
228
|
get loadBalanced(): boolean {
|
|
245
229
|
return this.client.topology?.description.type === TopologyType.LoadBalanced;
|
|
246
230
|
}
|
|
247
231
|
|
|
248
|
-
/** @internal */
|
|
249
|
-
get pinnedConnection(): Connection | undefined {
|
|
250
|
-
return this[kPinnedConnection];
|
|
251
|
-
}
|
|
252
|
-
|
|
253
232
|
/** @internal */
|
|
254
233
|
pin(conn: Connection): void {
|
|
255
|
-
if (this
|
|
234
|
+
if (this.pinnedConnection) {
|
|
256
235
|
throw TypeError('Cannot pin multiple connections to the same session');
|
|
257
236
|
}
|
|
258
237
|
|
|
259
|
-
this
|
|
238
|
+
this.pinnedConnection = conn;
|
|
260
239
|
conn.emit(
|
|
261
240
|
PINNED,
|
|
262
241
|
this.inTransaction() ? ConnectionPoolMetrics.TXN : ConnectionPoolMetrics.CURSOR
|
|
@@ -273,7 +252,7 @@ export class ClientSession
|
|
|
273
252
|
}
|
|
274
253
|
|
|
275
254
|
get isPinned(): boolean {
|
|
276
|
-
return this.loadBalanced ? !!this
|
|
255
|
+
return this.loadBalanced ? !!this.pinnedConnection : this.transaction.isPinned;
|
|
277
256
|
}
|
|
278
257
|
|
|
279
258
|
/**
|
|
@@ -295,12 +274,12 @@ export class ClientSession
|
|
|
295
274
|
squashError(error);
|
|
296
275
|
} finally {
|
|
297
276
|
if (!this.hasEnded) {
|
|
298
|
-
const serverSession = this
|
|
277
|
+
const serverSession = this.serverSession;
|
|
299
278
|
if (serverSession != null) {
|
|
300
279
|
// release the server session back to the pool
|
|
301
280
|
this.sessionPool.release(serverSession);
|
|
302
281
|
// Store a clone of the server session for reference (debugging)
|
|
303
|
-
this
|
|
282
|
+
this._serverSession = new ServerSession(serverSession);
|
|
304
283
|
}
|
|
305
284
|
// mark the session as ended, and emit a signal
|
|
306
285
|
this.hasEnded = true;
|
|
@@ -391,7 +370,7 @@ export class ClientSession
|
|
|
391
370
|
* This is because the serverSession is lazily acquired after a connection is obtained
|
|
392
371
|
*/
|
|
393
372
|
incrementTransactionNumber(): void {
|
|
394
|
-
this
|
|
373
|
+
this.txnNumberIncrement += 1;
|
|
395
374
|
}
|
|
396
375
|
|
|
397
376
|
/** @returns whether this session is currently in a transaction or not */
|
|
@@ -410,7 +389,7 @@ export class ClientSession
|
|
|
410
389
|
* @param options - Options for the transaction
|
|
411
390
|
*/
|
|
412
391
|
startTransaction(options?: TransactionOptions): void {
|
|
413
|
-
if (this
|
|
392
|
+
if (this.snapshotEnabled) {
|
|
414
393
|
throw new MongoCompatibilityError('Transactions are not supported in snapshot sessions');
|
|
415
394
|
}
|
|
416
395
|
|
|
@@ -908,7 +887,7 @@ export function maybeClearPinnedConnection(
|
|
|
908
887
|
options?: EndSessionOptions
|
|
909
888
|
): void {
|
|
910
889
|
// unpin a connection if it has been pinned
|
|
911
|
-
const conn = session
|
|
890
|
+
const conn = session.pinnedConnection;
|
|
912
891
|
const error = options?.error;
|
|
913
892
|
|
|
914
893
|
if (
|
|
@@ -929,7 +908,7 @@ export function maybeClearPinnedConnection(
|
|
|
929
908
|
|
|
930
909
|
if (options?.error == null || options?.force) {
|
|
931
910
|
loadBalancer.pool.checkIn(conn);
|
|
932
|
-
session
|
|
911
|
+
session.pinnedConnection = undefined;
|
|
933
912
|
conn.emit(
|
|
934
913
|
UNPINNED,
|
|
935
914
|
session.transaction.state !== TxnState.NO_TRANSACTION
|
|
@@ -1123,8 +1102,8 @@ export function applySession(
|
|
|
1123
1102
|
const isRetryableWrite = !!options.willRetryWrite;
|
|
1124
1103
|
|
|
1125
1104
|
if (isRetryableWrite || inTxnOrTxnCommand) {
|
|
1126
|
-
serverSession.txnNumber += session
|
|
1127
|
-
session
|
|
1105
|
+
serverSession.txnNumber += session.txnNumberIncrement;
|
|
1106
|
+
session.txnNumberIncrement = 0;
|
|
1128
1107
|
// TODO(NODE-2674): Preserve int64 sent from MongoDB
|
|
1129
1108
|
command.txnNumber = Long.fromNumber(serverSession.txnNumber);
|
|
1130
1109
|
}
|
|
@@ -1141,10 +1120,10 @@ export function applySession(
|
|
|
1141
1120
|
) {
|
|
1142
1121
|
command.readConcern = command.readConcern || {};
|
|
1143
1122
|
Object.assign(command.readConcern, { afterClusterTime: session.operationTime });
|
|
1144
|
-
} else if (session
|
|
1123
|
+
} else if (session.snapshotEnabled) {
|
|
1145
1124
|
command.readConcern = command.readConcern || { level: ReadConcernLevel.snapshot };
|
|
1146
|
-
if (session
|
|
1147
|
-
Object.assign(command.readConcern, { atClusterTime: session
|
|
1125
|
+
if (session.snapshotTime != null) {
|
|
1126
|
+
Object.assign(command.readConcern, { atClusterTime: session.snapshotTime });
|
|
1148
1127
|
}
|
|
1149
1128
|
}
|
|
1150
1129
|
|
|
@@ -1187,12 +1166,12 @@ export function updateSessionFromResponse(session: ClientSession, document: Mong
|
|
|
1187
1166
|
session.transaction._recoveryToken = document.recoveryToken;
|
|
1188
1167
|
}
|
|
1189
1168
|
|
|
1190
|
-
if (session?.
|
|
1169
|
+
if (session?.snapshotEnabled && session.snapshotTime == null) {
|
|
1191
1170
|
// find and aggregate commands return atClusterTime on the cursor
|
|
1192
1171
|
// distinct includes it in the response body
|
|
1193
1172
|
const atClusterTime = document.atClusterTime;
|
|
1194
1173
|
if (atClusterTime) {
|
|
1195
|
-
session
|
|
1174
|
+
session.snapshotTime = atClusterTime;
|
|
1196
1175
|
}
|
|
1197
1176
|
}
|
|
1198
1177
|
}
|