从零开始学习MySQL调试跟踪
Posted GreatSQL
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了从零开始学习MySQL调试跟踪相关的知识,希望对你有一定的参考价值。
- GreatSQL社区原创内容未经授权不得随意使用,转载请联系小编并注明来源。
- GreatSQL是MySQL的国产分支版本,使用上与MySQL一致。
- 作者: Yejinrong/叶金荣
- 文章来源:GreatSQL社区投稿
-
- 编译GreatSQL
-
- 安装gdb
-
- 开始调试GreatSQL源码
- 3.1 利用gdb设置断点
- 3.2 使用 Trace 文件调试
有时为了跟踪故障需要调试MySQL/GreatSQL源码,本文介绍如何在Linux下构建MySQL/GreatSQL源码调试环境。
在这之前,我也是一名小白,一起从零开始探索吧。
本文以CentOS 8.x环境下的GreatSQL 8.0.25-16版本为例。
1. 编译GreatSQL
查看系统环境:
$ cat /etc/system-release
CentOS Linux release 8.4.2105
首先,从https://gitee.com/GreatSQL/GreatSQL/releases/ 下载GreatSQL 8.0.25-16的源码包
- Source Code
Packages Size greatsql-8.0.25-16.tar.gz 503M
接下来,参考文章 在Linux下源码编译安装GreatSQL 构建好编译环境。然后开始编译GreatSQL源码,编译参数中增加/修改debug相关选项,这样编译后得到的二进制文件才能支持调试模式,例如:
$ cd /opt/greatsql-8.0.25-16
$ mkdir -p build
$ cd build
$ cmake3 .. \\
-DBOOST_INCLUDE_DIR=/opt/boost_73_0 \\
-DLOCAL_BOOST_DIR=/opt/boost_73_0 \\
-DCMAKE_INSTALL_PREFIX=/usr/local/GreatSQL-8.0.25-16-Linux-glibc2.28-x86_64 \\
-DWITH_ZLIB=bundled \\
-DWITH_NUMA=ON \\
-DCMAKE_EXE_LINKER_FLAGS="-ljemalloc" \\
-DBUILD_CONFIG=mysql_release \\
-DWITH_TOKUDB=OFF \\
-DWITH_ROCKSDB=OFF \\
-DMAJOR_VERSION=8 \\
-DMINOR_VERSION=0 \\
-DPATCH_VERSION=25 \\
-DWITH_UNIT_TESTS=OFF \\
-DWITH_NDBCLUSTER=OFF \\
-DWITH_SSL=system \\
-DWITH_SYSTEMD=ON \\
-DWITH_LDAP=OFF \\
-DWITH_AUTHENTICATION_LDAP=OFF \\
-DWITH_DEBUG=1 \\
-DCMAKE_BUILD_TYPE=Debug \\
&& make -j8 VERBOSE=1 && make install
主要是增加两个参数 -DWITH_DEBUG=1
和 -DCMAKE_BUILD_TYPE=Debug
,注意不要有参数 -DCMAKE_BUILD_TYPE=RelWithDebInfo
。
编译完成后,即可得到包含debug功能的GreatSQL二进制文件,执行下面的命令检查:
$ cd /usr/local/GreatSQL-8.0.25-16-Linux-glibc2.28-x86_64
$ ./bin/mysqld-debug --verbose --version
/usr/local/GreatSQL-8.0.25-16-Linux-glibc2.28-x86_64/bin/mysqld-debug Ver 8.0.25-16-debug for Linux on x86_64 (Source distribution)
可以看到,输出的结果中包含 debug
关键字,这就表示成功了。
2. 安装gdb
直接执行yum安装gdb即可:
$ yum install -y gdb
$ gdb --version
GNU gdb (GDB) Red Hat Enterprise Linux 9.2-4.el8
Copyright (C) 2020 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
gdb常用的调试相关指令有以下几个:
命令 | 缩写 | 备注 |
---|---|---|
attach | 挂接/进入准备调试的进程pid | |
detach | 取消挂接进程(退出进程) | |
list | l | 显示多行源代码 |
break | b | 设置断点,程序运行到断点的位置会停下来 |
info | i | 描述程序的状态 |
run | r | 开始运行程序 |
display | disp | 跟踪查看某个变量,每次停下来都显示它的值 |
step | s | 执行下一条语句,如果该语句为函数调用,则进入函数执行其中的第一条语句 |
next | n | 执行下一条语句,如果该语句为函数调用,不会进入函数内部执行(即不会一步步地调试函数内部语句) |
p | 打印内部变量值 | |
continue | c | 继续程序的运行,直到遇到下一个断点 |
set var name=v | 设置变量的值 | |
start | st | 开始执行程序,在main函数的第一条语句前面停下来 |
file | 装入需要调试的程序 | |
kill | k | 终止正在调试的程序 |
watch | 监视变量值的变化 | |
backtrace | bt | 查看函数调用信息(堆栈) |
frame | f | 查看栈帧 |
quit | q | 退出gdb |
3. 开始调试GreatSQL源码
第一次运行gdb准备调试时,可能会提示类似下面的信息
warning: Unable to find libthread_db matching inferior\'s thread library, thread debugging will not be available.
0x00007ffb358ada41 in poll () from /lib64/libc.so.6
Missing separate debuginfos, use: dnf debuginfo-install keyutils-libs-1.5.10-9.el8.x86_64 ...
这表示缺少一些相关的debuginfo包,可以根据提示内容补充安装,例如:
dnf debuginfo-install keyutils-libs-1.5.10-9.el8.x86_64 ...
如果提示找不到这些安装包:
Could not find debuginfo package for the following installed packages: keyutils-libs-1.5.10-9.el8.x86_64 ...
可以检查yum配置文件 /etc/yum.repos.d/CentOS-Linux-Debuginfo.repo
,确认是否设置了 enable = 1
,例如:
# CentOS-Linux-Debuginfo.repo
#
# All debug packages are merged into a single repo, split by basearch, and are
# not signed.
[debuginfo]
name=CentOS Linux $releasever - Debuginfo
baseurl=http://debuginfo.centos.org/$releasever/$basearch/
gpgcheck=1
enabled=1 #<---这里要设置1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
此外,还要把GreatSQL 8.0.25-16的源码包解压缩到 /opt 目录下:
$ tar zxf PATH/greatsql-8.0.25-16.tar.gz -C /opt/
接下来,演示如何跟踪调试。
先初始化GreatSQL数据文件,然后再启动GreatSQL服务进程:
# 初始化GreatSQL
$ cd /usr/local/GreatSQL-8.0.25-16-Linux-glibc2.28-x86_64
$ ./bin/mysqld-debug --no-defaults --initialize-insecure --user=mysql --datadir=./data
# 启动GreatSQL
$ ./bin/mysqld-debug --no-defaults --user=mysql --datadir=./data1 &
# 查看进程pid
$ ps -ef | grep mysqld
...
mysql 2644322 2542442 3 14:38 pts/7 00:00:01 ./bin/mysqld-debug --no-defaults --user=mysql --datadir=./data1
# 在另一个终端(终端#2),连入GreatSQL
$ mysql -S/tmp/mysql.sock
Welcome to the MySQL monitor. Commands end with ; or \\g.
Your MySQL connection id is 7
Server version: 8.0.25-16-debug Source distribution
...
mysql>\\s
...
Server version: 8.0.25-16-debug Source distribution
...
启动gdb,准备调试跟踪GreatSQL,我们分别演示几种不同方式。
3.1 利用gdb设置断点
在 终端#1
中启动gdb,并挂接GreatSQL进程,准备跟踪
$ gdb -p 2644322
GNU gdb (GDB) Red Hat Enterprise Linux 9.2-4.el8
Copyright (C) 2020 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
...
Attaching to process 2644322
[New LWP 2643482]
[New LWP 2643483]
[New LWP 2643484]
...
[New LWP 2643522]
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
--Type <RET> for more, q to quit, c to continue without paging-- #<-- 这里按下回车,即可进入
0x00007fb7ae93ba41 in __GI___poll (fds=0x7fb7ae229140, nfds=2, timeout=-1) at ../sysdeps/unix/sysv/linux/poll.c:29
29 return SYSCALL_CANCEL (poll, fds, nfds, timeout);
(gdb)
(gdb) p mysql_sysvar_version #<-- 打印变量,查看GreatSQL版本号
$1 = flags = 68101, name = 0x7f10d1c6cc90 "innodb_version", comment = 0x6c47f92 "InnoDB version", check = 0x37dd9e2
<check_func_str(THD*, SYS_VAR*, void*, st_mysql_value*)>, update = 0x37ddeb0 <update_func_str(THD*, SYS_VAR*, void*, void const*)>,
value = 0x7e7c768 <innodb_version_str>, def_val = 0x6c38440 "8.0.25-15"
(gdb)
(gdb)
(gdb) b mysql_execute_command #<--- 输入指令"b dispatch_command"设置断点,意为当GreatSQL程序运行到这个函数时,就会停下来
Breakpoint 3 at 0x379c3f2: file /opt/greatsql-8.0.25-16/sql/sql_parse.cc, line 2875.
(gdb)
切换到 终端#2
,随便执行一条SQL命令:
mysql> select \'debug\' from dual;
回到 终端#1
,继续调试:
(gdb)
(gdb) bt #<-- 打印函数调用信息
#0 dispatch_command (thd=0x7f10a3a0b000, com_data=0x7f10d12a7370, command=COM_QUERY) at /opt/greatsql-8.0.25-16/sql/sql_parse.cc:1605
#1 0x0000000003797c48 in do_command (thd=0x7f10a3a0b000) at /opt/greatsql-8.0.25-16/sql/sql_parse.cc:1388
#2 0x0000000003991168 in handle_connection (arg=0x7f10d1f9d120) at /opt/greatsql-8.0.25-16/sql/conn_handler/connection_handler_per_thread.cc:307
#3 0x00000000052e4b22 in pfs_spawn_thread (arg=0x7f10e8a45660) at /opt/greatsql-8.0.25-16/storage/perfschema/pfs.cc:2899
#4 0x00007f10eb1e917a in start_thread (arg=<optimized out>) at pthread_create.c:479
#5 0x00007f10e9128dc3 in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:95
(gdb)
(gdb) p thd->m_query_string #<-- 打印SQL语句
$14 = str = 0x7f10a3a0e828 "select \'debug\' from dual", length = 24
(gdb)
(gdb) c #<-- 继续执行,终端#2里被阻塞的SQL语句就可以执行了
Continuing.
切回 终端#2
查看SQL语句执行结果:
mysql> select \'debug\' from dual;
+-------+
| debug |
+-------+
| debug |
+-------+
1 row in set (12 min 11.55 sec)
可以看到,因为一直被阻塞,这条SQL请求耗时超过12分钟。当 终端#2
的连接断开退出后,可以看到gdb端也有相应提示:
Thread 39 "mysqld-debug" hit Breakpoint 1, dispatch_command (thd=0x7f10a3a0b000, com_data=0x7f10d12a7370, command=COM_QUIT)
at /opt/greatsql-8.0.25-16/sql/sql_parse.cc:1605
1605 bool error = false;
(gdb)
如果不想继续跟踪调试了,只需输入指令 q
或 quit
即可退出gdb。
(gdb) quit
A debugging session is active.
Inferior 1 [process 2644322] will be detached.
Quit anyway? (y or n) y
Detaching from program: /usr/local/GreatSQL-8.0.25-16-Linux-glibc2.28-x86_64/bin/mysqld-debug, process 2644322
[Inferior 1 (process 2644322) detached]
3.2 使用 Trace 文件调试
还可以在GreatSQL客户端中设置变量 debug
为不同值,就可以输出GreatSQL运行过程中涉及的调用模块、函数、状态信息等全部信息,并记录到本地文件中。用法示例:
mysql> SET SESSION debug = \'debug_options\';
变量 debug
支持多种设置模式:
debug_options = field_1:field_2:...:field_N
field = [+|-]flag[,modifier,modifier,...,modifier]
+
, -
表示从当前debug值添加或者减少某些选项。
flag相关可选项如下:
flag | 说明 |
---|---|
d | 开启DBUG |
f | 只跟踪指定的函数 |
F | 跟踪指定的源码文件 |
i | 跟踪指定的线程 |
L | 跟踪指定的源码行数 |
n | 打印函数调用层次序号 |
N | 输出日志从0开始打印行号 |
o | 指定输出到某个文件 |
O | 类似o,每次写文件都会flush,reopen |
P | 匹配DBUG_PROCESS |
p | 打印process name |
t | 打印函数调用和退出 |
使用案例1(精简模式)
# 设置debug选项
mysql> set session debug=\'d:t:o,/tmp/mysqld.trace\';
# 执行SQL请求
mysql> select \'debug\' from dual;
+-------+
| debug |
+-------+
| debug |
+-------+
1 row in set (0.00 sec)
查看生成的trace文件:
$ cat /tmp/mysqld.trace
...
>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\' /opt/greatsql-8.0.25-16/sql/conn_handler/init_net_server_extension.cc:102
...
使用案例2(复杂模式)增加了打印文件名和行号等信息,更方便定位查找。
mysql> set session debug=\'d:t:L:F:o,/tmp/mysqld.trace\';
mysql> select \'debug\' from dual;
...
查看生成的trace文件:
$ cat /tmp/mysqld.trace
...
sql_parse.cc: <do_command
sql_parse.cc: 1269: >do_command
sql_class.h: 3287: | >THD::clear_error
sql_class.h: | <THD::clear_error
sql_error.cc: 357: | >Diagnostics_area::reset_diagnostics_area
sql_error.cc: | <Diagnostics_area::reset_diagnostics_area
net_serv.cc: 2246: | >my_net_set_read_timeout
net_serv.cc: 2247: | | enter: timeout: 28800
viosocket.cc: 380: | | >vio_socket_timeout
viosocket.cc: | | <vio_socket_timeout
net_serv.cc: | <my_net_set_read_timeout
viosocket.cc: 373: | >vio_is_blocking
viosocket.cc: | <vio_is_blocking
net_serv.cc: 1341: | >net_read_raw_loop
viosocket.cc: 169: | | >vio_read
viosocket.cc: 373: | | | >vio_is_blocking
viosocket.cc: | | | <vio_is_blocking
viosocket.cc: 1118: | | | >vio_io_wait
viosocket.cc: | | | <vio_io_wait
viosocket.cc: | | <vio_read
net_serv.cc: | <net_read_raw_loop
sql_parse.cc: 320: | THD::enter_stage: \'starting\' /opt/greatsql-8.0.25-16/sql/conn_handler/init_net_server_extension.cc:102
...
本文简单演示了如何跟踪调试GreatSQL的几种方法,更多有趣实用的方法还有待进一步挖掘,一起探索新世界吧。
P.S,我也在MacOS环境下构建了基于vscode的跟踪调试环境,但还是更喜欢在Linux终端命令行模式下工作,所以本文没介绍如何利用vscode跟踪调试,有兴趣的读者可以根据其他资料自行构建。
Enjoy GreatSQL
Java从零开始学习——Java基础
一、IDE的应用
IDE(Integrated Development Environment)集成开发环境是用于提供程序开发环境的应用程序,一般包括代码编辑器、编译器、调试器和图形用户界面等工具。集成了代码编写功能、分析功能、编译功能、调试功能等一体化的开发软件服务套。
快捷代码
-
psvm == public static void main(String[] args)
-
sout == System.out.println();
-
ctrl + D == 复制当前行到下一行
二、基础语法
注释
-
单行注释
//
-
多行注释
/*
*/
-
文档注释
/**
*/
//新建空项目的时候,需要配置项目框架,选择Java版本
标识符
关键字
标识符使用注意点
三、数据类型
Java为强类型语言,要求变量的使用要严格符合规定,所有变量都必须先定义后才能使用。
两大数据类型
基本类(primitive type)
数值类型——整数型——byte 占1字节:-128~127
——short 占2字节:-32768~32767
——int 占4字节:-2147483648~2147483647
——long 占8字节:-9223372036854775808~9223372036854775807
——浮点型——float 占4字节
——double 占8字节
——字符型——char 占2字节
布尔类型(boolean) ——占1位,其值只有true和false
引用类(reference type)
-
类(如String、Integer)
-
接口
-
数组
整数拓展
十进制
二进制(0b)
八进制(0)
十六进制(0x)
浮点数扩展
1 float f = 0.1f; 2 double d = 1.0/10; 3 System.out.println(f==d);//false 4 ? 5 //float 有限、离散、舍入误差、大约、接近但不等于,最好避免使用浮点数进行比较 6 float a = 123123123123123f; 7 float b = a + 1; 8 System.out.println(a==b);//true
字符型扩展
1 char c1 = ‘a‘; 2 System.out.println((int)c1);//97 3 char c2 = ‘中‘; 4 System.out.println((int)c2));//20013 5 //所有字符的本质还是数值 6 //编码 Unicode 表(97 = a;65 = A) 2字节 7 //0 ~ 65536;U0000 ~ UFFFF 8 ? 9 //转义字符 10 // 制表符 11 // 换行 12 System.out.println("Hello World");
布尔值扩展
1 boolean flag = true; 2 if(flag == true){} 3 if(flag){} 4 //效果一样,下方代码更精简
其他扩展
1 String s1 = new String(original:"Hello World"); 2 String s2 = new String(original:"Hello World"); 3 System.out.println(s1==s2);//false 4 ? 5 String s3 = "Hello World"; 6 String s4 = "Hello World"; 7 System.out.println(s3==s4);//true 8 //对象要从内存分析
类型转换
1 int i = 128; 2 byte b = (byte)i;//内存溢出 3 System.out.println(i);//128 4 System.out.println(b);//-128 5 ? 6 //高转低,强制转换 7 //低转告,自动转换 8 double d = i; 9 System.out.println(b);//128.0 10 ? 11 /* 12 1.不能对布尔值进行转换 13 2.不能把对象类型转换为不相干的类型 14 3.在把高容量转换成低容量时,强制转换(存在内存溢出和精度问题) 15 4.在把低容量转换成高容量时,自动转换 16 */ 17 System.out.println((int)12.3);//12 18 System.out.println((int)12.34f);//12 19 ? 20 //JDK7特性,数字之间可以用下划线分割 21 //int 范围正负20E 22 int i = 1000_000_000; 23 System.out.println(i);//1000000000 24 ? 25 int a = 20; 26 int total = i * a; //内存溢出 27 long total2 = i * a; //内存溢出,赋值之前就已经出问题 28 long total3 = i * ((long)a);//a转换成long以后,赋值就以其为类型
四、变量、常量
变量的三要素
-
变量名
-
变量类型
-
作用域
类变量 //static
实例变量 //变量类型 变量名字 = new HelloWorld();
局部变量 //写在方法里
变量是特殊的常量
通过final这个修饰词来定义(修饰符不分先后顺序)
1 //静态常量 2 static final double PI = 3.14;
变量的命名规范
五、运算符
算术运算符
1 int a = 10; 2 int b = 20; 3 System.out.println(a/b);//0,两者都是int类型,结果会有精度损失 4 System.out.println(a/(double)b);/0.5 5 long a = 123456789123L; 6 int b = 123; 7 short c = 10; 8 byte d = 8; 9 System.out.println(a+b+c+d);//Long,有Long就是Long(有Double同理) 10 System.out.println(b+c+d); //Int,没Long就是Int 11 System.out.println(c+d); //Int
关系、逻辑运算符
1 int a = 3; 2 boolean b = (a < 2)&&(a++ < 4); 3 System.out.println(b); 4 System.out.println(a);
位运算
1 /** 2 0000 0000 0 3 0000 0001 1 4 0000 0010 2 5 0000 0100 4 6 0000 1000 8 7 0001 0000 16 8 ? 9 A = 0011 1100; 10 B = 0000 1101; 11 ? 12 A&B = 0000 1100; 13 A|B = 0011 1101; 14 A^B = 0011 0001; 15 ~B = 1111 0010; 16 ? 17 2*8如何计算最快,2*2*2*2 18 ? 19 << *2 20 >> /2 21 ? 22 2<<3 == 16; 23 */ 24 int a = 10; 25 int b = 30; 26 //加号两侧有String类型的,则将另一侧转换为字符串类型进行拼接 27 System.out.println(""+a+b);//1030 28 //先运算前面的,然后再拼接 29 System.out.println(a+b+"");//30 30 //三元运算符 31 int score = 80; 32 //x ? y : z 如何x为ture,则y,否则z 33 String type = score < 60 ? "不及格" : "及格";
六、包(Package)
建立分级目录
建分级目录时(com.kevin.www),取消项目右上角的compact middle packlages,即可实现。
包命名规则
一般利用公司域名倒置作为包名。
使用import语句导入需要使用的包。
1 //导入路径下所有包文件 2 import com.kevin.www.*;
七、JavaDoc
1 /** 2 * @author Kevin 作者 3 * @version 1.0 版本号 4 * @since 1.8 最早使用的JDK版本 5 * @param name 参数名 6 * @return 返回值情况 7 * @throws Exception异常抛出情况 8 */
利用命令行生成文档
cmd中输入javadoc -encoding UTF-8 -charset UTF-8 name.java
可以生成一份网页文档,可以查看其中内容
利用IDEA生成文档
Tools-> Generate JavaDoc,打开 javadoc 文档配置页面
以上是关于从零开始学习MySQL调试跟踪的主要内容,如果未能解决你的问题,请参考以下文章