从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的主要工作也就完成。接下来的其他代码就暂不研究了。