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';
- 在 debug 的时候,可以详细的显示函数的调用路径
- 或者提供一个额外的参数,供外部调用,以模拟或者实现某些特殊的功能,例如 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代码
- 个人觉得这个只能适合那些
- 不是内核研发,但是只是想看看mysql的运行原理
- 或者是刚接触MySQL内核的研发人员,毕竟MySQL内核结构不是那么清晰,