文档核心概念操作日志 (OpLog) 与文档状态 (DocState) 分离

OpLog 与 DocState

快速概览

  • OpLog = 构成文档历史的事件 / 操作序列
  • DocState = 文档当前具象化的状态

二者分离使得时光旅行、高效同步与灵活存储策略成为可能。

核心概念

OpLog(操作日志)

  • 仅追加的操作序列
  • 保存因果关系与元数据

DocState(文档状态)

  • 文档当前的具象视图
  • 实际的数据结构与值
  • 应用读取和展示的数据来源

优势

  • 内存效率:中继服务器只加载 OpLog,而不加载状态
  • 时光旅行:回溯历史而不丢失操作日志
  • 快速启动:先加载快照获取状态,再按需拉取历史
  • 灵活存储:两者可分开存储以便优化
const  = new ();
 
// 编辑会同时更新两者
.("text").(0, "Hello");
.(.());  // 最新已知版本
.(.());       // 当前 DocState 的版本
// 当文档处于 attached 状态时,两者相同

时光旅行与分离

const  = new ();
.("text").(0, "v1");
const  = .();
 
.("text").(2, " -> v2");
 
// checkout 旧版本:DocState 与 OpLog 出现分歧
.();
.(.());       // 显示 v1 状态
.(.());  // 仍包含 v2
.(.());    // true
 
// 回到最新版本
.();

Detached 状态:DocState 显示旧版本,但 OpLog 保留全部操作;默认禁用编辑。

导出策略

// update:仅导出 OpLog(用于同步)
const  = .({ : "update" });
 
// snapshot:导出 OpLog + DocState(用于持久化)
const  = .({ : "snapshot" });
 
// shallow:最小化 OpLog + DocState(快速启动)
const  = .({ : "shallow-snapshot", : .() });

常见模式

中继服务器(仅 OpLog)

class  {
  private : ;
  constructor() {
    this. = new ();
    this..(); // 从不具象化状态
  }
 
  (: ) {
    this..();
  }
}

最佳实践

  • 导出模式选择:update 用于同步,snapshot 用于持久化,shallow 适合快速启动
  • 按场景优化
    • 编辑器:同时在内存中保留两者
    • 中继服务:只保留 OpLog

相关文档