1use async_trait::async_trait;
8use serde::{Deserialize, Serialize};
9
10#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
17pub enum CommitMode {
18 MemoryOnly,
19 AsyncDurable { group_window_ms: u32 },
20 SyncDurable,
21}
22
23#[derive(Clone, Debug, Serialize, Deserialize)]
25pub struct PersistOptions {
26 pub commit_mode: CommitMode,
27 pub snapshot_every_n_events: u32,
28 pub snapshot_every_bytes: u64,
29 pub snapshot_every_ms: u64,
30 pub compression: bool,
31}
32
33#[derive(Clone, Debug, Serialize, Deserialize)]
40pub struct PersistedEvent {
41 pub lsn: i64,
42 pub tr_id: u64,
43 pub doc_id: String,
44 pub ts: i64,
45 pub actor: Option<String>,
46 pub idempotency_key: String,
47 pub payload: Vec<u8>,
48 pub meta: serde_json::Value,
49 pub checksum: u32,
50}
51
52#[derive(Clone, Debug, Serialize, Deserialize)]
54pub struct Snapshot {
55 pub doc_id: String,
56 pub upto_lsn: i64,
57 pub created_at: i64,
58 pub state_blob: Vec<u8>,
59 pub version: i32,
60}
61
62#[async_trait]
64pub trait EventStore: Send + Sync {
65 async fn append(
67 &self,
68 ev: PersistedEvent,
69 ) -> anyhow::Result<i64>;
70 async fn append_batch(
72 &self,
73 evs: Vec<PersistedEvent>,
74 ) -> anyhow::Result<i64>;
75 async fn load_since(
77 &self,
78 doc_id: &str,
79 from_lsn: i64,
80 limit: u32,
81 ) -> anyhow::Result<Vec<PersistedEvent>>;
82 async fn latest_snapshot(
84 &self,
85 doc_id: &str,
86 ) -> anyhow::Result<Option<Snapshot>>;
87 async fn write_snapshot(
89 &self,
90 snap: Snapshot,
91 ) -> anyhow::Result<()>;
92 async fn compact(
94 &self,
95 doc_id: &str,
96 ) -> anyhow::Result<()>;
97}
98
99#[derive(Clone, Debug)]
101pub struct LoadedState {
102 pub upto_lsn: i64,
103 pub snapshot: Option<Snapshot>,
104 pub events: Vec<PersistedEvent>,
105}
106
107#[async_trait]
109pub trait Persistence: Send + Sync {
110 async fn persist_transaction(
111 &self,
112 tr: &mf_state::Transaction,
113 doc_id: &str,
114 context_meta: &serde_json::Value,
115 ) -> anyhow::Result<i64>;
116
117 async fn load_state(
118 &self,
119 doc_id: &str,
120 ) -> anyhow::Result<LoadedState>;
121
122 async fn checkpoint_if_needed(
123 &self,
124 doc_id: &str,
125 ) -> anyhow::Result<()>;
126}