db_redis: new Redis (server/cluster) DB backend module#4111
Open
Lt-Flash wants to merge 7 commits into
Open
Conversation
added 6 commits
July 15, 2026 15:07
Implements the OpenSIPS db_api on top of Redis, storing rows as hashes at <table>:<pk> with driver-side schemas provisioned as schema:<table> hashes (see scripts/redis/README). Phase 1 scope: - structured ops: query (pk fast path + scan-filter, all operators, single-column ORDER BY), insert, update, delete (incl. bulk OR pk-deletes and truncate), replace, insert_update, last_inserted_id (auto-increment emulated via INCR seq:<table>) - dual transport mode, auto-detected per connection via CLUSTER INFO: single endpoint (standalone or LB-fronted sentinel master, with READONLY-triggered reconnect) and Redis Cluster (topology from CLUSTER SHARDS with CLUSTER SLOTS fallback, eager connections to all masters, MOVED served from the warm pool, ASK/TRYAGAIN handling, deferred topology refresh) - typed results from declared schemas (int/bigint/double/string/blob/ datetime), binary-safe blobs, NULL as absent hash field The module is optional and excluded from the default build (needs hiredis); enable by removing db_redis from exclude_modules. Verified against redis-server 5.x with the dialog module in db_mode 1: table version check, full-table load of seeded dialogs, and the shutdown update flush.
The cluster probe queried CLUSTER INFO for cluster_enabled, but that field is only reported by the general INFO command (Cluster section), not by CLUSTER INFO - so a real cluster was misdetected as a single endpoint. Probe with INFO CLUSTER instead, which reliably reports cluster_enabled:0/1 on both standalone and cluster instances. Also log a one-line summary of the discovered master pool and its warm connection count after cluster topology load (per-master detail at debug level). Verified against a live 3-master/3-replica Redis 8 cluster: seeded with a single node, all three masters are discovered and their TCP connections warmed up, and dialog rows load and flush across the non-seed masters via the slot map.
DocBook admin guide covering the data model (schema/row/sequence hashes), the single-endpoint and Redis Cluster deployment modes, the exported parameters, usage examples and limitations, plus the generated README and contributors file.
Adds ready-to-load schema definitions matching the canonical SQL layouts: - dispatcher (dispatcher table, v9) - usrloc (location table, v1013) - clusterer (clusterer v4, clusterer_bridge v1) Each file is self-contained and also provisions the version-table schema. The tm module keeps no DB table, so it has none. usrloc's raw-query paths remain unsupported; the structured contact path works. Verified: all schemas pass the column/type-field consistency check, and the dispatcher table loads end-to-end through db_redis (schema parsed, destination row read and activated).
get_domain_db_ucontacts() used a raw SQL query (the only raw_query in usrloc) to fetch all live contacts, which excluded DB backends that do not implement raw queries, such as db_redis. When the bound DB module lacks DB_CAP_RAW_QUERY, build the equivalent query through the structured DB API (column projection plus an 'expires > now' filter) and apply the contact_id modulo partitioning client-side while iterating the rows. SQL backends keep the exact same raw-query path as before, so there is no behaviour change for existing setups; this also makes the code work with db_text. Consequently DB_CAP_RAW_QUERY is no longer a hard requirement in sql-only mode. Verified: usrloc in sql-only mode over db_redis loads the location schema and returns live contacts to nathelper for pinging.
Update the module limitations and the scripts/redis README now that usrloc no longer depends on raw queries, and list dispatcher, clusterer and usrloc among the supported consumers.
Lt-Flash
marked this pull request as ready for review
July 15, 2026 05:57
Marshal DB values through the db_ut helpers (db_str2int/bigint/double, db_int2str/bigint2str/double2str) instead of raw strtoll/snprintf, the same way db_sqlite and the other DB drivers do. This keeps type conversion and its error handling consistent across the DB backends. No functional change: the memory model was already correct (per-process pkg allocations, pool_con-compatible connection header, driver-owned result values freed via VAL_FREE).
Author
|
Refactored the module to comply with OpenSIPS conventions after an internal review of the memory model and DB API usage:
The rest of the model was already compliant and was verified during the review:
Remaining Regression-tested after the change: dialog load + shutdown flush over |
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.
Overview
This PR adds
db_redis, a new optional OpenSIPS DB API backend that stores data in a Redis server or a Redis Cluster. Unlikecachedb_redis(which exposes Redis through the key-value NoSQL interface),db_redispresents Redis as a relational-style backend behind the standarddb_urlmechanism: a module is switched to Redis simply by pointing itsdb_urlat aredis://URL — no code change in the consuming module.The module is excluded from the default build (it depends on
hiredis) and is enabled by removingdb_redisfromexclude_modules, exactly like the other library-dependent DB drivers.What the module covers
Data model — Redis is schemaless, so table layouts are declared out of band as Redis hashes:
schema:<table>— ordered column list (__cols), primary key (__pk), and onetype[,null][,auto]field per column (types:int,bigint,double,string,blob,datetime).<table>:<pk>— one row per key, one hash field per non-NULL column. Blobs are stored binary-safe (no encoding overhead); NULL is the absence of a field.seq:<table>—INCRcounter backing auto-increment primary keys andlast_inserted_id.versiontable is provisioned like any other table.Ready-to-load provisioning files ship under
scripts/redis/.Structured DB API implemented —
query(primary-key fast path + full-table scan-and-filter, all six operators= < > <= >= !=combined with AND/OR, single-columnORDER BY),insert(HSETNXrow reservation for SQL-insert uniqueness),update(HSET/HDEL),delete(incl. bulkORprimary-key deletes and truncate),replace,insert_update,last_inserted_id. Typed results are produced from the declared schema.Dual transport mode, auto-detected at startup via
INFO CLUSTER:-READONLYreplies (a demoted master after failover).CLUSTER SHARDS, falling back toCLUSTER SLOTS) and keeps a warm connection open to every master shard, so any key can be served immediately without a new TCP handshake on redirect. Keys are routed by CRC16 hash slot (honouring{hash tags});MOVEDis served from the warm pool with a deferred topology refresh,ASKis followed with a one-shotASKING, andTRYAGAINis retried after a short back-off. Full-table operations scan every master and merge. Only masters are used (read-your-writes consistency).The mode can be pinned with the
modemodparam (auto|single|cluster), turning a misconfiguration into a clear startup error instead of silently wrong behaviour.Modules supported in this PR
dialogdialog(v12)dispatcherdispatcher(v9)usrloclocation(v1013)sql-onlymode)clustererclusterer(v4),clusterer_bridge(v1)usrloc change
usrlochad a single raw SQL query (get_domain_db_ucontacts, used to fetch live contacts for NAT pinging) that excluded any backend without raw-query support. This PR adds a structured-query fallback: when the bound DB module lacksDB_CAP_RAW_QUERY, the query is built through the structured API (column projection +expires > now) and thecontact_idmodulo partitioning is applied client-side while iterating rows. SQL backends keep the exact same raw-query path, so there is no behaviour change for existing setups — and this also makesusrlocwork withdb_text. ConsequentlyDB_CAP_RAW_QUERYis no longer a hard requirement insql-onlymode.Roadmap
db_redis module
RediSearch ON HASHwhere available),FETCHresult cursors, per-node pipelining for bulk operations.raw_query, adbschemageneration target to emitschema:<table>files fromdb/schema/*.xml, async operations.Module coverage
Supported now:
dialog,dispatcher,usrloc,clusterer.Ready with only a provisioning file (structured DB API, no code change needed): the large majority of DB consumers, e.g.
acc,alias_db,auth_db,domain,domainpolicy,permissions,group,speeddial,dialplan,load_balancer,mqueue,msilo,ratelimit,uac_registrant,userblacklist,tls_mgm,b2b_entities/b2b_logic/b2b_sca,presence/presence_xml/rls/pua,call_center,imc,tracer,trie,qrouting,rate_cacher,emergency,fraud_detection,cpl_c,xcap/xcap_client. These only need their schema hashes provisioned.Needs a per-module structured fallback (raw SQL today, like usrloc did):
drouting,carrierroute,auth_jwt,sipcapture.Not applicable:
sqlops— executes arbitrary user-supplied SQL, which cannot be translated to Redis operations.cachedb_*— these use the NoSQL cache interface, not the structured DB API; usecachedb_redisfor Redis caching.db_virtual,db_cachedb,cachedb_sql,sql_cacher— DB-layer plumbing, not end consumers.tm— keeps no database table.Testing
db_redisbuilds cleanly; module loads and binds viadb_bind_api.redis-server(standalone) and a live 3-master / 3-replica Redis 8 cluster: seeded with a single node, all masters are discovered and their connections warmed up;dialogrows load and flush across non-seed masters via the slot map.dispatcherandusrlocload their tables end-to-end throughdb_redis.Notes
modules/db_redis/with DocBook documentation and generatedREADME.scripts/redis/.db_redisadded toexclude_modulesinMakefile.conf.template(optional, off by default).