mace 记录 -- 恢复
mace 的恢复基于 ARIES 实现,但不同于 update-in-place 的实现,mace 中实现了内存事务,并且树的分裂拆分为了两个阶段,并且任意线程都能辅助完成,因此 mace 的恢复 update-in-place 的实现来说要简单不少,只需要关注数据本身,而不需要关注树的 SMO
mace 通过一个“meta文件”控制恢复的行为
- 如果meta或者wal不存在,那么就认定这是一个新的instance
- 如果meta不存在但有wal,那么就扫描wal尝试恢复
- 如果meta存在且完整,那么无需恢复
- 如果meta存在但损坏,那么按照2处理
- 如果2过程中发现数据文件损坏,放弃恢复并报错
wal
WAL 服务于 txn abort 和 crash recovery,其中记录了每个修改操作,每个工作线程本地拥有一个日志空间用来记录 WAL entry,后台有一个线程(group commit)遍历所有线程的日志空间获取到当前写入的部分,一起打包写入到文件即
为了保证日志先于数据落盘,mace 使用了一个 FLSN 作为同步手段,表示当前的 wal 文件的大小,每次在刷入 wal 文件后同步给 buffer 模块,每当 arena 释放引用计数时,从 buffer 模块将 FLSN 存放到本地,当 arena 尝试 flush 到disk 时,会检查buffer 中的 FLSN 是否大于 arena 本地的 FLSN,如果满足条件则说明日志已经先于 arena 刷盘
此外为了方便 undo,在 group commit 线程中还为每个事务的 record 设置了 LSN (这里是一个优化点,可以移到工作线程中)
analyze
分析阶段从 checkpoint 处开始,由于是 append-only 的,因不存在 dirty page table,也就不会有通过 page lsn 来判断是否数据是最新的,在 mace 中通过在树中查找记录的 key,比较找到的 key 的版本和日志中的版本,这样来发现数据中的记录是否是最新的,这个过程相较于 update-in-place 来说多了“查找”的过程,因此相对较慢
这个过程中会将日志中较新的记录的位置存到 dirty table 中,同时也会记录未完成的事务的最后一个记录的位置存到 undo table 中
redo
这个过程就是将 dirty table 中的记录应用到数据中,整个恢复的过程不开 GC 也不启动 checkpoint
undo
undo 有两种情况,1. 事务的回滚,2. 恢复时回滚未提交的事务,这两者的逻辑完全相同。由于 mace 是 append-only 的,因此 undo 其实就是做逆向操作,比如:插入的变为删除。逆向操作拥有原操作相同的 key-val 以及 txid,mace 中使用 u32 类型 的cmd 作为区分,同时写入 CLR 避免 undo 时崩溃导致问题
依赖于前面记录的 undo table,根据事务的最后一个位置倒着遍历 wal 文件做逆向操作即可
checkpoint
在 mace 中 checkpoint 又 group commit 完成,它记录到当前最新的 txid 以及当前活跃的事务的 txid,根据配置,每当刷入固定数量的 wal 时就触发 checkpoint。checkpoint 要求立即将 dirty page 刷盘,因此在 arena 中增加上次 flush 的位置,以及一个 flag 来表示 arena 是否已经刷盘,如果以及刷盘,那么 checkpoint 仅作为同步通知告诉 group commit 可以写入 checkpoint 记录到 wal
简单来说,由于有内存事务和不需要关注SMO,mace 中的恢复并不困难,而是需要特别仔细