secondary-cache
Version:
support secondary cache mechanism. the first level cache is fixed memory-resident always with the highest priority. the second level is the LRU cache.
206 lines (205 loc) • 5.92 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.LRUCache = LRUCache;
exports.default = void 0;
var _eventsEx = require("events-ex");
var _lruQueue = _interopRequireDefault(require("./lru-queue"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
const create = Object.create;
const MAX_CAPACITY = 1024;
function LRUCacheItem(id, value, expires) {
this.id = id;
this.value = value;
this.expires = expires;
}
function LRUCache(options) {
if (!(this instanceof LRUCache)) {
return new LRUCache(options);
}
this.reset(options);
}
// add the event support to the LRUCache Class
(0, _eventsEx.eventable)(LRUCache);
LRUCache.prototype.delListener = LRUCache.prototype.off;
LRUCache.prototype.has = function (id) {
const item = this._cacheLRU[id];
return item !== undefined && !this.isExpired(item);
};
LRUCache.prototype.isExist = LRUCache.prototype.has;
LRUCache.prototype.isExists = LRUCache.prototype.has;
LRUCache.prototype.delete = function (id, isInternal) {
if (this.cleanInterval > 0 && Date.now() - this.lastCleanTime >= this.cleanInterval) {
setImmediate(this.clearExpires);
}
const result = this._cacheLRU[id];
if (result !== undefined) {
delete this._cacheLRU[id];
if (this._lruQueue && isInternal !== true) {
this._lruQueue.delete(result);
}
this.emit('del', id, result.value);
return true;
} else {
return false;
}
};
LRUCache.prototype.del = LRUCache.prototype.delete;
LRUCache.prototype.isExpired = function (item) {
let expired = item.expires;
expired = expired > 0 && Date.now() >= expired;
if (this.cleanInterval > 0 && Date.now() - this.lastCleanTime >= this.cleanInterval) {
setImmediate(this.clearExpires);
} else if (expired) {
this.del(item.id);
}
return expired;
};
LRUCache.prototype.peek = function (id) {
const result = this._cacheLRU[id];
if (result === undefined || this.isExpired(result)) {
return;
}
return result.value;
};
LRUCache.prototype.get = function (id) {
let result = this._cacheLRU[id];
if (result !== undefined && !this.isExpired(result)) {
if (this._lruQueue) {
this._lruQueue.use(result);
}
result = result.value;
} else {
result = undefined;
}
return result;
};
LRUCache.prototype.set = function (id, value, expires) {
let event;
if (this.cleanInterval > 0 && Date.now() - this.lastCleanTime >= this.cleanInterval) {
setImmediate(this.clearExpires);
}
let item = this._cacheLRU[id];
const oldValue = item && item.value;
if (item !== undefined) {
event = 'update';
} else {
event = 'add';
}
this.emit('before_' + event, id, value, oldValue);
if (item !== undefined) {
item.value = value;
if (expires <= 0) {
delete item.expires;
} else if (expires > 0) {
item.expires = Date.now() + expires;
} else if (this.maxAge > 0) {
item.expires = Date.now() + this.maxAge;
}
if (this._lruQueue) {
this._lruQueue.use(item);
}
} else {
if (expires > 0) {
expires = Date.now() + expires;
} else if (this.maxAge > 0) {
expires = Date.now() + this.maxAge;
} else {
expires = undefined;
}
item = new LRUCacheItem(id, value, expires);
this._cacheLRU[id] = item;
if (this._lruQueue) {
const delItem = this._lruQueue.add(item);
if (delItem !== undefined) {
this.del(delItem.id, true);
}
}
}
return this.emit(event, id, value, oldValue);
};
LRUCache.prototype.clear = function () {
const oldCache = this._cacheLRU;
this._cacheLRU = create(null);
for (const k in oldCache) {
const v = oldCache[k];
this.emit('del', k, v.value);
}
if (this.maxCapacity > 0) {
this._lruQueue = new _lruQueue.default(this.maxCapacity);
} else {
this._lruQueue = null;
}
return this;
};
LRUCache.prototype.reset = function (options) {
this.setDefaultOptions(options);
return this.clear();
};
LRUCache.prototype.free = function () {
const ref = this._cacheLRU;
for (const k in ref) {
const v = ref[k];
this.emit('del', k, v.value);
}
this._cacheLRU = null;
this._lruQueue = null;
return this.lastCleanTime = 0;
};
LRUCache.prototype.forEach = function (callback, thisArg) {
if (this.cleanInterval > 0 && Date.now() - this.lastCleanTime >= this.cleanInterval) {
setImmediate(this.clearExpires);
}
thisArg || (thisArg = this);
if (this._lruQueue) {
this._lruQueue.forEach(function (item) {
if (!this.isExpired(item)) {
return callback.call(thisArg, item.value, item.id, this);
}
}, this);
} else {
const ref = this._cacheLRU;
for (const k in ref) {
const item = ref[k];
if (!this.isExpired(item)) {
callback.call(thisArg, item.value, k, this);
}
}
}
};
LRUCache.prototype.clearExpires = function () {
const ref = this._cacheLRU;
for (const k in ref) {
const v = ref[k];
const expires = v.expires;
if (v && Date.now() >= expires || v.value === undefined) {
this.del(k);
}
}
return this.lastCleanTime = Date.now();
};
LRUCache.prototype.setDefaultOptions = function (options) {
if (options >= 0 || options < 0) {
this.maxCapacity = options;
this.maxAge = 0;
this.cleanInterval = 0;
} else if (options) {
this.maxCapacity = options.capacity || MAX_CAPACITY;
this.maxAge = options.expires;
this.cleanInterval = options.cleanInterval;
if (this.cleanInterval > 0) {
this.cleanInterval = this.cleanInterval * 1000;
}
} else {
this.maxCapacity = MAX_CAPACITY;
}
if (this._lruQueue && this._lruQueue.maxCapacity !== this.maxCapacity) {
this._lruQueue.maxCapacity = this.maxCapacity;
}
};
LRUCache.prototype.length = function () {
return Object.keys(this._cacheLRU).length;
};
var _default = LRUCache;
exports.default = _default;