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