一部分 LINUX 系统安装
选择CENTOS 7 GNOME桌面兼容XWINDOWS
192.168.2.30 SINGLEDB 1CPU 4GB内存
1.1 DNS
echo "nameserver 202.96.134.133" >>/etc/resolv.conf
echo "nameserver 202.96.128.68 " >>/etc/resolv.conf
echo "nameserver 202.96.154.8 " >>/etc/resolv.conf
echo "nameserver 202.96.154.15 " >>/etc/resolv.conf
1.2 配置好了YUM源 我使用CENTOS7自带的YUM源
第二部分下载源码
https://dev.mysql.com/downloads/mysql/
MySQL Community Server 8.0.20
Select Operation System: Source Code
Select OS Version:ALL
拉到最下面看到
Generic Linux (Architecture Independent), Compressed TAR Archive
Includes Boost Headers
点击右边下载按钮
跳的账号注册,选择最下面的蓝色小字体
No Thanks Just start my download
上传到虚机CENTOS7 /root 目录下
创建目录和用户
groupadd -g 1101 dba
useradd -u 1102 -g dba -d /home/mysql -s /bin/bash -c "Oracle Software Owner" mysql
mkdir -p /u01/mysql8/soft /u01/mysql8/data /u01/mysql8/binlog
mkdir -p /u01/mysql8/buildcd root
tar -zvxf mysql-boost-8.0.20.tar.gz -C u01/mysql8
cd u01/mysql8
mv mysql-8.0.20/ sourcechown -R mysql /u01/mysql8
注意 该目录下需要很大的空间,因为编译MYSQL8 需要7GB
第三部分下载VIM CSCOPE
vim插件cscope使用方法
yum -y install cscope
建立索引文件(会生成cscope.out文件)
$ cd U01/mysql8/source
$ cscope -Rbqk
上面执行过后会生成三个文件,cscope.out就是生成的数据库,
cscope.in.out和cscope.po.out是q控制对应的索引。
[root@SINGLEDB mysql8020]# ll *.out
-rw-r--r--. 1 root root 10903552 7月 6 06:10 cscope.in.out
-rw-r--r--. 1 root root 90794833 7月 6 06:10 cscope.out
-rw-r--r--. 1 root root 132811152 7月 6 06:10 cscope.po.out
进入源码根目录后VIM 空文件名 会出现VIM的版本号
~ VIM - Vi IMproved
~
~ 版本 7.4.160
~ 维护人 Bram Moolenaar 等
~ 修改者 <bugzilla@redhat.com>
~ Vim 是可自由分发的开放源代码软件
~
~ 成为 Vim 的注册用户!
~ 输入 :help register<Enter> 查看说明
~
~ 输入 :q<Enter> 退出
~ 输入 :help<Enter> 或 <F1> 查看在线帮助
~ 输入 :help version7<Enter> 查看版本信息
已经设置好了CSCOPE,并自动调用CSCOPE.OUT
按ECS键 进入VIM命令模式
:cs find s get_files
Cscope tag: get_files
# 行 文件名 / 上下文 / 行
1 1021 sql/dd/impl/bootstrap/bootstrapper.cc <<GLOBAL>>
tablespace_def->get_files();
2 174 sql/plugin_table.h <<get_files>>
const List<const Plugin_tablespace_file> &get_files() const {
3 110 storage/innobase/arch/arch0log.cc <<get_files>>
int Log_Arch_Client_Ctx::get_files(Log_Arch_Cbk *cbk_func, void *ctx) {
4 448 storage/innobase/clone/clone0copy.cc <<init_redo_copy>>
redo_error = m_redo_ctx.get_files(add_redo_file_callback, context);
5 79 storage/innobase/include/arch0log.h <<m_end_lsn>>
int get_files(Log_Arch_Cbk *cbk_func, void *ctx);
Type number and <Enter> (empty cancels): 5
输入5 就进入该文件的头文件定义出
int stop(byte *trailer, uint32_t &len, uint64_t &offset);
/** Get archived data file details
@param[in] cbk_func callback called for each file
@param[in] ctx callback function context
@return error code */
int get_files(Log_Arch_Cbk *cbk_func, void *ctx);
/** Release archived data so that system can purge it */
void release();
Type number and <Enter> (empty cancels): 3 就显示该函数的实现文件
CSCOPE其他命令参考:
使用cscope find s xxx来进行cscope的使用即可。s是参数,其他参数及意义如下:
s: 查找C语言符号,即查找函数名、宏、枚举值等出现的地方
g: 查找函数、宏、枚举等定义的位置,类似ctags所提供的功能
d: 查找本函数调用的函数
c: 查找调用本函数的函数
t: 查找指定的字符串
e: 查找egrep模式,相当于egrep功能,但查找速度快多了
f: 查找并打开文件,类似vim的find功能
i: 查找
MYSQL8的源码也有WIN版本,可以使用WIN平台下的文本加色软件来看.
源码根目录下是各个MYSQL8组件套餐,MYROUTE也在其中.
我们这样看是精态方法, 大部分代码都是CC扩展名.
需要动态看源码之间的关系,就需要用到GDB调试工具,下会我们谈源码动态看法!
动态看需要DEBUG方式编译MYSQL8
第四部分 GCC安装
编译 MySQL 8.0 版本,需要 GCC 版本 5.5.0 最好是5.5 太老了编不动,太新了编译出错!
下载
http://ftp.tsukuba.wide.ad.jp/software/gcc/releases/
上传到
/u01/rpm_install
mkdir -p u01/GCC
解压
# tar -zxvf gcc-5.5.0.tar.gz -C u01/GCC
#下载mpfr、gmp、mpc、isl等依赖包 晚上下载有点慢
cd u01/GCC/gcc-5.5.0
[root@SINGLEDB gcc-5.5.0]# ./contrib/download_prerequisites
2020-07-06 10:20:32 URL: ftp://gcc.gnu.org/pub/gcc/infrastructure/mpfr-3.1.4.tar.bz2 [1279284] -> "./mpfr-3.1.4.tar.bz2"
2020-07-06 10:21:30 URL: ftp://gcc.gnu.org/pub/gcc/infrastructure/mpc-1.0.3.tar.gz [669925] -> "./mpc-1.0.3.tar.gz" [1]
2020-07-06 10:23:25 URL: ftp://gcc.gnu.org/pub/gcc/infrastructure/isl-0.18.tar.bz2 [1658291] -> "./isl-0.18.tar.bz2" [1]
2020-07-06 10:30:21 URL: ftp://gcc.gnu.org/pub/gcc/infrastructure/gmp-6.1.0.tar.bz2 [2383840] -> "./gmp-6.1.0.tar.bz2" [1]
gmp-6.1.0.tar.bz2: 确定
mpfr-3.1.4.tar.bz2: 确定
mpc-1.0.3.tar.gz: 确定
isl-0.18.tar.bz2: 确定
All prerequisites downloaded successfully.
觉得太慢可以自行下载
yum -y install gmp-devel // 编译依赖此库
yum -y install mpfr-devel 编译依赖此库
yum -y install libmpc-devel 编译依赖此库
yum -y install bzip2 // 编译依赖此库
因为安装CENTOS7时只选择了桌面系统,没有带开发工具
所以编译前安装包
yum install -y glibc-headers
yum install -y gcc-c++
建立编译输出目录
mkdir build
cd build
配置
../configure --enable-checking=release --enable-languages=c,c++ --disable-multilib --enable-threads=posix
参数解释:
–enable-checking=release 增加一些检查,也可以–disable-checking生成的编译器在编译过程中不做额外检查
–enable-languages=c,c++ 你要让你的gcc支持的编程语言
–disable-multilib 取消多目标库编译(取消32位库编译)
编译安装
make && make install
然后听着音乐,看着黑客帝国式地刷屏
WAITING.....
WAITING.....
23*10分后 5GB.....
[root@localhost build]# gcc -v
使用内建 specs。
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/local/libexec/gcc/x86_64-unknown-linux-gnu/5.5.0/lto-wrapper
目标:x86_64-unknown-linux-gnu
配置为:../configure --enable-checking=release --enable-languages=c,c++ --disable-multilib --enable-threads=posix
线程模型:posix
gcc 版本 5.5.0 (GCC)
第五步安装CMAKE 3.5.1
安装必要的软件依赖:
yum install -y bison bison-devel libaio-devel git
yum install -y ncurses-devel openssl openssl-devel
yum install -y make automake binutils
CMAKE版本过低去直接下载二进制版本,
https://cmake.org/download/
运行SH
#sh cmake-3.18.0-rc3-Linux-x86_64.sh
显示前要说明 按回车键直到出现如下
Do you accept the license? [yn]: YES
Do you want to include the subdirectory cmake-3.18.0-rc3-Linux-x86_64?
Saying no will install in: "/u01/rpm_install" [Yn]:
解压完后
# cd cmake-3.18.0-rc3-Linux-x86_64/bin
然后复制到/USR/BIN
[root@localhost bin]# cp c* usr/bin
cp:是否覆盖"/usr/bin/ccmake"?y
cp:是否覆盖"/usr/bin/cmake"?y
cp:是否覆盖"/usr/bin/cpack"?y
cp:是否覆盖"/usr/bin/ctest"?y
cd /u01/rpm_install/cmake-3.18.0-rc3-Linux-x86_64/share
cp -r cmake-3.18 /usr/share
[root@CENT0S7 ~]# cmake /V
cmake version 3.18.0-rc3
CMake suite maintained and supported by Kitware (kitware.com/cmake).
第六步 使用cmake进行生成编译环境:
进入MySQL源文件目录,新建configure做为编译目录,并进入该目录:
mkdir configure
cd configure
使用cmake进行生成编译环境:注意 \ 前的空格
cmake .. \
-DWITH_BOOST=/u01/mysql8/source/boost/ \
-DWITH_DEBUG=ON \
-DWITH_SSL=bundled \
-DWITH_INNODB_MEMCACHED=ON \
-DWITH_ZLIB=system \
-DDEFAULT_CHARSET=utf8mb4 \
-DCMAKE_INSTALL_PREFIX=/u01/mysql8/soft \
-DMYSQL_DATADIR=/u01/mysql8/data \
-DWITHOUT_CSV_STORAGE_ENGINE=1 \
-DWITHOUT_BLACKHOLD_STORAGE_ENGINE=1 \
-DWITHOUT_FEDERATED_STORAGE_ENGINE=1 \
-DWITHOUT_ARCHIVE_STORAGE_ENGINE=1 \
-DWITHOUT_MRG_MYISAM_STORAGE_ENGINE=1 \
-DWITHOUT_NDBCLUSTER_STORAGE_ENGINE=1 \
-DFORCE_INSOURCE_BUILD=1 \
-DCMAKE_CXX_COMPILER=/usr/local/bin/g++ \
-DCMAKE_C_COMPILER=/usr/local/bin/gcc
这里重点是
-DWITH_DEBUG=ON 开启DEBUG模式
-DWITH_BOOST= 告诉BOOST已经下载了,目录
-DMYSQL_DATADIR=
-DCMAKE_INSTALL_PREFIX这两个是安装目录和数据目录,需要看环境改写
其他的可以照抄
如果编译出现错误,请先删除CMakeCache.txt后,再重新编译:
rm -rf CMakeCache.txt
CMAKE 环境设置OK! 显示如下开心的信息:
CMake Warning:
Manually-specified variables were not used by the project:
WITHOUT_BLACKHOLD_STORAGE_ENGINE
WITHOUT_MRG_MYISAM_STORAGE_ENGINE
WITHOUT_NDBCLUSTER_STORAGE_ENGINE
-- Build files have been written to: /u01/mysql/source/mysql-8.0.20/configure
第七步 MYSQL8的编译
设置字符模式并关机配置多点CPU
查看当前的开机默认运行方式:systemctl get-default
设置开机不自启图形界面:systemctl set-default multi-user.target
设置开机启动图形界面:systemctl set-default graphical.target
重启后进入
# cd /u01/mysql8/source/configure
编译
make
出错处理:
[ 3%] Generating uca900_zh_tbls.cc, uca900_ja_tbls.cc
../runtime_output_directory/uca9dump: lib64/libstdc++.so.6: version `CXXABI_1.3.9' not found (required by ../runtime_output_directory/uca9dump)
make[2]: *** [strings/uca900_zh_tbls.cc] 错误 1
make[1]: *** [strings/CMakeFiles/strings_objlib.dir/all] 错误 2
YUM补救安装下
yum install y libstdc++
软件包 libstdc++-4.8.5-39.el7.x86_64 已安装并且是最新版本
检查下
#cd usr/lib64
[root@localhost lib64]# ll libstdc++*
lrwxrwxrwx. 1 root root 19 7月 9 22:01 libstdc++.so.6 -> libstdc++.so.6.0.19
-rwxr-xr-x. 1 root root 991616 8月 7 2019 libstdc++.so.6.0.19
# strings libstdc++.so.6.0.19 | grep 'CXXABI_'
果真没有
全系统检查一下,哪里还有SO
[root@localhost config]# find / -name "libstdc++.so.6*"
/usr/local/lib64/libstdc++.so.6.0.21-gdb.py
/usr/local/lib64/libstdc++.so.6.0.21
/usr/local/lib64/libstdc++.so.6
/u01/rpm_install/gcc-5.5.0/build/stage1-x86_64-unknown-linux-gnu/libstdc++-v3/src/.libs/libstdc++.so.6
/u01/rpm_install/gcc-5.5.0/build/stage1-x86_64-unknown-linux-gnu/libstdc++-v3/src/.libs/libstdc++.so.6.0.21
/u01/rpm_install/gcc-5.5.0/build/x86_64-unknown-linux-gnu/libstdc++-v3/src/.libs/libstdc++.so.6
/u01/rpm_install/gcc-5.5.0/build/x86_64-unknown-linux-gnu/libstdc++-v3/src/.libs/libstdc++.so.6.0.21
/u01/rpm_install/gcc-5.5.0/build/prev-x86_64-unknown-linux-gnu/libstdc++-v3/src/.libs/libstdc++.so.6
/u01/rpm_install/gcc-5.5.0/build/prev-x86_64-unknown-linux-gnu/libstdc++-v3/src/.libs/libstdc++.so.6.0.21
检查 strings XXXX | grep 'CXXABI_'
发现有,然后复制该目录
cp u01/rpm_install/gcc-5.5.0/build/stage1-x86_64-unknown-linux-gnu/libstdc++-v3/src/.libs/libstdc++.so.6.0.21 usr/lib64
软链接
[root@mysql_8 lib64]# rm -f libstdc++.so.6
[root@mysql_8 lib64]# ln -s libstdc++.so.6.0.21 libstdc++.so.6
这下可以编译了,花了2个小时达到69%,真心累!
Scanning dependencies of target myisam_ftdump
[ 69%] Building CXX object storage/myisam/CMakeFiles/myisam_ftdump.dir/myisam_ftdump.cc.o
[ 69%] Linking CXX executable ../../runtime_output_directory/myisam_ftdump
[ 69%] Built target myisam_ftdump
Scanning dependencies of target myisamchk
[ 69%] Building CXX object storage/myisam/CMakeFiles/myisamchk.dir/myisamchk.cc.o
[ 69%] Linking CXX executable ../../runtime_output_directory/myisamchk
[ 69%] Built target myisamchk
Scanning dependencies of target myisamlog
[ 69%] Building CXX object storage/myisam/CMakeFiles/myisamlog.dir/myisamlog.cc.o
[ 69%] Linking CXX executable ../../runtime_output_directory/myisamlog
[ 69%] Built target myisamlog
Scanning dependencies of target myisampack
[ 69%] Building CXX object storage/myisam/CMakeFiles/myisampack.dir/myisampack.cc.o
[ 69%] Linking CXX executable ../../runtime_output_directory/myisampack
[ 69%] Built target myisampack
Scanning dependencies of target mytap
[ 69%] Building CXX object unittest/mytap/CMakeFiles/mytap.dir/tap.cc.o
[ 69%] Linking CXX static library libmytap.a
[ 69%] Built target mytap
Scanning dependencies of target pfs_connect_attr-t
[ 69%] Building CXX object storage/perfschema/unittest/CMakeFiles/pfs_connect_attr-t.dir/pfs_connect_attr-t.cc.o
[ 69%] Building CXX object storage/perfschema/unittest/CMakeFiles/pfs_connect_attr-t.dir/__/__/__/sql/sql_builtin.cc.o
[ 69%] Linking CXX executable ../../../runtime_output_directory/pfs_connect_attr-t
7.5GB 编译文件大小
为了快 开启并行编译命令是 4 是CPU数量 make -j 4 不过不建议 容易报错.
如果遇到错误,则继续MAKE下 重新编译都能编译过去.
安装
make install
安装我们指定目录下
进入安装目录
cd u01/mysql8/soft
[root@CENT0S7 soft]# dirsize
20K ./docs
228M ./lib
384K ./include
1.1G ./bin
9.0M ./share
576M ./mysql-test
20K ./support-files
0 ./run
0 ./var
832K ./man
1.9G .
[root@CENT0S7 soft]#
然后按正常二进制安装流程走了
新建数据库初始化SHELL
vim mysql_initdb.sh
./bin/mysqld --initialize --user=mysql --basedir=/u01/mysql8/soft/
--datadir=/u01/mysql8/data --character-set-server=UTF8MB4
注意一定要设置字符集UTF8MB4 ,最好在一行
第二个注意是初始化前DATA目录必须RM -RF 掉
初始化遇到任何ERROR而终止的话,DATA目录也必须RM -RF 掉
然后百度去处理问题
成功如下信息:
[root@localhost mysql8020debug]# sh mysql_initdb.sh
2020-07-10T23:22:03.011126Z 0 [System] [MY-013169] [Server] /u01/mysql/mysql8020debug/bin/mysqld (mysqld 8.0.20-debug) initializing of server in progress as process 3807
2020-07-10T23:22:03.033145Z 1 [System] [MY-013576] [InnoDB] InnoDB initialization has started.
2020-07-10T23:22:06.600075Z 1 [System] [MY-013577] [InnoDB] InnoDB initialization has ended.
2020-07-10T23:22:14.145163Z 6 [Note] [MY-010454] [Server] A temporary password is generated for root@localhost: YYUgDtrs6*x#
YYUgDtrs6*x#
备份下我们的DEBUG二进制版本
[root@CENT0S7 mysql8]# tar -zcvf mysql8024_debug_cenots7.tar.gz soft/ -C build/
[root@CENT0S7 mysql8]# cd build/
[root@CENT0S7 build]# ll
总用量 637M
-rw-r--r--. 1 root root 637M 4月 30 23:40 mysql8024_debug_cenots7.tar.gz
设置服务模式
进入支持文件夹
# cd/u01/mysql8/soft/support-files
编辑服务文件 mysql.server 另外一个是多实例 mysqld_multi.server
cp mysql.server mysqld
# vim mysqld
basedir=/u01/mysql8/soft
datadir=/u01/mysql8/data
另外在207行处
conf=/etc/my.cnf
改成 conf=/u01/mysql8/soft/my.cnf
保存后复制到服务文件夹中
# cp mysqld /etc/init.d/
创建配置文件
# vim u01/mysql8/soft/my.cnf
[mysqld]
basedir=/u01/mysql8/softdatadir=/u01/mysql8/data
character-set-server=UTF8MB4
socket=/tmp/mysql.sock
init_connect='SET NAMES utf8'
join_buffer_size = 128M
sort_buffer_size = 2M
read_rnd_buffer_size = 2M
[mysqld_safe]
pid-file=/u01/mysql8/soft/mysqld.pid
log-error =/u01/mysql8/soft/mysql-error.log
#InnoDB#
default-storage-engine=INNODB
innodb_buffer_pool_size=128M
innodb_log_file_size=256M
innodb_log_buffer_size=12M
启动服务:
[root@localhost init.d]# service mysqld start
Starting MySQL.2020-07-10T23:42:54.738179Z mysqld_safe error:
log-error set to '/u01/mysql/mysql8020debug/mysql-error.log',
however file don't exists. Create writable for user 'mysql'.
ERROR! The server quit without updating PID file
(/u01/mysql/mysql8020debug/data/localhost.localdomain.pid).
添加用户,密码和组:
这里添加DBA组, mysql用户 mysql密码
groupadd -g 1000 dba
useradd -u 1100 -g dba -d /home/mysql -s /bin/bash -c "zabbix mysql8.0 Owner" mysql
echo "mysql" | passwd --stdin mysql
设置目录权限
cd /
chown root:dba u01
cd /u01
chown -R mysql:dba mysql8/
成功启动服务
[root@localhost u01]# service mysqld start
Starting MySQL... SUCCESS!
[root@localhost u01]# service mysqld stop
Shutting down MySQL.. SUCCESS!
[root@localhost u01]# service mysqld start
登录MYSQL服务里
新开个SHELL窗口 切换到MYSQL用户下
cd u01/mysql8/soft
[mysql@localhost mysql8024debug]$ ./bin/mysql -uroot -pYYUgDtrs6*x#
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 8
Server version: 8.0.20-debug
Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.mysql>
注意临时密码有特殊符号需要这样处理 : ./mysql -uroot -p'<6nC&pSfg9Du'
更改ROOT密码
mysql> alter user 'root'@'localhost' identified by "123456" password expire never;
mysql> use mysql
mysql> update user set host='%' where host='localhost';
mysql> flush privileges;
所谓动态看代码就类似我们用JAVA开发样,进入调试代码,
看函数怎么调函数,查看函数传递的变量值,设置某行为断点,当运行此行的时候就暂停,然后查相应的变量,表达式的值.步进,步出!
不过小仙上次写C语言的使用NETBEAN 图形工具来调用GDB的,所以比较方便,不用记那么多命令。
毕竟LINUX下好多命令,每个命令有贼多参数,参看起来又不那么友好,不可能所有参数都学一遍,经常百度下该命令,常用命令,和使用列子!
启动调试命令GDB
[root@localhost u01]# gdb
GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-51.el7
Copyright (C) 2013 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. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
输入HELP命令
(gdb) help
List of classes of commands:
aliases -- Aliases of other commands
breakpoints -- Making program stop at certain points
data -- Examining data
files -- Specifying and examining files
internals -- Maintenance commands
obscure -- Obscure features
running -- Running the program
stack -- Examining the stack
status -- Status inquiries
support -- Support facilities
tracepoints -- Tracing of program execution without stopping the program
user-defined -- User-defined commands
Type "help" followed by a class name for a list of commands in that class.
Type "help all" for the list of all commands.
Type "help" followed by command name for full documentation.
Type "apropos word" to search for commands related to "word".
Command name abbreviations are allowed if unambiguous.
退出命令
(gdb) quit
GDB 命令简介
篇幅较长,大家稍微看看有个印象
1. 启动GDB的方法有以下几种:
gdb <program>
program也就是你的执行文件,一般在当前目录下。
gdb <program> core
用gdb同时调试一个运行程序和core文件,core是程序非法执行后core dump后产生的文件。
gdb <program> <PID>
如果你的程序是一个服务程序,那么你可以指定这个服务程序运行时的进程ID。
gdb会自动attach上去,并调试他。program应该在PATH环境变量中搜索得到。
2. 当以gdb <program>方式启动gdb后,gdb会在PATH路径和当前目录中搜索<program>的源文件
3. 暂停/恢复程序运行
调试程序中,暂停程序运行是必须的,GDB可以方便地暂停程序的运行。
你可以设置程序的在哪行停住,在什么条件下停住,在收到什么信号时停住等等。
以便于你查看运行时的变量,以及运行时的流程。
当进程被gdb停住时,你可以使用info program 来查看程序的是否在运行,
进程号,被暂停的原因。
在gdb中,我们可以有以下几种暂停方式:断点(BreakPoint)、
观察点(Watch Point)、捕捉点(Catch Point)、信号(Signals)、
线程停止(Thread Stops)。如果要恢复程序运行,可以使用c或是 continue命令。
4. 设置断点(Break Points)
我们用break命令来设置断点。下面有几点设置断点的方法:
break <function>
在进入指定函数时停住。C++中可以使用class::function或function(type,type)格式来指定函数名。
break <linenum>
在指定行号停住。
break +offset
break -offset
在当前行号的前面或后面的offset行停住。offiset为自然数。
break filename:linenum
在源文件filename的linenum行处停住。
break filename:function
在源文件filename的function函数的入口处停住。
break *address
在程序运行的内存地址处停住。
break
break命令没有参数时,表示在下一条指令处停住。
break ... if <condition>
...可以是上述的参数,condition表示条件,在条件成立时停住。
比如在循环体中,可以设置break if i==100,表示当i为100时停住程序。
查看断点时,可使用info命令,如下所示:(注:n表示断点号)
info breakpoints [n]
info break [n]
5. 设置观察点(WatchPoint)
观察点一般来观察某个表达式(变量也是一种表达式)的值是否有变化了,
如果有变化,马上停住程序。我们有下面的几种方法来设置观察点:
watch <expr>
为表达式(变量)expr设置一个观察点。一表达式值有变化时,马上停住程序。
rwatch <expr>
当表达式(变量)expr被读时,停住程序。
awatch <expr>
当表达式(变量)的值被读或被写时,停住程序。
info watchpoints
列出当前所设置了的所有观察点。
[编辑] 设置捕捉点(CatchPoint)
你可设置捕捉点来捕捉程序运行时的一些事件。如:载入共享库(动态链接库)或是C++的异常。
设置捕捉点的格式为:
catch <event>
当event发生时,停住程序。event可以是下面的内容:
throw 一个C++抛出的异常。(throw为关键字)
catch 一个C++捕捉到的异常。(catch为关键字)
exec 调用系统调用exec时。(exec为关键字,目前此功能只在HP-UX下有用)
fork 调用系统调用fork时。(fork为关键字,目前此功能只在HP-UX下有用)
vfork 调用系统调用vfork时。(vfork为关键字,目前此功能只在HP-UX下有用)
load 或 load <libname> 载入共享库(动态链接库)时。(load为关键字,目前此功能只在HP-UX下有用)
unload 或 unload <libname> 卸载共享库(动态链接库)时。(unload为关键字,目前此功能只在HP-UX下有用)
tcatch <event>
只设置一次捕捉点,当程序停住以后,该点被自动删除。
6. 维护停止点
上面说了如何设置程序的停止点,GDB中的停止点也就是上述的三类。
在GDB中,如果你觉得已定义好的停止点没有用了,
你可以使用delete、clear、disable、enable这几个命令来进行维护。
clear
清除所有的已定义的停止点。
clear <function>
clear <filename:function>
清除所有设置在函数上的停止点。
clear <linenum>
clear <filename:linenum>
清除所有设置在指定行上的停止点。
delete [breakpoints] [range...]
删除指定的断点,breakpoints为断点号。如果不指定断点号,则表示删除所有的断点。
range 表示断点号的范围(如:3-7)。其简写命令为d。
比删除更好的一种方法是disable停止点,disable了的停止点,GDB不会删除,
当你还需要时,enable即可,就好像回收站一样。
disable [breakpoints] [range...]
7. 恢复程序运行和单步调试
当程序被停住了,你可以用continue命令恢复程序的运行直到程序结束,
或下一个断点到来。也可以使用step或next命令单步跟踪程序。
continue [ignore-count]
c [ignore-count]
fg [ignore-count]
恢复程序运行,直到程序结束,或是下一个断点到来。ignore-count表示忽略其后的断点次数。
continue,c,fg三个命令都是一样的意思。
step <count>
单步跟踪,如果有函数调用,他会进入该函数。进入函数的前提是,此函数被编译有debug信息。
很像VC等工具中的step in。后面可以加count也可以不加,不加表示一条条地执行,
加表示执行后面的count条指令,然后再停住。
next <count>
同样单步跟踪,如果有函数调用,他不会进入该函数。很像VC等工具中的step over。
后面可以加count也可以不加,不加表示一条条地执行,加表示执行后面的count条指令,然后再停住。
set step-mode
set step-mode on
打开step-mode模式,于是,在进行单步跟踪时,程序不会因为没有debug信息而不停住。
这个参数很有利于查看机器码。
set step-mode off
关闭step-mode模式。
finish
运行程序,直到当前函数完成返回。并打印函数返回时的堆栈地址和返回值及参数值等信息。
until 或 u
当你厌倦了在一个循环体内单步跟踪时,这个命令可以运行程序直到退出循环体。
stepi 或 si
nexti 或 ni
单步跟踪一条机器指令!一条程序代码有可能由数条机器指令完成,
stepi和nexti可以单步执行机器指令。
与之一样有相同功能的命令是 “display/i $pc” ,
当运行完这个命令后,
单步跟踪会在打出程序代码的同时打出机器指令(也就是汇编代码)
查看当前MYSQLD进程号 和客户端进程
[root@localhost u01]# ps -ef | grep mysqld
MYSQL是线程模型,调试进程反而抓不到!
MYSQL客户端操作:
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| bookstore |
| information_schema |
| mysql |
| performance_schema |
| sys |
+--------------------+
5 rows in set (0.00 sec)
mysql> use bookstore;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
Database changed
mysql> show tables;
+---------------------+
| Tables_in_bookstore |
+---------------------+
| books |
| books2 |
+---------------------+
2 rows in set (0.00 sec)
mysql> select * from books;
+----+------------------------+-------+---------------------+
| id | title | price | publishDate |
+----+------------------------+-------+---------------------+
| 1 | Java编程思想 | 98.50 | 2005-01-02 00:00:00 |
| 2 | HeadFirst设计模式 | 55.70 | 2010-11-09 00:00:00 |
| 3 | 第一行Android代码 | 69.90 | 2015-06-23 00:00:00 |
| 4 | C++编程思想 | 88.50 | 2004-01-09 00:00:00 |
| 5 | HeadFirst Java | 55.70 | 2013-12-17 00:00:00 |
| 6 | 疯狂Android | 19.50 | 2014-07-31 00:00:00 |
+----+------------------------+-------+---------------------+
6 rows in set (0.05 sec)
mysql> show processlist;
+----+-----------------+-----------+-----------+---------+-------+------------------------+------------------+
| Id | User | Host | db | Command | Time | State | Info |
+----+-----------------+-----------+-----------+---------+-------+------------------------+------------------+
| 5 | event_scheduler | localhost | NULL | Daemon | 12096 | Waiting on empty queue | NULL |
| 14 | root | localhost | bookstore | Query | 0 | starting | show processlist |
+----+-----------------+-----------+-----------+---------+-------+------------------------+------------------+
2 rows in set (0.00 sec)
+-----------+----------------+------------------+------------------+----------------+--------------+------------+
| thread_id | processlist_id | processlist_user | processlist_host | processlist_db | thread_os_id | type |
+-----------+----------------+------------------+------------------+----------------+--------------+------------+
| 43 | 5 | NULL | NULL | NULL | 14183 | FOREGROUND |
| 46 | 7 | NULL | NULL | NULL | 14187 | FOREGROUND |
| 54 | 14 | root | localhost | bookstore | 24760 | FOREGROUND |
+-----------+----------------+------------------+------------------+----------------+--------------+------------+
3 rows in set (0.01 sec)
一顿操作猛如虎 重点就是抓到 进程->MYSQL线程->系统线程
注意这里是 14->54->24760
GDB 操作:
[root@localhost ~]# clear
[root@localhost ~]# ps -ef | grep mysqld
root 13815 1 0 19:11 pts/1 00:00:00 /bin/sh /u01/mysql/mysql8020debug/bin/mysqld_safe --datadir=/u01/mysql/mysql8020debug/data
--pid-file=/u01/mysql/mysql8020debug/data/localhost.localdomain.pid
mysql 14138 13815 1 19:11 pts/1 00:02:03 /u01/mysql/mysql8020debug/bin/mysqld --basedir=/u01/mysql/mysql8020debug
--datadir=/u01/mysql/mysql8020debug/data --plugin-dir=/u01/mysql/mysql8020debug/lib/plugin
--user=mysql --log-error=/u01/mysql/mysql8020debug/mysql-error.log
--pid-file=/u01/mysql/mysql8020debug/data/localhost.localdomain.pid --socket=/tmp/mysql.sock --port=3306
##使用GDB调试MYSQLD 选择第二个 MYSQL用户下的进程14138
##为什么不是13185
(gdb) info thread
Id Target Id Frame
* 1 process 13815 "mysqld_safe" 0x00007f9214a9046c in waitpid () from /lib64/libc.so.6
##因为它是MYSQLD_SAFE
[root@localhost mysql8020debug]# clear
[root@localhost mysql8020debug]# gdb -p 14138
GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-51.el7
Copyright (C) 2013 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. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Attaching to process 14138
Reading symbols from /u01/mysql/mysql8020debug/bin/mysqld...
##等5秒 它读取进程DEBUG信息
done.
(no debugging symbols found)...done.
Loaded symbols for /lib64/libnss_dns.so.2
0x00007f868dde1c3d in poll () from /lib64/libc.so.6
Missing separate debuginfos, use: debuginfo-install glibc-2.17-307.el7.1.x86_64 keyutils-libs-1.5.8-3.el7.x86_64 krb5-libs-1.11.3-49.el7.x86_64 krb5-libs-1.15.1-46.el7.x86_64 libcom_err-1.42.9-17.el7.x86_64 libcom_err-1.42.9-4.el7.x86_64 libgcc-4.8.5-39.el7.x86_64 libselinux-2.2.2-6.el7.x86_64 libselinux-2.5-15.el7.x86_64 nss-softokn-freebl-3.15.4-2.el7.x86_64 openssl-libs-1.0.1e-34.el7.x86_64 openssl-libs-1.0.2k-19.el7.x86_64 pcre-8.32-12.el7.x86_64 pcre-8.32-17.el7.x86_64 sssd-client-1.11.2-65.el7.x86_64 zlib-1.2.7-13.el7.x86_64 zlib-1.2.7-18.el7.x86_64
(gdb)
(gdb) ##等待你输入命令
##查看线程
(gdb) info thread
Id Target Id Frame
42 Thread 0x7f867f4a7700 (LWP 14141) "mysqld" 0x00007f868fb47a35 in pthread_cond_wait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
41 Thread 0x7f867e29a700 (LWP 14142) "mysqld" 0x00007f868fb47a35 in pthread_cond_wait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
40 Thread 0x7f867da99700 (LWP 14143) "mysqld" 0x00007f868fb47a35 in pthread_cond_wait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
39 Thread 0x7f867d298700 (LWP 14144) "mysqld" 0x00007f868fb47a35 in pthread_cond_wait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
38 Thread 0x7f867ca97700 (LWP 14145) "mysqld" 0x00007f868fb47a35 in pthread_cond_wait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
37 Thread 0x7f86679ff700 (LWP 14146) "mysqld" 0x00007f868fb47a35 in pthread_cond_wait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
36 Thread 0x7f86671fe700 (LWP 14147) "mysqld" 0x00007f868fb47a35 in pthread_cond_wait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
35 Thread 0x7f86669fd700 (LWP 14148) "mysqld" 0x00007f868fb47a35 in pthread_cond_wait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
34 Thread 0x7f86661fc700 (LWP 14149) "mysqld" 0x00007f868fb47a35 in pthread_cond_wait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
33 Thread 0x7f86659fb700 (LWP 14150) "mysqld" 0x00007f868fb47a35 in pthread_cond_wait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
32 Thread 0x7f86651fa700 (LWP 14151) "mysqld" 0x00007f868fb47de2 in pthread_cond_timedwait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
31 Thread 0x7f86649f9700 (LWP 14152) "mysqld" 0x00007f868fb47de2 in pthread_cond_timedwait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
30 Thread 0x7f863dffd700 (LWP 14153) "mysqld" 0x00007f868fb47de2 in pthread_cond_timedwait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
29 Thread 0x7f863d7fc700 (LWP 14154) "mysqld" 0x00007f868fb47de2 in pthread_cond_timedwait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
28 Thread 0x7f863cffb700 (LWP 14155) "mysqld" 0x00007f868fb47de2 in pthread_cond_timedwait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
27 Thread 0x7f863c7fa700 (LWP 14156) "mysqld" 0x00007f868fb47de2 in pthread_cond_timedwait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
26 Thread 0x7f863bff9700 (LWP 14157) "mysqld" 0x00007f868fb47de2 in pthread_cond_timedwait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
25 Thread 0x7f863b7f8700 (LWP 14161) "mysqld" 0x00007f868fb47de2 in pthread_cond_timedwait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
24 Thread 0x7f863aff7700 (LWP 14162) "mysqld" 0x00007f868fb47de2 in pthread_cond_timedwait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
23 Thread 0x7f863a7f6700 (LWP 14163) "mysqld" 0x00007f868fb47de2 in pthread_cond_timedwait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
22 Thread 0x7f8639ff5700 (LWP 14166) "mysqld" 0x00007f868fb47a35 in pthread_cond_wait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
21 Thread 0x7f86397f4700 (LWP 14167) "mysqld" 0x00007f868fb4ae9d in nanosleep () from /lib64/libpthread.so.0
20 Thread 0x7f8638ff3700 (LWP 14168) "mysqld" 0x00007f868fb47de2 in pthread_cond_timedwait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
19 Thread 0x7f862bfff700 (LWP 14169) "mysqld" 0x00007f868fb47de2 in pthread_cond_timedwait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
18 Thread 0x7f867ea42700 (LWP 14170) "xpl_worker0" 0x00007f868fb47de2 in pthread_cond_timedwait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
17 Thread 0x7f867e9fb700 (LWP 14171) "xpl_worker1" 0x00007f868fb47de2 in pthread_cond_timedwait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
16 Thread 0x7f867e9b4700 (LWP 14172) "mysqld" 0x00007f868fb47a35 in pthread_cond_wait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
15 Thread 0x7f868074c700 (LWP 14177) "mysqld" 0x00007f868fb47a35 in pthread_cond_wait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
14 Thread 0x7f862b7fe700 (LWP 14178) "mysqld" 0x00007f868fb47de2 in pthread_cond_timedwait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
13 Thread 0x7f862affd700 (LWP 14179) "mysqld" 0x00007f868fb47a35 in pthread_cond_wait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
12 Thread 0x7f862a7fc700 (LWP 14180) "mysqld" 0x00007f868fb47a35 in pthread_cond_wait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
11 Thread 0x7f8629ffb700 (LWP 14181) "mysqld" 0x00007f868fb47a35 in pthread_cond_wait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
10 Thread 0x7f86297fa700 (LWP 14182) "mysqld" 0x00007f868fb47a35 in pthread_cond_wait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
9 Thread 0x7f867e96d700 (LWP 14183) "mysqld" 0x00007f868fb47a35 in pthread_cond_wait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
8 Thread 0x7f867e925700 (LWP 14184) "mysqld" 0x00007f868dd2558a in sigwaitinfo () from /lib64/libc.so.6
7 Thread 0x7f867e8dd700 (LWP 14185) "mysqld" 0x00007f868dde6bf9 in syscall () from /lib64/libc.so.6
6 Thread 0x7f8628ff9700 (LWP 14187) "mysqld" 0x00007f868fb47a35 in pthread_cond_wait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
5 Thread 0x7f867c275700 (LWP 24685) "mysqld" 0x00007f868fb47a35 in pthread_cond_wait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
---Type <return> to continue, or q <return> to quit---
4 Thread 0x7f86641f8700 (LWP 24725) "mysqld" 0x00007f868fb47a35 in pthread_cond_wait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
3 Thread 0x7f86641b0700 (LWP 24760) "mysqld" 0x00007f868dde1cff in ppoll () from /lib64/libc.so.6
2 Thread 0x7f8664168700 (LWP 25684) "mysqld" 0x00007f868fb47a35 in pthread_cond_wait@@GLIBC_2.3.2 () from /lib64/libpthread.so.0
* 1 Thread 0x7f868ff58980 (LWP 14138) "mysqld" 0x00007f868dde1c3d in poll () from /lib64/libc.so.6
##在众多线程中哪个是我们的客户端线程呢?
LWP 24760==>THREAD_OS_ID
##切换到对应的线程上 3
(gdb) thread 3
[Switching to thread 3 (Thread 0x7f86641b0700 (LWP 24760))]
#0 0x00007f868dde1cff in ppoll () from lib64/libc.so.6
##打印堆栈信息:
(gdb) bt
#0 0x00007f868dde1cff in ppoll () from /lib64/libc.so.6
#1 0x00000000055a00bf in vio_io_wait (vio=0x7f8658001920, event=VIO_IO_EVENT_READ, timeout=28800000) at /u01/mysql/source/mysql-8.0.20/vio/viosocket.cc:842
#2 0x000000000559eb44 in vio_socket_io_wait (vio=0x7f8658001920, event=VIO_IO_EVENT_READ) at /u01/mysql/source/mysql-8.0.20/vio/viosocket.cc:105
#3 0x000000000559ecdd in vio_read (vio=0x7f8658001920, buf=0x7f8658006c50 "\001", size=4) at /u01/mysql/source/mysql-8.0.20/vio/viosocket.cc:168
#4 0x00000000037d61fb in net_read_raw_loop (net=0x7f86580048d8, count=4) at /u01/mysql/source/mysql-8.0.20/sql-common/net_serv.cc:1221
#5 0x00000000037d6512 in net_read_packet_header (net=0x7f86580048d8) at /u01/mysql/source/mysql-8.0.20/sql-common/net_serv.cc:1304
#6 0x00000000037d6e27 in net_read_packet (net=0x7f86580048d8, complen=0x7f86641afa80) at /u01/mysql/source/mysql-8.0.20/sql-common/net_serv.cc:1594
#7 0x00000000037d70c1 in my_net_read (net=0x7f86580048d8) at /u01/mysql/source/mysql-8.0.20/sql-common/net_serv.cc:1684
#8 0x0000000003bff056 in Protocol_classic::read_packet (this=0x7f8658002130) at /u01/mysql/source/mysql-8.0.20/sql/protocol_classic.cc:1404
#9 0x0000000003bffc1d in Protocol_classic::get_command (this=0x7f8658002130, com_data=0x7f86641afbd0, cmd=0x7f86641afbfc)
at /u01/mysql/source/mysql-8.0.20/sql/protocol_classic.cc:2809
#10 0x0000000003616dd7 in do_command (thd=0x7f8658002db0) at /u01/mysql/source/mysql-8.0.20/sql/sql_parse.cc:1220
#11 0x00000000037db47f in handle_connection (arg=0xa13d2e0) at /u01/mysql/source/mysql-8.0.20/sql/conn_handler/connection_handler_per_thread.cc:302
#12 0x0000000005330060 in pfs_spawn_thread (arg=0xa161680) at /u01/mysql/source/mysql-8.0.20/storage/perfschema/pfs.cc:2854
#13 0x00007f868fb43ea5 in start_thread () from /lib64/libpthread.so.0
#14 0x00007f868ddec8dd in clone () from /lib64/libc.so.6
##设置断点函数 my_net_read
(gdb) b my_net_read
Breakpoint 1 at 0x37d7058: file /u01/mysql/source/mysql-8.0.20/sql-common/net_serv.cc, line 1681.
##客户端发起SQL语句
mysql> select * from books;
##你会发现它卡着,不返回任何数据
##GDB 单步调试 一路火花带闪电 你可以输入C命令 然后碰到断点函数就停下来,我们这里N 过去
(gdb) n
Single stepping until exit from function ppoll,
which has no line number information.
vio_io_wait (vio=0x7f8658001920, event=VIO_IO_EVENT_READ, timeout=28800000) at /u01/mysql/source/mysql-8.0.20/vio/viosocket.cc:846
846 } while (ret < 0 && vio_should_retry(vio) &&
(gdb) n
834 do {
(gdb) n
850 vio->poll_shutdown_flag.clear();
(gdb) n
853 switch (ret) {
(gdb) n
866 DBUG_ASSERT(pfd.revents & revents);
(gdb) n
867 break;
(gdb) n
870 MYSQL_END_SOCKET_WAIT(locker, 0);
(gdb) n
871 return ret;
(gdb) n
788 DBUG_TRACE;
(gdb) n
872 }
(gdb) n
vio_socket_io_wait (vio=0x7f8658001920, event=VIO_IO_EVENT_READ) at /u01/mysql/source/mysql-8.0.20/vio/viosocket.cc:116
116 ret = 0;
(gdb) n
117 break;
(gdb) n
120 return ret;
(gdb) n
121 }
(gdb) n
vio_read (vio=0x7f8658001920, buf=0x7f8658006c50 "\001", size=4) at /u01/mysql/source/mysql-8.0.20/vio/viosocket.cc:146
146 while ((ret = mysql_socket_recv(vio->mysql_socket, (SOCKBUF_T *)buf, size,
(gdb) n
170 return ret;
(gdb) n
138 DBUG_TRACE;
(gdb) p buf
$1 = (uchar *) 0x7f8658006c50 "\024"
(gdb) dislplay
Undefined command: "dislplay". Try "help".
(gdb) dislpaly
Undefined command: "dislpaly". Try "help".
(gdb) display
(gdb) n
171 }
(gdb) n
net_read_raw_loop (net=0x7f86580048d8, count=4) at /u01/mysql/source/mysql-8.0.20/sql-common/net_serv.cc:1224
1224 if (recvcnt == VIO_SOCKET_ERROR) {
(gdb) n
1232 else if (!recvcnt) {
(gdb) n
1237 count -= recvcnt;
(gdb) n
1238 buf += recvcnt;
(gdb) n
1240 thd_increment_bytes_received(recvcnt);
(gdb) p buf
$2 = (uchar *) 0x7f8658006c54 "\004-"
(gdb) n
1220 while (count) {
(gdb) n
1245 if (count) {
(gdb) n
1266 return count != 0;
(gdb) n
1267 }
(gdb) n
net_read_packet_header (net=0x7f86580048d8) at /u01/mysql/source/mysql-8.0.20/sql-common/net_serv.cc:1305
1305 server_extension->m_after_header(net, user_data, count, rc);
(gdb) p user_data
$3 = (void *) 0x7f8658002db0
(gdb) p count
$4 = 4
(gdb) n
1312 if (rc) return true;
(gdb) n
1314 DBUG_DUMP("packet_header", net->buff + net->where_b, NET_HEADER_SIZE);
(gdb) n
1316 pkt_nr = net->buff[net->where_b + 3];
(gdb) n
1322 if (pkt_nr != (uchar)net->pkt_nr) {
(gdb) n
1340 net->pkt_nr++;
(gdb) n
1342 return false;
(gdb) n
1343 }
(gdb) n
net_read_packet (net=0x7f86580048d8, complen=0x7f86641afa80) at /u01/mysql/source/mysql-8.0.20/sql-common/net_serv.cc:1596
1596 net->compress_pkt_nr = net->pkt_nr;
(gdb) n
1598 if (net->compress) {
(gdb) n
1614 pkt_len = uint3korr(net->buff + net->where_b);
(gdb) n
1617 if (!pkt_len) goto end;
(gdb) n
1619 pkt_data_len = max(pkt_len, *complen) + net->where_b;
(gdb) n
1622 if ((pkt_data_len >= net->max_packet) && net_realloc(net, pkt_data_len))
(gdb) n
1626 if (net_read_raw_loop(net, pkt_len)) goto error;
(gdb) n
1629 DBUG_DUMP("net read", net->buff + net->where_b, pkt_len);
(gdb) n
1630 net->reading_or_writing = 0;
(gdb) n
1631 return pkt_len;
(gdb) n
1636 }
(gdb) n
my_net_read (net=0x7f86580048d8) at /u01/mysql/source/mysql-8.0.20/sql-common/net_serv.cc:1685
1685 if (len == MAX_PACKET_LENGTH) {
(gdb) p len
$5 = 20
(gdb) n
1697 net->read_pos = net->buff + net->where_b;
(gdb) n
1698 if (len != packet_error)
## 终于发现了SQL,输入P命令 显示某个变量 值
(gdb) p net->read_pos
$6 = (unsigned char *) 0x7f8658006c50 "\003select * from booksore\005books\005books\002id\002id\f?"
(gdb)
##继续一路火花带闪电
(gdb) n
1700 return static_cast<ulong>(len);
(gdb) p len
$7 = 20
(gdb) n
1812 }
(gdb) n
Protocol_classic::read_packet (this=0x7f8658002130) at /u01/mysql/source/mysql-8.0.20/sql/protocol_classic.cc:1405
1405 if (input_packet_length != packet_error) {
(gdb) n
1406 DBUG_ASSERT(!m_thd->net.error);
(gdb) n
1407 bad_packet = false;
(gdb) n
1408 input_raw_packet = m_thd->net.read_pos;
(gdb) n
1409 return 0;
(gdb) n
1414 }
(gdb) n
Protocol_classic::get_command (this=0x7f8658002130, com_data=0x7f86641afbd0, cmd=0x7f86641afbfc) at /u01/mysql/source/mysql-8.0.20/sql/protocol_classic.cc:2819
2819 if (input_packet_length == 0) /* safety */
(gdb) p input_packet_length
$8 = 20
(gdb) n
2826 input_raw_packet[input_packet_length] = '\0'; /* safety */
(gdb) n
2828 *cmd = (enum enum_server_command)(uchar)input_raw_packet[0];
(gdb) p cmd
$9 = (enum_server_command *) 0x7f86641afbfc
(gdb) p *cmd
$10 = COM_SLEEP
(gdb) n
2830 if (*cmd >= COM_END) *cmd = COM_END; // Wrong command
(gdb) p COM_END
$11 = COM_END
(gdb) p *cmd
$12 = COM_QUERY
(gdb) p cmd
$13 = (enum_server_command *) 0x7f86641afbfc
(gdb) p 0x7f86641afbfc
$14 = 140215181835260
(gdb) n
2832 DBUG_ASSERT(input_packet_length);
(gdb) n
2834 input_packet_length--;
(gdb) n
2835 input_raw_packet++;
(gdb) n
2837 return parse_packet(com_data, *cmd);
(gdb) p com_data
$15 = (COM_DATA *) 0x7f86641afbd0
(gdb) n
2838 }
(gdb) n
do_command (thd=0x7f8658002db0) at /u01/mysql/source/mysql-8.0.20/sql/sql_parse.cc:1221
1221 thd->m_server_idle = false;
##开启源码代码窗口,显示行号并跳到1221行
vim /u01/mysql/source/mysql-8.0.20/sql/sql_parse.cc
: set number
: 1221G
##定位到C++代码区
1208 /*
1209 Because of networking layer callbacks in place,
1210 this call will maintain the following instrumentation:
1211 - IDLE events
1212 - SOCKET events
1213 - STATEMENT events
1214 - STAGE events
1215 when reading a new network packet.
1216 In particular, a new instrumented statement is started.
1217 See init_net_server_extension()
1218 */
1219 thd->m_server_idle = true;
1220 rc = thd->get_protocol()->get_command(&com_data, &command);
1221 thd->m_server_idle = false;
1222
1223 if (rc) {
1224 #ifndef DBUG_OFF
1225 char desc[VIO_DESCRIPTION_SIZE];
1226 vio_description(net->vio, desc);
1227 DBUG_PRINT("info", ("Got error %d reading command from socket %s",
1228 net->error, desc));
1229 #endif // DBUG_OFF
1230 /* Instrument this broken statement as "statement/com/error" */
1231 thd->m_statement_psi = MYSQL_REFINE_STATEMENT(
1232 thd->m_statement_psi, com_statement_info[COM_END].m_key);
1233
1234 /* Check if we can continue without closing the connection */
1235
1236 /* The error must be set. */
1237 DBUG_ASSERT(thd->is_error());
1238 thd->send_statement_status();
1239
1240 /* Mark the statement completed. */
1241 MYSQL_END_STATEMENT(thd->m_statement_psi, thd->get_stmt_da());
1242 thd->m_statement_psi = nullptr;
1243 thd->m_digest = nullptr;
1244
1245 if (rc < 0) {
1246 return_value = true; // We have to close it.
1247 goto out;
1248 }
1249 net->error = 0;
1250 return_value = false;
1251 goto out;
1252 }
1253
##GDB端奇怪的事情,执行的不是1221后面的代码 直接跳到1256行
1223 if (rc) {
1256 vio_description(net->vio, desc);
1257 DBUG_PRINT("info", ("Command on %s = %d (%s)", desc, command,
1260 DBUG_PRINT("info", ("packet: '%*.s'; command: %d",
1263 if (thd->get_protocol_classic()->bad_packet)
1267 thd->get_protocol_classic()->get_output_packet()->shrink(
1268 thd->variables.net_buffer_length);
1270 my_net_set_read_timeout(net, thd->variables.net_read_timeout);
1272 DEBUG_SYNC(thd, "before_command_dispatch");
1274 return_value = dispatch_command(thd, &com_data, command);
1275 thd->get_protocol_classic()->get_output_packet()->shrink(
1276 thd->variables.net_buffer_length);
1280 DBUG_ASSERT(thd->m_digest == nullptr);
1281 DBUG_ASSERT(thd->m_statement_psi == nullptr);
1282 return return_value;
1164 DBUG_TRACE;
1282 return return_value;
1283 }
handle_connection (arg=0xa13d2e0) at /u01/mysql/source/mysql-8.0.20/sql/conn_handler/connection_handler_per_thread.cc:301
301 while (thd_connection_alive(thd)) {
##此时MYSQL客户端获得了结果集.
mysql> select * from books;
+----+------------------------+-------+---------------------+
| id | title | price | publishDate |
+----+------------------------+-------+---------------------+
| 1 | Java编程思想 | 98.50 | 2005-01-02 00:00:00 |
| 2 | HeadFirst设计模式 | 55.70 | 2010-11-09 00:00:00 |
| 3 | 第一行Android代码 | 69.90 | 2015-06-23 00:00:00 |
| 4 | C++编程思想 | 88.50 | 2004-01-09 00:00:00 |
| 5 | HeadFirst Java | 55.70 | 2013-12-17 00:00:00 |
| 6 | 疯狂Android | 19.50 | 2014-07-31 00:00:00 |
+----+------------------------+-------+---------------------+
6 rows in set (19 min 9.88 sec)
##发现GDB执行的函数是在1221后面的代码
1254 #ifndef DBUG_OFF
1255 char desc[VIO_DESCRIPTION_SIZE];
1256 vio_description(net->vio, desc);
1257 DBUG_PRINT("info", ("Command on %s = %d (%s)", desc, command,
1258 command_name[command].str));
1259 #endif // DBUG_OFF
1260 DBUG_PRINT("info", ("packet: '%*.s'; command: %d",
1261 thd->get_protocol_classic()->get_packet_length(),
1262 thd->get_protocol_classic()->get_raw_packet(), command));
1263 if (thd->get_protocol_classic()->bad_packet)
1264 DBUG_ASSERT(0); // Should be caught earlier
1265
1266 // Reclaim some memory
1267 thd->get_protocol_classic()->get_output_packet()->shrink(
1268 thd->variables.net_buffer_length);
1269 /* Restore read timeout value */
1270 my_net_set_read_timeout(net, thd->variables.net_read_timeout);
1271
1272 DEBUG_SYNC(thd, "before_command_dispatch");
1273
1274 return_value = dispatch_command(thd, &com_data, command);
1275 thd->get_protocol_classic()->get_output_packet()->shrink(
1276 thd->variables.net_buffer_length);
1277
1278 out:
1279 /* The statement instrumentation must be closed in all cases. */
1280 DBUG_ASSERT(thd->m_digest == nullptr);
1281 DBUG_ASSERT(thd->m_statement_psi == nullptr);
1282 return return_value;
1283 }
最后感觉代码量不是很多,或许BT显示堆栈函数比较少,或者N 单步调试NEXT方式没有显示更多的函数调用路径. 当然我们还是掌握了方法!
上次有两个问题没搞明白
1 是 为什么一定要开启调试线程 ? 因为MYSQL是线程模型,当是你也可以调试整个MYSQLD服务进程
使用GDB 要先设置断点,MYSQLD遇到断点所有线程和服务都停了下来. 为此你不调试线程也可以.
不过我们是要跟踪某个线程执行流程,执行了哪些函数? 如果调试进程是无法抓到的,.
2 是 为什么没有执行 IF(RC) {...} 里面的代码? 当时折腾了会儿,后来几天想起来 估计不符合RC的条件
[root@localhost ~]# gdp -p 6041
(gdb) b do_command
Breakpoint 1 at 0x3616c8e: file /u01/mysql/source/mysql-8.0.20/sql/sql_parse.cc, line 1161.
(gdb) n
Single stepping until exit from function poll,
which has no line number information.
GDB 挂死了!
杀伤GDB 再来,顶多重启系统
调试窗口:
(gdb) b do_command
Breakpoint 1 at 0x3616c8e: file /u01/mysql/source/mysql-8.0.20/sql/sql_parse.cc, line 1161.
(gdb) c
Continuing.
MySQL客户端窗口:
mysql> select * from books;
调试窗口:
[Switching to Thread 0x7f1f940f5700 (LWP 3398)]
Breakpoint 1, do_command (thd=0x7f1f6c006790)
at /u01/mysql/source/mysql-8.0.20/sql/sql_parse.cc:1161
1161 NET *net = nullptr;
## 啥意思呢?
info thread
* 2 Thread 0x7f1f940f5700 (LWP 3398) "mysqld" do_command (thd=0x7f1f6c006790)
明白了! GDB 调试服务进程时,设置断点函数后, 客户端发出SQL请求, 这时GDB处于死人状态.
为此在设置断点后输入C 命令让GDB继续下去. 然后才让客户端发SQL请求,这时GDB就触发了断点函数,并且自动切换到该线程上, 并且停止1161这行,只要N的命令就可以追踪下去了!
这样就省了我们去查客户端的进程,线程,OS线程麻烦! 不过在生产环境,也就是多用户同时发出SQL语句下,这方法估计不好使.
不过对于我们学习内核源码来说,没有那么多客户端并发操作!
源码代码:
1158 bool do_command(THD *thd) {
1159 bool return_value;
1160 int rc;
1161 NET *net = nullptr;
1162 enum enum_server_command command;
1163 COM_DATA com_data;
1164 DBUG_TRACE;
1165 DBUG_ASSERT(thd->is_classic_protocol());
然后一路火花带闪电N下去, 遇到了RC P一下 结果真的为0
(gdb) n
1164 DBUG_TRACE;
(gdb) n
1165 DBUG_ASSERT(thd->is_classic_protocol());
(gdb) n
1171 thd->lex->set_current_select(nullptr);
(gdb) n
1179 thd->clear_error(); // Clear error message
(gdb) n
1180 thd->get_stmt_da()->reset_diagnostics_area();
(gdb) n
1188 net = thd->get_protocol_classic()->get_net();
(gdb) n
1189 my_net_set_read_timeout(net, thd->variables.net_wait_timeout);
(gdb) n
1190 net_new_transaction(net);
(gdb) n
1206 DEBUG_SYNC(thd, "before_do_command_net_read");
(gdb) n
1219 thd->m_server_idle = true;
(gdb) n
1220 rc = thd->get_protocol()->get_command(&com_data, &command);
(gdb) n
1221 thd->m_server_idle = false;
(gdb) n
1223 if (rc) {
(gdb) p rc
$1 = 0
(gdb) n
1256 vio_description(net->vio, desc);
(gdb) n
1257 DBUG_PRINT("info", ("Command on %s = %d (%s)", desc, command,
(gdb) n
1260 DBUG_PRINT("info", ("packet: '%*.s'; command: %d",
(gdb) n
1263 if (thd->get_protocol_classic()->bad_packet)
(gdb) n
1267 thd->get_protocol_classic()->get_output_packet()->shrink(
(gdb) n
1268 thd->variables.net_buffer_length);
(gdb) n
1270 my_net_set_read_timeout(net, thd->variables.net_read_timeout);
(gdb) n
1272 DEBUG_SYNC(thd, "before_command_dispatch");
(gdb) n
1274 return_value = dispatch_command(thd, &com_data, command);
(gdb) n
1275 thd->get_protocol_classic()->get_output_packet()->shrink(
(gdb) n
1276 thd->variables.net_buffer_length);
(gdb) n
1280 DBUG_ASSERT(thd->m_digest == nullptr);
(gdb) n
1281 DBUG_ASSERT(thd->m_statement_psi == nullptr);
(gdb) n
1282 return return_value;
(gdb) n
1164 DBUG_TRACE;
(gdb) n
1282 return return_value;
(gdb) n
1283 }
(gdb) n
handle_connection (arg=0xa739020)
at /u01/mysql/source/mysql-8.0.20/sql/conn_handler/connection_handler_per_thread.cc:301
301 while (thd_connection_alive(thd)) {
在1275 1276 行的函数执行完后,客户端就收到了数据
Breakpoint 1, do_command (thd=0x7f1f6c006790)
at /u01/mysql/source/mysql-8.0.20/sql/sql_parse.cc:1161
1161 NET *net = nullptr;
(gdb) n
1164 DBUG_TRACE;
(gdb) n
1165 DBUG_ASSERT(thd->is_classic_protocol());
(gdb) n
1171 thd->lex->set_current_select(nullptr);
(gdb) n
1179 thd->clear_error(); // Clear error message
(gdb) n
1180 thd->get_stmt_da()->reset_diagnostics_area();
(gdb) n
1188 net = thd->get_protocol_classic()->get_net();
(gdb) n
1189 my_net_set_read_timeout(net, thd->variables.net_wait_timeout);
(gdb) n
1190 net_new_transaction(net);
(gdb) n
1206 DEBUG_SYNC(thd, "before_do_command_net_read");
(gdb) n
1219 thd->m_server_idle = true;
(gdb) n
1220 rc = thd->get_protocol()->get_command(&com_data, &command);
(gdb) n
1221 thd->m_server_idle = false;
(gdb) n
1223 if (rc) {
(gdb) n
1256 vio_description(net->vio, desc);
(gdb) n
1257 DBUG_PRINT("info", ("Command on %s = %d (%s)", desc, command,
(gdb) n
1260 DBUG_PRINT("info", ("packet: '%*.s'; command: %d",
(gdb) n
1263 if (thd->get_protocol_classic()->bad_packet)
(gdb) n
1267 thd->get_protocol_classic()->get_output_packet()->shrink(
(gdb) n
1268 thd->variables.net_buffer_length);
(gdb) n
1270 my_net_set_read_timeout(net, thd->variables.net_read_timeout);
(gdb) n
1272 DEBUG_SYNC(thd, "before_command_dispatch");
(gdb) n
1274 return_value = dispatch_command(thd, &com_data, command);
(gdb) p thd
$17 = (THD *) 0x7f1f6c006790
(gdb) p com_data
$18 = {com_init_db = {db_name = 0x7f1f6c00bbe1 "select * from books", length = 19},
com_refresh = {options = 225 '\341'}, com_kill = {id = 139772932701153},
com_set_option = {opt_command = 1811987425}, com_stmt_execute = {
stmt_id = 139772932701153, open_cursor = 19, parameters = 0x7f1f6c00bbe8,
parameter_count = 139772932688388, has_new_types = 32 ' '}, com_stmt_fetch = {
stmt_id = 139772932701153, num_rows = 19}, com_stmt_send_long_data = {
stmt_id = 139772932701153, param_number = 19, longdata = 0x7f1f6c00bbe8 "* from books",
length = 139772932688388}, com_stmt_prepare = {
query = 0x7f1f6c00bbe1 "select * from books", length = 19}, com_stmt_close = {
stmt_id = 1811987425}, com_stmt_reset = {stmt_id = 1811987425}, com_query = {
query = 0x7f1f6c00bbe1 "select * from books", length = 19}, com_field_list = {
table_name = 0x7f1f6c00bbe1 "select * from books", table_name_length = 19,
query = 0x7f1f6c00bbe8 "* from books", query_length = 1811974660}}
(gdb) p command
$19 = COM_QUERY
(gdb) n
1275 thd->get_protocol_classic()->get_output_packet()->shrink(
(gdb) n
1276 thd->variables.net_buffer_length);
1274行的dispatch_command(thd, &com_data, command); 这个是命令分配器吗?
THD 估计是线程, COM_DATA是命令数据包, COMMAND 是命令类型
不过还是感觉有点跳跃性, 语法分析,优化分析,生成执行计划,读MVCC 之类的函数 都没有找到, 感觉就一两个函数就结束了.
各位亲,最近微信改了推送规则,公众号文章已不是按时间先后推送文章,而是根据权重推荐文章了。
如果您看我们的推文少了,或者从来不评论、不点赞、不点在看、不转发,那您以后可能就再也收不到我们的推送了。
所以,如果您以后还想收到我们的推送,可以给标个星标,经常点在看和赞,转发分享,给我们评论留言,感谢各位亲们一路支持




