参考:
http://www.cnblogs.com/cchust/p/3295547.html
http://www.zhdba.com/mysqlops/2012/02/24/mysql-xa-analyze/
http://hedengcheng.com/?p=136
WAL原则必须先刷redo,再刷binlog
3.记录事务对应的binlog偏移,写入系统表空间; //trx_sys_update_mysql_binlog_offset调用
http://www.cnblogs.com/cchust/p/3295547.html
http://www.zhdba.com/mysqlops/2012/02/24/mysql-xa-analyze/
http://hedengcheng.com/?p=136
提交流程
打开binlog选项后,执行事务提交命令时,就会进入两阶段(innodb_support_xa参数控制)提交模式。两阶段提交分为prepare阶段和commit两个阶段。WAL原则必须先刷redo,再刷binlog
prepare阶段:
1.设置undo state=TRX_UNDO_PREPARED; //trx_undo_set_state_at_prepare调用
2.刷事务更新产生的redo日志;【步骤1产生的redo日志也会刷入】 innodb_flush_log_at_trx_commit影响刷新策略
commit阶段:
1.将事务产生的binlog写入文件,刷入磁盘;sync_binlog值影响刷新策略
2.设置undo页的状态,置为TRX_UNDO_TO_FREE或TRX_UNDO_TO_PURGE; // trx_undo_set_state_at_finish调用
异常处理
mysqld可能在任何情况下crash,os也有可能出现问题,另外若机器掉电,mysqld也会同样挂掉。下面给出几种常见故障场景,
1.prepare阶段,redo log落盘前,mysqld crash
2.prepare阶段,redo log落盘后,binlog落盘前,mysqld crash
3.commit阶段,binlog落盘后,mysqld crash
第一种情况,由于redo没有落盘,毫无疑问,事务的更新肯定没有写入磁盘,数据库的一致性受影响;
回滚
第二种情况,redo log写入完成,但binlog还未写入,事务处于TRX_STATE_PREPARED状态,这是提交还是回滚呢?
回滚
第三种情况,redo log和binlog都已经落盘,只是undo状态没有更新,这种情况也应该提交,因为redo log和binlog已经一致了。
提交
下面给出了mysqld异常重启后的执行逻辑以及关键的源代码。对于第三种情况,我们可以搜集到未提交事务的binlog event,所以需要提交,与我们假设相符;而对于第二种情况,由于binlog未写入,需要通过执行回滚操作来保证数据库的一致性。
异常重启后,如何判断事务该提交还是回滚
1.读binlog日志,获取崩溃时没有提交的event; //info->commit_list中含有该元素,倒叙遍历binlog,直到遇见提交的event?;如果binlog找不到,则会丢失
2.若存在,则对应的事务要提交; 否则需要回滚
?无法处理情况一
>>> 个人看法
1、读取redo日志中的prepare状态的event的xid。
innodb是否可以根据redo中的flush LSN与LSN差别
2、读取最后1个binlog文件的全部数据,将文件中的xid存入commit_list hash表,此list中对应prepare状态的xid
若binlog文件很大,则效率会变低
MySQL写Binlog与底层存储引擎(InnoDB)写redo log的方式分析:
同一事务只能写到同一个Binlog文件中,不能跨文件。
为了保证底层引擎Commit顺序与Binlog顺序一致,
目前MySQL+InnoDB不支持group commit(新版Precona,MariaDB除外),同一时间只有一个事务可以进行提交(内部的XA事务,二阶段提交):InnoDB prepare + Binlog flush + InnoDB commit这一系列操作。
因此下一个事务开始进行InnoDB prepare时,前一个事务的系列动作一定结束,事务已提交。意味着crash recovery时,最多只有一个InnoDB事务处于prepare状态。
最后一个prepare事务一定位于最后的Binlog文件中
3、commit_list中的xid则根据redo重新提交事务。
剩余xid,则根据redo回滚事务
简而言之,对于异常的xa事务,若binlog已落盘,则事务应该提交;binlog未落盘,则事务就应该回滚
?无法处理情况一
>>> 个人看法
1、读取redo日志中的prepare状态的event的xid。
innodb是否可以根据redo中的flush LSN与LSN差别
2、读取最后1个binlog文件的全部数据,将文件中的xid存入commit_list hash表,此list中对应prepare状态的xid
若binlog文件很大,则效率会变低
MySQL写Binlog与底层存储引擎(InnoDB)写redo log的方式分析:
同一事务只能写到同一个Binlog文件中,不能跨文件。
为了保证底层引擎Commit顺序与Binlog顺序一致,
目前MySQL+InnoDB不支持group commit(新版Precona,MariaDB除外),同一时间只有一个事务可以进行提交(内部的XA事务,二阶段提交):InnoDB prepare + Binlog flush + InnoDB commit这一系列操作。
因此下一个事务开始进行InnoDB prepare时,前一个事务的系列动作一定结束,事务已提交。意味着crash recovery时,最多只有一个InnoDB事务处于prepare状态。
最后一个prepare事务一定位于最后的Binlog文件中
3、commit_list中的xid则根据redo重新提交事务。
剩余xid,则根据redo回滚事务
简而言之,对于异常的xa事务,若binlog已落盘,则事务应该提交;binlog未落盘,则事务就应该回滚