@leyyo/cache
Version:
Common cache library
191 lines (190 loc) • 6.98 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.invalidatorRepo = void 0;
const config_1 = require("../config");
const hub_1 = require("../hub");
class CacheInvalidatorRepoImpl {
constructor() {
this._zeroCount = 0;
this._notifyQueue = new Map();
this._invalidatesQueue = new Map();
setTimeout(() => this._trigger(), config_1.cacheConfig.invalidation.firstInterval);
}
_chunkArray(values, size) {
const chunks = [];
for (let i = 0; i < values.length; i += size) {
chunks.push(values.slice(i, i + size));
}
return chunks;
}
_trigger() {
const size = this._notifyQueue.size + this._invalidatesQueue.size;
if (size > 0) {
const now = this._now();
const stats = { notifies: 0, invalidates: 0, times: 0 };
this._triggerForNotify(now, stats);
this._triggerForInvalidate(now, stats);
if (stats.times > 0) {
console.log(`Invalidator run. ${JSON.stringify(stats)}`);
}
}
this._schedule(size);
}
_triggerForNotify(now, stats) {
if (this._notifyQueue.size < 1) {
return;
}
const chunkSize = config_1.cacheConfig.invalidation.chunkSizeAdd;
for (const [time, ownerMap] of this._notifyQueue.entries()) {
stats.times++;
if (time < now) {
for (const [idOwner, idBasicMap] of ownerMap.entries()) {
const invalidatorConsumer = hub_1.cacheHub.getInvalidatorConsumer(idOwner);
if (!invalidatorConsumer) {
// todo
continue;
}
const chunks = [];
// Record<idBasicKey, Record<dataFullKey, dataOwner>>
let currentChunk = {};
let count = 0;
for (const [idBasicKey, dataMap] of idBasicMap.entries()) {
currentChunk[idBasicKey] = Object.fromEntries(dataMap.entries());
if (count === chunkSize) {
chunks.push(Object.assign({}, currentChunk)); // cloned
currentChunk = {};
count = 0;
}
else {
count++;
}
dataMap.clear();
stats.notifies++;
}
idBasicMap.clear();
if (Object.keys(currentChunk).length > 0) {
chunks.push(Object.assign({}, currentChunk)); // cloned
}
chunks.forEach(chunk => {
invalidatorConsumer.$invalidatorForNotify({
from: 'todo',
records: chunk,
});
});
}
this._notifyQueue.delete(time);
}
}
}
_triggerForInvalidate(now, stats) {
if (this._invalidatesQueue.size < 1) {
return;
}
const chunkSize = config_1.cacheConfig.invalidation.chunkSizeDelete;
for (const [time, idOwnerMap] of this._invalidatesQueue.entries()) {
stats.times++;
if (time < now) {
for (const [idOwner, idBasicKeySet] of idOwnerMap.entries()) {
const invalidatorConsumer = hub_1.cacheHub.getInvalidatorConsumer(idOwner);
if (!invalidatorConsumer) {
// todo
continue;
}
const idBasicKeys = Array.from(idBasicKeySet.keys());
if (idBasicKeys.length < chunkSize) {
invalidatorConsumer.$invalidatorForInvalidate({ from: 'todo', ids: idBasicKeys });
}
else {
const chunks = this._chunkArray(idBasicKeys, chunkSize);
chunks.forEach(chunk => {
invalidatorConsumer.$invalidatorForInvalidate({ from: 'todo', ids: chunk });
});
}
stats.invalidates += idBasicKeys.length;
idBasicKeySet.clear();
}
this._invalidatesQueue.delete(time);
}
}
}
_schedule(size) {
let interval = 1000;
if (size > 1) {
this._zeroCount = 0;
}
else if (size === 0) {
if (this._zeroCount < 5) {
interval = 2000;
}
else {
interval = 10000;
}
if (this._zeroCount === Number.MAX_SAFE_INTEGER - 1) {
this._zeroCount = 0;
}
else {
this._zeroCount++;
}
}
setTimeout(() => this._trigger(), interval);
}
_now() {
const now = new Date();
now.setSeconds(0);
return now.getTime();
}
notify(dataOwner, dataFullKey, idOwner, idBasicKeys) {
const now = this._now();
let idOwnerMap;
let idBasicMap;
let dataRec;
if (!this._notifyQueue.has(now)) {
idOwnerMap = new Map();
idBasicMap = new Map();
idOwnerMap.set(idOwner, idBasicMap);
this._notifyQueue.set(now, idOwnerMap);
}
else {
idOwnerMap = this._notifyQueue.get(now);
if (!idOwnerMap.has(idOwner)) {
idBasicMap = new Map();
idOwnerMap.set(idOwner, idBasicMap);
}
else {
idBasicMap = idOwnerMap.get(idOwner);
}
}
idBasicKeys.forEach(idBasicKey => {
if (!idBasicMap.has(idBasicKey)) {
dataRec = new Map();
dataRec.set(dataFullKey, dataOwner);
idBasicMap.set(idBasicKey, dataRec);
}
else {
idBasicMap.get(idBasicKey).set(dataFullKey, dataOwner);
}
});
}
invalidate(idOwner, idBasicKey) {
const now = this._now();
let idMap;
let idSet;
if (!this._invalidatesQueue.has(now)) {
idMap = new Map();
idSet = new Set();
idSet.add(idBasicKey);
idMap.set(idOwner, idSet);
this._invalidatesQueue.set(now, idMap);
return;
}
idMap = this._invalidatesQueue.get(now);
if (!idMap.has(idOwner)) {
idSet = new Set();
idSet.add(idBasicKey);
idMap.set(idOwner, idSet);
return;
}
idMap.get(idOwner).add(idBasicKey);
}
}
exports.invalidatorRepo = new CacheInvalidatorRepoImpl();