Skip to content

Commit 0206e84

Browse files
committed
refactor: keep waitqueue members in queue until connection ready
1 parent 88ef8a5 commit 0206e84

File tree

1 file changed

+29
-10
lines changed

1 file changed

+29
-10
lines changed

src/cmap/connection_pool.ts

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ const kMetrics = Symbol('metrics');
6666
const kProcessingWaitQueue = Symbol('processingWaitQueue');
6767
/** @internal */
6868
const kPoolState = Symbol('poolState');
69+
/** @internal */
70+
const kWaitQueuePending = Symbol('waitQueuePending');
6971

7072
/** @public */
7173
export interface ConnectionPoolOptions extends Omit<ConnectionOptions, 'id' | 'generation'> {
@@ -154,6 +156,8 @@ export class ConnectionPool extends TypedEventEmitter<ConnectionPoolEvents> {
154156
[kMetrics]: ConnectionPoolMetrics;
155157
/** @internal */
156158
[kProcessingWaitQueue]: boolean;
159+
/** @internal */
160+
[kWaitQueuePending]: number;
157161

158162
/**
159163
* Emitted when the connection pool is created.
@@ -245,6 +249,7 @@ export class ConnectionPool extends TypedEventEmitter<ConnectionPoolEvents> {
245249
this[kCancellationToken] = new CancellationToken();
246250
this[kCancellationToken].setMaxListeners(Infinity);
247251
this[kWaitQueue] = new Denque();
252+
this[kWaitQueuePending] = 0;
248253
this[kMetrics] = new ConnectionPoolMetrics();
249254
this[kProcessingWaitQueue] = false;
250255

@@ -396,6 +401,7 @@ export class ConnectionPool extends TypedEventEmitter<ConnectionPoolEvents> {
396401
if (this.closed) {
397402
return;
398403
}
404+
this[kWaitQueuePending] = 0;
399405

400406
// handle load balanced case
401407
if (this.loadBalanced && serviceId) {
@@ -453,6 +459,7 @@ export class ConnectionPool extends TypedEventEmitter<ConnectionPoolEvents> {
453459
}
454460

455461
this[kPoolState] = PoolState.closed;
462+
this[kWaitQueuePending] = 0;
456463
this.clearMinPoolSizeTimer();
457464
this.processWaitQueue();
458465

@@ -591,8 +598,8 @@ export class ConnectionPool extends TypedEventEmitter<ConnectionPoolEvents> {
591598
return;
592599
}
593600

594-
// The pool might have closed since we started trying to create a connection
595-
if (this.closed) {
601+
// The pool might have been cleared or closed since we started trying to create a connection
602+
if (this[kPoolState] !== PoolState.ready) {
596603
this[kPending]--;
597604
connection.destroy({ force: true });
598605
return;
@@ -722,17 +729,29 @@ export class ConnectionPool extends TypedEventEmitter<ConnectionPoolEvents> {
722729
}
723730

724731
const { maxPoolSize, maxConnecting } = this.options;
725-
while (
726-
this.waitQueueSize > 0 &&
727-
this.pendingConnectionCount < maxConnecting &&
728-
(maxPoolSize === 0 || this.totalConnectionCount < maxPoolSize)
732+
for (
733+
let waitQueueIndex = this[kWaitQueuePending];
734+
waitQueueIndex < this.waitQueueSize;
735+
waitQueueIndex++
729736
) {
730-
const waitQueueMember = this[kWaitQueue].shift();
731-
if (!waitQueueMember || waitQueueMember[kCancelled]) {
732-
continue;
737+
if (
738+
this.pendingConnectionCount >= maxConnecting ||
739+
(maxPoolSize > 0 && this.totalConnectionCount >= maxPoolSize)
740+
) {
741+
break;
733742
}
743+
this[kWaitQueuePending]++;
734744
this.createConnection((err, connection) => {
735-
if (waitQueueMember[kCancelled]) {
745+
// The > 0 guard is just a precaution against future refactors
746+
// Currently, the callback is invoked sync from createConnection
747+
// so we are guaranteed the pool is still ready at this point
748+
// however, if this changes to async, then it will be possible for the
749+
// queue to get cleared before we get here
750+
if (this[kWaitQueuePending] > 0) {
751+
this[kWaitQueuePending]--;
752+
}
753+
const waitQueueMember = this[kWaitQueue].shift();
754+
if (!waitQueueMember || waitQueueMember[kCancelled]) {
736755
if (!err && connection) {
737756
this[kConnections].push(connection);
738757
}

0 commit comments

Comments
 (0)