UNPKG

@thermopylae/lib.cache

Version:
102 lines (101 loc) 3.29 kB
import { chrono } from '@thermopylae/lib.utils'; import { HashMapBucketList } from "../data-structures/bucket-list/hash-map-bucket-list.js"; import { EXPIRES_AT_SYM } from "../constants.js"; class BucketGarbageCollector { static EVICTION_TIMEOUT = 1; buckets; evictionTimer; entryExpiredCb; constructor(entryExpiredCb) { this.buckets = new HashMapBucketList(); this.evictionTimer = new EvictionTimer(this.evictionTimerHandler); this.entryExpiredCb = entryExpiredCb || BucketGarbageCollector.defaultEntryExpiredCallback; } get idle() { return this.evictionTimer.idle; } get size() { return this.buckets.size; } manage(entry) { this.buckets.add(entry[EXPIRES_AT_SYM], entry); this.evictionTimer.restart(entry[EXPIRES_AT_SYM]); } update(oldExpiration, entry) { this.buckets.move(oldExpiration, entry[EXPIRES_AT_SYM], entry); this.evictionTimer.synchronize(entry[EXPIRES_AT_SYM]); } leave(entry) { this.buckets.remove(entry[EXPIRES_AT_SYM], entry); if (this.buckets.numberOfBuckets === 0) { this.evictionTimer.stop(); } } clear() { this.buckets.clear(); this.evictionTimer.stop(); } setEntryExpiredCallback(cb) { this.entryExpiredCb = cb; } evictionTimerHandler = () => { let now = chrono.unixTime(); let evictedBucketId; while (true) { evictedBucketId = now; this.buckets.dropBucket(now, this.entryExpiredCb); now = chrono.unixTime(); if (evictedBucketId === now) { break; } } if (this.buckets.numberOfBuckets === 0) { return this.evictionTimer.stop(); } this.evictionTimer.startAfter(BucketGarbageCollector.EVICTION_TIMEOUT, now); }; static defaultEntryExpiredCallback() { return undefined; } } class EvictionTimer { evictionInterval; onTick; constructor(onTick) { this.evictionInterval = { timeoutId: null, willTickOn: -1 }; this.onTick = onTick; } get idle() { return this.evictionInterval.timeoutId == null; } startAt(startTimestamp) { this.evictionInterval.willTickOn = startTimestamp; this.evictionInterval.timeoutId = setTimeout(this.onTick, chrono.secondsToMilliseconds(startTimestamp - chrono.unixTime())); } startAfter(timeout, now) { this.evictionInterval.willTickOn = now + timeout; this.evictionInterval.timeoutId = setTimeout(this.onTick, chrono.secondsToMilliseconds(timeout)); } synchronize(withTimestamp) { if (this.evictionInterval.willTickOn > withTimestamp) { this.stop(); this.startAt(withTimestamp); } } restart(startTimestamp) { if (this.evictionInterval.timeoutId == null) { this.startAt(startTimestamp); return; } this.synchronize(startTimestamp); } stop() { clearTimeout(this.evictionInterval.timeoutId); this.evictionInterval.timeoutId = null; this.evictionInterval.willTickOn = -1; } } export { BucketGarbageCollector };