暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

GDB 查看MYSQL-5.7.38 COMMIT过程

原创 大大刺猬 2023-02-27
803

看源码太费眼睛了. 还是gdb方便点, 为了方便低版本gdb的环境, 这里就不升级gdb了.

高版本的是彩色的, 方便看, 有条件的可以安装下:https://www.sourceware.org/gdb/

环境:

gdb:7.6.1-120.el7

mysql:5.7.38

image.png

GDB 常用命令

其实还有其它常用的, 但是不在本次调试的使用范围

直接回车就是上一条命令

简写 全称 解释
p print 打印变量
b break 在某处打断点
i b info break 查看断点. 还可以delete/disable break
s step 下一条代码, 函数也会进入(详细的看,贼TM多的堆栈…)
n next 下一条代码, 不会进入函数(粗略的看)
l N list N 显示源码指定位置(默认当前)源码前后内容.
默认10行,嫌少的话, 可以设置下 set listsize 30
fi finish 结束当前正在执行的frame(就是bt最上面那个)
bt backtrace 查看函数调用,frame
frame n frame n 切换到某个frame去.(backtrace查看)
set set 设置变量的值
attach attach 接管某个进程(gdb -p pid)
c continue 继续运行,知道下一个断点

准备MYSQL源码

编译的时候有些没有指定 -g

5.7.x 后面几个版本都差不多, 随便哪个都行, 8.0.x的也行. 源码环境和二进制mysqld是一样的版本就行

wget https://downloads.mysql.com/archives/get/p/23/file/mysql-5.7.38.tar.gz

开始GDB调试

启动mysqld

略. mysqld --defaults-file=/data/mysql_3308/conf/mysql_3308.cnf

使用GDB接管mysqld

gdb -p `pidof mysqld`

image.png

设置mysql源码路径(可选)

不设置的话, 有部分源码就看不到. 不过影响也不大

其它版本的mysql,自己换名字哈

set substitute-path /var/lib/pb2/sb_1-6473437-1647886122.65/mysql-5.7.38 /root/mysql_source/mysql-5.7.38

image.png

设置断点

本次主要是看提交过程, 所以断点给 trans_commit

你也可以看看mysql命令执行过程,就可以设置mysql_execute_command, 也可以设置其它的, 也可以都设置.

设置完后,记得continue, 不然是阻塞着的.

break trans_commit info break continue

image.png

登录Mysql,发起一个事务并提交

提交的时候,看到在等待着server端反馈

begin; insert into db1.t1(id) values(20230225); commit;

image.png

gdb 开始查看提交过程

我们看到自动切换到了新连接的线程,并触发了breakpoint 1

image.png

此时, 代码就停在trans_commit处, 可以使用bt查看frame信息, 也可以step/next运行代码, 也可以finish完成当前frame代码.

上层的frame就是mysql_execute_command解析mysql命令, 再上层就是sql_parse了

frame信息是从下往上的, 就是栈, 也叫栈帧

使用 list查看下当前的源码信息(有点少, 可以使用set listsize 30设置显示多点,也可以手动指定起始范围)

image.png

使用 step 进入函数执行

然后就进入了trans_check_state , (检查事务能否提交或者回滚的)

image.png

我们并不关心它的检查过程, 直接 finish(返回了false,表示可以提交或者回滚), 就又回到了trans_commit

image.png

继续step, 到了ha_commit_trans. 后面就已经是提交完成的了, 所以我们使用step进入这个函数, 看下具体的提交过程

image.png

再使用list看下代码, 发现commit_owned_gtids, 在事务prepare之前,保存gtid信息, 我们并不关系它怎么保存的, 所以使用next执行代码(直接执行完函数,不会进入函数)

image.png

获取事务之类的我们也不关心, 都直接next了, (需要看详情的话,就使用step进去)

image.png

这是个很枯燥的过程(太多的if)… 截图太细也没得意义. 后面我就都直接跳到关键地方. 忘记自己在哪的时候使用 bt(backtrace)就知道了

tc_log->prepare

终于到了tc_log->prepare了, 有必要使用step进去瞧瞧. 不想瞧的直接next去看commit也可以的.

image.png

进去后是MYSQL_BIN_LOG (两阶段提交的CN角色)

注:没开启binlog的时候, CN是tc_log_mmap/tc_log_dummy(都是继承自tc_log)

image.png

查看源码,发现又是调用的ha_prepare_low, 就使用step一步步进去吧…

image.png

进去后又是一堆…

image.png

image.png

又是获取事务信息之类的,太多了,直接跳过

image.png

终于到了binlog的prepare了(起始它基本上啥也没做…)

注:innobase/binlog的prepare代码里都是ht->prepare, 前面有ht哪来的,只是我没截图而已.

image.png

很快就到innobase的prepare阶段了(毕竟binlog->prepare啥也没干…)

不看细节了(比如check_trx_exists,innobase_trx_init之类的,还有一大堆锁,尤其是mutex… 还有undo状态设置). 有兴趣的自己去看吧.

image.png

你也可以把其中涉及到的变量之类的打印出来瞧瞧. (也可以修改,不过不建议. 连接数满的时候,就可以通过这种方法修改最大连接数)

image.png

image.pngLSN在这

tc_log->commit

终于到commit阶段了

image.png

binlog生成之类的都不看了(要解析Binlog的话,可以使用mysql-replication)…

直接到flush阶段(刷redo, 是在commit阶段的flush阶段), 详情就不看了, 太多了

image.png

刷完redo,刷binlog (可以确认下binlog的时间戳是否变化)

image.png

刷完之后还会调用fsync

image.png

都刷完后,就该commit了. 提交阶段都是更新一些状态信息之类的(会在存储引擎提交,还会刷redo. ha_commit_low).

后面还有process_after_commit_stage_queue,finish_commit…

image.png

image.png

总结

这居然只是一个提交, 修改的东西已经很多了, 总结下过程吧

用户发起 ‘commit’ --> 服务器解析sql --> tc_log->prpare (binlog->prepare,innobase->prepare) --> tc_log->commit(flush,刷redo, binlog, sync,commit)

COMMIT_SQL
  >trans_commit
    >ha_commit_trans
      >tc_log->prepare(这里是MYSQL_BINLOG::prepare)
        >ha_prepare_low
          >binlog_prepare(啥也不干)
          >innobase_xa_prepare
      >tc_log->commit(MYSQL_BINLOG::commit)
        >process_flush_stage_queue(ha_flush_logs)(刷redo)
        >flush_cache_to_file(刷binlog)
        >sync_binlog_file
        >process_commit_stage_queue
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论