cachedb_perf: high-performance local memory cache built on modern kernel features - #4118
Open
Lt-Flash wants to merge 7 commits into
Open
cachedb_perf: high-performance local memory cache built on modern kernel features#4118Lt-Flash wants to merge 7 commits into
Lt-Flash wants to merge 7 commits into
Conversation
Lt-Flash
pushed a commit
to Lt-Flash/opensips
that referenced
this pull request
Jul 24, 2026
The isolated-cache, 50k end-to-end and 100k three-way benchmarks are all published in PR OpenSIPS#4118; only the two-socket huge-page-arena end-to-end number is still outstanding.
Lt-Flash
force-pushed
the
feature/cachedb-perf-devel
branch
from
July 25, 2026 00:05
cf2d1e4 to
642c828
Compare
Lt-Flash
marked this pull request as ready for review
July 26, 2026 07:34
This was referenced Jul 26, 2026
topology_hiding: keep the dialog-less state in a shared store (fixes long Contact / SUBSCRIBE)
#4114
Open
Lt-Flash
force-pushed
the
feature/cachedb-perf-devel
branch
3 times, most recently
from
August 10, 2026 09:12
d51c274 to
2fc31a9
Compare
Lt-Flash
force-pushed
the
feature/cachedb-perf-devel
branch
from
August 21, 2026 02:47
0585839 to
16790b0
Compare
Lt-Flash
pushed a commit
to Lt-Flash/opensips
that referenced
this pull request
Aug 23, 2026
…penSIPS#4118 The upstream PR keeps the module description and the headline numbers; the index-structure shootout, concurrency and read-protocol experiments, memory-backing tiers, cachedb_local / cachedb_redis comparisons, the 50k and 100k topology-hiding runs, the huge-page arena measurements and the soak findings, with their graphs, live here.
A local cachedb backend (URL scheme perf://) built for the SIP hot path: lock-free reads (per-bucket seqlock + copy-out validation), short locked writes, named collections that grow at runtime under a maintenance timer, instant expiry with cheap background reclaim, and a size-class slab arena with optional huge-page backing (memory_backing=auto|core|own-hg|own, with full reclaim - retire, re-cut, give-back - in the own modes). Optional surfaces, each degrading explicitly when absent: persistence to any db_* backend (perf_save/perf_load, db_mode), cluster warm-up sync over a sharing tag, and cross-node pull-on-miss over the clusterer bin links, the clusterer_controller plane, or the module's own udp/tcp sockets (pull_transport, with bin-capability HELLO peer discovery). Keys are hashed with MurmurHash3. One addition outside the module: an optional CACHEDB_CAP_GET_BUF cachedb capability - an allocation-free read into the caller's buffer - that backends and consumers may ignore. Ships with perf_stats/introspection MI, statistics, events, admin docs, a benchmark/soak harness (bench/), and the full measurement study (doc/STUDY.md, doc/PR-NOTES.md).
Lt-Flash
force-pushed
the
feature/cachedb-perf-devel
branch
from
August 24, 2026 15:35
0fc5ee2 to
1eaa330
Compare
|
Tested and verified on commit 1eaa330 (branch feature/cachedb-perf-latest).
|
added 6 commits
August 25, 2026 21:12
Three complete deployment shapes - standalone, clustered over the stock clusterer (bin/udp/tcp pull transports), and clusterer_controller-managed (clctr) - with the pull modes, persistence, memory backings and the failover hooks explained around each.
The earlier cross-node latency/convergence figures came from three containers on one host - a single-kernel bridge with no real wire. Re-run on three physical hosts (one container per host, host networking, same binary): 30k-key thirds convergence takes 10.7-14.2 s to 99.9% (udp/tcp/ bin), warm p50 is ~197 us including one real LAN round trip, and the transport differences live entirely in the miss-path tail, where the module-owned udp/tcp sockets halve bin's p99. Zero failures across 25M requests. STUDY.md gains the authoritative section + 4 figures; the archived PR-NOTES numbers are banner-marked as superseded.
Every MI command's exact invocation syntax and response shape, pulled directly from the mi_export_t recipes and their handlers rather than paraphrased - all 16 commands across read/introspect, single-key ops, bulk ops, cross-node pull (CP-15), and persistence/cluster sync (CP-19), plus the two invocation surfaces and the named-params-only / glob-first gotchas that cost real debugging time otherwise.
…ot written past pcache_htable_new() computed nbuckets = 1U << size_log2 and then allocated nbuckets / PCACHE_SEG_SIZE segments into ht->seg[], a FIXED array of PCACHE_NSEGS pointers sized for 2^24 buckets. A size_log2 of 25 asks for 8192 segments and writes past a 4096-entry directory; 32 or more is not a defined shift at all. Every caller in the tree is gated below the ceiling today, so this is latent rather than live - which is exactly the kind of latent a later caller trips, since nothing in the function's contract says where the limit is. Refuse above the ceiling and name it, and derive PCACHE_NSEGS from the new PCACHE_MAX_SIZE_LOG2 rather than repeating 24 in two places, so the guard and the directory cannot drift apart. (cherry picked from commit 58cd08c224c0b4a3204b4676c8b14e3b3248df44)
A table at its target load factor keeps almost nothing in the leg; a table that has stopped growing puts everything there, and the leg is a chain per hash bucket under ONE lock, so its occupancy is the difference between a table that performs and one that does not. ovf_count was already maintained and reported nowhere, so a table sitting at 81 entries per bucket looked identical from the outside to one at 4. An accessor beside pcache_ht_nbuckets(), which is where a caller already goes for the shape of a table. (cherry picked from commit 81080fe7c6735fb0542d8b39c0b4de151814d25b)
A key lives in its bucket OR in the overflow leg, never both, so any operation that misses the bucket must walk the chain for its hash under the one leg lock - and that includes every store, not only operations on records that are actually in the leg. A table whose leg grew during a write burst therefore taxes all of its subsequent writes. Profiled on a node applying replicas at about 118,000 records a second: the leg lookup was 17.0% of the applying thread, the largest cost outside the cipher, ahead of the store itself at 12.1%. Chain length is leg size divided by the number of heads, so widening the head array shortens every chain in proportion. 16,384 heads is 131,072 bytes, the largest power of two that still fits inside the single 256 KB region slot that 1,024 heads already occupied - sixteen times the chains for no additional memory. Nothing else changes: the array is one allocation, the index is a mask, and both follow the constant. (cherry picked from commit 20fc9c0b3ae0705a0178a952030a7830900d5a41)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
cachedb_perfis a local in-memorycachedbbackend, selected by URL scheme (perf://). It implements the standardcachedb_funcsvtable, so every module that takes acachedb_url(topology_hiding,dialogprofiles,sql_cacher, ...) and the corecache_*script functions work unchanged — changing the URL is the whole migration.It exists because
cachedb_local's single fixed-size table and per-bucket locking become the bottleneck at high churn: at 50k resident entries and the topology-hiding access pattern,cachedb_perfdoes 448 ns/op vs 1,013 ns (2.3×; 7.9× vscachedb_local's 512-bucket default), pure writes are 5.6–9.9× faster and stay flat with concurrency, and end-to-end topology hiding sustains 6,000 CPS wherecachedb_localbreaks at ~3,900.How: lock-free reads (per-bucket version + copy-out validation; writers hold a bucket lock for ~hundreds of ns), named collections that grow at runtime, instant expiry with a cheap background sweep, and records in a size-class slab arena — in core shm or a dedicated reservation (
memory_backing), with full reclaim in the dedicated modes. Keys hash with MurmurHash3 (the core's hash collides on sequential keys).Optional, each degrading explicitly when absent: persistence to any
db_*backend, cluster warm-up sync, and cross-node pull-on-miss — over the clusterer's bin links, theclusterer_controllerplane, or the module's own udp/tcp sockets.Outside the module, one optional cachedb capability:
CACHEDB_CAP_GET_BUF, an allocation-free read into the caller's buffer. Backends and consumers that do not know it are unaffected.Usage
From the script the backend id is
perf(orperf:<group>when a grouped URL is declared):cache_store("perf", "call-$ci", "$var(state)", 3600);Complete worked configurations - standalone, clustered over the stock clusterer, and clusterer_controller-managed, with every pull mode and transport explained: Configuration examples.
Parameters
cache_collectionsdefault=14name[=log2(buckets)];...— the size is only a starting point, tables growcachedb_urlperf://perf:///namepicks the collection; repeatablememory_backingautocoreshm,own-hg(dedicated huge-page arena),own(dedicated slab in shm, full reclaim)arena_hugepage_mb00= plain shmarena_hugepage_cap_mb/arena_profilereclaim_keep,reclaim_quiet_s,reclaim_cooloff_s,reclaim_givebackexpiry_sweep_period1growth_load_factor/growth_budget2/4096db_url,db_table,db_mode,persist_collectionssync_cluster_id,sync_shtagreplicate_collections,pull_on_misspull_transportbinbin,clctr, or module-ownedudp/tcpsocketspull_bind,pull_portpull_timeout_ms,pull_negative_msevent_expired_collections,arena_selftest,htable_selftestMI (
perf_stats, introspection,perf_save/perf_load/perf_sync), statistics and events are documented in the module README. All 16 MI commands with real invocation + response examples: MI examples.Docs, testing
Everything measured, with graphs, lives in the branch: doc/STUDY.md (the study), doc/PR-NOTES.md (progress notes), bench/README.md (the test/benchmark harness). Builds clean with gcc and clang under
-Werror; no new dependencies.