Context
Surfaced during an incident (PR #131): a cold boot rebuilding in-memory state from the full published import OOM'd at the 1536 MiB V8 old-space ceiling. Mitigated by raising the heap to 3072 MiB + container limit to 3.5Gi, but the underlying footprint is worth a real look.
The smell
- On-disk record data on
published is only ~25 MB of TOML (uncompressed blob bytes across people/projects/updates/buzz/memberships/tag-assignments).
- A cold boot building the in-memory representation needs >1.5 GB of V8 heap — roughly a 60× expansion.
- The full-text store is
better-sqlite3 FTS5 (apps/api/src/store/fts.ts), which is off-heap (native memory), so it does not explain the V8 heap blowup. The heap cost is the record maps + secondary indices.
Dataset shape (published)
- people: 31,832
- tag-assignments: 10,353
- tags: 1,005
- projects: 268
- project-memberships: 822 / project-updates: 503 / project-buzz: 112
Worth investigating
- Duplication: does each record exist in more than one in-memory structure (raw map + multiple indices + gitsheets' cached per-sheet
dataTree snapshot)? See apps/api/src/store/memory/ (loader.ts, state.ts) and apps/api/src/store/sheet-indices.ts, plus the gitsheets openStore data-tree caching noted in apps/api/src/store/public.ts / memory/reload.ts.
- Per-record overhead: 31.8k people at >40 KB heap each would be ~1.3 GB — are person objects carrying large/derived fields, retained TOML source strings, or boxed structures?
- Index sizing: how many secondary indices, and are any of them O(records) string-keyed Maps holding full objects rather than ids?
- gitsheets retention: confirm whether the parsed blob contents / tree objects are held alongside the typed record maps (a second full copy).
Goal
Bring the cold-boot heap footprint down meaningfully (target: comfortably under 1.5 GB for the current import, with margin to grow), or document why the current footprint is irreducible. This also de-risks prod, where the dataset only grows.
Related: PR #131 (the heap/limit bump mitigation).
Context
Surfaced during an incident (PR #131): a cold boot rebuilding in-memory state from the full
publishedimport OOM'd at the 1536 MiB V8 old-space ceiling. Mitigated by raising the heap to 3072 MiB + container limit to 3.5Gi, but the underlying footprint is worth a real look.The smell
publishedis only ~25 MB of TOML (uncompressed blob bytes across people/projects/updates/buzz/memberships/tag-assignments).better-sqlite3FTS5 (apps/api/src/store/fts.ts), which is off-heap (native memory), so it does not explain the V8 heap blowup. The heap cost is the record maps + secondary indices.Dataset shape (published)
Worth investigating
dataTreesnapshot)? Seeapps/api/src/store/memory/(loader.ts,state.ts) andapps/api/src/store/sheet-indices.ts, plus the gitsheetsopenStoredata-tree caching noted inapps/api/src/store/public.ts/memory/reload.ts.Goal
Bring the cold-boot heap footprint down meaningfully (target: comfortably under 1.5 GB for the current import, with margin to grow), or document why the current footprint is irreducible. This also de-risks prod, where the dataset only grows.
Related: PR #131 (the heap/limit bump mitigation).