Skip to main content

vantage_live/cache/
mod.rs

1//! Cache backend abstraction for `LiveTable`.
2//!
3//! `LiveTable` only knows about [`Cache`] — concrete backends like
4//! [`MemCache`], [`NoCache`], or `RedbCache` plug in via this trait. The
5//! storage shape is `key → CachedRows`; keys are caller-supplied
6//! `cache_key` plus a per-page suffix produced by `LiveTable`. See
7//! `DESIGN.md` for the keying contract.
8
9use async_trait::async_trait;
10use indexmap::IndexMap;
11use std::time::SystemTime;
12use vantage_core::Result;
13use vantage_types::Record;
14
15mod mem;
16mod noop;
17
18pub use mem::MemCache;
19pub use noop::NoCache;
20
21/// A row set as stored in the cache, with the wall-clock instant the master
22/// fetch completed. Fetch time isn't used in v1 (no TTL), but we keep it
23/// because every backend can provide it cheaply and it's the obvious knob
24/// to add later.
25#[derive(Clone, Debug)]
26pub struct CachedRows {
27    pub rows: IndexMap<String, Record<ciborium::Value>>,
28    pub fetched_at: SystemTime,
29}
30
31impl CachedRows {
32    pub fn new(rows: IndexMap<String, Record<ciborium::Value>>) -> Self {
33        Self {
34            rows,
35            fetched_at: SystemTime::now(),
36        }
37    }
38}
39
40/// Cache backend interface. Implementations must be safe to share across
41/// the read path, the write-queue worker, and the live-event consumer.
42#[async_trait]
43pub trait Cache: Send + Sync {
44    /// Look up `key`; `Ok(None)` is a normal miss, `Err` is reserved for
45    /// real backend faults (disk error, redb panic recovery, etc.).
46    async fn get(&self, key: &str) -> Result<Option<CachedRows>>;
47
48    /// Store `rows` under `key`, replacing whatever was there.
49    async fn put(&self, key: &str, rows: CachedRows) -> Result<()>;
50
51    /// Drop every entry whose key starts with `prefix`. v1 callers always
52    /// pass the bare `cache_key` — every page suffix below it goes.
53    /// Implementations should accept any prefix (so finer-grained
54    /// invalidation can be added later without breaking the trait).
55    async fn invalidate_prefix(&self, prefix: &str) -> Result<()>;
56}