在最近release的8.0.14版本中,开始支持SQL接口来创建,修改和删除 (undo space的管理不记录binlog)。可以预见未来将逐步废弃根据配置innodb_undo_tablespaces来创建undo tablespace, 通过SQL接口来创建undo tablespace将是唯一的接口。实际上在最新版本中已经将参数innodb_undo_tablespaces标记为deprecated状态,用户应尽量避免依赖该参数。
在安装实例时,会默认创建两个undo tablespace:
你可以通过如下语句来创建独立的undo tablespace, 文件后缀必须以ibu结尾。新创建的tablespace为active状态
在创建undo space时,你可以使用绝对路径,也可以放在实例配置的undo目录下,但要注意一点:在崩溃恢复前undo space必须要能够被发现并打开,但这时候Innodb data dictionary还是处于不可用的状态,我们无法从其中获取准确的文件位置,只有–datadir, –innodb-home-directory, –innodb-undo-directory 和 –innodb-directories会被扫描掉,如果你放在其他地方,就可能造成找不到该tablespace, 导致实例数据不一致。
- Server层接口类:Sql_cmd_create_undo_tablespace
- 为undo tablespace预留的space id (但最多依然是127个undo tablespace, 每个space number会给一个范围内的space id, 默认512个id):
- s_min_undo_space_id = 0xFFFFFFF0UL - 127 * 512
- s_max_undo_space_id = 0xFFFFFFF0UL - 1
- InnoDB入口函数: innodb_create_undo_tablespace
- 获取下一个可用的space id: undo::get_next_available_space_num(), 先拿到空闲的space number,再分配一个可用的space id
- srv_undo_tablespace_create: 创建undo space, 初始化回滚段并加入到全局事务系统中
如果你不想使用某个Undo tablespace,可以将其设置为inactive状态, 但需要保证至少有连个active的undo tablespace, 这个限制的原因是:当一个undo tablespace正在被truncate时,至少有一个是可用的。
当被设置为Inactive状态之后,事务就不会从其中分配回滚段。
相关代码:
- server层接口类:Sql_cmd_alter_undo_tablespace
- 在崩溃恢复data dicitonary提供服务后,需要将undo space状态更新到内存(apply_dd_undo_state())
- innodb_alter_undo_tablespace–> innodb_alter_undo_tablespace_active
- 设置Undo space 为active状态,并修改dd元数据
- innodb_alter_undo_tablespace –> innodb_alter_undo_tablespace_inactive
- 当undo space状态为empty时,直接返回
- 当undo space状态为active时,需要确保至少两个active的undo space才允许操作,否则返回错误
- 设置dd state为inactive,并修改回滚段状态
- 设置truncate frequency为1并唤醒purge线程, 这样purge线程会更频繁的去做purge操作,加快undo space的回收
在删除一个undo tablespace之前,首先要把undo tablespace设置为inactive状态
- 没有任何事务需要看到其中的老版本数据,也就是说所有在该事务之前开启的read view必须全部关闭
- 所有使用该undo tablespace的事务必须全部提交或回滚掉
- purge线程需要将其中的Undo log全部清理掉
如果undo tablespace非空,在drop时,会返回错误码HA_ERR_TABLESPACE_IS_NOT_EMPTY. 所以在设置为inactive到真正可以删除可能存在时间差,我们可以通过监控INFORMATION_SCHEMA.INNODB_TABLESPACES中的undo space状态是否为empty来判定是否可以删除。 Note:系统创建的Undo space不允许被删除
相关代码:
- Server层接口类:Sql_cmd_drop_undo_tablespace
- InnoDB 入口函数: innodb_drop_undo_tablespace
- invalidate buffer pool中该space的page
- 从内存中删除,记录ddl log
- 事务提交后,执行post ddl (Log_DDL::replay_delete_space_log)
- 真正物理删除文件
- 标记对应的space num为未使用状态
当参数innodb_undo_log_truncate打开时,所有隐式和显式创建的Undo tablespace都会在满足一定条件时被purge线程truncate掉. 当参数关闭时,则只有将Undo tablespace设置为Inactive状态时才会去truncate tablespace。 因此如果你想自己控制undo truncation, 可以关闭参数,在监控undo tablespace的大小,通过SET INACTIVE触发truncation, 再通过SET ACTIVE激活undo space。
相关代码:
- 由purge线程发起,入口函数:trx_purge_truncate_marked_undo()
- 需要获取MDL锁,来保护space不被alter/drop
- 通过flush_observer flush当前space的page
- trx_purge_truncate_marked_undo_low
- trx_undo_truncate_tablespace:
- 为当前space分配一个新的space id: undo::use_next_space_id(space_num)
- fil_replace_tablespace: 删除当前undo space,重建文件并设置为新的space id
- 重新初始化回滚段和内存信息
- 根据新的space id,将所有变更刷到磁盘
- 更新DD
- trx_undo_truncate_tablespace:
1. WL#9508: InnoDB: Support CREATE/ALTER/DROP UNDO TABLESPACE 3. 主要代码 5. MySQL8.0 · 引擎特性 · 关于undo表空间的一些新变化