|
|
|
|
|
|
|
|
|
|
|
|
|
|
class LRUCache { |
|
|
constructor(maxSize = 500) { |
|
|
this.maxSize = maxSize |
|
|
this.cache = new Map() |
|
|
this.hits = 0 |
|
|
this.misses = 0 |
|
|
this.evictions = 0 |
|
|
this.lastCleanup = Date.now() |
|
|
this.cleanupInterval = 5 * 60 * 1000 |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
get(key) { |
|
|
|
|
|
if (Date.now() - this.lastCleanup > this.cleanupInterval) { |
|
|
this.cleanup() |
|
|
} |
|
|
|
|
|
const item = this.cache.get(key) |
|
|
if (!item) { |
|
|
this.misses++ |
|
|
return undefined |
|
|
} |
|
|
|
|
|
|
|
|
if (item.expiry && Date.now() > item.expiry) { |
|
|
this.cache.delete(key) |
|
|
this.misses++ |
|
|
return undefined |
|
|
} |
|
|
|
|
|
|
|
|
this.cache.delete(key) |
|
|
this.cache.set(key, { |
|
|
...item, |
|
|
lastAccessed: Date.now() |
|
|
}) |
|
|
|
|
|
this.hits++ |
|
|
return item.value |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
set(key, value, ttl = 5 * 60 * 1000) { |
|
|
|
|
|
if (this.cache.size >= this.maxSize && !this.cache.has(key)) { |
|
|
const firstKey = this.cache.keys().next().value |
|
|
this.cache.delete(firstKey) |
|
|
this.evictions++ |
|
|
} |
|
|
|
|
|
this.cache.set(key, { |
|
|
value, |
|
|
createdAt: Date.now(), |
|
|
lastAccessed: Date.now(), |
|
|
expiry: ttl ? Date.now() + ttl : null |
|
|
}) |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
cleanup() { |
|
|
const now = Date.now() |
|
|
let cleanedCount = 0 |
|
|
|
|
|
for (const [key, item] of this.cache.entries()) { |
|
|
if (item.expiry && now > item.expiry) { |
|
|
this.cache.delete(key) |
|
|
cleanedCount++ |
|
|
} |
|
|
} |
|
|
|
|
|
this.lastCleanup = now |
|
|
if (cleanedCount > 0) { |
|
|
console.log(`🧹 LRU Cache: Cleaned ${cleanedCount} expired items`) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
clear() { |
|
|
const { size } = this.cache |
|
|
this.cache.clear() |
|
|
this.hits = 0 |
|
|
this.misses = 0 |
|
|
this.evictions = 0 |
|
|
console.log(`🗑️ LRU Cache: Cleared ${size} items`) |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
getStats() { |
|
|
const total = this.hits + this.misses |
|
|
const hitRate = total > 0 ? ((this.hits / total) * 100).toFixed(2) : 0 |
|
|
|
|
|
return { |
|
|
size: this.cache.size, |
|
|
maxSize: this.maxSize, |
|
|
hits: this.hits, |
|
|
misses: this.misses, |
|
|
evictions: this.evictions, |
|
|
hitRate: `${hitRate}%`, |
|
|
total |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
printStats() { |
|
|
const stats = this.getStats() |
|
|
console.log( |
|
|
`📊 LRU Cache Stats: Size: ${stats.size}/${stats.maxSize}, Hit Rate: ${stats.hitRate}, Hits: ${stats.hits}, Misses: ${stats.misses}, Evictions: ${stats.evictions}` |
|
|
) |
|
|
} |
|
|
} |
|
|
|
|
|
module.exports = LRUCache |
|
|
|