文档教程导出模式 (Export Mode)

导出模式

Loro 1.0 的数据格式已稳定,不会再发生破坏性变更。

Loro 提供三种编码模式,以适配不同场景:

  • Updates 编码:编码全部或指定区间的操作,适合增量同步。
  • Snapshot 编码:编码完整文档,包含全部操作与当前状态。
  • Shallow Snapshot 编码:Loro 1.0 新增的模式,可丢弃无用历史,只保留最近历史与当前状态。

使用统一的 doc.export(mode) 导出,所有二进制格式都可以通过 doc.import(bytes) 导入。

export type ExportMode =
  | {
      mode: "update";
      from?: VersionVector;
    }
  | {
      mode: "updates-in-range";
      spans: {
        id: ID;
        len: number;
      }[];
    }
  | {
      mode: "snapshot";
    }
  | {
      mode: "shallow-snapshot";
      frontiers: Frontiers;
    };

Updates 编码

包含 updateupdates-in-range 两种子模式:

  • update:从指定版本 from 到最新版本的所有操作
  • updates-in-range:编码指定版本区间内的操作
const  = new ();
const  = new ();
.(2);
 
.("text").(0, "hello");
const  = .({ : "update", : .() });
// const bytes = doc2.export({ mode: "updates-in-range", spans: [{ id: { peer: 2, counter: 0 }, len: 1 }] });
.();
.(.()); // { text: "hello" }

与其导出整个文档,不如只导出增量操作,更适合实时协作。

Snapshot 编码

const  = new ();
const  = new ();
 
.("text").(0, "hello");
const  = .({ : "snapshot" });
.();
.(.()); // { text: "hello" }

Snapshot 编码会打包当前状态与全部历史,适合快速恢复完整文档。

Shallow Snapshot 编码

为了支持冲突解决与回溯,Loro 默认保留全部历史;但在多数场景中,旧历史既无用又占空间。Shallow Snapshot 允许你指定历史起点,截断更早的记录。

const  = new ();
const  = new ();
.(2);
 
const  = .("text");
.(0, "hello");
const  = .();
.(0, "w");
.(0, "o");
.(0, "r");
.(0, "l");
.(0, "d");
const  = .({ : "shallow-snapshot",  });
.();
.(.()); // { text: "hello" }

注意:使用浅快照后,不能再导入与起始版本并发的更新。详情见浅快照

Snapshot 文件格式

为支持惰性加载,Loro 借鉴数据库通用格式,引入简单的 LSM 引擎,将编码结果抽象为 key/value 形式,方便未来与常用 KV 数据库集成。

编码细节

  • 连续属于同一容器的多个操作会合并成一个 Change,每个 Change 包含 ID、Lamport、Timestamp 等元数据
  • 多个连续的 Change 会组合成 ChangeBlock,作为最小的历史编码单元
  • ChangeBlock 以首个 Change ID 作为 key,可快速查询对应操作
  • 文档状态由各容器状态组成:key 为 ContainerID,value 为容器元数据 + 语义化编码数据
  • 所有 key-value 会存入简化的 LSM 结构

最终导出包含四部分:编码头、oplog 字节、最新状态字节、浅状态字节。

  • Header:4 字节 magic number + 16 字节校验和 + 2 字节编码模式
  • 其余部分均使用 LSM 编码结构

Snapshot 编码布局