diff --git a/backend/database/database.go b/backend/database/database.go index a82fa72..893eea8 100644 --- a/backend/database/database.go +++ b/backend/database/database.go @@ -54,9 +54,19 @@ type DB struct { // form is silently ignored, which is why WAL was never actually on. const ( writeDSNParams = "?_pragma=busy_timeout(5000)&_pragma=journal_mode(WAL)" - readDSNParams = "?_pragma=busy_timeout(5000)&_pragma=journal_mode(WAL)" + + // The read pool's own page cache and mapping bound, sized by + // measurement rather than by appetite (#283). On a 50 000-track + // library, halving the cache and quartering the mapping moved no + // query — 1 172 → 1 197 ms for the whole track list, 106 → 124 ms + // for the album list, 6 → 8 ms for an FTS search, all inside the + // run-to-run spread — and the RSS of the database mapping was 46 MB + // under both settings, because a mapping's cost is what the working + // set touches, not the bound. The bound is what matters on a + // phone, where five connections' worth of address space is the + // thing the low-memory killer reads (cf. #52). + readDSNParams = "?_pragma=busy_timeout(5000)&_pragma=journal_mode(WAL)" + "&_pragma=query_only(true)&_pragma=synchronous(NORMAL)" + - "&_pragma=cache_size(-8000)&_pragma=mmap_size(67108864)" + "&_pragma=cache_size(-2000)&_pragma=mmap_size(16777216)" // readPoolConns bounds concurrent read connections. A handful is // plenty for interactive search + art/lookup fan-out and keeps WAL // reader overhead small. @@ -354,8 +364,8 @@ func applyPRAGMAs(ctx context.Context, db *sql.DB) error { pragmas := []string{ "PRAGMA foreign_keys = ON", "PRAGMA synchronous = NORMAL", - "PRAGMA cache_size = -8000", - "PRAGMA mmap_size = 67108864", + "PRAGMA cache_size = -2000", + "PRAGMA mmap_size = 16777216", } for _, pragma := range pragmas {