Comparing version 7.1.4 to 7.1.5
@@ -17,2 +17,45 @@ 'use strict'; | ||
internals.toBoundCallback = function (callback) { | ||
return process.domain ? process.domain.bind(callback) : callback; | ||
}; | ||
internals.PendingResponse = function (id, addCallback, onDidSend) { | ||
this.id = id; | ||
this.callbacks = [internals.toBoundCallback(addCallback)]; | ||
this.onDidSend = onDidSend; | ||
this.timeoutTimer = null; | ||
}; | ||
internals.PendingResponse.prototype.add = function (callback) { | ||
this.callbacks.push(internals.toBoundCallback(callback)); // Explicitly bind callback to its process.domain (_finalize might get called from a different active process.domain) | ||
}; | ||
internals.PendingResponse.prototype.send = function (err, value, cached, report) { | ||
const length = this.callbacks.length; | ||
for (let i = 0; i < length; ++i) { | ||
Hoek.nextTick(this.callbacks[i])(err, value, cached, report); | ||
} | ||
clearTimeout(this.timeoutTimer); | ||
this.callbacks = []; | ||
return this.onDidSend(length, report); | ||
}; | ||
internals.PendingResponse.prototype.setTimeout = function (fn, timeoutMs) { | ||
clearTimeout(this.timeoutTimer); | ||
this.timeoutTimer = setTimeout(fn, timeoutMs); | ||
}; | ||
exports = module.exports = internals.Policy = function (options, cache, segment) { | ||
@@ -23,4 +66,4 @@ | ||
this._cache = cache; | ||
this._pendings = {}; // id -> [callbacks] | ||
this._pendingGenerateCall = {}; // id -> boolean | ||
this._pendings = Object.create(null); // id -> PendingResponse | ||
this._pendingGenerateCall = Object.create(null); // id -> boolean | ||
this.rules(options); | ||
@@ -59,10 +102,16 @@ | ||
const id = (key && typeof key === 'object') ? key.id : key; | ||
const pendingsId = '+' + id; // Prefix to avoid conflicts with JS internals (e.g. __proto__) | ||
if (this._pendings[pendingsId]) { | ||
this._pendings[pendingsId].push(process.domain ? process.domain.bind(callback) : callback); // Explicitly bind callback to its process.domain (_finalize might get called from a different active process.domain) | ||
if (this._pendings[id]) { | ||
this._pendings[id].add(callback); | ||
return; | ||
} | ||
this._pendings[pendingsId] = [callback]; | ||
const pending = this._pendings[id] = new internals.PendingResponse(id, callback, (count, report) => { | ||
delete this._pendings[id]; | ||
if (count > 0 && report.isStale !== undefined) { | ||
this.stats.hits = this.stats.hits + count; | ||
} | ||
}); | ||
// Lookup in cache | ||
@@ -101,3 +150,3 @@ | ||
return internals.respond(this, id, err, cached ? cached.item : null, cached, report); | ||
return pending.send(err, cached ? cached.item : null, cached, report); | ||
} | ||
@@ -110,6 +159,6 @@ | ||
return internals.respond(this, id, null, cached.item, cached, report); | ||
return pending.send(null, cached.item, cached, report); | ||
} | ||
return this._generate(id, key, cached, report); | ||
return this._generate(pending, key, cached, report); | ||
}); | ||
@@ -119,6 +168,4 @@ }; | ||
internals.Policy.prototype._generate = function (id, key, cached, report) { | ||
internals.Policy.prototype._generate = function (pending, key, cached, report) { | ||
const respond = Hoek.once(internals.respond); | ||
if (cached) { // Must be stale | ||
@@ -134,5 +181,5 @@ | ||
setTimeout(() => { | ||
pending.setTimeout(() => { | ||
return respond(this, id, null, cached.item, cached, report); | ||
return pending.send(null, cached.item, cached, report); | ||
}, this.rule.staleTimeout); | ||
@@ -144,5 +191,5 @@ } | ||
setTimeout(() => { | ||
pending.setTimeout(() => { | ||
return respond(this, id, Boom.serverUnavailable(), null, null, report); | ||
return pending.send(Boom.serverUnavailable(), null, null, report); | ||
}, this.rule.generateTimeout); | ||
@@ -153,11 +200,10 @@ } | ||
const pendingId = ('+' + id); | ||
if (!this._pendingGenerateCall[pendingId]) { // Check if a generate call is already in progress | ||
if (!this._pendingGenerateCall[pending.id]) { // Check if a generate call is already in progress | ||
++this.stats.generates; // Record generation before call in case it times out | ||
if (this.rule.pendingGenerateTimeout) { | ||
this._pendingGenerateCall[pendingId] = true; | ||
this._pendingGenerateCall[pending.id] = pending; | ||
setTimeout(() => { | ||
delete this._pendingGenerateCall[pendingId]; | ||
delete this._pendingGenerateCall[pending.id]; | ||
}, this.rule.pendingGenerateTimeout); | ||
@@ -167,17 +213,21 @@ } | ||
try { | ||
this._callGenerateFunc(id, key, cached, report, respond); | ||
this._callGenerateFunc(pending, key, cached, report); | ||
} | ||
catch (err) { | ||
delete this._pendingGenerateCall[pendingId]; | ||
return respond(this, id, err, null, null, report); | ||
delete this._pendingGenerateCall[pending.id]; | ||
return pending.send(err, null, null, report); | ||
} | ||
} | ||
else { | ||
this._pendingGenerateCall[pending.id] = pending; | ||
} | ||
}; | ||
internals.Policy.prototype._callGenerateFunc = function (id, key, cached, report, respond) { | ||
internals.Policy.prototype._callGenerateFunc = function (pending, key, cached, report) { | ||
this.rule.generateFunc.call(null, key, (generateError, value, ttl) => { | ||
delete this._pendingGenerateCall['+' + id]; | ||
pending = this._pendingGenerateCall[pending.id] || pending; | ||
delete this._pendingGenerateCall[pending.id]; | ||
@@ -191,6 +241,6 @@ const finalize = (err) => { | ||
return respond(this, id, error, cached.item, cached, report); | ||
return pending.send(error, cached.item, cached, report); | ||
} | ||
return respond(this, id, error, value, null, report); // Ignored if stale value already returned | ||
return pending.send(error, value, null, report); // Ignored if stale value already returned | ||
}; | ||
@@ -201,7 +251,7 @@ | ||
if ((generateError && this.rule.dropOnError) || ttl === 0) { // null or undefined means use policy | ||
return this.drop(id, finalize); // Invalidate cache | ||
return this.drop(pending.id, finalize); // Invalidate cache | ||
} | ||
if (!generateError) { | ||
return this.set(id, value, ttl, finalize); // Lazy save (replaces stale cache copy with late-coming fresh copy) | ||
return this.set(pending.id, value, ttl, finalize); // Lazy save (replaces stale cache copy with late-coming fresh copy) | ||
} | ||
@@ -224,19 +274,2 @@ | ||
internals.respond = function (policy, id, err, value, cached, report) { | ||
id = '+' + id; | ||
const pendings = policy._pendings[id]; | ||
delete policy._pendings[id]; | ||
const length = pendings.length; | ||
for (let i = 0; i < length; ++i) { | ||
Hoek.nextTick(pendings[i])(err, value, cached, report); | ||
} | ||
if (report.isStale !== undefined) { | ||
policy.stats.hits = policy.stats.hits + length; | ||
} | ||
}; | ||
internals.Policy.prototype.set = function (key, value, ttl, callback) { | ||
@@ -243,0 +276,0 @@ |
{ | ||
"name": "catbox", | ||
"description": "Multi-strategy object caching service", | ||
"version": "7.1.4", | ||
"version": "7.1.5", | ||
"repository": "git://github.com/hapijs/catbox", | ||
@@ -22,3 +22,3 @@ "main": "lib/index.js", | ||
"code": "4.x.x", | ||
"lab": "13.x.x" | ||
"lab": "14.x.x" | ||
}, | ||
@@ -25,0 +25,0 @@ "scripts": { |
@@ -8,3 +8,3 @@ ![catbox Logo](https://raw.github.com/hapijs/catbox/master/images/catbox.png) | ||
Lead Maintainer: [Eran Hammer](https://github.com/hueniverse) | ||
Lead Maintainer: [Gil Pedersen](https://github.com/kanongil) | ||
@@ -39,2 +39,3 @@ **catbox** is a multi-strategy key-value object store. It comes with extensions supporting a memory cache, | ||
- [LevelDB](https://github.com/mshick/catbox-multilevel) | ||
- [Local Disk](https://github.com/mirusresearch/catbox-disk) | ||
@@ -41,0 +42,0 @@ |
Sorry, the diff of this file is not supported yet
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
31234
429
167
1