利用checkpoint来去批量刷新到磁盘,在日志重做的时候,就可以在这个点后重新回放对应的东西,然后把没提交的东西回滚
fuzzy checkpoint
记录checkpoint的起始和结束,start以后的事务无需放置在checkpoint里面,因为之后的事务后面去提交,无需跟随fuzzy checkpoint放置在log中。同时将对应的脏页刷新到磁盘中。
起始: 就记录start
结束 包括att和dtp
为了达成这个目的,需要以下结构
active transaction table 活动的事务 ATT
对于每个活动的事务,我们需要记录
txnId transactionId
status 当前事务的模式 Running Committing Candidate for Undo
lastLSN 最近的lsn
dirty page table DTP脏页
bufferPool中的RecLsn 其中最早的引起页变脏的一个lsn
回滚
analysis (灰色)分析哪些事务已经提交了,哪些已经failed了
redo(浅蓝色)重复所有的动作
undo(深蓝色)回滚所有的失败的动作(包括未提交的)
mysql回滚具体
1 初始化崩溃恢复
数据库关闭只有2种情况,正常关闭,非正常关闭(包括数据库实例crash及服务器crash)。
正常关闭情况,所有buffer pool里边的脏页都会都会刷新一遍到磁盘,同时记录最新LSN到ibdata文件的第一个page中。而非正常关闭来不及做这些操作,也就是没及时把脏数据flush到磁盘,也没有记录最新LSN到ibdata file。
当我们重启数据库实例的时候,数据库做2个阶段性操作:redo log处理,undo log及binlog 处理。
1.1 redo log处理
- 打开系统表空间ibdata,读取第一个page中的LSN,若第一个页损坏,则依次往后面的page读,知道有个完整的page能够提供LSN,这个LSN当作上次shutdown时的checkpoint点,后续恢复,从这个LSN点开始恢复
- 进入redo log文件,读取第一个redo log文件头的checkpoint LSN, 并根据该LSN定位到redo日志文件中对应的位置,从该checkpoint点开始扫描,进行3次redo log文件扫描:
-
- 第一次,找 MLOG_CHECKPOINT日志
-
-
- 如果是正常关闭,这个日志是不做记录的,也就是扫描的过程中不回找到对应的MLOG_CHECKPOINT日志,不会进行接下来的两次扫描,因为属于正常关闭数据库服务,不需要考虑奔溃恢复情况;
-
-
-
- 如果是非正常关闭,则会查找到 MLOG_CHECKPOINT (如果是多个,则说明redo文件已损坏,恢复报错),获取MLOG_FILE_NAME中指定后续需要恢复的ibd文件;
-
-
- 第二次,从redo log读到的LSN,找到checkpoint点开始重复扫描存储日志对象
-
-
- 根据MLOG_CHECKPOINT日志,读取对应LSN之后的日志解析到hash表中,如果剩下的日志解析结束后还没有填满hash表格,则不需要进行第三次扫描;
-
-
-
- 进行到这里,则说明数据库是非正常关闭,会在errorlog中提示:Database was not shutdown normally!详见下图。
-
-
- 第三次,若第二次扫描hash表空间不足,则发起第三次扫描,清空hash表空间,重新从新的checkpoint点开始扫描
-
-
- 如果第二次扫扫描就把hash表填满,那么会先把hash表里边的记录重做到buffer pool中的数据页,然后再来加载redo log 记录到被清空的hash表中,hash表满后立即执行恢复操作,知道所有需要redo 的redo log 被应用结束。
-
恢复的过程中,注意两个点:打开ibd文件形式,读取数据库到buffer pool的改进。
根据hash表中的相应信息读取数据页, 读数据页的时候,5.7之前版本采用把所有表空间都打开,所有表格仅执行ReadOnly,5.7版本做了优化,新增了 MLOG_FILE_NAME 记录在checkpoint之后,所有被修改过的信息,根据这些信息,在恢复过程中,只需要打开相应的ibd文件即可,不涉及恢复的表格支持正常DML跟DDL操作,涉及恢复的表格则仅执行ReadOnly功能。
当把数据页读取到buffer pool中,以往版本是只读取对应的单个页面,而现在的是直接读取与该页面相邻的32个data page 也一起加载的buffer pool,因为一个数据页的修改,可能周围的页面也被修改,一次性读取,可以避免后面根据hash表中再重新读取其相邻的页面。
1.2 undo log及binlog 处理
上一阶段中,把redo log中的操作都apply到数据页中,但是对于prepare状态的事务却还没有进行回滚处理,这个阶段则是针对prepare状态的事务进行处理,需要使用到binlog和undo log。
- 根据最后一个binlog文件,为啥不是所有binlog文件呢?因为每一个binlog文件切换的时候,都会确保当前binlog文件的所有操作已落盘,所以只需要考虑最后一个binlog文件。跟进最后一个binlog文件,获取所有可能没有提交事务的xid列表;
- 根据undo log中的 insert_undo_list,upddate_undo_list事务链,构建undo_list,在根据undo_list构建未提交事务链表;
- 从未提交事务链表中,提取出xid,凡是存在于xid列表中的,则需要提交,不存在的,则回滚。
后面转载自 https://www.cnblogs.com/xinysu/p/6586386.html