Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

debug

MySQL debug


-- d	开启DBUG_XXX
-- f	只跟踪指定的函数
-- F	跟踪指定的源码文件
-- i	跟踪指定的线程
-- L	跟踪指定的源码行数
-- n	打印函数调用层次序号
-- N	输出日志从0开始打印行号
-- o	指定输出到某个文件
-- O	类似o,每次写文件都会flush,reopen
-- P	匹配DBUG_PROCESS
-- p	打印process name
-- t	打印函数调用和退出

set session debug='d:t:o,/tmp/mysqld.trace';

set session debug='d:t:L:F:o,/tmp/mysqld.trace';

set session debug='d:t:L:F:n:O,/tmp/mysqld.trace';

  1. 在 debug 的时候,可以详细的显示函数的调用路径
  2. 或者提供一个额外的参数,供外部调用,以模拟或者实现某些特殊的功能,例如 skip_dd_table_access_check
    • 主要由 DBUG_EVALUATE_IF 实现的
  • 最早代码可以追溯到 87 年
<do_command
>do_command
| >THD::clear_error
| <THD::clear_error
| >Diagnostics_area::reset_diagnostics_area
| <Diagnostics_area::reset_diagnostics_area
| >my_net_set_read_timeout
| | enter: timeout: 28800
| | >vio_socket_timeout
| | <vio_socket_timeout
| <my_net_set_read_timeout
| >vio_is_blocking
| <vio_is_blocking
| >net_read_raw_loop
| | >vio_read
| | | >vio_is_blocking
| | | <vio_is_blocking
| | | >vio_io_wait
| | | <vio_io_wait
| | <vio_read
| <net_read_raw_loop
| THD::enter_stage: 'starting' /home/asky/imysql/sql/conn_handler/init_net_server_extension.cc:104
| >PROFILING::status_change
| <PROFILING::status_change
| packet_header: Memory: 0x7f5af8007660  Bytes: (4)
38 00 00 00
| >net_read_raw_loop
| | >vio_read
| | <vio_read
| <net_read_raw_loop

实现原理

使用宏以及 c++ 对象自动析构的特点,实现函数调用栈的跟踪。并且加上输出的控制机制,可以指定输出位置,输出格式等

详细格式如下

  op_list_to_buf('d', cs->stack->keywords, DEBUGGING);
  op_int_to_buf('D', cs->stack->delay, 0);
  op_list_to_buf('f', cs->stack->functions, cs->stack->functions);
  op_bool_to_buf('F', cs->stack->flags & FILE_ON);
  op_bool_to_buf('i', cs->stack->flags & PID_ON);
  op_list_to_buf('g', cs->stack->p_functions, PROFILING);
  op_bool_to_buf('L', cs->stack->flags & LINE_ON);
  op_bool_to_buf('n', cs->stack->flags & DEPTH_ON);
  op_bool_to_buf('N', cs->stack->flags & NUMBER_ON);
  op_str_to_buf(((cs->stack->flags & FLUSH_ON_WRITE ? 0 : 32) |
                 (cs->stack->flags & OPEN_APPEND ? 'A' : 'O')),
                cs->stack->name, cs->stack->out_file != stderr);
  op_list_to_buf('p', cs->stack->processes, cs->stack->processes);
  op_bool_to_buf('P', cs->stack->flags & PROCESS_ON);
  op_bool_to_buf('r', cs->stack->sub_level != 0);
  op_intf_to_buf('t', cs->stack->maxdepth, MAXDEPTH, TRACING);
  op_bool_to_buf('T', cs->stack->flags & TIMESTAMP_ON);

主要宏操作

  • DBUG_EVALUATE_IF(flag, a, b)

    • 满足 d 设置的标记的时候, 结果是 a ,否则是 b,类似运行时 ? :
  • DBUG_EXECUTE(flag, expr)

    • 满足条件的时候, 执行 expr ,expr 是表达式,可以是函数调用,也可以是语句块
  • DBUG_PRINT(flag, (format, args...))

    • 满足条件的时候,输出指定格式,这里是直接把参数传递 func,宏里面类似 db_doprnt(format, args...)
  • DBUG_EXECUTE_IF(flag, expr)

    • 同上,但是只在 flag 条件下执行,和 DBUG_EXECUTE 类似,但是区别是 DBUG_EXECUTE_IF 只有设置对应得 falg 才会触发,而 DBUG_EXECUTE 则是列表为null或者设置flag得时候触发

对比其他

实现起来不难,但是没有见过其他数据库有类似的实现

  • 首先这是 debug 期间使用的,对于非研发来讲,没有太大的作用
  • 其次,如果是结构合理,模块清晰,调用堆栈其实没有太大的作用
    • MySQL 代码结构不合理, 所以这个还是有点用。。
    • 但是太多的 debug 宏的使用,会导致代码可读性和结构混乱,不利于维护和扩展,分不清哪些是逻辑代码,那些是debug代码
  • 个人觉得这个只能适合那些
    1. 不是内核研发,但是只是想看看mysql的运行原理
    2. 或者是刚接触MySQL内核的研发人员,毕竟MySQL内核结构不是那么清晰,