MySQL InnoDB undo log生成逻辑分析

目录

引用《InnoDB存储引擎》中有一句话,特别重要:

1、初始化回滚段

2、分配回滚段

3、使用回滚段

4、写入undo log


引用《InnoDB存储引擎》中有一句话,特别重要:

用户通常对undo有这样的误解:undo用于将数据库物理地恢复到执行语句或事务之前的样子---但事实并非如此。

undo是逻辑日志,因此只是将数据库逻辑地恢复到原来的样子。所有的修改都被逻辑地取消了,但是数据库和页本身在回滚之后可能大不相同。

MySQL InnoDB undo log数据结构分析

1、初始化回滚段

回滚段的初始化在InnoDB引擎启动时就已初始化好,它主要通过三个函数调用,最终在表空间初始化函数srv_undo_  tablespaces_init中,初始化了128个回滚段

2、分配回滚段

当开启一个事务后,需要给当前的事务分配一个回滚段,调用它的函数流程关系为:

trx_assign_rseg-> trx_assign_rseg_low-> get_next_noredo_rseg:对于只读事务,如果产生对临时表的写入,则需要为其分配回滚段,使用临时表回滚段(第1~32号回滚段)。

trx_set_rw_mode-> trx_assign_rseg_low-> get_next_redo_rseg:在MySQL5.7中事务默认以只读事务开启,当随后判定为读写事务时,则转换成读写模式,并为其分配事务ID和回滚段。

在源码中的具体代码为:

 

普通回滚段的分配方式如下:

  1. 采用round-robin的轮询方式来赋予回滚段给事务,如果回滚段被标记为skip_allocation,则跳到下一个;
  2. 选择一个回滚段给事务后,该回滚段的rseg->trx_ref_count会递增,这样该回滚段所在的undo tablespace文件就不可以被truncate掉;
  3. 临时表回滚段被赋予trx->rsegs->m_noredo,普通读写操作的回滚段被赋予trx->rsegs->m_redo;如果事务在只读阶段使用到临时表,随后转换成读写事务,那么会为该事务分配两个回滚段。

3、使用回滚段

使用undo log时也需要判断undo log的类型,记录下变更前的数据以维护多版本信息。insert 和 delete/update 分开记录undo log,因此需要从回滚段单独分配undo slot。

从下面源代码中可以看出,无论是TRX_UNDO_INSERT_OP还是TRX_UNDO_MODIFY_OP类型,都调用trx_undo_assign_undo函数。

函数trx_undo_assign_undo的流程如下:

4、写入undo log

将undo log写入到回滚段的总流程如下:

省略不重要的步骤,单看最重要的函数调用:

分析:

通过trx_undo_report_row_operation函数,首先会分配了一个undo slot,调用的函数为trx_undo_assign_undo。分配分配好slot同时初始化完可用的空闲区域后,就可以向其中写入undo记录了。写入的page no取自undo->last_page_no,初始情况下和hdr_page_no相同。然后根据undo log的类型来判断是分配insert undo log还是update undo log。

对于INSERT_UNDO,调用函数trx_undo_page_report_insert进行插入,对于UPDATE_UNDO,调用函数trx_undo_page_report_modify进行插入。

比如,对于较为复杂的update undo log来说,写入undo log的过程是通过一个指针ptr将各种信息写入到指针指向的区域,从源代码中trx_undo_page_report_modify函数可以看到具体的实现:

        后面会有循环在不断往ptr所指向的地址写各个字段的数据,

        …….

        然后,会将指针写入上一个和下一个回滚日志记录:

最后将UNDO日志中更改的信息写入REDO日志,这也证明了写undo log时也会写redo log。undo log也需要持久性的保护。

完成undo log写入后,构建新的回滚段指针并返回(trx_undo_build_roll_ptr),回滚段指针包括undo log所在的回滚段id、日志所在的page no、以及page内的偏移量,需要记录到聚集索引记录中。

下面是两次实测结果:

已知开启的事务已经执行完3次update操作,第一张图中,当前事务在第4次update时,top_page_no不变,仍在331号页,但是,top_offset偏移量从2192变为2228,并且top_undo_no由2变3;第二张图中,此事务在第5次update操作时,top_page_no不变,仍在331号页,但是,top_offset偏移量从2228变为2264,并且top_undo_no由3变4。

分析可知:写undo log记录时,在当前的undo页偏移位置开始写undo log记录,通过偏移量来记录undo log,并且top_undo_no每次记录顺序加1,这也证明了undo log顺序写。

下面两张图实测了update操作十万多次的结果:

可以看到:随着undo log写入的越多,top_page_no也在不断变大。

### MySQL 中 BinlogUndo Log 和 Redo Log 的概念及区别 #### 1. Redo Log (重做日志) Redo logInnoDB 存储引擎特有的物理日志,记录的是数据页的物理更改内容。当事务提交时,这些更改会被先写入 redo log 缓冲区并最终持久化到磁盘上的 redo 日志文件中[^1]。 - **特点**: 循环写入,日志空间大小固定。 - **用途**: 主要用于崩溃恢复,在发生意外宕机或介质故障后能够快速恢复未完成的数据页更新操作。 ```sql -- 示例:查看当前实例的redo log配置 SHOW VARIABLES LIKE 'innodb_redo%'; ``` #### 2. Undo Log (撤销日志) Undo log 同样由 InnoDB 维护,它保存了旧版本的数据副本以便支持回滚操作以及实现多版本并发控制(MVCC)[^3]。 - **特性**: - 支持事务的原子性和一致性; - 提供 MVCC 功能,允许不同时间点读取不同的数据视图而不被其他正在运行中的事务干扰。 - **应用场景**: - 当事务需要回滚时,可以通过 undo log 进行逆向处理来撤消已做的变更; - 对于长时间运行的大查询来说非常重要,因为它们依赖于一致性的快照读取而不会阻塞其他写入者。 #### 3. Binlog (二进制日志) Binlog 则是由 MySQL Server 层维护的一类逻辑日志,其记录形式取决于所选的日志格式(STATEMENT/ROW/MIXED),通常情况下是以事件的方式描述SQL语句及其影响的结果集变化情况[^2]。 - **特征**: - 文件追加方式写入,即每次新产生的日志都会附加到现有文件之后直到达到设定的最大尺寸再创建新的文件继续记录; - 不同于 redo log, binlog 并不是针对特定表结构而是整个服务器层面的操作历史档案。 - **功能应用**: - 数据库主从同步的基础工具之一; - 基于增量备份策略下的灾难恢复手段; - 审计追踪——通过分析 binlogs 来监控数据库活动模式。 --- 总结而言: | 特性 | Redo Log | Undo Log | Binlog | | --- | --- | --- | --- | | 所属层次 | InnoDB 引擎层 | InnoDB 引擎层 | MySQL Server 层 | | 记录类型 | 物理日志 | 逻辑日志 | 逻辑日志 | | 写入方式 | 循环覆盖 | 随需分配 | 追加写入 | | 主要目的 | 故障恢复 | 回滚与MVCC | 复制和审计 |
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值