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 <noreply@anthropic.com>
This commit is contained in:
Dorian
2026-03-09 07:38:04 +00:00
co-authored by Claude Opus 4.6
parent fbc61ef154
commit 46d560af24
2 changed files with 18 additions and 7 deletions
+12 -7
View File
@@ -120,7 +120,7 @@ const _pending = new Map<number, {
// --- Audio state (main thread only) ---
let _audioCtx: AudioContext | null = null
const audioCache = new Map<string, AudioBuffer>()
const audioCache = new Map<string, { buf: AudioBuffer; lastAccess: number }>()
const MAX_CACHE = 50
const activeSources: Set<AudioBufferSourceNode> = new Set()
@@ -265,7 +265,7 @@ async function _generateAndCache(text: string, profile: string): Promise<AudioBu
if (!_workerReady) return null
const key = _cacheKey(text, profile)
const cached = audioCache.get(key)
if (cached) return cached
if (cached) { cached.lastAccess = Date.now(); return cached.buf }
// Dedup: if already generating this exact audio, reuse the in-flight promise
const existing = _inflight.get(key)
@@ -288,12 +288,16 @@ async function _doGenerate(text: string, profile: string, key: string): Promise<
const buf = ctx.createBuffer(1, raw.audio.length, raw.sampleRate)
buf.getChannelData(0).set(raw.audio)
// Evict oldest if cache is full
// Evict least-recently-used if cache is full
if (audioCache.size >= 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 }
}
audioCache.set(key, buf)
if (lruKey) audioCache.delete(lruKey)
}
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
+6
View File
@@ -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