Skip to content

Commit 971eb5d

Browse files
committed
initial work on new pool
1 parent d046ffc commit 971eb5d

File tree

2 files changed

+181
-0
lines changed

2 files changed

+181
-0
lines changed

lib/pool.js

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
var defaults = require(__dirname + '/defaults');
2+
var genericPool = require('generic-pool');
3+
4+
//takes the same config structure as client
5+
var createPool = function(config) {
6+
config = config || {};
7+
var name = JSON.stringify(config);
8+
var pool = createPool.all[name];
9+
if(pool) {
10+
return pool;
11+
}
12+
pool = genericPool.Pool({
13+
name: name,
14+
max: defaults.poolSize,
15+
create: function(cb) {
16+
var client = new createPool.Client(config);
17+
client.connect(function(err) {
18+
return cb(err, client);
19+
});
20+
},
21+
destroy: function(client) {
22+
client.end();
23+
}
24+
});
25+
createPool.all[name] = pool;
26+
pool.connect = function(cb) {
27+
pool.acquire(function(err, client) {
28+
//TODO: on connection error should we remove this client automatically?
29+
if(err) {
30+
return cb(err);
31+
}
32+
if(cb.length > 2) {
33+
return newConnect(pool, client, cb);
34+
}
35+
return oldConnect(pool, client, cb);
36+
});
37+
};
38+
return pool;
39+
}
40+
41+
//the old connect method of the pool
42+
//would automatically subscribe to the 'drain'
43+
//event and automatically return the client to
44+
//the pool once 'drain' fired once. This caused
45+
//a bunch of problems, but for backwards compatibility
46+
//we're leaving it in
47+
var alarmDuration = 1000;
48+
var errorMessage = ['A client has been checked out from the pool for longer than ' + alarmDuration + ' ms.',
49+
'You might have a leak!',
50+
'You should use the following new way to check out clients','pg.connect(function(err, client, done)) {',
51+
' //do something',
52+
' done(); //call done() to signal you are finished with the client',
53+
'}'].join(require('os').EOL);
54+
var oldConnect = function(pool, client, cb) {
55+
var tid = setTimeout(function() {
56+
console.error(errorMessage);
57+
}, alarmDuration);
58+
var release = function() {
59+
clearTimeout(tid);
60+
pool.release(client);
61+
};
62+
client.once('drain', release);
63+
cb(null, client);
64+
};
65+
66+
var newConnect = function(pool, client, cb) {
67+
cb(null, client, function() {
68+
pool.release(client);
69+
});
70+
};
71+
72+
//list of all created pools
73+
createPool.all = {};
74+
75+
//reference to client constructor
76+
createPool.Client = require(__dirname + '/client');
77+
78+
module.exports = createPool;

test/unit/pool/basic-tests.js

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
var util = require('util');
2+
var EventEmitter = require('events').EventEmitter;
3+
4+
var libDir = __dirname + '/../../../lib';
5+
var defaults = require(libDir + '/defaults');
6+
var pool = require(libDir + '/pool');
7+
var poolId = 0;
8+
9+
require(__dirname + '/../../test-helper');
10+
11+
var FakeClient = function() {
12+
EventEmitter.call(this);
13+
}
14+
15+
util.inherits(FakeClient, EventEmitter);
16+
17+
FakeClient.prototype.connect = function(cb) {
18+
process.nextTick(cb);
19+
}
20+
21+
FakeClient.prototype.end = function() {
22+
23+
}
24+
25+
//Hangs the event loop until 'end' is called on client
26+
var HangingClient = function(config) {
27+
EventEmitter.call(this);
28+
this.config = config;
29+
}
30+
31+
util.inherits(HangingClient, EventEmitter);
32+
33+
HangingClient.prototype.connect = function(cb) {
34+
this.intervalId = setInterval(function() {
35+
console.log('hung client...');
36+
}, 1000);
37+
process.nextTick(cb);
38+
}
39+
40+
HangingClient.prototype.end = function() {
41+
clearInterval(this.intervalId);
42+
}
43+
44+
pool.Client = FakeClient;
45+
46+
test('no pools exist', function() {
47+
assert.empty(Object.keys(pool.all));
48+
});
49+
50+
test('pool creates pool on miss', function() {
51+
var p = pool();
52+
assert.ok(p);
53+
assert.equal(Object.keys(pool.all).length, 1);
54+
var p2 = pool();
55+
assert.equal(p, p2);
56+
assert.equal(Object.keys(pool.all).length, 1);
57+
var p3 = pool("pg://postgres:password@localhost:5432/postgres");
58+
assert.notEqual(p, p3);
59+
assert.equal(Object.keys(pool.all).length, 2);
60+
});
61+
62+
test('pool follows default limits', function() {
63+
var p = pool(poolId++);
64+
for(var i = 0; i < 100; i++) {
65+
p.acquire(function(err, client) {
66+
});
67+
}
68+
assert.equal(p.getPoolSize(), defaults.poolSize);
69+
});
70+
71+
test('pool#connect with 2 parameters (legacy, for backwards compat)', function() {
72+
var p = pool(poolId++);
73+
p.connect(assert.success(function(client) {
74+
assert.ok(client);
75+
assert.equal(p.availableObjectsCount(), 0);
76+
assert.equal(p.getPoolSize(), 1);
77+
client.emit('drain');
78+
assert.equal(p.availableObjectsCount(), 1);
79+
assert.equal(p.getPoolSize(), 1);
80+
p.destroyAllNow();
81+
}));
82+
});
83+
84+
test('pool#connect with 3 parameters', function() {
85+
var p = pool(poolId++);
86+
var tid = setTimeout(function() {
87+
throw new Error("Connection callback was never called");
88+
}, 100);
89+
p.connect(function(err, client, done) {
90+
clearTimeout(tid);
91+
assert.equal(err, null);
92+
assert.ok(client);
93+
assert.equal(p.availableObjectsCount(), 0);
94+
assert.equal(p.getPoolSize(), 1);
95+
client.emit('drain');
96+
assert.equal(p.availableObjectsCount(), 0);
97+
assert.equal(p.getPoolSize(), 1);
98+
done();
99+
assert.equal(p.availableObjectsCount(), 1);
100+
assert.equal(p.getPoolSize(), 1);
101+
p.destroyAllNow();
102+
});
103+
});

0 commit comments

Comments
 (0)