• gdb调试入手MySQL源码

    背景

    提到MySQL源代码,很对人都会望而却步。因为确实很庞杂,想要统筹的去阅读源码本身就有一些难度,而且也并不建议那样做。 我觉得很多时候,无论阅读什么源代码时,调试都是一种很有效的方式。 可以由某个知识点进入,然后扩展到线,再扩展到面。这样难度会小,也更容易接受。

    接下来就简单的讲一讲怎样去通过gdb调试技术去探一探MySQL的源代码对某个功能的实现:

    gdb调试基础

    GDBGNU Debugger)包含在GNU的gcc开发套件中,是功能强大的程序调试器。gdb主要支持C、C++、Pascal等语言的调试。

    gdb的功能

    1.启动你的程序,可以按照你的自定义的要求随心所欲的运行程序。
    2.可让被调试的程序在你所指定的调置的断点处停住。(断点可以是条件表达式)
    3.当程序被停住时,可以检查此时你的程序中所发生的事。
    4.动态的改变你程序的执行环境。

    gdb的启动

    语法: gdb [options]  filename

    gdb常用命令
    命令 简写 解释 示例
    file <文件名> 加载被调试的可执行程序文件。 因为一般都在被调试程序所在目录下执行GDB,因而文本名不需要带路径。 (gdb) file /usr/local/mysql/bin/mysqld
    run r 运行被调试的程序。 如果此前没有下过断点,则执行完整个程序;如果有断点,则程序暂停在第一个可用断点处。 (gdb) r
    continue c 继续执行被调试程序,直至下一个断点或程序结束。 (gdb) c
    “break 行号”、 “break 函数名称”、 “break 行号/函数名 if 条件” b 设置断点到某行、 设置断点到函数名称、 设置断点到 (gdb) b 10、 (gdb) b JOIN::exec (gdb) b if val > 10
    step s 执行一行源程序代码,如果此行代码中有函数调用,则进入该函数 (gdb) s
    next n 执行一行源程序代码,此行代码中的函数调用也一并执行 (gdb) n
    print <变量名> p 显示指定变量(临时变量或全局变量)的值。 (gdb)p name
    info i 查看和可执行程序相关的各种信息,info breakpoint 只是众多info命令中的一种,info可以查看可执行程序的很多信息,例如,info function可以查看所有函数名称。关于info命令的具体用法,可以在GDB中使用help info查看相关的帮助 (gdb)info breakpoint
    list l 不带任何参数使用list命令时,会从开始位置列出所有陈旭代码,同时list还支持列出指定行号之间的代码,具体命令为”list num1, num2” (gdb)list 2, 10
    quit q 退出gdb交互程序 (gdb)q
    breacktrace bt 打印当前的函数调用栈的所有信息,当程序被停住了,你需要做的第一件事就是查看程序是在哪里停住的。当你的程序调用了一个函数,函数的地址,函数参数,函数内的局部变量都会被压入“栈”(Stack)中. (gdb) bt

     

    如何调试MySQL

    mysql的调试其实不难,主要分为以下几步:

    1. 从官网下载源码包并且编译安装,这里提供一个简单的脚本:

    注意:一定要加上后面的那个 -DWITH_DEBUG=1才行。

    2. 生成数据库本身需要的一些库表:

    3. debug方式启动数据库:

    启动以后你会发现在  /tmp目录下生成了一个mysqld.trace的文件。 这个文件会自动记录当前运行mysql进程的一些函数调用。但是打开以后会发现,即使我只执行一条最简单的sql读取操作都要产生将近几百上千的函数调用。还是很难去分析和查看。这时候,就需要结合gdb进行调试观察了。

    4. 我们用ps命令取得mysql进程的进程号,并且使用gdb进入调试

    5. 在 /tmp/mysqld.trace 文件中找到想要观察或跟踪的函数名称,比如我想观察binlog点的刷新机制。那么我首先登录数据库。并且执行一条update ,mysql自动将此过程中调用到的函数一一记录下来,当然也包括binlog的记录与刷新:

    %e5%b1%8f%e5%b9%95%e5%bf%ab%e7%85%a7-2016-11-08-%e4%b8%8b%e5%8d%882-31-46

    6. 在gdb中设置断点到函数处,开始调试。

    7. 新打开一个终端,执行一条sql语句

    会发现sql语句阻塞住了,因为它刚好停到了断点处。然后就会发现gdb的调试中出现了断点处的源代码

    8. 这样我们就可以对照着源码进行调试了,比如我们想知道函数的调用栈:

    接下来我们深入到MYSQL_BIN_LOG::ordered_commit函数的源码中去看看,当然我们最好带着问题去看。 到底是先将日志从binlog_cache刷新到binlog文件中再commit,还是先commit然后再刷新入binlog文件呢?其实甚至我们都不需要看源码,单单从函数的注释就可以得到答案:

     

    到此我们就掌握了通过调试入手MySQL的方法,至于具体的源码分析。本人目前还不具备实例,期待日后能够更进一步。