在双1的情况下,两阶段提交的过程

环境准备:mysql 5.5.18, innodb 1.1 version
配置:
  sync_binlog=1
  innodb_flush_log_at_trx_commit=1
  autocommit=0

设置断点:

sql_parse.cc::dispatch_command --命令跳转入口
sql_parse.cc::mysql_parse
sql_parse.cc::mysql_execute_command
sql_parse.cc::trans_commit_stmt --语句commit入口
handler.cc::ha_commit_trans --commit入口

log.cc::binlog_prepare --binlog prepare入口
Ha_innodb.cc::innobase_xa_prepare --innodb prepare入口

log.cc::binlog_commit --binlog commit入口
Ha_innodb.cc::innobase_commit --innodb commit入口


实验步骤

步骤1:

 use test;
create table xpchild(id int auto_increment primary key, name varchar(100));
insert into xpchild(1,'xpchild');

步骤1过程:

1. dispatch_command:
  command = COM_QUERY
  inc_thread_running():增加thread running
  statistic_increment:增加计数
  switch (command):跳转命令
2. mysql_execute_command:
  解析命令为:SQLCOM_INSERT
3. mysql_insert:
  跳转到真正的insert
  bool log_on= (thd->variables.option_bits & OPTION_BIN_LOG):判断是否打开了binlog
  open_and_lock_tables(thd, table_list, TRUE, 0):打开table并锁表
4. trans_commit_stmt:
  语句级别的提交
  if (thd->transaction.stmt.ha_list)
    res= ha_commit_trans(thd, FALSE);
    针对语句所有参与的引擎进行提交, 但这里all的参数是false,说明是语句的提交动作,而非真正的事务commit。
5. ha_commit_trans:
  这里trans=all ? &thd->transaction.all : &thd->transaction.stmt,说明是stmt的transaction。
  ha_check_and_coalesce_trx_read_only:判断事务是否需要两阶段提交
  for (Ha_trx_info *hi= ha_info; hi; hi= hi->next())
    一共有两个引擎参与:binlog&&innodb


进入prepare阶段:

5.1. binlog_prepare:

     直接返回什么也没有做
5.2. innobase_xa_prepare:
  all参数是false,innodb认为是语句级别的提交,就只做如下的事情:
  row_unlock_table_autoinc_for_mysql(trx);释放语句hold的auto_increment锁
  trx_mark_sql_stat_end(trx);记录本语句的undo信息,以便语句级的回滚

进入提交阶段:

commit_one_phase_low(thd, all, trans, is_real_trans);

5.3. binlog_commit
  只是cache了statement的binlog,没有做flush操作
5.4. innobase_commit
  row_unlock_table_autoinc_for_mysql(trx);释放了自增锁
  trx_mark_sql_stat_end(trx);记录本语句的undo信息  
  这个地方做的事情和prepare阶段一样,多做虽然没有坏处,但也没有看到有什么意义
  srv_active_wake_master_thread:给主线程发信号唤醒,就结束
6. close_thread_tables(thd)
  在mysql_execute_command中close table,然后这次命令就结束了。

步骤2:

  

commit

1. 前面的步骤都相似:
  mysql_execute_command函数中跳转到trans_commit进行真正的提交。

2. ha_commit_trans
  进入commit函数,传入参数all=true,为真正的提交动作。
  检查rw_ha_count= ha_check_and_coalesce_trx_read_only(thd, ha_info, all)
  rw_ha_count=2 代表binlog引擎和innodb引擎
  is_real_trans=true

进入两阶段提交过程:

3. binlog_prepare:
  直接return 0;
4. innobase_xa_prepare:
  trx_prepare_off_kernel:
  mutex_enter(&(rseg->mutex));锁住undo segment的mutex
  trx_undo_set_state_at_prepare;设置这个insert语句所对应的undo的状态从TRX_UNDO_ACTIVE-》TRX_UNDO_PREPARED。
  mutex_exit(&(rseg->mutex));释放mutex
  mtr_commit(&mtr): 对于本次的内存更改,因为非原子操作,所以也对应一个提交动作
  lsn = mtr.end_lsn:或者最后的lsn后,flush的时候要保证大于或者等于lsn。
  if flush_log_at_trx_commit=1
    log_write_up_to(lsn, LOG_WAIT_ONE_GROUP, TRUE); 参数flush_to_disk=true表示flush log到disk中。

5. tc_log->log_and_order:这里做了大部分的commit的工作,包括:
  binlog_commit_flush_trx_cache:刷新binlog到disk
    TC_LOG::run_commit_ordered:
      对binlog进行group commit操作

  innodb::innobase_commit_ordered:
  trx_commit_off_kernel:
    标记事务为TRX_COMMITTED_IN_MEMORY,
    如果是insert undo,直接purge掉。
    trx->flush_log_later=true,所以这里并不进行flush,只是记录了commit的lsn,flush的动作放在了提交阶段。
    trx_roll_free_all_savepoints:释放所有的save_point.
    事务的标记最终为: trx->conc_state = TRX_NOT_STARTED

进入最终提交阶段:
commit_one_phase_low(thd, all, trans, is_real_trans):
  binlog_commit:这里貌似什么都没有做,直接进入
  if (cache_mngr->trx_cache.empty())
    cache_mngr->reset_cache(&cache_mngr->trx_cache)
    所以binlog commit并不是真正flush log的地方,而是在ha_commit_trans函数中,完成prepare过程后,commit提交前做了:
    cookie= tc_log->log_and_order(thd, xid, all, need_commit_ordered);
    所以,其实binlog已经提交了,只不过位置不在这里,不过,不妨碍一致性,因为都是在一阶段完成后。

innobase_commit:
  trx_commit_complete_for_mysql:
    log_write_up_to(lsn, LOG_WAIT_ONE_GROUP, TRUE);刷新log到disk中,这里的lsn是commit_lsn.

到这里commit完整结束。

MySQL源码之两阶段提交的更多相关文章

  1. mysql源码解读之事务提交过程(二)

    上一篇文章我介绍了在关闭binlog的情况下,事务提交的大概流程.之所以关闭binlog,是因为开启binlog后事务提交流程会变成两阶段提交,这里的两阶段提交并不涉及分布式事务,当然mysql把它称 ...

  2. mysql源码解读之事务提交过程(一)

    mysql是一种关系型数据库,关系型数据库一个重要的特性就是支持事务,这是区别于no-sql产品的一个核心特性.当然了,no-sql产品支持键值查询,不能支持sql语句,这也是一个区别.今天主要讨论下 ...

  3. 聊一聊 MySQL 中的数据编辑过程中涉及的两阶段提交

    MySQL 数据库中的两阶段提交,不知道您知道不?这篇文章就简单的聊一聊 MySQL 数据库中的两阶段提交,两阶段提交发生在数据变更期间(更新.删除.新增等),两阶段提交过程中涉及到了 MySQL 数 ...

  4. Flink EOS如何防止外部系统乱入--两阶段提交源码

    一.前言 根据维基百科的定义,两阶段提交(Two-phase Commit,简称2PC)是巨人们用来解决分布式系统架构下的所有节点在进行事务提交时保持一致性问题而设计的一种算法,也可称之为协议. 在F ...

  5. flink-----实时项目---day07-----1.Flink的checkpoint原理分析 2. 自定义两阶段提交sink(MySQL) 3 将数据写入Hbase(使用幂等性结合at least Once实现精确一次性语义) 4 ProtoBuf

    1.Flink中exactly once实现原理分析 生产者从kafka拉取数据以及消费者往kafka写数据都需要保证exactly once.目前flink中支持exactly once的sourc ...

  6. MySQL binlog 组提交与 XA(两阶段提交)

    1. XA-2PC (two phase commit, 两阶段提交 ) XA是由X/Open组织提出的分布式事务的规范(X代表transaction; A代表accordant?).XA规范主要定义 ...

  7. MySQL binlog 组提交与 XA(分布式事务、两阶段提交)【转】

    概念: XA(分布式事务)规范主要定义了(全局)事务管理器(TM: Transaction Manager)和(局部)资源管理器(RM: Resource Manager)之间的接口.XA为了实现分布 ...

  8. MySQL binlog 组提交与 XA(两阶段提交)--1

    参考了网上几篇比较靠谱的文章 http://www.linuxidc.com/Linux/2015-11/124942.htm http://blog.csdn.net/woqutechteam/ar ...

  9. 使用golang理解mysql的两阶段提交

    使用golang理解mysql的两阶段提交 文章源于一个问题:如果我们现在有两个mysql实例,在我们要尽量简单地完成分布式事务,怎么处理? 场景重现 比如我们现在有两个数据库,mysql3306和m ...

随机推荐

  1. javaweb常用工具类及配置文件备份

    Javaweb常用工具类及配置文件备份   做一个代码备份,以后常用到的. hibernate工具类备份 package com.dly.service; /*  * hibernate获取sessi ...

  2. mysql 直接从date 文件夹备份表,还原数据库之后提示 table doesn`t exist的原因和解决方法

    补充:正常情况下,建议数据库备份最好用工具进行备份,通过拷贝数据库表进行数据迁移,不同的环境会出现各种不同的意外问题. 背景:今天在整理一个网站的时候,操作系统由于系统自动更新导致一直出现系统蓝屏死机 ...

  3. 九度OJ 1082 代理服务器 -- 贪心算法

    题目地址:http://ac.jobdu.com/problem.php?pid=1082 题目描述: 使用代理服务器能够在一定程度上隐藏客户端信息,从而保护用户在互联网上的隐私.我们知道n个代理服务 ...

  4. log4j使用细节

    问题一:打印不同类的类名信息? 在log4j中通常是通过Logger.getLogger(class)指定所打印的类名,但是当我们需要打印不同类信息时,目前只能这样做,在不同的类文件中构建不同的log ...

  5. [翻译][MVC 5 + EF 6] 4:弹性连接和命令拦截

    原文:Connection Resiliency and Command Interception with the Entity Framework in an ASP.NET MVC Applic ...

  6. 网站开发常用jQuery插件总结(十)菜单插件superfish

    网站对于菜单的依赖其实并不是很大,我们完全可以不使用菜单来设计网站,显示网站内容.但是如果网站的分类太多,“也许”使用菜单作为网站导航可以使 用户 更方便的寻找内容.superfish插件就是用于实现 ...

  7. echo和print语句

    在php中,有两种基本的输出方法:echo  和  print echo 和 print 之间的差异: echo——能够输出一个以上的字符串,无返回值 print——只能输出一个字符串,并始终返回值为 ...

  8. setTimeout和setInterval的深入理解

    以前写的setTimeout和setInterval的文章有些不足之处,今天抽时间整理了一下,要想真正理解还得从javascript的单线程机制说起 大概半年前发表过一篇关于setTimeout和se ...

  9. php文件上传大小限制设置

    配置选项说明: upload_max_filesize 所上传的文件的最大大小. post_max_size 设定 POST 数据所允许的最大大小. memory_limit 设定了一个脚本所能够申请 ...

  10. python实现模拟登录【转】

    原文网址:http://www.blogjava.net/hongqiang/archive/2012/08/01/384552.html 本文主要用python实现了对网站的模拟登录.通过自己构造p ...