Permalink
Browse files

initial commit

  • Loading branch information...
coopernurse committed Oct 2, 2010
0 parents commit 5fbfb910a3e896cfdee44b2cc71f56736ef95681
Showing with 238 additions and 0 deletions.
  1. +2 −0 .gitignore
  2. +61 −0 README.md
  3. +27 −0 fabfile.py
  4. +98 −0 lib/pool.js
  5. +16 −0 package.json
  6. +34 −0 test/pool.test.js
@@ -0,0 +1,2 @@
+fabfile.pyc
+node-pool.iml
@@ -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
+
+
@@ -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)
+
@@ -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;
+};
@@ -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" }
+}
@@ -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.