Skip to main content

Commands

Trait Commands 

Source
pub trait Commands:
    Clone
    + Send
    + 'static {
Show 25 methods // Required methods fn route<A: ArgvView + ?Sized>(&self, args: &A) -> Route; fn dispatch<A: ArgvView + ?Sized>( &self, store: &mut Store, args: &A, ) -> Vec<u8> ; fn is_quit<A: ArgvView + ?Sized>(&self, args: &A) -> bool; fn is_write<A: ArgvView + ?Sized>(&self, args: &A) -> bool; fn txn_kind<A: ArgvView + ?Sized>(&self, args: &A) -> TxnKind; // Provided methods fn dispatch_resp3<A: ArgvView + ?Sized>( &self, store: &mut Store, args: &A, ) -> Vec<u8> { ... } fn dispatch_into<A: ArgvView + ?Sized>( &self, store: &mut Store, args: &A, out: &mut Vec<u8>, ) { ... } fn dispatch_into_resp3<A: ArgvView + ?Sized>( &self, store: &mut Store, args: &A, out: &mut Vec<u8>, ) { ... } fn notify_class<A: ArgvView + ?Sized>( &self, _args: &A, ) -> Option<NotifyClass> { ... } fn hello_reply<A: ArgvView + ?Sized>( &self, _args: &A, current_proto: RespVersion, ) -> (RespVersion, Vec<u8>) { ... } fn on_shard_init(&self, _store: &mut Store) { ... } fn on_shard_start(&self, _shard: usize) { ... } fn on_persist_stats(&self, _in_flight: bool, _aof_rewrites_total: u64) { ... } fn on_replication_view( &self, _master_repl_offset: u64, _replicas: Vec<(Ipv4Addr, u16, u64)>, ) { ... } fn on_shard_tick(&self, _store: &mut Store) { ... } fn on_command(&self) { ... } fn on_connection(&self) { ... } fn shard_tick_interval_ms(&self) -> u64 { ... } fn live_runtime_config(&self) -> LiveRuntimeConfig { ... } fn wake_idx<A: ArgvView + ?Sized>(&self, _args: &A) -> Option<u8> { ... } fn block_hint<A: ArgvView + ?Sized>(&self, _args: &A) -> BlockHint { ... } fn resolve_block_argv<A: ArgvView + ?Sized>( &self, _store: &mut Store, args: &A, _kind: BlockKind, ) -> Argv { ... } fn block_serve_argv<A: ArgvView + ?Sized>( &self, args: &A, _kind: BlockKind, _key: &[u8], ) -> Argv { ... } fn block_ready<A: ArgvView + ?Sized>( &self, _store: &mut Store, _serve_argv: &A, _kind: BlockKind, ) -> bool { ... } fn resolve<A: ArgvView + ?Sized>(&self, args: &A) -> ResolvedCmd { ... }
}
Expand description

Command-set semantics injected into the runtime. Cloned to every core, so it must be cheap/stateless to clone.

Required Methods§

Source

fn route<A: ArgvView + ?Sized>(&self, args: &A) -> Route

Classify how a command is routed across shards.

Source

fn dispatch<A: ArgvView + ?Sized>(&self, store: &mut Store, args: &A) -> Vec<u8>

Execute a full command against one shard’s store, returning RESP bytes.

Source

fn is_quit<A: ArgvView + ?Sized>(&self, args: &A) -> bool

Whether this command should close the connection (QUIT).

Source

fn is_write<A: ArgvView + ?Sized>(&self, args: &A) -> bool

Whether this command mutates the keyspace (so it must be logged to the AOF).

Source

fn txn_kind<A: ArgvView + ?Sized>(&self, args: &A) -> TxnKind

Transaction-control classification (MULTI/EXEC/DISCARD vs anything else).

Provided Methods§

Source

fn dispatch_resp3<A: ArgvView + ?Sized>( &self, store: &mut Store, args: &A, ) -> Vec<u8>

RESP3 variant of Self::dispatch — called when the connection has negotiated HELLO 3. Default: delegate to the RESP2 path (the cross-shard forward carries a per-cmd RespVersion so a V2 client and a V3 client can share the owning shard).

Source

fn dispatch_into<A: ArgvView + ?Sized>( &self, store: &mut Store, args: &A, out: &mut Vec<u8>, )

Execute a command, appending the RESP reply to out. The in-order local fast path uses this to write straight into the connection’s output buffer (no per-command reply Vec). Default: delegate to dispatch.

Source

fn dispatch_into_resp3<A: ArgvView + ?Sized>( &self, store: &mut Store, args: &A, out: &mut Vec<u8>, )

RESP3 variant of Self::dispatch_into — called when the connection has negotiated HELLO 3. Default: delegate to the RESP2 path (so a server that hasn’t migrated any replies still works correctly with a RESP3 client, per spec). Override per command to emit RESP3 shapes (Map / Set / Double / …).

Source

fn notify_class<A: ArgvView + ?Sized>(&self, _args: &A) -> Option<NotifyClass>

Classify a command for keyspace notifications. Returns Some for write commands that should fire a notification when the corresponding flag is enabled; None for read-only / no-op / not-yet-classified commands (those never publish). Default None so non-kevy embedders pay nothing.

Source

fn hello_reply<A: ArgvView + ?Sized>( &self, _args: &A, current_proto: RespVersion, ) -> (RespVersion, Vec<u8>)

Handle HELLO — return the new connection protocol version + the reply bytes. The runtime applies the new version to the conn before scheduling the reply, so a HELLO 3 ack itself comes out shaped as a RESP3 Map (the new protocol is in effect for its own reply).

Default: ignore the args, keep current_proto, emit a minimal RESP2 +OK so embedders that don’t care still see a sane reply. kevy’s own impl in kevy::KevyCommands parses the optional protover and emits the full server-info shape.

Source

fn on_shard_init(&self, _store: &mut Store)

Called once per shard, immediately after Store::new, before the reactor enters its event loop. Implementations install per-shard configuration that the runtime doesn’t know about — currently the maxmemory + eviction-policy pair, which kevy ships via its own process-wide config snapshot. Default: no-op so non-kevy embedders aren’t forced to override.

Source

fn on_shard_start(&self, _shard: usize)

Called once on the shard’s own thread, first thing in the reactor entry (both reactors), before restore/replay. Implementations that need per-shard identity at dispatch time (e.g. kevy’s CLUSTER MYID / CLUSTER NODES myself flag) stash shard in a thread-local here — in a thread-per-core runtime the current thread is the shard. Default: no-op.

Source

fn on_persist_stats(&self, _in_flight: bool, _aof_rewrites_total: u64)

Per-tick persistence-stats publication: whether this shard has a background save/rewrite in flight and how many AOF rewrites have completed since open. Command layers that serve INFO persistence stash these in a thread-local (thread-per-core: the answering thread is the shard, same pattern as Self::on_shard_start). Default: no-op.

Source

fn on_replication_view( &self, _master_repl_offset: u64, _replicas: Vec<(Ipv4Addr, u16, u64)>, )

Per-tick replication-view publication: the answering shard’s current master_repl_offset (== ReplicationSource::next_offset()) plus the per-replica (ipv4, port, sent_offset) triple for every handshake-complete replica (in AckSent, Streaming, or SnapshotShipping). connected_slaves for INFO / ROLE is derived as replicas.len(). Only called when this shard has a ReplicationSource installed (i.e. Runtime::with_replication(true, ...) was requested); standalone setups pay nothing. Command layers that serve ROLE / INFO replication stash the values in a thread-local (thread-per-core: the answering thread is the shard, same pattern as Self::on_persist_stats). Default no-op.

Source

fn on_shard_tick(&self, _store: &mut Store)

Periodic shard housekeeping (the equivalent of Redis’s serverCron). kevy uses this to run Store::tick_expire at the configured [expiry].hz. Default no-op so non-kevy embedders / runtimes can ignore it.

Source

fn on_command(&self)

Called once per client command at dispatch entry (before routing / fan-out, so a multi-key command counts once). kevy uses it for INFO stats: total_commands_processed. Hot path — keep it to a single thread-local bump. Default no-op so non-kevy embedders pay nothing.

Source

fn on_connection(&self)

Called once per accepted client connection. kevy uses it for INFO stats: total_connections_received. Default no-op.

Source

fn shard_tick_interval_ms(&self) -> u64

Interval between Self::on_shard_tick calls. Default 100 ms (matching Redis’s hz = 10). 0 disables ticking entirely.

Source

fn live_runtime_config(&self) -> LiveRuntimeConfig

Snapshot of the runtime-owned knobs that can be hot-modified (the kevy server wires this to CONFIG SET). Called once per shard tick — each Some value is applied to the shard’s live state; each None keeps the existing setting untouched.

Default returns all-None so embedders that never hot-swap config pay nothing beyond one struct-build per tick. The cost lives in the impl’s read of its own config source.

Source

fn wake_idx<A: ArgvView + ?Sized>(&self, _args: &A) -> Option<u8>

Index into args of the key whose write may wake a blocked waiter (LPUSH / RPUSH feed BLPOP / BRPOP; XADD feeds the stream blocks). Some(1) for those verbs, None for everything else. The in-shard fast path reads this off ResolvedCmd::wake_idx; the cross-shard write path (exec_op, where a forwarded write lands on the key’s owning shard) re-derives it via this method since the forwarded envelope doesn’t carry the resolved hint. Default None so non-blocking embedders pay nothing.

Source

fn block_hint<A: ArgvView + ?Sized>(&self, _args: &A) -> BlockHint

Classify a command for blocking semantics. BlockHint::None (default) is the zero-cost answer for every non-blocking verb; the dispatcher only registers a waiter when this returns BlockHint::Block and the command’s dispatch_into produced no reply (i.e. it could not satisfy itself immediately — e.g. BLPOP on an empty list). Concrete impls should fold this into their override of Self::resolve so the verb-table lookup happens once per command.

Source

fn resolve_block_argv<A: ArgvView + ?Sized>( &self, _store: &mut Store, args: &A, _kind: BlockKind, ) -> Argv

Rewrite args into the owned Argv that the dispatcher will store as the parked waiter’s command and replay on wake. Lets a command set normalise positional ID / cursor arguments that would otherwise re-resolve to a different value on retry — most notably XREAD BLOCK ... STREAMS k $, where leaving $ literal in the retried argv causes a fresh re-resolve to the post-XADD last_id and zero matching entries (the wake hangs).

Default: just materialise the argv unchanged. Concrete impls only need to override when a registered command carries an arg whose meaning depends on store state at park time (XREAD $, the classic case).

For the cross-shard arbiter this runs on the target shard (the one that owns the key) when the waiter is armed, so $ snapshots the target’s real last_id — not the origin shard’s (which may not hold the stream at all).

Source

fn block_serve_argv<A: ArgvView + ?Sized>( &self, args: &A, _kind: BlockKind, _key: &[u8], ) -> Argv

Build the single-key command the dispatcher will replay to satisfy one watched key of a (possibly multi-key) blocking command. args is the original command; key is one of its watched keys. Returns an Argv that, when dispatched, pops / reads only key — e.g. BLPOP k1 k2 0 watching k2 yields BLPOP k2 0; XREAD … STREAMS s1 s2 id1 id2 watching s2 yields XREAD … STREAMS s2 id2.

Any state-dependent positional arg ($) is left literal here — it’s frozen later by Self::resolve_block_argv on the key’s owning shard. No store access needed (pure argv slicing). Default: the unchanged argv (single-key blocking commands need no rewrite).

Source

fn block_ready<A: ArgvView + ?Sized>( &self, _store: &mut Store, _serve_argv: &A, _kind: BlockKind, ) -> bool

Non-destructive readiness peek for a parked waiter: would replaying serve_argv (built by Self::block_serve_argv, $ already frozen) produce a reply right now? Runs on the key’s owning shard when arming and is the gate for emitting a cross-shard wake. Must NOT mutate the store (no pop / no group-cursor advance). Default false so non-blocking embedders never spuriously wake.

Source

fn resolve<A: ArgvView + ?Sized>(&self, args: &A) -> ResolvedCmd

Resolve all verb-dependent attributes in one verb-table lookup. The default implementation calls the per-attribute methods above (five upper_verb scans + matches); concrete impls SHOULD override this with a single match so the reactor’s hot path pays the verb- resolution cost only once per command.

Dyn Compatibility§

This trait is not dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety".

Implementors§