[转帖]关于MYSQL 5.7 新连接建立流程源码接口(和5.6不同) _MySQL, Oracle及数据库讨论区_Weblogic技术|Tuxedo技术|中间件技术|Oracle论坛|JAVA论坛|Linux/Unix技术|hadoop论坛_联动北方技术论坛  
网站首页 | 关于我们 | 服务中心 | 经验交流 | 公司荣誉 | 成功案例 | 合作伙伴 | 联系我们 |
联动北方-国内领先的云技术服务提供商
»  游客             当前位置:  论坛首页 »  自由讨论区 »  MySQL, Oracle及数据库讨论区 »
总帖数
1
每页帖数
101/1页1
返回列表
0
发起投票  发起投票 发新帖子
查看: 1952 | 回复: 0   主题: [转帖]关于MYSQL 5.7 新连接建立流程源码接口(和5.6不同)         下一篇 
ad222888
注册用户
等级:新兵
经验:66
发帖:134
精华:0
注册:2016-9-25
状态:离线
发送短消息息给ad222888 加好友    发送短消息息给ad222888 发消息
发表于: IP:您无权察看 2018-8-27 17:45:37 | [全部帖] [楼主帖] 楼主

今天在看运维内参第三章源码的时候,发现书上很多代码入口函数和我用的5.7.14的源码对不上,然后再看了一下5.6的源码,

书上写的基本都是5.6的源码(书是2015年开始写的)5.7.14在连接这一块做了相当大的改动,加了很多抽象类,变得更加复杂了。

当然这也是软件模块划分的更加清晰的必然的结果,顺便说一下MYSQL在UNIX上使用的select/poll 这种多路I/O转接模型来监听

客户端的连接,监听的只是读操作,当客户端发起连接的时候select/poll通过监听LISTEN scoket上的是否有读取信息来判断,是否

有新的连接到来,然后调用线程回调函数建立新的线程来处理这个新的accpet的socket通道(还会判断是否有空闲的线程队列而不需要

新建立新的线程来处理),线程的建立我们说是比进程代价小很多,他没有独立的内存三区(共享区,代码段和堆内存),但是他也有PCB

有独立的栈空间所以能节约一点是一点吧。

关于MYSQL的源码各种多态太多了,真是眼花缭乱

下面是我使用到一些断点。

(gdb) info b
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   0x0000000000ebd333 in main(int, char**) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/main.cc:25
breakpoint already hit 1 time
2       breakpoint     keep y   0x00000000016e350d in inline_mysql_socket_accept(char const*, uint, PSI_socket_key, MYSQL_SOCKET, sockaddr*, socklen_t*) at /root/mysql5.7.14/percona-server-5.7.14-7/include/mysql/psi/mysql_socket.h:1110
breakpoint already hit 18 times
6       breakpoint     keep y   0x0000000000f1b8d9 in Connection_handler_manager::process_new_connection(Channel_info*) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/conn_handler/connection_handler_manager.cc:289
breakpoint already hit 15 times
8       breakpoint     keep y   0x00000000016e197f in handle_connection(void*) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/conn_handler/connection_handler_per_thread.cc:239
breakpoint already hit 6 times
9      breakpoint     keep y   0x0000000000f1b1d5 in Connection_handler_manager::check_and_incr_conn_count(bool) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/conn_handler/connection_handler_manager.cc:105
breakpoint already hit 1 time
12      breakpoint     keep y   0x00000000016e1f41 in Per_thread_connection_handler::add_connection(Channel_info*) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/conn_handler/connection_handler_per_thread.cc:399


下面按照调用流程解释一下这几个函数作用,希望帮到在5.7.14下使用GDB调试MYSQL连接的同学一点帮助

1、不解释主函数main

2、

 inline_mysql_socket_accept


 当然也就是sokcet accept返回新的socket文件描述符的函数,因为找不到多路I/O转接 select和poll的入口用了这招去找

  找到多路I/O转接接口变为了Channel_info* Mysqld_socket_listener::listen_for_connection_event()

Channel_info就是一个抽象类,这个函数会返回连接socket的相关信息给

Channel_info这个基类指针。

  又有多太发生了擦。

这里贴出一点和运维内参同样的代码,但是入口函数全部变了,而且除了逻辑相似,很多实现都变了

大量的用

点击(此处)折叠或打开

#ifdef HAVE_POLL //多路I/O转接判断是否有写连接到来
int retval= poll(&m_poll_info.m_fds[0], m_socket_map.size(), -1);
#else
m_select_info.m_read_fds= m_select_info.m_client_fds;
int retval= select((int) m_select_info.m_max_used_connection,
&m_select_info.m_read_fds, 0, 0, 0);
#endif


点击(此处)折叠或打开

#ifdef HAVE_POLL //多路I/O转接判断是否有写连接到来
int retval= poll(&m_poll_info.m_fds[0], m_socket_map.size(), -1);
#else
m_select_info.m_read_fds= m_select_info.m_client_fds;
int retval= select((int) m_select_info.m_max_used_connection,
&m_select_info.m_read_fds, 0, 0, 0);
#endif


点击(此处)折叠或打开

for (uint retry= 0; retry < MAX_ACCEPT_RETRY; retry++) //重试次数MAX_ACCEPT_RETRY好像是10
{
      socket_len_t length= sizeof(struct sockaddr_storage);
      connect_sock= mysql_socket_accept(key_socket_client_connection, listen_sock,
      (struct sockaddr *)(&cAddr), &length);//这里没什么好说的返回新的sokcet文件描述符了
      if (mysql_socket_getfd(connect_sock) != INVALID_SOCKET ||//返回的新的socket文件描述符无效(-1)
      (socket_errno != SOCKET_EINTR && socket_errno != SOCKET_EAGAIN)) //如果是信号中断或者eagain重试没关系再来
      break;
}


点击(此处)折叠或打开

Channel_info* channel_info= NULL;
//注意下面有多态发生这里和5.6很多不同了
if (is_unix_socket) //是否是本地UNIX_DOMAIN SOCKET
channel_info= new (std::nothrow) Channel_info_local_socket(connect_sock);
else//不是就是远程TCP/IP SCOKET
channel_info= new (std::nothrow)
Channel_info_tcpip_socket(connect_sock,
(mysql_socket_getfd(listen_sock)
== m_extra_tcp_port_fd)); //根据connect_scok 建立channel_info
if (channel_info == NULL) //分配内存是否正常不正常搞下面的。
{
      (void) mysql_socket_shutdown(connect_sock, SHUT_RDWR);
      (void) mysql_socket_close(connect_sock);
      connection_errors_internal++;
      return NULL;
}
return channel_info;


栈帧

#0  inline_mysql_socket_accept (src_file=0x21c5f30 "/root/mysql5.7.14/percona-server-5.7.14-7/sql/conn_handler/socket_connection.cc", src_line=928, key=3, socket_listen=..., addr=0x7fffffffdc50, addr_len=0x7fffffffdcdc)
at /root/mysql5.7.14/percona-server-5.7.14-7/include/mysql/psi/mysql_socket.h:1110
#1  0x00000000016e4981 in Mysqld_socket_listener::listen_for_connection_event (this=0x2fca760) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/conn_handler/socket_connection.cc:928
#2  0x0000000000ecf016 in Connection_acceptor::connection_event_loop (this=0x2fc9b30) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/conn_handler/connection_acceptor.h:66
#3  0x0000000000ec6a06 in mysqld_main (argc=52, argv=0x2e97438) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/mysqld.cc:5287
#4  0x0000000000ebd344 in main (argc=9, argv=0x7fffffffe418) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/main.cc:25
6、


Connection_handler_manager::process_new_connection,通过
Channel_info指针指向的SCOKET信息建立新线程

栈帧

#1  0x0000000000f1b9c6 in Connection_handler_manager::process_new_connection (this=0x2e98fc0, channel_info=0x34c4a30) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/conn_handler/connection_handler_manager.cc:301
#2  0x0000000000ecf034 in Connection_acceptor::connection_event_loop (this=0x2fc9b30) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/conn_handler/connection_acceptor.h:68
#3  0x0000000000ec6a06 in mysqld_main (argc=52, argv=0x2e97438) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/mysqld.cc:5287
#4  0x0000000000ebd344 in main (argc=9, argv=0x7fffffffe418) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/main.cc:25
9、
Connection_handler_manager::check_and_incr_conn_count(bool)


   这里判断
MAX_CONNECTIONS是否合适这里也和运维内参说的5.6的代码有了

很大的不同,但是逻辑一样如下:

点击(此处)折叠或打开

if (extra_port_connection)
{
      if (extra_connection_count > extra_max_connections)
      {
            connection_accepted= false;
            m_connection_errors_max_connection++;
      }
      else
      {
            ++extra_connection_count;
      }
}
else if (connection_count > max_connections)
{
      connection_accepted= false;
      m_connection_errors_max_connection++;
}


GDB如下:

(gdb) n
106       mysql_mutex_lock(&LOCK_connection_count);
(gdb) n
115       if (extra_port_connection)
(gdb) n
127       else if (connection_count > max_connections)
(gdb) P  max_connections
$4 = 6
(gdb) p connection_count
$5 = 7
(gdb) n
129         connection_accepted= false;
(gdb) n
130         m_connection_errors_max_connection++;
(gdb) n
141       mysql_mutex_unlock(&LOCK_connection_count);
(gdb) n
142       return connection_accepted;


栈帧

#0  Connection_handler_manager::check_and_incr_conn_count (this=0x2e98fc0, extra_port_connection=false) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/conn_handler/connection_handler_manager.cc:105
#1  0x0000000000f1b904 in Connection_handler_manager::process_new_connection (this=0x2e98fc0, channel_info=0x34c4a30) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/conn_handler/connection_handler_manager.cc:289
#2  0x0000000000ecf034 in Connection_acceptor::connection_event_loop (this=0x2fc9b30) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/conn_handler/connection_acceptor.h:68
#3  0x0000000000ec6a06 in mysqld_main (argc=52, argv=0x2e97438) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/mysqld.cc:5287
#4  0x0000000000ebd344 in main (argc=9, argv=0x7fffffffe418) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/main.cc:25
12、


 Per_thread_connection_handler::add_connection(Channel_info*) 这个函数会判断连接队列是否有空闲的,如果没有调用
mysql_thread_create建立新的线程

截取如下:

点击(此处)折叠或打开

if (!check_idle_thread_and_enqueue_connection(channel_info)) //判断是否有空闲的连接队里
DBUG_RETURN(false);
/*
There are no idle threads avaliable to take up the new
connection. Create a new thread to handle the connection
*/
error= mysql_thread_create(key_thread_one_connection, &id, //建立新的线程对接
&connection_attrib,
handle_connection,
(void*) channel_info);


栈帧

#0  Per_thread_connection_handler::add_connection (this=0x2f67b10, channel_info=0x34c4a30) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/conn_handler/connection_handler_per_thread.cc:399
#1  0x0000000000f1b9c6 in Connection_handler_manager::process_new_connection (this=0x2e98fc0, channel_info=0x34c4a30) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/conn_handler/connection_handler_manager.cc:301
#2  0x0000000000ecf034 in Connection_acceptor::connection_event_loop (this=0x2fc9b30) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/conn_handler/connection_acceptor.h:68
#3  0x0000000000ec6a06 in mysqld_main (argc=52, argv=0x2e97438) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/mysqld.cc:5287
#4  0x0000000000ebd344 in main (argc=9, argv=0x7fffffffe418) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/main.cc:25
8、


 handle_connection(void*)  这里就是5.7.16真正的回调函数用于建立线程,这里就不解释了,因为这里只是分析流程,以后在详细研究

这里终于找到了建立线程的回调函数,调试有时候不知道入口函数名字也是一种悲剧




赞(0)    操作        顶端 
总帖数
1
每页帖数
101/1页1
返回列表
发新帖子
请输入验证码: 点击刷新验证码
您需要登录后才可以回帖 登录 | 注册
技术讨论