Skip to content

Instantly share code, notes, and snippets.

@sorensen
Created May 14, 2014 17:08
Show Gist options
  • Save sorensen/8f9c5be363d158547c9c to your computer and use it in GitHub Desktop.
Save sorensen/8f9c5be363d158547c9c to your computer and use it in GitHub Desktop.
Memory store with limit
'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