diff --git a/Readme.md b/Readme.md index 5af3ed261..a5cc74950 100644 --- a/Readme.md +++ b/Readme.md @@ -367,8 +367,7 @@ time one is needed. Connections are lazily created by the pool. If you configure the pool to allow up to 100 connections, but only ever use 5 simultaneously, only 5 connections -will be made. Connections are also cycled round-robin style, with connections -being taken from the top of the pool and returning to the bottom. +will be made. When a previous connection is retrieved from the pool, a ping packet is sent to the server to check if the connection is still good. @@ -391,6 +390,9 @@ constructor. In addition to those options pools accept a few extras: * `queueLimit`: The maximum number of connection requests the pool will queue before returning an error from `getConnection`. If set to `0`, there is no limit to the number of queued connection requests. (Default: `0`) +* `roundRobinConnectionCycling`: Whether the pool should cycle through connections + or not. If set to false, connections will be retrieved and returned to the pool + on a last in first out basis. (Default: `true`) ## Pool events diff --git a/lib/Pool.js b/lib/Pool.js index 87a40114a..2750f5a71 100644 --- a/lib/Pool.js +++ b/lib/Pool.js @@ -136,10 +136,14 @@ Pool.prototype.releaseConnection = function releaseConnection(connection) { // connection already in free connection pool // this won't catch all double-release cases throw new Error('Connection already released'); - } else { - // add connection to end of free queue + } else if (this.config.roundRobinConnectionCycling) { + // add connection to the bottom of the free queue this._freeConnections.push(connection); this.emit('release', connection); + } else { + // add connection to the top of the free queue + this._freeConnections.unshift(connection); + this.emit('release', connection); } } diff --git a/lib/PoolConfig.js b/lib/PoolConfig.js index 8c5017a27..970fabdc1 100644 --- a/lib/PoolConfig.js +++ b/lib/PoolConfig.js @@ -20,6 +20,10 @@ function PoolConfig(options) { this.queueLimit = (options.queueLimit === undefined) ? 0 : Number(options.queueLimit); + this.roundRobinConnectionCycling = (options.roundRobinConnectionCycling === undefined) + ? true + : Boolean(options.roundRobinConnectionCycling); + } PoolConfig.prototype.newConnectionConfig = function newConnectionConfig() { diff --git a/test/unit/pool/test-connection-cycling-lifo.js b/test/unit/pool/test-connection-cycling-lifo.js new file mode 100644 index 000000000..a910a99d0 --- /dev/null +++ b/test/unit/pool/test-connection-cycling-lifo.js @@ -0,0 +1,48 @@ +var after = require('after'); +var assert = require('assert'); +var common = require('../../common'); +var pool = common.createPool({ + port : common.fakeServerPort, + roundRobinConnectionCycling : false +}); + +var server = common.createFakeServer(); +var lastConnectionId = null; +var numberOfConnections = 4; + +server.listen(common.fakeServerPort, function (err) { + assert.ifError(err); + + var getConnectionAndEnsureItsTheLastConnection = function(cb) { + pool.getConnection(function (err, connection) { + assert.ifError(err); + assert.ok(connection.id === lastConnectionId); + connection.release(); + if (cb) cb(); + }); + }; + + var done = after(numberOfConnections, function () { + getConnectionAndEnsureItsTheLastConnection(function() { + getConnectionAndEnsureItsTheLastConnection(function() { + pool.end(function (err) { + assert.ifError(err); + server.destroy(); + }); + }); + }); + }); + + var counter = 1; + + var createIndexedConnection = function () { + pool.getConnection(function (err, connection) { + assert.ifError(err); + connection.id = counter++; + lastConnectionId = connection.id; + connection.release(); + done(); + }); + }; + Array.apply(null, Array(numberOfConnections)).map(createIndexedConnection); +}); diff --git a/test/unit/pool/test-connection-cycling-round-robin.js b/test/unit/pool/test-connection-cycling-round-robin.js new file mode 100644 index 000000000..b4d37e45c --- /dev/null +++ b/test/unit/pool/test-connection-cycling-round-robin.js @@ -0,0 +1,47 @@ +var after = require('after'); +var assert = require('assert'); +var common = require('../../common'); +var pool = common.createPool({port: common.fakeServerPort}); + +var server = common.createFakeServer(); +var numberOfConnections = 4; +var connectionIds = []; +var connectionNumber = 0; + +server.listen(common.fakeServerPort, function (err) { + assert.ifError(err); + + var getConnectionAndEnsureItsTheCorrectOne = function(cb) { + pool.getConnection(function (err, connection) { + assert.ifError(err); + assert.ok(connection.id === connectionIds[connectionNumber]); + connectionNumber++; + connection.release(); + if (cb) cb(); + }); + }; + + var done = after(numberOfConnections, function () { + getConnectionAndEnsureItsTheCorrectOne(function() { + getConnectionAndEnsureItsTheCorrectOne(function() { + pool.end(function (err) { + assert.ifError(err); + server.destroy(); + }); + }); + }); + }); + + var counter = 1; + + var createIndexedConnection = function () { + pool.getConnection(function (err, connection) { + assert.ifError(err); + connection.id = counter++; + connectionIds.push(connection.id); + connection.release(); + done(); + }); + }; + Array.apply(null, Array(numberOfConnections)).map(createIndexedConnection); +});