Skip to main content

kevy_embedded/
info.rs

1//! Introspection on a live [`Store`] — the embedded-mode answer to Redis's
2//! `INFO` / `DBSIZE` / `TTL` / expire-set diagnostics. In-process mode has no
3//! TCP endpoint to point `redis-cli` at, so these expose the same signals as
4//! plain method calls on the `Store` handle.
5
6use std::time::Duration;
7
8use crate::store::Store;
9
10/// Snapshot of a store's runtime counters, returned by [`Store::info`]. A
11/// cheap aggregate (one mutex lock); fields mirror the individual accessors.
12#[derive(Debug, Clone)]
13pub struct KevyInfo {
14    /// Live key count (`DBSIZE`).
15    pub keys: usize,
16    /// Estimated resident bytes (`INFO memory: used_memory`).
17    pub used_memory: u64,
18    /// Current on-disk AOF size in bytes (0 when persistence is off).
19    pub aof_bytes: u64,
20    /// Live keys carrying a TTL — the expire-set size. A `0` here when you
21    /// expected TTLs is the tell that the TTL subsystem didn't register them.
22    pub expire_pending: usize,
23    /// Total keys evicted by `maxmemory` so far.
24    pub evictions: u64,
25    /// Total keys expired (lazy + active reaper) so far.
26    pub expired_keys: u64,
27}
28
29impl Store {
30    /// One-shot snapshot of the store's introspection counters. See
31    /// [`KevyInfo`]. Takes the embedded mutex once; safe to call from a
32    /// health endpoint.
33    pub fn info(&self) -> KevyInfo {
34        KevyInfo {
35            keys: self.sum_shards(|i| i.store.dbsize()),
36            used_memory: self.sum_shards_u64(|i| i.store.used_memory()),
37            aof_bytes: self.sum_shards_u64(|i| i.aof.as_ref().map_or(0, |a| a.size_bytes())),
38            expire_pending: self.sum_shards(|i| i.store.ttl_pending_count()),
39            evictions: self.sum_shards_u64(|i| i.store.evictions_total()),
40            expired_keys: self.sum_shards_u64(|i| i.store.expired_keys_total()),
41        }
42    }
43
44    /// Number of live keys that currently carry a TTL (the expire-set size,
45    /// summed across shards).
46    pub fn expire_pending_count(&self) -> usize {
47        self.sum_shards(|i| i.store.ttl_pending_count())
48    }
49
50    /// Remaining TTL for `key` as a [`Duration`], or `None` when the key is
51    /// absent or has no TTL (persistent). For the raw Redis `PTTL` sentinels
52    /// (`-2` no key, `-1` no TTL) use [`Store::ttl_ms`].
53    pub fn ttl(&self, key: &[u8]) -> Option<Duration> {
54        let ms = self.wshard(key).store.pttl(key);
55        if ms < 0 {
56            None
57        } else {
58            Some(Duration::from_millis(ms as u64))
59        }
60    }
61}