Skip to main content

oris_kernel/kernel/
snapshot.rs

1//! Snapshot and SnapshotStore for the Oris kernel.
2//!
3//! **Checkpointing/snapshots are strictly an optimization layer.** The source of truth
4//! is the event-sourced execution log (see [crate::kernel::execution_log::ExecutionLog] and
5//! [crate::kernel::event::EventStore]). Snapshots only speed up replay by providing
6//! initial state at a given seq; they do not replace the log.
7//! Every snapshot must carry `at_seq` (the seq up to which state has been projected).
8
9use serde::{Deserialize, Serialize};
10
11use crate::kernel::identity::{RunId, Seq};
12use crate::kernel::KernelError;
13
14/// A snapshot of state at a given sequence number.
15///
16/// **Invariant:** `at_seq` is the seq of the last event that was applied to produce this state.
17/// Recovery: load latest snapshot, then replay events with seq > at_seq.
18#[derive(Clone, Debug, Serialize, Deserialize)]
19pub struct Snapshot<S> {
20    /// Run this snapshot belongs to.
21    pub run_id: RunId,
22    /// Sequence number of the last event applied (projection point).
23    pub at_seq: Seq,
24    /// The state at this point.
25    pub state: S,
26}
27
28/// Snapshot store: load latest snapshot or save a new one (optimization layer).
29pub trait SnapshotStore<S>: Send + Sync {
30    /// Loads the latest snapshot for the run, if any.
31    fn load_latest(&self, run_id: &RunId) -> Result<Option<Snapshot<S>>, KernelError>;
32
33    /// Saves a snapshot. Overwrites or appends according to implementation.
34    fn save(&self, snapshot: &Snapshot<S>) -> Result<(), KernelError>;
35}
36
37/// In-memory snapshot store: one snapshot per run (latest overwrites).
38pub struct InMemorySnapshotStore<S> {
39    latest: std::sync::RwLock<std::collections::HashMap<RunId, Snapshot<S>>>,
40}
41
42impl<S: Clone + Send + Sync> InMemorySnapshotStore<S> {
43    pub fn new() -> Self {
44        Self {
45            latest: std::sync::RwLock::new(std::collections::HashMap::new()),
46        }
47    }
48}
49
50impl<S: Clone + Send + Sync> Default for InMemorySnapshotStore<S> {
51    fn default() -> Self {
52        Self::new()
53    }
54}
55
56impl<S: Clone + Send + Sync> SnapshotStore<S> for InMemorySnapshotStore<S> {
57    fn load_latest(&self, run_id: &RunId) -> Result<Option<Snapshot<S>>, KernelError> {
58        let guard = self
59            .latest
60            .read()
61            .map_err(|e| KernelError::SnapshotStore(e.to_string()))?;
62        Ok(guard.get(run_id).cloned())
63    }
64
65    fn save(&self, snapshot: &Snapshot<S>) -> Result<(), KernelError> {
66        let mut guard = self
67            .latest
68            .write()
69            .map_err(|e| KernelError::SnapshotStore(e.to_string()))?;
70        guard.insert(snapshot.run_id.clone(), snapshot.clone());
71        Ok(())
72    }
73}