|
|
@ -6,31 +6,60 @@ var domain = require('domain'); |
|
|
|
/** |
|
|
|
* Module that lets you specify a hierarchy of caches. |
|
|
|
*/ |
|
|
|
var multi_caching = function(caches) { |
|
|
|
var multi_caching = function (caches) { |
|
|
|
var self = {}; |
|
|
|
if (!Array.isArray(caches)) { throw new Error('multi_caching requires an array of caches'); } |
|
|
|
if (!Array.isArray(caches)) { |
|
|
|
throw new Error('multi_caching requires an array of caches'); |
|
|
|
} |
|
|
|
|
|
|
|
self.queues = {}; |
|
|
|
|
|
|
|
function get_from_highest_priority_cache(key, cb, options) { |
|
|
|
function get_from_highest_priority_cache(key, options, cb) { |
|
|
|
if (typeof options === 'function') { |
|
|
|
cb = options; |
|
|
|
options = undefined; |
|
|
|
} |
|
|
|
|
|
|
|
var i = 0; |
|
|
|
async.forEachSeries(caches, function(cache, async_cb) { |
|
|
|
cache.store.get(key, function(err, result) { |
|
|
|
if (err) { return cb(err); } |
|
|
|
if (result) { |
|
|
|
// break out of async loop.
|
|
|
|
return cb(err, result, i); |
|
|
|
} |
|
|
|
async.forEachSeries(caches, function (cache, async_cb) { |
|
|
|
if(typeof options === 'object'){ |
|
|
|
cache.store.get(key, options, function (err, result) { |
|
|
|
if (err) { |
|
|
|
return cb(err); |
|
|
|
} |
|
|
|
if (result) { |
|
|
|
// break out of async loop.
|
|
|
|
return cb(err, result, i); |
|
|
|
} |
|
|
|
|
|
|
|
i += 1; |
|
|
|
async_cb(err); |
|
|
|
}); |
|
|
|
}else{ |
|
|
|
cache.store.get(key, function (err, result) { |
|
|
|
if (err) { |
|
|
|
return cb(err); |
|
|
|
} |
|
|
|
if (result) { |
|
|
|
// break out of async loop.
|
|
|
|
return cb(err, result, i); |
|
|
|
} |
|
|
|
|
|
|
|
i += 1; |
|
|
|
async_cb(err); |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
i += 1; |
|
|
|
async_cb(err); |
|
|
|
}, options); |
|
|
|
}, cb); |
|
|
|
} |
|
|
|
|
|
|
|
function set_in_multiple_caches(caches, opts, cb) { |
|
|
|
async.forEach(caches, function(cache, async_cb) { |
|
|
|
cache.store.set(opts.key, opts.value, opts.ttl, async_cb, opts.options); |
|
|
|
async.forEach(caches, function (cache, async_cb) { |
|
|
|
if (typeof opts.options !== 'object') { |
|
|
|
cache.store.set(opts.key, opts.value, opts.ttl, async_cb); |
|
|
|
} else { |
|
|
|
cache.store.set(opts.key, opts.value, opts.options, async_cb); |
|
|
|
} |
|
|
|
}, cb); |
|
|
|
} |
|
|
|
|
|
|
@ -39,8 +68,8 @@ var multi_caching = function(caches) { |
|
|
|
* |
|
|
|
* When a key is found in a lower cache, all higher levels are updated |
|
|
|
*/ |
|
|
|
self.get_and_pass_up = function(key, cb) { |
|
|
|
get_from_highest_priority_cache(key, function(err, result, index) { |
|
|
|
self.get_and_pass_up = function (key, cb) { |
|
|
|
get_from_highest_priority_cache(key, function (err, result, index) { |
|
|
|
if (err) { |
|
|
|
return cb(err); |
|
|
|
} |
|
|
@ -49,7 +78,7 @@ var multi_caching = function(caches) { |
|
|
|
|
|
|
|
if (result !== undefined && index) { |
|
|
|
var cachesToUpdate = caches.slice(0, index); |
|
|
|
async.forEach(cachesToUpdate, function(cache, async_cb) { |
|
|
|
async.forEach(cachesToUpdate, function (cache, async_cb) { |
|
|
|
cache.set(key, result, result.ttl, async_cb); |
|
|
|
}); |
|
|
|
} |
|
|
@ -66,11 +95,10 @@ var multi_caching = function(caches) { |
|
|
|
* If a key doesn't exist in a higher-priority cache but exists in a lower-priority |
|
|
|
* cache, it gets set in all higher-priority caches. |
|
|
|
*/ |
|
|
|
self.wrap = function(key, work, ttl, cb, options) { |
|
|
|
if (typeof ttl === 'function') { |
|
|
|
cb = ttl; |
|
|
|
options = cb; |
|
|
|
ttl = undefined; |
|
|
|
self.wrap = function (key, work, options, cb) { |
|
|
|
if (typeof options === 'function') { |
|
|
|
cb = options; |
|
|
|
options = undefined; |
|
|
|
} |
|
|
|
|
|
|
|
if (self.queues[key]) { |
|
|
@ -81,14 +109,14 @@ var multi_caching = function(caches) { |
|
|
|
self.queues[key] = [{cb: cb, domain: process.domain}]; |
|
|
|
|
|
|
|
function fillCallbacks(err, data) { |
|
|
|
self.queues[key].forEach(function(task) { |
|
|
|
self.queues[key].forEach(function (task) { |
|
|
|
var taskDomain = task.domain || domain.create(); |
|
|
|
taskDomain.bind(task.cb)(err, data); |
|
|
|
}); |
|
|
|
delete self.queues[key]; |
|
|
|
} |
|
|
|
|
|
|
|
get_from_highest_priority_cache(key, function(err, result, index) { |
|
|
|
get_from_highest_priority_cache(key, function (err, result, index) { |
|
|
|
if (err) { |
|
|
|
return fillCallbacks(err); |
|
|
|
} else if (result) { |
|
|
@ -96,19 +124,23 @@ var multi_caching = function(caches) { |
|
|
|
var opts = { |
|
|
|
key: key, |
|
|
|
value: result, |
|
|
|
ttl: ttl, |
|
|
|
options: options |
|
|
|
}; |
|
|
|
set_in_multiple_caches(caches_to_update, opts, function(err) { |
|
|
|
|
|
|
|
if (typeof options !== 'object') { |
|
|
|
opts.ttl = options; |
|
|
|
} |
|
|
|
|
|
|
|
set_in_multiple_caches(caches_to_update, opts, function (err) { |
|
|
|
fillCallbacks(err, result); |
|
|
|
}); |
|
|
|
} else { |
|
|
|
domain |
|
|
|
.create() |
|
|
|
.on('error', function(err) { |
|
|
|
fillCallbacks(err); |
|
|
|
}) |
|
|
|
.bind(work)(function(err, data) { |
|
|
|
.create() |
|
|
|
.on('error', function (err) { |
|
|
|
fillCallbacks(err); |
|
|
|
}) |
|
|
|
.bind(work)(function (err, data) { |
|
|
|
if (err) { |
|
|
|
fillCallbacks(err); |
|
|
|
return; |
|
|
@ -116,10 +148,13 @@ var multi_caching = function(caches) { |
|
|
|
var opts = { |
|
|
|
key: key, |
|
|
|
value: data, |
|
|
|
ttl: ttl, |
|
|
|
options: options |
|
|
|
}; |
|
|
|
set_in_multiple_caches(caches, opts, function(err) { |
|
|
|
|
|
|
|
if (typeof options !== 'object') { |
|
|
|
opts.ttl = options; |
|
|
|
} |
|
|
|
set_in_multiple_caches(caches, opts, function (err) { |
|
|
|
if (err) { |
|
|
|
fillCallbacks(err); |
|
|
|
} else { |
|
|
@ -131,23 +166,37 @@ var multi_caching = function(caches) { |
|
|
|
}); |
|
|
|
}; |
|
|
|
|
|
|
|
self.set = function(key, value, ttl, cb, options) { |
|
|
|
self.set = function (key, value, options, cb) { |
|
|
|
var opts = { |
|
|
|
key: key, |
|
|
|
value: value, |
|
|
|
ttl: ttl, |
|
|
|
options: options |
|
|
|
}; |
|
|
|
if (typeof options !== 'object') { |
|
|
|
opts.ttl = options; |
|
|
|
} |
|
|
|
set_in_multiple_caches(caches, opts, cb); |
|
|
|
}; |
|
|
|
|
|
|
|
self.get = function(key, cb, options) { |
|
|
|
get_from_highest_priority_cache(key, cb, options); |
|
|
|
self.get = function (key, options, cb) { |
|
|
|
if (typeof options === 'function') { |
|
|
|
cb = options; |
|
|
|
options = false; |
|
|
|
} |
|
|
|
get_from_highest_priority_cache(key, options, cb); |
|
|
|
}; |
|
|
|
|
|
|
|
self.del = function(key, cb, options) { |
|
|
|
async.forEach(caches, function(cache, async_cb) { |
|
|
|
cache.store.del(key, async_cb, options); |
|
|
|
self.del = function (key, options, cb) { |
|
|
|
if (typeof options === 'function') { |
|
|
|
cb = options; |
|
|
|
options = false; |
|
|
|
} |
|
|
|
async.forEach(caches, function (cache, async_cb) { |
|
|
|
if(typeof options ==='object'){ |
|
|
|
cache.store.del(key, options, async_cb ); |
|
|
|
}else{ |
|
|
|
cache.store.del(key, async_cb ); |
|
|
|
} |
|
|
|
}, cb); |
|
|
|
}; |
|
|
|
|
|
|
|