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}