pub struct Store { /* private fields */ }Expand description
The embedded keyspace.
Store is Clone (since v1.1.0). 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 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]) -> Result<bool>
pub fn set(&self, key: &[u8], value: &[u8]) -> Result<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,
) -> Result<bool>
pub fn set_with_ttl( &self, key: &[u8], value: &[u8], ttl: Duration, ) -> Result<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 (INC-2026-06-09).
Sourcepub fn get(&self, key: &[u8]) -> Result<Option<Vec<u8>>>
pub fn get(&self, key: &[u8]) -> Result<Option<Vec<u8>>>
GET key — Some(bytes) on hit, None on miss or expired.
With eviction off (maxmemory == 0, the default) this takes the read
lock and a non-mutating store lookup, so concurrent readers scale across
cores — the path a read-heavy embed cache lives on. With eviction on it
falls back to the exclusive lock + mutating get so each access still
stamps the LRU clock.
Sourcepub fn del(&self, keys: &[&[u8]]) -> Result<usize>
pub fn del(&self, keys: &[&[u8]]) -> Result<usize>
DEL key1 [key2 ...]. Returns the count of keys actually removed.
Keys fan out to their owning shards.
Sourcepub fn exists(&self, keys: &[&[u8]]) -> Result<usize>
pub fn exists(&self, keys: &[&[u8]]) -> Result<usize>
EXISTS key1 [key2 ...]. Count of existing keys (duplicates counted
multiple times, matching Redis).
Sourcepub fn incr_by(&self, key: &[u8], delta: i64) -> Result<i64>
pub fn incr_by(&self, key: &[u8], delta: i64) -> Result<i64>
INCRBY key delta. Negative delta does DECR-style work.
Sourcepub fn expire(&self, key: &[u8], ttl: Duration) -> Result<bool>
pub fn expire(&self, key: &[u8], ttl: Duration) -> Result<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]) -> Result<bool>
pub fn persist(&self, key: &[u8]) -> Result<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 flushall(&self) -> Result<()>
pub fn flushall(&self) -> Result<()>
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 flush(&self) -> Result<()>
👎Deprecated since 1.2.0: renamed to flushall: flush collides with Write::flush (sync-to-disk); this WIPES the store
pub fn flush(&self) -> Result<()>
renamed to flushall: flush collides with Write::flush (sync-to-disk); this WIPES the store
Deprecated alias for Self::flushall. The old name read like
Write::flush (sync-to-disk) but actually WIPES the store — a
data-loss footgun.
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.
Sourcepub fn used_memory(&self) -> u64
pub fn used_memory(&self) -> u64
Live used_memory estimate (summed across shards).
Sourcepub fn evictions_total(&self) -> u64
pub fn evictions_total(&self) -> u64
INFO-style counter: total keys evicted by maxmemory (all shards).
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).
Sourcepub fn hset(&self, key: &[u8], pairs: &[(&[u8], &[u8])]) -> Result<usize>
pub fn hset(&self, key: &[u8], pairs: &[(&[u8], &[u8])]) -> Result<usize>
HSET key field value [field value ...]. Returns count newly added.
Sourcepub fn hget(&self, key: &[u8], field: &[u8]) -> Result<Option<Vec<u8>>>
pub fn hget(&self, key: &[u8], field: &[u8]) -> Result<Option<Vec<u8>>>
HGET key field. None if absent.
Sourcepub fn hdel(&self, key: &[u8], fields: &[&[u8]]) -> Result<usize>
pub fn hdel(&self, key: &[u8], fields: &[&[u8]]) -> Result<usize>
HDEL key field [field ...]. Returns count actually removed.
Sourcepub fn lpush(&self, key: &[u8], values: &[&[u8]]) -> Result<usize>
pub fn lpush(&self, key: &[u8], values: &[&[u8]]) -> Result<usize>
LPUSH key value [value ...]. Returns the new list length.
Sourcepub fn rpush(&self, key: &[u8], values: &[&[u8]]) -> Result<usize>
pub fn rpush(&self, key: &[u8], values: &[&[u8]]) -> Result<usize>
RPUSH key value [value ...]. Returns the new list length.
Sourcepub fn lpop(&self, key: &[u8], count: usize) -> Result<Vec<Vec<u8>>>
pub fn lpop(&self, key: &[u8], count: usize) -> Result<Vec<Vec<u8>>>
LPOP key count. Returns popped values from the head.
Sourcepub fn rpop(&self, key: &[u8], count: usize) -> Result<Vec<Vec<u8>>>
pub fn rpop(&self, key: &[u8], count: usize) -> Result<Vec<Vec<u8>>>
RPOP key count. Symmetric to LPOP from the tail.
Sourcepub fn llen(&self, key: &[u8]) -> Result<usize>
pub fn llen(&self, key: &[u8]) -> Result<usize>
LLEN key. Length of the list at key; 0 if absent.
Sourcepub fn sadd(&self, key: &[u8], members: &[&[u8]]) -> Result<usize>
pub fn sadd(&self, key: &[u8], members: &[&[u8]]) -> Result<usize>
SADD key member [member ...]. Returns count newly added.
Sourcepub fn srem(&self, key: &[u8], members: &[&[u8]]) -> Result<usize>
pub fn srem(&self, key: &[u8], members: &[&[u8]]) -> Result<usize>
SREM key member [member ...]. Returns count actually removed.
Sourcepub fn smembers(&self, key: &[u8]) -> Result<Vec<Vec<u8>>>
pub fn smembers(&self, key: &[u8]) -> Result<Vec<Vec<u8>>>
SMEMBERS key. Order implementation-defined; empty if absent.
Sourcepub fn zadd(&self, key: &[u8], pairs: &[(f64, &[u8])]) -> Result<usize>
pub fn zadd(&self, key: &[u8], pairs: &[(f64, &[u8])]) -> Result<usize>
ZADD key score member [score member ...]. Returns count newly added.
Sourcepub fn zrem(&self, key: &[u8], members: &[&[u8]]) -> Result<usize>
pub fn zrem(&self, key: &[u8], members: &[&[u8]]) -> Result<usize>
ZREM key member [member ...]. Returns count actually removed.
Sourcepub fn zscore(&self, key: &[u8], member: &[u8]) -> Result<Option<f64>>
pub fn zscore(&self, key: &[u8], member: &[u8]) -> Result<Option<f64>>
ZSCORE key member. Some(score) if present.
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<'_>) -> Result<R>,
) -> Result<R>
pub fn atomic<R>( &self, body: impl FnOnce(&mut AtomicCtx<'_>) -> Result<R>, ) -> Result<R>
Run body as a single-shard atomic transaction. Inside the
closure every read sees previous writes; on closure return
the queued AOF writes are committed under one fsync.
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<'_>) -> Result<R>,
) -> Result<R>
pub fn atomic_all_shards<R>( &self, body: impl FnOnce(&mut AtomicAllShards<'_>) -> Result<R>, ) -> Result<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) -> Result<u8>
pub fn getbit(&self, key: &[u8], offset: u64) -> Result<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) -> Result<u8>
pub fn setbit(&self, key: &[u8], offset: u64, value: u8) -> Result<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)>) -> Result<u64>
pub fn bitcount(&self, key: &[u8], range: Option<(i64, i64)>) -> Result<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)>,
) -> Result<Option<u64>>
pub fn bitpos( &self, key: &[u8], bit: u8, range: Option<(i64, i64)>, ) -> Result<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) -> Result<Vec<u8>>
pub fn getrange(&self, key: &[u8], start: i64, end: i64) -> Result<Vec<u8>>
GETRANGE key start end — substring with Redis negative
indexing; [start, end] inclusive.
Sourcepub fn setrange(&self, key: &[u8], offset: u64, value: &[u8]) -> Result<usize>
pub fn setrange(&self, key: &[u8], offset: u64, value: &[u8]) -> Result<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]]) -> Result<usize>
pub fn bitop(&self, op: BitOp, dst: &[u8], srcs: &[&[u8]]) -> Result<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]) -> Result<bool>
pub fn setnx(&self, key: &[u8], value: &[u8]) -> Result<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) -> Result<f64>
pub fn incrbyfloat(&self, key: &[u8], delta: f64) -> Result<f64>
INCRBYFLOAT key delta — atomic float increment of a string
value. Returns the post-increment value parsed as f64.
Sourcepub fn decrby(&self, key: &[u8], delta: i64) -> Result<i64>
pub fn decrby(&self, key: &[u8], delta: i64) -> Result<i64>
DECRBY key delta — atomic decrement by delta.
Sourcepub fn strlen(&self, key: &[u8]) -> Result<usize>
pub fn strlen(&self, key: &[u8]) -> Result<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]) -> Result<usize>
pub fn append(&self, key: &[u8], data: &[u8]) -> Result<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) -> Result<bool>
pub fn copy(&self, src: &[u8], dst: &[u8], replace: bool) -> Result<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.
Source§impl Store
impl Store
Sourcepub fn prefix_digest(&self, prefix: &[u8]) -> (u64, u64)
pub fn prefix_digest(&self, prefix: &[u8]) -> (u64, u64)
v2.10 — 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]) -> Result<bool>
pub fn sismember(&self, key: &[u8], member: &[u8]) -> Result<bool>
SISMEMBER key member — true when member is in the set.
Sourcepub fn spop(&self, key: &[u8], count: usize) -> Result<Vec<Vec<u8>>>
pub fn spop(&self, key: &[u8], count: usize) -> Result<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) -> Result<Vec<Vec<u8>>>
pub fn srandmember(&self, key: &[u8], count: usize) -> Result<Vec<Vec<u8>>>
SRANDMEMBER key count — return up to count random members
without removing them.
Sourcepub fn zrank(&self, key: &[u8], member: &[u8]) -> Result<Option<usize>>
pub fn zrank(&self, key: &[u8], member: &[u8]) -> Result<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) -> Result<usize>
pub fn zcount(&self, key: &[u8], min: f64, max: f64) -> Result<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) -> Result<Vec<(Vec<u8>, f64)>>
pub fn zpopmin(&self, key: &[u8], count: usize) -> Result<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,
) -> Result<usize>
pub fn zremrangebyrank( &self, key: &[u8], start: i64, stop: i64, ) -> Result<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) -> Result<usize>
pub fn zremrangebyscore(&self, key: &[u8], min: f64, max: f64) -> Result<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,
) -> Result<Vec<(Vec<u8>, f64)>>
pub fn zrev_range_by_score( &self, key: &[u8], max: f64, min: f64, ) -> Result<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]) -> Result<()>
pub fn lset(&self, key: &[u8], idx: i64, value: &[u8]) -> Result<()>
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) -> Result<()>
pub fn ltrim(&self, key: &[u8], start: i64, stop: i64) -> Result<()>
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]) -> Result<Vec<(Vec<u8>, Vec<u8>)>>
pub fn hgetall(&self, key: &[u8]) -> Result<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]) -> Result<bool>
pub fn hexists(&self, key: &[u8], field: &[u8]) -> Result<bool>
HEXISTS key field — true when field is present.
Sourcepub fn hkeys(&self, key: &[u8]) -> Result<Vec<Vec<u8>>>
pub fn hkeys(&self, key: &[u8]) -> Result<Vec<Vec<u8>>>
HKEYS key — every field name in key’s hash.
Sourcepub fn hmget(
&self,
key: &[u8],
fields: &[&[u8]],
) -> Result<Vec<Option<Vec<u8>>>>
pub fn hmget( &self, key: &[u8], fields: &[&[u8]], ) -> Result<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) -> Result<i64>
pub fn hincrby(&self, key: &[u8], field: &[u8], delta: i64) -> Result<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,
) -> Result<Vec<(Vec<u8>, f64)>>
pub fn zrange( &self, key: &[u8], start: i64, stop: i64, ) -> Result<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,
) -> Result<Vec<(Vec<u8>, f64)>>
pub fn zrevrange( &self, key: &[u8], start: i64, stop: i64, ) -> Result<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,
) -> Result<Vec<(Vec<u8>, f64)>>
pub fn zrange_by_score( &self, key: &[u8], min: f64, max: f64, ) -> Result<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,
) -> Result<Vec<(Vec<u8>, f64)>>
pub fn zrange_by_score_excl( &self, key: &[u8], min: ScoreBound, max: ScoreBound, ) -> Result<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,
) -> Result<Vec<(Vec<u8>, f64)>>
pub fn zrange_by_score_limit( &self, key: &[u8], min: f64, max: f64, offset: usize, count: usize, ) -> Result<Vec<(Vec<u8>, f64)>>
ZRANGEBYSCORE key min max LIMIT offset count — score-range
read with pagination (v2.2; 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,
) -> Result<Vec<(Vec<u8>, f64)>>
pub fn zrevrange_by_score_limit( &self, key: &[u8], max: f64, min: f64, offset: usize, count: usize, ) -> Result<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,
) -> Result<Vec<(Vec<u8>, f64)>>
pub fn zpopmin_below( &self, key: &[u8], below: f64, count: usize, ) -> Result<Vec<(Vec<u8>, f64)>>
v2.4 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]) -> Result<f64>
pub fn zincrby(&self, key: &[u8], delta: f64, member: &[u8]) -> Result<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) -> Result<Vec<Vec<u8>>>
pub fn lrange(&self, key: &[u8], start: i64, stop: i64) -> Result<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) -> Result<Option<Vec<u8>>>
pub fn lindex(&self, key: &[u8], idx: i64) -> Result<Option<Vec<u8>>>
LINDEX key idx — element at index idx; None out of range.
Sourcepub fn lrem(&self, key: &[u8], count: i64, value: &[u8]) -> Result<usize>
pub fn lrem(&self, key: &[u8], count: i64, value: &[u8]) -> Result<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])]) -> Result<()>
pub fn mset(&self, pairs: &[(&[u8], &[u8])]) -> Result<()>
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]]) -> Result<Vec<Option<Vec<u8>>>>
pub fn mget(&self, keys: &[&[u8]]) -> Result<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) -> Result<Option<Vec<u8>>>
pub fn getex(&self, key: &[u8], ttl: Duration) -> Result<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 PEXPIRE.
Sourcepub fn sinter(&self, keys: &[&[u8]]) -> Result<Vec<Vec<u8>>>
pub fn sinter(&self, keys: &[&[u8]]) -> Result<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]]) -> Result<Vec<Vec<u8>>>
pub fn sunion(&self, keys: &[&[u8]]) -> Result<Vec<Vec<u8>>>
SUNION key [key ...] — set union over N sets.
Sourcepub fn sdiff(&self, keys: &[&[u8]]) -> Result<Vec<Vec<u8>>>
pub fn sdiff(&self, keys: &[&[u8]]) -> Result<Vec<Vec<u8>>>
SDIFF key [key ...] — keys[0] minus the union of every
subsequent set.
Sourcepub fn expireat(&self, key: &[u8], unix_secs: u64) -> Result<bool>
pub fn expireat(&self, key: &[u8], unix_secs: u64) -> Result<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) -> Result<bool>
pub fn pexpireat(&self, key: &[u8], unix_ms: u64) -> Result<bool>
PEXPIREAT key unix_ms — same as expireat but in
milliseconds.
Sourcepub fn pexpire(&self, key: &[u8], ms: u64) -> Result<bool>
pub fn pexpire(&self, key: &[u8], ms: u64) -> Result<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) -> Result<f64>
pub fn hincrbyfloat(&self, key: &[u8], field: &[u8], delta: f64) -> Result<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],
) -> Result<i64>
pub fn linsert( &self, key: &[u8], before: bool, pivot: &[u8], value: &[u8], ) -> Result<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
v2.3 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>,
) -> Result<Option<(Vec<u8>, Vec<u8>)>>
pub fn blpop( &self, keys: &[&[u8]], timeout: Option<Duration>, ) -> Result<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,
) -> Result<Vec<HExpireCode>>
pub fn hexpire( &self, key: &[u8], fields: &[&[u8]], ttl: Duration, cond: HExpireCond, ) -> Result<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,
) -> Result<Vec<HExpireCode>>
pub fn hpexpire_at( &self, key: &[u8], fields: &[&[u8]], deadline_ms: u64, cond: HExpireCond, ) -> Result<Vec<HExpireCode>>
HPEXPIREAT — absolute unix-ms per-field deadline (the
canonical form; also what the AOF carries).
Source§impl Store
impl Store
Sourcepub fn idx_create(
&self,
name: &[u8],
prefix: &[u8],
field: &[u8],
ty: ValType,
kind: IndexKind,
) -> Result<()>
pub fn idx_create( &self, name: &[u8], prefix: &[u8], field: &[u8], ty: ValType, kind: IndexKind, ) -> Result<()>
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,
) -> Result<()>
pub fn idx_create_ann( &self, name: &[u8], prefix: &[u8], field: &[u8], params: AnnSpec, ) -> Result<()>
v2.8: 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,
) -> Result<IndexPage>
pub fn idx_query( &self, name: &[u8], min: &IndexValue, max: &IndexValue, cursor: Option<&Cursor>, limit: usize, ) -> Result<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,
) -> Result<u64>
pub fn idx_count( &self, name: &[u8], min: &IndexValue, max: &IndexValue, ) -> Result<u64>
Count without materializing keys.
Sourcepub fn idx_stats(&self, name: &[u8]) -> Result<SegmentStats>
pub fn idx_stats(&self, name: &[u8]) -> Result<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,
) -> Result<Vec<(Vec<u8>, f64)>>
pub fn idx_match( &self, name: &[u8], query: &[u8], limit: usize, ) -> Result<Vec<(Vec<u8>, f64)>>
v2.7 MATCH — BM25-ranked hits merged across shards
(shard-local statistics; see docs/text-search.md).
Sourcepub fn idx_create_agg(
&self,
name: &[u8],
prefix: &[u8],
field: &[u8],
ty: ValType,
group_by: &[u8],
) -> Result<()>
pub fn idx_create_agg( &self, name: &[u8], prefix: &[u8], field: &[u8], ty: ValType, group_by: &[u8], ) -> Result<()>
v3.1: declare an aggregate index (KIND agg — write-time GROUP
BY). ty must be numeric.
Sourcepub fn idx_group(&self, name: &[u8], group: &[u8]) -> Result<GroupStats>
pub fn idx_group(&self, name: &[u8], group: &[u8]) -> Result<GroupStats>
v3.1: one group’s merged stats across shards.
Sourcepub fn idx_groups(
&self,
name: &[u8],
by: AggBy,
limit: usize,
) -> Result<Vec<(Vec<u8>, GroupStats)>>
pub fn idx_groups( &self, name: &[u8], by: AggBy, limit: usize, ) -> Result<Vec<(Vec<u8>, GroupStats)>>
v3.1: top groups merged + ranked across shards.
Source§impl Store
impl Store
Sourcepub fn view_create(
&self,
name: &[u8],
tree: Tree,
order_by: &[u8],
desc: bool,
mode: ViewMode,
) -> Result<()>
pub fn view_create( &self, name: &[u8], tree: Tree, order_by: &[u8], desc: bool, mode: ViewMode, ) -> Result<()>
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,
) -> Result<ViewPage>
pub fn view_query( &self, name: &[u8], after: Option<&(IndexValue, Vec<u8>)>, limit: usize, ) -> Result<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]) -> Result<u64>
pub fn view_count(&self, name: &[u8]) -> Result<u64>
Summed member count across shards.
Source§impl Store
impl Store
Sourcepub fn zinterstore(
&self,
dst: &[u8],
keys: &[&[u8]],
weights: Option<&[f64]>,
aggregate: ZAggregate,
) -> Result<usize>
pub fn zinterstore( &self, dst: &[u8], keys: &[&[u8]], weights: Option<&[f64]>, aggregate: ZAggregate, ) -> Result<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,
) -> Result<usize>
pub fn zunionstore( &self, dst: &[u8], keys: &[&[u8]], weights: Option<&[f64]>, aggregate: ZAggregate, ) -> Result<usize>
ZUNIONSTORE dst keys… [WEIGHTS …] [AGGREGATE …].
Sourcepub fn zdiffstore(&self, dst: &[u8], keys: &[&[u8]]) -> Result<usize>
pub fn zdiffstore(&self, dst: &[u8], keys: &[&[u8]]) -> Result<usize>
ZDIFFSTORE dst keys… (no weights/aggregate — Redis 6.2).
Sourcepub fn zintercard(&self, keys: &[&[u8]], limit: usize) -> Result<usize>
pub fn zintercard(&self, keys: &[&[u8]], limit: usize) -> Result<usize>
ZINTERCARD keys… [LIMIT n] — limit = 0 means unlimited.
Source§impl Store
impl Store
Sourcepub fn zadd_flags(
&self,
key: &[u8],
pairs: &[(f64, &[u8])],
flags: ZaddFlags,
) -> Result<ZaddReport>
pub fn zadd_flags( &self, key: &[u8], pairs: &[(f64, &[u8])], flags: ZaddFlags, ) -> Result<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,
) -> Result<(u64, Vec<(Vec<u8>, Vec<u8>)>)>
pub fn hscan( &self, key: &[u8], cursor: u64, count: usize, ) -> Result<(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]) -> Result<IntoIter<(Vec<u8>, Vec<u8>)>>
pub fn hash_iter(&self, key: &[u8]) -> Result<IntoIter<(Vec<u8>, Vec<u8>)>>
Iterator wrapper around Self::hscan.
Source§impl Store
impl Store
Sourcepub fn open(config: Config) -> Result<Self>
pub fn open(config: Config) -> Result<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 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>) -> Result<Self>
pub fn open_replica(upstream: impl Into<String>) -> Result<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 set_replica_upstream(
&self,
new_upstream: impl Into<String>,
) -> Result<()>
pub fn set_replica_upstream( &self, new_upstream: impl Into<String>, ) -> Result<()>
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]]) -> Result<()>
pub fn log(&self, parts: &[&[u8]]) -> Result<()>
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.
Source§impl Store
impl Store
Sourcepub fn fsync_aof(&self) -> Result<()>
pub fn fsync_aof(&self) -> Result<()>
Durability barrier (v2.1): 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) -> Result<Option<RewriteStats>>
pub fn rewrite_aof(&self) -> Result<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 save_snapshot(&self) -> Result<bool>
pub fn save_snapshot(&self) -> Result<bool>
Snapshot every shard to its dump-{i}.rdb (single shard: the configured
name), atomically. Ok(false) when persistence is disabled.