Ruvio.

Commands

The machine-readable list is docs/compatibility-matrix.json. This page is the reading version of that contract. A command against the wrong type returns WRONGTYPE. SET replaces any type. PING still answers PONG. RUVIO answers PONG is taken. RUVIO OWNER names the rule: the core that owns the slot does the work.

Key jobs on the owner shard

These commands run on the shard that owns the key. None of them allocate on keys that never use them. GET, SET, and INCR do not consult them.

LEASE / RELEASE
LEASE returns a token, or a null bulk while the lease is still held. RELEASE drops the hold only when the token matches, and returns 1 or 0. Expiry and RELEASE keep the token while the key exists; DEL restarts it at 1. Tokens are not sufficient to fence writes to an external system after deletion or data loss. Grants and releases are WAL records in WAL-backed modes. GET of a lease is WRONGTYPE.
SEMAPHORE key max ttl_ms / RELEASE
A counting semaphore. Returns a token while fewer than max holders are live, or a null bulk when full. Each holder has its own TTL, so a crashed worker frees its slot when the TTL passes. RELEASE key token frees one slot and returns 1 or 0. The first holder stays in the object. Each further holder is 16 bytes in an exact slice. The key goes away with the last holder. Tokens start from the clock when the key is created, so a stale token never matches a later holder. The grant and the release are WAL records. GET of a semaphore is WRONGTYPE.
INCRBY key n MAX limit
Adds n only when the result stays at or below limit, and returns the new value. Otherwise it returns a null bulk and writes nothing. The accepted call is the same integer WAL record as INCR. Plain INCR and INCRBY keep their fast path.
SETV
Writes a versioned string. The first call with no version creates version 1. A later call must pass the current version and receives the next one. A mismatch returns an error and does not change the value. A plain SET replaces the versioned string. INCR does not accept a versioned string.
LIMIT key max window_ms
A fixed window on one key. Returns the remaining allowance after this call, or a null bulk when the window is full. The counter is not incremented on rejection. The window is the key deadline, so an unused window disappears. The accepted call is a WAL record. GET of a limit is WRONGTYPE.
ONCE key ttl_ms
The first call returns 1 and keeps the key until the TTL. A later call returns 0 and does not refresh the TTL. After the deadline the next call is first again. The first call is a WAL record. GET of an once key is WRONGTYPE.
IDEM key BEGIN fingerprint owner ttl_ms / IDEM key COMPLETE fingerprint owner result
A native pending/completed state machine, separate from ONCE. BEGIN returns ["acquired"], ["pending"], ["conflict"], or ["completed", result]. Only the acquired case creates a record. COMPLETE checks the live fingerprint and owner and returns 1 when it saves the binary result; an identical completion also returns 1 without rewriting. Missing/expired ownership or a changed completed result returns 0. Nothing renews the original TTL. Fingerprint/owner: 1-128 bytes each; retention: 1 ms-7 days; result: at most 4 MiB, also subject to protocol limits including stored metadata.
Only used keys pay for an 11-byte packed header, fingerprint, owner and optional result, plus normal string/expiry storage. TYPE is string; GET exposes an internal record, so reserve the namespace for this command. No Lua, global owner table, or extra fields on ordinary keys. Value and deadline are one WAL opcode 53 record; upgrade replicas and recovery tools before use. Completed replay borrows the stored result for encoding.
This does not make external effects exactly-once: a handler can crash before completion or outlive retention; eviction and replica/data loss can allow another attempt. Use downstream deduplication/transactions and appropriate non-evicting durable storage. Native commands reject old Lua hash records rather than overwriting them; drain old handlers and retention before upgrading. The ASP.NET Core integration uses this command.
TAKE
Subtracts a positive count from an integer when the key holds at least that many, and returns the remainder. A missing key or a shortfall returns a null bulk and does not create or change the key. The subtraction is the same integer WAL record as INCR. A non-integer is WRONGTYPE.
GETEX
Returns the string and sets its deadline to now plus the given milliseconds, so a key read often stays alive. A missing key returns a null bulk and stores nothing. GET does not move a deadline. The deadline is the existing expire WAL record.
XADD … DELAY
The stream entry is stored now. XREADGROUP skips it until the delay passes. XREAD can still see it. The hold is a WAL record and a snapshot trailer, written only when a delay is set.
CHANGES
CHANGES START arms an in-memory feed of later SET, SETV, LEASE, and RELEASE notes on that shard and returns the cursor. CHANGES cursor reads at most 1024 notes after it. Nothing is recorded before START. The feed is not the WAL, and it is empty after restart.

Strings

GET, GETEX, TAKE, SETV, SET with EX, PX, EXAT, PXAT, KEEPTTL, NX, XX, plus MGET, MSET, GETSET, APPEND, STRLEN, INCR, DECR, INCRBY, DECRBY.

Keys and expiry

DEL, UNLINK (deletes in the command, like DEL), EXISTS, TYPE, RENAME, SCAN, DBSIZE, EXPIRE, PEXPIRE, EXPIREAT, PEXPIREAT, TTL, PTTL, PERSIST, LEASE, RELEASE, SEMAPHORE, LIMIT, ONCE, CHANGES.

Logical databases

SELECT switches the connection to database 0 through databases - 1 (16 by default). FLUSHDB empties the selected database, FLUSHALL empties all of them, SWAPDB exchanges two in O(1), and MOVE sends one key to another database. INFO lists db<N>:keys=… per database. With more than one shard only database 0 exists, as in Redis Cluster. Hot keys live in database 0 only. Each database is its own map; WAL records carry the database number.

Lists, sets, hashes, sorted sets, Bloom

Streams

XADD, XLEN, XRANGE, XREVRANGE, XREAD, XDEL, XTRIM, XSETID, XGROUP CREATE, CREATECONSUMER, DESTROY, SETID, DELCONSUMER, XREADGROUP, XACK, XPENDING, XCLAIM, XAUTOCLAIM, XINFO STREAM, XINFO GROUPS, and XINFO CONSUMERS.

XADD ids are *, ms-*, or ms-seq. NOMKSTREAM leaves a missing key absent. MAXLEN and MINID, including ~ and =, trim exactly. The assigned id is stored in the WAL and in snapshots. DELAY hides that entry from XREADGROUP until the delay passes, and the hold is stored the same way. XREAD BLOCK waits and leaves the entry stored. XREADGROUP reads one stream with >. NOACK skips the pending list. XSETID moves the last generated id forward without storing an entry.

Transactions and Lua

MULTI / EXEC / DISCARD / WATCH / UNWATCH stay on one hash slot and record one WAL batch. Lua 5.1: EVAL, EVALSHA, SCRIPT LOAD, EXISTS, FLUSH, KILL. FUNCTION LOAD, LIST, DELETE, and FCALL keep one named body in memory. Declared keys must share a slot; a script with no keys runs on the connection's shard. Recovery replays the mutations a script wrote. It does not run Lua again. A restart drops the function library.

Pub/Sub, tracking, cluster discovery

Sharded Pub/Sub (SPUBLISH, SSUBSCRIBE, SUNSUBSCRIBE) stays on the channel's slot owner. Classic PUBLISH, SUBSCRIBE, and PSUBSCRIBE stay on the shard that accepted the connection. Messages are not stored and are not sent to other shards.

HELLO 2 and HELLO 3 negotiate the protocol, including AUTH and SETNAME. RESP3 adds nulls, booleans, doubles, maps, sets, and one invalidate push from CLIENT TRACKING. RESP3 attributes are not produced. CLIENT accepts GETNAME, SETNAME, and TRACKING. CLIENT SETINFO and any other unknown command are a protocol error and close the connection. Application clients are Ruvio.Client and ruvio-client.

CLUSTER SLOTS, CLUSTER SHARDS, CLUSTER NODES, CLUSTER INFO, CLUSTER MYID, and CLUSTER KEYSLOT describe a static topology. READONLY and READWRITE reply OK. A key on the wrong shard returns MOVED. Mixed slots return CROSSSLOT. This is not Redis Cluster failover or migration. The first-party SDKs take one seed address and route by slot.

WAIT replicas milliseconds blocks only that client until replicas copies of this shard have synced wal_last_sequence to disk, or the timeout. 0 waits until shutdown. The integer reply is how many replicas reached the sequence. A replica that has not caught up does not drop the write. The primary still holds it. A process that is not a primary replies 0. GET, SET, and INCR do not wait.

Left out on purpose