Created
May 14, 2014 17:08
-
-
Save sorensen/8f9c5be363d158547c9c to your computer and use it in GitHub Desktop.
Memory store with limit
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict'; | |
/*! | |
* Module dependencies. | |
*/ | |
var config = {} | |
, cache = {} | |
, timeouts = {} | |
, limit = config.size_limit | |
; | |
/*! | |
* Debug mode. Output memory store size. | |
*/ | |
if (config.debug) { | |
setInterval(function() { | |
console.log('[MemoryStore] size: ' + exports.size() / 1000 + ' kb'); | |
}, 15 * 1000); | |
} | |
/*! | |
* Auto removal for memory size limit. | |
*/ | |
if (config.size_limit) { | |
setInterval(function() { | |
var keys = Object.keys(cache) | |
, len = keys.length | |
, arr = new Array(len) | |
// Transform cache map to array of values | |
for (var i = 0; i < len; i++) { | |
var key = keys[i]; | |
arr[i] = cache[key]; | |
arr[i].key = key | |
} | |
// Sort the array map by created time | |
arr.sort(function(a, b) { return a.created - b.created; }); | |
// Remove the oldest key known as long as we are above the size limit | |
while (exports.size() > config.size_limit) { | |
console.log('[MemoryStore.autoFlush] ', exports.size()) | |
var data = arr.shift(); | |
exports.remove(data.key); | |
} | |
// Report the resulting memory size | |
console.log('[MemoryStore.autoFlush] ', exports.size()); | |
}, 15 * 1000); | |
} | |
/** | |
* Get the value of a given key | |
* | |
* @param {String} cache key | |
*/ | |
exports.get = function(key) { | |
console.log('[MemoryStore.get] ' + key); | |
var val = cache[key]; | |
if (val) return val.value; | |
return undefined; | |
}; | |
/** | |
* Save a key / value pair in the store | |
* | |
* @param {String} cache key | |
* @param {Any} cache value | |
* @param {Number} expiry in seconds | |
*/ | |
exports.set = function(key, val, ttl) { | |
console.log('[MemoryStore.set] ' + key); | |
cache[key] = { | |
value: val | |
, created: Date.now() | |
} | |
if (typeof ttl !== 'undefined') { | |
exports.expire(key, ttl); | |
} | |
}; | |
/** | |
* Set expiration of a key | |
* | |
* @param {String} cache key | |
* @param {Number} expiry in seconds | |
*/ | |
exports.expire = function(key, ttl) { | |
console.log('[MemoryStore.expire] ' + key + ' - ' + ttl); | |
if (timeouts.hasOwnProperty(key)) { | |
clearTimeout(timeouts[key]); | |
} | |
timeouts[key] = setTimeout(function() { | |
exports.remove(key); | |
}, ttl * 1000); | |
}; | |
/** | |
* Remove a given key from the store | |
* | |
* @param {String} cache key | |
*/ | |
exports.remove = function(key) { | |
console.log('[MemoryStore.remove] ' + key); | |
if (cache.hasOwnProperty(key)) { | |
delete cache[key]; | |
} | |
if (timeouts.hasOwnProperty(key)) { | |
clearTimeout(timeouts[key]); | |
delete timeouts[key]; | |
} | |
}; | |
/** | |
* Flush / reset the cache | |
*/ | |
exports.flush = function() { | |
console.log('[MemoryStore.flush] ' + Object.keys(cache).length); | |
Object.keys(timeouts).forEach(function(x) { | |
clearTimeout(timeouts[x]); | |
}); | |
cache = {}; | |
timeouts = {}; | |
}; | |
/** | |
* Get an approximate memory size of an object | |
* http://stackoverflow.com/questions/1248302/javascript-object-size | |
* | |
* @param {Any} input | |
* @return {Number} size in bytes | |
*/ | |
function getSize(obj) { | |
var objectList = [] | |
, stack = [obj] | |
, bytes = 0 | |
; | |
while (stack.length) { | |
var val = stack.pop(); | |
if (typeof val === 'boolean') { | |
bytes += 4; | |
} else if (typeof val === 'string') { | |
bytes += val.length * 2; | |
} else if (typeof val === 'number') { | |
bytes += 8; | |
} else if (typeof val === 'object' && objectList.indexOf(val) === -1) { | |
objectList.push(val); | |
for (var i in val) stack.push(val[i]); | |
} | |
} | |
return bytes; | |
} | |
/** | |
* | |
*/ | |
exports.size = function() { | |
return getSize(cache) + getSize(timeouts); | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment