Comparing version 0.1.0 to 0.1.1
@@ -7,3 +7,2 @@ "use strict"; | ||
exports.Manager = ConnectionManager; // connection pooling | ||
exports.IssueLog = IssueLog; // connection issue handling | ||
@@ -108,66 +107,1 @@ exports.Available = ping; // connection availablity | ||
}; | ||
function ConnectionManager (name, limit, constructor) { | ||
this.name = name; | ||
this.total = limit; | ||
this.factory = constructor; | ||
this.connections = []; | ||
} | ||
var Manager = ConnectionManager.prototype; | ||
Manager.allocate = function allocate (callback) { | ||
var total, i | ||
, Manager = this; | ||
i = total = this.connections.length; | ||
// check for available | ||
while (i--){ | ||
if (this.isAvailable(this.connections[i])) { | ||
return callback(false, this.connections[i]); | ||
} | ||
} | ||
// create new | ||
if (total < this.total) { | ||
return this.connections.push(this.factory.apply(this, arguments)); | ||
} | ||
// give up and don't saturate the node.js process by retying #43 | ||
var full = new Error("All the connections in the memcached pool are busy"); | ||
full.connectionPool = true; | ||
callback(full); | ||
}; | ||
Manager.isAvailable = function isAvailable (connection) { | ||
var readyState = connection.readyState; | ||
return (readyState === 'open' || readyState === 'writeOnly') | ||
&& !(connection._writeQueue && connection._writeQueue.length) | ||
&& !(connection._handle && connection._handle.writeQueueSize); | ||
}; | ||
Manager.remove = function remove (connection) { | ||
var position = this.connections.indexOf(connection); | ||
if (position !== -1) this.connections.splice(position, 1); | ||
if (connection.readyState && connection.readyState !== 'closed' && connection.end) { | ||
connection.end(); | ||
} | ||
}; | ||
Manager.free = function freemymemories (keep) { | ||
var save = 0 | ||
, connection; | ||
while (this.connections.length) { | ||
connection = this.connections.shift(); | ||
if (save < keep && this.isAvailable(this.connection[0])) { | ||
save++; | ||
continue; | ||
} | ||
this.remove(connection); | ||
} | ||
}; |
@@ -6,3 +6,2 @@ "use strict"; | ||
*/ | ||
var EventEmitter = require('events').EventEmitter | ||
@@ -15,7 +14,6 @@ , Stream = require('net').Stream | ||
*/ | ||
var HashRing = require('hashring') | ||
, Connection = require('./connection') | ||
, Jackpot = require('jackpot') | ||
, Utils = require('./utils') | ||
, Manager = Connection.Manager | ||
, IssueLog = Connection.IssueLog; | ||
@@ -26,3 +24,2 @@ | ||
*/ | ||
var curry = Utils.curry; | ||
@@ -38,3 +35,2 @@ | ||
*/ | ||
function Client (args, options) { | ||
@@ -79,17 +75,17 @@ var servers = [] | ||
Client.config = { | ||
maxKeySize: 251 // max key size allowed by Memcached | ||
, maxExpiration: 2592000 // max expiration duration allowed by Memcached | ||
, maxValue: 1048576 // max length of value allowed by Memcached | ||
maxKeySize: 251 // max key size allowed by Memcached | ||
, maxExpiration: 2592000 // max expiration duration allowed by Memcached | ||
, maxValue: 1048576 // max length of value allowed by Memcached | ||
, algorithm: 'crc32' // hashing algorithm that is used for key mapping | ||
, algorithm: 'crc32' // hashing algorithm that is used for key mapping | ||
, poolSize: 10 // maximal parallel connections | ||
, reconnect: 18000000 // if dead, attempt reconnect each xx ms | ||
, timeout: 5000 // after x ms the server should send a timeout if we can't connect | ||
, retries: 5 // amount of retries before server is dead | ||
, retry: 30000 // timeout between retries, all call will be marked as cache miss | ||
, remove: false // remove server if dead if false, we will attempt to reconnect | ||
, redundancy: false // allows you do re-distribute the keys over a x amount of servers | ||
, keyCompression: true // compress keys if they are to large (md5) | ||
, debug: false // Output the commands and responses | ||
, poolSize: 10 // maximal parallel connections | ||
, reconnect: 18000000 // if dead, attempt reconnect each xx ms | ||
, timeout: 5000 // after x ms the server should send a timeout if we can't connect | ||
, retries: 5 // amount of retries before server is dead | ||
, retry: 30000 // timeout between retries, all call will be marked as cache miss | ||
, remove: false // remove server if dead if false, we will attempt to reconnect | ||
, redundancy: false // allows you do re-distribute the keys over a x amount of servers | ||
, keyCompression: true // compress keys if they are to large (md5) | ||
, debug: false // Output the commands and responses | ||
}; | ||
@@ -114,3 +110,3 @@ | ||
// will receive the connection if the operation was successful | ||
memcached.connect = function connect (server, callback) { | ||
memcached.connect = function connect(server, callback) { | ||
// server is dead, bail out | ||
@@ -123,3 +119,3 @@ if (server in this.issues && this.issues[server].failed) { | ||
if (server in this.connections) { | ||
return this.connections[server].allocate(callback); | ||
return this.connections[server].pull(callback); | ||
} | ||
@@ -143,3 +139,4 @@ | ||
manager = new Manager(server, this.poolSize, function factory (callback) { | ||
manager = new Jackpot(this.poolSize); | ||
manager.factory(function factory() { | ||
var S = Array.isArray(serverTokens) | ||
@@ -164,13 +161,10 @@ ? new Stream | ||
Utils.fuse(S, { | ||
connect: function streamConnect () { | ||
callback(false, this); | ||
} | ||
, close: function streamClose () { | ||
close: function streamClose() { | ||
Manager.remove(this); | ||
} | ||
, error: function streamError (err) { | ||
, error: function streamError(err) { | ||
memcached.connectionIssue(err, S, callback); | ||
} | ||
, data: curry(memcached, privates.buffer, S) | ||
, timeout: function streamTimeout () { | ||
, timeout: function streamTimeout() { | ||
Manager.remove(this); | ||
@@ -190,3 +184,3 @@ } | ||
// connection | ||
this.connections[server].allocate(callback); | ||
this.connections[server].pull(callback); | ||
}; | ||
@@ -196,3 +190,3 @@ | ||
// servers. | ||
memcached.multi = function memcachedMulti (keys, callback) { | ||
memcached.multi = function memcachedMulti(keys, callback) { | ||
var map = {} | ||
@@ -206,3 +200,3 @@ , memcached = this | ||
if (keys) { | ||
keys.forEach(function fetchMultipleServers (key) { | ||
keys.forEach(function fetchMultipleServers(key) { | ||
var server = memcached.servers.length === 1 | ||
@@ -234,3 +228,3 @@ ? memcached.servers[0] | ||
// use the query.key to get the server from the HashRing | ||
memcached.command = function memcachedCommand (queryCompiler, server) { | ||
memcached.command = function memcachedCommand(queryCompiler, server) { | ||
// generate a regular query, | ||
@@ -266,5 +260,5 @@ var query = queryCompiler() | ||
this.connect(server, function allocateMemcachedConnection (error, S) { | ||
this.connect(server, function allocateMemcachedConnection(error, S) { | ||
if (memcached.debug) { | ||
query.command.split(LINEBREAK).forEach(function errors (line) { | ||
query.command.split(LINEBREAK).forEach(function errors(line) { | ||
console.log(S.streamID + ' << ' + line); | ||
@@ -297,6 +291,6 @@ }); | ||
redundancy.forEach(function each (server) { | ||
redundancy.forEach(function each(server) { | ||
if (server in memcached.issues && memcached.issues[server].failed) return; | ||
memcached.connect(server, function allocateMemcachedConnection (error, S) { | ||
memcached.connect(server, function allocateMemcachedConnection(error, S) { | ||
if (!S || error || S.readyState !== 'open') return; | ||
@@ -311,3 +305,3 @@ S.write(queryRedundancy.command + LINEBREAK); | ||
// cache misses. | ||
memcached.connectionIssue = function connectionIssue (error, S, callback) { | ||
memcached.connectionIssue = function connectionIssue(error, S, callback) { | ||
// end connection and mark callback as cache miss | ||
@@ -336,15 +330,15 @@ if (S && S.end) S.end(); | ||
Utils.fuse(issues, { | ||
issue: function issue (details) { | ||
issue: function issue(details) { | ||
memcached.emit('issue', details); | ||
} | ||
, failure: function failure (details) { | ||
, failure: function failure(details) { | ||
memcached.emit('failure', details); | ||
} | ||
, reconnecting: function reconnect (details) { | ||
, reconnecting: function reconnect(details) { | ||
memcached.emit('reconnecting', details); | ||
} | ||
, reconnected: function reconnected (details) { | ||
, reconnected: function reconnected(details) { | ||
memcached.emit('reconnect', details); | ||
} | ||
, remove: function remove (details) { | ||
, remove: function remove(details) { | ||
// emit event and remove servers | ||
@@ -368,6 +362,6 @@ memcached.emit('remove', details); | ||
// Kills all active connections | ||
memcached.end = function endMemcached () { | ||
memcached.end = function endMemcached() { | ||
var memcached = this; | ||
Object.keys(this.connections).forEach(function closeConnection (key) { | ||
Object.keys(this.connections).forEach(function closeConnection(key) { | ||
memcached.connections[key].free(0); | ||
@@ -381,17 +375,21 @@ }); | ||
// handle error responses | ||
'NOT_FOUND': function notfound (tokens, dataSet, err) { | ||
'NOT_FOUND': function notfound(tokens, dataSet, err) { | ||
return [CONTINUE, false]; | ||
} | ||
, 'NOT_STORED': function notstored (tokens, dataSet, err) { | ||
, 'NOT_STORED': function notstored(tokens, dataSet, err) { | ||
return [CONTINUE, false]; | ||
} | ||
, 'ERROR': function error (tokens, dataSet, err) { | ||
, 'ERROR': function error(tokens, dataSet, err) { | ||
err.push('Received an ERROR response'); | ||
return [FLUSH, false]; | ||
} | ||
, 'CLIENT_ERROR': function clienterror (tokens, dataSet, err) { | ||
, 'CLIENT_ERROR': function clienterror(tokens, dataSet, err) { | ||
err.push(tokens.splice(1).join(' ')); | ||
return [CONTINUE, false]; | ||
} | ||
, 'SERVER_ERROR': function servererror (tokens, dataSet, err, queue, S, memcached) { | ||
, 'SERVER_ERROR': function servererror(tokens, dataSet, err, queue, S, memcached) { | ||
(memcached || this.memcached).connectionIssue(tokens.splice(1).join(' '), S); | ||
@@ -402,15 +400,19 @@ return [CONTINUE, false]; | ||
// keyword based responses | ||
, 'STORED': function stored (tokens, dataSet) { | ||
, 'STORED': function stored(tokens, dataSet) { | ||
return [CONTINUE, true]; | ||
} | ||
, 'DELETED': function deleted (tokens, dataSet) { | ||
, 'DELETED': function deleted(tokens, dataSet) { | ||
return [CONTINUE, true]; | ||
} | ||
, 'OK': function ok (tokens, dataSet) { | ||
, 'OK': function ok(tokens, dataSet) { | ||
return [CONTINUE, true]; | ||
} | ||
, 'EXISTS': function exists (tokens, dataSet) { | ||
, 'EXISTS': function exists(tokens, dataSet) { | ||
return [CONTINUE, false]; | ||
} | ||
, 'END': function end (tokens, dataSet, err, queue) { | ||
, 'END': function end(tokens, dataSet, err, queue) { | ||
if (!queue.length) queue.push(false); | ||
@@ -421,3 +423,3 @@ return [FLUSH, true]; | ||
// value parsing: | ||
, 'VALUE': function value (tokens, dataSet, err, queue) { | ||
, 'VALUE': function value(tokens, dataSet, err, queue) { | ||
var key = tokens[1] | ||
@@ -458,10 +460,12 @@ , flag = +tokens[2] | ||
, 'INCRDECR': function incrdecr (tokens) { | ||
, 'INCRDECR': function incrdecr(tokens) { | ||
return [CONTINUE, +tokens[1]]; | ||
} | ||
, 'STAT': function stat (tokens, dataSet, err, queue) { | ||
, 'STAT': function stat(tokens, dataSet, err, queue) { | ||
queue.push([tokens[1], /^\d+$/.test(tokens[2]) ? +tokens[2] : tokens[2]]); | ||
return [BUFFER, true]; | ||
} | ||
, 'VERSION': function version (tokens, dataSet) { | ||
, 'VERSION': function version(tokens, dataSet) { | ||
var versionTokens = /(\d+)(?:\.)(\d+)(?:\.)(\d+)$/.exec(tokens.pop()); | ||
@@ -477,3 +481,4 @@ | ||
} | ||
, 'ITEM': function item (tokens, dataSet, err, queue) { | ||
, 'ITEM': function item(tokens, dataSet, err, queue) { | ||
queue.push({ | ||
@@ -489,3 +494,3 @@ key: tokens[1] | ||
function resultSetIsEmpty (resultSet) { | ||
function resultSetIsEmpty(resultSet) { | ||
return !resultSet || (resultSet.length === 1 && !resultSet[0]); | ||
@@ -496,3 +501,3 @@ } | ||
// combines the stats array, in to an object | ||
'stats': function stats (resultSet) { | ||
'stats': function stats(resultSet) { | ||
var response = {}; | ||
@@ -505,3 +510,3 @@ if (resultSetIsEmpty(resultSet)) return response; | ||
// Fill the object | ||
resultSet.forEach(function each (statSet) { | ||
resultSet.forEach(function each(statSet) { | ||
if (statSet) response[statSet[0]] = statSet[1]; | ||
@@ -514,7 +519,8 @@ }); | ||
// the settings uses the same parse format as the regular stats | ||
, 'stats settings': function settings () { | ||
, 'stats settings': function settings() { | ||
return privates.resultParsers.stats.apply(this, arguments); | ||
} | ||
// Group slabs by slab id | ||
, 'stats slabs': function slabs (resultSet) { | ||
, 'stats slabs': function slabs(resultSet) { | ||
var response = {}; | ||
@@ -527,3 +533,3 @@ if (resultSetIsEmpty(resultSet)) return response; | ||
// Fill the object | ||
resultSet.forEach(function each (statSet) { | ||
resultSet.forEach(function each(statSet) { | ||
if (statSet) { | ||
@@ -539,3 +545,4 @@ var identifier = statSet[0].split(':'); | ||
} | ||
, 'stats items': function items (resultSet) { | ||
, 'stats items': function items(resultSet) { | ||
var response = {}; | ||
@@ -548,3 +555,3 @@ if (resultSetIsEmpty(resultSet)) return response; | ||
// Fill the object | ||
resultSet.forEach(function each (statSet) { | ||
resultSet.forEach(function each(statSet) { | ||
if (statSet) { | ||
@@ -575,3 +582,3 @@ var identifier = statSet[0].split(':'); | ||
// all responds end with them. | ||
privates.buffer = function BufferBuffer (S, BufferStream) { | ||
privates.buffer = function BufferBuffer(S, BufferStream) { | ||
S.responseBuffer += BufferStream; | ||
@@ -585,3 +592,3 @@ | ||
if (this.debug) { | ||
chunks.forEach(function each (line) { | ||
chunks.forEach(function each(line) { | ||
console.log(S.streamID + ' >> ' + line); | ||
@@ -600,3 +607,3 @@ }); | ||
// format, deciding if we should queue it up, or send it to a callback fn. | ||
memcached.rawDataReceived = function rawDataReceived (S) { | ||
memcached.rawDataReceived = function rawDataReceived(S) { | ||
var queue = [] | ||
@@ -696,3 +703,3 @@ , token | ||
// Small wrapper function that only executes errors when we have a callback | ||
privates.errorResponse = function errorResponse (error, callback) { | ||
privates.errorResponse = function errorResponse(error, callback) { | ||
if (typeof callback === 'function') callback(error, false); | ||
@@ -707,3 +714,3 @@ | ||
this.command(function getCommand (noreply) { | ||
this.command(function getCommand(noreply) { | ||
return { | ||
@@ -741,3 +748,3 @@ key: key | ||
// handle multiple responses and cache them untill we receive all. | ||
function handle (err, results) { | ||
function handle(err, results) { | ||
if (err) { | ||
@@ -748,3 +755,3 @@ errors.push(err); | ||
// add all responses to the array | ||
(Array.isArray(results) ? results : [results]).forEach(function each (value) { | ||
(Array.isArray(results) ? results : [results]).forEach(function each(value) { | ||
Utils.merge(responses, value); | ||
@@ -756,6 +763,6 @@ }); | ||
this.multi(keys, function multi (server, key, index, totals) { | ||
this.multi(keys, function multi(server, key, index, totals) { | ||
if (!calls) calls = totals; | ||
memcached.command(function getMultiCommand (noreply) { | ||
memcached.command(function getMultiCommand(noreply) { | ||
return { | ||
@@ -776,3 +783,3 @@ callback: handle | ||
// enough to ignore those. | ||
privates.setters = function setters (type, validate, key, value, lifetime, callback, cas) { | ||
privates.setters = function setters(type, validate, key, value, lifetime, callback, cas) { | ||
var flag = 0 | ||
@@ -798,3 +805,3 @@ , valuetype = typeof value | ||
this.command(function settersCommand (noreply) { | ||
this.command(function settersCommand(noreply) { | ||
return { | ||
@@ -848,3 +855,3 @@ key: key | ||
memcached.cas = function checkandset (key, value, cas, lifetime, callback) { | ||
memcached.cas = function checkandset(key, value, cas, lifetime, callback) { | ||
privates.setters.call(this | ||
@@ -866,3 +873,3 @@ , 'cas' | ||
memcached.append = function append (key, value, callback) { | ||
memcached.append = function append(key, value, callback) { | ||
privates.setters.call(this | ||
@@ -883,3 +890,3 @@ , 'append' | ||
memcached.prepend = function prepend (key, value, callback) { | ||
memcached.prepend = function prepend(key, value, callback) { | ||
privates.setters.call(this | ||
@@ -901,4 +908,4 @@ , 'prepend' | ||
// Small handler for incr and decr's | ||
privates.incrdecr = function incrdecr (type, key, value, callback) { | ||
this.command(function incredecrCommand (noreply) { | ||
privates.incrdecr = function incrdecr(type, key, value, callback) { | ||
this.command(function incredecrCommand(noreply) { | ||
return { | ||
@@ -926,4 +933,4 @@ key: key | ||
// Deletes the keys from the servers | ||
memcached.del = function del (key, callback){ | ||
this.command(function deleteCommand (noreply) { | ||
memcached.del = function del(key, callback){ | ||
this.command(function deleteCommand(noreply) { | ||
return { | ||
@@ -946,3 +953,3 @@ key: key | ||
// Small wrapper that handle single keyword commands such as FLUSH ALL, VERSION and STAT | ||
privates.singles = function singles (type, callback) { | ||
privates.singles = function singles(type, callback) { | ||
var memcached = this | ||
@@ -954,3 +961,3 @@ , responses = [] | ||
// handle multiple servers | ||
function handle (err, results) { | ||
function handle(err, results) { | ||
if (err) { | ||
@@ -966,6 +973,6 @@ errors = errors || []; | ||
this.multi(false, function multi (server, keys, index, totals) { | ||
this.multi(false, function multi(server, keys, index, totals) { | ||
if (!calls) calls = totals; | ||
memcached.command(function singlesCommand (noreply) { | ||
memcached.command(function singlesCommand(noreply) { | ||
return { | ||
@@ -997,4 +1004,4 @@ callback: handle | ||
// see simple_cachedump.js for an example | ||
memcached.cachedump = function cachedump (server, slabid, number, callback) { | ||
this.command(function cachedumpCommand (noreply) { | ||
memcached.cachedump = function cachedump(server, slabid, number, callback) { | ||
this.command(function cachedumpCommand(noreply) { | ||
return { | ||
@@ -1001,0 +1008,0 @@ callback: callback |
{ | ||
"name": "memcached" | ||
, "version": "0.1.0" | ||
, "version": "0.1.1" | ||
, "author": "Arnout Kazemier" | ||
@@ -37,3 +37,4 @@ , "description": "A fully featured Memcached API client, supporting both single and clustered Memcached servers through consistent hashing and failover/failure. Memcached is rewrite of nMemcached, which will be deprecated in the near future." | ||
, "dependencies": { | ||
"hashring": "*" | ||
"hashring": "0.0.x" | ||
, "jackpot": "0.0.x" | ||
} | ||
@@ -40,0 +41,0 @@ , "devDependencies": { |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Non-existent author
Supply chain riskThe package was published by an npm account that no longer exists.
Found 1 instance in 1 package
Wildcard dependency
QualityPackage has a dependency with a floating version range. This can cause issues if the dependency publishes a new major version.
Found 1 instance in 1 package
58
0
0
428920
2
2132
+ Addedjackpot@0.0.x
+ Addedbisection@0.0.3(transitive)
+ Addedhashring@0.0.8(transitive)
+ Addedjackpot@0.0.6(transitive)
+ Addedretry@0.6.0(transitive)
- Removedconnection-parse@0.0.7(transitive)
- Removedhashring@3.2.0(transitive)
Updatedhashring@0.0.x