Skip to content

Review 11 | Transactions

:material-circle-edit-outline: 约 1715 个字 :material-clock-time-two-outline: 预计阅读时间 6 分钟

Basic

Failure Classification

数据库系统可能出现的故障

  • 发生在数据库应用里的是事务故障出现在单个事务里,比较局部,一般直接rollback
  • DBMS和OS的故障就是系统崩溃,是全局性的,一堆事务都会受影响,也需要日志去恢复
    • 比如死锁需要牺牲一个事务,我们称这个被牺牲的事务发生了系统故障,这不是他自己的问题;还有突然断电也是系统故障
  • Database的故障就是磁盘故障,解决思路就是多备份,还是得借用日记去恢复

image-20240603191711558

Storage Structure

  • Volatile storage
    • not survive system crashes, like main memory, cache memory
  • Nonvolatile storage
    • survives system crashes, like disk, tape, flash memory
  • Stable storage
    • 理想化的存储结构,100%不会出问题,只存在于理论中

Log-Based Recovery

log 存储在 stable storage(稳定存储器),是一个序列/线性文件,包含的元素是 log records,记录各种会影响数据库的操作信息,特别是 update

  1. \(T_i\) 开始会记录 <Ti start>
    • Ti 是这个事务的 id,每个事务的标识符
  2. 执行 write(X) 操作,日志会先记录 <Ti, X, V1, V2>, V1 旧,V2
  3. 事务完成最后一个statement后,记录 <Ti commit>
  4. 事务要 rollback ,记录 <Ti abort>

image-20240603205826000

恢复现场(redo pass)repeating history(重复历史),没有 commit 的或没有 abort 的事务就放进 undo list,undo pass 撤销 undo list 的事务已经执行的操作

Write-Ahead Logging or WAL(先写日志原则),事务commit结束的标志是其对应的log commit记录写入了stable storage

Checkpoints

设置检查点的操作如下:

  1. 先让目前所有还在主存的日志都写入 stable storage
  2. 再让所有目前主存里已修改的block写出去,保证前面的操作已经全部写入了数据库
  3. 日志记录 <checkpoint L>,L 是此时正在运行的事务表,包含所有正在进行的事务

设置检查点时会中断所有的 update 操作

image-20240603212727718

Fuzzy Checkpointing

模糊的检查点,只刷日志不刷脏数据,会记录此时哪些block是脏的,以此减少写检查点的stall

多一个指向检查点的指针 last_checkpoint ,等一个检查点所有被记录的脏数据都被写出去了,last_checkpoint 就会指向这个检查点

Recovery with Early Lock Release and Logical Undo

不是严格两阶段锁协议的情况,undo 需要使用 logical Undo ,如果你加了300,那么我就减 300,而不是直接用旧数据覆盖

操作的 log record 是从 undo 角度记录的,还没end就crash的操作还是只能用物理undo实现

image-20240603224146632

ARIES Recovery Algorithm

ARIES Database

每个日志record都有一个严格单增的 Log sequence number (LSN) ,类似id

image-20240603230117407

  • 左下角就是磁盘/数据库,里面我们假设有四个 page
    • P1 17 表示 P1 这个 page 已经被写入 pageLSN=17 对应的操作需要写的数据
  • 右边的大表就是 \(log\; file\),同一个颜色对应同一个事务
    • PrevLSN 指向同一事务上一个record
    • TNO 就是事务 id
    • TYPE 指示该record 对应的操作类型,u 就是 update
    • PID 指示操作的页,与 lenoffset 共同指示要修改的数据段位置
    • beforeafter 即修改前后数据
    • checkpoint 只保存 Dirty Page Table 和 当前事务表(Active TXN Table)
  • 左边的 \(Active\; TXN\; Table\) 即当前事务表
    • 记录目前的活跃的事务中最新的已执行的操作
  • 上面的 \(Buffer \;Pool\) 即缓冲池,存放还没被写入数据库的脏数据
    • 对应的数字就是已经执行好的操作,但还没写入数据库
  • 左上角的 \(Dirty\; Page\; Table\) 记录脏数据,已经这个脏数据哪些操作造成的修改还没被写入数据库
    • 记录当前的 buffer pool 里哪些是脏数据
    • PageLSN 记录最新的已执行操作,RecLSN 记录最远的还没写入数据库的操作
    • 比如,我们只关注page P1,其相关的操作共有 LSN =15,17,20,22 四个,15和17已经写入数据库了,20和22还没写入,还滞留在缓冲里,可能会丢失

此外,还有 redo-only log record called compensation log record (CLR) ,用来记录永远不需要被 undo 的恢复操作,其有一个 UndoNextLSN 用于标记上一条需要被 undo 的record,这中间的 record 都是已经undo完成了的

image-20240620210541684

UndoNextLSN 用于 undo 过程中出故障的情况,这样重新开始恢复时就不需要 undo 已经 undo 过的了

Aries Recovery: 3 Passes

Analysis pass

Analysis pass 从最后一个检查点出发,读取里面的脏页表,找出最小的 RecLSN作为 redo 的起点,记为 RedoLSN;如果没脏表就用检查点的 LSN

关于构建 undo-list ,先把检查点里的当前事务表 ATT 包含的事务全部放进去,同时读取这些事务目前读取到的最新的 LSN,并在后面的分析中不断更新,这个会在 undo 时用到

然后从检查点开始往下找,发现有 record 对应的事务不在 undo-list 的,就把对应的事务放进去

如果发现有 update 类型的 record,就看其写的 page 在不在脏页表,如果不在就将这个 page 放入脏页表,并将 RecLSN 设置为相关的最新 LSN

如果发现事务执行结束的 record,就将这个事务移出 undo-list

执行到log最后,分析就结束了

这时,你得到了 RedoLSN 用于确定从哪开始 redo pass,脏页表和 RecLSN 用于减少 redo工作量,undo-list的事务都要被回滚

Redo pass

scan forward 是指 log file 往下读,该死的洋文

RedoLSN 开始,检查 update record,如果写的 page 不在脏页表就不用管,如果 LSN 小于 RecLSN 也不用管,如果 pageLSN 大于 record LSN,也不用管,否则就要 redo

Undo Pass

redo 完按照 undo-list 里现有的事务,准备进行 undo

undo 是一个事务一个事务来的,先undo完一个事务再undo下一个事务,undo顺序按照各事务最后一条record的LSN从近到远

我们给 undo-list 的每个事务都设置一个所谓的 next LSN,指向这个事务下一条要 undo record,然后我们每次 undo 的是 next LSN 中最新的那个

analysis 时我们找出了 undo-list 里每个事务的最新的 LSN 用于初始化 next LSN

我们先从 undo-list 里最新的日志开始 undo,如果遇到了 CLR,就跳转到 UndoNextLSN 进行 undo,如果不是 CLRs,只是普通的 record,我们就将下一条需要 undo 的日志设置为这条日志的 PrevLSN,同时写一条对应的 CLR,UndoNextLSN 即 PrevLSN,知道事务的开头

然后 undo 下一个事务,直到全部 undo 完

最后是个恢复例子:

image-20240603231929819