From 5064d185fd1618dc615d17933ec898b2f429aafe Mon Sep 17 00:00:00 2001 From: Barret Schloerke Date: Mon, 19 Mar 2012 20:29:35 -0700 Subject: [PATCH 1/4] white space --- lib/memcache.js | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/lib/memcache.js b/lib/memcache.js index d53085b..d105e3c 100644 --- a/lib/memcache.js +++ b/lib/memcache.js @@ -25,7 +25,7 @@ var tcp = require('net'), util = require('util'); - + var crlf = "\r\n"; var crlf_len = crlf.length; @@ -53,22 +53,22 @@ Client.prototype.connect = function () { this.setNoDelay(); self.emit("connect"); self.dispatchHandles(); - }); - + }); + this.conn.addListener("data", function (data) { self.buffer += data; // util.debug(data); self.recieves += 1; self.handle_received_data(); }); - + this.conn.addListener("end", function () { if (self.conn && self.conn.readyState) { self.conn.end(); self.conn = null; } }); - + this.conn.addListener("close", function () { self.conn = null; self.emit("close"); @@ -88,7 +88,7 @@ Client.prototype.connect = function () { Client.prototype.addHandler = function(callback) { this.handles.push(callback); - + if (this.conn.readyState == 'open') { this.dispatchHandles(); } @@ -163,7 +163,7 @@ Client.prototype.cas = function(key, value, unique, callback, lifetime, flags) { Client.prototype.del = function(key, callback){ util.error("mc.del() is deprecated - use mc.delete() instead"); - return this.delete(key, callback); + return this.delete(key, callback); }; Client.prototype.delete = function(key, callback){ @@ -211,7 +211,7 @@ Client.prototype.stats = function(type, callback){ } Client.prototype.handle_received_data = function(){ - + while (this.buffer.length > 0){ var result = this.determine_reply_handler(this.buffer); @@ -247,7 +247,7 @@ Client.prototype.determine_reply_handler = function (buffer){ if (crlf_at == -1){ return null; } - + // determine errors for (var error_idx in error_replies){ var error_indicator = error_replies[error_idx]; @@ -270,7 +270,7 @@ Client.prototype.handle_get = function(buffer) { var result_value = null; var end_indicator_len = 3; var result_len = 0; - + if (buffer.indexOf('END') == 0) { return [result_value, end_indicator_len + crlf_len]; } else if (buffer.indexOf('VALUE') == 0 && buffer.indexOf('END') != -1) { @@ -278,12 +278,12 @@ Client.prototype.handle_get = function(buffer) { var end_indicator_start = buffer.indexOf('END'); result_len = end_indicator_start - first_line_len - crlf_len; result_value = buffer.substr(first_line_len, result_len); - return [result_value, first_line_len + parseInt(result_len, 10) + crlf_len + end_indicator_len + crlf_len] + return [result_value, first_line_len + parseInt(result_len, 10) + crlf_len + end_indicator_len + crlf_len] } else { var first_line_len = buffer.indexOf(crlf) + crlf_len; var result_len = buffer.substr(0, first_line_len).split(' ')[3]; result_value = buffer.substr(first_line_len, result_len); - + return [result_value, first_line_len + parseInt(result_len ) + crlf_len + end_indicator_len + crlf_len]; } }; From eec0519bec69e634576f628e638d3679dfde3d50 Mon Sep 17 00:00:00 2001 From: Barret Schloerke Date: Mon, 19 Mar 2012 21:04:29 -0700 Subject: [PATCH 2/4] get with multiple keys implemented --- lib/memcache.js | 86 ++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 78 insertions(+), 8 deletions(-) diff --git a/lib/memcache.js b/lib/memcache.js index d105e3c..25af9e0 100644 --- a/lib/memcache.js +++ b/lib/memcache.js @@ -26,11 +26,30 @@ var tcp = require('net'), util = require('util'); -var crlf = "\r\n"; +var crlf = "\r\n"; var crlf_len = crlf.length; +var endTag = 'END\r\n'; +var endTag_len = endTag.length; + +var fullEndTag = '\r\nEND\r\n'; +var fullEndTag_len = fullEndTag.length; + var error_replies = ['ERROR', 'NOT_FOUND', 'CLIENT_ERROR', 'SERVER_ERROR']; +isArray = Array.isArray || function(obj) { + return toString.call(obj) == '[object Array]'; +}; + +trimLeft = /^\s+/ +trimRight = /\s+$/ +trim = String.prototype.trim || function(text) { + return text == null ? + "" : + text.toString().replace( trimLeft, "" ).replace( trimRight, "" ) +} + + var Client = exports.Client = function(port, host) { this.port = port || 11211; this.host = host || 'localhost'; @@ -118,7 +137,22 @@ Client.prototype.close = function() { }; Client.prototype.get = function(key, callback) { - return this.query('get ' + key, 'get', callback); + // allow for multi get calls + var keyIsArray = false; + if ( isArray(key) ) { + keyIsArray = true; + // replace whitespace with length > 2 with single space + key = key.join(' ').replace(/\s{2,}/, " "); + key = trim.call(key); + } + + key = trim.call(key); + + if (keyIsArray || (key.indexOf(" ") != -1)) { + return this.query('get ' + key, 'get_multi', callback); + } else { + return this.query('get ' + key, 'get', callback); + } }; @@ -268,26 +302,62 @@ Client.prototype.determine_reply_handler = function (buffer){ Client.prototype.handle_get = function(buffer) { var next_result_at = 0; var result_value = null; - var end_indicator_len = 3; var result_len = 0; - if (buffer.indexOf('END') == 0) { - return [result_value, end_indicator_len + crlf_len]; - } else if (buffer.indexOf('VALUE') == 0 && buffer.indexOf('END') != -1) { + if (buffer.indexOf(endTag) == 0) { + return [result_value, endTag_len]; + } else if (buffer.indexOf('VALUE') == 0 && buffer.indexOf(fullEndTag) != -1) { first_line_len = buffer.indexOf(crlf) + crlf_len; var end_indicator_start = buffer.indexOf('END'); result_len = end_indicator_start - first_line_len - crlf_len; result_value = buffer.substr(first_line_len, result_len); - return [result_value, first_line_len + parseInt(result_len, 10) + crlf_len + end_indicator_len + crlf_len] + return [result_value, first_line_len + parseInt(result_len, 10) + fullEndTag_len] } else { var first_line_len = buffer.indexOf(crlf) + crlf_len; var result_len = buffer.substr(0, first_line_len).split(' ')[3]; result_value = buffer.substr(first_line_len, result_len); - return [result_value, first_line_len + parseInt(result_len ) + crlf_len + end_indicator_len + crlf_len]; + return [result_value, first_line_len + parseInt(result_len ) + fullEndTag_len]; } }; + +Client.prototype.handle_get_multi = function(buffer) { + + if (buffer.indexOf(endTag) == 0) { + // received nothing. return a lonely result + return [null, endTag_len, null]; + } + + var end_tag_pos = buffer.indexOf(fullEndTag); + if ( (buffer.indexOf('VALUE ') == 0) && (end_tag_pos != -1) ) { + // got valid stuff! + + // split by new lines to get... + // ["Value KEY1 X Y", "RESULT #1","VALUE KEY2 X Y", "RESULT #2", ...., "END", ""] + results = buffer.split(crlf); + + results = results.slice(0, -2); // remove ["END", ""] + resultsLength = results.length; + + // ret[key] = value for key and value within arr + var ret = {}; + var resultKey; + for (var i = 0; i < resultsLength; i += 2) { + resultKey = results[i].split(' ')[1]; // retrieve key name + ret[resultKey] = results[i + 1]; // retrieve value and store + } + + return [ret, end_tag_pos + fullEndTag_len, null] + } else { + + // still has more to receive... + // return null to avoid work... no need to parse results to break right afterwards + return null; + } +}; + + Client.prototype.handle_stats = function(buffer){ // special case - no stats at all From cc7cbe6fd55cc55ad0f823e2a298e93126dfe085 Mon Sep 17 00:00:00 2001 From: Barret Schloerke Date: Tue, 20 Mar 2012 11:46:28 -0700 Subject: [PATCH 3/4] parseInt needs to have a base --- lib/memcache.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/memcache.js b/lib/memcache.js index 25af9e0..6a13d8a 100644 --- a/lib/memcache.js +++ b/lib/memcache.js @@ -317,7 +317,7 @@ Client.prototype.handle_get = function(buffer) { var result_len = buffer.substr(0, first_line_len).split(' ')[3]; result_value = buffer.substr(first_line_len, result_len); - return [result_value, first_line_len + parseInt(result_len ) + fullEndTag_len]; + return [result_value, first_line_len + parseInt(result_len, 10) + fullEndTag_len]; } }; From 27b660ee7151cffe1ecc3814a0bfd69e824e79d0 Mon Sep 17 00:00:00 2001 From: Barret Schloerke Date: Wed, 21 Mar 2012 12:05:02 -0700 Subject: [PATCH 4/4] no matching keys returns a blank dictionary --- lib/memcache.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/memcache.js b/lib/memcache.js index 6a13d8a..005bb3c 100644 --- a/lib/memcache.js +++ b/lib/memcache.js @@ -326,7 +326,7 @@ Client.prototype.handle_get_multi = function(buffer) { if (buffer.indexOf(endTag) == 0) { // received nothing. return a lonely result - return [null, endTag_len, null]; + return [{}, endTag_len, null]; } var end_tag_pos = buffer.indexOf(fullEndTag);