mongodb 6.12.0 → 6.13.0-dev.20250201.sha.35c703e3
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/beta.d.ts +176 -108
- 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/client-side-encryption/auto_encrypter.js +4 -2
- package/lib/client-side-encryption/auto_encrypter.js.map +1 -1
- package/lib/client-side-encryption/client_encryption.js +4 -4
- package/lib/client-side-encryption/client_encryption.js.map +1 -1
- package/lib/client-side-encryption/state_machine.js +56 -30
- package/lib/client-side-encryption/state_machine.js.map +1 -1
- package/lib/cmap/auth/mongodb_aws.js +1 -1
- package/lib/cmap/auth/mongodb_aws.js.map +1 -1
- package/lib/cmap/auth/mongodb_oidc.js +1 -1
- package/lib/cmap/auth/mongodb_oidc.js.map +1 -1
- package/lib/cmap/command_monitoring_events.js +9 -50
- package/lib/cmap/command_monitoring_events.js.map +1 -1
- package/lib/cmap/connection.js +28 -22
- package/lib/cmap/connection.js.map +1 -1
- package/lib/cmap/connection_pool.js +88 -117
- package/lib/cmap/connection_pool.js.map +1 -1
- package/lib/cmap/wire_protocol/on_data.js +6 -1
- package/lib/cmap/wire_protocol/on_data.js.map +1 -1
- package/lib/collection.js.map +1 -1
- package/lib/connection_string.js +68 -86
- package/lib/connection_string.js.map +1 -1
- package/lib/cursor/abstract_cursor.js +47 -18
- package/lib/cursor/abstract_cursor.js.map +1 -1
- package/lib/cursor/aggregation_cursor.js +2 -1
- package/lib/cursor/aggregation_cursor.js.map +1 -1
- package/lib/cursor/find_cursor.js +2 -1
- package/lib/cursor/find_cursor.js.map +1 -1
- package/lib/cursor/list_collections_cursor.js +2 -1
- package/lib/cursor/list_collections_cursor.js.map +1 -1
- package/lib/db.js +2 -1
- package/lib/db.js.map +1 -1
- package/lib/encrypter.js +5 -9
- package/lib/encrypter.js.map +1 -1
- package/lib/error.js +10 -18
- package/lib/error.js.map +1 -1
- package/lib/index.js +5 -2
- package/lib/index.js.map +1 -1
- package/lib/mongo_client.js +46 -26
- package/lib/mongo_client.js.map +1 -1
- package/lib/mongo_logger.js +102 -3
- package/lib/mongo_logger.js.map +1 -1
- package/lib/operations/execute_operation.js +9 -5
- package/lib/operations/execute_operation.js.map +1 -1
- package/lib/operations/list_collections.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 +27 -17
- package/lib/sdam/server.js.map +1 -1
- package/lib/sdam/topology.js +20 -19
- package/lib/sdam/topology.js.map +1 -1
- package/lib/sessions.js +24 -48
- package/lib/sessions.js.map +1 -1
- package/lib/utils.js +64 -44
- package/lib/utils.js.map +1 -1
- package/mongodb.d.ts +176 -108
- package/package.json +2 -2
- package/src/bulk/common.ts +6 -9
- package/src/change_stream.ts +21 -33
- package/src/client-side-encryption/auto_encrypter.ts +12 -8
- package/src/client-side-encryption/client_encryption.ts +6 -4
- package/src/client-side-encryption/state_machine.ts +80 -36
- package/src/cmap/auth/mongodb_aws.ts +1 -1
- package/src/cmap/auth/mongodb_oidc.ts +1 -1
- package/src/cmap/command_monitoring_events.ts +10 -55
- package/src/cmap/connection.ts +37 -29
- package/src/cmap/connection_pool.ts +121 -145
- package/src/cmap/wire_protocol/on_data.ts +9 -2
- package/src/collection.ts +15 -8
- package/src/connection_string.ts +74 -99
- package/src/cursor/abstract_cursor.ts +71 -23
- package/src/cursor/aggregation_cursor.ts +5 -3
- package/src/cursor/find_cursor.ts +5 -3
- package/src/cursor/list_collections_cursor.ts +5 -3
- package/src/db.ts +11 -7
- package/src/encrypter.ts +6 -11
- package/src/error.ts +11 -23
- package/src/index.ts +3 -3
- package/src/mongo_client.ts +78 -47
- package/src/mongo_logger.ts +158 -11
- package/src/mongo_types.ts +38 -0
- package/src/operations/execute_operation.ts +11 -6
- package/src/operations/list_collections.ts +4 -1
- package/src/operations/operation.ts +8 -9
- package/src/sdam/monitor.ts +30 -38
- package/src/sdam/server.ts +33 -20
- package/src/sdam/topology.ts +29 -26
- package/src/sessions.ts +37 -58
- package/src/utils.ts +79 -43
|
@@ -25,10 +25,18 @@ import {
|
|
|
25
25
|
MongoRuntimeError,
|
|
26
26
|
MongoServerError
|
|
27
27
|
} from '../error';
|
|
28
|
-
import { CancellationToken, TypedEventEmitter } from '../mongo_types';
|
|
28
|
+
import { type Abortable, CancellationToken, TypedEventEmitter } from '../mongo_types';
|
|
29
29
|
import type { Server } from '../sdam/server';
|
|
30
30
|
import { type TimeoutContext, TimeoutError } from '../timeout';
|
|
31
|
-
import {
|
|
31
|
+
import {
|
|
32
|
+
addAbortListener,
|
|
33
|
+
type Callback,
|
|
34
|
+
kDispose,
|
|
35
|
+
List,
|
|
36
|
+
makeCounter,
|
|
37
|
+
now,
|
|
38
|
+
promiseWithResolvers
|
|
39
|
+
} from '../utils';
|
|
32
40
|
import { connect } from './connect';
|
|
33
41
|
import { Connection, type ConnectionEvents, type ConnectionOptions } from './connection';
|
|
34
42
|
import {
|
|
@@ -52,35 +60,6 @@ import {
|
|
|
52
60
|
} from './errors';
|
|
53
61
|
import { ConnectionPoolMetrics } from './metrics';
|
|
54
62
|
|
|
55
|
-
/** @internal */
|
|
56
|
-
const kServer = Symbol('server');
|
|
57
|
-
/** @internal */
|
|
58
|
-
const kConnections = Symbol('connections');
|
|
59
|
-
/** @internal */
|
|
60
|
-
const kPending = Symbol('pending');
|
|
61
|
-
/** @internal */
|
|
62
|
-
const kCheckedOut = Symbol('checkedOut');
|
|
63
|
-
/** @internal */
|
|
64
|
-
const kMinPoolSizeTimer = Symbol('minPoolSizeTimer');
|
|
65
|
-
/** @internal */
|
|
66
|
-
const kGeneration = Symbol('generation');
|
|
67
|
-
/** @internal */
|
|
68
|
-
const kServiceGenerations = Symbol('serviceGenerations');
|
|
69
|
-
/** @internal */
|
|
70
|
-
const kConnectionCounter = Symbol('connectionCounter');
|
|
71
|
-
/** @internal */
|
|
72
|
-
const kCancellationToken = Symbol('cancellationToken');
|
|
73
|
-
/** @internal */
|
|
74
|
-
const kWaitQueue = Symbol('waitQueue');
|
|
75
|
-
/** @internal */
|
|
76
|
-
const kCancelled = Symbol('cancelled');
|
|
77
|
-
/** @internal */
|
|
78
|
-
const kMetrics = Symbol('metrics');
|
|
79
|
-
/** @internal */
|
|
80
|
-
const kProcessingWaitQueue = Symbol('processingWaitQueue');
|
|
81
|
-
/** @internal */
|
|
82
|
-
const kPoolState = Symbol('poolState');
|
|
83
|
-
|
|
84
63
|
/** @public */
|
|
85
64
|
export interface ConnectionPoolOptions extends Omit<ConnectionOptions, 'id' | 'generation'> {
|
|
86
65
|
/** The maximum number of connections that may be associated with a pool at a given time. This includes in use and available connections. */
|
|
@@ -103,7 +82,7 @@ export interface ConnectionPoolOptions extends Omit<ConnectionOptions, 'id' | 'g
|
|
|
103
82
|
export interface WaitQueueMember {
|
|
104
83
|
resolve: (conn: Connection) => void;
|
|
105
84
|
reject: (err: AnyError) => void;
|
|
106
|
-
|
|
85
|
+
cancelled: boolean;
|
|
107
86
|
checkoutTime: number;
|
|
108
87
|
}
|
|
109
88
|
|
|
@@ -114,6 +93,8 @@ export const PoolState = Object.freeze({
|
|
|
114
93
|
closed: 'closed'
|
|
115
94
|
} as const);
|
|
116
95
|
|
|
96
|
+
type PoolState = (typeof PoolState)[keyof typeof PoolState];
|
|
97
|
+
|
|
117
98
|
/**
|
|
118
99
|
* @public
|
|
119
100
|
* @deprecated This interface is deprecated and will be removed in a future release as it is not used
|
|
@@ -143,26 +124,23 @@ export type ConnectionPoolEvents = {
|
|
|
143
124
|
* @internal
|
|
144
125
|
*/
|
|
145
126
|
export class ConnectionPool extends TypedEventEmitter<ConnectionPoolEvents> {
|
|
146
|
-
options: Readonly<ConnectionPoolOptions>;
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
[kWaitQueue]: List<WaitQueueMember>;
|
|
164
|
-
[kMetrics]: ConnectionPoolMetrics;
|
|
165
|
-
[kProcessingWaitQueue]: boolean;
|
|
127
|
+
public options: Readonly<ConnectionPoolOptions>;
|
|
128
|
+
/** An integer representing the SDAM generation of the pool */
|
|
129
|
+
public generation: number;
|
|
130
|
+
/** A map of generations to service ids */
|
|
131
|
+
public serviceGenerations: Map<string, number>;
|
|
132
|
+
|
|
133
|
+
private poolState: PoolState;
|
|
134
|
+
private server: Server;
|
|
135
|
+
private connections: List<Connection>;
|
|
136
|
+
private pending: number;
|
|
137
|
+
private checkedOut: Set<Connection>;
|
|
138
|
+
private minPoolSizeTimer?: NodeJS.Timeout;
|
|
139
|
+
private connectionCounter: Generator<number>;
|
|
140
|
+
private cancellationToken: CancellationToken;
|
|
141
|
+
private waitQueue: List<WaitQueueMember>;
|
|
142
|
+
private metrics: ConnectionPoolMetrics;
|
|
143
|
+
private processingWaitQueue: boolean;
|
|
166
144
|
|
|
167
145
|
/**
|
|
168
146
|
* Emitted when the connection pool is created.
|
|
@@ -241,22 +219,22 @@ export class ConnectionPool extends TypedEventEmitter<ConnectionPoolEvents> {
|
|
|
241
219
|
);
|
|
242
220
|
}
|
|
243
221
|
|
|
244
|
-
this
|
|
245
|
-
this
|
|
246
|
-
this
|
|
247
|
-
this
|
|
248
|
-
this
|
|
249
|
-
this
|
|
250
|
-
this
|
|
251
|
-
this
|
|
252
|
-
this
|
|
253
|
-
this
|
|
254
|
-
this
|
|
255
|
-
this
|
|
256
|
-
this
|
|
257
|
-
this
|
|
258
|
-
|
|
259
|
-
this.mongoLogger = this
|
|
222
|
+
this.poolState = PoolState.paused;
|
|
223
|
+
this.server = server;
|
|
224
|
+
this.connections = new List();
|
|
225
|
+
this.pending = 0;
|
|
226
|
+
this.checkedOut = new Set();
|
|
227
|
+
this.minPoolSizeTimer = undefined;
|
|
228
|
+
this.generation = 0;
|
|
229
|
+
this.serviceGenerations = new Map();
|
|
230
|
+
this.connectionCounter = makeCounter(1);
|
|
231
|
+
this.cancellationToken = new CancellationToken();
|
|
232
|
+
this.cancellationToken.setMaxListeners(Infinity);
|
|
233
|
+
this.waitQueue = new List();
|
|
234
|
+
this.metrics = new ConnectionPoolMetrics();
|
|
235
|
+
this.processingWaitQueue = false;
|
|
236
|
+
|
|
237
|
+
this.mongoLogger = this.server.topology.client?.mongoLogger;
|
|
260
238
|
this.component = 'connection';
|
|
261
239
|
|
|
262
240
|
process.nextTick(() => {
|
|
@@ -275,12 +253,7 @@ export class ConnectionPool extends TypedEventEmitter<ConnectionPoolEvents> {
|
|
|
275
253
|
* TODO(NODE-3263): We can remove this property once shell no longer needs it
|
|
276
254
|
*/
|
|
277
255
|
get closed(): boolean {
|
|
278
|
-
return this
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
/** An integer representing the SDAM generation of the pool */
|
|
282
|
-
get generation(): number {
|
|
283
|
-
return this[kGeneration];
|
|
256
|
+
return this.poolState === PoolState.closed;
|
|
284
257
|
}
|
|
285
258
|
|
|
286
259
|
/** An integer expressing how many total connections (available + pending + in use) the pool currently has */
|
|
@@ -292,31 +265,27 @@ export class ConnectionPool extends TypedEventEmitter<ConnectionPoolEvents> {
|
|
|
292
265
|
|
|
293
266
|
/** An integer expressing how many connections are currently available in the pool. */
|
|
294
267
|
get availableConnectionCount(): number {
|
|
295
|
-
return this
|
|
268
|
+
return this.connections.length;
|
|
296
269
|
}
|
|
297
270
|
|
|
298
271
|
get pendingConnectionCount(): number {
|
|
299
|
-
return this
|
|
272
|
+
return this.pending;
|
|
300
273
|
}
|
|
301
274
|
|
|
302
275
|
get currentCheckedOutCount(): number {
|
|
303
|
-
return this
|
|
276
|
+
return this.checkedOut.size;
|
|
304
277
|
}
|
|
305
278
|
|
|
306
279
|
get waitQueueSize(): number {
|
|
307
|
-
return this
|
|
280
|
+
return this.waitQueue.length;
|
|
308
281
|
}
|
|
309
282
|
|
|
310
283
|
get loadBalanced(): boolean {
|
|
311
284
|
return this.options.loadBalanced;
|
|
312
285
|
}
|
|
313
286
|
|
|
314
|
-
get serviceGenerations(): Map<string, number> {
|
|
315
|
-
return this[kServiceGenerations];
|
|
316
|
-
}
|
|
317
|
-
|
|
318
287
|
get serverError() {
|
|
319
|
-
return this
|
|
288
|
+
return this.server.description.error;
|
|
320
289
|
}
|
|
321
290
|
|
|
322
291
|
/**
|
|
@@ -327,26 +296,26 @@ export class ConnectionPool extends TypedEventEmitter<ConnectionPoolEvents> {
|
|
|
327
296
|
* This property may be removed as a part of NODE-3263.
|
|
328
297
|
*/
|
|
329
298
|
get checkedOutConnections() {
|
|
330
|
-
return this
|
|
299
|
+
return this.checkedOut;
|
|
331
300
|
}
|
|
332
301
|
|
|
333
302
|
/**
|
|
334
303
|
* Get the metrics information for the pool when a wait queue timeout occurs.
|
|
335
304
|
*/
|
|
336
305
|
private waitQueueErrorMetrics(): string {
|
|
337
|
-
return this
|
|
306
|
+
return this.metrics.info(this.options.maxPoolSize);
|
|
338
307
|
}
|
|
339
308
|
|
|
340
309
|
/**
|
|
341
310
|
* Set the pool state to "ready"
|
|
342
311
|
*/
|
|
343
312
|
ready(): void {
|
|
344
|
-
if (this
|
|
313
|
+
if (this.poolState !== PoolState.paused) {
|
|
345
314
|
return;
|
|
346
315
|
}
|
|
347
|
-
this
|
|
316
|
+
this.poolState = PoolState.ready;
|
|
348
317
|
this.emitAndLog(ConnectionPool.CONNECTION_POOL_READY, new ConnectionPoolReadyEvent(this));
|
|
349
|
-
clearTimeout(this
|
|
318
|
+
clearTimeout(this.minPoolSizeTimer);
|
|
350
319
|
this.ensureMinPoolSize();
|
|
351
320
|
}
|
|
352
321
|
|
|
@@ -355,7 +324,7 @@ export class ConnectionPool extends TypedEventEmitter<ConnectionPoolEvents> {
|
|
|
355
324
|
* will be held by the pool. This means that if a connection is checked out it MUST be checked back in or
|
|
356
325
|
* explicitly destroyed by the new owner.
|
|
357
326
|
*/
|
|
358
|
-
async checkOut(options: { timeoutContext: TimeoutContext }): Promise<Connection> {
|
|
327
|
+
async checkOut(options: { timeoutContext: TimeoutContext } & Abortable): Promise<Connection> {
|
|
359
328
|
const checkoutTime = now();
|
|
360
329
|
this.emitAndLog(
|
|
361
330
|
ConnectionPool.CONNECTION_CHECK_OUT_STARTED,
|
|
@@ -369,10 +338,16 @@ export class ConnectionPool extends TypedEventEmitter<ConnectionPoolEvents> {
|
|
|
369
338
|
const waitQueueMember: WaitQueueMember = {
|
|
370
339
|
resolve,
|
|
371
340
|
reject,
|
|
341
|
+
cancelled: false,
|
|
372
342
|
checkoutTime
|
|
373
343
|
};
|
|
374
344
|
|
|
375
|
-
|
|
345
|
+
const abortListener = addAbortListener(options.signal, function () {
|
|
346
|
+
waitQueueMember.cancelled = true;
|
|
347
|
+
reject(this.reason);
|
|
348
|
+
});
|
|
349
|
+
|
|
350
|
+
this.waitQueue.push(waitQueueMember);
|
|
376
351
|
process.nextTick(() => this.processWaitQueue());
|
|
377
352
|
|
|
378
353
|
try {
|
|
@@ -381,7 +356,7 @@ export class ConnectionPool extends TypedEventEmitter<ConnectionPoolEvents> {
|
|
|
381
356
|
} catch (error) {
|
|
382
357
|
if (TimeoutError.is(error)) {
|
|
383
358
|
timeout?.clear();
|
|
384
|
-
waitQueueMember
|
|
359
|
+
waitQueueMember.cancelled = true;
|
|
385
360
|
|
|
386
361
|
this.emitAndLog(
|
|
387
362
|
ConnectionPool.CONNECTION_CHECK_OUT_FAILED,
|
|
@@ -402,6 +377,7 @@ export class ConnectionPool extends TypedEventEmitter<ConnectionPoolEvents> {
|
|
|
402
377
|
}
|
|
403
378
|
throw error;
|
|
404
379
|
} finally {
|
|
380
|
+
abortListener?.[kDispose]();
|
|
405
381
|
timeout?.clear();
|
|
406
382
|
}
|
|
407
383
|
}
|
|
@@ -412,7 +388,7 @@ export class ConnectionPool extends TypedEventEmitter<ConnectionPoolEvents> {
|
|
|
412
388
|
* @param connection - The connection to check in
|
|
413
389
|
*/
|
|
414
390
|
checkIn(connection: Connection): void {
|
|
415
|
-
if (!this
|
|
391
|
+
if (!this.checkedOut.has(connection)) {
|
|
416
392
|
return;
|
|
417
393
|
}
|
|
418
394
|
const poolClosed = this.closed;
|
|
@@ -421,10 +397,10 @@ export class ConnectionPool extends TypedEventEmitter<ConnectionPoolEvents> {
|
|
|
421
397
|
|
|
422
398
|
if (!willDestroy) {
|
|
423
399
|
connection.markAvailable();
|
|
424
|
-
this
|
|
400
|
+
this.connections.unshift(connection);
|
|
425
401
|
}
|
|
426
402
|
|
|
427
|
-
this
|
|
403
|
+
this.checkedOut.delete(connection);
|
|
428
404
|
this.emitAndLog(
|
|
429
405
|
ConnectionPool.CONNECTION_CHECKED_IN,
|
|
430
406
|
new ConnectionCheckedInEvent(this, connection)
|
|
@@ -475,10 +451,10 @@ export class ConnectionPool extends TypedEventEmitter<ConnectionPoolEvents> {
|
|
|
475
451
|
}
|
|
476
452
|
// handle non load-balanced case
|
|
477
453
|
const interruptInUseConnections = options.interruptInUseConnections ?? false;
|
|
478
|
-
const oldGeneration = this
|
|
479
|
-
this
|
|
480
|
-
const alreadyPaused = this
|
|
481
|
-
this
|
|
454
|
+
const oldGeneration = this.generation;
|
|
455
|
+
this.generation += 1;
|
|
456
|
+
const alreadyPaused = this.poolState === PoolState.paused;
|
|
457
|
+
this.poolState = PoolState.paused;
|
|
482
458
|
|
|
483
459
|
this.clearMinPoolSizeTimer();
|
|
484
460
|
if (!alreadyPaused) {
|
|
@@ -503,7 +479,7 @@ export class ConnectionPool extends TypedEventEmitter<ConnectionPoolEvents> {
|
|
|
503
479
|
* Only connections where `connection.generation <= minGeneration` are killed.
|
|
504
480
|
*/
|
|
505
481
|
private interruptInUseConnections(minGeneration: number) {
|
|
506
|
-
for (const connection of this
|
|
482
|
+
for (const connection of this.checkedOut) {
|
|
507
483
|
if (connection.generation <= minGeneration) {
|
|
508
484
|
connection.onError(new PoolClearedOnNetworkError(this));
|
|
509
485
|
this.checkIn(connection);
|
|
@@ -518,25 +494,25 @@ export class ConnectionPool extends TypedEventEmitter<ConnectionPoolEvents> {
|
|
|
518
494
|
}
|
|
519
495
|
|
|
520
496
|
// immediately cancel any in-flight connections
|
|
521
|
-
this
|
|
497
|
+
this.cancellationToken.emit('cancel');
|
|
522
498
|
|
|
523
499
|
// end the connection counter
|
|
524
|
-
if (typeof this
|
|
525
|
-
this
|
|
500
|
+
if (typeof this.connectionCounter.return === 'function') {
|
|
501
|
+
this.connectionCounter.return(undefined);
|
|
526
502
|
}
|
|
527
503
|
|
|
528
|
-
this
|
|
504
|
+
this.poolState = PoolState.closed;
|
|
529
505
|
this.clearMinPoolSizeTimer();
|
|
530
506
|
this.processWaitQueue();
|
|
531
507
|
|
|
532
|
-
for (const conn of this
|
|
508
|
+
for (const conn of this.connections) {
|
|
533
509
|
this.emitAndLog(
|
|
534
510
|
ConnectionPool.CONNECTION_CLOSED,
|
|
535
511
|
new ConnectionClosedEvent(this, conn, 'poolClosed')
|
|
536
512
|
);
|
|
537
513
|
conn.destroy();
|
|
538
514
|
}
|
|
539
|
-
this
|
|
515
|
+
this.connections.clear();
|
|
540
516
|
this.emitAndLog(ConnectionPool.CONNECTION_POOL_CLOSED, new ConnectionPoolClosedEvent(this));
|
|
541
517
|
}
|
|
542
518
|
|
|
@@ -557,7 +533,7 @@ export class ConnectionPool extends TypedEventEmitter<ConnectionPoolEvents> {
|
|
|
557
533
|
}
|
|
558
534
|
|
|
559
535
|
const resolvedCredentials = credentials.resolveAuthMechanism(connection.hello);
|
|
560
|
-
const provider = this
|
|
536
|
+
const provider = this.server.topology.client.s.authProviders.getOrCreateProvider(
|
|
561
537
|
resolvedCredentials.mechanism,
|
|
562
538
|
resolvedCredentials.mechanismProperties
|
|
563
539
|
);
|
|
@@ -575,7 +551,7 @@ export class ConnectionPool extends TypedEventEmitter<ConnectionPoolEvents> {
|
|
|
575
551
|
|
|
576
552
|
/** Clear the min pool size timer */
|
|
577
553
|
private clearMinPoolSizeTimer(): void {
|
|
578
|
-
const minPoolSizeTimer = this
|
|
554
|
+
const minPoolSizeTimer = this.minPoolSizeTimer;
|
|
579
555
|
if (minPoolSizeTimer) {
|
|
580
556
|
clearTimeout(minPoolSizeTimer);
|
|
581
557
|
}
|
|
@@ -601,7 +577,7 @@ export class ConnectionPool extends TypedEventEmitter<ConnectionPoolEvents> {
|
|
|
601
577
|
return connection.generation !== generation;
|
|
602
578
|
}
|
|
603
579
|
|
|
604
|
-
return connection.generation !== this
|
|
580
|
+
return connection.generation !== this.generation;
|
|
605
581
|
}
|
|
606
582
|
|
|
607
583
|
private connectionIsIdle(connection: Connection) {
|
|
@@ -627,14 +603,14 @@ export class ConnectionPool extends TypedEventEmitter<ConnectionPoolEvents> {
|
|
|
627
603
|
private createConnection(callback: Callback<Connection>) {
|
|
628
604
|
const connectOptions: ConnectionOptions = {
|
|
629
605
|
...this.options,
|
|
630
|
-
id: this
|
|
631
|
-
generation: this
|
|
632
|
-
cancellationToken: this
|
|
606
|
+
id: this.connectionCounter.next().value,
|
|
607
|
+
generation: this.generation,
|
|
608
|
+
cancellationToken: this.cancellationToken,
|
|
633
609
|
mongoLogger: this.mongoLogger,
|
|
634
|
-
authProviders: this
|
|
610
|
+
authProviders: this.server.topology.client.s.authProviders
|
|
635
611
|
};
|
|
636
612
|
|
|
637
|
-
this
|
|
613
|
+
this.pending++;
|
|
638
614
|
// This is our version of a "virtual" no-I/O connection as the spec requires
|
|
639
615
|
const connectionCreatedTime = now();
|
|
640
616
|
this.emitAndLog(
|
|
@@ -645,8 +621,8 @@ export class ConnectionPool extends TypedEventEmitter<ConnectionPoolEvents> {
|
|
|
645
621
|
connect(connectOptions).then(
|
|
646
622
|
connection => {
|
|
647
623
|
// The pool might have closed since we started trying to create a connection
|
|
648
|
-
if (this
|
|
649
|
-
this
|
|
624
|
+
if (this.poolState !== PoolState.ready) {
|
|
625
|
+
this.pending--;
|
|
650
626
|
connection.destroy();
|
|
651
627
|
callback(this.closed ? new PoolClosedError(this) : new PoolClearedError(this));
|
|
652
628
|
return;
|
|
@@ -658,8 +634,8 @@ export class ConnectionPool extends TypedEventEmitter<ConnectionPoolEvents> {
|
|
|
658
634
|
}
|
|
659
635
|
|
|
660
636
|
if (this.loadBalanced) {
|
|
661
|
-
connection.on(Connection.PINNED, pinType => this
|
|
662
|
-
connection.on(Connection.UNPINNED, pinType => this
|
|
637
|
+
connection.on(Connection.PINNED, pinType => this.metrics.markPinned(pinType));
|
|
638
|
+
connection.on(Connection.UNPINNED, pinType => this.metrics.markUnpinned(pinType));
|
|
663
639
|
|
|
664
640
|
const serviceId = connection.serviceId;
|
|
665
641
|
if (serviceId) {
|
|
@@ -680,12 +656,12 @@ export class ConnectionPool extends TypedEventEmitter<ConnectionPoolEvents> {
|
|
|
680
656
|
new ConnectionReadyEvent(this, connection, connectionCreatedTime)
|
|
681
657
|
);
|
|
682
658
|
|
|
683
|
-
this
|
|
659
|
+
this.pending--;
|
|
684
660
|
callback(undefined, connection);
|
|
685
661
|
},
|
|
686
662
|
error => {
|
|
687
|
-
this
|
|
688
|
-
this
|
|
663
|
+
this.pending--;
|
|
664
|
+
this.server.handleError(error);
|
|
689
665
|
this.emitAndLog(
|
|
690
666
|
ConnectionPool.CONNECTION_CLOSED,
|
|
691
667
|
new ConnectionClosedEvent(
|
|
@@ -706,11 +682,11 @@ export class ConnectionPool extends TypedEventEmitter<ConnectionPoolEvents> {
|
|
|
706
682
|
|
|
707
683
|
private ensureMinPoolSize() {
|
|
708
684
|
const minPoolSize = this.options.minPoolSize;
|
|
709
|
-
if (this
|
|
685
|
+
if (this.poolState !== PoolState.ready || minPoolSize === 0) {
|
|
710
686
|
return;
|
|
711
687
|
}
|
|
712
688
|
|
|
713
|
-
this
|
|
689
|
+
this.connections.prune(connection => this.destroyConnectionIfPerished(connection));
|
|
714
690
|
|
|
715
691
|
if (
|
|
716
692
|
this.totalConnectionCount < minPoolSize &&
|
|
@@ -721,20 +697,20 @@ export class ConnectionPool extends TypedEventEmitter<ConnectionPoolEvents> {
|
|
|
721
697
|
// the connection to a checkout request
|
|
722
698
|
this.createConnection((err, connection) => {
|
|
723
699
|
if (!err && connection) {
|
|
724
|
-
this
|
|
700
|
+
this.connections.push(connection);
|
|
725
701
|
process.nextTick(() => this.processWaitQueue());
|
|
726
702
|
}
|
|
727
|
-
if (this
|
|
728
|
-
clearTimeout(this
|
|
729
|
-
this
|
|
703
|
+
if (this.poolState === PoolState.ready) {
|
|
704
|
+
clearTimeout(this.minPoolSizeTimer);
|
|
705
|
+
this.minPoolSizeTimer = setTimeout(
|
|
730
706
|
() => this.ensureMinPoolSize(),
|
|
731
707
|
this.options.minPoolSizeCheckFrequencyMS
|
|
732
708
|
);
|
|
733
709
|
}
|
|
734
710
|
});
|
|
735
711
|
} else {
|
|
736
|
-
clearTimeout(this
|
|
737
|
-
this
|
|
712
|
+
clearTimeout(this.minPoolSizeTimer);
|
|
713
|
+
this.minPoolSizeTimer = setTimeout(
|
|
738
714
|
() => this.ensureMinPoolSize(),
|
|
739
715
|
this.options.minPoolSizeCheckFrequencyMS
|
|
740
716
|
);
|
|
@@ -742,31 +718,31 @@ export class ConnectionPool extends TypedEventEmitter<ConnectionPoolEvents> {
|
|
|
742
718
|
}
|
|
743
719
|
|
|
744
720
|
private processWaitQueue() {
|
|
745
|
-
if (this
|
|
721
|
+
if (this.processingWaitQueue) {
|
|
746
722
|
return;
|
|
747
723
|
}
|
|
748
|
-
this
|
|
724
|
+
this.processingWaitQueue = true;
|
|
749
725
|
|
|
750
726
|
while (this.waitQueueSize) {
|
|
751
|
-
const waitQueueMember = this
|
|
727
|
+
const waitQueueMember = this.waitQueue.first();
|
|
752
728
|
if (!waitQueueMember) {
|
|
753
|
-
this
|
|
729
|
+
this.waitQueue.shift();
|
|
754
730
|
continue;
|
|
755
731
|
}
|
|
756
732
|
|
|
757
|
-
if (waitQueueMember
|
|
758
|
-
this
|
|
733
|
+
if (waitQueueMember.cancelled) {
|
|
734
|
+
this.waitQueue.shift();
|
|
759
735
|
continue;
|
|
760
736
|
}
|
|
761
737
|
|
|
762
|
-
if (this
|
|
738
|
+
if (this.poolState !== PoolState.ready) {
|
|
763
739
|
const reason = this.closed ? 'poolClosed' : 'connectionError';
|
|
764
740
|
const error = this.closed ? new PoolClosedError(this) : new PoolClearedError(this);
|
|
765
741
|
this.emitAndLog(
|
|
766
742
|
ConnectionPool.CONNECTION_CHECK_OUT_FAILED,
|
|
767
743
|
new ConnectionCheckOutFailedEvent(this, reason, waitQueueMember.checkoutTime, error)
|
|
768
744
|
);
|
|
769
|
-
this
|
|
745
|
+
this.waitQueue.shift();
|
|
770
746
|
waitQueueMember.reject(error);
|
|
771
747
|
continue;
|
|
772
748
|
}
|
|
@@ -775,19 +751,19 @@ export class ConnectionPool extends TypedEventEmitter<ConnectionPoolEvents> {
|
|
|
775
751
|
break;
|
|
776
752
|
}
|
|
777
753
|
|
|
778
|
-
const connection = this
|
|
754
|
+
const connection = this.connections.shift();
|
|
779
755
|
if (!connection) {
|
|
780
756
|
break;
|
|
781
757
|
}
|
|
782
758
|
|
|
783
759
|
if (!this.destroyConnectionIfPerished(connection)) {
|
|
784
|
-
this
|
|
760
|
+
this.checkedOut.add(connection);
|
|
785
761
|
this.emitAndLog(
|
|
786
762
|
ConnectionPool.CONNECTION_CHECKED_OUT,
|
|
787
763
|
new ConnectionCheckedOutEvent(this, connection, waitQueueMember.checkoutTime)
|
|
788
764
|
);
|
|
789
765
|
|
|
790
|
-
this
|
|
766
|
+
this.waitQueue.shift();
|
|
791
767
|
waitQueueMember.resolve(connection);
|
|
792
768
|
}
|
|
793
769
|
}
|
|
@@ -798,14 +774,14 @@ export class ConnectionPool extends TypedEventEmitter<ConnectionPoolEvents> {
|
|
|
798
774
|
this.pendingConnectionCount < maxConnecting &&
|
|
799
775
|
(maxPoolSize === 0 || this.totalConnectionCount < maxPoolSize)
|
|
800
776
|
) {
|
|
801
|
-
const waitQueueMember = this
|
|
802
|
-
if (!waitQueueMember || waitQueueMember
|
|
777
|
+
const waitQueueMember = this.waitQueue.shift();
|
|
778
|
+
if (!waitQueueMember || waitQueueMember.cancelled) {
|
|
803
779
|
continue;
|
|
804
780
|
}
|
|
805
781
|
this.createConnection((err, connection) => {
|
|
806
|
-
if (waitQueueMember
|
|
782
|
+
if (waitQueueMember.cancelled) {
|
|
807
783
|
if (!err && connection) {
|
|
808
|
-
this
|
|
784
|
+
this.connections.push(connection);
|
|
809
785
|
}
|
|
810
786
|
} else {
|
|
811
787
|
if (err) {
|
|
@@ -821,7 +797,7 @@ export class ConnectionPool extends TypedEventEmitter<ConnectionPoolEvents> {
|
|
|
821
797
|
);
|
|
822
798
|
waitQueueMember.reject(err);
|
|
823
799
|
} else if (connection) {
|
|
824
|
-
this
|
|
800
|
+
this.checkedOut.add(connection);
|
|
825
801
|
this.emitAndLog(
|
|
826
802
|
ConnectionPool.CONNECTION_CHECKED_OUT,
|
|
827
803
|
new ConnectionCheckedOutEvent(this, connection, waitQueueMember.checkoutTime)
|
|
@@ -832,7 +808,7 @@ export class ConnectionPool extends TypedEventEmitter<ConnectionPoolEvents> {
|
|
|
832
808
|
process.nextTick(() => this.processWaitQueue());
|
|
833
809
|
});
|
|
834
810
|
}
|
|
835
|
-
this
|
|
811
|
+
this.processingWaitQueue = false;
|
|
836
812
|
}
|
|
837
813
|
}
|
|
838
814
|
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { type EventEmitter } from 'events';
|
|
2
2
|
|
|
3
|
+
import { type Abortable } from '../../mongo_types';
|
|
3
4
|
import { type TimeoutContext } from '../../timeout';
|
|
4
|
-
import { List, promiseWithResolvers } from '../../utils';
|
|
5
|
+
import { addAbortListener, kDispose, List, promiseWithResolvers } from '../../utils';
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* @internal
|
|
@@ -21,8 +22,10 @@ type PendingPromises = Omit<
|
|
|
21
22
|
*/
|
|
22
23
|
export function onData(
|
|
23
24
|
emitter: EventEmitter,
|
|
24
|
-
{ timeoutContext }: { timeoutContext?: TimeoutContext }
|
|
25
|
+
{ timeoutContext, signal }: { timeoutContext?: TimeoutContext } & Abortable
|
|
25
26
|
) {
|
|
27
|
+
signal?.throwIfAborted();
|
|
28
|
+
|
|
26
29
|
// Setup pending events and pending promise lists
|
|
27
30
|
/**
|
|
28
31
|
* When the caller has not yet called .next(), we store the
|
|
@@ -90,6 +93,9 @@ export function onData(
|
|
|
90
93
|
// Adding event handlers
|
|
91
94
|
emitter.on('data', eventHandler);
|
|
92
95
|
emitter.on('error', errorHandler);
|
|
96
|
+
const abortListener = addAbortListener(signal, function () {
|
|
97
|
+
errorHandler(this.reason);
|
|
98
|
+
});
|
|
93
99
|
|
|
94
100
|
const timeoutForSocketRead = timeoutContext?.timeoutForSocketRead;
|
|
95
101
|
timeoutForSocketRead?.throwIfExpired();
|
|
@@ -115,6 +121,7 @@ export function onData(
|
|
|
115
121
|
// Adding event handlers
|
|
116
122
|
emitter.off('data', eventHandler);
|
|
117
123
|
emitter.off('error', errorHandler);
|
|
124
|
+
abortListener?.[kDispose]();
|
|
118
125
|
finished = true;
|
|
119
126
|
timeoutForSocketRead?.clear();
|
|
120
127
|
const doneResult = { value: undefined, done: finished } as const;
|