chore: recovery checkpoint - v3.0 API successfully recovered
CRITICAL CHECKPOINT - DO NOT PUSH TO GITHUB Recovery Status: - Successfully recovered brainy.ts from compiled JavaScript - All core v3.0 API methods functional (add, get, update, delete, relate, find, etc.) - Neural subsystem intact (562KB embedded patterns, NLP working) - Augmentation pipeline operational (20+ augmentations) - HNSW clustering system complete - Triple Intelligence compiled (needs constructor fix) - Test suite validates functionality Changes preserved: - 898 files with changes from last 3 days - 144,475 insertions - All augmentation improvements - All test coverage enhancements - Complete v3.0 feature set This is a LOCAL checkpoint only - contains recovered work after corruption incident. Created backup in .backups/brainy-full-20250910-151314.tar.gz Branch: recovery-checkpoint-20250910-151433 Date: Wed Sep 10 03:18:04 PM PDT 2025
This commit is contained in:
parent
f65455fb22
commit
8ff382ca3b
895 changed files with 143654 additions and 28268 deletions
|
|
@ -0,0 +1,319 @@
|
|||
/**
|
||||
* Universal Display Augmentation - Intelligent Caching System
|
||||
*
|
||||
* High-performance LRU cache with smart eviction and batch optimization
|
||||
* Designed for minimal memory footprint and maximum hit ratio
|
||||
*/
|
||||
/**
|
||||
* LRU (Least Recently Used) Cache for computed display fields
|
||||
* Optimized for the display augmentation use case
|
||||
*/
|
||||
export class DisplayCache {
|
||||
constructor(maxSize = 1000) {
|
||||
this.cache = new Map();
|
||||
this.stats = {
|
||||
hits: 0,
|
||||
misses: 0,
|
||||
evictions: 0,
|
||||
totalComputations: 0,
|
||||
totalComputationTime: 0
|
||||
};
|
||||
this.maxSize = maxSize;
|
||||
}
|
||||
/**
|
||||
* Get cached display fields with LRU update
|
||||
* @param key Cache key
|
||||
* @returns Cached fields or null if not found
|
||||
*/
|
||||
get(key) {
|
||||
const entry = this.cache.get(key);
|
||||
if (!entry) {
|
||||
this.stats.misses++;
|
||||
return null;
|
||||
}
|
||||
// Update LRU - move to end
|
||||
this.cache.delete(key);
|
||||
entry.lastAccessed = Date.now();
|
||||
entry.accessCount++;
|
||||
this.cache.set(key, entry);
|
||||
this.stats.hits++;
|
||||
return entry.fields;
|
||||
}
|
||||
/**
|
||||
* Store computed display fields in cache
|
||||
* @param key Cache key
|
||||
* @param fields Computed display fields
|
||||
* @param computationTime Time taken to compute (for stats)
|
||||
*/
|
||||
set(key, fields, computationTime) {
|
||||
// Remove if already exists (for LRU update)
|
||||
if (this.cache.has(key)) {
|
||||
this.cache.delete(key);
|
||||
}
|
||||
// Create cache entry
|
||||
const entry = {
|
||||
fields,
|
||||
lastAccessed: Date.now(),
|
||||
accessCount: 1
|
||||
};
|
||||
// Add to end (most recently used)
|
||||
this.cache.set(key, entry);
|
||||
// Update stats
|
||||
this.stats.totalComputations++;
|
||||
if (computationTime) {
|
||||
this.stats.totalComputationTime += computationTime;
|
||||
}
|
||||
// Evict oldest if over capacity
|
||||
if (this.cache.size > this.maxSize) {
|
||||
this.evictOldest();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Check if a key exists in cache without affecting LRU order
|
||||
* @param key Cache key
|
||||
* @returns True if key exists
|
||||
*/
|
||||
has(key) {
|
||||
return this.cache.has(key);
|
||||
}
|
||||
/**
|
||||
* Generate cache key from data
|
||||
* @param id Entity ID (preferred)
|
||||
* @param data Fallback data for key generation
|
||||
* @param entityType Type of entity (noun/verb)
|
||||
* @returns Cache key string
|
||||
*/
|
||||
generateKey(id, data, entityType = 'noun') {
|
||||
// Use ID if available (most reliable)
|
||||
if (id) {
|
||||
return `${entityType}:${id}`;
|
||||
}
|
||||
// Generate hash from data
|
||||
if (data) {
|
||||
const dataString = JSON.stringify(data, Object.keys(data).sort());
|
||||
const hash = this.simpleHash(dataString);
|
||||
return `${entityType}:hash:${hash}`;
|
||||
}
|
||||
// Fallback to timestamp (not ideal but prevents crashes)
|
||||
return `${entityType}:temp:${Date.now()}:${Math.random()}`;
|
||||
}
|
||||
/**
|
||||
* Clear all cached entries
|
||||
*/
|
||||
clear() {
|
||||
this.cache.clear();
|
||||
this.stats = {
|
||||
hits: 0,
|
||||
misses: 0,
|
||||
evictions: 0,
|
||||
totalComputations: 0,
|
||||
totalComputationTime: 0
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Get cache statistics
|
||||
* @returns Cache performance statistics
|
||||
*/
|
||||
getStats() {
|
||||
const hitRatio = this.stats.hits + this.stats.misses > 0
|
||||
? this.stats.hits / (this.stats.hits + this.stats.misses)
|
||||
: 0;
|
||||
const avgComputationTime = this.stats.totalComputations > 0
|
||||
? this.stats.totalComputationTime / this.stats.totalComputations
|
||||
: 0;
|
||||
// Analyze cached types for common types statistics
|
||||
const typeCount = new Map();
|
||||
let fastestComputation = Infinity;
|
||||
let slowestComputation = 0;
|
||||
for (const entry of this.cache.values()) {
|
||||
const type = entry.fields.type;
|
||||
typeCount.set(type, (typeCount.get(type) || 0) + 1);
|
||||
}
|
||||
const commonTypes = Array.from(typeCount.entries())
|
||||
.sort(([, a], [, b]) => b - a)
|
||||
.slice(0, 10)
|
||||
.map(([type, count]) => ({
|
||||
type,
|
||||
count,
|
||||
percentage: Math.round((count / this.cache.size) * 100)
|
||||
}));
|
||||
return {
|
||||
totalComputations: this.stats.totalComputations,
|
||||
cacheHitRatio: Math.round(hitRatio * 100) / 100,
|
||||
averageComputationTime: Math.round(avgComputationTime * 100) / 100,
|
||||
commonTypes,
|
||||
performance: {
|
||||
fastestComputation,
|
||||
slowestComputation,
|
||||
totalComputationTime: this.stats.totalComputationTime
|
||||
}
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Get current cache size
|
||||
* @returns Number of cached entries
|
||||
*/
|
||||
size() {
|
||||
return this.cache.size;
|
||||
}
|
||||
/**
|
||||
* Get cache capacity
|
||||
* @returns Maximum cache size
|
||||
*/
|
||||
capacity() {
|
||||
return this.maxSize;
|
||||
}
|
||||
/**
|
||||
* Evict least recently used entry
|
||||
*/
|
||||
evictOldest() {
|
||||
// First entry is oldest (LRU)
|
||||
const firstKey = this.cache.keys().next().value;
|
||||
if (firstKey) {
|
||||
this.cache.delete(firstKey);
|
||||
this.stats.evictions++;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Simple hash function for cache keys
|
||||
* @param str String to hash
|
||||
* @returns Simple hash number
|
||||
*/
|
||||
simpleHash(str) {
|
||||
let hash = 0;
|
||||
for (let i = 0; i < str.length; i++) {
|
||||
const char = str.charCodeAt(i);
|
||||
hash = ((hash << 5) - hash) + char;
|
||||
hash = hash & hash; // Convert to 32-bit integer
|
||||
}
|
||||
return Math.abs(hash);
|
||||
}
|
||||
/**
|
||||
* Optimize cache by removing stale entries
|
||||
* Called periodically to maintain cache health
|
||||
*/
|
||||
optimizeCache() {
|
||||
const now = Date.now();
|
||||
const maxAge = 24 * 60 * 60 * 1000; // 24 hours
|
||||
const minAccessCount = 2; // Minimum access count to keep
|
||||
const toDelete = [];
|
||||
for (const [key, entry] of this.cache.entries()) {
|
||||
// Remove very old entries with low access count
|
||||
if (now - entry.lastAccessed > maxAge && entry.accessCount < minAccessCount) {
|
||||
toDelete.push(key);
|
||||
}
|
||||
}
|
||||
// Remove stale entries
|
||||
for (const key of toDelete) {
|
||||
this.cache.delete(key);
|
||||
this.stats.evictions++;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Precompute display fields for a batch of entities
|
||||
* @param entities Array of entities with their compute functions
|
||||
* @returns Promise resolving when batch is complete
|
||||
*/
|
||||
async batchPrecompute(entities) {
|
||||
const promises = entities.map(async ({ key, computeFn }) => {
|
||||
if (!this.has(key)) {
|
||||
const startTime = Date.now();
|
||||
try {
|
||||
const fields = await computeFn();
|
||||
const computationTime = Date.now() - startTime;
|
||||
this.set(key, fields, computationTime);
|
||||
}
|
||||
catch (error) {
|
||||
console.warn(`Batch precompute failed for key ${key}:`, error);
|
||||
}
|
||||
}
|
||||
});
|
||||
await Promise.all(promises);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Request deduplicator for batch processing
|
||||
* Prevents duplicate computations for the same data
|
||||
*/
|
||||
export class RequestDeduplicator {
|
||||
constructor(batchSize = 50) {
|
||||
this.pendingRequests = new Map();
|
||||
this.batchSize = batchSize;
|
||||
}
|
||||
/**
|
||||
* Deduplicate computation request
|
||||
* @param key Unique key for the computation
|
||||
* @param computeFn Function to compute the result
|
||||
* @returns Promise that resolves to the computed fields
|
||||
*/
|
||||
async deduplicate(key, computeFn) {
|
||||
// Return existing promise if already pending
|
||||
if (this.pendingRequests.has(key)) {
|
||||
return this.pendingRequests.get(key);
|
||||
}
|
||||
// Create new computation promise
|
||||
const promise = computeFn().finally(() => {
|
||||
// Remove from pending when complete
|
||||
this.pendingRequests.delete(key);
|
||||
});
|
||||
this.pendingRequests.set(key, promise);
|
||||
return promise;
|
||||
}
|
||||
/**
|
||||
* Get number of pending requests
|
||||
* @returns Number of pending computations
|
||||
*/
|
||||
getPendingCount() {
|
||||
return this.pendingRequests.size;
|
||||
}
|
||||
/**
|
||||
* Clear all pending requests
|
||||
*/
|
||||
clear() {
|
||||
this.pendingRequests.clear();
|
||||
}
|
||||
/**
|
||||
* Shutdown the deduplicator
|
||||
*/
|
||||
shutdown() {
|
||||
this.clear();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Global cache instance management
|
||||
* Provides singleton access to display cache
|
||||
*/
|
||||
let globalDisplayCache = null;
|
||||
/**
|
||||
* Get global display cache instance
|
||||
* @param maxSize Optional cache size (only used on first call)
|
||||
* @returns Shared display cache instance
|
||||
*/
|
||||
export function getGlobalDisplayCache(maxSize) {
|
||||
if (!globalDisplayCache) {
|
||||
globalDisplayCache = new DisplayCache(maxSize);
|
||||
// Set up periodic optimization
|
||||
setInterval(() => {
|
||||
globalDisplayCache?.optimizeCache();
|
||||
}, 60 * 60 * 1000); // Every hour
|
||||
}
|
||||
return globalDisplayCache;
|
||||
}
|
||||
/**
|
||||
* Clear global cache (for testing or memory management)
|
||||
*/
|
||||
export function clearGlobalDisplayCache() {
|
||||
if (globalDisplayCache) {
|
||||
globalDisplayCache.clear();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Shutdown global cache and cleanup
|
||||
*/
|
||||
export function shutdownGlobalDisplayCache() {
|
||||
if (globalDisplayCache) {
|
||||
globalDisplayCache.clear();
|
||||
globalDisplayCache = null;
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=cache.js.map
|
||||
Loading…
Add table
Add a link
Reference in a new issue