首頁 > 軟體

分享MySQL常用 核心 Debug 幾種常見方法

2022-03-17 13:01:39

閱讀本文你將瞭解:

  • 如何準備 MySQL 偵錯環境
  • GDB 偵錯入門及操作範例
  • Trace 檔案偵錯及操作範例

一、準備 Debug 環境

首先用原始碼編譯安裝一個用來偵錯的 MySQL 環境。

開啟-DWITH_DEBUG ,在原始碼路徑建立 build 目錄,

進入目錄並執行:

cmake .. -DWITH_BOOST=../../boost -DWITH_DEBUG=1

然後通過如下方式,確認是否編譯成功。

方式一:

$ ./bin/mysqld --verbose --version

回顯 debug 版本資訊,則編譯的是 debug 版本。

ver 8.0.18-debug for Linux on x86_64 (Source distribution)

方式二:

連線資料庫,執行檢視版本命令。回顯包含了 debug 字樣,則編譯的是 debug 版本。

$ mysql> select version();
+--------------+
| version()    |
+--------------+
| 8.0.18-debug |
+--------------+
1 row in set (0.00 sec)

二、使用 GDB 偵錯

GDB 全稱 “GNU symbolic debugger”,是 Linux 下常用的程式偵錯程式,通常以 gdb 命令的形式在終端(Shell)中使用。

啟動 GDB 編譯器

執行如下命令啟動 GDB 編譯器(假設 my.cnf 在使用者根目錄中)。進入 GDB 後,敲入 run 即可執行。

gdb --args ./bin/mysqld --defaults-file=~/my.cnf --gdb

其中 --gdb 引數允許你隨時 Ctrl+C 的方式中斷 mysqld 程序,進行偵錯命令。

GDB 常用命令

使用多視窗檢視原始碼與偵錯的讀者,可以使用 layout 命令,在 gdb 中執行help layout 可以檢視更多 gdb 命令用法。

(gdb) help layout
(gdb) help layoutChange the layout of windows.
Usage: layout prev | next | <layout_name>
Layout names are:
   src   : Displays source and command windows.
   asm   : Displays disassembly and command windows.
   split : Displays source, disassembly and command windows.
   regs  : Displays register window. If existing layout
           is source/command or assembly/command, the
           register window is displayed. If the
           source/assembly/command (split) is displayed,
           the register window is displayed with
           the window that has current logical focus.
           (gdb)

Debug 範例

安裝好 Debug 環境後,我們用以下兩個例子,來簡單演示使用思路及技巧。

1、取變數值

在某種情況下發現 mysqld 已經 crash,系統只有一個 core 檔案,而我們要知道某個系統變數的值。但是系統變數的值,不見得與 my.cnf 檔案一致。

此時,就可以用 gdb 命令將變數列印出來,獲取變數值。

如下所示,需獲取變數 version 的值,只需要在前面加mysql_sysvar_ 字首列印即可。

Thread 1 "mysqld" received signal SIGINT, Interrupt.
0x00007ffff5f74cb9 in __GI___poll (fds=0x55555e8a3de0, nfds=2, timeout=-1) at ../sysdeps/unix/sysv/linux/poll.c:29
29    ../sysdeps/unix/sysv/linux/poll.c: No such file or directory.
(gdb) p mysql_sysvar_version
$1 = {flags = 68101, name = 0x55555e7ff738 "innodb_version", comment = 0x55555ca953e2 "InnoDB version", check = 0x555558e222f1 <check_func_str(THD*, SYS_VAR*, void*, st_mysql_value*)>, update = 0x555558e22881 <update_func_str(THD*, SYS_VAR*, void*, void const*)>,
  value = 0x55555def1c20 <innodb_version_str>, def_val = 0x55555ca89598 "8.0.18"}
(gdb)

2、偵錯指令碼

假設需獲取某一個連線進入dispatch_command 有哪些 command ,可以執行 gdb 指令碼[2] 獲取。

gdb 指令碼內容如下:

b dispatch_command
commands
    print command
    continue
end

執行 gdb 指令碼,然後使用 mysql 使用者端連線資料庫,並執行 SQL 語句操作,即可檢視到 gdb 偵錯資訊。

(gdb) b dispatch_command
Breakpoint 3 at 0x555558ddb37c: file /home/kyc/mysql8/sql/sql_parse.cc, line 1581.
(gdb) commands
Type commands for breakpoint(s) 3, one per line.
End with a line saying just "end".
>print command
>continue
>end
(gdb) c
Continuing.
[Switching to Thread 0x7fffe01fc700 (LWP 5941)]

Thread 49 "mysqld" hit Breakpoint 3, dispatch_command (thd=0x7fff4c000f70, com_data=0x7fffe01fbba0, command=COM_QUERY) at /home/kyc/galaxyengine/sql/sql_parse.cc:1581
1581                          enum enum_server_command command) {
$4 = COM_QUERY

三、使用 Trace 檔案偵錯

MySQL 的 debug 版提供了一個專門的 DBUG 包[3]。通過這個 DBUG 包,可獲取正在執行操作程式的 Trace 檔案。

通過控制 DBUG 開關,可以將 MySQL 的任何操作,以及所涉及的呼叫模組、函數、狀態資訊記錄在 Trace 檔案中。

設定 debug 引數

通過設定 debug 引數選項,指定跟蹤方式。

--debug [ = debug_options ]

[ = debug _ options ] 可識別字元 d、t、i 、o 等。

Debug 範例

若需獲取程式碼中DBUG_PRINT("info:" 列印的紀錄檔,可以使用 MySQL 使用者端連上伺服器,並執行如下命令,開啟 debug 引數。

set debug = 'd,info';
use test;

mysqld.trace 檔案,可獲取 use test 在 MySQL 中的執行流程。

do_command: info: Command on socket (46) = 3 (Query)
do_command: info: packet: '                 '; command: 3
dispatch_command: info: command: 3
gtid_pre_statement_checks: info: gtid_next->type=0 owned_gtid.{sidno,gno}={0,0}
THD::is_ddl_gtid_compatible: info: SQLCOM_CREATE:0 CREATE-TMP:0 SELECT:1 SQLCOM_DROP:0 DROP-TMP:0 trx:0
SELECT_LEX::prepare: info: setup_ref_array this 0x7fff1400d298    3 :    0    0    1    2    0    0
setup_fields: info: thd->mark_used_columns: 1
setup_fields: info: thd->mark_used_columns: 1
SELECT_LEX::setup_conds: info: thd->mark_used_columns: 1
THD::decide_logging_format: info: query: SELECT DATABASE()
THD::decide_logging_format: info: variables.binlog_format: 2
................
MDL_context::release_locks_stored_before: info: found lock to release ticket=0x7fff14019ae0
MDL_context::release_locks_stored_before: info: found lock to release ticket=0x7fff1412dd20
MDL_context::release_locks_stored_before: info: found lock to release ticket=0x7fff1412dcc0
net_send_ok: info: affected_rows: 0  id: 0  status: 2  warning_count: 0
net_send_ok: info: OK sent, so no more error sending allowed

本文使用幾個簡單的範例,演示了 MySQL 核心的 Debug 的幾種常見方法。當然,僅僅起到拋磚引玉的作用,更多好玩的技巧,還需讀者自行深度挖掘。

參考:

[2]: GDB 指令碼偵錯:https://sourceware.org/gdb/current/onlinedocs/gdb/Commands.html

[3]: DBUG Package[:https://dev.mysql.com/doc/refman/8.0/en/dbug-package.html


IT145.com E-mail:sddin#qq.com