Skip to main content

Store

Struct Store 

Source
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 kevy_store::Store + AOF + reaper + pub/sub bus. The reaper thread is joined and the 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. The internal Arc<Mutex<Inner>> is what makes shared access safe under contention.

Implementations§

Source§

impl Store

Source

pub fn open(config: Config) -> Result<Self>

Open an embedded keyspace per config.

  • Pure in-memory when config.data_dir is None.
  • With persistence: loads <data_dir>/<snapshot_filename> first, then replays <data_dir>/<aof_filename>. Both are best-effort — missing files are fine, a truncated AOF tail is silently dropped.
  • Spawns a background TTL reaper thread when config.ttl_reaper == Background (the default).
Examples found in repository?
examples/embedded.rs (line 8)
7fn main() -> std::io::Result<()> {
8    let s = Store::open(Config::default())?;
9    s.set(b"greeting", b"hello, kevy")?;
10    let v = s.get(b"greeting")?;
11    println!("greeting = {}", String::from_utf8_lossy(v.as_deref().unwrap_or(b"<missing>")));
12    println!("dbsize = {}", s.dbsize());
13    Ok(())
14}
More examples
Hide additional examples
examples/embedded-cache.rs (lines 10-14)
9fn main() -> std::io::Result<()> {
10    let s = Store::open(
11        Config::default()
12            .with_max_memory(200 * 1024)
13            .with_eviction(EvictionPolicy::AllKeysLru),
14    )?;
15
16    for i in 0..10_000 {
17        let key = format!("user:{i:05}");
18        let val = format!("user-payload-{i}");
19        s.set(key.as_bytes(), val.as_bytes())?;
20    }
21
22    println!("dbsize after insert flood: {}", s.dbsize());
23    println!("used_memory: {} bytes (limit 200 KiB)", s.used_memory());
24    println!("evictions_total: {}", s.evictions_total());
25
26    // Touch a recent key — it should still be live.
27    let recent = format!("user:0{}", 9999);
28    println!(
29        "user:09999 → {:?}",
30        s.get(recent.as_bytes())?.as_deref().map(String::from_utf8_lossy)
31    );
32
33    Ok(())
34}
Source

pub fn downgrade(&self) -> WeakStore

Get a weak handle that does not keep the keyspace alive. upgrade() returns None once the last strong Store is dropped.

Source

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.

Source

pub fn with<F, R>(&self, f: F) -> R
where F: FnOnce(&mut Store) -> R,

Run f against the underlying kevy_store::Store under the embedded mutex. Use for direct access to methods this crate hasn’t wrapped (snapshot iteration, ZRANGE, raw collect_keys, …). The closure can mutate, but does not auto-log to the AOF — call Self::log yourself if the mutation must survive a crash.

Source

pub fn log(&self, parts: &[&[u8]]) -> Result<()>

Append a raw RESP-frame argument list to the AOF. Pairs with Self::with when the closure performed a write you want to make crash-safe. No-op when persistence is disabled.

Source

pub fn tick(&self) -> ExpireStats

Run one TTL-reaper tick. Required call cadence in Manual mode (call ~10× per second to match Redis’s hz=10); no-op cost is one mutex lock + map-emptiness check when nothing has TTL.

Source

pub fn rewrite_aof(&self) -> Result<Option<RewriteStats>>

BGREWRITEAOF: rebuild the AOF from current state. Synchronous — blocks until the rewrite + atomic rename completes. Returns Ok(None) when persistence is disabled.

Source

pub fn save_snapshot(&self) -> Result<bool>

Snapshot the store to <data_dir>/<snapshot_filename>, atomically. Ok(false) when persistence is disabled (caller can decide to surface that or no-op).

Source

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 Self::with for the full surface).

Examples found in repository?
examples/embedded.rs (line 9)
7fn main() -> std::io::Result<()> {
8    let s = Store::open(Config::default())?;
9    s.set(b"greeting", b"hello, kevy")?;
10    let v = s.get(b"greeting")?;
11    println!("greeting = {}", String::from_utf8_lossy(v.as_deref().unwrap_or(b"<missing>")));
12    println!("dbsize = {}", s.dbsize());
13    Ok(())
14}
More examples
Hide additional examples
examples/embedded-cache.rs (line 19)
9fn main() -> std::io::Result<()> {
10    let s = Store::open(
11        Config::default()
12            .with_max_memory(200 * 1024)
13            .with_eviction(EvictionPolicy::AllKeysLru),
14    )?;
15
16    for i in 0..10_000 {
17        let key = format!("user:{i:05}");
18        let val = format!("user-payload-{i}");
19        s.set(key.as_bytes(), val.as_bytes())?;
20    }
21
22    println!("dbsize after insert flood: {}", s.dbsize());
23    println!("used_memory: {} bytes (limit 200 KiB)", s.used_memory());
24    println!("evictions_total: {}", s.evictions_total());
25
26    // Touch a recent key — it should still be live.
27    let recent = format!("user:0{}", 9999);
28    println!(
29        "user:09999 → {:?}",
30        s.get(recent.as_bytes())?.as_deref().map(String::from_utf8_lossy)
31    );
32
33    Ok(())
34}
Source

pub fn set_with_ttl( &self, key: &[u8], value: &[u8], ttl: Duration, ) -> Result<bool>

SET key value PX ms — overwrites + sets TTL.

Source

pub fn get(&self, key: &[u8]) -> Result<Option<Vec<u8>>>

GET keySome(bytes) on hit, None on miss or expired.

Examples found in repository?
examples/embedded.rs (line 10)
7fn main() -> std::io::Result<()> {
8    let s = Store::open(Config::default())?;
9    s.set(b"greeting", b"hello, kevy")?;
10    let v = s.get(b"greeting")?;
11    println!("greeting = {}", String::from_utf8_lossy(v.as_deref().unwrap_or(b"<missing>")));
12    println!("dbsize = {}", s.dbsize());
13    Ok(())
14}
More examples
Hide additional examples
examples/embedded-cache.rs (line 30)
9fn main() -> std::io::Result<()> {
10    let s = Store::open(
11        Config::default()
12            .with_max_memory(200 * 1024)
13            .with_eviction(EvictionPolicy::AllKeysLru),
14    )?;
15
16    for i in 0..10_000 {
17        let key = format!("user:{i:05}");
18        let val = format!("user-payload-{i}");
19        s.set(key.as_bytes(), val.as_bytes())?;
20    }
21
22    println!("dbsize after insert flood: {}", s.dbsize());
23    println!("used_memory: {} bytes (limit 200 KiB)", s.used_memory());
24    println!("evictions_total: {}", s.evictions_total());
25
26    // Touch a recent key — it should still be live.
27    let recent = format!("user:0{}", 9999);
28    println!(
29        "user:09999 → {:?}",
30        s.get(recent.as_bytes())?.as_deref().map(String::from_utf8_lossy)
31    );
32
33    Ok(())
34}
Source

pub fn del(&self, keys: &[&[u8]]) -> Result<usize>

DEL key1 [key2 ...]. Returns the count of keys actually removed.

Source

pub fn exists(&self, keys: &[&[u8]]) -> Result<usize>

EXISTS key1 [key2 ...]. Returns the count of existing keys (duplicates counted multiple times, matching Redis).

Source

pub fn incr(&self, key: &[u8]) -> Result<i64>

INCR key. Returns the post-increment value.

Source

pub fn incr_by(&self, key: &[u8], delta: i64) -> Result<i64>

INCRBY key delta. Negative delta does DECR-style work.

Source

pub fn expire(&self, key: &[u8], ttl: Duration) -> Result<bool>

EXPIRE key seconds. Returns true if a key was touched.

Source

pub fn persist(&self, key: &[u8]) -> Result<bool>

PERSIST key. Returns true if a TTL was actually cleared.

Source

pub fn ttl_ms(&self, key: &[u8]) -> i64

Remaining TTL in ms (or Redis-style -1/-2 for no-TTL/no-key).

Source

pub fn type_of(&self, key: &[u8]) -> &'static str

TYPE key"string", "hash", "list", "set", "zset", or "none".

Source

pub fn dbsize(&self) -> usize

DBSIZE — total live keys.

Examples found in repository?
examples/embedded.rs (line 12)
7fn main() -> std::io::Result<()> {
8    let s = Store::open(Config::default())?;
9    s.set(b"greeting", b"hello, kevy")?;
10    let v = s.get(b"greeting")?;
11    println!("greeting = {}", String::from_utf8_lossy(v.as_deref().unwrap_or(b"<missing>")));
12    println!("dbsize = {}", s.dbsize());
13    Ok(())
14}
More examples
Hide additional examples
examples/embedded-cache.rs (line 22)
9fn main() -> std::io::Result<()> {
10    let s = Store::open(
11        Config::default()
12            .with_max_memory(200 * 1024)
13            .with_eviction(EvictionPolicy::AllKeysLru),
14    )?;
15
16    for i in 0..10_000 {
17        let key = format!("user:{i:05}");
18        let val = format!("user-payload-{i}");
19        s.set(key.as_bytes(), val.as_bytes())?;
20    }
21
22    println!("dbsize after insert flood: {}", s.dbsize());
23    println!("used_memory: {} bytes (limit 200 KiB)", s.used_memory());
24    println!("evictions_total: {}", s.evictions_total());
25
26    // Touch a recent key — it should still be live.
27    let recent = format!("user:0{}", 9999);
28    println!(
29        "user:09999 → {:?}",
30        s.get(recent.as_bytes())?.as_deref().map(String::from_utf8_lossy)
31    );
32
33    Ok(())
34}
Source

pub fn flush(&self) -> Result<()>

FLUSHALL — empty the keyspace (logged so a replay reaches the same empty state).

Source

pub fn key_bytes(&self, key: &[u8]) -> Option<u64>

MEMORY USAGE for one key — Some(bytes) or None if absent.

Source

pub fn used_memory(&self) -> u64

Live used_memory estimate (matches INFO memory’s field).

Examples found in repository?
examples/embedded-cache.rs (line 23)
9fn main() -> std::io::Result<()> {
10    let s = Store::open(
11        Config::default()
12            .with_max_memory(200 * 1024)
13            .with_eviction(EvictionPolicy::AllKeysLru),
14    )?;
15
16    for i in 0..10_000 {
17        let key = format!("user:{i:05}");
18        let val = format!("user-payload-{i}");
19        s.set(key.as_bytes(), val.as_bytes())?;
20    }
21
22    println!("dbsize after insert flood: {}", s.dbsize());
23    println!("used_memory: {} bytes (limit 200 KiB)", s.used_memory());
24    println!("evictions_total: {}", s.evictions_total());
25
26    // Touch a recent key — it should still be live.
27    let recent = format!("user:0{}", 9999);
28    println!(
29        "user:09999 → {:?}",
30        s.get(recent.as_bytes())?.as_deref().map(String::from_utf8_lossy)
31    );
32
33    Ok(())
34}
Source

pub fn evictions_total(&self) -> u64

INFO-style counter: total keys evicted by maxmemory so far.

Examples found in repository?
examples/embedded-cache.rs (line 24)
9fn main() -> std::io::Result<()> {
10    let s = Store::open(
11        Config::default()
12            .with_max_memory(200 * 1024)
13            .with_eviction(EvictionPolicy::AllKeysLru),
14    )?;
15
16    for i in 0..10_000 {
17        let key = format!("user:{i:05}");
18        let val = format!("user-payload-{i}");
19        s.set(key.as_bytes(), val.as_bytes())?;
20    }
21
22    println!("dbsize after insert flood: {}", s.dbsize());
23    println!("used_memory: {} bytes (limit 200 KiB)", s.used_memory());
24    println!("evictions_total: {}", s.evictions_total());
25
26    // Touch a recent key — it should still be live.
27    let recent = format!("user:0{}", 9999);
28    println!(
29        "user:09999 → {:?}",
30        s.get(recent.as_bytes())?.as_deref().map(String::from_utf8_lossy)
31    );
32
33    Ok(())
34}
Source

pub fn expired_keys_total(&self) -> u64

INFO-style counter: total keys expired (lazy + active reaper).

Source

pub fn hset(&self, key: &[u8], pairs: &[(&[u8], &[u8])]) -> Result<usize>

Source

pub fn hget(&self, key: &[u8], field: &[u8]) -> Result<Option<Vec<u8>>>

Source

pub fn hdel(&self, key: &[u8], fields: &[&[u8]]) -> Result<usize>

Source

pub fn lpush(&self, key: &[u8], values: &[&[u8]]) -> Result<usize>

Source

pub fn rpush(&self, key: &[u8], values: &[&[u8]]) -> Result<usize>

Source

pub fn lpop(&self, key: &[u8], count: usize) -> Result<Vec<Vec<u8>>>

Source

pub fn rpop(&self, key: &[u8], count: usize) -> Result<Vec<Vec<u8>>>

Source

pub fn llen(&self, key: &[u8]) -> Result<usize>

Source

pub fn sadd(&self, key: &[u8], members: &[&[u8]]) -> Result<usize>

Source

pub fn srem(&self, key: &[u8], members: &[&[u8]]) -> Result<usize>

Source

pub fn smembers(&self, key: &[u8]) -> Result<Vec<Vec<u8>>>

Source

pub fn scard(&self, key: &[u8]) -> Result<usize>

Source

pub fn zadd(&self, key: &[u8], pairs: &[(f64, &[u8])]) -> Result<usize>

Source

pub fn zrem(&self, key: &[u8], members: &[&[u8]]) -> Result<usize>

Source

pub fn zscore(&self, key: &[u8], member: &[u8]) -> Result<Option<f64>>

Source

pub fn zcard(&self, key: &[u8]) -> Result<usize>

Source

pub fn publish(&self, channel: &[u8], payload: &[u8]) -> usize

PUBLISH channel payload. Delivers payload to every subscriber on channel (direct + pattern matches) running inside this same process. Returns the count of receivers that the message reached.

Source

pub fn subscribe(&self, channels: &[&[u8]]) -> Subscription

Open a Subscription subscribed to channels. The subscription owns its receive end; drop it to unsubscribe from everything. Pass &[] to start with no subscriptions and add some later via Subscription::subscribe / Subscription::psubscribe.

Source

pub fn psubscribe(&self, patterns: &[&[u8]]) -> Subscription

Convenience: open a Subscription starting on pattern subscriptions.

Trait Implementations§

Source§

impl Clone for Store

Source§

fn clone(&self) -> Store

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more

Auto Trait Implementations§

§

impl Freeze for Store

§

impl RefUnwindSafe for Store

§

impl Send for Store

§

impl Sync for Store

§

impl Unpin for Store

§

impl UnsafeUnpin for Store

§

impl UnwindSafe for Store

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.