Skip to the document
Madhuopen lab

HanuDB, tuned while I slept · part 3 of 6

adopted14 September 2026cost: local CPU; a free-tier VM for the real runs

Memory: allocators, guards and the cgroup

Why resident size was the wrong number

The question

Of 17 attempts in this theme, which ones survived two benchmark runs, the correctness suite and the gates?

adopted

The tantivy "heap" budget is not the whole story: 64 MB of arena turned into ~350 MB of resident memory with three JSON fields (columnar/fast-field writers live outside the budget). 32 MB costs ~8 % indexing speed and halves the peak.

Attempts17
Kept9
Discarded or crashed4
Best kept score37,100.2

Every run in this theme

Every run in this theme
#scorewrites/sreads/sverdictwhat changed
000511,322.518,5166,924keepHARNESS: container now pinned to 1 core (cpuset) instead of CFS quota. ENGINE: keyword field ignore_above 64 (index 226->106 MB); no delete_term for fresh ids (recovery…
001314,2159,727crashINVALID (same cause: ran on the 0001 code): mimalloc global allocator; re-test later
001527,9517,143discardmimalloc (valid re-test): writes +13% (28k/s) but rebuild peak anon 502 MB vs 408 MB glibc at 400k docs; at the 560k docs it produces the 768 MB container OOMs;…
005337,100.229,68846,364keeptantivy index heap 32 -> 48 MB (default): runs 37100 / 37000 (mean 37.05k vs 35.3k, +5%), reads 46.4k both runs, RSS ~300 MB. Rebuild replays only the tail after a…
005436,917.229,18346,702discardtantivy heap 64 MB: runs 36917 / 37106 (mean 37.0k) = same as 48 MB; 48 stays (less rebuild memory)
0071dinfoCONTAINER SOAK (768 MB, snapshots every 50): ~3 min at ~29k writes/s observed, server RSS 400-640 MB (peaks during 0.8-1.2 GB snapshot packs), no OOM, kv 2.2 GB, index…
0072b12,881infoCONTAINER SOAK 10 min (768 MB): OOM-killed after ~4 min of writes (RSS 230 -> 713 MB), snapshots grew to 2.4 GB packed in 30 s each every ~15 s of writes; sealed…
007334,839.428,73242,245keepSAFETY: memory guard (--max-rss-mb 700: writers sleep 20 ms per request while RSS is above it; status.memory_guard) + snapshots only when segments since the last one are…
0073b19,2612,856infoCONTAINER SOAK 10 min with memory guard + growth-proportional snapshots: 11.56M docs at 19.3k/s, 0 errors, no OOM (guard on twice at 713-749 MB), reads 2.9k/s over 11.5M…
007733,874.727,78441,300keepSAFETY: the rebuild's segment replay pauses while RSS is over --max-rss-mb (indexer/flushes catch up), same guard as live writes. Bench unchanged
008130,712.728,08033,594keepSAFETY: memory guard compares anon + dirty (statm resident-shared + cgroup file_dirty/writeback; io log now has anon_mb/dirty_mb) instead of resident size, which counts…
008330,984.528,38933,817keepSAFETY: the snapshot (commit, stage, pack, upload, bucket GC, prune) runs on its own tokio task, one at a time; the seal loop keeps sealing, uploading segments and…
008433,414.527,54840,531keepSAFETY: the rebuild's memory pause is bounded (10 s per segment, then continue with a warning): the 0083b soak rebuild hung forever because the rebuilt engine's own…
0085cinfoREBUILD MEMORY, same 3.8M-doc state (919 MB snapshot + ~700k-record tail), one core: FRESH PROCESS peaks at 259 MB heap (heaptrack; 101 MB fjall memtable copies, 43 MB…
008629,891.525,87534,532discardMEMORY: mallopt(M_ARENA_MAX, 1). Bench: writes -7% (25.9k), peak rss 385 (better), old-engine residue 5 MB (vs 30-104) BUT the 3.8M-doc in-process rebuild ballooned to…
008735,081.134,28335,900keepMEMORY+SPEED: jemalloc (tikv-jemallocator, background_thread, 1 s dirty/muzzy decay, narenas 2) as the global allocator. Writes +22% (34.3k/s both runs, p99 4.6 ms),…
010635,682.234,68236,711keepOBSERVABILITY: /metrics now exposes hanudb_index_lag, hanudb_bucket_lag_txn/segments, kv_flushed_txn, index_txn, snapshot_seq, rss_anon_mb, memory_guard, index_segments,…
hanudbmemoryautonomous loop