日志
1.日志包含的记录:
<T, X, V1, V2>: 表示事务T对X的修改,将V1修改为V2
<T start> 事务T开始
<T commit> 事务T提交,指的是最后一次更改已经写入。
<T abort> 事务T中止, undo完成后写入日志
<checkpoint L> 检查点
<T, X, V2> redo only
撤销和重做
redo: 把每个redo only都做一次
undo: 把每一个修改记录都修改为旧值,添加一个redo only记录
undo 相当于撤销, redo相当于重做。这些都是没有崩溃时候正常操作。
redo-only 不会对redo only进行undo,即不会undo undo的结果。
恢复算法
重做阶段,自上往下
1.把undo_list设置为最后一个checkPoint中的L
2.遇到正常日志和redo only日志,都重做
3.遇到start 把T加入undo_list
4.遇到abort, commit,把T从undo_list去掉
撤销阶段,自下往上
1.遇到了undo_list里的事务,执行undo
2.发现start,则将事务T abort写入log,然后将其取出undo_list
Aries 恢复算法
LSN: 一条日志唯一的标识
和页相关的:
PageLSN: 最新一次修改的日志序号
RecLSN: 第一次修改这个页的日志序号
和事务相关的:
LastLSN: 一个事务写的最后一条日志
和日志相关的:
CLR, 指的是undo时产生的redo_only的日志
包含一个UndoNextLSN, 指向回滚时下一个需要undo的CLR
恢复算法:
分析阶段,从老->新
1.找到最后一个检查点,将RedoLSN设置为脏页表中最小的RecLSN
如果没有脏页表,设置为检查点的LSN
2.将undo_list初始为checkPoint中的事务
3.从RedoLSN开始老->新进行检查,如果遇到不在undo_list中的事务,将其加入undo_list,遇到end, 将事务删除。
4.如果遇到了更新页的日志,如果该页不在脏页表,将其加入,设置RecLSN为当前记录的LSN
简单来说,就是从RedoLSN到最新的日志,所有的page加入脏页表,所有没有commit或者abort的事务加入undo_list
重做阶段,老->新
1.从RedoLSN开始扫描,找到更新页的日志
2.如果该日志LSN小于RecLSN或者该页不在脏页表,则跳过
如果PageRec小于LSN,则重做
撤销阶段,新->老
1.找到一个undo_list中事务的更新记录,执行undo,产生一个CLR,将CLR的UndoNextLSN设置为当前记录的PreLSN
2.遇到CLR,则跳往它的UndoNextLSN
3.遇到start,将其从undo_list删除