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§
Sourcefn route<A: ArgvView + ?Sized>(&self, args: &A) -> Route
fn route<A: ArgvView + ?Sized>(&self, args: &A) -> Route
Classify how a command is routed across shards.
Sourcefn dispatch<A: ArgvView + ?Sized>(&self, store: &mut Store, args: &A) -> Vec<u8> ⓘ
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.
Sourcefn is_quit<A: ArgvView + ?Sized>(&self, args: &A) -> bool
fn is_quit<A: ArgvView + ?Sized>(&self, args: &A) -> bool
Whether this command should close the connection (QUIT).
Provided Methods§
Sourcefn dispatch_resp3<A: ArgvView + ?Sized>(
&self,
store: &mut Store,
args: &A,
) -> Vec<u8> ⓘ
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).
Sourcefn dispatch_into<A: ArgvView + ?Sized>(
&self,
store: &mut Store,
args: &A,
out: &mut Vec<u8>,
)
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.
Sourcefn dispatch_into_resp3<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>, )
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 / …).
Sourcefn notify_class<A: ArgvView + ?Sized>(&self, _args: &A) -> Option<NotifyClass>
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.
Sourcefn hello_reply<A: ArgvView + ?Sized>(
&self,
_args: &A,
current_proto: RespVersion,
) -> (RespVersion, Vec<u8>)
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.
Sourcefn on_shard_init(&self, _store: &mut Store)
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.
Sourcefn on_shard_start(&self, _shard: usize)
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.
Sourcefn on_persist_stats(&self, _in_flight: bool, _aof_rewrites_total: u64)
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.
Sourcefn on_replication_view(
&self,
_master_repl_offset: u64,
_replicas: Vec<(Ipv4Addr, u16, u64)>,
)
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.
Sourcefn on_shard_tick(&self, _store: &mut Store)
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.
Sourcefn on_command(&self)
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.
Sourcefn on_connection(&self)
fn on_connection(&self)
Called once per accepted client connection. kevy uses it for
INFO stats: total_connections_received. Default no-op.
Sourcefn shard_tick_interval_ms(&self) -> u64
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.
Sourcefn live_runtime_config(&self) -> LiveRuntimeConfig
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.
Sourcefn wake_idx<A: ArgvView + ?Sized>(&self, _args: &A) -> Option<u8>
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.
Sourcefn block_hint<A: ArgvView + ?Sized>(&self, _args: &A) -> BlockHint
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.
Sourcefn resolve_block_argv<A: ArgvView + ?Sized>(
&self,
_store: &mut Store,
args: &A,
_kind: BlockKind,
) -> Argv
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).
Sourcefn block_serve_argv<A: ArgvView + ?Sized>(
&self,
args: &A,
_kind: BlockKind,
_key: &[u8],
) -> Argv
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).
Sourcefn block_ready<A: ArgvView + ?Sized>(
&self,
_store: &mut Store,
_serve_argv: &A,
_kind: BlockKind,
) -> bool
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.
Sourcefn resolve<A: ArgvView + ?Sized>(&self, args: &A) -> ResolvedCmd
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".