Repository navigation
Commit fea6b19
committed
cachedb_perf: new high-performance local cache backend (perf://)
A from-scratch cachedb backend for large, high-churn local caches,
selected by URL scheme (perf://), as a drop-in alternative to
cachedb_local. It implements the same cachedb_funcs vtable, so any module
taking a cachedb_url works unchanged.
Motivation: cachedb_local sizes its hash table once from cache_collections
and never resizes, so a large cache degrades to long lock-held chain walks
(measured while benchmarking topology_hiding's th_store backend). This
module keeps lookups flat as the cache grows.
Core design:
- 64-byte, one-cache-line buckets with 1-byte per-slot tags (SWAR scan)
and a per-bucket seqlock: readers take no locks, snapshot optimistically
and re-check, with a bounded retry and a lock fallback. Legal because shm
is mapped once before fork and never unmapped, so a stale pointer read is
bounded garbage the version re-check discards.
- Slab arena: entries live in fixed-size cells in class-bound chunks that
are never returned to shm; per-process bump allocation with no atomics on
the fast path (byte 0 of every cell is the immutable class id).
- Runtime growth: a segmented directory + linear hashing splits one bucket
at a time from the single maintenance timer - buckets never move, the
routing word is re-checked on a miss, and the load-factor cliff cannot
form (growth_load_factor).
- Native int64 counters (add/sub) accumulated under the bucket lock; a
versionless TTL bump that refreshes expiry with one atomic store; an
overflow side table for full buckets.
- No allocator call ever happens under a bucket lock.
This is also the first backend to implement the allocation-free read added
in the previous commit. The two entry points share one implementation, so
they cannot diverge over which record they return: the optimistic loop,
the lock fallback, the re-route retry, the overflow leg and the expiry
check all live in one function, which copies into the caller's buffer, and
the allocating entry point is a thin wrapper that passes the per-process
scratch and then copies into pkg. get() and get_counter() keep the
documented cachedb behaviour byte for byte - in particular get_counter()
still returns only {-2,-1,0} and never the new too-small code. Measured
with the cachedb-vtable benchmark, 50 000 entries, 200-byte values, 100%
reads, one worker, alternating runs: 397.7 ns/op via get() against
290.1 ns/op via get_buf() at the median, the new path faster in every pair.
Operability and durability:
- Per-collection expiry sweep (min-expires hints), per-process sharded
statistics, and a huge-page arena (hugetlb -> THP -> MADV_COLLAPSE -> 4K,
detected by trying; arena_hugepage_mb), measured +7-13%.
- Introspection MI (all lock-free): perf_keys, perf_scan (cursored, Redis
SCAN semantics), perf_dump, perf_get, perf_set, perf_ttl, perf_del, plus
perf_stats and perf_stats_reset; glob script functions perf_del/
perf_mget/perf_mget_json. perf_stats reports hit rate, expired and
destroyed counts, and when each collection last synced.
- Observability events: E_CACHEDB_PERF_EXPIRED / NOMEM / GROWN /
MEM_DEGRADED, each gated by evi_probe_event so a subscriber-less cluster
pays nothing, none on the hot path.
- DB persistence: whole-collection save/load to any db_* backend
(perf_save/perf_load, db_mode startup-load / shutdown-save), TTLs kept as
absolute wall-clock time so they survive a restart. A save/load is a full
blocking snapshot written in one transaction - a maintenance/bootstrap
operation, not per-request - and rows that no longer exist in memory are
dropped at load rather than resurrected.
- Cluster sync: perf_sync saves a collection then signals peers over
clusterer to reload it from the shared DB (one message per sync, not per
operation), raising E_CACHEDB_PERF_SYNCED. A pull-from-DB refresh for
single-writer/read-replica topologies - deliberately not per-operation
replication, which would tax the lock-free path this module exists for.
v1 is single-node in-memory with optional db_* persistence and the DB-
backed cluster refresh; per-operation replication is out of scope.1 parent 3232f3f commit fea6b19
31 files changed
Lines changed: 9889 additions & 0 deletions
File tree
- modules/cachedb_perf
- bench
- doc
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
0 commit comments