pub struct Store { /* private fields */ }Expand description
The embedded keyspace.
Store is Clone. A clone is a cheap Arc bump:
every clone reaches the same underlying shards + AOF + reaper + pub/sub
bus. The reaper thread is joined and each shard’s AOF is flushed exactly
once, when the last clone is dropped.
use kevy_embedded::{Config, Store};
let s = Store::open(Config::default().with_ttl_reaper_manual())?;
let s2 = s.clone();
std::thread::spawn(move || {
s2.set(b"from-thread", b"v").unwrap();
}).join().unwrap();
assert_eq!(s.get(b"from-thread")?, Some(b"v".to_vec()));Every method takes &self. Sharding (see Config::with_shards) lets a
multi-threaded consumer scale across cores; pub/sub is process-wide
(handled on shard 0).
Implementations§
Source§impl Store
impl Store
Sourcepub fn info(&self) -> KevyInfo
pub fn info(&self) -> KevyInfo
One-shot snapshot of the store’s introspection counters. See
KevyInfo. Takes the embedded mutex once; safe to call from a
health endpoint.
Sourcepub fn tier_info(&self) -> Option<KevyTierInfo>
pub fn tier_info(&self) -> Option<KevyTierInfo>
The # Tiering gauges summed across shards, or None when
tiering is off (the section is absent, not zeroed — INFO
stability for untiered stores).
Sourcepub fn expire_pending_count(&self) -> usize
pub fn expire_pending_count(&self) -> usize
Number of live keys that currently carry a TTL (the expire-set size, summed across shards).
Source§impl Store
impl Store
Sourcepub fn set(&self, key: &[u8], value: &[u8]) -> KevyResult<bool>
pub fn set(&self, key: &[u8], value: &[u8]) -> KevyResult<bool>
SET key value (no TTL, no NX/XX). Returns true always under the
embedded API (Redis semantics: SET overwrites; NX/XX vetoes would
return false but we don’t expose those here — use Store::with
for the full surface).
Sourcepub fn set_with_ttl(
&self,
key: &[u8],
value: &[u8],
ttl: Duration,
) -> KevyResult<bool>
pub fn set_with_ttl( &self, key: &[u8], value: &[u8], ttl: Duration, ) -> KevyResult<bool>
SET key value PX ms — overwrites + sets TTL. The AOF records an
absolute PEXPIREAT deadline (not the relative ttl) so the key
expires at the same wall-clock instant after a restart — a relative
PEXPIRE would be re-anchored to replay-time, resetting the TTL to a
fresh full duration on every restart (seen as a production
incident: cache keys never expired across restarts).
Sourcepub fn get(&self, key: &[u8]) -> KevyResult<Option<Vec<u8>>>
pub fn get(&self, key: &[u8]) -> KevyResult<Option<Vec<u8>>>
GET key — Some(bytes) on hit, None on miss or expired.
The lock is policy-gated (see Self::reads_use_shared_lock):
whenever the active eviction policy won’t consume a per-read LRU/LFU
tick — maxmemory == 0 (the default), or the NoEviction /
*Random / VolatileTtl policies — this takes the shared lock and a
non-mutating get_shared lookup. That
is a lock-correctness choice: a read-only GET has no business holding
the exclusive lock and blocking a concurrent writer on its shard. It is
not a throughput win — concurrent GETs still contend on the shard’s
RwLock word (there is no lock-free read path), so read scaling is
bounded by shard count, not core count. Expired keys still read as
None here (lazy expire-skip; the reaper / next write reclaims them).
Only the true LRU/LFU policies fall back to the exclusive lock + mutating
get so each access stamps the clock the eviction scorer ranks by.
GET for the FFI zero-copy shared lane (kevy_get_shared). Bulk
values come back as an Arc::clone — no byte copy — so the FFI can
hand JS a buffer viewing the engine’s own storage (the win vs the plain
Self::get, which into_owned-copies). The lookup is non-mutating;
the lock is policy-gated like Self::get (Self::reads_use_shared_lock).
This lane never stamps the LRU clock and never promotes a cold value.
Sourcepub fn del(&self, keys: &[&[u8]]) -> KevyResult<usize>
pub fn del(&self, keys: &[&[u8]]) -> KevyResult<usize>
DEL key1 [key2 ...]. Returns the count of keys actually removed.
Keys fan out to their owning shards.
Sourcepub fn exists(&self, keys: &[&[u8]]) -> KevyResult<usize>
pub fn exists(&self, keys: &[&[u8]]) -> KevyResult<usize>
EXISTS key1 [key2 ...]. Count of existing keys (duplicates counted
multiple times, matching Redis).
Sourcepub fn incr(&self, key: &[u8]) -> KevyResult<i64>
pub fn incr(&self, key: &[u8]) -> KevyResult<i64>
INCR key. Returns the post-increment value.
Sourcepub fn incr_by(&self, key: &[u8], delta: i64) -> KevyResult<i64>
pub fn incr_by(&self, key: &[u8], delta: i64) -> KevyResult<i64>
INCRBY key delta. Negative delta does DECR-style work.
Sourcepub fn expire(&self, key: &[u8], ttl: Duration) -> KevyResult<bool>
pub fn expire(&self, key: &[u8], ttl: Duration) -> KevyResult<bool>
EXPIRE key seconds. Returns true if a key was touched. The AOF
records an absolute PEXPIREAT deadline (see Self::set_with_ttl)
so the TTL survives a restart unchanged.
Sourcepub fn persist(&self, key: &[u8]) -> KevyResult<bool>
pub fn persist(&self, key: &[u8]) -> KevyResult<bool>
PERSIST key. Returns true if a TTL was actually cleared.
Sourcepub fn ttl_ms(&self, key: &[u8]) -> i64
pub fn ttl_ms(&self, key: &[u8]) -> i64
Remaining TTL in ms (or Redis-style -1/-2 for no-TTL/no-key).
Sourcepub fn type_of(&self, key: &[u8]) -> &'static str
pub fn type_of(&self, key: &[u8]) -> &'static str
TYPE key — "string", "hash", "list", "set", "zset", or "none".
Sourcepub fn dbsize(&self) -> usize
pub fn dbsize(&self) -> usize
DBSIZE — total live keys across all shards.
Aggregates under each shard’s SHARED lock (the underlying dbsize is
&self). This is a latency fix, not a scaling one: a full-keyspace
count shouldn’t hold every shard’s write lock and stall concurrent
writers while it sums.
Sourcepub fn flushall(&self) -> KevyResult<()>
pub fn flushall(&self) -> KevyResult<()>
FLUSHALL — empty every shard (each logs FLUSHALL so a replay reaches
the same empty state).
Named flushall — not flush — to avoid colliding with
Write::flush’s “sync buffered writes to disk” meaning. This call
WIPES the store; durability needs no explicit call (each write appends
to the AOF, the shard’s BufWriter lands per AppendFsync cadence
and on drop).
Sourcepub fn key_bytes(&self, key: &[u8]) -> Option<u64>
pub fn key_bytes(&self, key: &[u8]) -> Option<u64>
MEMORY USAGE for one key — Some(bytes) or None if absent.
Read-only (estimate_key_bytes is &self), so it takes the shard’s
SHARED lock rather than blocking a concurrent writer on that shard.
Sourcepub fn used_memory(&self) -> u64
pub fn used_memory(&self) -> u64
Live used_memory estimate (summed across shards).
Aggregates under each shard’s SHARED lock (latency fix — an INFO-time
memory sum shouldn’t hold every shard’s write lock; see Self::dbsize).
Sourcepub fn evictions_total(&self) -> u64
pub fn evictions_total(&self) -> u64
INFO-style counter: total keys evicted by maxmemory (all shards).
Read-only aggregation under each shard’s SHARED lock (see Self::dbsize).
Sourcepub fn expired_keys_total(&self) -> u64
pub fn expired_keys_total(&self) -> u64
INFO-style counter: total keys expired (lazy + active reaper, all shards).
Read-only aggregation under each shard’s SHARED lock (see Self::dbsize).
Sourcepub fn hset(&self, key: &[u8], pairs: &[(&[u8], &[u8])]) -> KevyResult<usize>
pub fn hset(&self, key: &[u8], pairs: &[(&[u8], &[u8])]) -> KevyResult<usize>
HSET key field value [field value ...]. Returns count newly added.
Sourcepub fn hget(&self, key: &[u8], field: &[u8]) -> KevyResult<Option<Vec<u8>>>
pub fn hget(&self, key: &[u8], field: &[u8]) -> KevyResult<Option<Vec<u8>>>
HGET key field. None if absent.
Sourcepub fn hdel(&self, key: &[u8], fields: &[&[u8]]) -> KevyResult<usize>
pub fn hdel(&self, key: &[u8], fields: &[&[u8]]) -> KevyResult<usize>
HDEL key field [field ...]. Returns count actually removed.
Sourcepub fn lpush(&self, key: &[u8], values: &[&[u8]]) -> KevyResult<usize>
pub fn lpush(&self, key: &[u8], values: &[&[u8]]) -> KevyResult<usize>
LPUSH key value [value ...]. Returns the new list length.
Sourcepub fn rpush(&self, key: &[u8], values: &[&[u8]]) -> KevyResult<usize>
pub fn rpush(&self, key: &[u8], values: &[&[u8]]) -> KevyResult<usize>
RPUSH key value [value ...]. Returns the new list length.
Sourcepub fn lpop(&self, key: &[u8], count: usize) -> KevyResult<Vec<Vec<u8>>>
pub fn lpop(&self, key: &[u8], count: usize) -> KevyResult<Vec<Vec<u8>>>
LPOP key count. Returns popped values from the head.
Sourcepub fn rpop(&self, key: &[u8], count: usize) -> KevyResult<Vec<Vec<u8>>>
pub fn rpop(&self, key: &[u8], count: usize) -> KevyResult<Vec<Vec<u8>>>
RPOP key count. Symmetric to LPOP from the tail.
Sourcepub fn llen(&self, key: &[u8]) -> KevyResult<usize>
pub fn llen(&self, key: &[u8]) -> KevyResult<usize>
LLEN key. Length of the list at key; 0 if absent.
Sourcepub fn sadd(&self, key: &[u8], members: &[&[u8]]) -> KevyResult<usize>
pub fn sadd(&self, key: &[u8], members: &[&[u8]]) -> KevyResult<usize>
SADD key member [member ...]. Returns count newly added.
Sourcepub fn srem(&self, key: &[u8], members: &[&[u8]]) -> KevyResult<usize>
pub fn srem(&self, key: &[u8], members: &[&[u8]]) -> KevyResult<usize>
SREM key member [member ...]. Returns count actually removed.
Sourcepub fn smembers(&self, key: &[u8]) -> KevyResult<Vec<Vec<u8>>>
pub fn smembers(&self, key: &[u8]) -> KevyResult<Vec<Vec<u8>>>
SMEMBERS key. Order implementation-defined; empty if absent.
Sourcepub fn scard(&self, key: &[u8]) -> KevyResult<usize>
pub fn scard(&self, key: &[u8]) -> KevyResult<usize>
SCARD key. Member count; 0 if absent.
Sourcepub fn zadd(&self, key: &[u8], pairs: &[(f64, &[u8])]) -> KevyResult<usize>
pub fn zadd(&self, key: &[u8], pairs: &[(f64, &[u8])]) -> KevyResult<usize>
ZADD key score member [score member ...]. Returns count newly added.
Sourcepub fn zrem(&self, key: &[u8], members: &[&[u8]]) -> KevyResult<usize>
pub fn zrem(&self, key: &[u8], members: &[&[u8]]) -> KevyResult<usize>
ZREM key member [member ...]. Returns count actually removed.
Sourcepub fn zscore(&self, key: &[u8], member: &[u8]) -> KevyResult<Option<f64>>
pub fn zscore(&self, key: &[u8], member: &[u8]) -> KevyResult<Option<f64>>
ZSCORE key member. Some(score) if present.
Sourcepub fn zcard(&self, key: &[u8]) -> KevyResult<usize>
pub fn zcard(&self, key: &[u8]) -> KevyResult<usize>
ZCARD key. Member count; 0 if absent.
Sourcepub fn dispatch_argv(&self, argv: &[Vec<u8>], out: &mut Vec<u8>)
pub fn dispatch_argv(&self, argv: &[Vec<u8>], out: &mut Vec<u8>)
Dispatch one command as argv, appending the RESP-encoded reply to
out — the full read+write verb surface (ESTORE_OPS plus the
conn face). This is the generic entry the FFI layer builds every
language binding on: one function reaches the whole engine. The
read-only listener keeps its own narrower whitelist.
Sourcepub fn publish(&self, channel: &[u8], payload: &[u8]) -> usize
pub fn publish(&self, channel: &[u8], payload: &[u8]) -> usize
PUBLISH channel payload. Delivers payload to every subscriber on
channel (direct + pattern matches) inside this process. Returns
the count of receivers the message reached.
Sourcepub fn subscribe(&self, channels: &[&[u8]]) -> Subscription
pub fn subscribe(&self, channels: &[&[u8]]) -> Subscription
Open a Subscription subscribed to channels. Drop the handle
to unsubscribe from everything atomically. Pass &[] to start
with no subscriptions and add some later via
Subscription::subscribe / Subscription::psubscribe.
Sourcepub fn psubscribe(&self, patterns: &[&[u8]]) -> Subscription
pub fn psubscribe(&self, patterns: &[&[u8]]) -> Subscription
Convenience: open a Subscription starting on pattern subscriptions.
Source§impl Store
impl Store
Sourcepub fn atomic<R>(
&self,
body: impl FnOnce(&mut AtomicCtx<'_>) -> KevyResult<R>,
) -> KevyResult<R>
pub fn atomic<R>( &self, body: impl FnOnce(&mut AtomicCtx<'_>) -> KevyResult<R>, ) -> KevyResult<R>
Run body as a single-shard atomic transaction: it applies
entirely, or not at all.
Inside the closure every read sees the closure’s own previous
writes. On Ok, the queued AOF frames are committed as one
group — under Fsync::Always that is a single fsync for the
whole block, not one per mutation.
On Err, every write the closure made is rolled back and
nothing is appended to the AOF. This is what lets the closure
act as the enforcement point for an invariant: read, decide,
write, and return Err to reject — the rejection leaves no
trace. (Before 4.0 the writes stayed live in memory while their
AOF frames were discarded, so a restarted process disagreed
with the running one.)
Rollback restores each touched key to the value and TTL it had before the transaction — including deleting keys the closure created. It is a snapshot of the keys the closure touches, so the cost scales with the transaction, not the keyspace.
Constraint: every key touched inside the closure must hash to the same shard. The default embedded config uses 1 shard, so any key works.
Source§impl Store
impl Store
Sourcepub fn atomic_all_shards<R>(
&self,
body: impl FnOnce(&mut AtomicAllShards<'_>) -> KevyResult<R>,
) -> KevyResult<R>
pub fn atomic_all_shards<R>( &self, body: impl FnOnce(&mut AtomicAllShards<'_>) -> KevyResult<R>, ) -> KevyResult<R>
Run body as a transaction holding write locks on EVERY
shard for the closure’s duration. Reads inside the closure
see prior writes (full read-modify-write). On closure
return, AOF writes commit with one fsync per shard.
Cost: blocks every other writer + reader on this Store for
the closure body. Use when atomic multi-shard semantics are
required; otherwise prefer the single-shard atomic.
Source§impl Store
impl Store
Sourcepub fn getbit(&self, key: &[u8], offset: u64) -> KevyResult<u8>
pub fn getbit(&self, key: &[u8], offset: u64) -> KevyResult<u8>
GETBIT key offset — return the bit at offset (MSB-first).
0 for missing key or past-end.
Sourcepub fn setbit(&self, key: &[u8], offset: u64, value: u8) -> KevyResult<u8>
pub fn setbit(&self, key: &[u8], offset: u64, value: u8) -> KevyResult<u8>
SETBIT key offset value — set the bit at offset to
value (0 or 1). Extends the underlying string with zero
padding as needed. Returns the PREVIOUS bit value.
Sourcepub fn bitcount(&self, key: &[u8], range: Option<(i64, i64)>) -> KevyResult<u64>
pub fn bitcount(&self, key: &[u8], range: Option<(i64, i64)>) -> KevyResult<u64>
BITCOUNT key [start end] — count set bits over the
optional byte-offset range (inclusive, negatives-from-tail
like Redis). None for range = whole string.
Sourcepub fn bitpos(
&self,
key: &[u8],
bit: u8,
range: Option<(i64, i64)>,
) -> KevyResult<Option<u64>>
pub fn bitpos( &self, key: &[u8], bit: u8, range: Option<(i64, i64)>, ) -> KevyResult<Option<u64>>
BITPOS key bit [start [end]] — find first bit equal to
bit (0 or 1) in the optional byte range. Returns None
when not found (Redis would reply :-1).
Sourcepub fn getrange(&self, key: &[u8], start: i64, end: i64) -> KevyResult<Vec<u8>>
pub fn getrange(&self, key: &[u8], start: i64, end: i64) -> KevyResult<Vec<u8>>
GETRANGE key start end — substring with Redis negative
indexing; [start, end] inclusive.
Sourcepub fn setrange(
&self,
key: &[u8],
offset: u64,
value: &[u8],
) -> KevyResult<usize>
pub fn setrange( &self, key: &[u8], offset: u64, value: &[u8], ) -> KevyResult<usize>
SETRANGE key offset value — overwrite bytes at offset;
extends with zero padding if past current length. Returns
the new total length.
Sourcepub fn bitop(&self, op: BitOp, dst: &[u8], srcs: &[&[u8]]) -> KevyResult<usize>
pub fn bitop(&self, op: BitOp, dst: &[u8], srcs: &[&[u8]]) -> KevyResult<usize>
BITOP AND|OR|XOR|NOT destkey srckey [srckey ...] — bitwise
op across N source keys, stored at destkey. Returns the
destination string length (= longest source length, with
shorter sources zero-padded). For Not, exactly one source
key (additional ones are rejected).
Source§impl Store
impl Store
Sourcepub fn setnx(&self, key: &[u8], value: &[u8]) -> KevyResult<bool>
pub fn setnx(&self, key: &[u8], value: &[u8]) -> KevyResult<bool>
SETNX key value — set only if the key does not exist.
Returns true when the SET succeeded; false when it was
vetoed by an existing value.
Sourcepub fn incrbyfloat(&self, key: &[u8], delta: f64) -> KevyResult<f64>
pub fn incrbyfloat(&self, key: &[u8], delta: f64) -> KevyResult<f64>
INCRBYFLOAT key delta — atomic float increment of a string
value. Returns the post-increment value parsed as f64.
Sourcepub fn decr(&self, key: &[u8]) -> KevyResult<i64>
pub fn decr(&self, key: &[u8]) -> KevyResult<i64>
DECR key — atomic decrement by 1.
Sourcepub fn decrby(&self, key: &[u8], delta: i64) -> KevyResult<i64>
pub fn decrby(&self, key: &[u8], delta: i64) -> KevyResult<i64>
DECRBY key delta — atomic decrement by delta.
Sourcepub fn strlen(&self, key: &[u8]) -> KevyResult<usize>
pub fn strlen(&self, key: &[u8]) -> KevyResult<usize>
STRLEN key — length of the string value at key; 0 if
absent. Errors on wrong type.
Sourcepub fn append(&self, key: &[u8], data: &[u8]) -> KevyResult<usize>
pub fn append(&self, key: &[u8], data: &[u8]) -> KevyResult<usize>
APPEND key data — append data to the string at key.
Creates the key if absent. Returns the new total length.
Source§impl Store
impl Store
Sourcepub fn copy(&self, src: &[u8], dst: &[u8], replace: bool) -> KevyResult<bool>
pub fn copy(&self, src: &[u8], dst: &[u8], replace: bool) -> KevyResult<bool>
COPY src dst [REPLACE] — copy src’s value (and TTL if any)
to dst. Returns true when the copy happened.
Semantics:
falseifsrcdoesn’t exist.falseifdstexists andreplace = false.- Preserves source TTL on the destination via
pexpireat.
Sourcepub fn randomkey(&self) -> Option<Vec<u8>>
pub fn randomkey(&self) -> Option<Vec<u8>>
RANDOMKEY — return a randomly-chosen existing key, or
None when the keyspace is empty.
Implementation: snapshot all keys via collect_keys, then
pick a uniform index. For large keyspaces this is O(N); a
future ship can add a key_at(rank) Store method for O(1)
random pick.
Sourcepub fn unlink(&self, keys: &[&[u8]]) -> KevyResult<usize>
pub fn unlink(&self, keys: &[&[u8]]) -> KevyResult<usize>
UNLINK key [key ...] — alias for Self::del. In Redis
this is the async (non-blocking) variant; kevy is in-process
so the sync del IS the unblocking semantic. Returns count
actually removed.
Sourcepub fn touch(&self, keys: &[&[u8]]) -> KevyResult<usize>
pub fn touch(&self, keys: &[&[u8]]) -> KevyResult<usize>
TOUCH key [key ...] — count keys that exist. Side effect:
the existence check refreshes LRU/LFU bookkeeping on the
touched shards, matching Redis semantics.
Source§impl Store
impl Store
Sourcepub fn prefix_digest(&self, prefix: &[u8]) -> (u64, u64)
pub fn prefix_digest(&self, prefix: &[u8]) -> (u64, u64)
Order-insensitive prefix checksum for migration
verification: (row_count, xor_of_row_digests). Matches the
server’s PREFIX.DIGEST bit for bit (same canonicalization).
Source§impl Store
impl Store
Sourcepub fn sismember(&self, key: &[u8], member: &[u8]) -> KevyResult<bool>
pub fn sismember(&self, key: &[u8], member: &[u8]) -> KevyResult<bool>
SISMEMBER key member — true when member is in the set.
Sourcepub fn spop(&self, key: &[u8], count: usize) -> KevyResult<Vec<Vec<u8>>>
pub fn spop(&self, key: &[u8], count: usize) -> KevyResult<Vec<Vec<u8>>>
SPOP key count — atomically remove + return up to count
random members.
AOF form: logged as SREM key <popped…> (the members actually
removed), not SPOP key count — a random pick replayed against
a store whose internal layout differs (replica applying frames
onto snapshot-loaded state) would remove different members.
Redis propagates SPOP the same way.
Sourcepub fn srandmember(&self, key: &[u8], count: usize) -> KevyResult<Vec<Vec<u8>>>
pub fn srandmember(&self, key: &[u8], count: usize) -> KevyResult<Vec<Vec<u8>>>
SRANDMEMBER key count — return up to count random members
without removing them.
Sourcepub fn zrank(&self, key: &[u8], member: &[u8]) -> KevyResult<Option<usize>>
pub fn zrank(&self, key: &[u8], member: &[u8]) -> KevyResult<Option<usize>>
ZRANK key member — rank (0-based, ascending) of member;
None if not present.
Sourcepub fn zcount(&self, key: &[u8], min: f64, max: f64) -> KevyResult<usize>
pub fn zcount(&self, key: &[u8], min: f64, max: f64) -> KevyResult<usize>
ZCOUNT key min max — count members whose score falls in
[min, max] (inclusive). Pass ±INFINITY for open bounds.
Sourcepub fn zpopmin(
&self,
key: &[u8],
count: usize,
) -> KevyResult<Vec<(Vec<u8>, f64)>>
pub fn zpopmin( &self, key: &[u8], count: usize, ) -> KevyResult<Vec<(Vec<u8>, f64)>>
ZPOPMIN key count — atomically remove + return up to count
members with the lowest scores. Pairs are (member, score).
Sourcepub fn zremrangebyrank(
&self,
key: &[u8],
start: i64,
stop: i64,
) -> KevyResult<usize>
pub fn zremrangebyrank( &self, key: &[u8], start: i64, stop: i64, ) -> KevyResult<usize>
ZREMRANGEBYRANK key start stop — remove members in
[start, stop] rank range (inclusive, Redis-style negative
indexing). Returns count removed.
Sourcepub fn zremrangebyscore(
&self,
key: &[u8],
min: f64,
max: f64,
) -> KevyResult<usize>
pub fn zremrangebyscore( &self, key: &[u8], min: f64, max: f64, ) -> KevyResult<usize>
ZREMRANGEBYSCORE key min max — remove members with scores
in [min, max] (inclusive). Returns count removed.
Sourcepub fn zrev_range_by_score(
&self,
key: &[u8],
max: f64,
min: f64,
) -> KevyResult<Vec<(Vec<u8>, f64)>>
pub fn zrev_range_by_score( &self, key: &[u8], max: f64, min: f64, ) -> KevyResult<Vec<(Vec<u8>, f64)>>
ZREVRANGEBYSCORE key max min — members with scores in
[min, max] in DESCENDING score order. Inclusive bounds.
Sourcepub fn lset(&self, key: &[u8], idx: i64, value: &[u8]) -> KevyResult<()>
pub fn lset(&self, key: &[u8], idx: i64, value: &[u8]) -> KevyResult<()>
LSET key idx value — set the element at idx (negative
indexes count from tail). Errors NoSuchKey / OutOfRange
matching Redis.
Sourcepub fn ltrim(&self, key: &[u8], start: i64, stop: i64) -> KevyResult<()>
pub fn ltrim(&self, key: &[u8], start: i64, stop: i64) -> KevyResult<()>
LTRIM key start stop — trim list to [start, stop]
inclusive (Redis-style negative indexing).
Source§impl Store
impl Store
Sourcepub fn hgetall(&self, key: &[u8]) -> KevyResult<Vec<(Vec<u8>, Vec<u8>)>>
pub fn hgetall(&self, key: &[u8]) -> KevyResult<Vec<(Vec<u8>, Vec<u8>)>>
HGETALL key — every (field, value) pair in key’s hash, in
arbitrary order. Empty when key is absent. Errors on wrong type.
Sourcepub fn hexists(&self, key: &[u8], field: &[u8]) -> KevyResult<bool>
pub fn hexists(&self, key: &[u8], field: &[u8]) -> KevyResult<bool>
HEXISTS key field — true when field is present.
Sourcepub fn hlen(&self, key: &[u8]) -> KevyResult<usize>
pub fn hlen(&self, key: &[u8]) -> KevyResult<usize>
HLEN key — number of fields; 0 when absent.
Sourcepub fn hkeys(&self, key: &[u8]) -> KevyResult<Vec<Vec<u8>>>
pub fn hkeys(&self, key: &[u8]) -> KevyResult<Vec<Vec<u8>>>
HKEYS key — every field name in key’s hash.
Sourcepub fn hvals(&self, key: &[u8]) -> KevyResult<Vec<Vec<u8>>>
pub fn hvals(&self, key: &[u8]) -> KevyResult<Vec<Vec<u8>>>
HVALS key — every value in key’s hash.
Sourcepub fn hmget(
&self,
key: &[u8],
fields: &[&[u8]],
) -> KevyResult<Vec<Option<Vec<u8>>>>
pub fn hmget( &self, key: &[u8], fields: &[&[u8]], ) -> KevyResult<Vec<Option<Vec<u8>>>>
HMGET key field [field ...] — read multiple fields in one
call. None per requested field that is absent.
Sourcepub fn hincrby(&self, key: &[u8], field: &[u8], delta: i64) -> KevyResult<i64>
pub fn hincrby(&self, key: &[u8], field: &[u8], delta: i64) -> KevyResult<i64>
HINCRBY key field delta — atomic integer increment of a hash
field. Returns the post-increment value.
Sourcepub fn zrange(
&self,
key: &[u8],
start: i64,
stop: i64,
) -> KevyResult<Vec<(Vec<u8>, f64)>>
pub fn zrange( &self, key: &[u8], start: i64, stop: i64, ) -> KevyResult<Vec<(Vec<u8>, f64)>>
ZRANGE key start stop WITHSCORES — members in ascending score
order between rank start..=stop (Redis-style inclusive
indexing; negatives count from the tail). Returns (member, score) pairs.
Sourcepub fn zrevrange(
&self,
key: &[u8],
start: i64,
stop: i64,
) -> KevyResult<Vec<(Vec<u8>, f64)>>
pub fn zrevrange( &self, key: &[u8], start: i64, stop: i64, ) -> KevyResult<Vec<(Vec<u8>, f64)>>
ZREVRANGE key start stop WITHSCORES — zrange with the order
reversed (highest score first). The start..=stop indexing is
against the reversed list, matching Redis semantics.
Sourcepub fn zrange_by_score(
&self,
key: &[u8],
min: f64,
max: f64,
) -> KevyResult<Vec<(Vec<u8>, f64)>>
pub fn zrange_by_score( &self, key: &[u8], min: f64, max: f64, ) -> KevyResult<Vec<(Vec<u8>, f64)>>
ZRANGEBYSCORE — score-range read. min / max are
inclusive; pass f64::NEG_INFINITY / f64::INFINITY for open
bounds. Returns (member, score) pairs in ascending score
order. Exclusive bounds are ZRANGEBYSCORE ( syntax in Redis;
expose via the dedicated Self::zrange_by_score_excl.
Sourcepub fn zrange_by_score_excl(
&self,
key: &[u8],
min: ScoreBound,
max: ScoreBound,
) -> KevyResult<Vec<(Vec<u8>, f64)>>
pub fn zrange_by_score_excl( &self, key: &[u8], min: ScoreBound, max: ScoreBound, ) -> KevyResult<Vec<(Vec<u8>, f64)>>
Same as Self::zrange_by_score but with explicit
inclusive/exclusive control on each bound ((min / (max in
Redis syntax).
Sourcepub fn zrange_by_score_limit(
&self,
key: &[u8],
min: f64,
max: f64,
offset: usize,
count: usize,
) -> KevyResult<Vec<(Vec<u8>, f64)>>
pub fn zrange_by_score_limit( &self, key: &[u8], min: f64, max: f64, offset: usize, count: usize, ) -> KevyResult<Vec<(Vec<u8>, f64)>>
ZRANGEBYSCORE key min max LIMIT offset count — score-range
read with pagination (closes the embedded LIMIT gap —
the server parser always had it).
Sourcepub fn zrevrange_by_score_limit(
&self,
key: &[u8],
max: f64,
min: f64,
offset: usize,
count: usize,
) -> KevyResult<Vec<(Vec<u8>, f64)>>
pub fn zrevrange_by_score_limit( &self, key: &[u8], max: f64, min: f64, offset: usize, count: usize, ) -> KevyResult<Vec<(Vec<u8>, f64)>>
ZREVRANGEBYSCORE key max min LIMIT offset count — descending
score-range read with pagination.
Sourcepub fn zpopmin_below(
&self,
key: &[u8],
below: f64,
count: usize,
) -> KevyResult<Vec<(Vec<u8>, f64)>>
pub fn zpopmin_below( &self, key: &[u8], below: f64, count: usize, ) -> KevyResult<Vec<(Vec<u8>, f64)>>
zpopmin_below — pop up to count lowest members with
score strictly < below (delayed-job “pop what’s due”).
AOF logs the effect (ZREM of the popped members).
Sourcepub fn zincrby(&self, key: &[u8], delta: f64, member: &[u8]) -> KevyResult<f64>
pub fn zincrby(&self, key: &[u8], delta: f64, member: &[u8]) -> KevyResult<f64>
ZINCRBY key delta member — atomic float increment of a member’s
score. Returns the post-increment score.
Sourcepub fn lrange(
&self,
key: &[u8],
start: i64,
stop: i64,
) -> KevyResult<Vec<Vec<u8>>>
pub fn lrange( &self, key: &[u8], start: i64, stop: i64, ) -> KevyResult<Vec<Vec<u8>>>
LRANGE key start stop — list slice. Negative indices count
from the tail. Empty when absent.
Sourcepub fn lindex(&self, key: &[u8], idx: i64) -> KevyResult<Option<Vec<u8>>>
pub fn lindex(&self, key: &[u8], idx: i64) -> KevyResult<Option<Vec<u8>>>
LINDEX key idx — element at index idx; None out of range.
Sourcepub fn lrem(&self, key: &[u8], count: i64, value: &[u8]) -> KevyResult<usize>
pub fn lrem(&self, key: &[u8], count: i64, value: &[u8]) -> KevyResult<usize>
LREM key count value — remove up to |count| occurrences of
value. count > 0 from head, count < 0 from tail,
count == 0 all. Returns the count actually removed.
Source§impl Store
impl Store
Sourcepub fn mset(&self, pairs: &[(&[u8], &[u8])]) -> KevyResult<()>
pub fn mset(&self, pairs: &[(&[u8], &[u8])]) -> KevyResult<()>
MSET key value [key value ...] — set every pair atomically
per-key. Each pair is logged independently to its shard’s
AOF (no cross-shard atomic guarantee — a crash mid-call may
leave a prefix applied; matches Redis Cluster semantics).
Sourcepub fn mget(&self, keys: &[&[u8]]) -> KevyResult<Vec<Option<Vec<u8>>>>
pub fn mget(&self, keys: &[&[u8]]) -> KevyResult<Vec<Option<Vec<u8>>>>
MGET key [key ...] — return Some(value) per requested key
that’s present, None per absent / wrong-type.
Sourcepub fn keys(&self, pattern: Option<&[u8]>, limit: Option<usize>) -> Vec<Vec<u8>>
pub fn keys(&self, pattern: Option<&[u8]>, limit: Option<usize>) -> Vec<Vec<u8>>
KEYS pattern — glob-match every key in the keyspace
(across all shards). pattern = None matches everything.
limit = None is unbounded; otherwise bounds the TOTAL
returned across shards. Glob syntax matches Redis (* /
? / [abc] / escape).
Sourcepub fn getex(&self, key: &[u8], ttl: Duration) -> KevyResult<Option<Vec<u8>>>
pub fn getex(&self, key: &[u8], ttl: Duration) -> KevyResult<Option<Vec<u8>>>
GETEX key TTL — get the value and update the TTL atomically
(single lock cycle on the owning shard). Returns the value;
None when absent. AOF-logged as an absolute PEXPIREAT — a
relative frame re-anchors on every replay, handing the key its
full TTL back at each restart (the incident class the absolute
form exists to prevent; this was its last relative holdout).
Sourcepub fn sinter(&self, keys: &[&[u8]]) -> KevyResult<Vec<Vec<u8>>>
pub fn sinter(&self, keys: &[&[u8]]) -> KevyResult<Vec<Vec<u8>>>
SINTER key [key ...] — set intersection. Reads each key’s
members, computes the intersection in BTreeSet order
(sorted, no duplicates).
Sourcepub fn sunion(&self, keys: &[&[u8]]) -> KevyResult<Vec<Vec<u8>>>
pub fn sunion(&self, keys: &[&[u8]]) -> KevyResult<Vec<Vec<u8>>>
SUNION key [key ...] — set union over N sets.
Sourcepub fn sdiff(&self, keys: &[&[u8]]) -> KevyResult<Vec<Vec<u8>>>
pub fn sdiff(&self, keys: &[&[u8]]) -> KevyResult<Vec<Vec<u8>>>
SDIFF key [key ...] — keys[0] minus the union of every
subsequent set.
Sourcepub fn expireat(&self, key: &[u8], unix_secs: u64) -> KevyResult<bool>
pub fn expireat(&self, key: &[u8], unix_secs: u64) -> KevyResult<bool>
EXPIREAT key unix_secs — schedule expiry for the given
absolute UNIX wall-clock time. Returns true when the key
existed and the deadline was set; false when absent.
Sourcepub fn pexpireat(&self, key: &[u8], unix_ms: u64) -> KevyResult<bool>
pub fn pexpireat(&self, key: &[u8], unix_ms: u64) -> KevyResult<bool>
PEXPIREAT key unix_ms — same as expireat but in
milliseconds.
Sourcepub fn pexpire(&self, key: &[u8], ms: u64) -> KevyResult<bool>
pub fn pexpire(&self, key: &[u8], ms: u64) -> KevyResult<bool>
PEXPIRE key ms — relative TTL in milliseconds. (expire
takes Duration; this is the integer-ms variant matching
the Redis wire command.)
Sourcepub fn hincrbyfloat(
&self,
key: &[u8],
field: &[u8],
delta: f64,
) -> KevyResult<f64>
pub fn hincrbyfloat( &self, key: &[u8], field: &[u8], delta: f64, ) -> KevyResult<f64>
HINCRBYFLOAT key field delta — atomic float increment of a
hash field. Returns the post-increment value. Errors on
NotFloat when the field is present but not parseable.
Sourcepub fn linsert(
&self,
key: &[u8],
before: bool,
pivot: &[u8],
value: &[u8],
) -> KevyResult<i64>
pub fn linsert( &self, key: &[u8], before: bool, pivot: &[u8], value: &[u8], ) -> KevyResult<i64>
LINSERT key BEFORE|AFTER pivot value — insert value before
or after the first occurrence of pivot in the list. Returns:
Ok(new_len)on success (>= 1);Ok(0)whenkeydoes not exist;Ok(-1)whenpivotwas not found in the list.
before = true matches Redis LINSERT … BEFORE, false
matches LINSERT … AFTER.
Sourcepub fn ping_ns(&self) -> u128
pub fn ping_ns(&self) -> u128
Store::ping_us() — return the round-trip duration of a
shard-0 read-lock acquire + release in nanoseconds, for
perfgate observability. Always returns immediately; the
duration reflects current shard-0 contention (= shorter when
idle, longer when many readers/writers compete).
Source§impl Store
impl Store
Sourcepub fn info_prefix(&self, prefix: &[u8]) -> PrefixInfo
pub fn info_prefix(&self, prefix: &[u8]) -> PrefixInfo
info_prefix: count live keys (and TTL’d keys) under a
byte prefix, across all shards. O(keyspace) — an ops/stats
call, not a hot-path primitive.
Sourcepub fn feed_shards(&self) -> usize
pub fn feed_shards(&self) -> usize
Number of independent change streams this store exposes (the embedded write path serializes all shards: always 1).
Sourcepub fn changes_tail(&self) -> Result<(u64, u64), FeedError>
pub fn changes_tail(&self) -> Result<(u64, u64), FeedError>
The current (generation, next_offset) cursor — where a
consumer starting fresh (or resuming after a rebuild) begins.
Sourcepub fn changes_since(
&self,
generation: u64,
offset: u64,
limit: usize,
prefixes: &[&[u8]],
) -> Result<ChangeBatch, FeedError>
pub fn changes_since( &self, generation: u64, offset: u64, limit: usize, prefixes: &[&[u8]], ) -> Result<ChangeBatch, FeedError>
Deliver up to limit changes at cursor (generation, offset),
optionally prefix-filtered (fail-open on multi-key verbs; the
filter never affects the returned cursor). At-least-once: after
a Resync rebuild, frames already applied may be seen again.
Source§impl Store
impl Store
Sourcepub fn blpop(
&self,
keys: &[&[u8]],
timeout: Option<Duration>,
) -> KevyResult<Option<(Vec<u8>, Vec<u8>)>>
pub fn blpop( &self, keys: &[&[u8]], timeout: Option<Duration>, ) -> KevyResult<Option<(Vec<u8>, Vec<u8>)>>
BLPOP — block until one of keys has a head element (checked
in argument order each round) or timeout passes (None =
wait forever). Returns (key, value).
Source§impl Store
impl Store
Sourcepub fn hexpire(
&self,
key: &[u8],
fields: &[&[u8]],
ttl: Duration,
cond: HExpireCond,
) -> KevyResult<Vec<HExpireCode>>
pub fn hexpire( &self, key: &[u8], fields: &[&[u8]], ttl: Duration, cond: HExpireCond, ) -> KevyResult<Vec<HExpireCode>>
HEXPIRE — set a relative per-field TTL. One Redis code per
field (-2 missing, 0 condition failed, 1 set, 2 deleted).
Sourcepub fn hpexpire_at(
&self,
key: &[u8],
fields: &[&[u8]],
deadline_ms: u64,
cond: HExpireCond,
) -> KevyResult<Vec<HExpireCode>>
pub fn hpexpire_at( &self, key: &[u8], fields: &[&[u8]], deadline_ms: u64, cond: HExpireCond, ) -> KevyResult<Vec<HExpireCode>>
HPEXPIREAT — absolute unix-ms per-field deadline (the
canonical form; also what the AOF carries).
Sourcepub fn httl(&self, key: &[u8], fields: &[&[u8]]) -> KevyResult<Vec<i64>>
pub fn httl(&self, key: &[u8], fields: &[&[u8]]) -> KevyResult<Vec<i64>>
HTTL — remaining seconds per field (-2 missing, -1 no TTL).
Rounded to the nearest second, as the wire verb and Redis both do. For
the unrounded value use [Db::hpttl]. Before 4.0 this method carried the
HTTL name and returned milliseconds, which is a thousand-fold error
waiting to happen in any caller that trusted the name.
Sourcepub fn hpttl(&self, key: &[u8], fields: &[&[u8]]) -> KevyResult<Vec<i64>>
pub fn hpttl(&self, key: &[u8], fields: &[&[u8]]) -> KevyResult<Vec<i64>>
HPTTL — remaining milliseconds per field (-2 missing, -1 no
TTL).
Sourcepub fn hpersist(
&self,
key: &[u8],
fields: &[&[u8]],
) -> KevyResult<Vec<HExpireCode>>
pub fn hpersist( &self, key: &[u8], fields: &[&[u8]], ) -> KevyResult<Vec<HExpireCode>>
HPERSIST — clear per-field TTLs (-2 missing, -1 had no
TTL, 1 cleared).
Source§impl Store
impl Store
Sourcepub fn idx_match_with(
&self,
name: &[u8],
query: &[u8],
limit: usize,
opts: MatchOpts<'_>,
) -> KevyResult<Vec<(Vec<u8>, f64, Vec<(Vec<u8>, Vec<(u32, u32)>)>)>>
pub fn idx_match_with( &self, name: &[u8], query: &[u8], limit: usize, opts: MatchOpts<'_>, ) -> KevyResult<Vec<(Vec<u8>, f64, Vec<(Vec<u8>, Vec<(u32, u32)>)>)>>
Self::idx_match with every optional clause: highlight spans,
a typo budget, an offset, and a field scope.
A scoped query is a field-scoped BM25 — frequency, length and document frequency all come from the named fields alone — so naming a field the index does not declare is an error rather than an empty result that would look like a working query.
Sourcepub fn idx_match_faceted(
&self,
name: &[u8],
query: &[u8],
limit: usize,
opts: MatchOpts<'_>,
) -> KevyResult<MatchPage>
pub fn idx_match_faceted( &self, name: &[u8], query: &[u8], limit: usize, opts: MatchOpts<'_>, ) -> KevyResult<MatchPage>
Self::idx_match_with, additionally counting the values of the
FACET fields over the whole match set — not just the page, which
is why the counts cannot be derived from the hits.
Source§impl Store
impl Store
Sourcepub fn idx_create_with_values(
&self,
name: &[u8],
prefix: &[u8],
field: &[u8],
ty: ValType,
kind: IndexKind,
values: &[(&[u8], ValType)],
) -> KevyResult<()>
pub fn idx_create_with_values( &self, name: &[u8], prefix: &[u8], field: &[u8], ty: ValType, kind: IndexKind, values: &[(&[u8], ValType)], ) -> KevyResult<()>
Store::idx_create with declared stored VALUES columns —
the scalar kinds’ G1 capability (the catalog refuses the
declaration on kinds that carry no stored-value column).
Sourcepub fn idx_query_claused(
&self,
name: &[u8],
min: &IndexValue,
max: &IndexValue,
cursor: Option<&Cursor>,
limit: usize,
opts: ScalarQueryOpts<'_>,
) -> KevyResult<ScalarPage>
pub fn idx_query_claused( &self, name: &[u8], min: &IndexValue, max: &IndexValue, cursor: Option<&Cursor>, limit: usize, opts: ScalarQueryOpts<'_>, ) -> KevyResult<ScalarPage>
Store::idx_query with the stored-value clauses — the scalar
twin of Store::idx_match_faceted’s clause surface. Semantics
are the wire’s: each shard selects with the clauses applied, the
union merges in the page’s own order, DISTINCT re-collapses,
OFFSET drains after the merge, facet counts sum by coerced
identity. Only FILTER (with no other clause) is cursor-paged.
Source§impl Store
impl Store
Sourcepub fn idx_create_text(
&self,
name: &[u8],
prefix: &[u8],
fields: &[(&[u8], f32)],
positions: bool,
values: &[(&[u8], ValType)],
) -> KevyResult<()>
pub fn idx_create_text( &self, name: &[u8], prefix: &[u8], fields: &[(&[u8], f32)], positions: bool, values: &[(&[u8], ValType)], ) -> KevyResult<()>
A multi-field text index over several weighted hash fields — what
the wire creates with ON FIELDS f1 f2 WEIGHTS 2 1, and what IN
scopes to. A weight scales that field’s term frequencies; 1.0 is
neutral.
positions records token offsets so phrase queries can verify
adjacency, at the cost of the positional side-channel’s memory.
values names hash fields stored per document with the type their
bytes compare as — what FILTER reads. An index that never
filters declares none.
Source§impl Store
impl Store
Sourcepub fn idx_create(
&self,
name: &[u8],
prefix: &[u8],
field: &[u8],
ty: ValType,
kind: IndexKind,
) -> KevyResult<()>
pub fn idx_create( &self, name: &[u8], prefix: &[u8], field: &[u8], ty: ValType, kind: IndexKind, ) -> KevyResult<()>
IDX.CREATE equivalent. Builds synchronously; errors on
duplicate name / cap / bad spec.
Sourcepub fn idx_create_ann(
&self,
name: &[u8],
prefix: &[u8],
field: &[u8],
params: AnnSpec,
) -> KevyResult<()>
pub fn idx_create_ann( &self, name: &[u8], prefix: &[u8], field: &[u8], params: AnnSpec, ) -> KevyResult<()>
Declare an ANN index (KIND ann, TYPE vector). params.m
/ params.ef of 0 select the defaults (16 / 200).
Sourcepub fn idx_drop(&self, name: &[u8]) -> bool
pub fn idx_drop(&self, name: &[u8]) -> bool
IDX.DROP equivalent; false if absent. On a hit the catalog
sidecar is re-persisted so the drop survives restart.
Sourcepub fn idx_query(
&self,
name: &[u8],
min: &IndexValue,
max: &IndexValue,
cursor: Option<&Cursor>,
limit: usize,
) -> KevyResult<IndexPage>
pub fn idx_query( &self, name: &[u8], min: &IndexValue, max: &IndexValue, cursor: Option<&Cursor>, limit: usize, ) -> KevyResult<IndexPage>
Range / EQ query with cursor pagination: merged across shards
in (value, key) order. cursor = None starts; the returned
cursor resumes exclusively.
Sourcepub fn idx_count(
&self,
name: &[u8],
min: &IndexValue,
max: &IndexValue,
) -> KevyResult<u64>
pub fn idx_count( &self, name: &[u8], min: &IndexValue, max: &IndexValue, ) -> KevyResult<u64>
Count without materializing keys.
Sourcepub fn idx_stats(&self, name: &[u8]) -> KevyResult<SegmentStats>
pub fn idx_stats(&self, name: &[u8]) -> KevyResult<SegmentStats>
Summed segment stats (entries / bytes / coerce failures / unique-fence duplicates).
Sourcepub fn idx_list(&self) -> Vec<(Vec<u8>, Vec<u8>, IndexKind)>
pub fn idx_list(&self) -> Vec<(Vec<u8>, Vec<u8>, IndexKind)>
Declared indexes (name, prefix, kind), declaration order.
Sourcepub fn idx_match(
&self,
name: &[u8],
query: &[u8],
limit: usize,
) -> KevyResult<Vec<(Vec<u8>, f64)>>
pub fn idx_match( &self, name: &[u8], query: &[u8], limit: usize, ) -> KevyResult<Vec<(Vec<u8>, f64)>>
MATCH — BM25-ranked hits merged across shards, scored against
global corpus statistics so a hit’s rank does not depend on
which shard it landed on (see docs/text-search.md).
Two query-time passes: the first sums each shard’s n_docs,
total_len and per-query-token df into one [CorpusStats]; the
second scores every shard against it. Only the query’s tokens’
df is aggregated, not a whole-corpus table — the query narrows it.
Sourcepub fn idx_create_agg(
&self,
name: &[u8],
prefix: &[u8],
field: &[u8],
ty: ValType,
group_by: &[u8],
) -> KevyResult<()>
pub fn idx_create_agg( &self, name: &[u8], prefix: &[u8], field: &[u8], ty: ValType, group_by: &[u8], ) -> KevyResult<()>
Declare an aggregate index (KIND agg — write-time GROUP
BY). ty must be numeric.
Sourcepub fn idx_group(&self, name: &[u8], group: &[u8]) -> KevyResult<GroupStats>
pub fn idx_group(&self, name: &[u8], group: &[u8]) -> KevyResult<GroupStats>
One group’s merged stats across shards.
Sourcepub fn idx_groups(
&self,
name: &[u8],
by: AggBy,
limit: usize,
) -> KevyResult<Vec<(Vec<u8>, GroupStats)>>
pub fn idx_groups( &self, name: &[u8], by: AggBy, limit: usize, ) -> KevyResult<Vec<(Vec<u8>, GroupStats)>>
Top groups merged + ranked across shards.
Source§impl Store
impl Store
Sourcepub fn table_declare(&self, spec: TableSpec) -> KevyResult<()>
pub fn table_declare(&self, spec: TableSpec) -> KevyResult<()>
TABLE.DECLARE equivalent: admit the declaration, then build
every compiled index synchronously. Atomic against catalog
errors: names are dry-run against a catalog clone first, so a
collision installs nothing.
Sourcepub fn table_ensure(&self, spec: TableSpec) -> KevyResult<TableEnsure>
pub fn table_ensure(&self, spec: TableSpec) -> KevyResult<TableEnsure>
TABLE.ENSURE equivalent — the boot verb.
The dogfood report’s F8.2: declaring at boot is the steady
state, and plain table_declare punishes it — a re-declare is
an error, so the obvious code (declare, log the error at debug)
keeps running against whatever shape the first boot declared,
forever, silently. ensure gives the boot path its true verb:
an identical spec is a no-op success, a changed spec is a named
refusal carrying what changed — never a silent rebuild, because
a rebuild is a full backfill and must be asked for by name
(Self::table_replace).
Sourcepub fn table_replace(&self, spec: TableSpec) -> KevyResult<()>
pub fn table_replace(&self, spec: TableSpec) -> KevyResult<()>
TABLE.REPLACE equivalent — drop and redeclare, rebuilding
every compiled index from the rows. Explicitly named because it
is a full backfill: the cost is asked for, not implied. The new
spec is compiled (and therefore validated) before the old
table is dropped, so a bad replacement leaves the old one
standing.
Sourcepub fn table_drop(&self, name: &[u8]) -> bool
pub fn table_drop(&self, name: &[u8]) -> bool
TABLE.DROP equivalent — drops the table AND its compiled
indexes; false if absent.
Sourcepub fn table_list(&self) -> Vec<TableSpec>
pub fn table_list(&self) -> Vec<TableSpec>
Declared tables, declaration order.
Sourcepub fn table_verify(
&self,
name: &[u8],
) -> KevyResult<(Vec<(Vec<u8>, [u64; 6])>, [u64; 2])>
👎Deprecated since 4.1.0: use table_verify_report, whose fields are named
pub fn table_verify( &self, name: &[u8], ) -> KevyResult<(Vec<(Vec<u8>, [u64; 6])>, [u64; 2])>
use table_verify_report, whose fields are named
TABLE.VERIFY equivalent: each compiled index’s full drift
recheck (the IDX.VERIFY discipline — composites re-derive their
byte encoding) plus a bounded column-type spot check, both
through the no-promote peek.
Sourcepub fn table_verify_report(&self, name: &[u8]) -> KevyResult<TableVerify>
pub fn table_verify_report(&self, name: &[u8]) -> KevyResult<TableVerify>
TABLE.VERIFY, with every counter named and its time semantics
documented on the field (see IndexVerify).
Source§impl Store
impl Store
Sourcepub fn view_create(
&self,
name: &[u8],
tree: Tree,
order_by: &[u8],
desc: bool,
mode: ViewMode,
) -> KevyResult<()>
pub fn view_create( &self, name: &[u8], tree: Tree, order_by: &[u8], desc: bool, mode: ViewMode, ) -> KevyResult<()>
Declare a view (typed tree; via is not supported embedded —
read fields in-process). Builds synchronously.
Sourcepub fn view_query(
&self,
name: &[u8],
after: Option<&(IndexValue, Vec<u8>)>,
limit: usize,
) -> KevyResult<ViewPage>
pub fn view_query( &self, name: &[u8], after: Option<&(IndexValue, Vec<u8>)>, limit: usize, ) -> KevyResult<ViewPage>
Ordered page across shards (after resumes exclusively; DESC
views page from the large end).
Sourcepub fn view_list(&self) -> Vec<(Vec<u8>, ViewMode, usize)>
pub fn view_list(&self) -> Vec<(Vec<u8>, ViewMode, usize)>
Declared views (name, mode, leaves).
Sourcepub fn view_count(&self, name: &[u8]) -> KevyResult<u64>
pub fn view_count(&self, name: &[u8]) -> KevyResult<u64>
Summed member count across shards.
Source§impl Store
impl Store
Sourcepub fn zinterstore(
&self,
dst: &[u8],
keys: &[&[u8]],
weights: Option<&[f64]>,
aggregate: ZAggregate,
) -> KevyResult<usize>
pub fn zinterstore( &self, dst: &[u8], keys: &[&[u8]], weights: Option<&[f64]>, aggregate: ZAggregate, ) -> KevyResult<usize>
ZINTERSTORE dst keys… [WEIGHTS …] [AGGREGATE SUM|MIN|MAX] —
returns the stored cardinality.
Sourcepub fn zunionstore(
&self,
dst: &[u8],
keys: &[&[u8]],
weights: Option<&[f64]>,
aggregate: ZAggregate,
) -> KevyResult<usize>
pub fn zunionstore( &self, dst: &[u8], keys: &[&[u8]], weights: Option<&[f64]>, aggregate: ZAggregate, ) -> KevyResult<usize>
ZUNIONSTORE dst keys… [WEIGHTS …] [AGGREGATE …].
Sourcepub fn zdiffstore(&self, dst: &[u8], keys: &[&[u8]]) -> KevyResult<usize>
pub fn zdiffstore(&self, dst: &[u8], keys: &[&[u8]]) -> KevyResult<usize>
ZDIFFSTORE dst keys… (no weights/aggregate — Redis 6.2).
Sourcepub fn zintercard(&self, keys: &[&[u8]], limit: usize) -> KevyResult<usize>
pub fn zintercard(&self, keys: &[&[u8]], limit: usize) -> KevyResult<usize>
ZINTERCARD keys… [LIMIT n] — limit = 0 means unlimited.
Sourcepub fn sinterstore(&self, dst: &[u8], keys: &[&[u8]]) -> KevyResult<usize>
pub fn sinterstore(&self, dst: &[u8], keys: &[&[u8]]) -> KevyResult<usize>
SINTERSTORE dst keys… — set-algebra store form (members only).
Sourcepub fn sunionstore(&self, dst: &[u8], keys: &[&[u8]]) -> KevyResult<usize>
pub fn sunionstore(&self, dst: &[u8], keys: &[&[u8]]) -> KevyResult<usize>
SUNIONSTORE dst keys….
Sourcepub fn sdiffstore(&self, dst: &[u8], keys: &[&[u8]]) -> KevyResult<usize>
pub fn sdiffstore(&self, dst: &[u8], keys: &[&[u8]]) -> KevyResult<usize>
SDIFFSTORE dst keys….
Source§impl Store
impl Store
Sourcepub fn zadd_flags(
&self,
key: &[u8],
pairs: &[(f64, &[u8])],
flags: ZaddFlags,
) -> KevyResult<ZaddReport>
pub fn zadd_flags( &self, key: &[u8], pairs: &[(f64, &[u8])], flags: ZaddFlags, ) -> KevyResult<ZaddReport>
Flags-aware ZADD. See ZaddFlags; read
ZaddReport::changed for the CH reply shape. The
monotonic-heal idiom is zadd_flags(k, pairs, ZaddFlags { gt: true, ..Default::default() }).
Source§impl Store
impl Store
Sourcepub fn scan(
&self,
cursor: u64,
pattern: Option<&[u8]>,
count: usize,
) -> (u64, Vec<Vec<u8>>)
pub fn scan( &self, cursor: u64, pattern: Option<&[u8]>, count: usize, ) -> (u64, Vec<Vec<u8>>)
SCAN cursor [MATCH pattern] [COUNT n] — return up to count
keys, plus the next cursor. cursor = 0 starts the walk;
next_cursor = 0 means the walk completed.
count is the page size; pass usize::MAX to drain in one
call.
Sourcepub fn keys_iter(&self, pattern: Option<&[u8]>) -> IntoIter<Vec<u8>>
pub fn keys_iter(&self, pattern: Option<&[u8]>) -> IntoIter<Vec<u8>>
Iterator wrapper around Self::scan — emits every matching
key as a Vec<u8>. Drains the keyspace in one snapshot at
construction time; matches Rust idioms.
Sourcepub fn hscan(
&self,
key: &[u8],
cursor: u64,
count: usize,
) -> KevyResult<(u64, Vec<(Vec<u8>, Vec<u8>)>)>
pub fn hscan( &self, key: &[u8], cursor: u64, count: usize, ) -> KevyResult<(u64, Vec<(Vec<u8>, Vec<u8>)>)>
HSCAN key cursor [COUNT n] — return up to count (field, value) pairs from the hash at key, plus the next cursor.
cursor = 0 starts; next_cursor = 0 means complete.
Sourcepub fn hash_iter(&self, key: &[u8]) -> KevyResult<IntoIter<(Vec<u8>, Vec<u8>)>>
pub fn hash_iter(&self, key: &[u8]) -> KevyResult<IntoIter<(Vec<u8>, Vec<u8>)>>
Iterator wrapper around Self::hscan.
Sourcepub fn zscan(
&self,
key: &[u8],
cursor: u64,
count: usize,
) -> KevyResult<(u64, Vec<(Vec<u8>, f64)>)>
pub fn zscan( &self, key: &[u8], cursor: u64, count: usize, ) -> KevyResult<(u64, Vec<(Vec<u8>, f64)>)>
ZSCAN key cursor [COUNT n] — return up to count (member, score) pairs from the sorted set at key, in ascending score
order, plus the next cursor.
Sourcepub fn zset_iter(&self, key: &[u8]) -> KevyResult<IntoIter<(Vec<u8>, f64)>>
pub fn zset_iter(&self, key: &[u8]) -> KevyResult<IntoIter<(Vec<u8>, f64)>>
Iterator wrapper around Self::zscan.
Source§impl Store
impl Store
Sourcepub fn writer_addr(&self) -> Option<SocketAddr>
pub fn writer_addr(&self) -> Option<SocketAddr>
The embed-writer replication listener’s actually-bound address,
when this store was opened with
Config::with_embed_writer.
Open with port 0 to let the OS pick a free port and read the
real one back here — the race-free way to run an ephemeral
writer (tests, sidecars, one process per scope).
Source§impl Store
impl Store
Sourcepub fn open(config: Config) -> KevyResult<Self>
pub fn open(config: Config) -> KevyResult<Self>
Open an embedded keyspace per config.
- Pure in-memory when
config.data_dirisNone. - With persistence: each shard loads its snapshot then replays its AOF
(
config.shards > 1re-shards a legacy single AOF on first open). - Spawns a background TTL reaper thread when
config.ttl_reaper == Background(the default). - When
config.replica_upstream = Some("host:port"), spawns a background thread that streams replication frames from the named primary and applies them to this store; local writes are rejected withREADONLY(seeSelf::open_replica).
Sourcepub fn open_report(&self) -> &OpenReport
pub fn open_report(&self) -> &OpenReport
What this open’s replay restored — and, crucially, what it could
NOT: dropped_bytes > 0 or corrupt means the store recovered
less than the files held (the dropped region was quarantined). Turn
this into a startup health check / alert — the machine-readable
twin of the boot WARN line.
Sourcepub fn dispatch_readonly(&self, argv: &[Vec<u8>], out: &mut Vec<u8>)
pub fn dispatch_readonly(&self, argv: &[Vec<u8>], out: &mut Vec<u8>)
Answer one RESP request against this store using the SAME
read-only verb whitelist the embedded RESP listener serves
(Config::with_resp_listener). The reply is appended to out
as raw RESP bytes; write verbs answer -ERR like the listener
does. This is the programmatic face of the listener — tooling
(e.g. kevy-cli --embed) inspects a store without a socket.
Sourcepub fn open_replica(upstream: impl Into<String>) -> KevyResult<Self>
pub fn open_replica(upstream: impl Into<String>) -> KevyResult<Self>
Convenience constructor for an embed-as-read-replica store
streaming writes from upstream ("host:port" of a kevy
server’s replication listener).
The replica:
- has its local AOF force-disabled (the upstream stream is the source of truth; replica AOF would diverge and double-apply on restart);
- rejects every local write with a
READONLYio::Error(you can still call read APIs concurrently); - reconnects with exponential backoff on disconnect, resuming from the last applied offset;
- gets a process-unique
replica_idso an open / drop / reopen cycle within the primary’s reconnect window does not look like the same slot from the primary’s POV (which would evict backlog frames the new embed still needs from offset 0). Override viaConfig::with_replica_idwhen you specifically want the slot to be re-claimed across restarts.
For full builder control (custom replica id, backoff bounds,
snapshot dir, etc.) use Self::open with
Config::with_replica_upstream + the related setters
instead.
Sourcepub fn is_replica(&self) -> bool
pub fn is_replica(&self) -> bool
true when this store was opened against a replication
upstream — local writes are rejected with READONLY.
Sourcepub fn shutdown(&self) -> Result<()>
pub fn shutdown(&self) -> Result<()>
Flush every shard’s AOF to disk (a real fsync), write the feed
continuity marker, then refuse every later write (they fail with
KevyError::Closed; reads stay available). Idempotent and
clone-safe: any clone’s shutdown gates them all, so a signal
handler’s teardown is two deterministic lines —
store.shutdown()?; std::process::exit(0) — instead of praying
every task’s Arc<Store> drops in time. Writes racing the call
may land after the fsync; writes issued after it returns cannot.
Sourcepub fn set_replica_upstream(
&self,
new_upstream: impl Into<String>,
) -> KevyResult<()>
pub fn set_replica_upstream( &self, new_upstream: impl Into<String>, ) -> KevyResult<()>
Retarget this replica at a new primary URL (host:port). The
runner picks up the change on its next connect — which is
forced now by shutdowning the current socket clone, so the
retarget lands within Config::replica_reconnect_min (default
100 ms) of this call.
Returns Err with ErrorKind::InvalidInput when this store is
not a replica (no upstream was configured at open). Application
code typically drives this from a kevy-elect failover signal —
see docs/cluster.md.
kevy-embedded itself stays elect-protocol-agnostic; the
integration glue lives in the application.
Sourcepub fn config(&self) -> &Config
pub fn config(&self) -> &Config
The active config (a clone — modifying it has no effect on the
running store). Useful for introspection / INFO-style telemetry.
Sourcepub fn with<F, R>(&self, f: F) -> R
pub fn with<F, R>(&self, f: F) -> R
Run f against the underlying kevy_store::Store under its lock. Use
for direct access to methods this crate hasn’t wrapped. The closure can
mutate, but does not auto-log to the AOF — call Self::log yourself
if the mutation must survive a crash.
Sharded stores: this targets shard 0 only. Use Self::with_key
to reach the shard owning a specific key.
Sourcepub fn with_key<F, R>(&self, key: &[u8], f: F) -> R
pub fn with_key<F, R>(&self, key: &[u8], f: F) -> R
Like Self::with but targets the shard that owns key.
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>>
KEYS / SCAN-glob across every shard — the cross-shard
replacement for with(|s| s.collect_keys(pat, lim)), which only sees
shard 0 once sharding is on. Behaves identically to with(...) when
shard_count() == 1. limit bounds the total returned across shards.
Takes a read lock per shard (concurrent-safe).
Sourcepub fn for_each_shard<F: FnMut(&mut Store)>(&self, f: F)
pub fn for_each_shard<F: FnMut(&mut Store)>(&self, f: F)
Run f against each shard’s underlying kevy_store::Store (in
shard-index order) — the cross-shard escape hatch. The caller assembles
the merged result. Pairs with Self::shard_count. For a single key,
prefer Self::with_key; for a glob scan, prefer Self::collect_keys.
Sourcepub fn shard_count(&self) -> usize
pub fn shard_count(&self) -> usize
Number of keyspace shards (== Config::shards).
Sourcepub fn log(&self, parts: &[&[u8]]) -> KevyResult<()>
pub fn log(&self, parts: &[&[u8]]) -> KevyResult<()>
Append a raw RESP-frame argument list to the shard owning its key’s AOF. No-op when persistence is disabled.
Sourcepub fn tick(&self) -> ExpireStats
pub fn tick(&self) -> ExpireStats
Run one TTL-reaper tick across every shard. Required call cadence in
Manual mode (~10×/s to match Redis hz=10). Returns the summed stats.
Sourcepub fn tier_counters(&self) -> (u64, u64)
pub fn tier_counters(&self) -> (u64, u64)
Tiering counters summed across shards:
(demotions_total, promotions_total) — the minimal counter pair
(the full INFO gauge set is tier_info). Zeros when tiering is off.
Source§impl Store
impl Store
Sourcepub fn downgradeable_to_v3(&self) -> Option<bool>
pub fn downgradeable_to_v3(&self) -> Option<bool>
Whether a 3.x binary could still open this data directory —
the downgrade window UPGRADING.md describes, as a readable
state instead of an assumption.
Some(true): every shard’s AOF still speaks KEVYAOF1, so
downgrading is a binary swap back. Some(false): at least one
shard has upgraded to v2 (a rewrite ran), so a downgrade needs a
keyspace export through a client. None: no AOF is configured —
the question has no meaning for a memory-only store.
From an embedder’s dogfood report: their doctor
command exists to tell users “where you are and what to do
next”, and this state was pub(crate) — so their CHANGELOG had
to declare the window closed unconditionally when it was open,
observable, and per-directory.
Sourcepub fn fsync_aof(&self) -> KevyResult<()>
pub fn fsync_aof(&self) -> KevyResult<()>
Durability barrier: flush + fdatasync every shard’s
AOF now, regardless of the configured appendfsync policy. On
Ok(()), every write acknowledged before this call is on
stable storage. The EverySec serving-store idiom:
store.atomic(|c| { /* critical write */ Ok(()) })?;
store.fsync_aof()?; // durable-on-ack for THIS block onlyCost: one fdatasync per dirty shard; a no-op on clean shards.
Under appendfsync = always it is a no-op (already durable).
Sourcepub fn rewrite_aof(&self) -> KevyResult<Option<RewriteStats>>
pub fn rewrite_aof(&self) -> KevyResult<Option<RewriteStats>>
BGREWRITEAOF: rebuild every shard’s AOF from current state.
Synchronous (despite the RESP name). Returns the summed stats
(None if persistence is off / no shard rewrote). Shards mid
rewrite are skipped. Emits KevyMetric::Rewrite per shard.
Sourcepub fn apply_frame(&self, args: &Argv)
pub fn apply_frame(&self, args: &Argv)
Apply one AOF-format command frame directly to the keyspace — the programmatic face of AOF replay, for hosts that store the log themselves (targets without a filesystem, where the embedding host reads the log back and feeds it in frame by frame on open).
Speaks the same verb set Store::open replays from an on-disk
AOF; unknown verbs are skipped (forward compatibility with logs
written by a newer kevy). Keyed verbs route to the owning shard;
FLUSHALL/FLUSHDB reach every shard. The frame is not
re-appended to any AOF — this is the read-back half of the pump,
so re-logging would double-apply on the next replay.
Sourcepub fn dump_aof_buf(&self) -> Vec<u8> ⓘ
pub fn dump_aof_buf(&self) -> Vec<u8> ⓘ
Serialize the whole keyspace into an in-memory compacted AOF image
(magic header + one command stream per key — the same bytes an
AOF rewrite puts on disk). The write half of host-mediated
persistence: hosts without a filesystem hand this buffer to their
own storage, replacing the accumulated append log, and feed it
back through Self::apply_frame on the next open.
Each shard is frozen copy-on-write and serialized off-lock, so concurrent readers and writers on other shards are not blocked for the duration of the dump.
Sourcepub fn save_snapshot(&self) -> KevyResult<bool>
pub fn save_snapshot(&self) -> KevyResult<bool>
Snapshot every shard to its dump-{i}.rdb, atomically. Ok(false)
when persistence is disabled.