kevy 5.1.0

kevy — a pure-Rust, zero-dependency, Redis-compatible KV server.
Documentation
//! Strings, the generic key surface, and the keyspace sweeps.
//!
//! 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::{VerbMeta, v};
use super::flags::*;

#[rustfmt::skip]
pub(super) const ROWS: &[VerbMeta] = &[
    // ---- scan ------------------------------------------------------
    v("KEYS",        "scan", 2,  R, "Return every key matching the glob pattern (cross-shard gather).", "1.0.0", "KEYS pattern",
      "O(N) keys in the whole keyspace — every shard walks its entire map, plus an O(P*K) glob match per key",
      "full"),
    v("RANDOMKEY",   "scan", 1,  R, "Return a random key from the keyspace.", "1.0.0", "RANDOMKEY",
      "O(1) expected — each shard probes a random slot, and the origin folds the candidates through a reservoir weighted by shard key counts, so every key is equally likely",
      "full"),
    v("SCAN",        "scan", -2, R, "Iterate the keyspace incrementally: each call walks ~COUNT buckets of one shard and returns the next cursor.", "4.0.0", "SCAN cursor [MATCH pattern] [COUNT count] [TYPE type]",
      "O(COUNT) buckets per call, amortised O(N) for a full sweep — reverse-binary cursor, rehash-tolerant (a key present for the whole sweep is returned at least once even across table growth)",
      "differs: cursors encode (shard, position), so a cursor is only valid on the server and shard count that issued it — the same per-node property Redis Cluster cursors have. MATCH and TYPE filter after collection; COUNT bounds the buckets visited, not the keys returned"),
    // ---- generic ---------------------------------------------------
    v("DEL",         "generic", -2, W, "Delete one or more keys.", "1.0.0", "DEL key [key ...]",
      "O(N) keys, plus O(M) per key holding a collection of M elements (the drop walks the container)",
      "differs: the multi-key form is split by shard and summed with no barrier, so it is not atomic across shards; the single-key form is"),
    v("EXISTS",      "generic", -2, R, "Count how many of the given keys exist.", "1.0.0", "EXISTS key [key ...]",
      "O(N) keys, one O(1) probe each",
      "differs: the multi-key form is gathered per shard, so the count is not a point-in-time snapshot across shards"),
    v("EXPIRE",      "generic", 3,  W, "Set a key's TTL in seconds (non-positive TTL deletes the key).", "1.0.0", "EXPIRE key seconds",
      "O(1)",
      "differs: the NX / XX / GT / LT condition flags are not parsed — arity is fixed at 3, so EXPIRE key seconds NX is a wrong-arity error"),
    v("EXPIREAT",    "generic", 3,  W, "Set a key's expiry as an absolute Unix timestamp in seconds.", "1.0.0", "EXPIREAT key unix-time-seconds",
      "O(1)",
      "differs: the NX / XX / GT / LT condition flags are not parsed — arity is fixed at 3"),
    v("PERSIST",     "generic", 2,  W, "Remove a key's TTL.", "1.0.0", "PERSIST key",
      "O(1)",
      "full"),
    v("PEXPIRE",     "generic", 3,  W, "Set a key's TTL in milliseconds.", "1.0.0", "PEXPIRE key milliseconds",
      "O(1)",
      "differs: the NX / XX / GT / LT condition flags are not parsed — arity is fixed at 3"),
    v("PEXPIREAT",   "generic", 3,  W, "Set a key's expiry as an absolute Unix timestamp in milliseconds.", "1.0.0", "PEXPIREAT key unix-time-milliseconds",
      "O(1)",
      "differs: the NX / XX / GT / LT condition flags are not parsed — arity is fixed at 3"),
    v("PTTL",        "generic", 2,  R, "Return a key's remaining TTL in milliseconds (-1 no TTL, -2 missing).", "1.0.0", "PTTL key",
      "O(1)",
      "full"),
    v("RENAME",      "generic", 3,  W, "Rename a key, overwriting the destination (write routed at the runtime Op level).", "1.0.0", "RENAME key newkey",
      "O(1) for a string value; O(M) for a collection of M elements (the entry's weight is re-derived by walking the value)",
      "differs: a cross-shard rename is a non-atomic Take then Put — there is a window in which neither key is visible; co-locate the two keys with a {hashtag} for the atomic path"),
    v("RENAMENX",    "generic", 3,  W, "Rename a key only if the destination does not exist (write routed at the runtime Op level).", "1.0.0", "RENAMENX key newkey",
      "O(1) for a string value; O(M) for a collection of M elements",
      "differs: cross-shard RENAMENX is a non-atomic Take, Put, restore-on-refusal sequence — there is a window in which the source is absent from the keyspace"),
    v("TTL",         "generic", 2,  R, "Return a key's remaining TTL in seconds (-1 no TTL, -2 missing).", "1.0.0", "TTL key",
      "O(1)",
      "full"),
    v("TYPE",        "generic", 2,  R, "Return the type of the value stored at key.", "1.0.0", "TYPE key",
      "O(1)",
      "full"),
    v("UNLINK",      "generic", -2, W, "Delete one or more keys (alias of DEL in kevy's shard model).", "1.0.0", "UNLINK key [key ...]",
      "O(N) keys, plus O(M) per collection-typed key — identical to DEL",
      "differs: UNLINK is an alias of DEL — the value is freed inline on the owning shard's reactor thread, not by a background thread, so it gives no latency benefit"),
    // ---- string ----------------------------------------------------
    v("APPEND",      "string", 3,  W, "Append bytes to a string value; returns the new length.", "1.0.0", "APPEND key value",
      "O(1) amortised while the value is <= 64 B; O(N) per call once it exceeds that (the Arc payload is copied out and re-boxed on every append), so building a large string by repeated APPEND is O(N^2)",
      "full"),
    v("DECR",        "string", 2,  W, "Decrement the integer value of a key by one.", "1.0.0", "DECR key",
      "O(1)",
      "full"),
    v("DECRBY",      "string", 3,  W, "Decrement the integer value of a key by the given amount.", "1.0.0", "DECRBY key decrement",
      "O(1)",
      "full"),
    v("GET",         "string", 2,  R, "Return the string value of a key.", "1.0.0", "GET key",
      "O(1)",
      "full"),
    v("GETDEL",      "string", 2,  W, "Return the string value of a key and delete it.", "1.0.0", "GETDEL key",
      "O(1)",
      "full"),
    v("GETSET",      "string", 3,  W, "Set a key's string value and return its previous value.", "1.0.0", "GETSET key value",
      "O(1)",
      "full"),
    v("INCR",        "string", 2,  W, "Increment the integer value of a key by one.", "1.0.0", "INCR key",
      "O(1)",
      "full"),
    v("INCRBY",      "string", 3,  W, "Increment the integer value of a key by the given amount.", "1.0.0", "INCRBY key increment",
      "O(1)",
      "full"),
    v("INCRBYFLOAT", "string", 3,  W, "Increment the float value of a key by the given amount.", "1.0.0", "INCRBYFLOAT key increment",
      "O(1)",
      "differs: arithmetic is f64 and the reply uses Rust's shortest-round-trip float printer, not a long double accumulator, so trailing digits can diverge from Redis"),
    v("MGET",        "string", -2, R, "Return the values of multiple keys (cross-shard gather).", "1.0.0", "MGET key [key ...]",
      "O(N) keys, one O(1) probe each on the owning shard",
      "differs: keys are grouped by shard and each shard is probed independently, so the reply is not a point-in-time snapshot across shards"),
    v("MSET",        "string", -3, W, "Set multiple key/value pairs atomically per shard.", "1.0.0", "MSET key value [key value ...]",
      "O(N) pairs, one O(1) SET each",
      "differs: atomic only per shard — pairs are split by key and applied shard-by-shard with no cross-shard barrier, so a reader can observe some pairs written and others not; Redis MSET is globally atomic"),
    v("PSETEX",      "string", 4,  W, "Set a key's value with a TTL in milliseconds.", "1.0.0", "PSETEX key milliseconds value",
      "O(1)",
      "full"),
    v("SET",         "string", -3, W, "Set a key's string value with optional TTL and existence conditions.", "1.0.0", "SET key value [EX seconds|PX milliseconds] [NX|XX]",
      "O(1)",
      "differs: only NX / XX / EX / PX are parsed — KEEPTTL, EXAT, PXAT, GET and the IFEQ family are a syntax error; a repeated expire option is silently accepted last-one-wins instead of erroring"),
    v("SETEX",       "string", 4,  W, "Set a key's value with a TTL in seconds.", "1.0.0", "SETEX key seconds value",
      "O(1)",
      "full"),
    v("SETNX",       "string", 3,  W, "Set a key's value only if it does not exist.", "1.0.0", "SETNX key value",
      "O(1)",
      "full"),
    v("STRLEN",      "string", 2,  R, "Return the length of a key's string value.", "1.0.0", "STRLEN key",
      "O(1)",
      "full"),
];