Skip to main content

Crate kevy_store

Crate kevy_store 

Source
Expand description

kevy-store — the keyspace.

A single-threaded, multi-type keyspace with lazy expiration. Each Redis data type is backed by a modern std structure — behaviour-compatible, but not Redis’s legacy encodings:

TypeBacking structure
StringVec<u8>
Hash / SetHashMap / HashSet (hashbrown Swiss table)
ListVecDeque (ring buffer, O(1) ends)
Sorted setHashMap + BTreeSet<(score, member)> (a B-tree, not a skiplist)

Wrong-type access returns StoreError::WrongType. The API is &mut self and lock-free, so a thread-per-core runtime (kevy-rt) can own one shard per core with no locking. Part of the kevy key–value server.

maxmemory enforcement + 8 eviction policies live in evict; toggle via Store::set_max_memory. With maxmemory == 0 (the default) the hot-path cost collapses to a single predicted-not-taken branch, matching the “unlimited” mode in Redis byte-for-byte.

§Example

use kevy_store::Store;

use std::borrow::Cow;
let mut s = Store::new();
s.set(b"greeting", b"hello".to_vec(), None, false, false);
assert_eq!(s.get(b"greeting").unwrap(), Some(Cow::Borrowed(&b"hello"[..])));

s.hset(b"user:1", &[(b"name".to_vec(), b"alice".to_vec())]).unwrap();
assert_eq!(s.hget(b"user:1", b"name").unwrap(), Some(&b"alice"[..]));

// A string command on a hash key is a type error, as in Redis.
assert_eq!(s.get(b"user:1"), Err(kevy_store::StoreError::WrongType));

Re-exports§

pub use expire::ExpireStats;

Modules§

evict
Maxmemory enforcement and the 8 eviction policies.
expire
Active TTL reaper — Redis’s activeExpireCycle, adapted to the thread-per-core / single-shard Store.

Structs§

AutoclaimResult
Snapshot of XAUTOCLAIM work in progress: cursor for the next call, IDs successfully transferred, and IDs skipped because the stream has since deleted them.
ConsumerGroup
One consumer group’s state. Sorted PEL plus a map of known consumers (with cached pel_count for O(1) XINFO answers).
ConsumerState
Per-consumer cached counters so XINFO CONSUMERS answers in O(1).
LoadedGroup
One consumer group decoded into primitive tuples — the dump/load wire form shared by snapshot v4, AOF-rewrite filtering, and reshard’s in-memory redistribution.
PelEntry
One pending entry: who got it, when, and how many times.
PendingExtended
Extended form of XPENDING key group [IDLE ms] start end count [consumer]: one row per matching PEL entry.
PendingExtendedRow
One row of the extended XPENDING reply.
PendingSummary
Summary form of XPENDING key group (only 3 args): total pending, min/max IDs across the PEL, and per-consumer aggregate counts.
Score
A total-ordered f64 score (Redis scores are never NaN). total_cmp gives a total order so scores can key a BTreeSet.
ScoreBound
A score-range endpoint for ZRANGEBYSCORE/ZCOUNT (inclusive or exclusive). Use value = ±INFINITY for -inf/+inf.
SmallHashData
Inline packed hash storage. 24 bytes total.
SmallHashIter
Iterator over SmallHashData yielding (&[u8] field, &[u8] value).
SmallListData
Inline packed list storage. 24 bytes total.
SmallListIter
Iterator over SmallListData.
SmallSetData
Inline packed set storage. 24 bytes total — see module docs for layout.
SmallSetIter
Iterator over SmallSetData members as &[u8] slices.
SmallZSetData
Inline packed sorted-set storage. 24 bytes total.
SmallZSetIter
Iterator over SmallZSetData yielding (member, score).
SnapshotView
A frozen, Send view of one store’s live entries at a single instant.
Store
A single-database keyspace.
StreamData
One stream’s storage: every entry in entries plus the per-stream scalar state Redis exposes via XINFO STREAM, plus the consumer groups map (sprint B). An empty groups map costs ~8 bytes and makes the no-group fast path (sprint A XADD/XREAD) zero-overhead.
StreamId
A stream entry’s <ms>-<seq> identifier. The Ord derivation compares ms first then seq, which is exactly the monotonic order the protocol requires; same derivation gives Eq, Hash, and the BTreeMap key bound.
XClaimOpts
Knobs for crate::StreamData’s xclaim: min-idle-ms plus the IDLE/TIME/RETRYCOUNT/FORCE/JUSTID flag tail.
ZSetData
Sorted set: a member→score map plus a B-tree ordered by (score, member). (A B-tree is cache-friendlier than Redis’s skiplist; ZRANK is O(n) here — an order-statistics tree for O(log n) rank is a later perf item.)

Enums§

EvictionPolicy
Maxmemory eviction policy. Mirror of kevy_config::EvictionPolicy — duplicated here so kevy-store stays a leaf crate (no kevy-config dep).
GetReply
L1 return shape for Store::get_for_reply — lets the reactor’s reply path choose between memcpy (Bytes) and writev zero-copy (ArcBulk) off one keyspace lookup.
GroupCreateMode
XGROUP CREATE ID argument: either an explicit ID or $ (= current stream’s last_id, resolved by the caller).
ReadGroupId
XREADGROUP’s per-stream ID: either > (= new entries) or an explicit “after this id” for PEL replay.
RenameOutcome
Outcome of Store::rename — three-way result so the dispatch layer can pick the right RESP frame (+OK / -ERR no such key / :0 for RENAMENX-with-existing-dst).
StoreError
Operation errors surfaced to the command layer.
StreamIdError
Errors parse_*_id may emit. Distinct from StoreError::NotInteger so callers can map to the more specific Redis wire shape (ERR Invalid stream ID specified as stream command argument).
Value
A stored value. One variant per Redis type.
XAddIdSpec
XADD’s ID argument: either an explicit <ms>-<seq> (both parts may be * to auto-fill seq only) or fully auto-generate via *.

Constants§

BULK_THRESHOLD
Threshold (bytes) above which a SET stores its value as Value::ArcBulk (writev-eligible on GET) instead of Value::Str (inline SmallBytes). 64 B ≈ one cache line — below that the inline-SmallBytes storage wins on L1 locality; above it the writev-borrow win dominates.
ENTRY_OVERHEAD
Per-entry overhead in the top-level keyspace map: the inline 24-byte SmallBytes key cell + the 64-byte Entry (post weight/clock fields) + metadata. Approximation that errs slightly high so used_memory stays a conservative upper bound vs the actual allocator footprint.
HEAP_HEAVY_BYTES
Heap-size threshold above which an overwritten Value is sent to the runtime’s bio thread for off-reactor drop instead of being freed inline (v1.25 A.3 lazy-drop).

Functions§

glob_match
Redis-style glob match (*, ?, [...] classes with ranges/^, \ escape).
hash_field_weight
Per-field delta a new hash field charges against the entry weight: heap bytes for the field name (if not inline) + value capacity + one slot of bucket overhead. Used when an HSET inserts a brand-new field.
list_item_weight
Per-item delta a new list element charges (Vec header slot + heap cap).
now_unix_ms
Wall-clock millis. Shared with dispatchers so every XADD on a shard uses the same clock source. On native targets reads SystemTime::now() (falls back to 0 on a pre-UNIX-EPOCH clock — impossible on supported platforms); on wasm32-unknown-unknown, where SystemTime::now() traps, reads the host-fed wall clock (see crate::set_wall_clock_ms, wasm-only).
parse_explicit_id
Parse a fully-explicit ID for XREAD’s per-stream “last-seen” arg (0, 0-0, 5-2). $ is handled by the caller (it means “the stream’s current last_id”, which only Store can resolve).
parse_range_end
Parse an XRANGE end ID. Accepts + (= StreamId::MAX), bare ms (seq=u64::MAX so the entire ms is included), and full ms-seq.
parse_range_start
Parse an XRANGE start ID. Accepts - (= StreamId::MIN), bare ms (seq=0), and full ms-seq.
parse_xadd_id
Parse an XADD ID argument (*, ms, ms-*, ms-seq).
set_member_weight
Per-member delta a new set member charges. Mirrors hash_field_weight for the set variant (no separate value, single bucket slot).
zset_member_weight
Per-member delta a new zset member charges: hash slot for by_member + BTreeSet slot for by_score + the member’s heap bytes.

Type Aliases§

BioDropSender
Sender half of the runtime’s bio-drop channel. Wired from kevy-rt’s bio.rs via crate::Store::set_bio_drop_sender; the concrete payload is Vec<Box<Value>> — a batch of values produced by one shard since its last flush (A.2 batch-send model). The bio thread (kevy-rt::bio::spawn) iterates the batch and drops each item. One mpsc message per shard-flush amortises the channel cost (atomic + cross-thread cacheline traffic) across however many values landed in the batch.
EntryBatch
Cloned-out view of stream entries, the cross-module wire form. Keeps the same shape Redis sends and lets the callers stay decoupled from the SmallBytes interning the store uses internally.
HashData
Backing structure for a Hash value — KevyMap keyed by SmallBytes (22 B inline / heap-else). Field names ≤22B (the vast majority — name, email, etc.) live entirely inside the bucket, saving the 24 B Vec metadata + heap allocation per field on a 22-byte budget.
ListData
Backing structure for a List value (a ring-buffer deque — O(1) both ends).
LoadedPelEntry
One PEL row in primitive form: (ms, seq, consumer, delivery_time_ms, delivery_count). The persist crate serializes these verbatim.
LoadedStreamEntry
Snapshot-loader payload: one stream entry decoded into primitive tuples (ms, seq, [(field, value), ...]). The persist crate emits these and Store::load_stream consumes them.
SetData
Backing structure for a Set value — KevySet of SmallBytes.

Unions§

SmallBytes
A 24-byte owned byte string with inline small-string optimization.