2.6.2 XID_EVENT
1.XID的作用
我们在解析binary log的时候经常会看到在事务结束的位置会包含一个XID,什么是XID呢?XID实际是binary log和InnoDB层之间保证事务一致性的桥梁。我们先来看看XID的生成过程。
(1)事务中的每个语句都会生成一个query_id,如下。
(2)设置XID,以事务中第一个语句的query_id为准,如下。
我们知道事务的提交顺序可能和事务第一条语句发起的顺序并不一致,因此XID在binary log中可能并不是按顺序排列的。同时,它不是连续的,因为我们的select语句也会生成query_id,所以可能导致XID存在很大的“空洞”。
在进行异常恢复时,InnoDB层所有处于prepare阶段的事务都需要根据MySQL层最后一个binary log中事务的XID来判断是回滚还是提交(在InnoDB的Undo log record header中TRX_UNDO_XA_XID 记录了XID),下面是对这个行为的证明。
参考trx_rollback_or_clean_recovered函数,这是InnoDB做Crash recovery回滚的函数。 注释如下。
从MYSQL_BIN_LOG::recovery函数中可以看到事务的扫描逻辑,并发送XID给InnoDB层,供其判断回滚或提交。下面是MySQL层发送XID给InnoDB层进行判断的代码。
XID在一个binary log中是唯一的,因此对XID的总结如下。
· XID在binary log中不是递增的。
· XID在binary log中不是连续的。
· XID在一个binary log中是唯一的。
· XID存在于MySQL层的binary log中,以及InnoDB层的Undo log record header的TRX_UNDO_XA_XID中。
· XID用于MySQL层和InnoDB层配合,决定对处于prepare状态的事务做何种操作。
2.XID_EVENT的作用
上面已经描述了XID的作用,XID_EVENT就是用于携带XID的Event。从库应用的时候会进行commit操作,并且和GTID_EVENT一样,它们的Event header的timestamp都是commit命令发起的时间。当然,如果没有显示开启事务,那么timestamp还是DML命令发起的时间。3.2节会详细说明。
3.源码重要接口
主库
· 初始化构造函数:Xid_log_event::Xid_log_event(THD* thd_arg,my_xid x)。
· 写入binlog cache函数:Xid_log_event::write(IO_CACHE* file)。
从库
· 读取构造函数:Xid_log_event(const char* buf,const Format_description_event* description_event)。
· 应用函数:Xid_apply_log_event::do_apply_event 调用 Xid_log_event::do_commit。
4.主体格式
这个Event的格式也很简单,没有携带复杂的数据,没有固定部分,XID放到了可变部分,8字节,记录的是XID的值。
5.实例解析
下面是一个XID_EVENT(mysqlbinlog--hexdump 输出):
43 00 00 00 00 00 00 00:十六进制值43,即十进制值67,即实际的XID。
6.生成时机
虽然XID在事务的第一条语句就已经定了,但是构造Event和写入binlog cache是在整个提交过程prepare之后,order commit之前。3.2节和3.3节会描述这个流程。