This is the command reference for the native TCP server, embedded API, and FerricFlow.

Start here if you need command syntax, logical return values, embedded API equivalents, or native protocol mapping notes. For a first walkthrough, use Getting Started.

Native TCP clients normally use dedicated opcodes with typed map payloads. For commands outside the compact opcode set, native clients use COMMAND_EXEC with {"command": "...", "args": [...]}. The command examples below show the logical command name and arguments, not a text wire protocol.

FerricFlow commands use the FLOW.* prefix and model durable workflow state: create, claim due work, transition, retry, complete, fail, cancel, signal, value refs, and fanout.

Command Surface Summary

Implemented Command Families

FerricStore implements these command names and argument shapes across native TCP mode and the embedded API:

GET, SET (EX/PX/EXAT/PXAT/NX/XX/GET/KEEPTTL), DEL, EXISTS, MGET, MSET, MSETNX, INCR, DECR, INCRBY, DECRBY, INCRBYFLOAT, APPEND, STRLEN, GETSET, GETDEL, GETEX, SETNX, SETEX, PSETEX, GETRANGE, SETRANGE, HSET, HGET, HDEL, HMGET, HGETALL, HEXISTS, HKEYS, HVALS, HLEN, HINCRBY, HINCRBYFLOAT, HSETNX, HSTRLEN, HRANDFIELD, HSCAN, HEXPIRE, HTTL, HPERSIST, HPEXPIRE, HPTTL, HEXPIRETIME, HGETDEL, HGETEX, HSETEX, LPUSH, RPUSH, LPOP, RPOP, LRANGE, LLEN, LINDEX, LSET, LREM, LTRIM, LPOS, LINSERT, LMOVE, RPOPLPUSH, LPUSHX, RPUSHX, SADD, SREM, SMEMBERS, SISMEMBER, SMISMEMBER, SCARD, SRANDMEMBER, SPOP, SDIFF, SINTER, SUNION, SDIFFSTORE, SINTERSTORE, SUNIONSTORE, SINTERCARD, SMOVE, SSCAN, ZADD (NX/XX/GT/LT/CH), ZSCORE, ZRANK, ZREVRANK, ZRANGE, ZREVRANGE, ZCARD, ZREM, ZINCRBY, ZCOUNT, ZPOPMIN, ZPOPMAX, ZRANDMEMBER, ZMSCORE, ZRANGEBYSCORE, ZREVRANGEBYSCORE, ZSCAN, XADD, XLEN, XRANGE, XREVRANGE, XREAD (including BLOCK), XTRIM, XDEL, XINFO STREAM, XGROUP CREATE, XREADGROUP, XACK, EXPIRE, PEXPIRE, EXPIREAT, PEXPIREAT, TTL, PTTL, PERSIST, EXPIRETIME, PEXPIRETIME, SETBIT, GETBIT, BITCOUNT, BITPOS, BITOP, PFADD, PFCOUNT, PFMERGE, GEOADD, GEOPOS, GEODIST, GEOHASH, GEOSEARCH, GEOSEARCHSTORE, PING, ECHO, DBSIZE, KEYS, FLUSHDB, FLUSHALL, INFO, TYPE, UNLINK, RENAME, RENAMENX, COPY, RANDOMKEY, OBJECT HELP/REFCOUNT, SCAN, CONFIG GET/SET/RESETSTAT/REWRITE, SLOWLOG GET/LEN/RESET, COMMAND/COMMAND COUNT/COMMAND LIST/COMMAND INFO/COMMAND DOCS/COMMAND GETKEYS, MULTI, EXEC, DISCARD, WATCH, UNWATCH, SUBSCRIBE, UNSUBSCRIBE, PSUBSCRIBE, PUNSUBSCRIBE, PUBLISH, CLIENT ID/SETNAME/GETNAME/INFO/LIST/TRACKING/CACHING/TRACKINGINFO/GETREDIR, HELLO, AUTH, QUIT, RESET

FerricStore-Native Flow Commands

Flow commands are FerricStore-native workflow commands, not FerricStore data-structure commands. They are exposed through native TCP mode and the embedded API:

FLOW.CREATE, FLOW.CREATE_MANY, FLOW.VALUE.PUT, FLOW.SIGNAL, FLOW.SPAWN_CHILDREN, FLOW.GET, FLOW.CLAIM_DUE, FLOW.RECLAIM, FLOW.EXTEND_LEASE, FLOW.COMPLETE, FLOW.COMPLETE_MANY, FLOW.RETRY, FLOW.RETRY_MANY, FLOW.FAIL, FLOW.FAIL_MANY, FLOW.CANCEL, FLOW.CANCEL_MANY, FLOW.TRANSITION, FLOW.TRANSITION_MANY, FLOW.REWIND, FLOW.LIST, FLOW.STATS, FLOW.BY_PARENT, FLOW.BY_ROOT, FLOW.BY_CORRELATION, FLOW.INFO, FLOW.STUCK, FLOW.HISTORY, FLOW.TERMINALS, FLOW.FAILURES, FLOW.POLICY.SET, FLOW.POLICY.GET, and FLOW.RETENTION_CLEANUP.

Flow attributes are small indexed metadata fields for query and dashboard filters. They are separate from payload and named value refs:

FLOW.CREATE order-1 TYPE order STATE queued ATTRIBUTE tenant acme ATTRIBUTE region us
FLOW.TRANSITION order-1 queued charged LEASE_TOKEN <token> FENCING 1 ATTRIBUTE_MERGE phase charge
FLOW.LIST order STATE queued ATTRIBUTE tenant acme COUNT 100
FLOW.STATS order STATE queued ATTRIBUTE tenant acme

Use attributes for values you want to filter or count by, such as tenant, region, campaign, device group, or model. Use value refs for large bytes or state-specific data. Attribute query projection is asynchronous, so use CONSISTENT_PROJECTION true when an admin/debug read must wait for projection catch-up.

Production semantics, retry policy, history caps, LMDB cold projection, and operator metrics are documented in docs/flow-production-readiness.md and docs/flow-retry-policy.md. The Elixir workflow SDK for the embedded API is documented in guides/flow-elixir-sdk.md.

Command-Specific Differences

CommandDifference
ZRANGEUnified BYSCORE/BYLEX/REV/LIMIT syntax is not yet supported -- use ZRANGEBYSCORE/ZREVRANGEBYSCORE instead
SCANCursor is key-based (alphabetic position), not an opaque integer
HSCAN/SSCAN/ZSCANCursor is an integer offset into the scanned list
FLUSHDB/FLUSHALLASYNC/SYNC accepted but both execute synchronously; true async reclaim happens during Bitcask merge
UNLINKSemantically identical to DEL -- async reclaim is deferred to Bitcask merge
OBJECT ENCODINGReturns type-specific logical encodings ("embstr", "raw", "hashtable", "quicklist", "skiplist", "stream") rather than exposing internal storage layouts
OBJECT FREQReturns the LFU counter from keydir
OBJECT IDLETIMEReturns idle seconds derived from LFU last-decrement-time
SELECTReturns error -- FerricStore is single-database
INFOReturns FerricStore-specific sections (raft, bitcask, ferricstore, keydir_analysis, namespace_config)
WAITAlways returns 0 immediately (no replica acknowledgement)
BLPOP/BRPOP/BLMOVE/BLMPOPSupported in TCP mode only, not in embedded mode
XREAD BLOCKSupported in TCP mode via stream waiters; not available in embedded mode

FerricStore-Only Commands

These are FerricStore-native commands:

CAS, LOCK, UNLOCK, EXTEND, RATELIMIT.ADD, FETCH_OR_COMPUTE, FETCH_OR_COMPUTE_RESULT, FETCH_OR_COMPUTE_ERROR, FERRICSTORE.CONFIG, FERRICSTORE.METRICS, FERRICSTORE.HOTNESS, FERRICSTORE.KEY_INFO, FERRICSTORE.DOCTOR, CLUSTER.HEALTH, CLUSTER.STATS, CLUSTER.KEYSLOT, CLUSTER.SLOTS

Command Names Not Yet Supported

EVAL, EVALSHA, EVALSHA_RO, EVAL_RO (Lua scripting), LMPOP, ZMPOP, BZMPOP (multi-key pop), ZUNIONSTORE, ZINTERSTORE, ZDIFFSTORE (sorted set store operations), ZRANGESTORE, ZRANGEBYLEX, ZREVRANGEBYLEX, ZLEXCOUNT, SORT, SORT_RO, OBJECT extended subcommands (OBJECT PERSIST, OBJECT COPY), CLUSTER (full cluster command family), DUMP, RESTORE, MIGRATE, MOVE, CLIENT KILL, CLIENT NO-EVICT, CLIENT PAUSE, CLIENT UNPAUSE, DEBUG (most subcommands)


String Commands

String commands operate on simple key-value pairs. Values are stored as raw byte strings in Bitcask. All writes go through Raft group-commit.

GET

Retrieves the value of a key. Returns a WRONGTYPE error if the key holds a non-string data structure (hash, list, set, zset). FerricStore detects data structure types by peeking at ETF header bytes without deserializing the entire value.

Protocol commandGET key
Embedded APIFerricStore.get(key)
ReturnBulk string, or _ (null) if key does not exist
Elixir return{:ok, binary()} or {:ok, nil}
StatusSupported

SET

Sets a string value with optional expiry and conditional flags.

Protocol commandSET key value [EX seconds | PX milliseconds | EXAT unix-sec | PXAT unix-ms] [NX|XX] [GET] [KEEPTTL]
Embedded APIFerricStore.set(key, value, ttl: ms)
Return+OK on success, _ (null) when NX/XX condition fails. With GET: returns old value or null.
Elixir return:ok on success, {:ok, nil} when condition fails

Options:

  • EX seconds -- set expiry in seconds (must be > 0)
  • PX milliseconds -- set expiry in milliseconds (must be > 0)
  • EXAT unix-sec -- set absolute expiry as Unix timestamp in seconds
  • PXAT unix-ms -- set absolute expiry as Unix timestamp in milliseconds
  • NX -- only set if key does not exist
  • XX -- only set if key already exists
  • GET -- return the old value stored at key (or null if key didn't exist)
  • KEEPTTL -- retain the existing TTL on the key (cannot combine with EX/PX/EXAT/PXAT)

Status: Supported -- all SET options supported.

FerricStore behavior: Expiry is stored as an absolute HLC timestamp (expire_at_ms). Writes go through Raft group-commit -- the ETS keydir is updated immediately (sub-microsecond read visibility) while Bitcask persistence is batched.

DEL

Deletes one or more keys. Handles both plain string keys and compound data structure keys (hash, list, set, zset) by cleaning up all sub-keys and type metadata.

Protocol commandDEL key [key ...]
Embedded APIFerricStore.del(key)
ReturnInteger -- number of keys deleted
Elixir return:ok
StatusSupported

EXISTS

Returns the count of keys that exist. Checks both plain keys and compound data structure type metadata.

Protocol commandEXISTS key [key ...]
Embedded APIFerricStore.exists(key)
ReturnInteger -- count of existing keys (a key is counted once for each time it appears in the argument list)
Elixir returntrue or false (single key)
StatusSupported

MGET

Returns values for multiple keys. Returns nil for keys that do not exist.

Protocol commandMGET key [key ...]
Embedded APIFerricStore.mget(keys)
ReturnArray of bulk strings / nulls
Elixir return{:ok, [binary() | nil]}
StatusSupported

MSET

Sets multiple key-value pairs atomically. Never fails (always overwrites).

Protocol commandMSET key value [key value ...]
Embedded APIFerricStore.mset(map)
Return+OK
Elixir return:ok
StatusSupported

Validation: Rejects empty keys and keys larger than 65,535 bytes.

MSETNX

Sets multiple keys only if NONE of the keys exist. Returns 0 if any key already exists (none are set).

Protocol commandMSETNX key value [key value ...]
Embedded APIFerricStore.msetnx(map)
ReturnInteger -- 1 (all set) or 0 (none set)
Elixir return{:ok, true} or {:ok, false}
StatusSupported

INCR / DECR / INCRBY / DECRBY

Atomically increment or decrement integer values. If the key does not exist, it is initialized to 0 before the operation.

Protocol commandINCR key, DECR key, INCRBY key increment, DECRBY key decrement
Embedded APIFerricStore.incr(key), FerricStore.decr(key), FerricStore.incr_by(key, n), FerricStore.decr_by(key, n)
ReturnInteger -- the new value
Elixir return{:ok, integer()}
StatusSupported

Error: Returns ERR value is not an integer or out of range if the value is not a valid integer.

INCRBYFLOAT

Atomically increment a value by a floating point amount. If the key does not exist, it is initialized to 0.0. Rejects inf and NaN.

Protocol commandINCRBYFLOAT key increment
Embedded APIFerricStore.incr_by_float(key, delta)
ReturnBulk string -- the new value as a string
Elixir return{:ok, binary()}
StatusSupported

APPEND

Appends a value to an existing string. If the key does not exist, it is created with the given value.

Protocol commandAPPEND key value
Embedded APIFerricStore.append(key, value)
ReturnInteger -- the new length in bytes
Elixir return{:ok, integer()}
StatusSupported

STRLEN

Returns the byte length of the string stored at key. Returns 0 if the key does not exist.

Protocol commandSTRLEN key
Embedded APIFerricStore.strlen(key)
ReturnInteger
Elixir return{:ok, integer()}
StatusSupported

GETSET

Atomically sets a key and returns the old value. Prefer SET ... GET for new clients, but GETSET is still supported.

Protocol commandGETSET key value
Embedded APIFerricStore.getset(key, value)
ReturnBulk string (old value) or null
Elixir return{:ok, binary() | nil}
StatusSupported

GETDEL

Atomically gets and deletes a key.

Protocol commandGETDEL key
Embedded APIFerricStore.getdel(key)
ReturnBulk string or null
Elixir return{:ok, binary() | nil}
StatusSupported

GETEX

Gets a key and optionally updates its TTL.

Protocol commandGETEX key [EX seconds | PX ms | EXAT ts | PXAT ms_ts | PERSIST]
Embedded APIFerricStore.getex(key, ttl: ms)
ReturnBulk string or null
Elixir return{:ok, binary() | nil}
StatusSupported -- all five TTL options supported

SETNX

Sets a key only if it does not already exist.

Protocol commandSETNX key value
Embedded APIFerricStore.setnx(key, value)
ReturnInteger -- 1 (set) or 0 (not set)
Elixir return{:ok, true} or {:ok, false}
StatusSupported

SETEX / PSETEX

Sets a key with an expiry.

Protocol commandSETEX key seconds value, PSETEX key milliseconds value
Embedded APIFerricStore.setex(key, seconds, value), FerricStore.psetex(key, ms, value)
Return+OK
Elixir return:ok
StatusSupported. TTL must be > 0.

GETRANGE

Returns a substring of the string value by byte range. Supports negative indices (from end).

Protocol commandGETRANGE key start end
Embedded APIFerricStore.getrange(key, start, stop)
ReturnBulk string (empty if key missing or range invalid)
Elixir return{:ok, binary()}
StatusSupported

SETRANGE

Overwrites part of a string starting at the given byte offset. If the key does not exist, creates a zero-padded string.

Protocol commandSETRANGE key offset value
Embedded APIFerricStore.setrange(key, offset, value)
ReturnInteger -- the new string length
Elixir return{:ok, integer()}
StatusSupported

Hash Commands

Each hash field is stored as an individual compound key in the shared shard Bitcask: H:user_key\0field_name -> value. This allows individual field access without reading the entire hash. Type metadata is maintained by TypeRegistry -- using a hash command on a key that holds a different type returns WRONGTYPE.

HSET

Sets one or more field-value pairs. Returns the number of NEW fields added (not updated).

Protocol commandHSET key field value [field value ...]
Embedded APIFerricStore.hset(key, map)
ReturnInteger -- count of new fields added
Elixir return:ok
StatusSupported

HGET

Returns the value of a single field.

Protocol commandHGET key field
Embedded APIFerricStore.hget(key, field)
ReturnBulk string or null
Elixir return{:ok, binary() | nil}
StatusSupported

HDEL

Deletes one or more fields. Cleans up type metadata if the hash becomes empty.

Protocol commandHDEL key field [field ...]
Embedded APIFerricStore.hdel(key, fields)
ReturnInteger -- count of fields deleted
Elixir return{:ok, integer()}
StatusSupported

HMGET

Returns values for multiple fields. Missing fields return null.

Protocol commandHMGET key field [field ...]
Embedded APIFerricStore.hmget(key, fields)
ReturnArray of bulk strings / nulls
Elixir return{:ok, [binary() | nil]}
StatusSupported

HGETALL

Returns all fields and values as a flat list: [field1, value1, field2, value2, ...].

Protocol commandHGETALL key
Embedded APIFerricStore.hgetall(key)
ReturnArray (flat interleaved) or Map in native TCP mode
Elixir return{:ok, map()}
StatusSupported

HEXISTS / HLEN / HKEYS / HVALS

CommandSyntaxReturn
HEXISTSHEXISTS key field1 if exists, 0 if not
HLENHLEN keyInteger -- field count
HKEYSHKEYS keyArray of field names
HVALSHVALS keyArray of values

All return empty results (0, []) for non-existent keys. native TCP mode.

HINCRBY / HINCRBYFLOAT

Atomically increment hash field values. If the field does not exist, it is initialized to 0.

Protocol commandHINCRBY key field increment, HINCRBYFLOAT key field increment
Embedded APIFerricStore.hincrby(key, field, n), FerricStore.hincrbyfloat(key, field, delta)
ReturnInteger (HINCRBY) or bulk string (HINCRBYFLOAT)
StatusSupported

HSETNX

Sets a field only if it does not exist.

Protocol commandHSETNX key field value
Return1 (set) or 0 (not set)
StatusSupported

HSTRLEN

Returns the string length of a hash field value. Returns 0 for missing fields.

Protocol commandHSTRLEN key field
ReturnInteger
StatusSupported

HRANDFIELD

Returns random field(s). Negative count allows duplicates.

Protocol commandHRANDFIELD key [count [WITHVALUES]]
ReturnBulk string (single), array (multiple)
StatusSupported. Negative count behavior allows repeated fields.

HSCAN

Cursor-based iteration over hash fields with optional pattern matching.

Protocol commandHSCAN key cursor [MATCH pattern] [COUNT count]
Return[next_cursor, [field, value, ...]]
StatusCursor is an integer offset into the scanned field list. Default COUNT is 10.

Hash Field TTL

FerricStore supports per-field expiry on hash fields:

CommandSyntaxReturn
HEXPIREHEXPIRE key seconds FIELDS count field [field ...]List of 1 (set) / -2 (field missing)
HTTLHTTL key FIELDS count field [field ...]List of TTL seconds / -1 (no expiry) / -2 (missing)
HPERSISTHPERSIST key FIELDS count field [field ...]List of 1 (removed) / -1 (no expiry) / -2 (missing)
HPEXPIREHPEXPIRE key ms FIELDS count field [field ...]Same as HEXPIRE but milliseconds
HPTTLHPTTL key FIELDS count field [field ...]Same as HTTL but milliseconds
HEXPIRETIMEHEXPIRETIME key FIELDS count field [field ...]Absolute Unix timestamp (seconds)
HGETDELHGETDEL key FIELDS count field [field ...]List of values (nil for missing)
HGETEXHGETEX key [EX sec|PX ms|EXAT ts|PXAT ms|PERSIST] FIELDS count field [...]List of values
HSETEXHSETEX key seconds field value [field value ...]Count of new fields

Status: Supported for native TCP and embedded command handlers.


List Commands

Lists are stored via ListOps using compound keys. Each element is individually addressable. Push operations notify any blocking waiters (BLPOP/BRPOP).

LPUSH / RPUSH

Push one or more elements to the head or tail. Returns the new list length.

Protocol commandLPUSH key element [element ...], RPUSH key element [element ...]
Embedded APIFerricStore.lpush(key, elements), FerricStore.rpush(key, elements)
ReturnInteger -- new length
Elixir return{:ok, integer()}
StatusSupported

LPOP / RPOP

Pop one or more elements from head or tail.

Protocol commandLPOP key [count], RPOP key [count]
Embedded APIFerricStore.lpop(key), FerricStore.rpop(key)
ReturnBulk string (single pop), Array (counted pop), null (empty/missing)
Elixir return{:ok, binary() | nil}
StatusSupported. Count=0 returns empty list if key exists, nil if not.

LRANGE

Returns elements in the specified range. Supports negative indices.

Protocol commandLRANGE key start stop
Embedded APIFerricStore.lrange(key, start, stop)
ReturnArray of bulk strings
Elixir return{:ok, [binary()]}
StatusSupported

LLEN / LINDEX / LSET / LREM / LTRIM / LPOS / LINSERT

CommandSyntaxReturnNotes
LLENLLEN keyIntegernative TCP mode
LINDEXLINDEX key indexBulk string / nullSupports negative indices
LSETLSET key index element+OK or errornative TCP mode
LREMLREM key count elementInteger (removed count)count>0: head-to-tail, count<0: tail-to-head, count=0: all
LTRIMLTRIM key start stop+OKnative TCP mode
LPOSLPOS key element [RANK r] [COUNT c] [MAXLEN m]Integer / Array / nullRANK 0 is invalid
LINSERTLINSERT key BEFORE|AFTER pivot elementInteger (new length) / -1 (pivot not found)native TCP mode

LMOVE / RPOPLPUSH

Atomically pops from one list and pushes to another.

Protocol commandLMOVE source destination LEFT|RIGHT LEFT|RIGHT
Embedded APIFerricStore.lmove(src, dst, from, to)
StatusSupported. RPOPLPUSH is an alias for LMOVE source dest RIGHT LEFT.

LPUSHX / RPUSHX

Push only if the list already exists. Returns 0 if the key does not exist.

Protocol commandLPUSHX key element [element ...], RPUSHX key element [element ...]
StatusSupported

BLPOP / BRPOP / BLMOVE / BLMPOP

Blocking variants of pop/move. These are only available in native TCP mode -- not in embedded mode. When the list is empty, the connection blocks until an element is pushed or the timeout expires.


Set Commands

Each set member is stored as a compound key S:user_key\0member -> "1". This allows O(1) membership testing.

SADD / SREM

Protocol commandSADD key member [member ...], SREM key member [member ...]
Embedded APIFerricStore.sadd(key, members), FerricStore.srem(key, members)
ReturnInteger -- count of members added/removed
Elixir return{:ok, integer()}
StatusSupported. Type metadata cleaned up when set becomes empty.

SMEMBERS / SISMEMBER / SCARD

CommandSyntaxReturn
SMEMBERSSMEMBERS keyArray of members
SISMEMBERSISMEMBER key member1 or 0
SCARDSCARD keyInteger -- set size

All native TCP mode. Non-existent keys return empty/0.

SRANDMEMBER / SPOP

Protocol commandSRANDMEMBER key [count], SPOP key [count]
StatusSupported. Negative count for SRANDMEMBER allows duplicates. SPOP removes the selected members.

SDIFF / SINTER / SUNION

Set algebra operations across multiple keys.

Protocol commandSDIFF key [key ...], SINTER key [key ...], SUNION key [key ...]
Embedded APIFerricStore.sdiff(keys), FerricStore.sinter(keys), FerricStore.sunion(keys)
ReturnArray of members
StatusSupported. All keys are loaded into MapSet for computation.

SDIFFSTORE / SINTERSTORE / SUNIONSTORE

Store operations that compute set algebra and write the result to a destination key.

Protocol commandSDIFFSTORE dest key [key ...], SINTERSTORE dest key [key ...], SUNIONSTORE dest key [key ...]
ReturnInteger -- cardinality of the resulting set
StatusSupported. Destination is cleared and re-created.

SINTERCARD

Returns the cardinality of the intersection without creating a new set.

Protocol commandSINTERCARD numkeys key [key ...] [LIMIT limit]
ReturnInteger -- intersection cardinality (capped by LIMIT if provided)
StatusSupported

SMISMEMBER

Returns whether each member is a member of the set.

Protocol commandSMISMEMBER key member [member ...]
ReturnArray of 1 / 0
StatusSupported

SMOVE

Atomically moves a member from source to destination set.

Protocol commandSMOVE source destination member
Return1 (moved) or 0 (member not in source)
StatusSupported

SSCAN

Cursor-based iteration with optional MATCH and COUNT.

Protocol commandSSCAN key cursor [MATCH pattern] [COUNT count]
StatusCursor is offset-based. Default COUNT is 10.

Sorted Set Commands

Each sorted set member is stored as Z:user_key\0member -> score_string. Scores are float64 strings. For range queries, all members are loaded and sorted in memory -- adequate for typical cache workloads.

ZADD

Adds members with scores. Supports all FerricStore modifier flags.

Protocol commandZADD key [NX|XX] [GT|LT] [CH] score member [score member ...]
Embedded APIFerricStore.zadd(key, [{score, member}, ...])
ReturnInteger -- count of elements added (or added+changed with CH)
Elixir return{:ok, integer()}

Options:

  • NX -- only add new elements, don't update existing
  • XX -- only update existing elements, don't add new
  • GT -- only update when new score > current score
  • LT -- only update when new score < current score
  • CH -- return count of added + changed (instead of just added)

Status: Supported.

ZSCORE / ZMSCORE

Protocol commandZSCORE key member, ZMSCORE key member [member ...]
ReturnBulk string (score) or null
StatusSupported

ZRANK / ZREVRANK

Returns zero-based rank of a member.

Protocol commandZRANK key member, ZREVRANK key member
ReturnInteger or null (member not found)
StatusSupported

ZRANGE / ZREVRANGE

Range query by index with optional WITHSCORES.

Protocol commandZRANGE key start stop [WITHSCORES], ZREVRANGE key start stop [WITHSCORES]
Embedded APIFerricStore.zrange(key, start, stop, withscores: bool)
ReturnArray of members, or interleaved [member, score, ...] with WITHSCORES
StatusIndex-based syntax is supported. Unified ZRANGE syntax (BYSCORE/BYLEX/REV/LIMIT) is not yet supported. Use ZRANGEBYSCORE/ZREVRANGEBYSCORE for score ranges.

ZRANGEBYSCORE / ZREVRANGEBYSCORE

Range by score with optional WITHSCORES and LIMIT.

Protocol commandZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count]
Supported boundsNumeric, -inf, +inf, (exclusive prefix
StatusSupported. Negative LIMIT count means "all remaining".

ZCOUNT

Count members with scores in the given range.

Protocol commandZCOUNT key min max
StatusSupported. Supports -inf, +inf, and (exclusive.

ZINCRBY

Increment the score of a member. Creates the member if it does not exist.

Protocol commandZINCRBY key increment member
ReturnBulk string -- the new score
StatusSupported

ZPOPMIN / ZPOPMAX

Pop the lowest/highest scored members.

Protocol commandZPOPMIN key [count], ZPOPMAX key [count]
ReturnArray of [member, score, ...]
StatusSupported. Cleans up type metadata when empty.

ZRANDMEMBER / ZSCAN / ZCARD / ZREM

CommandStatus
ZRANDMEMBER key [count [WITHSCORES]]Supported. Negative count allows duplicates.
ZSCAN key cursor [MATCH pattern] [COUNT count]Offset-based cursor
ZCARD keySupported
ZREM key member [member ...]Supported

Stream Commands

Stream entries are stored as compound keys X:{stream_key}\0{ms}-{seq} with field-value pairs serialized as ETF. Stream metadata (length, first/last ID, sequence counters) is tracked in an ETS table for fast access. Stream IDs use a Hybrid Logical Clock (HLC) for monotonicity, even when the wall clock jumps backward.

XADD

Adds an entry to a stream with optional trimming and NOMKSTREAM.

Protocol commandXADD key [NOMKSTREAM] [MAXLEN|MINID [=|~] threshold] *|ID field value [field value ...]
Embedded APIFerricStore.xadd(key, fields)
ReturnBulk string -- the generated entry ID
Elixir return{:ok, binary()}

ID generation: * auto-generates using HLC. Explicit IDs must be strictly greater than the last entry. Partial IDs (just milliseconds) auto-assign the sequence.

Status: Supported, including NOMKSTREAM and trim options.

XLEN / XRANGE / XREVRANGE

CommandSyntaxReturnNotes
XLENXLEN keyIntegerFrom ETS metadata, O(1)
XRANGEXRANGE key start end [COUNT count]Array of entries- = min, + = max
XREVRANGEXREVRANGE key end start [COUNT count]Array (reversed)native TCP mode

XREAD

Reads entries from one or more streams. Supports BLOCK for waiting on new data.

Protocol commandXREAD [COUNT count] [BLOCK ms] STREAMS key [key ...] id [id ...]
Special IDs$ = only new entries from now on; 0 = all entries
BLOCK behaviorIn TCP mode, the connection registers as a stream waiter and is notified by XADD. In embedded mode, BLOCK is not supported.
StatusSupported in TCP mode. BLOCK 0 = infinite wait.

XTRIM / XDEL

CommandSyntaxReturnNotes
XTRIMXTRIM key MAXLEN|MINID [=|~] thresholdInteger (entries deleted)~ is accepted but exact trim is always applied
XDELXDEL key id [id ...]Integer (entries deleted)Metadata rebuilt after deletion

XINFO STREAM

Returns stream metadata as a map.

Protocol commandXINFO STREAM key
ReturnMap with length, first-entry, last-entry, last-generated-id, groups
StatusSubset of FerricStore XINFO. FULL option not yet supported.

XGROUP CREATE / XREADGROUP / XACK

Consumer group support:

CommandSyntaxNotes
XGROUP CREATEXGROUP CREATE key group id [MKSTREAM]$ for new-only, 0 for all
XREADGROUPXREADGROUP GROUP group consumer [COUNT count] STREAMS key [key ...] id [id ...]> for new messages, 0 for pending
XACKXACK key group id [id ...]Returns count acknowledged

Consumer group state (pending entries, consumers, last-delivered-id) is tracked in ETS. XGROUP DESTROY, DELCONSUMER, and SETID are not yet implemented.


Key/Generic Commands

TYPE

Returns the type of a key as a simple string.

Protocol commandTYPE key
ReturnSimple string: string, hash, list, set, zset, stream, or none
StatusSupported

RENAME / RENAMENX / COPY

CommandSyntaxReturnNotes
RENAMERENAME key newkey+OK or errorCopies value+TTL, deletes old
RENAMENXRENAMENX key newkey1 (renamed) or 0 (dest exists)Same key returns 0
COPYCOPY source dest [REPLACE]1 (success) or errorREPLACE overwrites existing dest

Note: These operate on plain string keys only. Renaming compound data structures (hash, list, set, zset) is not supported -- only the raw value is copied.

SCAN

Cursor-based key iteration with optional MATCH pattern, COUNT hint, and TYPE filter.

Protocol commandSCAN cursor [MATCH pattern] [COUNT count] [TYPE type]
Return[next_cursor, [key, ...]]

FerricStore behavior: Cursor is the last key seen (alphabetic). "0" starts from the beginning. The prefix index is used for prefix:* patterns for O(matching) performance. Internal compound keys (H:, S:, Z:, T:, VM:, V:) are filtered out.

RANDOMKEY / DBSIZE / KEYS

CommandSyntaxReturn
RANDOMKEYRANDOMKEYRandom key or null
DBSIZEDBSIZEInteger -- key count (excludes internal keys)
KEYSKEYS patternArray of matching keys. Uses prefix index for prefix:* patterns.

EXPIRE / PEXPIRE / EXPIREAT / PEXPIREAT / TTL / PTTL / PERSIST

CommandSyntaxReturn
EXPIREEXPIRE key seconds1 (set) or 0 (key missing)
PEXPIREPEXPIRE key ms1 or 0
EXPIREATEXPIREAT key unix-ts1 or 0
PEXPIREATPEXPIREAT key unix-ts-ms1 or 0
TTLTTL keySeconds remaining, -1 (no expiry), -2 (missing)
PTTLPTTL keyMilliseconds remaining, -1, -2
PERSISTPERSIST key1 (removed), 0 (no expiry or missing)
EXPIRETIMEEXPIRETIME keyAbsolute Unix timestamp (seconds), -1, -2
PEXPIRETIMEPEXPIRETIME keyAbsolute Unix timestamp (ms), -1, -2

All native TCP mode. Expiry uses HLC timestamps internally.

OBJECT

SubcommandReturnNotes
OBJECT ENCODING keyType-specific encodingReturns "embstr" (strings <= 44 bytes), "raw" (longer strings), "hashtable" (hashes), "quicklist" (lists), "skiplist" (sorted sets), "stream" (streams)
OBJECT HELPArray of help stringsnative TCP mode format
OBJECT FREQ keyInteger (LFU counter)Uses keydir LFU, not FerricStore logarithmic frequency
OBJECT IDLETIME keyInteger (idle seconds)Derived from LFU last-decrement-time. Returns elapsed seconds since last access.
OBJECT REFCOUNT key1Always 1

WAIT

Protocol commandWAIT numreplicas timeout
Return0 (always)
StatusStub -- no replica acknowledgement. Always returns immediately.

Bitmap Commands

Bitmap operations work at the bit level on string values. Bits are numbered MSB-first: bit 0 is the MSB of byte 0 (value 128). Write operations (SETBIT, BITOP) perform a read-modify-write cycle.

CommandSyntaxReturnStatus
SETBITSETBIT key offset valueInteger (old bit value)Supported
GETBITGETBIT key offsetInteger (0 or 1)Supported
BITCOUNTBITCOUNT key [start end [BYTE|BIT]]Integer (count of set bits)Supported including BYTE/BIT mode
BITPOSBITPOS key bit [start [end [BYTE|BIT]]]Integer (position or -1)Supported
BITOPBITOP AND|OR|XOR|NOT destkey key [key ...]Integer (dest string length)Supported

HyperLogLog Commands

HyperLogLog sketches are stored as 16,384-byte binary values (plain strings in Bitcask). No special type metadata.

CommandSyntaxReturnStatus
PFADDPFADD key element [element ...]1 (modified) or 0Supported
PFCOUNTPFCOUNT key [key ...]Integer (estimated cardinality)Multi-key merges in memory without writing
PFMERGEPFMERGE destkey sourcekey [sourcekey ...]+OKSupported. Takes max across registers.

Bloom Filter Commands

Backed by mmap NIF resources. Each filter is a memory-mapped file at data_dir/prob/shard_N/KEY.bloom. Handles are cached in per-shard ETS tables.

CommandSyntaxReturnNotes
BF.RESERVEBF.RESERVE key error_rate capacity+OK or errorerror_rate: (0,1), capacity: positive int
BF.ADDBF.ADD key element1 (added) or 0Auto-creates with defaults (0.01, 100)
BF.MADDBF.MADD key element [element ...]Array of 1/0Auto-creates
BF.EXISTSBF.EXISTS key element1 (may exist) or 0Returns 0 for non-existent keys
BF.MEXISTSBF.MEXISTS key element [element ...]Array of 1/0Returns all 0s for non-existent keys
BF.CARDBF.CARD keyIntegerItems added count
BF.INFOBF.INFO keyArray: Capacity, Size, filters, items, expansion, error rate, hashes, bits

Status: Uses FerricStoreBloom module syntax. Optimal sizing uses m = -n*ln(p) / (ln(2))^2. No scaling/expansion support (single filter).


Cuckoo Filter Commands

Backed by mmap NIF resources at data_dir/prob/shard_N/KEY.cuckoo. Supports deletion (unlike Bloom).

CommandSyntaxReturnNotes
CF.RESERVECF.RESERVE key capacity+OK or errorBucket size: 4
CF.ADDCF.ADD key element1 or error (filter full)Auto-creates with capacity 1024
CF.ADDNXCF.ADDNX key element1 (added), 0 (already exists), or error
CF.DELCF.DEL key element1 (deleted) or 0 (not found)Deletes one occurrence
CF.EXISTSCF.EXISTS key element1 or 0
CF.MEXISTSCF.MEXISTS key element [element ...]Array of 1/0
CF.COUNTCF.COUNT key elementInteger (approximate count)Fingerprint occurrences
CF.INFOCF.INFO keyArray: Size, buckets, filters, items, deletes, bucket_size, fingerprint_size, max_kicks, expansion

Status: Uses FerricStoreBloom/Cuckoo module syntax.


Count-Min Sketch Commands

Backed by mmap NIF resources at data_dir/prob/shard_N/KEY.cms.

CommandSyntaxReturnNotes
CMS.INITBYDIMCMS.INITBYDIM key width depth+OKwidth and depth must be > 0
CMS.INITBYPROBCMS.INITBYPROB key error probability+OKwidth = ceil(e/error), depth = ceil(ln(1/prob))
CMS.INCRBYCMS.INCRBY key item count [item count ...]Array of countsEach count >= 1
CMS.QUERYCMS.QUERY key item [item ...]Array of estimated counts
CMS.MERGECMS.MERGE dst numkeys key [key ...] [WEIGHTS w ...]+OKAll sources must have same width/depth. Creates dst if missing.
CMS.INFOCMS.INFO key[width, W, depth, D, count, C]

Status: Uses FerricStoreBloom CMS module syntax.


TopK Commands

Backed by mmap NIF resources at prob/shard_N/KEY.topk. Uses Count-Min Sketch internally with a Heavy Keeper algorithm.

CommandSyntaxReturnNotes
TOPK.RESERVETOPK.RESERVE key k [width depth decay]+OKDefaults: width=8, depth=7, decay=0.9
TOPK.ADDTOPK.ADD key element [element ...]Array (evicted items or nil)
TOPK.INCRBYTOPK.INCRBY key element count [element count ...]Array (evicted items or nil)
TOPK.QUERYTOPK.QUERY key element [element ...]Array of 1/0
TOPK.LISTTOPK.LIST key [WITHCOUNT]Array of items (or interleaved items+counts)
TOPK.INFOTOPK.INFO key[k, K, width, W, depth, D, decay, D]

Status: Uses FerricStoreBloom TopK module syntax.


TDigest Commands

T-digests provide accurate rank-based statistics (quantiles, CDF, trimmed means) with bounded memory and high accuracy at the tails (P99, P99.9). Stored as tagged tuples {:tdigest, centroids, metadata} in Bitcask.

CommandSyntaxReturnNotes
TDIGEST.CREATETDIGEST.CREATE key [COMPRESSION c]+OKDefault compression: 100
TDIGEST.ADDTDIGEST.ADD key value [value ...]+OKAccepts floats and integers
TDIGEST.RESETTDIGEST.RESET key+OKClears data, preserves compression
TDIGEST.QUANTILETDIGEST.QUANTILE key q [q ...]Array of float stringsq must be in [0, 1]
TDIGEST.CDFTDIGEST.CDF key value [value ...]Array of float stringsCDF at each value
TDIGEST.RANKTDIGEST.RANK key value [value ...]Array of integersEstimated rank
TDIGEST.REVRANKTDIGEST.REVRANK key value [value ...]Array of integersReverse rank
TDIGEST.BYRANKTDIGEST.BYRANK key rank [rank ...]Array of float stringsValue at rank
TDIGEST.BYREVRANKTDIGEST.BYREVRANK key rank [rank ...]Array of float stringsValue at reverse rank
TDIGEST.TRIMMED_MEANTDIGEST.TRIMMED_MEAN key lo hiFloat stringlo must be < hi
TDIGEST.MINTDIGEST.MIN keyFloat string or "nan"
TDIGEST.MAXTDIGEST.MAX keyFloat string or "nan"
TDIGEST.INFOTDIGEST.INFO keyArray: Compression, Capacity, Merged/Unmerged nodes, weights, total_compressions, Memory usage
TDIGEST.MERGETDIGEST.MERGE dest numkeys key [key ...] [COMPRESSION c] [OVERRIDE]+OKOVERRIDE replaces dest; without it, merges into existing

Status: Uses FerricStoreBloom TDigest module syntax.


Geo Commands

Geo is implemented on top of Sorted Sets. Members are stored with 52-bit interleaved geohash scores (26 bits per axis, ~0.6mm precision), matching FerricStore's encoding. No new data structure is needed.

CommandSyntaxReturnNotes
GEOADDGEOADD key [NX|XX] [CH] lon lat member [...]Integer (added)Same flags as ZADD
GEOPOSGEOPOS key member [member ...]Array of [lon, lat] or null
GEODISTGEODIST key member1 member2 [M|KM|FT|MI]Bulk string (distance) or nullDefault unit: meters
GEOHASHGEOHASH key member [member ...]Array of 11-char base32 stringsStandard geohash alphabet
GEOSEARCHGEOSEARCH key FROMLONLAT lon lat|FROMMEMBER member BYRADIUS radius unit|BYBOX w h unit [ASC|DESC] [COUNT count [ANY]] [WITHCOORD] [WITHDIST] [WITHHASH]ArrayFull FerricStore GEOSEARCH syntax
GEOSEARCHSTOREGEOSEARCHSTORE dest source [GEOSEARCH opts] [STOREDIST]Integer (stored count)

Status: Supported including all GEOSEARCH options.


FerricStore-Native Commands

These commands extend beyond the FerricStore command set with operations not available in standard FerricStore.

CAS (Compare-and-Swap)

Atomically sets a key only if its current value matches the expected value. Routed directly through Router.cas/4.

Protocol commandCAS key expected new_value [EX seconds]
Embedded APIFerricStore.cas(key, expected, new_value)
Return1 (swapped), 0 (value mismatch), null (key missing)
Elixir return{:ok, true}, {:ok, false}, or {:ok, nil}

LOCK / UNLOCK / EXTEND

Distributed lock with owner identity and TTL. Routed through Router.lock/3, Router.unlock/2, Router.extend/3.

CommandSyntaxReturn
LOCKLOCK key owner ttl_ms+OK (acquired) or ERR (already held)
UNLOCKUNLOCK key owner1 (released) or ERR (wrong owner / not held)
EXTENDEXTEND key owner ttl_ms1 (extended) or ERR (wrong owner / not held)

RATELIMIT.ADD

Sliding window rate limiter. Routed through Router.ratelimit_add/4.

Protocol commandRATELIMIT.ADD key window_ms max_count [count]
Embedded APIFerricStore.ratelimit_add(key, window_ms, max)
ReturnArray: [allowed (0|1), current_count, remaining, retry_after_ms]
Default count1

FETCH_OR_COMPUTE

Cache-aside with stampede protection. The first caller to a missing key is designated the "computer" -- all concurrent callers block until the value is available.

CommandSyntaxReturn
FETCH_OR_COMPUTEFETCH_OR_COMPUTE key ttl_ms [hint]["hit", value] or ["compute", channel]
FETCH_OR_COMPUTE_RESULTFETCH_OR_COMPUTE_RESULT key value ttl_ms+OK
FETCH_OR_COMPUTE_ERRORFETCH_OR_COMPUTE_ERROR key message+OK

FERRICSTORE.KEY_INFO

Returns diagnostic metadata about a key.

Protocol commandFERRICSTORE.KEY_INFO key
ReturnArray: [type, T, value_size, N, ttl_ms, N, hot_cache_status, hot|cold, last_write_shard, N]

FERRICSTORE.DOCTOR

Runs bounded operator diagnostics and safe background repair jobs. This is an admin command intended for production debugging and dashboard actions. Inline CHECK reads bounded metadata only; expensive checks or repairs should be run with START so the client connection is not held.

Protocol commandFERRICSTORE.DOCTOR <subcommand> [args...]
Embedded APIInternal command surface only
ReturnMap with status, checks, job_id, or jobs depending on subcommand
ACL@admin; repair jobs are also @dangerous
Dashboard/dashboard/doctor

Supported scopes:

ScopeWhat It Checks
BITCASKKeydir availability, keydir binary bytes, data file count, and data bytes per shard
BLOB_REFSLarge-value blob segment metadata and protected blob refs
FLOW_LMDBFlow LMDB projection health, pending ops, oldest pending age, replay-safe lag, and degraded shards
ALLAll supported scopes

Subcommands:

CommandPurpose
FERRICSTORE.DOCTOR CHECK [SCOPE scope]Run a bounded inline check. Omitting SCOPE checks all scopes.
FERRICSTORE.DOCTOR CHECK SCOPES n scope...Run a bounded inline check for specific scopes.
FERRICSTORE.DOCTOR START CHECK [SCOPE scope]Start the same check as a background job and return job_id.
FERRICSTORE.DOCTOR START REPAIR PROJECTIONS SCOPE FLOW_LMDBFlush and reconcile the Flow LMDB cold projection from durable Flow records.
FERRICSTORE.DOCTOR STATUS job_idReturn one background job.
FERRICSTORE.DOCTOR LISTReturn known doctor jobs, newest first.
FERRICSTORE.DOCTOR CANCEL job_idCancel a running background job.

Examples:

FERRICSTORE.DOCTOR CHECK
FERRICSTORE.DOCTOR CHECK SCOPE FLOW_LMDB
FERRICSTORE.DOCTOR START CHECK SCOPE BITCASK
FERRICSTORE.DOCTOR START REPAIR PROJECTIONS SCOPE FLOW_LMDB
FERRICSTORE.DOCTOR STATUS doctor-1-123
FERRICSTORE.DOCTOR LIST

Repair notes:

  • START REPAIR PROJECTIONS SCOPE FLOW_LMDB repairs the cold/query projection only. It does not mutate hot Flow indexes or rewrite user state.
  • Flow command durability does not depend on LMDB projection being current; the durable source of truth remains FerricStore-managed WARaft segment/apply-projection storage.
  • Use this repair when FLOW_LMDB reports degraded shards or projection lag that does not drain after the underlying disk/LMDB issue is fixed.

Server Commands

PING / ECHO

CommandSyntaxReturn
PINGPING [message]+PONG (no args), or bulk string (with message)
ECHOECHO messageBulk string

INFO

Returns server information. Supports sections: server, clients, memory, keyspace, stats, persistence, replication, cpu, namespace_config, raft, bitcask, ferricstore, keydir_analysis. Use all or everything for all sections.

Protocol commandINFO [section]
FerricStore sectionsraft (per-shard role/term/commit), bitcask (per-shard file counts/sizes), ferricstore (raft committed, hot cache evictions), keydir_analysis (per-prefix key breakdown), namespace_config (group-commit settings)

The server section reports FerricStore version and native protocol metadata.

CONFIG

SubcommandSyntaxNotes
CONFIG GETCONFIG GET patternGlob pattern matching
CONFIG SETCONFIG SET key valueChanges logged to audit log
CONFIG SET LOCALCONFIG SET LOCAL key valueNode-local config override
CONFIG GET LOCALCONFIG GET LOCAL keyRead node-local config
CONFIG RESETSTATCONFIG RESETSTATResets stats + slowlog
CONFIG REWRITECONFIG REWRITEPersists config changes

SLOWLOG

SubcommandSyntaxReturn
SLOWLOG GETSLOWLOG GET [count]Array of [id, timestamp_us, duration_us, command]
SLOWLOG LENSLOWLOG LENInteger
SLOWLOG RESETSLOWLOG RESET+OK

COMMAND

SubcommandSyntaxReturn
COMMANDCOMMANDArray of command info tuples
COMMAND COUNTCOMMAND COUNTInteger
COMMAND LISTCOMMAND LISTArray of command names
COMMAND INFOCOMMAND INFO name [name ...]Array of info tuples (null for unknown)
COMMAND DOCSCOMMAND DOCS name [name ...]Interleaved [name, [summary]]
COMMAND GETKEYSCOMMAND GETKEYS cmd [args ...]Array of key arguments

CLIENT

Handled via dispatch_client/3 with per-connection state:

SubcommandSyntaxReturn
CLIENT IDCLIENT IDInteger (connection ID)
CLIENT SETNAMECLIENT SETNAME name+OK
CLIENT GETNAMECLIENT GETNAMEBulk string or null
CLIENT INFOCLIENT INFOInfo string for current connection
CLIENT LISTCLIENT LIST [TYPE type]Info string for all connections
CLIENT TRACKINGCLIENT TRACKING ON|OFF [REDIRECT id] [PREFIX ...] [BCAST] [OPTIN] [OPTOUT] [NOLOOP]+OK
CLIENT CACHINGCLIENT CACHING YES|NO+OK
CLIENT TRACKINGINFOCLIENT TRACKINGINFOTracking configuration
CLIENT GETREDIRCLIENT GETREDIRInteger (redirect target or 0)

Other Server Commands

CommandSyntaxReturnNotes
FLUSHDBFLUSHDB [ASYNC|SYNC]+OKBoth modes execute synchronously
FLUSHALLFLUSHALL [ASYNC|SYNC]+OKAlias for FLUSHDB
SELECTSELECT dbErrorSingle-database only
SAVESAVE+OKNo-op (Bitcask is always persisted)
BGSAVEBGSAVE+Background saving startedNo-op
LASTSAVELASTSAVEInteger (current timestamp)
LOLWUTLOLWUT [VERSION v]ASCII artFerricStore branding
DEBUG SLEEPDEBUG SLEEP seconds+OKTesting only. Logged to audit log.
MODULE LISTMODULE LISTEmpty arrayModules not supported
WAITAOFWAITAOF numlocal numreplicas timeout[0, 0]Stub
MEMORY USAGEMEMORY USAGE keyInteger (estimated bytes)

Transaction Commands

CommandSyntaxDescription
MULTIMULTIStart a transaction. Subsequent commands are queued (return +QUEUED).
EXECEXECExecute all queued commands atomically. Returns array of results. Returns null if WATCH detected a change.
DISCARDDISCARDDiscard queued commands, exit MULTI state.
WATCHWATCH key [key ...]Watch keys for changes. If any watched key is modified before EXEC, the transaction is aborted.
UNWATCHUNWATCHStop watching all keys.

Transactions work at the connection level. WATCH implements optimistic locking -- if a watched key is modified by another connection between WATCH and EXEC, EXEC returns null (transaction aborted).


Pub/Sub Commands

CommandSyntaxReturn
SUBSCRIBESUBSCRIBE channel [channel ...]Push messages: [subscribe, channel, count]
UNSUBSCRIBEUNSUBSCRIBE [channel ...]Push messages: [unsubscribe, channel, count]
PSUBSCRIBEPSUBSCRIBE pattern [pattern ...]Push messages: [psubscribe, pattern, count]
PUNSUBSCRIBEPUNSUBSCRIBE [pattern ...]Push messages: [punsubscribe, pattern, count]
PUBLISHPUBLISH channel messageInteger (subscribers that received)
PUBSUB CHANNELSPUBSUB CHANNELS [pattern]Array of active channels
PUBSUB NUMSUBPUBSUB NUMSUB [channel ...]Array of [channel, count, ...]
PUBSUB NUMPATPUBSUB NUMPATInteger (pattern subscriptions)

ACL Commands

CommandSyntaxDescription
ACL SETUSERACL SETUSER username [rule ...]Create/update user
ACL DELUSERACL DELUSER username [username ...]Delete user(s)
ACL GETUSERACL GETUSER usernameGet user info
ACL LISTACL LISTList all users
ACL WHOAMIACL WHOAMICurrent user
ACL SAVEACL SAVEPersist ACL to file
ACL LOADACL LOADLoad ACL from file
AUTHAUTH [username] passwordAuthenticate connection

FerricStore Command Notes

  1. Single database -- SELECT returns an error. FerricStore is single-database.
  2. Native TCP mode -- clients start with HELLO/STARTUP on the native control lane.
  3. No Lua scripting -- EVAL/EVALSHA are not implemented. Use CAS, LOCK, and FETCH_OR_COMPUTE for atomic operations.
  4. No blocking commands in embedded mode -- BLPOP, BRPOP, BLMOVE, BLMPOP, XREAD BLOCK require a TCP connection.
  5. Probabilistic structures are built-in -- available without an external module. BF, CF, CMS, TopK, TDigest are all native.
  6. CAS is a native command -- available as a direct compare-and-swap command. WATCH/MULTI/EXEC is also supported.
  7. FETCH_OR_COMPUTE -- built-in cache stampede protection.
  8. Group commit -- writes are batched for higher throughput. Individual write latency includes the batch window (default 1ms). Use hash tags {tag} to colocate related keys on the same shard for maximum batching -- see Best Practices.
  9. HLC timestamps -- expiry uses Hybrid Logical Clock timestamps instead of wall-clock time. Monotonic even during clock skew.
  10. Compound key storage -- hash fields, set members, and zset members are stored as individual Bitcask entries with structured key prefixes, enabling O(1) field-level access without deserializing the entire data structure.
  11. SCAN cursor -- uses alphabetic key position, a key-position cursor rather than an opaque hash-table cursor. Functionally equivalent but cursor values differ.
  12. OBJECT ENCODING -- returns type-specific encodings ("embstr", "raw", "hashtable", "quicklist", "skiplist", "stream") and does not expose implementation-specific internal encodings such as ziplist, listpack, or intset.
  13. INFO sections -- includes FerricStore-specific sections: raft, bitcask, ferricstore, keydir_analysis, namespace_config.