MYSQL 源码阅读 六
作者:互联网
前期节要
MYSQL源码阅读 一
MYSQL源码阅读 二
MYSQL源码阅读 三
MYSQL 源码阅读 四
MYSQL 源码阅读 五
上次有两个问题没搞明白
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 是命令类型
标签:get,gdb,源码,command,阅读,MYSQL,net,thd,com 来源: https://blog.51cto.com/15080028/2643041