sql/mysqld.cc mysqld_main
启动主函数
- 主要调用流程
- MySQL启动
-
主要代码在sql/mysqld.cc中,精简后的代码如下:
int main(int argc, char **argv) //标准入口函数
MY_INIT(argv[0]); //调用mysys/My_init.c->my_init(),初始化mysql内部的系统库
logger.init_base(); //初始化日志功能
init_common_variables(MYSQL_CONFIG_NAME,argc, argv, load_default_groups) //调用load_defaults(conf_file_name, groups, &argc, &argv),读取配置信息
user_info= check_user(mysqld_user);//检测启动时的用户选项
set_user(mysqld_user, user_info);//设置以该用户运行
init_server_components();//初始化内部的一些组件,如table_cache, query_cache等。
network_init();//初始化网络模块,创建socket监听
start_signal_handler();// 创建pid文件
mysql_rm_tmp_tables() || acl_init(opt_noacl)//删除tmp_table并初始化数据库级别的权限。
init_status_vars(); // 初始化mysql中的status变量
start_handle_manager();//创建manager线程
handle_connections_sockets();//主要处理函数,处理新的连接并创建新的线程处理之 - 监听接收链接
-
主要代码在sql/mysqld.cc中,精简后的代码如下:
THD *thd;
FD_SET(ip_sock,&clientFDs); //客户端socket
while (!abort_loop)
readFDs=clientFDs;
if (select((int) max_used_connection,&readFDs,0,0,0) error && net->vio != 0 &&
!(thd->killed == THD::KILL_CONNECTION))
{
if(do_command(thd)) //处理客户端发出的命令
break;
}
end_connection(thd);
} - 预处理连接
-
thread_count++;//增加当前连接的线程
thread_scheduler.add_connection(thd);
for (;;) {
lex_start(thd);
login_connection(thd); // 认证
prepare_new_connection_state(thd); //初始化thd描述符
while(!net->error && net->vio != 0 &&
!(thd->killed == THD::KILL_CONNECTION))
{
if(do_command(thd)) //处理客户端发出的命令
break;
}
end_connection(thd);
} - 处理
-
do_command在sql/sql_parse.cc中:读取客户端传递的命令并分发。
NET *net= &thd->net;
packet_length= my_net_read(net);
packet= (char*) net->read_pos;
command= (enum enum_server_command) (uchar) packet[0]; //从net结构中获取命令
dispatch_command(command, thd, packet+1, (uint) (packet_length-1));//分发命令
在dispatch_command函数中,根据命令的类型进行分发。
thd->command=command;
switch( command ) {
case COM_INIT_DB: ...;
case COM_TABLE_DUMP: ...;
case COM_CHANGE_USER: ...;
….
case COM_QUERY: //如果是查询语句
{
alloc_query(thd, packet, packet_length)//thd->set_query(query, packet_length);
mysql_parse(thd, thd->query(), thd->query_length(), &end_of_stmt);
// 解析查询语句
….
}
在mysql_parse函数中,
lex_start(thd);
if (query_cache_send_result_to_client(thd, (char*) inBuf, length) sql_command
在mysql_execute_command中,根据命令类型,转到相应的执行函数。
switch (lex->sql_command) {
LEX *lex= thd->lex;
TABLE_LIST *all_tables;
case SQLCOM_SELECT:
check_table_access(thd, lex->exchange ? SELECT_ACL | FILE_ACL : SELECT_ACL, all_tables, UINT_MAX, FALSE); //检查用户权限
execute_sqlcom_select(thd, all_tables); //执行select命令
break;case SQLCOM_INSERT:
{ res= insert_precheck(thd, all_tables) //rights
mysql_insert(thd, all_tables, lex->field_list, lex->many_values,
lex->update_list, lex->value_list,
lex->duplicates, lex->ignore);
break;
在execute_sqlcom_select函数中,
res= open_and_lock_tables(thd, all_tables)//directly and indirectly
res= handle_select(thd, lex, result, 0);
handle_select在sql_select.cc中,调用mysql_select ,在mysql_select中,
join->prepare();//Prepare of whole select (including sub queries in future).
join->optimize();//global select optimisation.
join->exec();//
在mysql_insert函数中,
open_and_lock_tables(thd, table_list)
mysql_prepare_insert(); //prepare item in INSERT statment
while ((values= its++))
write_record(thd, table ,&info);//写入新的数据
在write_record函数中,
table->file->ha_write_row(table->record[0])
ha_write_row在Handler.cc中,只是一个接口
write_row(buf); //调用表存储所用的引擎
-
当客户端链接上mysql服务端时,系统为其分配一个链接描述符thd,用以描述客户端的所有信息,将作为参数在各个模块之间传递。一个典型的客户端查询在MySQL的主要模块之间的调用关系如下图所示:
当mysql启动完毕后,调用handle_connection_sockets等待客户端连接。当客户端连接上服务器时,服务处理函数将接受连 接,会为其创建链接线程,并进行认证。如认证通过,每个连接线程将会被分配到一个线程描述符thd,可能是新创建的,也可能是从 cached_thread线程池中复用的。该描述符包含了客户端输入的所有信息,如查询语句等。服务器端会层层解析命令,根据命令类型的不同,转到相应 的sql执行函数,进而给传递给下层的存储引擎模块,处理磁盘上的数据库文件,最后将结果返回。执行完毕后thd将被加入cached_thread中。