//! Connection, server, transactions, scripting, pub/sub and replication.
//!
//! One row per dispatch-reachable verb. `complexity` and `compat` were
//! derived by reading THIS engine's implementation — never copied from
//! Redis's documentation, because several of ours genuinely differ (SCAN
//! sweeps in one batch, SPOP is deterministic, LINDEX is O(1) where
//! Redis's quicklist is O(N)).
use super::flags::*;
use super::{VerbMeta, v};
#[rustfmt::skip]
pub(super) const ROWS: &[VerbMeta] = &[
// ---- connection ------------------------------------------------
v("ECHO", "connection", 2, R, "Return the given message.", "1.0.0", "ECHO message",
"O(1)",
"full"),
v("HELLO", "connection", -1, R, "Handshake: report server info and switch RESP protocol version (2 or 3).", "1.0.0", "HELLO [protover]",
"O(1)",
"differs: only HELLO [2|3] is honoured — the AUTH and SETNAME tails are parsed off and ignored, because kevy has no AUTH and this form does not set the connection name"),
v("PING", "connection", -1, R, "Ping the server; returns PONG or echoes the optional message.", "1.0.0", "PING [message]",
"O(1)",
"differs: kevy has no RESP2 subscriber mode, so PING while subscribed does not switch to the array form and non-pubsub commands stay legal on a subscribed connection"),
v("QUIT", "connection", 1, R, "Close the connection after replying OK.", "1.0.0", "QUIT",
"O(1)",
"full"),
v("SELECT", "connection", 2, R, "Select the logical database; kevy is single-DB and only accepts index 0.", "1.0.0", "SELECT index",
"O(1)",
"differs: kevy is single-DB — SELECT 0 replies OK and any other index is an error"),
// ---- server ----------------------------------------------------
v("BGREWRITEAOF", "server", 1, WAD, "Start an append-only-file rewrite in the background.", "1.0.0", "BGREWRITEAOF",
"O(S) fan-out; each shard freezes a copy-on-write view and hands serialise plus fsync to its own worker",
"differs: replies +OK rather than Redis's status line, rewrites one AOF per shard, and replies +OK even when AOF is disabled"),
v("BGSAVE", "server", 1, WAD, "Start a snapshot save in the background.", "1.0.0", "BGSAVE",
"O(S) fan-out; O(N/S) copy-on-write freeze per shard on the reactor, then serialise off-thread",
"differs: replies +OK rather than Redis's status line, and writes one dump per shard"),
v("TIME", "server", 1, R, "Return the server clock as unix seconds and microseconds.", "1.0.0", "TIME",
"O(1)",
"full"),
v("COMMAND", "server", -1, R, "Introspect the command table (COUNT, LIST, INFO, DOCS subcommands).", "1.0.0", "COMMAND [COUNT | LIST | INFO command [command ...] | DOCS [command [command ...]]]",
"bare / LIST / DOCS: O(V) verbs. COUNT: O(1). INFO / DOCS with k names: O(k*V) — the lookup is a linear scan",
"differs: COUNT / LIST / INFO / DOCS only — GETKEYS and GETKEYSANDFLAGS are absent, and the info rows hard-code first/last/step and leave ACL categories, tips and key-specs empty"),
v("CONFIG", "server", -2, WAD, "Read or change server configuration parameters.", "1.0.0", "CONFIG GET parameter | SET parameter value | REWRITE | RESETSTAT",
"GET: O(patterns * 16). SET: O(1) plus one config swap that shards pick up on their next tick. REWRITE: O(config file size)",
"differs: 16 Redis-named parameters exist; only maxmemory, maxmemory-policy, appendfsync, the auto-rewrite pair, hz, maxmemory-samples, loglevel and logfile are hot-settable — bind, port, io-threads, dir and appendonly error at runtime; RESETSTAT is a no-op"),
v("CLIENT", "server", -2, AD, "Connection introspection and control subcommands.", "1.0.0", "CLIENT ID | GETNAME | SETNAME name | LIST | KILL filter | INFO | NO-EVICT ON|OFF",
"ID / GETNAME / SETNAME / INFO: O(1). LIST: O(S) fan-out + O(C) rows. KILL: O(S) + O(C) scan",
"differs: ID / GETNAME / SETNAME / INFO / LIST (bare) / KILL (ID, ADDR) / NO-EVICT only; CLIENT LIST with a filter is a syntax error and every other subcommand (PAUSE, REPLY, TRACKING, UNBLOCK, NO-TOUCH) is unknown"),
v("CLUSTER", "server", -2, AD, "Cluster topology introspection (virtual-node model over shards).", "1.0.0", "CLUSTER INFO | NODES | SLOTS | SHARDS | KEYSLOT key | COUNTKEYSINSLOT slot",
"INFO / NODES / SLOTS / SHARDS / MYID: O(S). KEYSLOT: O(len(key)). COUNTKEYSINSLOT: O(N/S)",
"differs: a read-only virtual-node topology derived from config (one virtual master per shard) — no gossip, no MEET / FORGET / SETSLOT effect (they reply OK as no-ops), no MIGRATE / ASK, no failover; COUNTKEYSINSLOT counts only the answering shard's keys"),
v("DBSIZE", "server", 1, R, "Return the number of keys across all shards.", "1.0.0", "DBSIZE",
"O(S) — one message per shard, each answering O(1) from its map length; NOT O(N)",
"full"),
v("DEBUG", "server", -2, AD, "Debug subcommands; SLEEP blocks the shard, other subcommands are tolerated as OK.", "1.0.0", "DEBUG SLEEP seconds | subcommand [args ...]",
"SLEEP: parks the ANSWERING shard's reactor thread for the duration (other shards keep serving). Everything else: O(1)",
"differs: SLEEP is the only subcommand with an effect and it blocks one shard, not the server; every other subcommand is accepted and answered OK without doing anything"),
v("FLUSHALL", "server", -1, W, "Delete every key on every shard.", "1.0.0", "FLUSHALL",
"O(S) fan-out; per shard O(N/S) clear plus WATCH invalidation plus a feed-generation bump",
"differs: ASYNC / SYNC are accepted and ignored (the flush is always synchronous per shard), and it bumps the CDC feed generation, so live FEED cursors get a resync error"),
v("FLUSHDB", "server", -1, W, "Delete every key of the current database (kevy is single-DB: same as FLUSHALL).", "1.0.0", "FLUSHDB",
"O(N + S) — identical to FLUSHALL",
"differs: kevy is single-DB, so FLUSHDB is an alias of FLUSHALL; ASYNC / SYNC are ignored"),
v("INFO", "server", -1, R, "Report server statistics and status sections as text.", "1.0.0", "INFO [section]",
"O(1) in the keyspace — it never walks it; O(S) to sum the per-shard gauges",
"differs: 8 sections only (server, clients, memory, persistence, stats, replication, cluster, keyspace) — no commandstats / latencystats / errorstats / cpu; reports redis_version 7.4.0 for client sniffing plus a kevy_version line, and the values are up to one tick stale"),
v("MEMORY", "server", -2, R, "Memory introspection subcommands.", "1.0.0", "MEMORY USAGE key [SAMPLES count] | STATS | DOCTOR | PURGE | MALLOC-STATS",
"USAGE: O(1) — the accounting is exact, not sampled. STATS: O(1) from the instance-wide gauges",
"differs: USAGE's SAMPLES count is parsed and ignored (our accounting is exact); PURGE is a no-op (system allocator, no arena); DOCTOR and MALLOC-STATS return canned strings; STATS is a trimmed 8-field set"),
v("SAVE", "server", 1, WAD, "Synchronously snapshot the dataset to disk.", "1.0.0", "SAVE",
"O(S) fan-out; O(N/S) copy-on-write freeze per shard",
"differs: SAVE is no longer synchronous-until-durable — it freezes a copy-on-write view and replies OK immediately, so 'SAVE returned, therefore the dump is safe to copy' no longer holds"),
v("SHUTDOWN", "server", -1, WAD, "Stop the server process (connection drops without a reply).", "1.0.0", "SHUTDOWN [NOSAVE|SAVE]",
"O(1) to trip the stop flag; the drain that follows is O(N)",
"differs: only SHUTDOWN [NOSAVE|SAVE] parses — NOW, FORCE and ABORT are a syntax error"),
v("SLOWLOG", "server", -2, AD, "Inspect or reset the slow-command log.", "1.0.0", "SLOWLOG GET [count] | LEN | RESET | HELP",
"GET: O(S) fan-out plus O(L log L) to merge. LEN: O(S). RESET: O(S)",
"differs: the log is per-shard and GET merges across shards by timestamp, so ids are not globally monotonic; every entry's client-addr and client-name are empty strings"),
// ---- replication -----------------------------------------------
v("FAILOVER", "replication", -3, WAD, "Planned zero-loss handover: quiesce writes, wait for the target replica to drain, promote it, and follow it.", "3.0.0", "FAILOVER host port [TIMEOUT ms] | ABORT",
"O(1) at the command — the handover runs in the background, polling the target until it is caught up",
"differs: Redis's syntax is FAILOVER [TO host port [FORCE]] [ABORT] [TIMEOUT ms] with an optional target; kevy's is FAILOVER host port [TIMEOUT ms] | ABORT — the target is mandatory and positional, and the port given is the target's client port"),
v("REPL.TOKEN", "replication", 1, RX, "kevy extension: mint a read-your-writes token — per-shard [generation, offset] pairs (a primary reports its live feed tail; a replica its applied positions).", "3.0.0", "REPL.TOKEN",
"O(S) — one (generation, offset) pair per shard",
"kevy-only: the read-your-writes token; the nearest Redis concept is master_repl_offset, which is not a resumable per-shard cursor"),
v("REPL.WAIT", "replication", -3, RBX, "kevy extension: on a replica, block until every shard has applied the given REPL.TOKEN (then reads are read-your-writes); +OK on success, -MISDIRECTED writer is <primary> on timeout or generation mismatch. Default TIMEOUT 1000 ms, hard cap 60 s. On a primary: immediate +OK.", "3.0.0", "REPL.WAIT gen offset [gen offset ...] [TIMEOUT milliseconds]",
"O(S) — a barrier, not a keyspace op; the wall-clock cost is the replication lag, bounded by TIMEOUT (default 1s, hard-capped at 60s)",
"kevy-only: waits until a (generation, offset) token has been applied, which is what makes read-your-writes possible across a failover"),
v("REPLICAOF", "replication", 3, WAD, "Make this server a replica of another, or promote it with NO ONE.", "1.0.0", "REPLICAOF host port | NO ONE",
"O(1) at the command; the full resync that follows is O(N) in the background",
"differs: the port argument is the primary's REPLICATION port base, not its client port (the default base is client port + 10000); chain replication is rejected"),
v("ROLE", "replication", 1, R, "Report the replication role and state of this server.", "1.0.0", "ROLE",
"O(1) on a replica; O(R) on a primary",
"full"),
v("SLAVEOF", "replication", 3, WAD, "Legacy alias of REPLICAOF.", "1.0.0", "SLAVEOF host port | NO ONE",
"O(1) plus a background resync",
"differs: a deprecated alias of REPLICAOF, including the replication-port-base argument"),
v("WAIT", "replication", 3, RB, "Block until every shard's master_repl_offset is acknowledged by at least numreplicas replicas (or timeout ms pass); returns the minimum acked-replica count across shards. timeout 0 = wait forever, hard-capped at 60 s. NOTE: a replica ACK is not fsync durability.", "1.0.0", "WAIT numreplicas timeout",
"O(S) — an all-shard barrier returning the MINIMUM acked-replica count; the wall-clock cost is the replication round trip",
"differs: it is an all-shard barrier returning the minimum across shards (Redis has one offset to wait on); timeout 0 is capped at 60s rather than blocking forever, and an ACK means the frame reached the replica's apply pipeline, not fsync durability"),
// ---- tx --------------------------------------------------------
v("DISCARD", "tx", 1, TX, "Abort the open MULTI transaction.", "1.0.0", "DISCARD",
"O(1) — drops the queued commands and the WATCH set",
"full"),
v("EXEC", "tx", 1, TX, "Execute every command queued since MULTI.", "1.0.0", "EXEC",
"O(sum of the queued commands' costs); with W watched keys, one extra O(W) pre-check fanned into O(min(W,S)) messages",
"differs: a MULTI batch spanning several shards is per-shard-atomic, not globally isolated (there is no cross-shard snapshot); a queue-time error aborts the whole batch with EXECABORT, but a runtime error inside EXEC leaves the other commands applied, as in Redis"),
v("MULTI", "tx", 1, TX, "Start a transaction; subsequent commands are queued until EXEC.", "1.0.0", "MULTI",
"O(1)",
"full"),
v("UNWATCH", "tx", 1, TX, "Forget all watched keys.", "1.0.0", "UNWATCH",
"O(1)",
"full"),
v("WATCH", "tx", -2, TX, "Watch keys for optimistic locking of the next EXEC.", "1.0.0", "WATCH key [key ...]",
"O(W) keys, grouped into O(min(W,S)) cross-shard messages",
"full"),
// ---- pubsub ----------------------------------------------------
v("PSUBSCRIBE", "pubsub", -2, PS, "Subscribe to channels matching the given glob patterns.", "1.0.0", "PSUBSCRIBE pattern [pattern ...]",
"O(p * P) — each pattern costs a linear scan of the shared pattern registry",
"full"),
v("PUBLISH", "pubsub", 3, PS, "Post a message to a channel; returns the receiver count.", "1.0.0", "PUBLISH channel message",
"O(1) channel lookup + O(P) — a linear walk of the registered patterns with one glob match each, even when none match. Delivery fans out only to the shards holding a subscriber",
"full"),
v("PUNSUBSCRIBE", "pubsub", -1, PS, "Unsubscribe from patterns (all patterns when none given).", "1.0.0", "PUNSUBSCRIBE [pattern [pattern ...]]",
"O(p * P)",
"full"),
v("SUBSCRIBE", "pubsub", -2, PS, "Subscribe to the given channels.", "1.0.0", "SUBSCRIBE channel [channel ...]",
"O(c) channels; never fans out to other shards",
"differs: kevy has no RESP2 subscriber mode — after SUBSCRIBE the connection may still issue any command, where Redis restricts it to the pubsub verbs plus PING / QUIT / RESET"),
v("UNSUBSCRIBE", "pubsub", -1, PS, "Unsubscribe from channels (all channels when none given).", "1.0.0", "UNSUBSCRIBE [channel [channel ...]]",
"O(c) channels",
"full"),
// ---- script ----------------------------------------------------
v("EVAL", "script", -3, W, "Run a Lua script server-side; routed to KEYS[1]'s shard when numkeys >= 1.", "1.0.0", "EVAL script numkeys [key [key ...]] [arg [arg ...]]",
"O(compile + the script's own work). The whole script is one atomic unit on KEYS[1]'s shard and blocks that shard for its duration. The runaway guard is an INSTRUCTION budget (lua time_limit_ms x 40000 instructions), not a wall clock",
"differs: there is no -BUSY state and no SCRIPT KILL — an over-budget script is aborted in place and answered with an ordinary error; nested EVAL is rejected, a redis.call touching another shard's key returns CROSSSLOT, and EVAL auto-caches its source by SHA1 so EVALSHA works without SCRIPT LOAD. Scripts replicate by SOURCE, not by effects: a script calling SPOP draws its own random members on a replica or an AOF replay — keep nondeterministic verbs out of scripts you replicate (plain SPOP outside EVAL propagates its effect and is safe)"),
v("EVALSHA", "script", -3, W, "Run a cached Lua script by its SHA1 digest.", "1.0.0", "EVALSHA sha1 numkeys [key [key ...]] [arg [arg ...]]",
"O(1) cache lookup, then identical to EVAL",
"differs: same instruction-budget model as EVAL (no -BUSY, no SCRIPT KILL); the cache is process-wide and EVAL populates it"),
v("SCRIPT", "script", -2, R, "Manage the process-wide Lua script cache.", "1.0.0", "SCRIPT LOAD script | EXISTS sha1 [sha1 ...] | FLUSH [ASYNC|SYNC]",
"LOAD: O(len(script)). EXISTS: O(k). FLUSH: O(cached scripts)",
"differs: LOAD / EXISTS / FLUSH only — SCRIPT KILL does not exist, by design: there is no -BUSY state to interrupt because an over-budget script self-aborts"),
];