diff --git a/mysql/mysql文档/mysql_事务.md b/mysql/mysql文档/mysql_事务.md index 3fee684..b348066 100644 --- a/mysql/mysql文档/mysql_事务.md +++ b/mysql/mysql文档/mysql_事务.md @@ -480,7 +480,25 @@ trx_undo_t关联的则是上面描述的undo segment。 #### undo writing 当一个写事务开启时,将会通过`trx_assign_rseg_durable`分配Rollback Segment,内存中的trx_t也会指向对应的trx_rseg_t内存结构。 -rollback segment的分配策略很简单,会依次尝试下一个活跃的rollback segment。在此之后,如果事务内的第一条修改命令需要写undo record,将会调用`trx_undo_assign_undo`来获取undo segment。在获取undo segment时,`trx_rseg_t`中包含的cached list中节点将会被优先使用。sa +rollback segment的分配策略很简单,会依次尝试下一个活跃的rollback segment。在此之后,如果事务内的第一条修改命令需要写undo record,将会调用`trx_undo_assign_undo`来获取undo segment。在获取undo segment时,`trx_rseg_t`中包含的cached list中节点将会被优先使用。 +> 如果已经存在`已分配但是未被使用的undo segment`,将会优先使用这部分undo segment。 +> +> 如果不存在已分配但是未被使用的undo segment,将会调用trx_undo_create创建新的undo segment。 + +##### undo record写入 +当undo page被写满后,会调用`trx_undo_add_page`来向当前undo segment中添加新的undo page。在将undo record写入到undo page时,存在如下约束: +- 一条undo record无法跨页面存在于两个page,如果当前page剩下的空间不足以写入undo record,那么会将undo record写入到下一个undo page + +在事务完成之后(提交/回滚), +- `如果当前undo segment中只使用了一个undo page,并且undo page的使用率小于75%`,那么该undo segment将会被保留并添加到对应的insert/update cachedlist中 +- `如果undo segment中undo page大于一个,或者undo page的使用率大于75%`,如么对于undo segment的处理如下: + - 对于insert类型的undo segment,其会在事务提交/回滚时直接被回收 + - 对于update类型的undo segment,其会在purge完成后被回收 + +根据场景的不同,undo segment其header的状态将会从`TRX_UNDO_ACTIVE`变为`TRX_UNDO_FREE`/`TRX_UNDO_TO_PURGE`/`TRX_UNDO_CACHED`,其代表了innodb事务的结束。 + +#### undo for rollback +在回滚时,会按照undo record生成的时序,逆向进行回滚。回滚根据undo record的内容。 ### purge 表`t`中,`a`为聚簇索引,`b`为辅助索引,若执行如下sql @@ -488,6 +506,18 @@ rollback segment的分配策略很简单,会依次尝试下一个活跃的roll delete from t where a=1; ``` +上图示例中,undo segment中包含了2个page和3个undo record: +- 第一个undo page中包含了undo record 1 +- 第二个undo page中包含了undo record 2和undo record 3 + +回滚流程如下所示: +- 从undo segment header中获取last undo page header的位置 +- 从last undo page header中获取最后一条undo record的位置,即undo record 3的位置,并根据undo record 3的内容执行回滚操作 +- 根据prev record offset的值来获取上一条undo record的位置,如此逆向遍历undo page中所有的undo record,并且执行回滚操作 +- 在当前page中,如果所有的undo records都执行完回滚操作,会根据undo page header查询前一个undo page,并按照上述流程执行回滚操作 + + + 上述语句造成的修改如下: - 将主键`a`为1的记录标记为delete,将记录`delete flag`设置为1(聚簇索引中的数据并没有被实际物理删除),`且会生成针对聚簇索引的undo log`。当事务发生回滚时,仅需将`delete flag`重新设置为0即可完成对删除的回滚。 - 对于辅助索引中满足`a=1`的记录,同样不会做任何处理,`也不会产生针对辅助索引的undo log`