Latest Code

This commit is contained in:
Dobie Wollert
2015-04-06 03:28:20 -04:00
parent 966152a631
commit d3089dcd17
105 changed files with 8731 additions and 96 deletions

22
node_modules/strong-store-cluster/lib/collection.js generated vendored Normal file
View File

@ -0,0 +1,22 @@
module.exports = collection;
var hasOwnProperty = Object.prototype.hasOwnProperty;
var cluster = require('cluster');
if (cluster.isMaster)
var Collection = require('./master/Collection.js');
else
var Collection = require('./worker/Collection.js');
var collections = {};
function collection(name) {
if (!hasOwnProperty.call(collections, name))
return collections[name] = new Collection(name);
else
return collections[name];
}

8
node_modules/strong-store-cluster/lib/lib.js generated vendored Normal file
View File

@ -0,0 +1,8 @@
var cluster = require('cluster'),
collection = require('./collection.js');
exports.collection = collection;
if (cluster.isMaster)
require('./master/setup.js');

107
node_modules/strong-store-cluster/lib/master/Client.js generated vendored Normal file
View File

@ -0,0 +1,107 @@
module.exports = Client;
var collection = require('../collection.js');
function Client(worker) {
this._worker = worker;
this._id = worker.id;
this._locks = {};
this._onMessage = this.onMessage.bind(this);
worker.on('message', this._onMessage);
}
Client.prototype.onMessage = function(msg) {
if (msg.type === 'DSM_REQUEST')
this[msg.method](msg);
};
Client.prototype.get = function(msg) {
var self = this,
entry = collection(msg.collection)._entry(msg.key);
entry.get(this._id, function(err, json) {
if (err) self._sendError(msg, err);
else self._sendReply(msg, { json: json });
});
};
Client.prototype.set = function(msg) {
var self = this,
entry = collection(msg.collection)._entry(msg.key);
entry.set(msg.json, this._id, function(err) {
if (err) self._sendError(msg, err);
else self._sendReply(msg);
});
};
Client.prototype.acquire = function(msg) {
var self = this,
entry = collection(msg.collection)._entry(msg.key);
entry.acquire(this._id, function(err, json) {
if (err) self._sendError(msg, err);
else self._sendReply(msg, { json: json });
});
};
Client.prototype.release = function(msg) {
var self = this,
entry = collection(msg.collection)._entry(msg.key);
entry.release(this._id, function(err, json) {
if (err) self._sendError(msg, err);
else self._sendReply(msg);
});
};
Client.prototype.setRelease = function(msg) {
var self = this,
entry = collection(msg.collection)._entry(msg.key);
entry.setRelease(msg.json, this._id, function(err) {
if (err) self._sendError(msg, err);
else self._sendReply(msg);
});
};
Client.prototype.configure = function(msg) {
var coll = collection(msg.collection),
err = undefined;
try {
coll._applyConfig(msg.config);
this._sendReply(msg);
} catch (err) {
this._sendError(msg, err);
}
};
// This function clobbers the data argument if specified!
Client.prototype._sendReply = function(msg, data) {
if (!msg.requestId)
return;
data = data || {};
data.type = 'DSM_REPLY';
data.requestId = msg.requestId;
data.err = undefined;
this._worker.send(data);
};
Client.prototype._sendError = function(msg, err) {
if (!msg.requestId)
return;
var data = {};
data.type = 'DSM_REPLY';
data.requestId = msg.requestId;
data.err = err;
this._worker.send(data);
};

View File

@ -0,0 +1,153 @@
module.exports = Collection;
var hasOwnProperty = Object.prototype.hasOwnProperty;
var assert = require('assert'),
inherits = require('util').inherits,
EventEmitter = require('events').EventEmitter;
var Entry = require('./Entry.js'),
KeyLock = require('./KeyLock.js');
function Collection(name) {
this._name = name;
this._entries = {};
this._count = 0;
this._expireKeys = null;
this._expireKeysTimer = null;
this._sweep = this._sweep.bind(this);
}
inherits(Collection, EventEmitter);
Collection.prototype._entry = function(key) {
if (!hasOwnProperty.call(this._entries, key)) {
if (!this._count++ && this._expireKeys)
this._startExpireKeysTimer();
return this._entries[key] = new Entry(this, key);
} else {
return this._entries[key];
}
};
Collection.prototype._remove = function(key) {
assert(hasOwnProperty.call(this._entries, key));
delete this._entries[key];
if (!--this._count && this.expireKeys)
this._stopExpireKeysTimer();
};
Collection.prototype.get = function(key, cb) {
this._entry(key).get(-1, function(err, json) {
if (err)
cb(err);
else if (!json)
cb(null, undefined);
else
cb(null, JSON.parse(json));
});
};
Collection.prototype.set = function(key, value, cb) {
cb = cb || noop;
this._entry(key).set(JSON.stringify(value), -1, cb);
};
Collection.prototype.del = function(key, cb) {
cb = cb || noop;
this._entry(key).set(undefined, -1, cb);
};
Collection.prototype.acquire = function(key, cb) {
var self = this,
entry = this._entry(key);
entry.acquire(-1, function(err, json) {
var lock = new KeyLock(entry, json);
return cb(null, lock, lock.get());
});
};
Collection.prototype._applyConfig = function(config) {
config = config || {};
for (var key in config) {
if (!hasOwnProperty.call(config, key))
continue;
switch (key) {
case 'expireKeys':
if (config.expireKeys === this._expireKeys)
break;
this._stopExpireKeysTimer();
this._expireKeys = config.expireKeys;
this._startExpireKeysTimer();
break;
default:
throw new Error('Unspported configuration option: ' + key);
}
}
};
Collection.prototype._startExpireKeysTimer = function() {
assert(!this._expireKeysTimer);
if (!this._expireKeys || !this._count)
return;
var interval = Math.ceil(this._expireKeys * 1000 / 2);
this._expireKeysTimer = setInterval(this._sweep, interval);
this._expireKeysTimer.unref();
};
Collection.prototype._stopExpireKeysTimer = function() {
if (!this._expireKeysTimer)
return;
clearInterval(this._expireKeysTimer);
this._expireKeysTimer = null;
};
Collection.prototype._sweep = function() {
var entries = this._entries,
key;
for (key in entries) {
if (!hasOwnProperty.call(entries, key))
continue;
if (entries[key].age(1) > 2)
this._remove(key);
}
if (!this._count)
this._stopExpireKeysTimer();
};
Collection.prototype.configure = function(config) {
var self = this;
try {
this._applyConfig(config);
} catch (err) {
process.nextTick(function() {
self.emit('error', err);
});
}
return this;
};
function noop() {
}

103
node_modules/strong-store-cluster/lib/master/Entry.js generated vendored Normal file
View File

@ -0,0 +1,103 @@
module.exports = Entry;
var assert = require('assert');
function Entry(collection, key) {
this._collection = collection;
this._key = key;
this._value = undefined;
this._queue = [];
this._age = 0;
}
Entry.prototype.get = function(requestor, cb) {
var self = this;
if (!this._queue.length) {
var value = self._value;
self._age = 0;
process.nextTick(function() {
cb(null, value);
});
} else {
this.acquire(requestor, function(err) {
self.release(requestor, noop);
cb(null, self._value);
});
}
};
Entry.prototype.set = function(newValue, requestor, cb) {
var self = this;
if (!this._queue.length) {
this._value = newValue;
this._age = 0;
if (newValue === undefined)
this._collection._remove(this._key);
process.nextTick(cb);
} else {
this.acquire(requestor, function() {
self._value = newValue;
if (newValue !== undefined)
self.release(requestor, cb);
else {
self._collection._remove(self._key);
cb();
}
});
}
};
Entry.prototype.acquire = function(requestor, cb) {
var self = this;
this._queue.push([cb, requestor]);
if (this._queue.length === 1) {
process.nextTick(function() {
cb(null, self._value);
});
}
};
Entry.prototype.release = function(requestor, cb) {
var self = this,
queue = this._queue;
setImmediate(function() {
assert.strictEqual(requestor, queue.shift()[1]);
self._age = 0;
cb();
if (queue.length)
queue[0][0](null, self._value);
});
};
Entry.prototype.setRelease = function(newValue, requestor, cb) {
this._value = newValue;
this.release(requestor, cb);
};
Entry.prototype.age = function(d) {
if (this._queue.length)
return this._age = 0;
else
return this._age += (d || 0);
};
function noop() {
}

View File

@ -0,0 +1,51 @@
module.exports = KeyLock;
function KeyLock(entry, json) {
this._entry = entry;
this._json = json;
this._updated = false;
this._released = false;
}
KeyLock.prototype.get = function() {
if (!this._json)
return undefined;
else
return JSON.parse(this._json);
};
KeyLock.prototype.set = function(newValue) {
if (this._released)
throw new Error("Can't set after releasing a lock.");
this._json = JSON.stringify(newValue);
this._updated = true;
};
KeyLock.prototype.del = function() {
if (this._released)
throw new Error("Can't delete after releasing a lock.");
this._json = undefined;
this._updated = true;
};
KeyLock.prototype.release = function(cb) {
if (this._released)
throw new Error('KeyLock has already been released.');
cb = cb || noop;
this._released = true;
if (!this._updated)
this._entry.release(-1, cb);
else
this._entry.setRelease(this._json, -1, cb);
};
function noop() {
}

10
node_modules/strong-store-cluster/lib/master/setup.js generated vendored Normal file
View File

@ -0,0 +1,10 @@
var cluster = require('cluster'),
Client = require('./Client.js');
for (var i = 0; i < cluster.workers.length; i++)
new Client(cluster.workers[i]);
cluster.on('online', function(worker) {
new Client(worker);
});

View File

@ -0,0 +1,68 @@
module.exports = Collection;
var inherits = require('util').inherits,
EventEmitter = require('events').EventEmitter,
KeyLock = require('./KeyLock.js'),
request = require('./request.js');
function Collection(name) {
this._name = name;
}
inherits(Collection, EventEmitter);
Collection.prototype.get = function(key, cb) {
this._request('get', key, null, function(err, msg) {
if (err)
return cb(err);
else if (!msg.json)
return cb(null, undefined);
else
return cb(null, JSON.parse(msg.json));
});
};
Collection.prototype.set = function(key, value, cb) {
var data = { json: JSON.stringify(value) };
this._request('set', key, data, cb && function(err, msg) {
return cb(err);
});
};
Collection.prototype.del = function(key, cb) {
return this._request('set', key, null, cb && function(err, msg) {
return cb(err);
});
};
Collection.prototype.acquire = function(key, cb) {
var self = this;
this._request('acquire', key, null, function(err, msg) {
if (err)
return cb(err);
var json = msg.json;
var lock = new KeyLock(self, key, json);
cb(null, lock, lock.get());
});
};
Collection.prototype.configure = function(config) {
var self = this;
this._request('configure', null, { config: config }, function(err, msg) {
if (err)
self.emit('error', err);
});
return this;
};
// This function clobbers `data` if specified
Collection.prototype._request = function(method, key, data, cb) {
request(method, this._name, key, data, cb);
};

View File

@ -0,0 +1,56 @@
module.exports = KeyLock;
var request = require('./request.js');
function KeyLock(collection, key, json) {
this._collection = collection;
this._key = key;
this._json = json;
this._updated = false;
this._released = false;
}
KeyLock.prototype.get = function() {
if (!this._json)
return undefined;
else
return JSON.parse(this._json);
};
KeyLock.prototype.set = function(newValue) {
if (this._released)
throw new Error("Can't set after releasing a lock.");
this._json = JSON.stringify(newValue);
this._updated = true;
};
KeyLock.prototype.del = function() {
if (this._released)
throw new Error("Can't delete after releasing a lock.");
this._json = undefined;
this._updated = true;
};
KeyLock.prototype.release = function(cb) {
if (this._released)
throw new Error('KeyLock has already been released.');
this._released = true;
if (!this._updated)
this._collection._request('release', this._key, null, cb && afterRelease);
else
this._collection._request('setRelease',
this._key,
{ json: this._json },
cb && afterRelease);
function afterRelease(err, msg) {
return cb(err);
}
};

View File

@ -0,0 +1,51 @@
module.exports = request;
process.on('message', onMessage);
var requestIdCounter = 0;
var requestCallbacks = {};
// This function clobbers `data` if specified
function request(method, collection, key, data, cb) {
data = data || {};
data.type = 'DSM_REQUEST';
data.method = method;
data.collection = collection;
data.key = key;
if (cb) {
var requestId = getRequestId();
requestCallbacks[requestId] = cb;
data.requestId = requestId;
}
process.send(data);
}
function onMessage(msg) {
if (msg.type !== 'DSM_REPLY')
return;
var requestId = msg.requestId;
var cb = requestCallbacks[requestId];
delete requestCallbacks[requestId];
if (msg.err) {
var err = new Error('Master error: ' + msg.err);
return cb(err);
}
cb(null, msg);
}
function getRequestId() {
return ++requestIdCounter;
}