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;
17mod redb;
18
19pub use mem::MemCache;
20pub use noop::NoCache;
21pub use redb::RedbCache;
22
23/// A row set as stored in the cache, with the wall-clock instant the master
24/// fetch completed. Fetch time isn't used in v1 (no TTL), but we keep it
25/// because every backend can provide it cheaply and it's the obvious knob
26/// to add later.
27#[derive(Clone, Debug)]
28pub struct CachedRows {
29    pub rows: IndexMap<String, Record<ciborium::Value>>,
30    pub fetched_at: SystemTime,
31}
32
33impl CachedRows {
34    pub fn new(rows: IndexMap<String, Record<ciborium::Value>>) -> Self {
35        Self {
36            rows,
37            fetched_at: SystemTime::now(),
38        }
39    }
40}
41
42/// Cache backend interface. Implementations must be safe to share across
43/// the read path, the write-queue worker, and the live-event consumer.
44#[async_trait]
45pub trait Cache: Send + Sync {
46    /// Look up `key`; `Ok(None)` is a normal miss, `Err` is reserved for
47    /// real backend faults (disk error, redb panic recovery, etc.).
48    async fn get(&self, key: &str) -> Result<Option<CachedRows>>;
49
50    /// Store `rows` under `key`, replacing whatever was there.
51    async fn put(&self, key: &str, rows: CachedRows) -> Result<()>;
52
53    /// Drop every entry whose key starts with `prefix`. v1 callers always
54    /// pass the bare `cache_key` — every page suffix below it goes.
55    /// Implementations should accept any prefix (so finer-grained
56    /// invalidation can be added later without breaking the trait).
57    async fn invalidate_prefix(&self, prefix: &str) -> Result<()>;
58}