为了提升分配 undo 段的效率 , 事务提交过程中,InnoDB 会缓存一些 undo 段 。只要同时满足两个条件,insert undo 段或 update undo 段就能被缓存 。1. 关于缓存 undo 段为了提升分配 undo 段的效率,事务提交过程中 , InnoDB 会缓存一些 undo 段 。
只要同时满足两个条件,insert undo 段或 update undo 段就能被缓存 。
条件 1:undo 段中只有一个 undo 页 。
条件 2:这个唯一的 undo 页中,已经使用的的空间必须小于数据页大小的四分之三 。以默认大小 16K 的 undo 页为例,undo 页中已经使用的空间必须小于 12K 。
如果 insert undo 段满足缓存条件 , 它会加入回滚段的 insert_undo_cached 链表头部 。
如果 update undo 段满足缓存条件 , 它会加入回滚段的 update_undo_cached 链表头部 。
2. InnoDB 提交事务二阶段提交过程中,commit 阶段的 flush 子阶段,把 prepare 阶段及之前产生的 redo 日志都刷盘了,把事务执行过程中产生的 binlog 日志都写入 binlog 日志文件了 。
sync 子阶段根据系统变量 sync_binlog 的值决定是否触发操作系统把 binlog 日志刷盘 。
前两个子阶段,都只处理了日志 , 不涉及 InnoDB 的事务 。这两个阶段完成之后,InnoDB 的事务还没有提交,事务还处于准备提交状态(TRX_STATE_PREPARED) 。
【MySQL 核心模块揭秘,你看明白了吗?】commit 子阶段才会真正提交 InnoDB 的事务,这个阶段完成之后,事务就提交完成了 。
commit 子阶段提交 InnoDB 的事务,要做的事情有这些:
- 修改 insert undo 段的状态 。
- 生成事务提交号 , 用于 purge 线程判断是否能清理某些 update undo 日志组中的 undo 日志 。
- 修改 update undo 段的状态 。
- 把 update undo 段中的 undo 日志组加入回滚段的 history list 链表 。purge 线程会从这个链表中获取需要清理的 update undo 日志组 。
- 把事务状态修改为 TRX_STATE_COMMITTED_IN_MEMORY 。
- 释放事务执行过程中 InnoDB 给表或记录加的锁 。
- 重新初始化事务对象,以备当前线程后续使用 。
如果事务插入记录到用户临时表,InnoDB 会为事务分配另一个 insert undo 段 。
InnoDB 可能会给事务分配 0 ~ 2 个 insert undo 段 。commit 子阶段会修分配给事务的所有 insert undo 段的状态 。
如果 insert undo 段满足缓存条件,它的状态会被修改为 TRX_UNDO_CACHED,否则,它的状态会被修改为 TRX_UNDO_TO_FREE 。
事务提交完成之后,InnoDB 会根据状态缓存或者释放 insert undo 段 。
2.2 生成事务提交号事务提交号是事务对象的 no 属性,通常用 trx->no 表示 。
代码里,对事务提交号的注释是 transaction serialization number,直译成中文应该称为事务序列号,或者事务串行号 。
因为 trx->no 是在事务提交时生成的 , 我们还是把它称为事务提交号更容易理解一些 。
只有 update undo 段需要事务提交号 。purge 线程清理 update undo 日志时 , 会根据 update undo 段的 undo 日志组中保存的事务提交号,决定是否能清理这个 undo 日志组中的 undo 日志 。
修改 update undo 段的状态之前 , InnoDB 会生成事务提交号 , 保存到事务对象的 no 属性中 。
// storage/innobase/trx/trx0trx.ccstatic inline bool trx_add_to_serialisation_list(trx_t *trx) {...trx->no = trx_sys_allocate_trx_no();...}
trx_sys_allocate_trx_no() 调用 trx_sys_allocate_trx_id_or_no() 生成事务提交号 。// storage/innobase/include/trx0sys.ic// 生成事务 IDinline trx_id_t trx_sys_allocate_trx_id() {ut_ad(trx_sys_mutex_own());return trx_sys_allocate_trx_id_or_no();}// 生成事务提交号inline trx_id_t trx_sys_allocate_trx_no() {ut_ad(trx_sys_serialisation_mutex_own());return trx_sys_allocate_trx_id_or_no();}
从上面的代码可以看到,生成事务 ID 和事务提交号调用的是同一个方法,trx_sys_allocate_trx_id_or_no() 的代码如下:// storage/innobase/include/trx0sys.icinline trx_id_t trx_sys_allocate_trx_id_or_no() {...// trx_sys_allocate_trx_id_or_no() 每次被调用// trx_sys->next_trx_id_or_no 加 1// trx_id 保存的是加 1 之前的值trx_id_t trx_id = trx_sys->next_trx_id_or_no.fetch_add(1);...return trx_id;}
推荐阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 东航坠机事故,你关心的十大核心问题是什么
- ie浏览器一直弹出修复工具,QQ浏览器怎么设置漏洞模块拦截
- 十八项核心制度闭环管理是什么意思 十八项核心制度闭环管理是什么意思呀
- 从 MySQL 到 ByteHouse,抖音精准推荐存储架构重构解读
- 功率模块自热阻和耦合热阻区别 功率模块自热阻和耦合热阻区别是什么
- 准线上事故之MySQL优化器索引选错
- 什么是网络中的路由器?核心功能解释
- MySQL数据恢复,你会吗?
- 揭秘Sora技术路线:核心成员来自伯克利,基础论文曾被CVPR拒稿
- 如何在MySQL中实现数据的版本管理和回滚操作?