kevy 6.4.0

kevy — a pure-Rust, zero-dependency, Redis-compatible KV server.
Documentation
//! 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"),
];