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
的倒序遍历, 根据lsn
和flushed_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
的顺序遍历, 根据lsn
和flushed_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
:- 如果
xid
在att
中:- 如果是
commit
类型, 把xid
从att
删除. - 否则更新
att
中xid
对应的last_lsn
.
- 如果是
- 如果
xid
不在att
中:- 将
xid
和对应的last_lsn
加入att
.
- 将
- 如果
- 更新脏页表
dpt
:- 如果
page_id
不在dpt
中:- 将
page_id
和对应的lsn
加入dpt
.
- 将
- 如果
page_id
在dpt
中:- 跳过, 无需进行处理.
- 如果
- 更新活跃事务表
LogManager::Redo()
选择脏页表dpt
中最小的rec_lsn
作为开始位置, 如果dpt
为, 从开始检查点的位置重做.LogManager::Undo()
通过活跃事务表att
记录的未完成事务进行回滚.
实验耗时
基础功能
事务回滚: 2h.
Redo: 3h.
ARIES 恢复算法: 3h.