mongodb 4.7.0 → 4.8.0
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/lib/change_stream.js +136 -271
- package/lib/change_stream.js.map +1 -1
- package/lib/cmap/command_monitoring_events.js +2 -3
- package/lib/cmap/command_monitoring_events.js.map +1 -1
- package/lib/cmap/connect.js +3 -6
- package/lib/cmap/connect.js.map +1 -1
- package/lib/cmap/connection.js.map +1 -1
- package/lib/cmap/wire_protocol/compression.js +2 -6
- package/lib/cmap/wire_protocol/compression.js.map +1 -1
- package/lib/collection.js +18 -3
- package/lib/collection.js.map +1 -1
- package/lib/cursor/abstract_cursor.js +55 -62
- package/lib/cursor/abstract_cursor.js.map +1 -1
- package/lib/cursor/change_stream_cursor.js +115 -0
- package/lib/cursor/change_stream_cursor.js.map +1 -0
- package/lib/cursor/list_collections_cursor.js +37 -0
- package/lib/cursor/list_collections_cursor.js.map +1 -0
- package/lib/cursor/list_indexes_cursor.js +36 -0
- package/lib/cursor/list_indexes_cursor.js.map +1 -0
- package/lib/db.js +2 -2
- package/lib/db.js.map +1 -1
- package/lib/deps.js.map +1 -1
- package/lib/encrypter.js +5 -12
- package/lib/encrypter.js.map +1 -1
- package/lib/index.js +9 -7
- package/lib/index.js.map +1 -1
- package/lib/mongo_client.js +49 -21
- package/lib/mongo_client.js.map +1 -1
- package/lib/mongo_types.js.map +1 -1
- package/lib/operations/common_functions.js.map +1 -1
- package/lib/operations/estimated_document_count.js +5 -0
- package/lib/operations/estimated_document_count.js.map +1 -1
- package/lib/operations/execute_operation.js +17 -8
- package/lib/operations/execute_operation.js.map +1 -1
- package/lib/operations/get_more.js +1 -1
- package/lib/operations/get_more.js.map +1 -1
- package/lib/operations/indexes.js +1 -32
- package/lib/operations/indexes.js.map +1 -1
- package/lib/operations/kill_cursors.js +22 -0
- package/lib/operations/kill_cursors.js.map +1 -0
- package/lib/operations/list_collections.js +1 -33
- package/lib/operations/list_collections.js.map +1 -1
- package/lib/operations/operation.js +4 -1
- package/lib/operations/operation.js.map +1 -1
- package/lib/read_preference.js.map +1 -1
- package/lib/sdam/topology.js +25 -64
- package/lib/sdam/topology.js.map +1 -1
- package/lib/sessions.js +27 -30
- package/lib/sessions.js.map +1 -1
- package/lib/utils.js +25 -7
- package/lib/utils.js.map +1 -1
- package/mongodb.d.ts +60 -27
- package/package.json +18 -18
- package/src/change_stream.ts +147 -373
- package/src/cmap/command_monitoring_events.ts +2 -3
- package/src/cmap/connect.ts +20 -25
- package/src/cmap/connection.ts +1 -2
- package/src/cmap/wire_protocol/compression.ts +8 -6
- package/src/collection.ts +21 -7
- package/src/cursor/abstract_cursor.ts +66 -71
- package/src/cursor/change_stream_cursor.ts +194 -0
- package/src/cursor/list_collections_cursor.ts +52 -0
- package/src/cursor/list_indexes_cursor.ts +41 -0
- package/src/db.ts +2 -5
- package/src/deps.ts +13 -22
- package/src/encrypter.ts +5 -13
- package/src/index.ts +9 -5
- package/src/mongo_client.ts +68 -27
- package/src/mongo_types.ts +29 -3
- package/src/operations/common_functions.ts +1 -1
- package/src/operations/estimated_document_count.ts +6 -0
- package/src/operations/execute_operation.ts +17 -8
- package/src/operations/get_more.ts +2 -2
- package/src/operations/indexes.ts +0 -37
- package/src/operations/kill_cursors.ts +27 -0
- package/src/operations/list_collections.ts +0 -43
- package/src/operations/operation.ts +5 -1
- package/src/read_preference.ts +5 -9
- package/src/sdam/topology.ts +35 -101
- package/src/sessions.ts +30 -38
- package/src/utils.ts +32 -8
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { Document } from '../bson';
|
|
2
2
|
import type { Collection } from '../collection';
|
|
3
|
-
import { AbstractCursor } from '../cursor/abstract_cursor';
|
|
4
3
|
import type { Db } from '../db';
|
|
5
4
|
import { MongoCompatibilityError, MONGODB_ERROR_CODES, MongoServerError } from '../error';
|
|
6
5
|
import type { OneOrMore } from '../mongo_types';
|
|
@@ -15,7 +14,6 @@ import {
|
|
|
15
14
|
OperationParent
|
|
16
15
|
} from './command';
|
|
17
16
|
import { indexInformation, IndexInformationOptions } from './common_functions';
|
|
18
|
-
import { executeOperation, ExecutionResult } from './execute_operation';
|
|
19
17
|
import { AbstractOperation, Aspect, defineAspects } from './operation';
|
|
20
18
|
|
|
21
19
|
const VALID_INDEX_OPTIONS = new Set([
|
|
@@ -412,41 +410,6 @@ export class ListIndexesOperation extends CommandOperation<Document> {
|
|
|
412
410
|
}
|
|
413
411
|
}
|
|
414
412
|
|
|
415
|
-
/** @public */
|
|
416
|
-
export class ListIndexesCursor extends AbstractCursor {
|
|
417
|
-
parent: Collection;
|
|
418
|
-
options?: ListIndexesOptions;
|
|
419
|
-
|
|
420
|
-
constructor(collection: Collection, options?: ListIndexesOptions) {
|
|
421
|
-
super(collection.s.db.s.client, collection.s.namespace, options);
|
|
422
|
-
this.parent = collection;
|
|
423
|
-
this.options = options;
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
clone(): ListIndexesCursor {
|
|
427
|
-
return new ListIndexesCursor(this.parent, {
|
|
428
|
-
...this.options,
|
|
429
|
-
...this.cursorOptions
|
|
430
|
-
});
|
|
431
|
-
}
|
|
432
|
-
|
|
433
|
-
/** @internal */
|
|
434
|
-
_initialize(session: ClientSession | undefined, callback: Callback<ExecutionResult>): void {
|
|
435
|
-
const operation = new ListIndexesOperation(this.parent, {
|
|
436
|
-
...this.cursorOptions,
|
|
437
|
-
...this.options,
|
|
438
|
-
session
|
|
439
|
-
});
|
|
440
|
-
|
|
441
|
-
executeOperation(this.parent.s.db.s.client, operation, (err, response) => {
|
|
442
|
-
if (err || response == null) return callback(err);
|
|
443
|
-
|
|
444
|
-
// TODO: NODE-2882
|
|
445
|
-
callback(undefined, { server: operation.server, session, response });
|
|
446
|
-
});
|
|
447
|
-
}
|
|
448
|
-
}
|
|
449
|
-
|
|
450
413
|
/** @internal */
|
|
451
414
|
export class IndexExistsOperation extends AbstractOperation<boolean> {
|
|
452
415
|
override options: IndexInformationOptions;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { Long } from '../bson';
|
|
2
|
+
import { MongoRuntimeError } from '../error';
|
|
3
|
+
import type { Server } from '../sdam/server';
|
|
4
|
+
import type { ClientSession } from '../sessions';
|
|
5
|
+
import type { Callback, MongoDBNamespace } from '../utils';
|
|
6
|
+
import { AbstractOperation, Aspect, defineAspects, OperationOptions } from './operation';
|
|
7
|
+
|
|
8
|
+
export class KillCursorsOperation extends AbstractOperation {
|
|
9
|
+
cursorId: Long;
|
|
10
|
+
constructor(cursorId: Long, ns: MongoDBNamespace, server: Server, options: OperationOptions) {
|
|
11
|
+
super(options);
|
|
12
|
+
this.ns = ns;
|
|
13
|
+
this.cursorId = cursorId;
|
|
14
|
+
this.server = server;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
execute(server: Server, session: ClientSession | undefined, callback: Callback<void>): void {
|
|
18
|
+
if (server !== this.server) {
|
|
19
|
+
return callback(
|
|
20
|
+
new MongoRuntimeError('Killcursor must run on the same server operation began on')
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
server.killCursors(this.ns, [this.cursorId], { session }, () => callback());
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
defineAspects(KillCursorsOperation, [Aspect.MUST_SELECT_SAME_SERVER]);
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
import type { Binary, Document } from '../bson';
|
|
2
|
-
import { AbstractCursor } from '../cursor/abstract_cursor';
|
|
3
2
|
import type { Db } from '../db';
|
|
4
3
|
import type { Server } from '../sdam/server';
|
|
5
4
|
import type { ClientSession } from '../sessions';
|
|
6
5
|
import { Callback, maxWireVersion } from '../utils';
|
|
7
6
|
import { CommandOperation, CommandOperationOptions } from './command';
|
|
8
|
-
import { executeOperation, ExecutionResult } from './execute_operation';
|
|
9
7
|
import { Aspect, defineAspects } from './operation';
|
|
10
8
|
|
|
11
9
|
/** @public */
|
|
@@ -86,47 +84,6 @@ export interface CollectionInfo extends Document {
|
|
|
86
84
|
idIndex?: Document;
|
|
87
85
|
}
|
|
88
86
|
|
|
89
|
-
/** @public */
|
|
90
|
-
export class ListCollectionsCursor<
|
|
91
|
-
T extends Pick<CollectionInfo, 'name' | 'type'> | CollectionInfo =
|
|
92
|
-
| Pick<CollectionInfo, 'name' | 'type'>
|
|
93
|
-
| CollectionInfo
|
|
94
|
-
> extends AbstractCursor<T> {
|
|
95
|
-
parent: Db;
|
|
96
|
-
filter: Document;
|
|
97
|
-
options?: ListCollectionsOptions;
|
|
98
|
-
|
|
99
|
-
constructor(db: Db, filter: Document, options?: ListCollectionsOptions) {
|
|
100
|
-
super(db.s.client, db.s.namespace, options);
|
|
101
|
-
this.parent = db;
|
|
102
|
-
this.filter = filter;
|
|
103
|
-
this.options = options;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
clone(): ListCollectionsCursor<T> {
|
|
107
|
-
return new ListCollectionsCursor(this.parent, this.filter, {
|
|
108
|
-
...this.options,
|
|
109
|
-
...this.cursorOptions
|
|
110
|
-
});
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
/** @internal */
|
|
114
|
-
_initialize(session: ClientSession | undefined, callback: Callback<ExecutionResult>): void {
|
|
115
|
-
const operation = new ListCollectionsOperation(this.parent, this.filter, {
|
|
116
|
-
...this.cursorOptions,
|
|
117
|
-
...this.options,
|
|
118
|
-
session
|
|
119
|
-
});
|
|
120
|
-
|
|
121
|
-
executeOperation(this.parent.s.client, operation, (err, response) => {
|
|
122
|
-
if (err || response == null) return callback(err);
|
|
123
|
-
|
|
124
|
-
// TODO: NODE-2882
|
|
125
|
-
callback(undefined, { server: operation.server, session, response });
|
|
126
|
-
});
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
|
|
130
87
|
defineAspects(ListCollectionsOperation, [
|
|
131
88
|
Aspect.READ_OPERATION,
|
|
132
89
|
Aspect.RETRYABLE,
|
|
@@ -11,7 +11,7 @@ export const Aspect = {
|
|
|
11
11
|
EXPLAINABLE: Symbol('EXPLAINABLE'),
|
|
12
12
|
SKIP_COLLATION: Symbol('SKIP_COLLATION'),
|
|
13
13
|
CURSOR_CREATING: Symbol('CURSOR_CREATING'),
|
|
14
|
-
|
|
14
|
+
MUST_SELECT_SAME_SERVER: Symbol('MUST_SELECT_SAME_SERVER')
|
|
15
15
|
} as const;
|
|
16
16
|
|
|
17
17
|
/** @public */
|
|
@@ -94,6 +94,10 @@ export abstract class AbstractOperation<TResult = any> {
|
|
|
94
94
|
return this[kSession];
|
|
95
95
|
}
|
|
96
96
|
|
|
97
|
+
clearSession() {
|
|
98
|
+
this[kSession] = undefined;
|
|
99
|
+
}
|
|
100
|
+
|
|
97
101
|
get canRetryRead(): boolean {
|
|
98
102
|
return true;
|
|
99
103
|
}
|
package/src/read_preference.ts
CHANGED
|
@@ -163,14 +163,10 @@ export class ReadPreference {
|
|
|
163
163
|
} else if (!(readPreference instanceof ReadPreference) && typeof readPreference === 'object') {
|
|
164
164
|
const mode = readPreference.mode || readPreference.preference;
|
|
165
165
|
if (mode && typeof mode === 'string') {
|
|
166
|
-
return new ReadPreference(
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
maxStalenessSeconds: readPreference.maxStalenessSeconds,
|
|
171
|
-
hedge: options.hedge
|
|
172
|
-
}
|
|
173
|
-
);
|
|
166
|
+
return new ReadPreference(mode, readPreference.tags ?? readPreferenceTags, {
|
|
167
|
+
maxStalenessSeconds: readPreference.maxStalenessSeconds,
|
|
168
|
+
hedge: options.hedge
|
|
169
|
+
});
|
|
174
170
|
}
|
|
175
171
|
}
|
|
176
172
|
|
|
@@ -193,7 +189,7 @@ export class ReadPreference {
|
|
|
193
189
|
} else if (r && !(r instanceof ReadPreference) && typeof r === 'object') {
|
|
194
190
|
const mode = r.mode || r.preference;
|
|
195
191
|
if (mode && typeof mode === 'string') {
|
|
196
|
-
options.readPreference = new ReadPreference(mode
|
|
192
|
+
options.readPreference = new ReadPreference(mode, r.tags, {
|
|
197
193
|
maxStalenessSeconds: r.maxStalenessSeconds
|
|
198
194
|
});
|
|
199
195
|
}
|
package/src/sdam/topology.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import Denque = require('denque');
|
|
2
2
|
import { setTimeout } from 'timers';
|
|
3
|
+
import { promisify } from 'util';
|
|
3
4
|
|
|
4
5
|
import type { BSONSerializeOptions, Document } from '../bson';
|
|
5
6
|
import { deserialize, serialize } from '../bson';
|
|
@@ -29,20 +30,14 @@ import {
|
|
|
29
30
|
MongoServerSelectionError,
|
|
30
31
|
MongoTopologyClosedError
|
|
31
32
|
} from '../error';
|
|
32
|
-
import type { MongoClient,
|
|
33
|
+
import type { MongoClient, ServerApi } from '../mongo_client';
|
|
33
34
|
import { TypedEventEmitter } from '../mongo_types';
|
|
34
35
|
import { ReadPreference, ReadPreferenceLike } from '../read_preference';
|
|
35
|
-
import {
|
|
36
|
-
ClientSession,
|
|
37
|
-
ClientSessionOptions,
|
|
38
|
-
ServerSessionId,
|
|
39
|
-
ServerSessionPool
|
|
40
|
-
} from '../sessions';
|
|
36
|
+
import type { ClientSession } from '../sessions';
|
|
41
37
|
import type { Transaction } from '../transactions';
|
|
42
38
|
import {
|
|
43
39
|
Callback,
|
|
44
40
|
ClientMetadata,
|
|
45
|
-
eachAsync,
|
|
46
41
|
emitWarning,
|
|
47
42
|
EventEmitterWithState,
|
|
48
43
|
HostAddress,
|
|
@@ -120,10 +115,6 @@ export interface TopologyPrivate {
|
|
|
120
115
|
minHeartbeatFrequencyMS: number;
|
|
121
116
|
/** A map of server instances to normalized addresses */
|
|
122
117
|
servers: Map<string, Server>;
|
|
123
|
-
/** Server Session Pool */
|
|
124
|
-
sessionPool: ServerSessionPool;
|
|
125
|
-
/** Active client sessions */
|
|
126
|
-
sessions: Set<ClientSession>;
|
|
127
118
|
credentials?: MongoCredentials;
|
|
128
119
|
clusterTime?: ClusterTime;
|
|
129
120
|
/** timers created for the initial connect to a server */
|
|
@@ -316,10 +307,6 @@ export class Topology extends TypedEventEmitter<TopologyEvents> {
|
|
|
316
307
|
minHeartbeatFrequencyMS: options.minHeartbeatFrequencyMS,
|
|
317
308
|
// a map of server instances to normalized addresses
|
|
318
309
|
servers: new Map(),
|
|
319
|
-
// Server Session Pool
|
|
320
|
-
sessionPool: new ServerSessionPool(this),
|
|
321
|
-
// Active client sessions
|
|
322
|
-
sessions: new Set(),
|
|
323
310
|
credentials: options?.credentials,
|
|
324
311
|
clusterTime: undefined,
|
|
325
312
|
|
|
@@ -443,13 +430,13 @@ export class Topology extends TypedEventEmitter<TopologyEvents> {
|
|
|
443
430
|
}
|
|
444
431
|
}
|
|
445
432
|
|
|
433
|
+
const exitWithError = (error: Error) =>
|
|
434
|
+
callback ? callback(error) : this.emit(Topology.ERROR, error);
|
|
435
|
+
|
|
446
436
|
const readPreference = options.readPreference ?? ReadPreference.primary;
|
|
447
437
|
this.selectServer(readPreferenceServerSelector(readPreference), options, (err, server) => {
|
|
448
438
|
if (err) {
|
|
449
|
-
this.close();
|
|
450
|
-
|
|
451
|
-
typeof callback === 'function' ? callback(err) : this.emit(Topology.ERROR, err);
|
|
452
|
-
return;
|
|
439
|
+
return this.close({ force: false }, () => exitWithError(err));
|
|
453
440
|
}
|
|
454
441
|
|
|
455
442
|
// TODO: NODE-2471
|
|
@@ -457,15 +444,14 @@ export class Topology extends TypedEventEmitter<TopologyEvents> {
|
|
|
457
444
|
if (!skipPingOnConnect && server && this.s.credentials) {
|
|
458
445
|
server.command(ns('admin.$cmd'), { ping: 1 }, {}, err => {
|
|
459
446
|
if (err) {
|
|
460
|
-
|
|
461
|
-
return;
|
|
447
|
+
return exitWithError(err);
|
|
462
448
|
}
|
|
463
449
|
|
|
464
450
|
stateTransition(this, STATE_CONNECTED);
|
|
465
451
|
this.emit(Topology.OPEN, this);
|
|
466
452
|
this.emit(Topology.CONNECT, this);
|
|
467
453
|
|
|
468
|
-
|
|
454
|
+
callback?.(undefined, this);
|
|
469
455
|
});
|
|
470
456
|
|
|
471
457
|
return;
|
|
@@ -475,7 +461,7 @@ export class Topology extends TypedEventEmitter<TopologyEvents> {
|
|
|
475
461
|
this.emit(Topology.OPEN, this);
|
|
476
462
|
this.emit(Topology.CONNECT, this);
|
|
477
463
|
|
|
478
|
-
|
|
464
|
+
callback?.(undefined, this);
|
|
479
465
|
});
|
|
480
466
|
}
|
|
481
467
|
|
|
@@ -489,52 +475,38 @@ export class Topology extends TypedEventEmitter<TopologyEvents> {
|
|
|
489
475
|
if (typeof options === 'boolean') {
|
|
490
476
|
options = { force: options };
|
|
491
477
|
}
|
|
492
|
-
|
|
493
478
|
options = options ?? {};
|
|
494
|
-
if (this.s.state === STATE_CLOSED || this.s.state === STATE_CLOSING) {
|
|
495
|
-
if (typeof callback === 'function') {
|
|
496
|
-
callback();
|
|
497
|
-
}
|
|
498
479
|
|
|
499
|
-
|
|
480
|
+
if (this.s.state === STATE_CLOSED || this.s.state === STATE_CLOSING) {
|
|
481
|
+
return callback?.();
|
|
500
482
|
}
|
|
501
483
|
|
|
502
|
-
|
|
484
|
+
const destroyedServers = Array.from(this.s.servers.values(), server => {
|
|
485
|
+
return promisify(destroyServer)(server, this, options);
|
|
486
|
+
});
|
|
503
487
|
|
|
504
|
-
|
|
505
|
-
|
|
488
|
+
Promise.all(destroyedServers)
|
|
489
|
+
.then(() => {
|
|
490
|
+
this.s.servers.clear();
|
|
506
491
|
|
|
507
|
-
|
|
508
|
-
this.s.srvPoller.stop();
|
|
509
|
-
this.s.srvPoller.removeListener(SrvPoller.SRV_RECORD_DISCOVERY, this.s.detectSrvRecords);
|
|
510
|
-
}
|
|
492
|
+
stateTransition(this, STATE_CLOSING);
|
|
511
493
|
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
stateTransition(this, STATE_CLOSED);
|
|
529
|
-
|
|
530
|
-
if (typeof callback === 'function') {
|
|
531
|
-
callback(err);
|
|
532
|
-
}
|
|
533
|
-
}
|
|
534
|
-
);
|
|
535
|
-
});
|
|
536
|
-
}
|
|
537
|
-
);
|
|
494
|
+
drainWaitQueue(this[kWaitQueue], new MongoTopologyClosedError());
|
|
495
|
+
drainTimerQueue(this.s.connectionTimers);
|
|
496
|
+
|
|
497
|
+
if (this.s.srvPoller) {
|
|
498
|
+
this.s.srvPoller.stop();
|
|
499
|
+
this.s.srvPoller.removeListener(SrvPoller.SRV_RECORD_DISCOVERY, this.s.detectSrvRecords);
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
this.removeListener(Topology.TOPOLOGY_DESCRIPTION_CHANGED, this.s.detectShardedTopology);
|
|
503
|
+
|
|
504
|
+
stateTransition(this, STATE_CLOSED);
|
|
505
|
+
|
|
506
|
+
// emit an event for close
|
|
507
|
+
this.emit(Topology.TOPOLOGY_CLOSED, new TopologyClosedEvent(this.s.id));
|
|
508
|
+
})
|
|
509
|
+
.finally(() => callback?.());
|
|
538
510
|
}
|
|
539
511
|
|
|
540
512
|
/**
|
|
@@ -628,44 +600,6 @@ export class Topology extends TypedEventEmitter<TopologyEvents> {
|
|
|
628
600
|
return this.loadBalanced || this.description.logicalSessionTimeoutMinutes != null;
|
|
629
601
|
}
|
|
630
602
|
|
|
631
|
-
/** Start a logical session */
|
|
632
|
-
startSession(options: ClientSessionOptions, clientOptions?: MongoOptions): ClientSession {
|
|
633
|
-
const session = new ClientSession(this.client, this.s.sessionPool, options, clientOptions);
|
|
634
|
-
session.once('ended', () => {
|
|
635
|
-
this.s.sessions.delete(session);
|
|
636
|
-
});
|
|
637
|
-
|
|
638
|
-
this.s.sessions.add(session);
|
|
639
|
-
return session;
|
|
640
|
-
}
|
|
641
|
-
|
|
642
|
-
/** Send endSessions command(s) with the given session ids */
|
|
643
|
-
endSessions(sessions: ServerSessionId[], callback?: Callback<Document>): void {
|
|
644
|
-
if (!Array.isArray(sessions)) {
|
|
645
|
-
sessions = [sessions];
|
|
646
|
-
}
|
|
647
|
-
|
|
648
|
-
this.selectServer(
|
|
649
|
-
readPreferenceServerSelector(ReadPreference.primaryPreferred),
|
|
650
|
-
{},
|
|
651
|
-
(err, server) => {
|
|
652
|
-
if (err || !server) {
|
|
653
|
-
if (typeof callback === 'function') callback(err);
|
|
654
|
-
return;
|
|
655
|
-
}
|
|
656
|
-
|
|
657
|
-
server.command(
|
|
658
|
-
ns('admin.$cmd'),
|
|
659
|
-
{ endSessions: sessions },
|
|
660
|
-
{ noResponse: true },
|
|
661
|
-
(err, result) => {
|
|
662
|
-
if (typeof callback === 'function') callback(err, result);
|
|
663
|
-
}
|
|
664
|
-
);
|
|
665
|
-
}
|
|
666
|
-
);
|
|
667
|
-
}
|
|
668
|
-
|
|
669
603
|
/**
|
|
670
604
|
* Update the internal TopologyDescription with a ServerDescription
|
|
671
605
|
*
|
package/src/sessions.ts
CHANGED
|
@@ -27,7 +27,6 @@ import { PromiseProvider } from './promise_provider';
|
|
|
27
27
|
import { ReadConcernLevel } from './read_concern';
|
|
28
28
|
import { ReadPreference } from './read_preference';
|
|
29
29
|
import { _advanceClusterTime, ClusterTime, TopologyType } from './sdam/common';
|
|
30
|
-
import type { Topology } from './sdam/topology';
|
|
31
30
|
import { isTransactionCommand, Transaction, TransactionOptions, TxnState } from './transactions';
|
|
32
31
|
import {
|
|
33
32
|
calculateDurationInMs,
|
|
@@ -269,9 +268,10 @@ export class ClientSession extends TypedEventEmitter<ClientSessionEvents> {
|
|
|
269
268
|
if (serverSession != null) {
|
|
270
269
|
// release the server session back to the pool
|
|
271
270
|
this.sessionPool.release(serverSession);
|
|
272
|
-
// Make sure a new serverSession never makes it
|
|
271
|
+
// Make sure a new serverSession never makes it onto this ClientSession
|
|
273
272
|
Object.defineProperty(this, kServerSession, {
|
|
274
|
-
value: ServerSession.clone(serverSession)
|
|
273
|
+
value: ServerSession.clone(serverSession),
|
|
274
|
+
writable: false
|
|
275
275
|
});
|
|
276
276
|
}
|
|
277
277
|
|
|
@@ -616,7 +616,7 @@ function attemptTransaction<TSchema>(
|
|
|
616
616
|
}
|
|
617
617
|
|
|
618
618
|
if (!isPromiseLike(promise)) {
|
|
619
|
-
session.abortTransaction();
|
|
619
|
+
session.abortTransaction().catch(() => null);
|
|
620
620
|
throw new MongoInvalidArgumentError(
|
|
621
621
|
'Function provided to `withTransaction` must return a Promise'
|
|
622
622
|
);
|
|
@@ -878,39 +878,18 @@ export class ServerSession {
|
|
|
878
878
|
* @internal
|
|
879
879
|
*/
|
|
880
880
|
export class ServerSessionPool {
|
|
881
|
-
|
|
881
|
+
client: MongoClient;
|
|
882
882
|
sessions: ServerSession[];
|
|
883
883
|
|
|
884
|
-
constructor(
|
|
885
|
-
if (
|
|
886
|
-
throw new MongoRuntimeError('ServerSessionPool requires a
|
|
884
|
+
constructor(client: MongoClient) {
|
|
885
|
+
if (client == null) {
|
|
886
|
+
throw new MongoRuntimeError('ServerSessionPool requires a MongoClient');
|
|
887
887
|
}
|
|
888
888
|
|
|
889
|
-
this.
|
|
889
|
+
this.client = client;
|
|
890
890
|
this.sessions = [];
|
|
891
891
|
}
|
|
892
892
|
|
|
893
|
-
/** Ends all sessions in the session pool */
|
|
894
|
-
endAllPooledSessions(callback?: Callback<void>): void {
|
|
895
|
-
if (this.sessions.length) {
|
|
896
|
-
this.topology.endSessions(
|
|
897
|
-
this.sessions.map((session: ServerSession) => session.id),
|
|
898
|
-
() => {
|
|
899
|
-
this.sessions = [];
|
|
900
|
-
if (typeof callback === 'function') {
|
|
901
|
-
callback();
|
|
902
|
-
}
|
|
903
|
-
}
|
|
904
|
-
);
|
|
905
|
-
|
|
906
|
-
return;
|
|
907
|
-
}
|
|
908
|
-
|
|
909
|
-
if (typeof callback === 'function') {
|
|
910
|
-
callback();
|
|
911
|
-
}
|
|
912
|
-
}
|
|
913
|
-
|
|
914
893
|
/**
|
|
915
894
|
* Acquire a Server Session from the pool.
|
|
916
895
|
* Iterates through each session in the pool, removing any stale sessions
|
|
@@ -918,16 +897,29 @@ export class ServerSessionPool {
|
|
|
918
897
|
* pool and returned. If no non-stale session is found, a new ServerSession is created.
|
|
919
898
|
*/
|
|
920
899
|
acquire(): ServerSession {
|
|
921
|
-
const sessionTimeoutMinutes = this.topology
|
|
900
|
+
const sessionTimeoutMinutes = this.client.topology?.logicalSessionTimeoutMinutes ?? 10;
|
|
922
901
|
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
902
|
+
let session: ServerSession | null = null;
|
|
903
|
+
|
|
904
|
+
// Try to obtain from session pool
|
|
905
|
+
while (this.sessions.length > 0) {
|
|
906
|
+
const potentialSession = this.sessions.shift();
|
|
907
|
+
if (
|
|
908
|
+
potentialSession != null &&
|
|
909
|
+
(!!this.client.topology?.loadBalanced ||
|
|
910
|
+
!potentialSession.hasTimedOut(sessionTimeoutMinutes))
|
|
911
|
+
) {
|
|
912
|
+
session = potentialSession;
|
|
913
|
+
break;
|
|
927
914
|
}
|
|
928
915
|
}
|
|
929
916
|
|
|
930
|
-
|
|
917
|
+
// If nothing valid came from the pool make a new one
|
|
918
|
+
if (session == null) {
|
|
919
|
+
session = new ServerSession();
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
return session;
|
|
931
923
|
}
|
|
932
924
|
|
|
933
925
|
/**
|
|
@@ -938,9 +930,9 @@ export class ServerSessionPool {
|
|
|
938
930
|
* @param session - The session to release to the pool
|
|
939
931
|
*/
|
|
940
932
|
release(session: ServerSession): void {
|
|
941
|
-
const sessionTimeoutMinutes = this.topology
|
|
933
|
+
const sessionTimeoutMinutes = this.client.topology?.logicalSessionTimeoutMinutes ?? 10;
|
|
942
934
|
|
|
943
|
-
if (this.topology
|
|
935
|
+
if (this.client.topology?.loadBalanced && !sessionTimeoutMinutes) {
|
|
944
936
|
this.sessions.unshift(session);
|
|
945
937
|
}
|
|
946
938
|
|
package/src/utils.ts
CHANGED
|
@@ -161,14 +161,15 @@ export function parseIndexOptions(indexSpec: IndexSpecification): IndexOptions {
|
|
|
161
161
|
};
|
|
162
162
|
}
|
|
163
163
|
|
|
164
|
+
const TO_STRING = (object: unknown) => Object.prototype.toString.call(object);
|
|
164
165
|
/**
|
|
165
166
|
* Checks if arg is an Object:
|
|
166
167
|
* - **NOTE**: the check is based on the `[Symbol.toStringTag]() === 'Object'`
|
|
167
168
|
* @internal
|
|
168
169
|
*/
|
|
169
|
-
|
|
170
|
+
|
|
170
171
|
export function isObject(arg: unknown): arg is object {
|
|
171
|
-
return '[object Object]' ===
|
|
172
|
+
return '[object Object]' === TO_STRING(arg);
|
|
172
173
|
}
|
|
173
174
|
|
|
174
175
|
/** @internal */
|
|
@@ -380,7 +381,7 @@ export interface DeprecateOptionsConfig {
|
|
|
380
381
|
/** index of options object in function arguments array */
|
|
381
382
|
optionsIndex: number;
|
|
382
383
|
/** optional custom message handler to generate warnings */
|
|
383
|
-
msgHandler?(name: string, option: string): string;
|
|
384
|
+
msgHandler?(this: void, name: string, option: string): string;
|
|
384
385
|
}
|
|
385
386
|
|
|
386
387
|
/**
|
|
@@ -1024,6 +1025,9 @@ export function setDifference<T>(setA: Iterable<T>, setB: Iterable<T>): Set<T> {
|
|
|
1024
1025
|
return difference;
|
|
1025
1026
|
}
|
|
1026
1027
|
|
|
1028
|
+
const HAS_OWN = (object: unknown, prop: string) =>
|
|
1029
|
+
Object.prototype.hasOwnProperty.call(object, prop);
|
|
1030
|
+
|
|
1027
1031
|
export function isRecord<T extends readonly string[]>(
|
|
1028
1032
|
value: unknown,
|
|
1029
1033
|
requiredKeys: T
|
|
@@ -1033,9 +1037,6 @@ export function isRecord(
|
|
|
1033
1037
|
value: unknown,
|
|
1034
1038
|
requiredKeys: string[] | undefined = undefined
|
|
1035
1039
|
): value is Record<string, any> {
|
|
1036
|
-
const toString = Object.prototype.toString;
|
|
1037
|
-
const hasOwnProperty = Object.prototype.hasOwnProperty;
|
|
1038
|
-
const isObject = (v: unknown) => toString.call(v) === '[object Object]';
|
|
1039
1040
|
if (!isObject(value)) {
|
|
1040
1041
|
return false;
|
|
1041
1042
|
}
|
|
@@ -1047,7 +1048,7 @@ export function isRecord(
|
|
|
1047
1048
|
}
|
|
1048
1049
|
|
|
1049
1050
|
// Check to see if some method exists from the Object exists
|
|
1050
|
-
if (!
|
|
1051
|
+
if (!HAS_OWN(ctor.prototype, 'isPrototypeOf')) {
|
|
1051
1052
|
return false;
|
|
1052
1053
|
}
|
|
1053
1054
|
}
|
|
@@ -1261,7 +1262,7 @@ export class HostAddress {
|
|
|
1261
1262
|
return `${this.socketPath}`;
|
|
1262
1263
|
}
|
|
1263
1264
|
|
|
1264
|
-
static fromString(s: string): HostAddress {
|
|
1265
|
+
static fromString(this: void, s: string): HostAddress {
|
|
1265
1266
|
return new HostAddress(s);
|
|
1266
1267
|
}
|
|
1267
1268
|
|
|
@@ -1406,3 +1407,26 @@ export function commandSupportsReadConcern(command: Document, options?: Document
|
|
|
1406
1407
|
|
|
1407
1408
|
return false;
|
|
1408
1409
|
}
|
|
1410
|
+
|
|
1411
|
+
/**
|
|
1412
|
+
* A utility function to get the instance of mongodb-client-encryption, if it exists.
|
|
1413
|
+
*
|
|
1414
|
+
* @throws MongoMissingDependencyError if mongodb-client-encryption isn't installed.
|
|
1415
|
+
* @returns
|
|
1416
|
+
*/
|
|
1417
|
+
export function getMongoDBClientEncryption() {
|
|
1418
|
+
let mongodbClientEncryption;
|
|
1419
|
+
|
|
1420
|
+
// NOTE(NODE-4254): This is to get around the circular dependency between
|
|
1421
|
+
// mongodb-client-encryption and the driver in the test scenarios.
|
|
1422
|
+
if (
|
|
1423
|
+
typeof process.env.MONGODB_CLIENT_ENCRYPTION_OVERRIDE === 'string' &&
|
|
1424
|
+
process.env.MONGODB_CLIENT_ENCRYPTION_OVERRIDE.length > 0
|
|
1425
|
+
) {
|
|
1426
|
+
mongodbClientEncryption = require(process.env.MONGODB_CLIENT_ENCRYPTION_OVERRIDE);
|
|
1427
|
+
} else {
|
|
1428
|
+
mongodbClientEncryption = require('mongodb-client-encryption');
|
|
1429
|
+
}
|
|
1430
|
+
|
|
1431
|
+
return mongodbClientEncryption;
|
|
1432
|
+
}
|