MySQL 5.7 BUGFIX BUG#12161

在MySQL 5.7版本里,大量遗留很多年的bug都被fix掉了,bug#12161就是其中一个,该bug在2005年第一次report到Bug list上,十年之后终于在MySQL 5.7.7 第一个RC版本被fix了。

Bug描述

当我们显式开启一个XA事务,执行操作,并完成XA PREPARE后,如果Kill session或者主动断开,再重连执行XA RECOVER,之前的这个XA事务是丢失了的。

例如:

mysql> XA BEGIN ‘abc';

Query OK, 0 rows affected (0.00 sec)

mysql> INSERT INTO t1 VALUES (1,2,3);

Query OK, 1 row affected (0.00 sec)

mysql> XA END ‘abc';

Query OK, 0 rows affected (0.00 sec)

mysql> XA PREPARE ‘abc';

Query OK, 0 rows affected (0.00 sec)

mysql> Ctrl-C — exit!

Aborted

mysql> XA RECOVER;

Empty set (0.00 sec)

有趣的是,如果在XA PREPARE后把实例KILL掉,是可以通过XA RECOVER恢复的:

mysql> XA RECOVER;

+———-+————–+————–+——+

| formatID | gtrid_length | bqual_length | data |

+———-+————–+————–+——+

| 1 | 3 | 0 | abc |

+———-+————–+————–+——+

1 row in set (0.00 sec)

mysql> XA COMMIT ‘abc';

Query OK, 0 rows affected (0.00 sec)

虽然实例异常重启可以恢复事务,但引入的另外一个问题是:事务变更的binlog丢失,导致主备数据不一致。

bug产生的原因也很简单:在退出session时,线程总是会去无条件的回滚掉自己尚未提交的事务。

官方修复:

a.持久化

为了解决这个问题,将XA的两阶段记录到了Binlog中;

对于上文描述的序列,当执行到XA PREPARE时,记录第一阶段的binlog,如下:

Query event : XA START X’616263′,X’’,1       // 这里的’616262’即是’abc’的十六进制编码

Table_map event

Write_rows event

Query event:XA END X’616263′,X”,1

XA_prepare event: XA PREPARE X’616263′,X’’,1 

这时候该XA事务同时在InnoDB层(事务处于Prepare状态,Redo持久化到磁盘)和Server层都有持久化信息。

其中XA_PREPARE事件是新引入的事件类型(内部类为XA_prepare_event),日后版本升级需要注意到这个低版本不兼容事件。

再执行XA COMMIT ‘abc’,产生新的事件:

Query event:XA COMMIT X’616263′,X”,1

如果执行XA ROLLBACK,则记录:

Query event:XA ROLLBACK X’616263′,X”,1

由于XA PREPARE和XA COMMIT是分开执行的,因此在这两个事件中间可能存在别的事务,备库复制线程需要处理这种情况。

为了实现XA PREPARE写binlog,对binlog_prepare进行了扩展,这里会调用mysql_bin_log.commit, 将cache中的binlog刷到文件中。

Tips:XID可以包含三个部分:gtrid, [, bqual [, format ID]],其中gtrid是必选的,表示全局标示,bqual是分支标识,默认为空’’,format ID是一个unsigned整型,默认值为1,在上例中,我们只指定了gtrid为’abc’,因此bqual段和format ID均为默认值。更具体的描述参考官方文档http://dev.mysql.com/doc/refman/5.7/en/xa-statements.html

b. 如何恢复

当会话断开时(例如kill session或者一次干净的shutdown/restart操作),我们必须要能恢复改事务,传统的逻辑是在cleanup时,直接回滚所有的活跃事务。在新版本中,需要对XA PREPARE的事务做特殊处理(THD::cleanup),如果处于Prepare状态,就将事务的in_recovery设置为TRUE,并更新到hash表transaction_cache中(transaction_cache_detach),该hash表用于维护所有XA事务。

对于非XA的活跃事务,在会话断开时,依然采用回滚策略。

当重连客户端后,我们可以直接执行 XA COMMIT ‘abc’,这时候会通过XID关键字是搜索transaction_cache并将对应的事务提交掉。

同时BINLOG的状态要保持一致,如果XA PREPARE没有记录Binlog, XA COMMIT也不应该记录。

c. 备库复制

由于XA PREPARE和XA COMMIT是分开记录的,当碰到XA COMMIT时,备库采用等待之前的事务全部完成,然后再执行的方式(相当于退化到串行)。

我们知道在一个正常的session过程中,总是为其cache一个事务对象,新的事务会重用这个事务对象,避免多次分配;而XA事务的COMMIT和PREPARE是分离的,需要为XA事务单独分配事务对象。 因此复制线程执行XA START时,将其拥有的事务对象临时保存起来(detach_native_trx),当执行到XA_prepare_log_event事件时,再将其恢复给复制线程,同时XA事务对象关闭read view,将is_recovered设置为TRUE。(函数innodb_replace_trx_in_thd)

随后复制线程在执行到XA COMMIT时直接根据XID进行提交。

参考:

worklog:http://dev.mysql.com/worklog/task/?id=6860

代码: git show f4c37f7aea732763947980600c6882ec908a54a0

MySQL 5.7.7-RC

 

 

时间: 2024-10-28 16:58:32

MySQL 5.7 BUGFIX BUG#12161的相关文章

MySQL · 捉虫状态 · bug分析两例

BUG 1 IN查询结果不对 背景 在mysql5.6.16版本下,构建如下测试用例 CREATE TABLE `a` ( `c1` varchar(512) NOT NULL DEFAULT '' ) ENGINE=InnoDB DEFAULT CHARSET=utf8; INSERT INTO `a` VALUES ('i-28s18atup'),('i-2850jdoa2'),('i-2872jv9o8'),('i-289z59set'),('i-2812c0mz1'),(''),('')

[MySQL 源码] 关于bug#65389的碎碎念

[MySQL Bug] bug#65389  MVCC IS BROKEN WITH IMPLICIT LOCK 该bug在5.5.26中被修复,changelog的描述如下: If a row was deleted from an InnoDB table, then another row was re-inserted with the same primary key value, an attempt by a concurrent transaction to lock the r

Scala 连接mysql 时出现的BUG

Caused by: com.mysql.cj.core.exceptions.InvalidConnectionAttributeException: The server time zone value '�й���׼ʱ��' is unrecognized or represents more than one time zone. You must configure either the server or JDBC driver (via the serverTimezone con

MySql Workbench中的BUG

MySql自带一个叫MySql Workbench的管理软件,可以直接设计表结构,但是当某个表附带了触发器,同时触发器语句中包含了特殊字符'//'后(这里2个斜杠,表示转义),就无法打开设计器了,查看DDL后发现,原来获取到的是'/',少了一个斜杠.

mysql jdbc处理0日期格式蛋疼问题-也算是BUG

最近在写一个数据库访问的中间平台时,使用MySQL JDBC处理一些日期数据,遇到点变态的问题,给大家乐一乐! 首先来看看什么样的日期数据这么蛋疼呢? DATE            0000-00-00 DATETIME   0000-00-00 00:00:00 TIMESTAMP 0000-00-00 00:00:00 TIME               25:21:22 对于前3种情况,直接用JDBC读取,肯定会报错,报错信息类似这样: Value '0000-00-00' can n

Mac下如何玩MySQL Server

版权声明:本文为博主原创文章,未经博主允许不得转载. 最近搞事务相关的语句,开始搞select for update了,在ECS上做实验,发现我安装的版本只支持MyISAM,不支持InnoDB,事务没法玩.于是在Mac上安装了一份MySQL Server. 如何安装,如何玩转,看说明书是最好的~ 我的机器上,StartupItems安装失败了,也不知道为什么.不过,MySQL Server安装是成功的,所以采用手动模式启动就OK了.      shell> cd /usr/local/mysql

changes of mysql 5.6.20

New option [Rev:5936][Rev:6045][Rev:6049]The new system variable binlog_impossible_mode controls what happens if the server cannot write to the binary log, for example, due to a file error. For backward compatibility, the default for binlog_impossibl

关于一个MYSQL异常问题的追查及优化

问题 用户工单疑问:相同的语句,只是最后的limit行数不同.奇怪的是,limit 10 的性能比limit 100的语句还慢约10倍. 隐藏用户表信息,语句及结果如下 SELECT f1 , SUM(`f2`) `CNT` FROM T WHERE f1 IS NOT NULL AND f3 = '2014-05-12′ GROUP BY f1 ORDER BY `CNT` DESC LIMIT 10; 执行时间3 min 3.65 sec SELECT f1 , SUM(`f2`) `CNT

分析一个MySQL的异常查询的案例_Mysql

问题 用户工单疑问:相同的语句,只是最后的limit行数不同.奇怪的是,limit 10 的性能比limit 100的语句还慢约10倍. 隐藏用户表信息,语句及结果如下 SELECT f1 , SUM(`f2`) `CNT` FROM T WHERE f1 IS NOT NULL AND f3 = '2014-05-12' GROUP BY f1 ORDER BY `CNT` DESC LIMIT 10; 执行时间3 min 3.65 sec SELECT f1 , SUM(`f2`) `CNT