第 6 篇 在 reconcile 时要选出「最新已提交且应上盘」的更新;第 08 篇 的读路径要按读时间戳在链 / 磁盘 / HS 之间查找。二者都依赖同一套 应用时间戳 + 事务快照 契约。Architecture Guide Timestamps 与 Snapshot 是本篇 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 /
developTimestamps、Snapshot、Transactions;源码mongodb-8.0的src/include/txn.h、timestamp.h、src/txn/。Timestamps 章文首注明草稿整理中,以不变量与结构字段为准。
一、应用时间 vs 执行时间
Timestamps 章的世界观:
- Timestamps 是应用时间上的点;提交顺序由应用(对 MongoDB 即上层)控制,不等于墙上时钟。
- Execution time 是调用实际发生的墙上时间;二者通常同向推进,但不必一一对应。
- 设计目标不是任意时间旅行或分支时间线;允许有限回绕(rollback to stable)。
任意执行时刻存在 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 快照内容
- Maximum transaction ID:创建时全局当前 txn ID;\(\ge\) max 的 ID 不可见。
- Concurrent transaction IDs:创建时仍活跃的事务 ID 列表(不可见);构建时跳过自己的 ID,以及 \(\ge\) max 的并发分配。
- Minimum transaction ID:通常取并发列表中的最小;严格小于 min 的 ID 视为可见(创建前已分配并提交)。
3.3 可见性检查顺序
对给定 txn ID:
- \(\ge\) max →
不可见
- \(<\) min →
可见
- 落在并发列表中 → 不可见
- 否则可见
先做 max/min 边界很重要:并发列表可能为空。
时间戳维度上,更新的 commit timestamp 还要对照读者的 read
timestamp(Timestamps:冲突检测先用 txn ID
看未提交,再用时间戳)。本篇不展开每个可见性函数名;以 Guide
规则与 src/txn/ 为准。
3.4 与 Checkpoint
Checkpoint 使用独立的特殊全局事务与快照。应用侧 snapshot 事务会把 checkpoint 的事务 ID 记为并发事务之一,从而忽略 checkpoint 尚未提交的元数据更改。
四、Prepared(预告)
Timestamps · Prepared transactions:
- Prepare timestamp \(>\) 开始 prepare 时的 stable;durable timestamp \(>\) 提交时的 stable。
- Prepare 后、commit 前:读落在 prepare 与 commit 之间返回
WT_PREPARE_CONFLICT。 - Commit 后、durable 前:若 stable 已过 commit 但未到 durable,读可能不安全;避免不一致暂时是应用责任。
- 与 HS:evict 时 prepared 留在用户 on-disk 页,更旧进 HS(第 08 篇)。
第 11、14 篇回收 prepared 与复制/RTS 的耦合。
五、谱系、争论与开放问题
谱系: Berenson et al., SIGMOD 1995 给出脏读/不可重复读/幻读/Write Skew 等词汇 → 引擎用多版本 + 快照兑现子集 → WT 再把应用时间戳从执行时钟中拆出,以支持 MongoDB 式的全局时间与 prepared。这是工程时间模型,不是新的隔离代数。
争论: 在 unstable 窗口内读是否应更强地由引擎拒绝,而非留给应用——Guide 当前把部分一致性责任放在应用;MongoDB 嵌入后责任上移到服务器。本系列按 Guide 写清契约,不在此改设计。
开放问题:
- oldest
推进与复制延迟、长游标、
minSnapshotHistoryWindowInSeconds的耦合(第 08、14–15 篇)。 - prepared 的 durable 与 checkpoint 交错导致的不一致窗口,生产上如何被 MongoDB 收死(第 11、14 篇)。
六、收束
- Oldest / stable / pinned 界定可读历史与可丢弃历史;不稳定侧可被 RTS 丢掉。
- 默认 snapshot 隔离:快照用 max/min/并发 txn ID 列表决定可见性;时间戳决定应用时间轴上的版本。
- 下一篇已发布的 History Store 回答:版本物理上放哪;再往后第 9–11 篇回答 checkpoint / journal / RTS 如何收束时间戳。
参考资料
规范 / 官方文档
- WiredTiger Architecture Guide, Timestamps:https://source.wiredtiger.com/develop/arch-timestamp.html
- WiredTiger Architecture Guide, Snapshot:https://source.wiredtiger.com/develop/arch-snapshot.html
- WiredTiger Architecture Guide, History Store、Rollback to Stable
论文
- Berenson, H., et al. A Critique of ANSI SQL Isolation Levels. SIGMOD, 1995。
源码
mongodb-8.0:src/include/txn.h、timestamp.h、timestamp_inline.h;src/txn/
站内
上一篇:Reconciliation
下一篇:History
Store 与 Durable History
同主题继续阅读
把当前热点继续串成多页阅读,而不是停在单篇消费。
【WiredTiger 内核】History Store 与 Durable History:文档库里的第三种 MVCC
拆解 MongoDB WiredTiger 如何把旧版本挪到 History Store(WiredTigerHS.wt),在 reconciliation / eviction 后仍服务快照读;对照 PostgreSQL 堆版本与 InnoDB undo,并交代 Lookaside 到 Durable History 的工程分叉。
【WiredTiger 内核】文档库存储引擎全景:MongoDB 默认引擎的生态位
定位文档库默认引擎 WiredTiger 相对 PG/InnoDB/SQLite/RocksDB 的生态位;钉住 Session→Cache→Reconcile→HS→Checkpoint 主线、站内分工与 17 篇阅读路线,并以 Berenson 隔离词汇与 Durable History 为学术/工程锚点。
【WiredTiger 内核】B-Tree 与 update chain:未提交更新只挂链
拆解 WiredTiger row-store B-Tree 的 WT_BTREE/WT_REF 结构,以及叶页上 WT_INSERT skiplist 与 WT_UPDATE 链如何承载插入与多版本;说明未提交更新不进磁盘镜像,为 Reconciliation 与 History Store 铺垫。
【WiredTiger 内核】Rollback to Stable:把库收到稳定时间戳
拆解 WiredTiger RTS:按 durable/stable 与 recovery checkpoint snapshot 判定不稳定更新,读 History Store 写回用户表,并在启停与 API 路径上独占运行;说明与 prepared、checkpoint、eviction 的交互边界。