UNPKG

@leyyo/cache

Version:
191 lines (190 loc) 6.98 kB
"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();