pub struct Store { /* private fields */ }Expand description
A single-database keyspace.
The keyspace map is a KevyMap — a pure-Rust open-addressing Swiss
table tuned for kevy’s per-shard, single-trust-domain keyspace. The
hasher is kevy_hash::KevyHash (one-call inlinable; no DoS hardening
since the shard is single-threaded with no cross-trust keys). Owning the
table also exposes bucket addresses for software prefetch on the batch
driver.
Implementations§
Source§impl Store
impl Store
Sourcepub fn prefetch_for_key(&self, key: &[u8])
pub fn prefetch_for_key(&self, key: &[u8])
Hint the CPU to fetch the bucket cache line for key into L1. Called
by the reactor’s parse loop on command N+1 while command N is still
being dispatched — by the time N+1 actually probes the table, the
metadata line is hot. No-op when the table is empty. Cheap when not.
Source§impl Store
impl Store
Sourcepub fn tick_expire(
&mut self,
samples_per_round: usize,
max_rounds: u32,
) -> ExpireStats
pub fn tick_expire( &mut self, samples_per_round: usize, max_rounds: u32, ) -> ExpireStats
Run up to max_rounds of active-expiry sampling against this shard.
Per round: sample samples_per_round TTL-bearing keys at random and
drop any whose deadline has passed. Stop early as soon as the
in-batch expire-rate drops below 25 % (Redis’s activeExpireCycle
continuation threshold) — that’s the signal the keyspace doesn’t
have a “thick band” of expired keys to clean up right now.
Cost when there are no TTL-bearing keys at all: one map-emptiness check + a single bucket-iter probe per round. Designed so the active reaper is never a tax on TTL-free workloads.
Sourcepub fn expired_keys_total(&self) -> u64
pub fn expired_keys_total(&self) -> u64
Total keys expired (by lazy reap OR active reaper). Surfaced via
INFO keyspace and MEMORY STATS once those grow the field.
Source§impl Store
impl Store
Sourcepub fn hset_borrowed(
&mut self,
key: &[u8],
pairs: &[(&[u8], &[u8])],
) -> Result<usize, StoreError>
pub fn hset_borrowed( &mut self, key: &[u8], pairs: &[(&[u8], &[u8])], ) -> Result<usize, StoreError>
G4 (v1.25): borrowed-pair HSET — kills the per-field+value
Vec<u8> allocs the dispatch layer used to do before calling
Self::hset. A.8: routes through the encoding-switch path.
Sourcepub fn hset(
&mut self,
key: &[u8],
pairs: &[(Vec<u8>, Vec<u8>)],
) -> Result<usize, StoreError>
pub fn hset( &mut self, key: &[u8], pairs: &[(Vec<u8>, Vec<u8>)], ) -> Result<usize, StoreError>
HSET — returns the count of newly-added fields.
Sourcepub fn hsetnx(
&mut self,
key: &[u8],
field: &[u8],
val: &[u8],
) -> Result<bool, StoreError>
pub fn hsetnx( &mut self, key: &[u8], field: &[u8], val: &[u8], ) -> Result<bool, StoreError>
HSETNX — set only if the field is absent; returns whether it was set.
pub fn hget( &mut self, key: &[u8], field: &[u8], ) -> Result<Option<&[u8]>, StoreError>
pub fn hexists(&mut self, key: &[u8], field: &[u8]) -> Result<bool, StoreError>
pub fn hlen(&mut self, key: &[u8]) -> Result<usize, StoreError>
pub fn hmget( &mut self, key: &[u8], fields: &[Vec<u8>], ) -> Result<Vec<Option<Vec<u8>>>, StoreError>
Sourcepub fn hmget_borrowed(
&mut self,
key: &[u8],
fields: &[&[u8]],
) -> Result<Vec<Option<Vec<u8>>>, StoreError>
pub fn hmget_borrowed( &mut self, key: &[u8], fields: &[&[u8]], ) -> Result<Vec<Option<Vec<u8>>>, StoreError>
G4 (v1.25): borrowed-slice HMGET.
Sourcepub fn hgetall(&mut self, key: &[u8]) -> Result<Vec<Vec<u8>>, StoreError>
pub fn hgetall(&mut self, key: &[u8]) -> Result<Vec<Vec<u8>>, StoreError>
HGETALL — flat [field, value, field, value, ...].
pub fn hkeys(&mut self, key: &[u8]) -> Result<Vec<Vec<u8>>, StoreError>
pub fn hvals(&mut self, key: &[u8]) -> Result<Vec<Vec<u8>>, StoreError>
Sourcepub fn hdel(
&mut self,
key: &[u8],
fields: &[Vec<u8>],
) -> Result<usize, StoreError>
pub fn hdel( &mut self, key: &[u8], fields: &[Vec<u8>], ) -> Result<usize, StoreError>
HDEL — returns count removed; deletes the key if hash becomes empty.
Sourcepub fn hdel_borrowed(
&mut self,
key: &[u8],
fields: &[&[u8]],
) -> Result<usize, StoreError>
pub fn hdel_borrowed( &mut self, key: &[u8], fields: &[&[u8]], ) -> Result<usize, StoreError>
G4 (v1.25): borrowed-slice HDEL. A.8: encoding-aware.
Source§impl Store
impl Store
pub fn del(&mut self, keys: &[Vec<u8>]) -> usize
Sourcepub fn del_borrowed(&mut self, keys: &[&[u8]]) -> usize
pub fn del_borrowed(&mut self, keys: &[&[u8]]) -> usize
G4 (v1.25): borrowed-slice DEL — kills the per-key Vec<u8> alloc
the dispatch layer used to do via rest(args, 1). Behaviour identical
to Self::del.
pub fn exists(&mut self, keys: &[Vec<u8>]) -> usize
Sourcepub fn exists_borrowed(&mut self, keys: &[&[u8]]) -> usize
pub fn exists_borrowed(&mut self, keys: &[&[u8]]) -> usize
G4 (v1.25): borrowed-slice EXISTS — see Self::del_borrowed.
pub fn expire(&mut self, key: &[u8], ttl: Duration) -> bool
Sourcepub fn expire_at_unix_ms(&mut self, key: &[u8], deadline_ms: u64) -> bool
pub fn expire_at_unix_ms(&mut self, key: &[u8], deadline_ms: u64) -> bool
EXPIREAT/PEXPIREAT semantics: set an absolute wall-clock
deadline (Unix epoch millis). This is the persistence-safe form —
a deadline survives restart unchanged, unlike the relative
Self::expire (whose duration is re-anchored to “now”). A
deadline already in the past deletes the key immediately (Redis
behaviour). Returns true iff the key existed (and was either
re-dated or deleted). The wall-clock → monotonic-Instant
conversion happens here so callers persist absolute time but the
hot path keeps its cheap monotonic deadline.
Sourcepub fn take_with_ttl(&mut self, key: &[u8]) -> Option<(Value, Option<u64>)>
pub fn take_with_ttl(&mut self, key: &[u8]) -> Option<(Value, Option<u64>)>
Cross-shard RENAME step 1: atomically remove the entry at
key (if any), returning the (value, ttl_ms_remaining). The
orchestrator on the origin shard ships the result into a
follow-up Self::put_with_ttl on the destination shard.
Lazy-reaps an expired entry before the take (so an expired
key is observed as None, not silently rehomed).
Sourcepub fn put_with_ttl(&mut self, key: Vec<u8>, value: Value, ttl_ms: Option<u64>)
pub fn put_with_ttl(&mut self, key: Vec<u8>, value: Value, ttl_ms: Option<u64>)
Cross-shard RENAME step 2: write value at key on this
shard, overwriting any prior entry. ttl_ms is set as a TTL
relative to now (i.e. the orchestrator should have computed
the remaining TTL on the source shard via take_with_ttl and
is shipping that exact remaining value here).
Sourcepub fn key_exists(&mut self, key: &[u8]) -> bool
pub fn key_exists(&mut self, key: &[u8]) -> bool
Whether a live (non-expired) entry exists at key. Reaps an
expired entry as a side effect. Used by the cross-shard RENAME
orchestrator’s nx pre-check.
Sourcepub fn rename(&mut self, src: &[u8], dst: &[u8], nx: bool) -> RenameOutcome
pub fn rename(&mut self, src: &[u8], dst: &[u8], nx: bool) -> RenameOutcome
RENAME (or RENAMENX if nx). Atomic on this shard. Returns
the outcome so the dispatch layer can emit the right RESP frame
(RENAME: +OK or -ERR no such key; RENAMENX: :1/:0/error).
Cross-shard rename is the runtime’s job — by the time this is
called, both src and dst are guaranteed to live on the same
shard. See kevy-rt::start_rename for the cross-shard split.
pub fn persist(&mut self, key: &[u8]) -> bool
Sourcepub fn pttl(&mut self, key: &[u8]) -> i64
pub fn pttl(&mut self, key: &[u8]) -> i64
Remaining TTL in ms: -2 no key, -1 no expiry, else >= 0.
pub fn type_of(&mut self, key: &[u8]) -> &'static str
pub fn dbsize(&self) -> usize
Sourcepub fn flushall(&mut self)
pub fn flushall(&mut self)
Wipe every key in this shard’s keyspace (the FLUSHALL/FLUSHDB
primitive). Resets used_memory; used_memory_peak is
lifetime-cumulative and intentionally not reset.
Named flushall — not flush — to avoid colliding with
Write::flush’s “sync buffered writes to disk” meaning. This method
DESTROYS data; it does not persist it.
Sourcepub fn flush(&mut self)
👎Deprecated since 1.17.0: renamed to flushall: flush collides with Write::flush (sync-to-disk); this WIPES the keyspace
pub fn flush(&mut self)
renamed to flushall: flush collides with Write::flush (sync-to-disk); this WIPES the keyspace
Deprecated alias for Self::flushall. The old name read like
Write::flush (sync-to-disk) but actually WIPES the keyspace.
Sourcepub fn ttl_pending_count(&self) -> usize
pub fn ttl_pending_count(&self) -> usize
Count live (non-expired) keys that carry a TTL — the size of the “expire set” Redis tracks. Useful as an introspection signal for confirming the TTL subsystem actually registered keys. O(n) over the keyspace; call it for diagnostics, not on the hot path.
Sourcepub fn snapshot_each<F>(&self, f: F)
pub fn snapshot_each<F>(&self, f: F)
Visit every live entry as (key, &value, ttl_ms) for snapshotting.
pub fn load_str(&mut self, key: Vec<u8>, value: Vec<u8>, ttl_ms: Option<u64>)
pub fn load_hash( &mut self, key: Vec<u8>, fields: Vec<(Vec<u8>, Vec<u8>)>, ttl_ms: Option<u64>, )
pub fn load_list( &mut self, key: Vec<u8>, items: Vec<Vec<u8>>, ttl_ms: Option<u64>, )
pub fn load_set( &mut self, key: Vec<u8>, members: Vec<Vec<u8>>, ttl_ms: Option<u64>, )
Sourcepub fn collect_keys(
&self,
pattern: Option<&[u8]>,
limit: Option<usize>,
) -> Vec<Vec<u8>>
pub fn collect_keys( &self, pattern: Option<&[u8]>, limit: Option<usize>, ) -> Vec<Vec<u8>>
Collect live keys (optionally matching a glob pattern, up to limit).
Used by KEYS/SCAN/RANDOMKEY. Treats expired keys as absent (no removal).
pub fn load_zset( &mut self, key: Vec<u8>, pairs: Vec<(Vec<u8>, f64)>, ttl_ms: Option<u64>, )
Sourcepub fn load_value(&mut self, key: &[u8], value: &Value, ttl_ms: Option<u64>)
pub fn load_value(&mut self, key: &[u8], value: &Value, ttl_ms: Option<u64>)
Insert one already-typed (key, value, ttl) triple, e.g. straight out
of another store’s Self::snapshot_each — the redistribution step
both reshard paths (embedded shards bring-up, server routing
migration) use to re-home keys after a layout change.
Sourcepub fn load_stream(
&mut self,
key: Vec<u8>,
entries: Vec<(u64, u64, Vec<(Vec<u8>, Vec<u8>)>)>,
last_id: (u64, u64),
max_deleted_id: (u64, u64),
entries_added: u64,
groups: Vec<LoadedGroup>,
ttl_ms: Option<u64>,
)
pub fn load_stream( &mut self, key: Vec<u8>, entries: Vec<(u64, u64, Vec<(Vec<u8>, Vec<u8>)>)>, last_id: (u64, u64), max_deleted_id: (u64, u64), entries_added: u64, groups: Vec<LoadedGroup>, ttl_ms: Option<u64>, )
Snapshot-load a stream: every entry plus the per-stream scalar
state (last_id, max_deleted_id, entries_added) and the consumer
groups are restored verbatim. Caller passes already-decoded
primitive tuples; this fn does the SmallBytes /
crate::StreamData conversion.
Source§impl Store
impl Store
Sourcepub fn lpush(
&mut self,
key: &[u8],
values: &[Vec<u8>],
) -> Result<usize, StoreError>
pub fn lpush( &mut self, key: &[u8], values: &[Vec<u8>], ) -> Result<usize, StoreError>
LPUSH — prepend each value in turn; returns the new length.
Sourcepub fn rpush(
&mut self,
key: &[u8],
values: &[Vec<u8>],
) -> Result<usize, StoreError>
pub fn rpush( &mut self, key: &[u8], values: &[Vec<u8>], ) -> Result<usize, StoreError>
RPUSH — append each value; returns the new length.
Sourcepub fn lpush_borrowed(
&mut self,
key: &[u8],
values: &[&[u8]],
) -> Result<usize, StoreError>
pub fn lpush_borrowed( &mut self, key: &[u8], values: &[&[u8]], ) -> Result<usize, StoreError>
G4 (v1.25): borrowed-slice LPUSH. A.8: encoding-switch.
Sourcepub fn rpush_borrowed(
&mut self,
key: &[u8],
values: &[&[u8]],
) -> Result<usize, StoreError>
pub fn rpush_borrowed( &mut self, key: &[u8], values: &[&[u8]], ) -> Result<usize, StoreError>
G4 (v1.25): borrowed-slice RPUSH. A.8: encoding-switch.
Sourcepub fn lpop(
&mut self,
key: &[u8],
count: usize,
) -> Result<Vec<Vec<u8>>, StoreError>
pub fn lpop( &mut self, key: &[u8], count: usize, ) -> Result<Vec<Vec<u8>>, StoreError>
LPOP — pop up to count from the head (deleting emptied key).
Sourcepub fn rpop(
&mut self,
key: &[u8],
count: usize,
) -> Result<Vec<Vec<u8>>, StoreError>
pub fn rpop( &mut self, key: &[u8], count: usize, ) -> Result<Vec<Vec<u8>>, StoreError>
RPOP — pop up to count from the tail.
pub fn llen(&mut self, key: &[u8]) -> Result<usize, StoreError>
pub fn lindex( &mut self, key: &[u8], idx: i64, ) -> Result<Option<Vec<u8>>, StoreError>
pub fn lrange( &mut self, key: &[u8], start: i64, stop: i64, ) -> Result<Vec<Vec<u8>>, StoreError>
Sourcepub fn lset(
&mut self,
key: &[u8],
idx: i64,
val: &[u8],
) -> Result<(), StoreError>
pub fn lset( &mut self, key: &[u8], idx: i64, val: &[u8], ) -> Result<(), StoreError>
LSET — errors with NoSuchKey / OutOfRange like Redis.
Source§impl Store
impl Store
Sourcepub fn rpoplpush(
&mut self,
src: &[u8],
dst: &[u8],
) -> Result<Option<Vec<u8>>, StoreError>
pub fn rpoplpush( &mut self, src: &[u8], dst: &[u8], ) -> Result<Option<Vec<u8>>, StoreError>
RPOPLPUSH source destination — atomically pop one element from
the tail of src and push it onto the head of dst. Returns the
moved element, or None if src was empty / absent.
When src == dst Redis defines the result as a rotation
(tail → head of the same list), which falls out of this code
naturally because the pop sees the pre-rotation tail.
Sourcepub fn lmove(
&mut self,
src: &[u8],
dst: &[u8],
from_left: bool,
to_left: bool,
) -> Result<Option<Vec<u8>>, StoreError>
pub fn lmove( &mut self, src: &[u8], dst: &[u8], from_left: bool, to_left: bool, ) -> Result<Option<Vec<u8>>, StoreError>
LMOVE source destination LEFT|RIGHT LEFT|RIGHT — generalised
RPOPLPUSH. from_left=true pops from the head, otherwise the
tail; to_left=true pushes to the head, otherwise the tail.
Sourcepub fn lpos(
&mut self,
key: &[u8],
element: &[u8],
rank: i64,
count: Option<i64>,
maxlen: usize,
) -> Result<Vec<i64>, StoreError>
pub fn lpos( &mut self, key: &[u8], element: &[u8], rank: i64, count: Option<i64>, maxlen: usize, ) -> Result<Vec<i64>, StoreError>
LPOS key element [RANK n] [COUNT n] [MAXLEN n] — find the
zero-based position(s) of element in the list.
rank > 0— scan head→tail, skipping the firstrank-1matches.rank == 1(default) returns the first match.rank < 0— scan tail→head, returning matches as absolute (head-relative) indices.count—Nonereturns the first match as a 1-element vec (caller emits an integer / nil);Some(0)returns all matches;Some(n)caps ton.maxlen—0means unlimited; otherwise stop after scanning that many elements (in the chosen direction).
Returns the matched indices in scan order. An empty result with
count == None is the caller’s signal to emit RESP nil.
Source§impl Store
impl Store
Sourcepub fn sadd(
&mut self,
key: &[u8],
members: &[Vec<u8>],
) -> Result<usize, StoreError>
pub fn sadd( &mut self, key: &[u8], members: &[Vec<u8>], ) -> Result<usize, StoreError>
SADD — returns the count of newly-added members.
Sourcepub fn sadd_borrowed(
&mut self,
key: &[u8],
members: &[&[u8]],
) -> Result<usize, StoreError>
pub fn sadd_borrowed( &mut self, key: &[u8], members: &[&[u8]], ) -> Result<usize, StoreError>
G4 (v1.25): borrowed-slice SADD — kills the per-member Vec<u8> alloc
the dispatch layer used to do via rest(args, 2). Behaviour identical
to Self::sadd; mirrors valkey’s setTypeAdd(set, objectGetVal( c->argv[j])) zero-copy hand-off (t_set.c:611).
A.7 O5: takes the encoding-switch path. New key starts as
SmallSetInline if the first member fits; subsequent inserts
stay inline until SmallSetData::try_add returns NoRoom, at
which point the set is promoted in-place to
Value::Set(Arc<KevySet>) and the spilling member is re-inserted
in the heap-backed variant.
Sourcepub fn srem(
&mut self,
key: &[u8],
members: &[Vec<u8>],
) -> Result<usize, StoreError>
pub fn srem( &mut self, key: &[u8], members: &[Vec<u8>], ) -> Result<usize, StoreError>
SREM — returns the count removed (deleting an emptied key).
Sourcepub fn srem_borrowed(
&mut self,
key: &[u8],
members: &[&[u8]],
) -> Result<usize, StoreError>
pub fn srem_borrowed( &mut self, key: &[u8], members: &[&[u8]], ) -> Result<usize, StoreError>
G4 (v1.25): borrowed-slice SREM — see Self::sadd_borrowed.
pub fn sismember( &mut self, key: &[u8], member: &[u8], ) -> Result<bool, StoreError>
pub fn scard(&mut self, key: &[u8]) -> Result<usize, StoreError>
pub fn smembers(&mut self, key: &[u8]) -> Result<Vec<Vec<u8>>, StoreError>
Sourcepub fn spop(
&mut self,
key: &[u8],
count: usize,
) -> Result<Vec<Vec<u8>>, StoreError>
pub fn spop( &mut self, key: &[u8], count: usize, ) -> Result<Vec<Vec<u8>>, StoreError>
SPOP key count — remove and return up to count arbitrary members.
Sourcepub fn srandmember(
&mut self,
key: &[u8],
count: usize,
) -> Result<Vec<Vec<u8>>, StoreError>
pub fn srandmember( &mut self, key: &[u8], count: usize, ) -> Result<Vec<Vec<u8>>, StoreError>
SRANDMEMBER key count — up to count arbitrary members, not removed.
Sourcepub fn set_snapshot(&mut self, key: &[u8]) -> Result<Vec<Vec<u8>>, StoreError>
pub fn set_snapshot(&mut self, key: &[u8]) -> Result<Vec<Vec<u8>>, StoreError>
Snapshot of a set’s members for cross-shard algebra (SINTER/etc.).
Source§impl Store
impl Store
Sourcepub fn collect_snapshot(&self) -> SnapshotView
pub fn collect_snapshot(&self) -> SnapshotView
Freeze a point-in-time SnapshotView of every live entry.
O(n) shallow: per entry one key clone + one Value clone (string
bytes copied, collections refcount-bumped) + the TTL resolved to
remaining millis. Expired-but-unreaped entries are skipped, matching
Store::snapshot_each.
Source§impl Store
impl Store
Sourcepub fn stream_view(
&mut self,
key: &[u8],
) -> Result<Option<&StreamData>, StoreError>
pub fn stream_view( &mut self, key: &[u8], ) -> Result<Option<&StreamData>, StoreError>
Read-only access to a stream’s StreamData, used by XINFO
to inspect entries / groups / consumers without going through
the wrapper layer. Returns Ok(None) for a missing key,
WrongType for a non-stream value at key.
Sourcepub fn xadd(
&mut self,
key: &[u8],
spec: XAddIdSpec,
fields: Vec<(Vec<u8>, Vec<u8>)>,
nomkstream: bool,
now_ms: u64,
) -> Result<Option<StreamId>, StoreError>
pub fn xadd( &mut self, key: &[u8], spec: XAddIdSpec, fields: Vec<(Vec<u8>, Vec<u8>)>, nomkstream: bool, now_ms: u64, ) -> Result<Option<StreamId>, StoreError>
XADD key <spec> field value [field value ...]. Returns the
assigned ID. nomkstream matches Redis’s NOMKSTREAM flag —
suppress key creation, returning Ok(None). now_ms is the
wall-clock used for XAddIdSpec::AutoAll.
Sourcepub fn xlen(&mut self, key: &[u8]) -> Result<u64, StoreError>
pub fn xlen(&mut self, key: &[u8]) -> Result<u64, StoreError>
XLEN key. Returns 0 for a missing key.
Sourcepub fn xrange(
&mut self,
key: &[u8],
start: StreamId,
end: StreamId,
count: Option<usize>,
) -> Result<Vec<(StreamId, Vec<(Vec<u8>, Vec<u8>)>)>, StoreError>
pub fn xrange( &mut self, key: &[u8], start: StreamId, end: StreamId, count: Option<usize>, ) -> Result<Vec<(StreamId, Vec<(Vec<u8>, Vec<u8>)>)>, StoreError>
XRANGE key start end [COUNT n].
Sourcepub fn xrevrange(
&mut self,
key: &[u8],
start: StreamId,
end: StreamId,
count: Option<usize>,
) -> Result<Vec<(StreamId, Vec<(Vec<u8>, Vec<u8>)>)>, StoreError>
pub fn xrevrange( &mut self, key: &[u8], start: StreamId, end: StreamId, count: Option<usize>, ) -> Result<Vec<(StreamId, Vec<(Vec<u8>, Vec<u8>)>)>, StoreError>
XREVRANGE key end start [COUNT n].
Sourcepub fn xread(
&mut self,
key: &[u8],
last_seen: StreamId,
count: Option<usize>,
) -> Result<Vec<(StreamId, Vec<(Vec<u8>, Vec<u8>)>)>, StoreError>
pub fn xread( &mut self, key: &[u8], last_seen: StreamId, count: Option<usize>, ) -> Result<Vec<(StreamId, Vec<(Vec<u8>, Vec<u8>)>)>, StoreError>
XREAD ... STREAMS key last_seen [...] — per-key part.
Sourcepub fn xread_dollar_last_id(
&mut self,
key: &[u8],
) -> Result<StreamId, StoreError>
pub fn xread_dollar_last_id( &mut self, key: &[u8], ) -> Result<StreamId, StoreError>
Resolve $ as XREAD’s “last-seen” to the stream’s current last
ID. Returns MIN for a missing key.
Sourcepub fn xdel(&mut self, key: &[u8], ids: &[StreamId]) -> Result<u64, StoreError>
pub fn xdel(&mut self, key: &[u8], ids: &[StreamId]) -> Result<u64, StoreError>
XDEL key id [...]. Returns count actually removed.
Sourcepub fn xtrim_maxlen(
&mut self,
key: &[u8],
maxlen: u64,
) -> Result<u64, StoreError>
pub fn xtrim_maxlen( &mut self, key: &[u8], maxlen: u64, ) -> Result<u64, StoreError>
XTRIM key MAXLEN n. Returns number removed.
Sourcepub fn xtrim_minid(
&mut self,
key: &[u8],
minid: StreamId,
) -> Result<u64, StoreError>
pub fn xtrim_minid( &mut self, key: &[u8], minid: StreamId, ) -> Result<u64, StoreError>
XTRIM key MINID id. Returns number removed.
Sourcepub fn xsetid(
&mut self,
key: &[u8],
last_id: StreamId,
entries_added: Option<u64>,
max_deleted_id: Option<StreamId>,
) -> Result<(), StoreError>
pub fn xsetid( &mut self, key: &[u8], last_id: StreamId, entries_added: Option<u64>, max_deleted_id: Option<StreamId>, ) -> Result<(), StoreError>
XSETID key last-id [ENTRIESADDED n] [MAXDELETEDID id]. Returns
NoSuchKey for a missing key (dispatch maps it to Redis’s
“requires the key to exist” wording), OutOfRange when last_id
is below the stream’s top entry.
Sourcepub fn xgroup_create(
&mut self,
key: &[u8],
group: &[u8],
mode: GroupCreateMode,
mkstream: bool,
) -> Result<bool, StoreError>
pub fn xgroup_create( &mut self, key: &[u8], group: &[u8], mode: GroupCreateMode, mkstream: bool, ) -> Result<bool, StoreError>
XGROUP CREATE key group <id|$> [MKSTREAM]. Returns Ok(true)
when a fresh group was added; Ok(false) if the group already
existed (caller emits -BUSYGROUP). mkstream matches Redis:
auto-create the stream key when missing.
Sourcepub fn xgroup_destroy(
&mut self,
key: &[u8],
group: &[u8],
) -> Result<bool, StoreError>
pub fn xgroup_destroy( &mut self, key: &[u8], group: &[u8], ) -> Result<bool, StoreError>
XGROUP DESTROY key group. Returns true if a group was dropped.
Sourcepub fn xgroup_setid(
&mut self,
key: &[u8],
group: &[u8],
mode: GroupCreateMode,
) -> Result<bool, StoreError>
pub fn xgroup_setid( &mut self, key: &[u8], group: &[u8], mode: GroupCreateMode, ) -> Result<bool, StoreError>
XGROUP SETID key group <id|$>.
Sourcepub fn xgroup_create_consumer(
&mut self,
key: &[u8],
group: &[u8],
consumer: &[u8],
now_ms: u64,
) -> Result<bool, StoreError>
pub fn xgroup_create_consumer( &mut self, key: &[u8], group: &[u8], consumer: &[u8], now_ms: u64, ) -> Result<bool, StoreError>
XGROUP CREATECONSUMER key group consumer.
Sourcepub fn xgroup_del_consumer(
&mut self,
key: &[u8],
group: &[u8],
consumer: &[u8],
) -> Result<u64, StoreError>
pub fn xgroup_del_consumer( &mut self, key: &[u8], group: &[u8], consumer: &[u8], ) -> Result<u64, StoreError>
XGROUP DELCONSUMER key group consumer. Returns dropped PEL count.
Sourcepub fn xreadgroup(
&mut self,
key: &[u8],
group: &[u8],
consumer: &[u8],
last_seen: ReadGroupId,
count: Option<usize>,
noack: bool,
now_ms: u64,
) -> Result<Vec<(StreamId, Vec<(Vec<u8>, Vec<u8>)>)>, StoreError>
pub fn xreadgroup( &mut self, key: &[u8], group: &[u8], consumer: &[u8], last_seen: ReadGroupId, count: Option<usize>, noack: bool, now_ms: u64, ) -> Result<Vec<(StreamId, Vec<(Vec<u8>, Vec<u8>)>)>, StoreError>
XREADGROUP GROUP g c [COUNT n] [NOACK] STREAMS key id.
Sourcepub fn xreadgroup_has_new(
&mut self,
key: &[u8],
group: &[u8],
) -> Result<bool, StoreError>
pub fn xreadgroup_has_new( &mut self, key: &[u8], group: &[u8], ) -> Result<bool, StoreError>
Non-destructive: would XREADGROUP … STREAMS key > yield new
entries for group right now? True iff the stream’s last id is
past the group’s last-delivered id. Used by the cross-shard BLOCK
arbiter’s readiness peek — never advances the group cursor. False
for a missing key / group.
Sourcepub fn xack(
&mut self,
key: &[u8],
group: &[u8],
ids: &[StreamId],
) -> Result<u64, StoreError>
pub fn xack( &mut self, key: &[u8], group: &[u8], ids: &[StreamId], ) -> Result<u64, StoreError>
XACK key group id [id ...]. Returns count of PEL removals.
Sourcepub fn xpending_summary(
&mut self,
key: &[u8],
group: &[u8],
) -> Result<Option<PendingSummary>, StoreError>
pub fn xpending_summary( &mut self, key: &[u8], group: &[u8], ) -> Result<Option<PendingSummary>, StoreError>
XPENDING key group — summary form.
Sourcepub fn xpending_extended(
&mut self,
key: &[u8],
group: &[u8],
idle_min_ms: Option<u64>,
start: StreamId,
end: StreamId,
count: usize,
consumer_filter: Option<&[u8]>,
now_ms: u64,
) -> Result<Option<PendingExtended>, StoreError>
pub fn xpending_extended( &mut self, key: &[u8], group: &[u8], idle_min_ms: Option<u64>, start: StreamId, end: StreamId, count: usize, consumer_filter: Option<&[u8]>, now_ms: u64, ) -> Result<Option<PendingExtended>, StoreError>
XPENDING key group [IDLE ms] start end count [consumer] —
extended form.
Sourcepub fn xclaim(
&mut self,
key: &[u8],
group: &[u8],
new_owner: &[u8],
ids: &[StreamId],
opts: &XClaimOpts,
now_ms: u64,
) -> Result<Vec<(StreamId, Vec<(Vec<u8>, Vec<u8>)>)>, StoreError>
pub fn xclaim( &mut self, key: &[u8], group: &[u8], new_owner: &[u8], ids: &[StreamId], opts: &XClaimOpts, now_ms: u64, ) -> Result<Vec<(StreamId, Vec<(Vec<u8>, Vec<u8>)>)>, StoreError>
XCLAIM key group consumer min-idle-ms id [id ...] [...].
Returns the (id, field-value) pairs successfully claimed —
dispatcher trims to ID-only when JUSTID is set.
Sourcepub fn xautoclaim(
&mut self,
key: &[u8],
group: &[u8],
new_owner: &[u8],
min_idle_ms: u64,
start: StreamId,
count: usize,
justid: bool,
now_ms: u64,
) -> Result<(StreamId, Vec<(StreamId, Vec<(Vec<u8>, Vec<u8>)>)>, Vec<StreamId>), StoreError>
pub fn xautoclaim( &mut self, key: &[u8], group: &[u8], new_owner: &[u8], min_idle_ms: u64, start: StreamId, count: usize, justid: bool, now_ms: u64, ) -> Result<(StreamId, Vec<(StreamId, Vec<(Vec<u8>, Vec<u8>)>)>, Vec<StreamId>), StoreError>
XAUTOCLAIM key group consumer min-idle-ms start [COUNT n] [JUSTID]. Returns the cursor + claimed payloads + deleted IDs.
Source§impl Store
impl Store
Sourcepub fn set(
&mut self,
key: &[u8],
value: Vec<u8>,
expire: Option<Duration>,
nx: bool,
xx: bool,
) -> bool
pub fn set( &mut self, key: &[u8], value: Vec<u8>, expire: Option<Duration>, nx: bool, xx: bool, ) -> bool
SET — overwrites any existing value/type. NX/XX guards; clears TTL.
Takes an owned Vec so a >22 B value’s allocation is adopted as-is
(no copy). For callers holding a borrowed slice, prefer
Self::set_slice — it skips the to_vec entirely for values that
inline.
Sourcepub fn set_slice(
&mut self,
key: &[u8],
value: &[u8],
expire: Option<Duration>,
nx: bool,
xx: bool,
) -> bool
pub fn set_slice( &mut self, key: &[u8], value: &[u8], expire: Option<Duration>, nx: bool, xx: bool, ) -> bool
Self::set for a borrowed value. Values ≤ 22 B store inline in the
entry — zero allocator traffic, where set(key, value.to_vec(), …)
paid a malloc for the Vec and a free when the inline copy dropped
it (the dominant overwrite-SET pattern). Larger values pay the same
single allocation either way.
Sourcepub fn get_for_reply(
&mut self,
key: &[u8],
) -> Result<Option<GetReply<'_>>, StoreError>
pub fn get_for_reply( &mut self, key: &[u8], ) -> Result<Option<GetReply<'_>>, StoreError>
L1 (2026-06-21): GET variant that exposes the underlying encoding
so the reactor’s reply path can choose zero-copy
(Value::ArcBulk → push the Arc to the conn’s output_arcs for a
writev iovec) vs memcpy (Value::Str / Value::Int → encode bytes
into the conn’s output Vec). ONE keyspace lookup; the variant tag
chooses the encoding without a second probe.
Sourcepub fn get_into_output(
&mut self,
key: &[u8],
output: &mut Vec<u8>,
output_arcs: &mut Vec<(usize, Arc<Box<[u8]>>)>,
) -> Result<bool, StoreError>
pub fn get_into_output( &mut self, key: &[u8], output: &mut Vec<u8>, output_arcs: &mut Vec<(usize, Arc<Box<[u8]>>)>, ) -> Result<bool, StoreError>
A.6 (v1.25): fused GET-into-output. Skips the GetReply enum tag
round-trip + caller match arm by writing the RESP frame directly into
output (header + bytes + CRLF for Str/Int) or pushing the Arc into
output_arcs at the right offset (ArcBulk zero-copy via writev).
Returns the same outcomes as Self::get_for_reply: Ok(true) if
the key was found and emitted, Ok(false) if absent (the caller
emits the $-1 null bulk — preserves the existing inline-null
semantics on the reactor side), Err for WRONGTYPE.
Sourcepub fn get(&mut self, key: &[u8]) -> Result<Option<Cow<'_, [u8]>>, StoreError>
pub fn get(&mut self, key: &[u8]) -> Result<Option<Cow<'_, [u8]>>, StoreError>
GET — returns a Cow<[u8]> so Value::Int callers can format the
integer to ASCII without storing it. L2 (2026-06-21): Value::Str
returns Cow::Borrowed (zero copy, same as before); Value::Int
formats to a small owned Vec<u8> (up to 20 bytes for i64::MIN).
Read-only GET: &self, so concurrent readers can run under a shared
lock (embedded mode’s RwLock read path). Expiry is checked against the
coarse cached clock but an expired key is not removed here (no &mut)
— the reaper / next write reclaims it; a reader just sees None. LRU is
not touched, so this path is only used when eviction is off
(maxmemory == 0); with eviction, the caller takes the mutating
Self::get under an exclusive lock so access still stamps the LRU.
pub fn strlen(&mut self, key: &[u8]) -> Result<usize, StoreError>
pub fn append(&mut self, key: &[u8], data: &[u8]) -> Result<usize, StoreError>
Sourcepub fn incr_by(&mut self, key: &[u8], delta: i64) -> Result<i64, StoreError>
pub fn incr_by(&mut self, key: &[u8], delta: i64) -> Result<i64, StoreError>
INCRBY family; preserves any TTL.
L2 (2026-06-21, lessons from valkey OBJ_ENCODING_INT): the hot path
matches Value::Int(n) and does the increment in place — no parse,
no format, no allocation. The legacy Value::Str arm parses,
increments, and promotes to Value::Int(next) so subsequent
INCRs land on the fast path. Insert-new path also lands as Int.
Sourcepub fn getset(
&mut self,
key: &[u8],
val: Vec<u8>,
) -> Result<Option<Vec<u8>>, StoreError>
pub fn getset( &mut self, key: &[u8], val: Vec<u8>, ) -> Result<Option<Vec<u8>>, StoreError>
GETSET — set to val, return the previous string (WRONGTYPE if the old
value isn’t a string). Clears any TTL, like SET.
Sourcepub fn getdel(&mut self, key: &[u8]) -> Result<Option<Vec<u8>>, StoreError>
pub fn getdel(&mut self, key: &[u8]) -> Result<Option<Vec<u8>>, StoreError>
GETDEL — get then delete (WRONGTYPE if non-string).
Sourcepub fn incr_by_float(
&mut self,
key: &[u8],
delta: f64,
) -> Result<Vec<u8>, StoreError>
pub fn incr_by_float( &mut self, key: &[u8], delta: f64, ) -> Result<Vec<u8>, StoreError>
INCRBYFLOAT — returns the new value formatted as Redis would. Preserves TTL.
Source§impl Store
impl Store
Sourcepub fn zadd_borrowed(
&mut self,
key: &[u8],
pairs: &[(f64, &[u8])],
) -> Result<usize, StoreError>
pub fn zadd_borrowed( &mut self, key: &[u8], pairs: &[(f64, &[u8])], ) -> Result<usize, StoreError>
G4 (v1.25): borrowed-pair ZADD. A.8: encoding-switch.
Sourcepub fn zadd(
&mut self,
key: &[u8],
pairs: &[(f64, Vec<u8>)],
) -> Result<usize, StoreError>
pub fn zadd( &mut self, key: &[u8], pairs: &[(f64, Vec<u8>)], ) -> Result<usize, StoreError>
ZADD — returns the count of newly-added members.
pub fn zscore( &mut self, key: &[u8], member: &[u8], ) -> Result<Option<f64>, StoreError>
pub fn zcard(&mut self, key: &[u8]) -> Result<usize, StoreError>
pub fn zrem( &mut self, key: &[u8], members: &[Vec<u8>], ) -> Result<usize, StoreError>
Sourcepub fn zrem_borrowed(
&mut self,
key: &[u8],
members: &[&[u8]],
) -> Result<usize, StoreError>
pub fn zrem_borrowed( &mut self, key: &[u8], members: &[&[u8]], ) -> Result<usize, StoreError>
G4 (v1.25): borrowed-slice ZREM. A.8: encoding-aware.
Sourcepub fn zrank(
&mut self,
key: &[u8],
member: &[u8],
) -> Result<Option<usize>, StoreError>
pub fn zrank( &mut self, key: &[u8], member: &[u8], ) -> Result<Option<usize>, StoreError>
ZRANK — 0-based position in ascending order (O(n) for now).
Sourcepub fn zincrby(
&mut self,
key: &[u8],
incr: f64,
member: &[u8],
) -> Result<f64, StoreError>
pub fn zincrby( &mut self, key: &[u8], incr: f64, member: &[u8], ) -> Result<f64, StoreError>
ZINCRBY — add incr to a member’s score; returns the new score.
Sourcepub fn zrange(
&mut self,
key: &[u8],
start: i64,
stop: i64,
) -> Result<Vec<(Vec<u8>, f64)>, StoreError>
pub fn zrange( &mut self, key: &[u8], start: i64, stop: i64, ) -> Result<Vec<(Vec<u8>, f64)>, StoreError>
ZRANGE key start stop by rank.
Sourcepub fn zrange_by_score(
&mut self,
key: &[u8],
min: ScoreBound,
max: ScoreBound,
) -> Result<Vec<(Vec<u8>, f64)>, StoreError>
pub fn zrange_by_score( &mut self, key: &[u8], min: ScoreBound, max: ScoreBound, ) -> Result<Vec<(Vec<u8>, f64)>, StoreError>
ZRANGEBYSCORE.
Sourcepub fn zcount(
&mut self,
key: &[u8],
min: ScoreBound,
max: ScoreBound,
) -> Result<usize, StoreError>
pub fn zcount( &mut self, key: &[u8], min: ScoreBound, max: ScoreBound, ) -> Result<usize, StoreError>
ZCOUNT.
Sourcepub fn zpopmin(
&mut self,
key: &[u8],
count: usize,
) -> Result<Vec<(Vec<u8>, f64)>, StoreError>
pub fn zpopmin( &mut self, key: &[u8], count: usize, ) -> Result<Vec<(Vec<u8>, f64)>, StoreError>
ZPOPMIN key [count] — pop and return the count lowest-scored
members (ascending by (score, member)). Returns (member, score) pairs in pop order; empty when the key is absent / empty.
Sourcepub fn zrem_range_by_rank(
&mut self,
key: &[u8],
start: i64,
stop: i64,
) -> Result<usize, StoreError>
pub fn zrem_range_by_rank( &mut self, key: &[u8], start: i64, stop: i64, ) -> Result<usize, StoreError>
ZREMRANGEBYRANK key start stop — remove members in the rank
range [start, stop] (inclusive, negative indices count from
the tail). Returns the number of members removed.
Sourcepub fn zrem_range_by_score(
&mut self,
key: &[u8],
min: ScoreBound,
max: ScoreBound,
) -> Result<usize, StoreError>
pub fn zrem_range_by_score( &mut self, key: &[u8], min: ScoreBound, max: ScoreBound, ) -> Result<usize, StoreError>
ZREMRANGEBYSCORE key min max — remove every member whose score
satisfies min ≤ score ≤ max (with ( for exclusive bounds via
ScoreBound). Returns the number removed.
Sourcepub fn zrev_range_by_score(
&mut self,
key: &[u8],
min: ScoreBound,
max: ScoreBound,
) -> Result<Vec<(Vec<u8>, f64)>, StoreError>
pub fn zrev_range_by_score( &mut self, key: &[u8], min: ScoreBound, max: ScoreBound, ) -> Result<Vec<(Vec<u8>, f64)>, StoreError>
ZREVRANGEBYSCORE — zrange_by_score reversed. Bounds are
passed in the (min, max) order already (the caller is
responsible for swapping the user-facing max first, min second
at the dispatch layer).
Source§impl Store
impl Store
pub fn new() -> Store
Sourcepub fn refresh_clock(&mut self)
pub fn refresh_clock(&mut self)
Refresh the coarse cached clock (Self::cached_ns) from a single
Instant::now(). Call once per reactor-loop batch / reaper tick; the
per-access read path then skips its own clock read. Lazy expiry is
coarse to this cadence (a key expires ≤ one refresh-interval late,
never early — writes stamp deadlines from a fresh clock).
Sourcepub fn set_cached_clock(&mut self, on: bool)
pub fn set_cached_clock(&mut self, on: bool)
Enable/disable trusting the cached clock for lazy expiry (see
Self::cached_ns). Call with true only when something refreshes the
clock regularly (the server reactor per batch, the embedded background
reaper per tick); leave false for manual-reaper mode. Seeds the cache
when enabling so the first access is accurate.
Sourcepub fn set_max_memory(&mut self, maxmemory: u64, policy: EvictionPolicy)
pub fn set_max_memory(&mut self, maxmemory: u64, policy: EvictionPolicy)
Install (or clear, with maxmemory == 0) the eviction limit and
policy. Cheap; safe to call repeatedly (e.g. on CONFIG SET).
Sourcepub fn set_bio_drop_sender(&mut self, sender: Sender<Vec<Box<Value>>>)
pub fn set_bio_drop_sender(&mut self, sender: Sender<Vec<Box<Value>>>)
Install the runtime’s bio-drop channel (v1.25 A.3 + A.2). Called
once from kevy-rt::Runtime::run per shard before the reactor
loop starts. After install, Self::maybe_offload_drop (invoked
from the SET overwrite fast path) accumulates oversize Values
into a per-shard batch; the reactor calls
Self::flush_pending_drops at the end of every iter to ship
the batch in one mpsc send. Bounded the Axis I 10 KB SET p999/max
blow-up that synchronous Box::<[u8]>::drop of a jemalloc
large-class slot caused (see kevy_rt::bio).
Sourcepub fn flush_pending_drops(&mut self)
pub fn flush_pending_drops(&mut self)
Ship the per-shard bio-drop batch buffer to the bio thread in
one mpsc send. Called from kevy-rt’s reactor loop at the end
of every iteration (both the epoll Shard::run and the io_uring
Shard::run_uring paths, just before the AOF fsync window so a
pending fsync stall doesn’t pin a batch-ful of heavy values in
per-shard memory).
Empty-buffer fast path: zero work, predictable not-taken branch. Reactor calls this unconditionally per iter; the steady- state cost for a no-SET-overwrite iter is one length check.
SendError here means the bio thread has exited (shutdown
territory — Runtime::run has dropped its sender AFTER the
shard threads joined). Drop the batch inline; the SendError
payload carries the Vec back so its Box<Value>s run their
Drop here, preserving correctness.
Sourcepub fn used_memory(&self) -> u64
pub fn used_memory(&self) -> u64
Live byte estimate (see field doc).
Sourcepub fn used_memory_peak(&self) -> u64
pub fn used_memory_peak(&self) -> u64
used_memory high-water mark since startup.
Sourcepub fn eviction_policy(&self) -> EvictionPolicy
pub fn eviction_policy(&self) -> EvictionPolicy
Configured eviction policy.
Sourcepub fn evictions_total(&self) -> u64
pub fn evictions_total(&self) -> u64
Total keys evicted since startup.
Sourcepub fn expires_count(&self) -> usize
pub fn expires_count(&self) -> usize
Live keys carrying a TTL (INFO keyspace’s expires=). O(1) — reads
the maintained counter, not an O(n) scan (cf. Self::ttl_pending_count).
Sourcepub fn record_watch(&mut self, key: &[u8]) -> u64
pub fn record_watch(&mut self, key: &[u8]) -> u64
WATCH — record this key in the version tracker and return its
current version. Subsequent writes on this shard bump the version
via Self::bump_if_watched. Caller (the conn’s origin shard)
stores the returned version; EXEC later asks every owning shard
“is the version still N?” via Self::key_version.
Keys that have never been written stay at version 0 — the first
write after a WATCH bumps to 1, which is what makes the “dirty”
comparison work (stored 0 ≠ current 1 ⇒ abort EXEC).
Sourcepub fn key_version(&self, key: &[u8]) -> u64
pub fn key_version(&self, key: &[u8]) -> u64
Read-only version lookup used by EXEC’s pre-execution check.
Returns 0 for keys never WATCH-ed (matches the initial value
record_watch would have inserted, so a WATCH → no-write →
EXEC sequence sees the stored 0 == current 0 and proceeds).
Sourcepub fn bump_if_watched(&mut self, key: &[u8])
pub fn bump_if_watched(&mut self, key: &[u8])
Bump the version of key if (and only if) it has been WATCH-ed at
least once. Write-side call after every mutation. The empty check
runs BEFORE the key is hashed — the common nothing-watched case
pays one branch, not a guaranteed-miss probe.
Sourcepub fn bump_all_watched(&mut self)
pub fn bump_all_watched(&mut self)
Invalidate every watched key in one shot. Called from FLUSHDB
/ FLUSHALL execution paths — every WATCH against this shard
must invalidate so a pending EXEC aborts.
Sourcepub fn estimate_key_bytes(&self, key: &[u8]) -> Option<u64>
pub fn estimate_key_bytes(&self, key: &[u8]) -> Option<u64>
Cached weight of key (dynamic part + ENTRY_OVERHEAD). Returns
None when the key is absent or expired (no implicit reap).
Sourcepub fn precheck_for_write(&self) -> Result<(), StoreError>
pub fn precheck_for_write(&self) -> Result<(), StoreError>
O(1) precondition check the dispatch layer calls before every write
command. Returns Err(OutOfMemory) only when maxmemory > 0, the
budget is already over, AND the policy is NoEviction (Redis
behaviour). All other policies let the write proceed and recover via
Self::try_evict_after_write.
Sourcepub fn try_evict_after_write(&mut self) -> usize
pub fn try_evict_after_write(&mut self) -> usize
Run after every write command. No-op when disabled or under budget;
otherwise samples per Self::eviction_policy and removes keys until
back under maxmemory or no eligible candidate remains. Returns the
number of keys evicted (0 on the common fast path).