土法炼钢兴趣小组的算法知识备份

【WiredTiger 内核】Timestamps、Snapshot 与事务:可见性契约

文章导航

分类入口
databasestorage
标签入口
#wiredtiger#timestamps#snapshot#isolation#prepared-transaction#mvcc#stable-timestamp#mongodb

目录

第 6 篇 在 reconcile 时要选出「最新已提交且应上盘」的更新;第 08 篇 的读路径要按读时间戳在链 / 磁盘 / HS 之间查找。二者都依赖同一套 应用时间戳 + 事务快照 契约。Architecture Guide TimestampsSnapshot 是本篇 A 级来源。

本文钉住:active time window、oldest/stable/pinned、snapshot 可见性算法、prepared 边界。不重写 Berenson 隔离理论全书(见 mvcc);不展开 MongoDB 如何分配时间戳的复制细节(第 14 篇边界)。

本文是「WiredTiger 内核」系列第 7 篇(共 17 篇)。→ 系列目录

先修:第 5–6 篇。续读:第 08 篇;第 11 篇 Rollback-to-Stable。

版本锚定:Architecture Guide Version 12.0.0 / develop TimestampsSnapshotTransactions;源码 mongodb-8.0src/include/txn.htimestamp.hsrc/txn/Timestamps 章文首注明草稿整理中,以不变量与结构字段为准。


一、应用时间 vs 执行时间

Timestamps 章的世界观:

任意执行时刻存在 active time window

边界 含义
Oldest timestamp 应用允许新事务开始读取的最早应用时间;读更早是应用错误
Stable timestamp 窗口内「已稳定」与「未稳定」的分界:稳定侧数据固定、禁止再写、更新已充分耐久;未稳定侧仍可累积写入,甚至可被 checkpoint,但未完全耐久
Pinned timestamp(内部) min(oldest, 所有运行中事务的 read timestamp);真正用于丢弃/GC 历史的下界,避免应用推进 oldest 时伤及进行中的读

未来端是「迄今用过的最新时间戳」,Guide 称其不显式统一管理。不稳定侧在启动恢复、关闭、以及 WT_CONNECTION::rollback_to_stable 时会被丢弃(第 11 篇)。

flowchart LR
  oldest["oldest"] --> pinned["pinned <= oldest"]
  pinned --> stable["stable"]
  stable --> unstable["unstable writes"]
  unstable --> latest["latest used ts"]

二、事务上的时间戳

每个事务(概念与 API 上)带有:

字段 用途
Read timestamp 读操作使用的应用时间
Commit timestamp 写操作使用的应用时间
Prepare / durable timestamp(prepared) prepare 点与「变为 stable」点;可相对 commit 分离,以支持分布式两阶段提交不拖死 stable 推进

值的时间窗:某一键的每次修改关联时间戳;值覆盖从 start 到 stop 的区间(stop 不含;被覆盖时 stop 等于下一值的 start)。区间不可重叠。内部用 WT_TIME_WINDOW(含 start/stop 的 ts、durable ts、txn id、prepare 状态等);internal 页上聚合为 WT_TIME_AGGREGATE,用于跳过与读时间戳无关的子树。

时间戳为 64 位无符号整数,0 保留;WT_TS_NONE / WT_TS_MAX 为哨兵。与应用交换时常用十六进制字符串(经配置参数系统)。

写入顺序约束

应用须对每个键按时间戳递增提交。默认一旦某键使用时间戳,则必须继续使用且不得回退;可用 write_timestamp_usage 调整(WT_SESSION::create)。

读写仍走事务系统与 snapshot isolation:读只能看见快照创建时已提交的更新,即使某写的 commit timestamp 相对读 timestamp 「更早」——若该写在快照之后才提交,仍不可见。Guide 警告:若在 stable 之后读,另一事务可能提交进「你的过去」,破坏一致性;应用应保证 commit timestamp 整体大于相关 read timestamp。MongoDB 层负责遵守该纪律。


三、Snapshot:隔离如何落地

Snapshot 章:快照捕获创建时刻的全局事务状态,存在 per-session 的 WT_TXN 中。

3.1 隔离级别与何时建快照

隔离 快照行为
snapshot(默认) 事务开始时建快照,持续整个事务;只读开始前已提交的版本
read-committed search 时建快照,后续读复用直到再次 search
read-uncommitted 不建快照;允许脏读

3.2 快照内容

3.3 可见性检查顺序

对给定 txn ID:

  1. \(\ge\) max → 不可见
  2. \(<\) min → 可见
  3. 落在并发列表中 → 不可见
  4. 否则可见

先做 max/min 边界很重要:并发列表可能为空。

时间戳维度上,更新的 commit timestamp 还要对照读者的 read timestamp(Timestamps:冲突检测先用 txn ID 看未提交,再用时间戳)。本篇不展开每个可见性函数名;以 Guide 规则与 src/txn/ 为准。

3.4 与 Checkpoint

Checkpoint 使用独立的特殊全局事务与快照。应用侧 snapshot 事务会把 checkpoint 的事务 ID 记为并发事务之一,从而忽略 checkpoint 尚未提交的元数据更改。


四、Prepared(预告)

Timestamps · Prepared transactions

第 11、14 篇回收 prepared 与复制/RTS 的耦合。


五、谱系、争论与开放问题

谱系: Berenson et al., SIGMOD 1995 给出脏读/不可重复读/幻读/Write Skew 等词汇 → 引擎用多版本 + 快照兑现子集 → WT 再把应用时间戳从执行时钟中拆出,以支持 MongoDB 式的全局时间与 prepared。这是工程时间模型,不是新的隔离代数。

争论: 在 unstable 窗口内读是否应更强地由引擎拒绝,而非留给应用——Guide 当前把部分一致性责任放在应用;MongoDB 嵌入后责任上移到服务器。本系列按 Guide 写清契约,不在此改设计。

开放问题:

  1. oldest 推进与复制延迟、长游标、minSnapshotHistoryWindowInSeconds 的耦合(第 08、14–15 篇)。
  2. prepared 的 durable 与 checkpoint 交错导致的不一致窗口,生产上如何被 MongoDB 收死(第 11、14 篇)。

六、收束

  1. Oldest / stable / pinned 界定可读历史与可丢弃历史;不稳定侧可被 RTS 丢掉。
  2. 默认 snapshot 隔离:快照用 max/min/并发 txn ID 列表决定可见性;时间戳决定应用时间轴上的版本。
  3. 下一篇已发布的 History Store 回答:版本物理上放哪;再往后第 9–11 篇回答 checkpoint / journal / RTS 如何收束时间戳。

参考资料

规范 / 官方文档

论文

源码

站内


上一篇Reconciliation
下一篇History Store 与 Durable History

同主题继续阅读

把当前热点继续串成多页阅读,而不是停在单篇消费。


By .