Pool object for use in connection pooling

This commit is contained in:
Brian Carlson 2010-12-09 18:10:42 -06:00
parent f0a04a7e79
commit 169c6dc3ce
3 changed files with 131 additions and 3 deletions

View File

@ -9,3 +9,58 @@ if(typeof events.EventEmitter.prototype.once !== 'function') {
});
};
}
var Pool = function(maxSize, createFn) {
this.maxSize = maxSize;
this.createFn = createFn;
this.items = [];
this.waits = [];
}
var p = Pool.prototype;
p.checkOut = function(callback) {
var len = 0;
for(var i = 0, len = this.items.length; i < len; i++) {
var item = this.items[i];
if(item.checkedIn) {
return this._pulse(item, callback);
}
}
//check if we can create a new item
if(len < this.maxSize && this.createFn) {
var item = {ref: this.createFn()}
this.items.push(item);
return this._pulse(item, callback)
}
this.waits.push(callback);
return false; //did not execute sync
}
p.checkIn = function(item) {
//scan current items
for(var i = 0, len = this.items.length; i < len; i++) {
var currentItem = this.items[i];
if(currentItem.ref == item) {
currentItem.checkedIn = true;
return this._pulse(currentItem);
}
}
//add new item
var newItem = {ref: item, checkedIn: true};
this.items.push(newItem);
return this._pulse(newItem);
}
p._pulse = function(item, cb) {
cb = cb || this.waits.pop()
if(cb) {
item.checkedIn = false;
cb(null, item.ref)
return true;
}
return false;
}
module.exports = {
Pool: Pool
}

View File

@ -85,7 +85,7 @@ assert.length = function(actual, expectedLength) {
var expect = function(callback) {
var executed = false;
var id = setTimeout(function() {
assert.ok(executed, "Expected execution never fired");
assert.ok(executed, "Expected execution of " + callback + " fired");
}, 1000)
return function(err, queryResult) {

View File

@ -1,4 +1,5 @@
require(__dirname + '/test-helper');
var Pool = require("utils").Pool;
//this tests the monkey patching
//to ensure comptability with older
@ -17,3 +18,75 @@ test("EventEmitter.once", function() {
stream.emit('single');
assert.equal(callCount, 1);
});
test('an empty pool', function() {
test('with no creation method', function() {
var pool = new Pool(10);
var brian = {name:'brian'};
test('can set and get an item', function() {
pool.checkIn(brian);
var sync = pool.checkOut(assert.calls(function(err, item) {
assert.equal(brian, item)
assert.same(brian, item)
}))
assert.ok(sync, "should have fired sync")
})
test('checkout blocks until item checked back in', function() {
var called = false;
var sync = pool.checkOut(assert.calls(function(err, item) {
called = true;
assert.equal(brian, item)
assert.same(brian, item)
}))
assert.ok(sync === false, "Should not have fired sync")
assert.ok(called === false, "Should not have fired callback yet")
pool.checkIn(brian)
})
})
test('with a creation method', function() {
var customName = "first";
var callCount = 0;
var pool = new Pool(3, function() {
return {name: customName + (++callCount)};
});
test('creates if pool is not at max size', function() {
var sync = pool.checkOut(assert.calls(function(err, item) {
assert.equal(item.name, "first1");
}))
assert.ok(sync, "Should have generated item & called callback in sync")
})
test('creates again if item is checked out', function() {
var sync = pool.checkOut(assert.calls(function(err, item) {
assert.equal(item.name, "first2")
}))
assert.ok(sync, "Should have called in sync again")
})
var external = {name: 'boom'};
test('can add another item', function() {
pool.checkIn(external)
var sync = pool.checkOut(assert.calls(function(err, item) {
assert.equal(item.name, 'boom')
}))
assert.ok(sync, "Should have fired 3rd in sync")
})
test('after pool is full, create is not called again', function() {
var called = false;
var sync = pool.checkOut(assert.calls(function(err, item) {
called = true;
assert.equal(item.name, 'boom')
}))
assert.ok(sync === false, "should not be sync")
assert.ok(called === false, "should not have called callback")
pool.checkIn(external);
})
})
})