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

从sql/mysqld.cc的4364行的主函数mysqld_main开始看起。跳过一些win32平台的初始化函数。

第一步,可以看到在mysqld_main里面会先加载一些默认配置参数

if (load_defaults(MYSQL_CONFIG_NAME, load_default_groups, &argc, &argv))
flush_error_log_messages();
return 1;


接着有逻辑判断是否开启了性能评估配置

#ifdef WITH_PERFSCHEMA_STORAGE_ENGINE
Initialize the array of performance schema instrument configurations.
init_pfs_instrument_array();
#endif /* WITH_PERFSCHEMA_STORAGE_ENGINE */


之后是一些配置检查,比如是直接启动还是daemonize后台启动,然后检测错误日志等配置是不是跟这两种方式吻合。接着是一些sql主要变量名及系统变量的初始化。

init_sql_statement_names();
sys_var_init();
ulong requested_open_files;
adjust_related_options(&requested_open_files);


之后跳过性能检查的操作,接着初始化错误日志及加载权限验证插件

init_error_log();
/* Initialize audit interface globals. Audit plugins are inited later. */
mysql_audit_initialize();


接着中间有一大段函数,貌似也没看懂,不属于主要逻辑,包括一些慢查询开启等。这里简要跳过,进入核心代码的开始network_init初始化。

if (init_ssl())
unireg_abort(MYSQLD_ABORT_EXIT);
if (network_init())
unireg_abort(MYSQLD_ABORT_EXIT);


接着我们看network_init函数内部代码

static bool network_init(void)
// more...
if (!opt_disable_networking || unix_sock_name != "")
std::string const bind_addr_str(my_bind_addr_str ? my_bind_addr_str : "");
Mysqld_socket_listener *mysqld_socket_listener=
new (std::nothrow) Mysqld_socket_listener(bind_addr_str,
mysqld_port, back_log,
mysqld_port_timeout,
unix_sock_name);
if (mysqld_socket_listener == NULL)
return true;
mysqld_socket_acceptor=
new (std::nothrow) Connection_acceptor<Mysqld_socket_listener>(mysqld_socket_listener);
if (mysqld_socket_acceptor == NULL)
delete mysqld_socket_listener;
mysqld_socket_listener= NULL;
return true;
if (mysqld_socket_acceptor->init_connection_acceptor())
return true; // mysqld_socket_acceptor would be freed in unireg_abort.
if (report_port == 0)
report_port= mysqld_port;
if (!opt_disable_networking)
DBUG_ASSERT(report_port != 0);
// more...


network_init里面使用Mysqld_socket_listener进行了实例化,目的是后面进行socket的侦听。同时对接收处理类Connection_acceptor的实例化,并初始化了这个连接处理类。

接着我们深入到连接处理类中sql/conn_handler/connection_handler.h文件中查看函数init_connection_acceptor

/**
Initialize a connection acceptor.
@retval return true if initialization failed, else false.
bool init_connection_acceptor()
return m_listener->setup_listener();


再接着查看setup_listener函数内部。在文件sql/conn_handler/socket_connection.cc 发现函数内部进行了socket的绑定。

bool Mysqld_socket_listener::setup_listener()
// Setup tcp socket listener
if (m_tcp_port)
TCP_socket tcp_socket(m_bind_addr_str, m_tcp_port,
m_backlog, m_port_timeout);
MYSQL_SOCKET mysql_socket= tcp_socket.get_listener_socket();
if (mysql_socket.fd == INVALID_SOCKET)
return true;
m_socket_map.insert(std::pair<MYSQL_SOCKET,bool>(mysql_socket, false));
// more...


接着我们返回到sql/mysqld.cc中的mysqld_main函数中继续研究,主要看代码5045行connection_event_loop函数循环。connection_event_loop连接事件循环,我们可以看出这里应该是开启了线程池进行侦听处理了。

if (opt_daemonize)
mysqld::runtime::signal_parent(pipe_write_fd,1);
mysqld_socket_acceptor->connection_event_loop(); // line no 5465


接着我们去看看connection_event_loop函数内部定义。在文件sql/conn_handler/connection_acceptor.h中。

/**
Connection acceptor loop to accept connections from clients.
void connection_event_loop()
Connection_handler_manager *mgr= Connection_handler_manager::get_instance();
while (!abort_loop)
Channel_info *channel_info= m_listener->listen_for_connection_event();
if (channel_info != NULL)
mgr->process_new_connection(channel_info);


我们可以看到代码里在循环侦听连接事件,然后使用process_new_connection去建立新的连接。

接着我们去看process_new_connection函数的定义。在文件sql/conn_handler/connection_handler_manager.cc中。

void
Connection_handler_manager::process_new_connection(Channel_info* channel_info)
if (abort_loop || !check_and_incr_conn_count())
channel_info->send_error_and_close_channel(ER_CON_COUNT_ERROR, 0, true);
delete channel_info;
return;
if (m_connection_handler->add_connection(channel_info))
inc_aborted_connects();
delete channel_info;


我们看到这里有个连接处理在使用add_connection添加连接。

继续查看add_connection函数内部定义。我们选取每个线程一个连接的方式查看文件sql/conn_handler/connection_handler_per_thread.cc里的定义。

bool Per_thread_connection_handler::add_connection(Channel_info* channel_info)
// more...
There are no idle threads avaliable to take up the new
connection. Create a new thread to handle the connection
channel_info->set_prior_thr_create_utime();
error= mysql_thread_create(key_thread_one_connection, &id,
&connection_attrib,
handle_connection,
(void*) channel_info);
// more...


这里我们看到了mysql_thread_create函数进行了线程的创建。此处有个参数handle_connection是在线程创建时注册要处理的函数handle_connection。在当前文件中。

extern "C" void *handle_connection(void *arg)
// more...
thd_manager->add_thd(thd);
if (thd_prepare_connection(thd))
handler_manager->inc_aborted_connects();
else
while (thd_connection_alive(thd))
if (do_command(thd))
break;
end_connection(thd);
close_connection(thd, 0, false, false);
// more...


我们看到了这里调用了do_command用来处理客户端发送过来的的sql语句。do_command函数会在下一篇文章中处理。

回到一开始的mysqld_main函数中,经过socket初始化及连接池初始化及注册事件处理函数。mysqld_main的主要工作也就完成。接下来的其他代码就暂不研究了。




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