You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							594 lines
						
					
					
						
							17 KiB
						
					
					
				
			
		
		
	
	
							594 lines
						
					
					
						
							17 KiB
						
					
					
				| 'use strict';
 | |
| 
 | |
| const Denque = require('denque');
 | |
| const EventEmitter = require('events').EventEmitter;
 | |
| const Logger = require('../core/connection/logger');
 | |
| const makeCounter = require('../utils').makeCounter;
 | |
| const MongoError = require('../core/error').MongoError;
 | |
| const Connection = require('./connection').Connection;
 | |
| const eachAsync = require('../core/utils').eachAsync;
 | |
| const connect = require('../core/connection/connect');
 | |
| const relayEvents = require('../core/utils').relayEvents;
 | |
| 
 | |
| const errors = require('./errors');
 | |
| const PoolClosedError = errors.PoolClosedError;
 | |
| const WaitQueueTimeoutError = errors.WaitQueueTimeoutError;
 | |
| 
 | |
| const events = require('./events');
 | |
| const ConnectionPoolCreatedEvent = events.ConnectionPoolCreatedEvent;
 | |
| const ConnectionPoolClosedEvent = events.ConnectionPoolClosedEvent;
 | |
| const ConnectionCreatedEvent = events.ConnectionCreatedEvent;
 | |
| const ConnectionReadyEvent = events.ConnectionReadyEvent;
 | |
| const ConnectionClosedEvent = events.ConnectionClosedEvent;
 | |
| const ConnectionCheckOutStartedEvent = events.ConnectionCheckOutStartedEvent;
 | |
| const ConnectionCheckOutFailedEvent = events.ConnectionCheckOutFailedEvent;
 | |
| const ConnectionCheckedOutEvent = events.ConnectionCheckedOutEvent;
 | |
| const ConnectionCheckedInEvent = events.ConnectionCheckedInEvent;
 | |
| const ConnectionPoolClearedEvent = events.ConnectionPoolClearedEvent;
 | |
| 
 | |
| const kLogger = Symbol('logger');
 | |
| const kConnections = Symbol('connections');
 | |
| const kPermits = Symbol('permits');
 | |
| const kMinPoolSizeTimer = Symbol('minPoolSizeTimer');
 | |
| const kGeneration = Symbol('generation');
 | |
| const kConnectionCounter = Symbol('connectionCounter');
 | |
| const kCancellationToken = Symbol('cancellationToken');
 | |
| const kWaitQueue = Symbol('waitQueue');
 | |
| const kCancelled = Symbol('cancelled');
 | |
| 
 | |
| const VALID_POOL_OPTIONS = new Set([
 | |
|   // `connect` options
 | |
|   'ssl',
 | |
|   'bson',
 | |
|   'connectionType',
 | |
|   'serverApi',
 | |
|   'monitorCommands',
 | |
|   'socketTimeout',
 | |
|   'credentials',
 | |
|   'compression',
 | |
| 
 | |
|   // node Net options
 | |
|   'host',
 | |
|   'port',
 | |
|   'localAddress',
 | |
|   'localPort',
 | |
|   'family',
 | |
|   'hints',
 | |
|   'lookup',
 | |
|   'path',
 | |
| 
 | |
|   // node TLS options
 | |
|   'ca',
 | |
|   'cert',
 | |
|   'sigalgs',
 | |
|   'ciphers',
 | |
|   'clientCertEngine',
 | |
|   'crl',
 | |
|   'dhparam',
 | |
|   'ecdhCurve',
 | |
|   'honorCipherOrder',
 | |
|   'key',
 | |
|   'privateKeyEngine',
 | |
|   'privateKeyIdentifier',
 | |
|   'maxVersion',
 | |
|   'minVersion',
 | |
|   'passphrase',
 | |
|   'pfx',
 | |
|   'secureOptions',
 | |
|   'secureProtocol',
 | |
|   'sessionIdContext',
 | |
|   'allowHalfOpen',
 | |
|   'rejectUnauthorized',
 | |
|   'pskCallback',
 | |
|   'ALPNProtocols',
 | |
|   'servername',
 | |
|   'checkServerIdentity',
 | |
|   'session',
 | |
|   'minDHSize',
 | |
|   'secureContext',
 | |
| 
 | |
|   // spec options
 | |
|   'maxPoolSize',
 | |
|   'minPoolSize',
 | |
|   'maxIdleTimeMS',
 | |
|   'waitQueueTimeoutMS'
 | |
| ]);
 | |
| 
 | |
| function resolveOptions(options, defaults) {
 | |
|   const newOptions = Array.from(VALID_POOL_OPTIONS).reduce((obj, key) => {
 | |
|     if (Object.prototype.hasOwnProperty.call(options, key)) {
 | |
|       obj[key] = options[key];
 | |
|     }
 | |
| 
 | |
|     return obj;
 | |
|   }, {});
 | |
| 
 | |
|   return Object.freeze(Object.assign({}, defaults, newOptions));
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Configuration options for drivers wrapping the node driver.
 | |
|  *
 | |
|  * @typedef {Object} ConnectionPoolOptions
 | |
|  * @property
 | |
|  * @property {string} [host] The host to connect to
 | |
|  * @property {number} [port] The port to connect to
 | |
|  * @property {bson} [bson] The BSON instance to use for new connections
 | |
|  * @property {number} [maxPoolSize=100] The maximum number of connections that may be associated with a pool at a given time. This includes in use and available connections.
 | |
|  * @property {number} [minPoolSize=0] The minimum number of connections that MUST exist at any moment in a single connection pool.
 | |
|  * @property {number} [maxIdleTimeMS] The maximum amount of time a connection should remain idle in the connection pool before being marked idle.
 | |
|  * @property {number} [waitQueueTimeoutMS=0] The maximum amount of time operation execution should wait for a connection to become available. The default is 0 which means there is no limit.
 | |
|  */
 | |
| 
 | |
| /**
 | |
|  * A pool of connections which dynamically resizes, and emit events related to pool activity
 | |
|  *
 | |
|  * @property {number} generation An integer representing the SDAM generation of the pool
 | |
|  * @property {number} totalConnectionCount An integer expressing how many total connections (active + in use) the pool currently has
 | |
|  * @property {number} availableConnectionCount An integer expressing how many connections are currently available in the pool.
 | |
|  * @property {string} address The address of the endpoint the pool is connected to
 | |
|  *
 | |
|  * @emits ConnectionPool#connectionPoolCreated
 | |
|  * @emits ConnectionPool#connectionPoolClosed
 | |
|  * @emits ConnectionPool#connectionCreated
 | |
|  * @emits ConnectionPool#connectionReady
 | |
|  * @emits ConnectionPool#connectionClosed
 | |
|  * @emits ConnectionPool#connectionCheckOutStarted
 | |
|  * @emits ConnectionPool#connectionCheckOutFailed
 | |
|  * @emits ConnectionPool#connectionCheckedOut
 | |
|  * @emits ConnectionPool#connectionCheckedIn
 | |
|  * @emits ConnectionPool#connectionPoolCleared
 | |
|  */
 | |
| class ConnectionPool extends EventEmitter {
 | |
|   /**
 | |
|    * Create a new Connection Pool
 | |
|    *
 | |
|    * @param {ConnectionPoolOptions} options
 | |
|    */
 | |
|   constructor(options) {
 | |
|     super();
 | |
|     options = options || {};
 | |
| 
 | |
|     this.closed = false;
 | |
|     this.options = resolveOptions(options, {
 | |
|       connectionType: Connection,
 | |
|       maxPoolSize: typeof options.maxPoolSize === 'number' ? options.maxPoolSize : 100,
 | |
|       minPoolSize: typeof options.minPoolSize === 'number' ? options.minPoolSize : 0,
 | |
|       maxIdleTimeMS: typeof options.maxIdleTimeMS === 'number' ? options.maxIdleTimeMS : 0,
 | |
|       waitQueueTimeoutMS:
 | |
|         typeof options.waitQueueTimeoutMS === 'number' ? options.waitQueueTimeoutMS : 0,
 | |
|       autoEncrypter: options.autoEncrypter,
 | |
|       metadata: options.metadata,
 | |
|       useUnifiedTopology: options.useUnifiedTopology
 | |
|     });
 | |
| 
 | |
|     if (options.minSize > options.maxSize) {
 | |
|       throw new TypeError(
 | |
|         'Connection pool minimum size must not be greater than maximum pool size'
 | |
|       );
 | |
|     }
 | |
| 
 | |
|     this[kLogger] = Logger('ConnectionPool', options);
 | |
|     this[kConnections] = new Denque();
 | |
|     this[kPermits] = this.options.maxPoolSize;
 | |
|     this[kMinPoolSizeTimer] = undefined;
 | |
|     this[kGeneration] = 0;
 | |
|     this[kConnectionCounter] = makeCounter(1);
 | |
|     this[kCancellationToken] = new EventEmitter();
 | |
|     this[kCancellationToken].setMaxListeners(Infinity);
 | |
|     this[kWaitQueue] = new Denque();
 | |
| 
 | |
|     process.nextTick(() => {
 | |
|       this.emit('connectionPoolCreated', new ConnectionPoolCreatedEvent(this));
 | |
|       ensureMinPoolSize(this);
 | |
|     });
 | |
|   }
 | |
| 
 | |
|   get address() {
 | |
|     return `${this.options.host}:${this.options.port}`;
 | |
|   }
 | |
| 
 | |
|   get generation() {
 | |
|     return this[kGeneration];
 | |
|   }
 | |
| 
 | |
|   get totalConnectionCount() {
 | |
|     return this[kConnections].length + (this.options.maxPoolSize - this[kPermits]);
 | |
|   }
 | |
| 
 | |
|   get availableConnectionCount() {
 | |
|     return this[kConnections].length;
 | |
|   }
 | |
| 
 | |
|   get waitQueueSize() {
 | |
|     return this[kWaitQueue].length;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Check a connection out of this pool. The connection will continue to be tracked, but no reference to it
 | |
|    * will be held by the pool. This means that if a connection is checked out it MUST be checked back in or
 | |
|    * explicitly destroyed by the new owner.
 | |
|    *
 | |
|    * @param {ConnectionPool~checkOutCallback} callback
 | |
|    */
 | |
|   checkOut(callback) {
 | |
|     this.emit('connectionCheckOutStarted', new ConnectionCheckOutStartedEvent(this));
 | |
| 
 | |
|     if (this.closed) {
 | |
|       this.emit('connectionCheckOutFailed', new ConnectionCheckOutFailedEvent(this, 'poolClosed'));
 | |
|       callback(new PoolClosedError(this));
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|     const waitQueueMember = { callback };
 | |
| 
 | |
|     const pool = this;
 | |
|     const waitQueueTimeoutMS = this.options.waitQueueTimeoutMS;
 | |
|     if (waitQueueTimeoutMS) {
 | |
|       waitQueueMember.timer = setTimeout(() => {
 | |
|         waitQueueMember[kCancelled] = true;
 | |
|         waitQueueMember.timer = undefined;
 | |
| 
 | |
|         pool.emit('connectionCheckOutFailed', new ConnectionCheckOutFailedEvent(pool, 'timeout'));
 | |
|         waitQueueMember.callback(new WaitQueueTimeoutError(pool));
 | |
|       }, waitQueueTimeoutMS);
 | |
|     }
 | |
| 
 | |
|     this[kWaitQueue].push(waitQueueMember);
 | |
|     process.nextTick(() => processWaitQueue(this));
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Check a connection into the pool.
 | |
|    *
 | |
|    * @param {Connection} connection The connection to check in
 | |
|    */
 | |
|   checkIn(connection) {
 | |
|     const poolClosed = this.closed;
 | |
|     const stale = connectionIsStale(this, connection);
 | |
|     const willDestroy = !!(poolClosed || stale || connection.closed);
 | |
| 
 | |
|     if (!willDestroy) {
 | |
|       connection.markAvailable();
 | |
|       this[kConnections].push(connection);
 | |
|     }
 | |
| 
 | |
|     this.emit('connectionCheckedIn', new ConnectionCheckedInEvent(this, connection));
 | |
| 
 | |
|     if (willDestroy) {
 | |
|       const reason = connection.closed ? 'error' : poolClosed ? 'poolClosed' : 'stale';
 | |
|       destroyConnection(this, connection, reason);
 | |
|     }
 | |
| 
 | |
|     process.nextTick(() => processWaitQueue(this));
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Clear the pool
 | |
|    *
 | |
|    * Pool reset is handled by incrementing the pool's generation count. Any existing connection of a
 | |
|    * previous generation will eventually be pruned during subsequent checkouts.
 | |
|    */
 | |
|   clear() {
 | |
|     this[kGeneration] += 1;
 | |
|     this.emit('connectionPoolCleared', new ConnectionPoolClearedEvent(this));
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Close the pool
 | |
|    *
 | |
|    * @param {object} [options] Optional settings
 | |
|    * @param {boolean} [options.force] Force close connections
 | |
|    * @param {Function} callback
 | |
|    */
 | |
|   close(options, callback) {
 | |
|     if (typeof options === 'function') {
 | |
|       callback = options;
 | |
|     }
 | |
| 
 | |
|     options = Object.assign({ force: false }, options);
 | |
|     if (this.closed) {
 | |
|       return callback();
 | |
|     }
 | |
| 
 | |
|     // immediately cancel any in-flight connections
 | |
|     this[kCancellationToken].emit('cancel');
 | |
| 
 | |
|     // drain the wait queue
 | |
|     while (this.waitQueueSize) {
 | |
|       const waitQueueMember = this[kWaitQueue].pop();
 | |
|       clearTimeout(waitQueueMember.timer);
 | |
|       if (!waitQueueMember[kCancelled]) {
 | |
|         waitQueueMember.callback(new MongoError('connection pool closed'));
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     // clear the min pool size timer
 | |
|     if (this[kMinPoolSizeTimer]) {
 | |
|       clearTimeout(this[kMinPoolSizeTimer]);
 | |
|     }
 | |
| 
 | |
|     // end the connection counter
 | |
|     if (typeof this[kConnectionCounter].return === 'function') {
 | |
|       this[kConnectionCounter].return();
 | |
|     }
 | |
| 
 | |
|     // mark the pool as closed immediately
 | |
|     this.closed = true;
 | |
| 
 | |
|     eachAsync(
 | |
|       this[kConnections].toArray(),
 | |
|       (conn, cb) => {
 | |
|         this.emit('connectionClosed', new ConnectionClosedEvent(this, conn, 'poolClosed'));
 | |
|         conn.destroy(options, cb);
 | |
|       },
 | |
|       err => {
 | |
|         this[kConnections].clear();
 | |
|         this.emit('connectionPoolClosed', new ConnectionPoolClosedEvent(this));
 | |
|         callback(err);
 | |
|       }
 | |
|     );
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Runs a lambda with an implicitly checked out connection, checking that connection back in when the lambda
 | |
|    * has completed by calling back.
 | |
|    *
 | |
|    * NOTE: please note the required signature of `fn`
 | |
|    *
 | |
|    * @param {ConnectionPool~withConnectionCallback} fn A function which operates on a managed connection
 | |
|    * @param {Function} callback The original callback
 | |
|    * @return {Promise}
 | |
|    */
 | |
|   withConnection(fn, callback) {
 | |
|     this.checkOut((err, conn) => {
 | |
|       // don't callback with `err` here, we might want to act upon it inside `fn`
 | |
| 
 | |
|       fn(err, conn, (fnErr, result) => {
 | |
|         if (typeof callback === 'function') {
 | |
|           if (fnErr) {
 | |
|             callback(fnErr);
 | |
|           } else {
 | |
|             callback(undefined, result);
 | |
|           }
 | |
|         }
 | |
| 
 | |
|         if (conn) {
 | |
|           this.checkIn(conn);
 | |
|         }
 | |
|       });
 | |
|     });
 | |
|   }
 | |
| }
 | |
| 
 | |
| function ensureMinPoolSize(pool) {
 | |
|   if (pool.closed || pool.options.minPoolSize === 0) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   const minPoolSize = pool.options.minPoolSize;
 | |
|   for (let i = pool.totalConnectionCount; i < minPoolSize; ++i) {
 | |
|     createConnection(pool);
 | |
|   }
 | |
| 
 | |
|   pool[kMinPoolSizeTimer] = setTimeout(() => ensureMinPoolSize(pool), 10);
 | |
| }
 | |
| 
 | |
| function connectionIsStale(pool, connection) {
 | |
|   return connection.generation !== pool[kGeneration];
 | |
| }
 | |
| 
 | |
| function connectionIsIdle(pool, connection) {
 | |
|   return !!(pool.options.maxIdleTimeMS && connection.idleTime > pool.options.maxIdleTimeMS);
 | |
| }
 | |
| 
 | |
| function createConnection(pool, callback) {
 | |
|   const connectOptions = Object.assign(
 | |
|     {
 | |
|       id: pool[kConnectionCounter].next().value,
 | |
|       generation: pool[kGeneration]
 | |
|     },
 | |
|     pool.options
 | |
|   );
 | |
| 
 | |
|   pool[kPermits]--;
 | |
|   connect(connectOptions, pool[kCancellationToken], (err, connection) => {
 | |
|     if (err) {
 | |
|       pool[kPermits]++;
 | |
|       pool[kLogger].debug(`connection attempt failed with error [${JSON.stringify(err)}]`);
 | |
|       if (typeof callback === 'function') {
 | |
|         callback(err);
 | |
|       }
 | |
| 
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|     // The pool might have closed since we started trying to create a connection
 | |
|     if (pool.closed) {
 | |
|       connection.destroy({ force: true });
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|     // forward all events from the connection to the pool
 | |
|     relayEvents(connection, pool, [
 | |
|       'commandStarted',
 | |
|       'commandFailed',
 | |
|       'commandSucceeded',
 | |
|       'clusterTimeReceived'
 | |
|     ]);
 | |
| 
 | |
|     pool.emit('connectionCreated', new ConnectionCreatedEvent(pool, connection));
 | |
| 
 | |
|     connection.markAvailable();
 | |
|     pool.emit('connectionReady', new ConnectionReadyEvent(pool, connection));
 | |
| 
 | |
|     // if a callback has been provided, check out the connection immediately
 | |
|     if (typeof callback === 'function') {
 | |
|       callback(undefined, connection);
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|     // otherwise add it to the pool for later acquisition, and try to process the wait queue
 | |
|     pool[kConnections].push(connection);
 | |
|     process.nextTick(() => processWaitQueue(pool));
 | |
|   });
 | |
| }
 | |
| 
 | |
| function destroyConnection(pool, connection, reason) {
 | |
|   pool.emit('connectionClosed', new ConnectionClosedEvent(pool, connection, reason));
 | |
| 
 | |
|   // allow more connections to be created
 | |
|   pool[kPermits]++;
 | |
| 
 | |
|   // destroy the connection
 | |
|   process.nextTick(() => connection.destroy());
 | |
| }
 | |
| 
 | |
| function processWaitQueue(pool) {
 | |
|   if (pool.closed) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   while (pool.waitQueueSize) {
 | |
|     const waitQueueMember = pool[kWaitQueue].peekFront();
 | |
|     if (waitQueueMember[kCancelled]) {
 | |
|       pool[kWaitQueue].shift();
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     if (!pool.availableConnectionCount) {
 | |
|       break;
 | |
|     }
 | |
| 
 | |
|     const connection = pool[kConnections].shift();
 | |
|     const isStale = connectionIsStale(pool, connection);
 | |
|     const isIdle = connectionIsIdle(pool, connection);
 | |
|     if (!isStale && !isIdle && !connection.closed) {
 | |
|       pool.emit('connectionCheckedOut', new ConnectionCheckedOutEvent(pool, connection));
 | |
|       clearTimeout(waitQueueMember.timer);
 | |
|       pool[kWaitQueue].shift();
 | |
|       waitQueueMember.callback(undefined, connection);
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|     const reason = connection.closed ? 'error' : isStale ? 'stale' : 'idle';
 | |
|     destroyConnection(pool, connection, reason);
 | |
|   }
 | |
| 
 | |
|   const maxPoolSize = pool.options.maxPoolSize;
 | |
|   if (pool.waitQueueSize && (maxPoolSize <= 0 || pool.totalConnectionCount < maxPoolSize)) {
 | |
|     createConnection(pool, (err, connection) => {
 | |
|       const waitQueueMember = pool[kWaitQueue].shift();
 | |
|       if (waitQueueMember == null || waitQueueMember[kCancelled]) {
 | |
|         if (err == null) {
 | |
|           pool[kConnections].push(connection);
 | |
|         }
 | |
| 
 | |
|         return;
 | |
|       }
 | |
| 
 | |
|       if (err) {
 | |
|         pool.emit('connectionCheckOutFailed', new ConnectionCheckOutFailedEvent(pool, err));
 | |
|       } else {
 | |
|         pool.emit('connectionCheckedOut', new ConnectionCheckedOutEvent(pool, connection));
 | |
|       }
 | |
| 
 | |
|       clearTimeout(waitQueueMember.timer);
 | |
|       waitQueueMember.callback(err, connection);
 | |
|     });
 | |
| 
 | |
|     return;
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * A callback provided to `withConnection`
 | |
|  *
 | |
|  * @callback ConnectionPool~withConnectionCallback
 | |
|  * @param {MongoError} error An error instance representing the error during the execution.
 | |
|  * @param {Connection} connection The managed connection which was checked out of the pool.
 | |
|  * @param {Function} callback A function to call back after connection management is complete
 | |
|  */
 | |
| 
 | |
| /**
 | |
|  * A callback provided to `checkOut`
 | |
|  *
 | |
|  * @callback ConnectionPool~checkOutCallback
 | |
|  * @param {MongoError} error An error instance representing the error during checkout
 | |
|  * @param {Connection} connection A connection from the pool
 | |
|  */
 | |
| 
 | |
| /**
 | |
|  * Emitted once when the connection pool is created
 | |
|  *
 | |
|  * @event ConnectionPool#connectionPoolCreated
 | |
|  * @type {PoolCreatedEvent}
 | |
|  */
 | |
| 
 | |
| /**
 | |
|  * Emitted once when the connection pool is closed
 | |
|  *
 | |
|  * @event ConnectionPool#connectionPoolClosed
 | |
|  * @type {PoolClosedEvent}
 | |
|  */
 | |
| 
 | |
| /**
 | |
|  * Emitted each time a connection is created
 | |
|  *
 | |
|  * @event ConnectionPool#connectionCreated
 | |
|  * @type {ConnectionCreatedEvent}
 | |
|  */
 | |
| 
 | |
| /**
 | |
|  * Emitted when a connection becomes established, and is ready to use
 | |
|  *
 | |
|  * @event ConnectionPool#connectionReady
 | |
|  * @type {ConnectionReadyEvent}
 | |
|  */
 | |
| 
 | |
| /**
 | |
|  * Emitted when a connection is closed
 | |
|  *
 | |
|  * @event ConnectionPool#connectionClosed
 | |
|  * @type {ConnectionClosedEvent}
 | |
|  */
 | |
| 
 | |
| /**
 | |
|  * Emitted when an attempt to check out a connection begins
 | |
|  *
 | |
|  * @event ConnectionPool#connectionCheckOutStarted
 | |
|  * @type {ConnectionCheckOutStartedEvent}
 | |
|  */
 | |
| 
 | |
| /**
 | |
|  * Emitted when an attempt to check out a connection fails
 | |
|  *
 | |
|  * @event ConnectionPool#connectionCheckOutFailed
 | |
|  * @type {ConnectionCheckOutFailedEvent}
 | |
|  */
 | |
| 
 | |
| /**
 | |
|  * Emitted each time a connection is successfully checked out of the connection pool
 | |
|  *
 | |
|  * @event ConnectionPool#connectionCheckedOut
 | |
|  * @type {ConnectionCheckedOutEvent}
 | |
|  */
 | |
| 
 | |
| /**
 | |
|  * Emitted each time a connection is successfully checked into the connection pool
 | |
|  *
 | |
|  * @event ConnectionPool#connectionCheckedIn
 | |
|  * @type {ConnectionCheckedInEvent}
 | |
|  */
 | |
| 
 | |
| /**
 | |
|  * Emitted each time the connection pool is cleared and it's generation incremented
 | |
|  *
 | |
|  * @event ConnectionPool#connectionPoolCleared
 | |
|  * @type {PoolClearedEvent}
 | |
|  */
 | |
| 
 | |
| module.exports = {
 | |
|   ConnectionPool
 | |
| };
 |