Skip to main content

mf_persistence/
api.rs

1//! 持久化抽象层的公共 API。
2//!
3//! 本模块定义了持久化的可调一致性选项、事件/快照的持久化格式,
4//! 以及具体后端需要实现的 trait。默认实现为基于 SQLite 的 WAL,
5//! 但上层仅依赖这些 trait 即可与具体后端解耦。
6
7use async_trait::async_trait;
8use serde::{Deserialize, Serialize};
9
10/// 写入持久性与延迟之间的权衡。
11///
12/// - `MemoryOnly`:事件入内存队列即返回,最低延迟、不具持久性,仅适合演示/开发。
13/// - `AsyncDurable`:写入 WAL/系统缓存后返回,fsync 由后台分组处理;
14///   在桌面环境具有很好的实际持久性与极低延迟(默认)。
15/// - `SyncDurable`:提交前强制 fsync,延迟最高、持久性最强。
16#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
17pub enum CommitMode {
18    MemoryOnly,
19    AsyncDurable { group_window_ms: u32 },
20    SyncDurable,
21}
22
23/// 快照节奏与压缩等可调参数。
24#[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/// 事件存储的"仅追加"记录。
34///
35/// 不变式:
36/// - `lsn` 为后端分配的单调递增日志序号
37/// - `idempotency_key` 全局唯一,用于请求重试的幂等去重
38/// - `checksum` 对(压缩/加密后的)`payload` 计算得到
39#[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/// 截止到 `upto_lsn` 的物化状态快照。
53#[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/// 具体后端必须实现的最小持久化接口。
63#[async_trait]
64pub trait EventStore: Send + Sync {
65    /// 追加单条事件。返回分配的 `lsn`。
66    async fn append(
67        &self,
68        ev: PersistedEvent,
69    ) -> anyhow::Result<i64>;
70    /// 在单事务内批量追加事件。返回最后一条的 `lsn`。
71    async fn append_batch(
72        &self,
73        evs: Vec<PersistedEvent>,
74    ) -> anyhow::Result<i64>;
75    /// 读取指定文档分片自 `from_lsn` 之后的增量事件,上限为 `limit` 条。
76    async fn load_since(
77        &self,
78        doc_id: &str,
79        from_lsn: i64,
80        limit: u32,
81    ) -> anyhow::Result<Vec<PersistedEvent>>;
82    /// 获取指定文档分片的最新快照(如果存在)。
83    async fn latest_snapshot(
84        &self,
85        doc_id: &str,
86    ) -> anyhow::Result<Option<Snapshot>>;
87    /// 写入/替换快照,应保证原子性。
88    async fn write_snapshot(
89        &self,
90        snap: Snapshot,
91    ) -> anyhow::Result<()>;
92    /// 可选压缩:删除已被最新快照覆盖的历史事件。
93    async fn compact(
94        &self,
95        doc_id: &str,
96    ) -> anyhow::Result<()>;
97}
98
99/// 用于启动引导的状态加载结果(快照 + 增量事件)。
100#[derive(Clone, Debug)]
101pub struct LoadedState {
102    pub upto_lsn: i64,
103    pub snapshot: Option<Snapshot>,
104    pub events: Vec<PersistedEvent>,
105}
106
107/// 高层持久化编排:事务持久化与快照检查点。
108#[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}