UNPKG

@dbs-portal/core-module-registry

Version:

Core module registry system for automatic module discovery and registration

277 lines 6.92 kB
/** * Module Cache * * High-performance caching system for module registry with TTL support, * memory management, and cache statistics. */ export class ModuleCache { cache = new Map(); options; stats; cleanupTimer = null; constructor(defaultTTL = 5 * 60 * 1000, options = {}) { this.options = { defaultTTL, maxSize: 1000, cleanupInterval: 60 * 1000, // 1 minute enableStats: true, ...options }; this.stats = { hits: 0, misses: 0, sets: 0, deletes: 0, evictions: 0, size: 0, hitRate: 0 }; // Start cleanup timer this.startCleanupTimer(); } /** * Get value from cache */ get(key) { const entry = this.cache.get(key); if (!entry) { this.updateStats('miss'); return null; } // Check if entry has expired if (Date.now() > entry.expiry) { this.cache.delete(key); this.updateStats('miss'); return null; } this.updateStats('hit'); return entry.value; } /** * Set value in cache */ set(key, value, ttl) { const actualTTL = ttl ?? this.options.defaultTTL; const expiry = Date.now() + actualTTL; // Check if we need to evict entries due to size limit if (this.cache.size >= this.options.maxSize && !this.cache.has(key)) { this.evictOldest(); } const entry = { value, expiry, timestamp: Date.now() }; this.cache.set(key, entry); this.updateStats('set'); } /** * Check if key exists in cache (without updating access time) */ has(key) { const entry = this.cache.get(key); if (!entry) { return false; } // Check if expired if (Date.now() > entry.expiry) { this.cache.delete(key); return false; } return true; } /** * Delete value from cache */ delete(key) { const deleted = this.cache.delete(key); if (deleted) { this.updateStats('delete'); } return deleted; } /** * Clear all cache entries */ clear() { this.cache.clear(); this.resetStats(); } /** * Get cache size */ size() { return this.cache.size; } /** * Get all cache keys */ keys() { return Array.from(this.cache.keys()); } /** * Get cache statistics */ getStats() { this.updateHitRate(); return { ...this.stats, size: this.cache.size }; } /** * Reset cache statistics */ resetStats() { this.stats = { hits: 0, misses: 0, sets: 0, deletes: 0, evictions: 0, size: this.cache.size, hitRate: 0 }; } /** * Get cache entries that match a pattern */ getByPattern(pattern) { const results = []; const now = Date.now(); for (const [key, entry] of this.cache.entries()) { // Skip expired entries if (now > entry.expiry) { this.cache.delete(key); continue; } if (pattern.test(key)) { results.push({ key, value: entry.value }); } } return results; } /** * Set multiple values at once */ setMany(entries) { entries.forEach(({ key, value, ttl }) => { this.set(key, value, ttl); }); } /** * Get multiple values at once */ getMany(keys) { return keys.map(key => ({ key, value: this.get(key) })); } /** * Delete multiple keys at once */ deleteMany(keys) { let deletedCount = 0; keys.forEach(key => { if (this.delete(key)) { deletedCount++; } }); return deletedCount; } /** * Get cache memory usage estimate (in bytes) */ getMemoryUsage() { let totalSize = 0; for (const [key, entry] of this.cache.entries()) { // Rough estimate: key size + value size + overhead totalSize += key.length * 2; // UTF-16 characters totalSize += JSON.stringify(entry.value).length * 2; totalSize += 64; // Overhead for entry object } return totalSize; } /** * Cleanup expired entries */ cleanup() { const now = Date.now(); let cleanedCount = 0; for (const [key, entry] of this.cache.entries()) { if (now > entry.expiry) { this.cache.delete(key); cleanedCount++; } } return cleanedCount; } /** * Destroy cache and cleanup resources */ destroy() { if (this.cleanupTimer) { clearInterval(this.cleanupTimer); this.cleanupTimer = null; } this.clear(); } /** * Start automatic cleanup timer */ startCleanupTimer() { if (this.options.cleanupInterval > 0) { this.cleanupTimer = setInterval(() => { this.cleanup(); }, this.options.cleanupInterval); } } /** * Evict oldest entry when cache is full */ evictOldest() { let oldestKey = null; let oldestTimestamp = Date.now(); for (const [key, entry] of this.cache.entries()) { if (entry.timestamp < oldestTimestamp) { oldestTimestamp = entry.timestamp; oldestKey = key; } } if (oldestKey) { this.cache.delete(oldestKey); this.updateStats('eviction'); } } /** * Update cache statistics */ updateStats(operation) { if (!this.options.enableStats) { return; } switch (operation) { case 'hit': this.stats.hits++; break; case 'miss': this.stats.misses++; break; case 'set': this.stats.sets++; break; case 'delete': this.stats.deletes++; break; case 'eviction': this.stats.evictions++; break; } } /** * Update hit rate calculation */ updateHitRate() { const total = this.stats.hits + this.stats.misses; this.stats.hitRate = total > 0 ? (this.stats.hits / total) * 100 : 0; } } //# sourceMappingURL=ModuleCache.js.map