Skip to main content

Crate kevy_rt

Crate kevy_rt 

Source
Expand description

kevy-rt — shared-nothing, thread-per-core runtime.

Each core runs its own reactor (kqueue/epoll) and owns one shard of the keyspace (hash(key) % nshards). There is no shared mutable state and no lock on the hot path — cores communicate only by message passing over channels, woken via a self-pipe (kevy_sys::Waker). Connections are spread across cores by SO_REUSEPORT; a command whose key lives on another core is forwarded to that core, executed there, and the reply routed back to the originating connection.

Per-connection reply ordering is preserved (RESP is pipelined): each command gets a monotonic seq; replies are emitted only in contiguous seq order, so an async cross-core reply never overtakes an earlier one.

The cross-core channel currently uses std::sync::mpsc (pure Rust, zero deps); swapping in a lock-free SPSC/MPSC ring is a perf-polish item. Command semantics are injected via the Commands trait, keeping the runtime independent of the concrete command set. Part of the kevy server.

§Module map

  • Runtime (in runtime) — public entry point; spawns one shard per core.
  • shard — the per-core reactor: sockets, the inbound queue, reply flushing.
  • exec — command semantics: routing, execution, and result reduction.
  • message — internal cross-core work/result types.
  • conn — per-connection state (input/output, seq ring, subscriptions).
  • reduce — reply reduction (materialize) and pure helpers (set algebra, shard hashing, pub/sub framing).

§Example

Implement Commands for your command set and run it. (Store is re-exported so you don’t need a separate dependency.)

use kevy_rt::{ArgvView, Commands, Route, Runtime, Store, TxnKind};
use std::sync::Arc;
use std::sync::atomic::AtomicBool;

#[derive(Clone)]
struct MyCommands;
impl Commands for MyCommands {
    fn route<A: ArgvView + ?Sized>(&self, args: &A) -> Route {
        if args.len() >= 2 { Route::Single(1) } else { Route::Local }
    }
    fn dispatch<A: ArgvView + ?Sized>(&self, _store: &mut Store, _args: &A) -> Vec<u8> {
        b"+OK\r\n".to_vec()
    }
    fn is_quit<A: ArgvView + ?Sized>(&self, args: &A) -> bool {
        args.first().is_some_and(|c| c.eq_ignore_ascii_case(b"QUIT"))
    }
    fn is_write<A: ArgvView + ?Sized>(&self, _args: &A) -> bool { false }
    fn txn_kind<A: ArgvView + ?Sized>(&self, _args: &A) -> TxnKind { TxnKind::Other }
}

// One shard per core, listening on 127.0.0.1:6379, until `stop` is set.
let rt = Runtime::builder(MyCommands).bind([127, 0, 0, 1], 6379).shards(4);
rt.run(Arc::new(AtomicBool::new(false))).unwrap();

Every public item here is documented, and the lint keeps it that way: kevy-rt is the reactor, and warnings = "deny" turns a new gap into a compile error rather than a number that drifts. Closed from 35 sites in v6 — all of them fields inside well-documented variants, which is where prose review does not look.

Modules§

propagation
Effect-frame propagation override — how a verb whose effect is nondeterministic (SPOP’s random pick) keeps the AOF and the replication stream deterministic.
serve_counters
Debug-only signal that a cross-shard serve reply was processed by the origin (i.e. origin_on_serve_resp ran). The escrow regression uses it to tell a genuine cross-shard placement from a co-located one: with N shards a random key lands on the conn’s own shard ~1/N of the time, and that takes the LOCAL block path, not this cross-shard one — so the test retries until it provably exercised the cross-shard code. Non-I/O, so it does not perturb the timing.

Structs§

Argv
A parsed command’s argument vector.
ArgvBorrowed
A parsed command’s argument vector that borrows its bytes from a contiguous input buffer.
LiveRuntimeConfig
Live snapshot of the runtime-owned knobs that may have been changed since this shard’s last tick. Built by the Commands impl from its own config source (e.g. kevy reads config_global). Each Some(_) is applied to the shard; each None leaves the existing setting alone.
NotificationFlags
Parsed view of NotificationSection::notify_keyspace_events. The runtime caches this struct per-shard (hot-reload via the existing LiveRuntimeConfig tick path) so the per-write-command check reduces to four bool reads on the hot path.
ReplicaAck
A replica’s acknowledged state, published per shard tick via Commands::on_replication_view: the offset from its latest REPLCONF ACK plus that ACK’s age at publication time. None in the view tuple means the replica has never ACKed.
ReplicaInboxReceiver
Receiver end. Lives inside the (private) Shard; drained every reactor iteration. Constructed by replica_inbox_pair and handed to the runtime via Runtime::with_replica_inboxes.
ReplicaInboxSender
Sender end of a per-shard replica inbox. Send + Clone + Sync (one std::sync::mpsc::Sender, no extra state) so the embedder can hand it freely to runner threads.
ReplicatedApplyGuard
RAII guard that marks the current thread as “applying a replicated frame” for the guard’s lifetime. The replica runner enters this scope before each dispatch call so the apply doesn’t re-push the frame into this shard’s own backlog.
ResolvedCmd
Per-command verb-resolution result. Produced once by Commands::resolve in the reactor’s parse-then-dispatch loop, reused for routing decisions, AOF logging, and the QUIT branch — so the per-cmd upper_verb cost goes from 4× down to 1×.
Runtime
The public entry point: configure and run the thread-per-core server.
ScanArgs
Parsed SCAN arguments carried by Route::Scan.
SnapshotGate
Opaque completion token riding on ReplicaApply::SnapshotEnd. The shard drops it only AFTER the snapshot swap has landed in its Store, so the embedder can hang side effects (e.g. lowering a -LOADING read gate) on the token’s Drop and know they fire once the new keyspace — not the one about to be replaced — is what readers will see. Clones share one inner value: in broadcast (single-source) mode every shard holds a clone and the Drop fires when the LAST shard finishes its load.
Store
A single-database keyspace.
XGroupCtx
The GROUP <name> <consumer> (+ NOACK) context an XREADGROUP gather carries to each per-stream sub-query.

Enums§

BlockHint
How a command wants to block, if at all. Returned by Commands::resolve inside crate::ResolvedCmd so the verb-table lookup happens once per command. None is the zero-cost default for every non-blocking verb (≥ 99.9 % of dispatches in steady state).
BlockKind
Which blocking command a waiter is parked in. Drives both timeout-nil shape and wake-retry dispatch.
ClientKillFilter
Parsed CLIENT KILL selector. Addr matches the peer ip:port exactly; Id matches the instance-unique conn id.
ExtensionReduced
Outcome of an extension fan-out reduce (Commands::extension_reduce).
Fsync
When to fsync the AOF to disk.
GeoHits
What a geo *STORE’s search phase produced on the source key’s shard. Public: crate::Commands::geo_search returns it. The runtime never interprets the scores — the command layer decides whether they carry the source geohash or (with STOREDIST) the distance in the queried unit.
MultiOp
The multi-key gather reductions computed on the originating shard. Public: crate::Route::Gather carries it, and embedders’ route() implementations construct it.
NotifyClass
Keyspace-notification event class — what category a write command belongs to, so the runtime can match it against the per-conn notify_keyspace_events flags before publishing.
ReplicaApply
One event delivered from a replica runner to its target shard. Mirrors kevy_replicate::replica::ReplicaEvent except Frame carries an owned Argv (already decoded by the runner) instead of a DecodedFrame { offset, argv } — the offset is gap-checked by the runner on the way in, so the shard doesn’t need it.
RespVersion
Which version of RESP a connection is speaking. Negotiated via the HELLO command — RESP2 is the default for backwards compatibility with every Redis 6.x and earlier client; RESP3 is opt-in via HELLO 3 and unlocks the additive reply types (Reply::Map / Reply::Set / Reply::Double / Reply::Boolean / Reply::Verbatim / Reply::BigNumber / Reply::Null / Reply::Push / Reply::BlobError) plus out-of-band push frames for PUBLISH delivery.
Route
How a command maps onto shards.
SlowlogSub
Parsed SLOWLOG <sub> [args] decision — picked at routing time so the runtime knows whether to fan out or short-circuit.
TxnKind
Transaction-control classification for a command.
ZCombine
Which algebra combination a *STORE orchestrator runs after its gather completes. Public: crate::Route::ZAlgebraStore carries it, and embedders’ route() implementations construct it.

Traits§

ArgvView
Read-only view over a parsed command’s argument vector.
Commands
Command-set semantics injected into the runtime. Cloned to every core, so it must be cheap/stateless to clone.

Functions§

parse_slowlog_sub
Parse args ( [verb, sub, ...] ) into a SlowlogSub. Verb name is assumed to already be SLOWLOG (the caller’s route table dispatched to here). Embedders call this from their Commands::resolve / Commands::route impl.
push_lua_wake_key
Lua’s redis.call dispatch closure calls this after every wake-triggering write (LPUSH / RPUSH / XADD / ZADD / ZINCRBY). The runtime drains via [drain_lua_wake_buffer] after the outer EVAL dispatch returns and fires wake_key for each.
repl_trace
True when replication tracing is enabled for this process.
repl_trace_line
Emit one trace line stamped with the shared wall clock (epoch ms) — the availgate crime scene spans three processes on one host, and only a shared clock lets their probe lines interleave into a single sequence. Callers gate on repl_trace first.
replica_inbox_pair
Create a matched (sender, receiver) pair for one shard’s replica inbox. The embedder calls this nshards times before Runtime::run.
shard_of_key
Shard index for key over n shards. Independent of the store’s internal hash so a cross-shard routing change doesn’t require rehashing the store.
shard_slot_range
The contiguous slot range [start, end] (inclusive, CLUSTER SLOTS shape) shard i of n owns: [ceil(i·16384/n), ceil((i+1)·16384/n) - 1]. Exact inverse of reduce::slot_to_shard’s multiply-shift.

Type Aliases§

ReplicaViewRow
One replica conn’s row in the per-tick replication view: (replica_id, peer_ipv4, peer_port, sent_offset, ack). The id is the identity string the replica presented at handshake — command layers group per-shard rows by it to render one aggregate entry per replica process.