Skip to main content

kevy_embedded/
store_tick.rs

1//! `Store::tick` — the Manual-mode maintenance cadence, the same
2//! per-shard body the background reaper drives. A `#[path]` child of
3//! `store.rs`, split under the 500-LOC rule.
4
5use kevy_store::ExpireStats;
6
7use crate::store::{Store, lock_write};
8
9impl Store {
10    /// Run one TTL-reaper tick across every shard. Required call cadence in
11    /// `Manual` mode (~10×/s to match Redis `hz=10`). Returns the summed stats.
12    pub fn tick(&self) -> ExpireStats {
13        let mut total = ExpireStats::default();
14        for (shard_i, shard) in self.shards.iter().enumerate() {
15            #[cfg(not(all(feature = "index", feature = "persist", not(target_arch = "wasm32"))))]
16            let _ = shard_i;
17            let stats = {
18                let mut g = lock_write(shard);
19                // Tiering upkeep: budget re-resolution + the index/view
20                // floor feed, then the tick continuation of the
21                // budgeted spill.
22                #[cfg(all(feature = "tier", not(target_arch = "wasm32")))]
23                crate::shard::tier_tick_upkeep(&mut g, self.config.tier_budget, self.shards.len());
24                let _ = g.store.demote_step();
25                let _ = g.store.tier_compact_tick();
26                #[cfg(feature = "index")]
27                crate::ops_index_tidy::tick(&mut g.idx_segs);
28                // The window tick rides the manual cadence exactly as it
29                // rides the background reaper's — a Manual-mode store
30                // with a windowed table must slide too, not silently
31                // stay all-hot.
32                #[cfg(all(feature = "index", feature = "persist", not(target_arch = "wasm32")))]
33                if let Some(dir) = &self.config.data_dir {
34                    let inner = &mut *g;
35                    crate::ops_index_window::window_tick(
36                        &mut inner.idx_segs,
37                        &mut inner.store,
38                        &mut inner.aof,
39                        &self.tables,
40                        &kevy_persist::layout::segs_dir(dir, shard_i),
41                    );
42                }
43                g.store.tick_expire(self.config.reaper_samples, self.config.reaper_max_rounds)
44            };
45            total.sampled += stats.sampled;
46            total.expired += stats.expired;
47            // Auto-rewrite rides the caller-driven tick in Manual mode; the
48            // non-blocking path releases the lock for the disk spill.
49            #[cfg(feature = "persist")]
50            crate::reaper::concurrent_auto_rewrite(
51                shard,
52                self.config.rewrite_policy(),
53                self.config.metric_sink.as_ref(),
54            );
55        }
56        total
57    }
58}