Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
coopernurse committed Oct 2, 2010
0 parents commit 5fbfb91
Show file tree
Hide file tree
Showing 6 changed files with 238 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .gitignore
@@ -0,0 +1,2 @@
fabfile.pyc
node-pool.iml
61 changes: 61 additions & 0 deletions README.md
@@ -0,0 +1,61 @@

# About

Generic resource pool. Can be used to reuse or throttle expensive resources such as
database connections.

## Installation

$ npm install pool

## Example

// Create a MySQL connection pool with
// a max of 10 connections and a 30 second max idle time
var poolModule = require('pool');
var pool = poolModule.Pool({
name : 'mysql',
create : function(callback) {
var Client = require('mysql').Client;
var c = new Client();
c.user = 'scott';
c.password = 'tiger';
c.database = 'mydb';
c.connect();
callback(c);
},
destroy : function(client) { client.end(); },
max : 10,
idleTimeoutMillis : 30000
});

// borrow connection - callback function is called
// once a resource becomes available
pool.borrow(function(client) {
client.query("select * from foo", [], function() {
// return object back to pool
pool.returnToPool(client);
});
});


## Documentation

// Pool() accepts 3 parameters:
//
// (a) factory object with 3 slots:
// name: string name
// create: function that returns a new resource
// should call callback() with the created resource
// destroy: function that accepts a resource and destroys it
//
// (b) max items to create in pool
// (c) idle timeout (milliseconds)
//

## Run Tests

$ npm install expresso
$ expresso -I lib test/*.js


27 changes: 27 additions & 0 deletions fabfile.py
@@ -0,0 +1,27 @@
#
# dependencies:
# fabric (apt-get install fabric)
# node-jslint (http://github.com/reid/node-jslint)
# expresso (or replace with whatever node.js test tool you're using)
#

from fabric.api import local
import os, os.path

def test():
local('expresso -I lib test/*', capture=False)

def jslint():
ignore = [ "/lib-cov/" ]
for root, subFolders, files in os.walk("."):
for file in files:
if file.endswith(".js"):
filename = os.path.join(root,file)
processFile = True
for i in ignore:
if filename.find(i) != -1:
processFile = False
if processFile:
print filename
local('jslint %s' % filename, capture=False)

98 changes: 98 additions & 0 deletions lib/pool.js
@@ -0,0 +1,98 @@

exports.Pool = function(factory) {
var self = {};

var idleTimeoutMillis = factory.idleTimeoutMillis || 30000;
var reapInterval = factory.reapInterval || 1000;

var availableObjects = [];
var objectTimeout = {};
var waitingClients = [];
var obj;
var count = 0;
var removeIdleScheduled = false;

function log(str) {
//console.log("pool " + factory.name + " - " + str);
}

function removeIdle() {
removeIdleScheduled = false;

var toKeep = [];
var now = new Date().getTime();
for (var i = 0; i < availableObjects.length; i++) {
var timeout = objectTimeout[availableObjects[i]];
if (now < timeout) {
toKeep.push(availableObjects[i]);
}
else {
log("removeIdle() destroying obj - now:" + now + " timeout:" + timeout);
self.destroy(availableObjects[i]);
}
}

availableObjects = toKeep;

if (availableObjects.length > 0) {
log("availableObjects.length=" + availableObjects.length);
scheduleRemoveIdle();
}
else {
log("removeIdle() all objects removed");
}
}

function scheduleRemoveIdle() {
if (!removeIdleScheduled) {
removeIdleScheduled = true;
setTimeout(removeIdle, reapInterval);
}
}

function dispense() {
log("dispense() clients=" + waitingClients.length + " available=" + availableObjects.length);
if (waitingClients.length > 0) {
obj = null;
if (availableObjects.length > 0) {
log("dispense() - reusing obj");
obj = availableObjects.shift();
delete objectTimeout[obj];
waitingClients.shift()(obj);
}
else if (count < factory.max) {
log("dispense() - creating obj - count="+count);
factory.create(function(obj) {
count++;
if (waitingClients.length > 0) {
waitingClients.shift()(obj);
}
else {
self.returnToPool(obj);
}
});
}
}
}

self.borrow = function(callback) {
waitingClients.push(callback);
dispense();
};

self.destroy = function(obj) {
count--;
factory.destroy(obj);
};

self.returnToPool = function(obj) {
//log("return to pool");
availableObjects.push(obj);
objectTimeout[obj] = (new Date().getTime() + idleTimeoutMillis);
log("timeout: " + objectTimeout[obj]);
dispense();
scheduleRemoveIdle();
};

return self;
};
16 changes: 16 additions & 0 deletions package.json
@@ -0,0 +1,16 @@
{
"name": "pool",
"description": "Generic resource pooling for Node.JS",
"version": "1.0.0",
"author": "James Cooper <james@bitmechanic.com>",
"contributors": [
{ "name": "James Cooper", "email": "james@bitmechanic.com" }
],
"keywords": ["pool", "pooling", "throttle"],
"main": "lib/pool.js",
"repository": {
"type": "git",
"url": "http://github.com/coopernurse/node-pool.git"
},
"engines": { "node": ">= 0.2.0" }
}
34 changes: 34 additions & 0 deletions test/pool.test.js
@@ -0,0 +1,34 @@
var poolModule = require('pool');

module.exports = {

'expands to max limit' : function (assert, beforeExit) {
var createCount = 0;
var destroyCount = 0;

var pool = poolModule.Pool({
name : 'test1',
create : function(callback) {
createCount++;
callback(createCount);
},
destroy : function(client) { destroyCount++; },
max : 2,
idleTimeoutMillis : 100
});

for (var i = 0; i < 10; i++) {
pool.borrow(function(obj) {
setTimeout(function() {
pool.returnToPool(obj);
}, 100);
});
}

beforeExit(function() {
assert.equal(2, createCount);
assert.equal(2, destroyCount);
});
}

};

0 comments on commit 5fbfb91

Please sign in to comment.