说明
文章的图片来源《MySQL是怎么运行的:从根儿上理解MySQL》,本篇文章只是个人学习总结,欢迎大家买一本正版小册看看,对于mysql是由浅入深的讲解非常细致
目录
23.undo日志(下)
通用链表结构
链表的基节点
FIL_PAGE_UNDO_LOG页面
- FIL_PAGE_INDEX:存储聚簇索引或者是二级索引的数据页类型
- FIL_PAGE_TYPE_FSP_HDR:描述存储表空间的头部信息
- FIL_PAGE_UNDO_LOG:专门用于存储undo页面
undo页面特有的Undo Page Header
- TRX_UNDO_PAGE_TYPE:存储什么类型的undo日志,分了几个类
- TRX_UNDO_INSERT:包含TRX_UNDO_INSERT_REC
- TRX_UNDO_UPDATE:包括TRX_UNDO_DEL_MARK_REC和TRX_UNDO_UPD_EXIST_REC
- TRX_UNDO_PAGE_START:从页面什么位置开始存储undo日志
- TRX_UNDO_PAGE_FREE:最后一条日志的偏移量
- TRX_UNDO_PAGE_NONE:代表一个ListNode结构
Undo页面链表
单个事务中的Undo页面链表
- 一个事务产生多个日志可能一个页面放不下,就需要多个页面,通过TRX_UNDO_PAGE_NONE链表节点结构进行串联
- first undo page是第一个页面还记录了链表管理信息,其它就是normal undo page
- 一个页面只能保存一种类型的undo日志,所以需要两条链表一条是insert,另一条是update
- 而且对于临时表和普通表的undo日志也需要进行分开记录
但不是一开始就这么分配,具体的分配策略
- 刚开启事务,不分配undo页面
- 事务插入记录到普通表,生成insert undo链表
- 如果事务对普通表更新和删除,那么就分配一个update undo链表
- 如果事务对临时表更新删除或或者是插入那么就会创建对应的链表
按照需要进行分配
多个事务中的Undo页面链表
不同事务产生的undo日志写入到不同的undo链表中
- 下面就是对于事务1进行临时表增删改和普通表更新,对事务2进行普通表增删改。
undo日志具体写入过程
Undo Log Segment Header
- 每一个undo log链表对应着一个段叫undo log segment。链表页面就是在这个段上面去申请。所以对于每个链表的第一个页面first undo page都会有一个undo log segment header的部分。包含了undo log segment的信息
看看这个header的结构
- TRX_UNDO_STATE:链表处于什么状态
- TRX_UNDO_LAST_LOG:最后一个Undo Log Header的位置
- TRX_UNDO_FSEG_HEADER:链表对应段segment header的信息,可以找到对应的INODE Entry
- TRX_UNDP_PAGE_LIST:undo链表的基节点
Undo Log Header
- 对于每个事务来说,每条undo页面链表都是一个组,而且每次都是直接插入记录,不够了就继续申请。那么记录组的属性的就是Undo Log Header
- 属性的意思
重用Undo页面
决定是否可以重用的条件
- 链表里面只有一个undo页面
如果事务产生undo日志太多,那么就会导致链表需要维护很多的页面。
- undo页面只是使用了小于页面空间的3/4
链表重用的不同策略
- insert undo链表
这种值存储TRX_UNDO_INSERT_REC的undo日志,提交之后就没用了,可以直接删除。也就是提交之后就可以覆盖这条链表
- update undo链表
提交之后不能立刻被删除用于mvcc,那么如果要重用相当于就是写入多组的undo log
回滚段
回滚段的概念
- 一个事务同时可以拥有4个链表,同一时刻有多个不同事务的undo链表。
- 所以需要一个Rollback Segment Header存储的是每个链表的first undo page页号这种页号称为undo slot。
- Rollback Segment Header对应着一个Rollback Segment,但是这个段只有一个页。为了某种目的分配的空间通常就是一个段
Rollback Segment Header对应的各个属性
- TRX_RSEG_MAX_SIZE:所有undo页面链表的页面之和不能大于max_size
- TRX_RSEG_HISTORY_SIZE:History链表占用的页面数量
- TRX_RSEG_HISTORY:History链表的基节点。
- TRX_RSEG_UNDO_SLOTS:每个链表的first undo page 集合
从回滚段中申请Undo页面链表
没有事务
- FIL_NULL:说明现在的Rollback Segment Header页面的undo slot没有指向任何页面
现在开始有事务
-
FIL_NULL的话那么就检查回滚段的第一个slot,如果是FIL_NULL那么就去表空间申请一个段(UNDO LOG SEGMENT)并且申请一个页作为first undo page
-
如果不是FIL_NULL那么就跳到下一个slot
-
现在说明一下回滚段和上面的undo log segment的一个区别。回滚段存储的主要是每个事务的页面链表的第一个页面,对于undo log segment来说其实就是对于每个事务都有自己的一个段,需要段去管理这些事务的日志,那么取出来的时候就能够一下子顺序IO取出来,因为可能一个事务产生的日志页占用大量的空间。
-
如果slot满了,那么就会报错,用户可以选择重新执行或者是放弃执行。
如果事务提交了,对于slot的处理
-
如果是可以重用,也就是slot的链表只占用一个页或者是占用页的空间不到3/4那么这个链表状态TRX_UNDO_STATE就会被设置为TRX_UNDO_CACHED
- insert链表加入到insert undo cached链表
- update加入到update undo cached链表
如果有新事务那么先去cached申请slot,如果没有那么才去Rollback Segment Header页面上去寻找
-
slot如果不符合重用
- insert链表的TRX_UNDO_STATE被设置为TRX_UNDO_TO_FREE(说明链表可以使用),并且链表对应的段也会被释放掉。slot变为FIL_FULL
- update链表状态设置TRX_UNDO_TO_PRUGE,slot设置为FIL_FULL并且把事务产生的日志写到History链表上面去。
多个回滚段
- 回滚段的slot不够那么就创建多几个回滚段,通常是128个回滚段。
- 每个回滚段对应一个Rollback Segment Header页面
- 页面的地址存储在上面的这个5号页的128个8字节大小的小格子上。
- 每个格子的构造指向不同的回滚段
总体结构就是5号页存储回滚段,回滚段存储各种链表slot。
回滚段的分类
- 0号,33-127号回滚段属于一类,0号存在系统表空间,其它33-127可以存在其它表空间(系统或者是undo表空间)
事务对普通表的修改
- 1-32:必须要在临时表空间(ibtmp1文件)
事务对临时表的修改
为什么要分类
- 修改页面之前需要把redo日志写上。那么才能在系统崩溃之后恢复
- undo日志其实也是一个写过程,也就是和普通页的修改都是要存入redo log的。但是对于修改临时表的undo log来说在运行系统时才有效,也就是不运行就无效,不需要写入redo log,也就不需要恢复了。
为事务分配Undo页面链表详细过程
- 事务修改表前,先去5号页分配一个回滚段
- 先查看cached链表是否有slot链表可以重用
- 那么只能在Rollback Segment Header找到一个可使用的slot分配给事务
- 如果slot没有分配一个undo log segment那么就分配一个
- 最后就可以把对应的undo日志写到链表上
回滚段相关配置
- innodb_rollback_segments普通表对应的回滚段
配置undo表空间
- innodb_undo_directory指定undo表空间的位置目录
- innodb_undo_tablespaces定义undo表空间的数量
总结
-
undo log segment就是针对于一个undo链表。如果链表需要申请空间,那么就要去段上面去申请。段其实对应着一个INODE Entry节点
-
对于多个header的不同作用
- Undo Log Segment Header主要是对于每个链表段的节点位置和链表的状态(状态主要是用于是否重用,处于什么处理的状态)
- Undo Page Header:主要就是处理页面的类型、页面存储第一条和最后一条记录的位置还有就是链表结构。
-
关于重用的过程
- 判断slot是否能够重用,可重用(对应占用一个页而且占用空间小于3/4)那么就加入链表
- 下次事务增删改普通表的时候就可以重用这个cached链表上面的slot。
-
关于链表的分类
- update
- insert
-
回滚段的分类
- 临时表回滚段
- 普通表回滚段
为了让redo log的压力不那么大,因为临时表并不需要写入到redo log,系统崩溃是不需要恢复临时表的。只在系统运行的时候使用
-
回滚段的作用
-
保存各个链表头
-
管理链表重用问题
-
判断slot是否能够重用,可重用(对应占用一个页而且占用空间小于3/4)那么就加入链表
-
下次事务增删改普通表的时候就可以重用这个cached链表上面的slot。
-
-
关于链表的分类
- update
- insert
-
回滚段的分类
- 临时表回滚段
- 普通表回滚段
为了让redo log的压力不那么大,因为临时表并不需要写入到redo log,系统崩溃是不需要恢复临时表的。只在系统运行的时候使用
-
回滚段的作用
- 保存各个链表头
- 管理链表重用问题