Skip to content

Commit b3e56af

Browse files
committed
initial working connection pool implementation & tests
1 parent 618c268 commit b3e56af

File tree

8 files changed

+116
-91
lines changed

8 files changed

+116
-91
lines changed

lib/index.js

Lines changed: 64 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,36 @@ var net = require('net');
44
var Pool = require(__dirname + '/utils').Pool;
55
var Client = require(__dirname+'/client');
66
var defaults = require(__dirname + '/defaults');
7+
8+
//wrap up common connection management boilerplate
9+
var connect = function(config, callback) {
10+
if(poolEnabled()) {
11+
return getPooledClient(config, callback)
12+
}
13+
throw new Error("Should be testing pools")
14+
var client = new Client(config);
15+
client.connect();
16+
17+
var onError = function(error) {
18+
client.connection.removeListener('readyForQuery', onReady);
19+
callback(error);
20+
}
21+
22+
var onReady = function() {
23+
client.removeListener('error', onError);
24+
callback(null, client);
25+
client.on('drain', client.end.bind(client));
26+
}
27+
28+
client.once('error', onError);
29+
30+
//TODO refactor
31+
//i don't like reaching into the client's connection for attaching
32+
//to specific events here
33+
client.connection.once('readyForQuery', onReady);
34+
}
35+
36+
737
//connection pool global cache
838
var clientPools = {
939
}
@@ -13,12 +43,13 @@ var poolEnabled = function() {
1343
}
1444

1545
var log = function() {
16-
46+
//do nothing
1747
}
1848

19-
var log = function() {
20-
console.log.apply(console, arguments);
21-
}
49+
//for testing
50+
// var log = function() {
51+
// console.log.apply(console, arguments);
52+
// }
2253

2354
var getPooledClient = function(config, callback) {
2455
//lookup pool using config as key
@@ -35,8 +66,9 @@ var getPooledClient = function(config, callback) {
3566
return client;
3667
})
3768
}
38-
69+
3970
pool.checkOut(function(err, client) {
71+
4072
//if client already connected just
4173
//pass it along to the callback and return
4274
if(client.connected) {
@@ -72,56 +104,36 @@ var getPooledClient = function(config, callback) {
72104
}
73105

74106
//destroys the world
75-
var end = function(callback) {
76-
for(var name in clientPools) {
77-
var pool = clientPools[name];
78-
log("destroying pool %s", name);
79-
pool.waits.forEach(function(wait) {
80-
wait(new Error("Client is being destroyed"))
81-
})
82-
pool.waits = [];
83-
pool.items.forEach(function(item) {
84-
var client = item.ref;
85-
if(client.activeQuery) {
86-
log("client is still active, waiting for it to complete");
87-
client.on('drain', client.end.bind(client))
88-
} else {
89-
client.end();
90-
}
91-
})
92-
//remove reference to pool lookup
93-
clientPools[name] = null;
94-
delete(clientPools[name])
107+
//or optionally only a single pool
108+
//mostly used for testing or
109+
//a hard shutdown
110+
var end = function(name) {
111+
if(!name) {
112+
for(var poolName in clientPools) {
113+
end(poolName)
114+
return
115+
}
95116
}
117+
var pool = clientPools[name];
118+
log("destroying pool %s", name);
119+
pool.waits.forEach(function(wait) {
120+
wait(new Error("Client is being destroyed"))
121+
})
122+
pool.waits = [];
123+
pool.items.forEach(function(item) {
124+
var client = item.ref;
125+
if(client.activeQuery) {
126+
log("client is still active, waiting for it to complete");
127+
client.on('drain', client.end.bind(client))
128+
} else {
129+
client.end();
130+
}
131+
})
132+
//remove reference to pool lookup
133+
clientPools[name] = null;
134+
delete(clientPools[name])
96135
}
97136

98-
//wrap up common connection management boilerplate
99-
var connect = function(config, callback) {
100-
// if(poolEnabled()) {
101-
// return getPooledClient(config, callback)
102-
// }
103-
104-
var client = new Client(config);
105-
client.connect();
106-
107-
var onError = function(error) {
108-
client.connection.removeListener('readyForQuery', onReady);
109-
callback(error);
110-
}
111-
112-
var onReady = function() {
113-
client.removeListener('error', onError);
114-
callback(null, client);
115-
client.on('drain', client.end.bind(client));
116-
}
117-
118-
client.once('error', onError);
119-
120-
//TODO refactor
121-
//i don't like reaching into the client's connection for attaching
122-
//to specific events here
123-
client.connection.once('readyForQuery', onReady);
124-
}
125137

126138
module.exports = {
127139
Client: Client,

test/integration/client/api-tests.js

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,15 @@
11
var helper = require(__dirname + '/../test-helper');
22
var pg = require(__dirname + '/../../../lib');
3+
var connectionString = helper.connectionString(__filename);
4+
5+
6+
var sink = new helper.Sink(2, function() {
7+
pg.end(connectionString);
8+
});
39

410
test('api', function() {
5-
pg.connect(helper.args, assert.calls(function(err, client) {
6-
assert.equal(err, null, "Failed to connect");
11+
pg.connect(connectionString, assert.calls(function(err, client) {
12+
assert.equal(err, null, "Failed to connect: " + sys.inspect(err));
713

814
client.query('CREATE TEMP TABLE band(name varchar(100))');
915

@@ -30,19 +36,22 @@ test('api', function() {
3036
assert.length(result.rows, 2);
3137
assert.equal(result.rows.pop().name, 'the flaming lips');
3238
assert.equal(result.rows.pop().name, 'the beach boys');
39+
sink.add();
3340
}))
3441
}))
3542

3643
}))
3744
})
3845

3946
test('executing nested queries', function() {
40-
pg.connect(helper.args, assert.calls(function(err, client) {
47+
pg.connect(connectionString, assert.calls(function(err, client) {
48+
assert.isNull(err);
4149
client.query('select now as now from NOW()', assert.calls(function(err, result) {
4250
assert.equal(new Date().getYear(), result.rows[0].now.getYear())
4351
client.query('select now as now_again FROM NOW()', assert.calls(function() {
4452
client.query('select * FROM NOW()', assert.calls(function() {
4553
assert.ok('all queries hit')
54+
sink.add();
4655
}))
4756
}))
4857
}))
@@ -55,5 +64,3 @@ test('raises error if cannot connect', function() {
5564
assert.ok(err, 'should have raised an error')
5665
}))
5766
})
58-
59-
pg.end();

test/integration/client/test-helper.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,7 @@ module.exports = {
1212
});
1313
client.connect();
1414
return client;
15-
}
15+
},
16+
connectionString: helper.connectionString,
17+
Sink: helper.Sink
1618
};
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
var helper = require(__dirname + "/test-helper")
2+
helper.testPoolSize(2);
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
var helper = require(__dirname + "/test-helper")
2+
helper.testPoolSize(10);
3+
helper.testPoolSize(11);
Lines changed: 1 addition & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,2 @@
11
var helper = require(__dirname + "/test-helper")
2-
3-
setTimeout(function() {
4-
helper.pg.defaults.poolSize = 10;
5-
test('executes a single pooled connection/query', function() {
6-
var args = helper.args;
7-
var conString = "pg://"+args.user+":"+args.password+"@"+args.host+":"+args.port+"/"+args.database;
8-
var queryCount = 0;
9-
helper.pg.connect(conString, assert.calls(function(err, client) {
10-
assert.isNull(err);
11-
client.query("select * from NOW()", assert.calls(function(err, result) {
12-
assert.isNull(err);
13-
queryCount++;
14-
}))
15-
}))
16-
var id = setTimeout(function() {
17-
assert.equal(queryCount, 1)
18-
}, 1000)
19-
var check = function() {
20-
setTimeout(function() {
21-
if(queryCount == 1) {
22-
clearTimeout(id)
23-
helper.pg.end();
24-
} else {
25-
check();
26-
}
27-
}, 50)
28-
}
29-
check();
30-
})
31-
}, 1000)
32-
2+
helper.testPoolSize(1);
Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,31 @@
1+
var helper = require(__dirname + "/../test-helper");
2+
var pg = require(__dirname + "/../../../lib");
3+
helper.pg = pg;
4+
5+
var testPoolSize = function(max) {
6+
var conString = helper.connectionString();
7+
var sink = new helper.Sink(max, function() {
8+
helper.pg.end(conString);
9+
});
10+
11+
test("can pool " + max + " times", function() {
12+
for(var i = 0; i < max; i++) {
13+
helper.pg.poolSize = 10;
14+
helper.pg.connect(conString, function(err, client) {
15+
assert.isNull(err);
16+
client.query("select * from NOW()", function() {
17+
sink.add();
18+
})
19+
})
20+
}
21+
})
22+
}
23+
124
module.exports = {
2-
args: require(__dirname + "/../test-helper").args,
3-
pg: require(__dirname + "/../../../lib")
25+
args: helper.args,
26+
pg: helper.pg,
27+
connectionString: helper.connectionString,
28+
Sink: helper.Sink,
29+
testPoolSize: testPoolSize
430
}
31+
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
var helper = require(__dirname + "/test-helper")
2+
helper.testPoolSize(200);

0 commit comments

Comments
 (0)