数据库专题训练 Lab 2


Lab 2 事务处理与故障恢复

基础功能

事务回滚

日志追加src/table/table.cpp.

  • 插入记录时, 通过 std::make_unique<char[]>(record->GetSize()) 新建一段缓冲区用于记录的反序列化, 在插入记录时增加写 InsertLog 过程, 同时若创建新的页面则增加写 NewPageLog 过程.
  • 删除记录时, 直接增加写 DeleteLog 过程.

事务回滚src/log/log_manager.cpp 中的 LogManager::Rollback().

  • 通过 log_record->GetPrevLSN() 实现 lsn 的倒序遍历, 根据 lsnflushed_lsn_ 的大小关系判断记录日志在 buffer 还是磁盘中.
  • 若日志在磁盘中, 通过 std::make_unique<char[]>(MAX_LOG_SIZE) 新建一段缓冲区用于日志的反序列化, 通过 disk_.ReadLog 读取日志.
  • 若日志在 buffer 中, 从后往前遍历 log_buffer_, 找到 lsn 对应的日志.

Undo 操作src/log/log_records/*.

  • 通过 catalog.GetDatabaseOid() 获取数据库 id, 并通过 buffer_pool 获取相应页面进行操作.

Redo

Redo 日志读取src/log/log_manager.cpp - LogManager::Redo().

  • FIRST_LSN 开始, 通过 lsn += log_record->GetSize() 实现 lsn 的顺序遍历, 根据 lsnflushed_lsn_ 的大小关系判断记录日志在 buffer 还是磁盘中, 其他逻辑与事务回滚相同.

Redo 操作src/log/log_records/*.

  • 通过 catalog.GetDatabaseOid() 获取数据库 id, 并通过 buffer_pool 获取相应页面进行操作.

ARIES 恢复算法流程

ARIES 恢复算法src/log/log_manager.cpp - LogManager::Analyze().

  • end_checkpoint 处获取记录点的脏页表 dpt 与活跃事务表 att.
  • end_checkpoint 开始扫描每一条日志:
    • 更新活跃事务表 att:
      • 如果 xidatt 中:
        • 如果是 commit 类型, 把 xidatt 删除.
        • 否则更新 attxid 对应的 last_lsn.
      • 如果 xid 不在 att 中:
        • xid 和对应的 last_lsn 加入 att.
    • 更新脏页表 dpt:
      • 如果 page_id 不在 dpt 中:
        • page_id 和对应的 lsn 加入 dpt.
      • 如果 page_iddpt 中:
        • 跳过, 无需进行处理.
  • LogManager::Redo() 选择脏页表 dpt 中最小的 rec_lsn 作为开始位置, 如果 dpt 为, 从开始检查点的位置重做.
  • LogManager::Undo() 通过活跃事务表 att 记录的未完成事务进行回滚.

实验耗时

  1. 基础功能

    • 事务回滚: 2h.

    • Redo: 3h.

    • ARIES 恢复算法: 3h.


文章作者: Chengsx
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Chengsx !
  目录