From 46d560af2430e50bbe3f3af9e814133bc8e9df3a Mon Sep 17 00:00:00 2001 From: Dorian Date: Mon, 9 Mar 2026 07:38:04 +0000 Subject: [PATCH] fix: replace TTS FIFO cache with LRU eviction, add database indexes TTS audioCache now tracks lastAccess timestamp per entry and evicts the least-recently-used entry when full (was FIFO, deleting commonly used phrases). Adds 6 new database indexes for bets, bot type/active filtering, payment status lookups, and tournament entries. Co-Authored-By: Claude Opus 4.6 --- frontend/src/game/tts.ts | 19 ++++++++++++------- server/src/db/startup.ts | 6 ++++++ 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/frontend/src/game/tts.ts b/frontend/src/game/tts.ts index 5c307be..337d6a3 100644 --- a/frontend/src/game/tts.ts +++ b/frontend/src/game/tts.ts @@ -120,7 +120,7 @@ const _pending = new Map() +const audioCache = new Map() const MAX_CACHE = 50 const activeSources: Set = new Set() @@ -265,7 +265,7 @@ async function _generateAndCache(text: string, profile: string): Promise= MAX_CACHE) { - const oldest = audioCache.keys().next().value - if (oldest) audioCache.delete(oldest) + let lruKey: string | undefined + let lruTime = Infinity + for (const [k, v] of audioCache) { + if (v.lastAccess < lruTime) { lruTime = v.lastAccess; lruKey = k } + } + if (lruKey) audioCache.delete(lruKey) } - audioCache.set(key, buf) + audioCache.set(key, { buf, lastAccess: Date.now() }) return buf } @@ -355,7 +359,8 @@ export function kokoroSpeak( const key = _cacheKey(text, profileName) const cached = audioCache.get(key) if (cached) { - _playBuffer(cached, dest, volume) + cached.lastAccess = Date.now() + _playBuffer(cached.buf, dest, volume) return true } // Generate in worker — will play when ready diff --git a/server/src/db/startup.ts b/server/src/db/startup.ts index 7ad7bd6..dbc8e98 100644 --- a/server/src/db/startup.ts +++ b/server/src/db/startup.ts @@ -182,6 +182,12 @@ export function runMigrations() { CREATE INDEX IF NOT EXISTS idx_payments_status ON payments(status); CREATE INDEX IF NOT EXISTS idx_payments_bot ON payments(bot_id); CREATE INDEX IF NOT EXISTS idx_tournament_matches_tournament ON tournament_matches(tournament_id); + CREATE INDEX IF NOT EXISTS idx_bets_fight ON bets(fight_id); + CREATE INDEX IF NOT EXISTS idx_bets_bettor ON bets(bettor_pubkey, created_at); + CREATE INDEX IF NOT EXISTS idx_bots_type_active ON bots(bot_type, is_active); + CREATE INDEX IF NOT EXISTS idx_payments_status_created ON payments(status, created_at); + CREATE INDEX IF NOT EXISTS idx_tournament_entries_tournament ON tournament_entries(tournament_id); + CREATE UNIQUE INDEX IF NOT EXISTS idx_analytics_date_metric ON analytics(date, metric); `) // Run PRAGMA optimize on startup for query planner stats