一、sql/main.cc
extern int mysqld_main(int argc, char **argv);
int main(int argc, char **argv)
{
return mysqld_main(argc, argv);
}
这就是mysqld的main()函数,它只是调用了mysql_main()。
二、mysqld_main
mysqld_main()位于sql/mysqld.cc中。sql/mysqld.cc中包含的头文件基本位于include/和sql/这两个文件夹下。下面看mysqld_main()的执行流程。
1、my_init()——init my_sys library & pthreads
其中static MYSQL_FILE instrumented_stdin.m_file= stdin;调用my_thread_global_init(),其中设置pthread_key_create(&THR_KEY_mysys, NULL)),mysql_mutex_init()初始化mutex(THR_LOCK_malloc, THR_LOCK_open, THR_LOCK_charset, THR_LOCK_threads以及之后的THR_LOCK_lock, THR_LOCK_isam,HR_LOCK_heap等)(见备注1),调用my_thread_init()初始化THR_KEY_mysys(见备注2),mysql_cond_init()初始化THR_COND_threads。
备注1:mysql_mutex_init(key_THR_LOCK_malloc, &THR_LOCK_malloc, MY_MUTEX_INIT_FAST)
key_THR_LOCK_malloc为PSI_mutex_key(unsigned int),THR_LOCK_malloc为struct mysql_mutex(主要成员是pthread_mutex_t m_mutex),该函数主要是初始化m_mutex。
备注2:my_thread_init()
执行pthread_setspecific(THR_KEY_mysys, tmp)(tmp为struct st_my_thread_var *);初始化这个tmp。
2、load_defaults()->my_load_defaults()
调用init_alloc_root()初始化MEM_ROOT *alloc;dirs=init_default_directories(&alloc)初始化目录数组(可能存放my.cnf的目录),数据保存在alloc管理的内存block中。my_init_dynamic_array()初始化用于存放argv参数的动态数组DYNAMIC_ARRAY args;my_search_option_files()先根据目录数组找到my.cnf(打开为MYSQL_FILE* fp),并提取参数,但尚未处理。
3、init_sql_statement_names
初始化LEX_CSTRING sql_statement_names[ ]数组,内部存放着诸如"create_db" "insert"等对应于SQL语句的字符串。
4、sys_var_init
调用my_hash_init()初始化HASH* system_variable_hash;调用mysql_add_sys_var_chain(all_sys_vars.first)(注意all_sys_vars此时并不为空,它已经被初始化了,什么时候初始化的,见备注3),它将这些变量的指针存在system_variable_hash哈希表中。
备注3:all_sys_vars.first的类型是sys_var *,这是一个class,具有构造函数。在sql/sys_vars.cc中具有多个static变量(当我们在客户端使用SHOW VARIABLES LIKE 'perf%';时就可以看到这些变量),这些变量在程序一开始就得到了初始化,并链入了all_sys_vars.first中。
5、my_getopt_register_get_addr()设置getopt_get_addr = null(getopt_get_addr 类型为my_getopt_value,这是一个函数指针)。
6、sys_var_add_options(&all_early_options, sys_var::PARSE_EARLY)
all_early_options为DYNAMIC_ARRAY,该函数将all_sys_vars链表中每个sys_var的option字段的地址存入该动态数组all_early_options中。
7、buffered_logs.init()初始化Buffered_logs buffered_logs的成员MEM_ROOT m_root(注意Buffered_logs是一个类)。(这是第二次出现MEM_ROOT了,这里它应当是用于管理log缓存的)。备注Buffered_logs::print()就是用于将缓存的日志写到日志文件中。
8、my_getopt_error_reporter= buffered_option_error_reporter前者是个函数指针,后者这个函数作用就是将出错信息缓存到上一步中的buffered_logs中。
9、handle_options(&remaining_argc, &remaining_argv,(my_option*)(all_early_options.buffer), NULL)
这里remaining_argv是命令行和my.cnf中所有参数的集合,all_early_options是每个sys_var的option字段都存在此处,很明显该函数是处理各参数;同时可看出上一步的设置的作用:将解析参数时的出错信息也记录到日志中。不过这里并没有处理完(实际上我设置的参数和option字段都没关系,所以这里并没有设置option字段中的值)。在此之后,delete all_early_options。
10、init_error_log_mutex()初始化LOCK_error_log(类型为mysql_mutex_t)
11、mysql_audit_initialize()——Initialize Audit global variables:初始化LOCK_audit_mask锁(mysql_mutex_t)
12、logger.init_base()
logger的类型是class Logger(位于sql/log.h),Class which manages slow, general and error log event handlers。初始化log handler (class Log_to_file_event_handler,其中元素有mysql_log和mysql_slow_log)。
13、init_common_variables()见第三部分。
14、init_signals()信号相关初始化。
15、init_server_components()
table_def_init()初始化table_def_cache哈希表;hostname_cache_init()初始化hostname_cache;query_cache_init();ifdef HAVE_REPLICATION,init_slave_list(); process_key_caches(&ha_init_key_cache)初始化key caches;plugin_init(&remaining_argc, remaining_argv, ...)初始化剩余的参数(这是第三次处理),这些参数,这些与存储引擎相关,见下一篇,该函数还创建了很多线程;ha_init()初始化存储引擎;Set the default storage engine,并设置到global_system_variables.table_plugin中;ha_recover();
16、network_init()
创建tcp套接口ip_sock并监听,创建unix套接口unix_sock(需要创建文件mysqld.sock,注意需要给mysql用户添加文件夹写入权限)。
17、start_signal_handler()
创建线程signal_thread,线程处理函数为signal_hand();主线程等待该线程完成一些工作。signal_hand见第四部分。
18、mysql_rm_tmp_tables() || acl_init(opt_noacl) || my_tz_init()与数据表相关
acl_init():Initialize structures responsible for user/db-level privilege checking and load privilege information for them from tables in the 'mysql' database;
my_tz_init():Initialize time zone support infrastructure.
19、grant_init():Initialize structures responsible for table/column-level privilege checking and load information for them from tables in the 'mysql' database
20、servers_init(): Initialize structures responsible for servers used in federated server scheme information for them from the server table in the 'mysql' database
21、init_status_vars():Make all_status_vars[ ] usable for SHOW STATUS(注意add_status_vars()已在init_common_variables()中调用。)只是做了排序。
22、binlog_unsafe_map_init()?
23、init_slave():Initialize slave structures;其中pthread_key_create(&RPL_MASTER_INFO, NULL);初始化Master_info *active_mi。
24、execute_ddl_log_recovery()
25、Events::init(opt_noacl || opt_bootstrap)
26、start_handle_manager()实际上本例什么也没做(因为flush_time=0)
27、mysql_cond_signal(&COND_server_started):如果有某线程等待主线程启动,此时主线程通知它已启动。
28、handle_connections_sockets()
Handle new connections and spawn new process to handle them. 其中循环调用poll一直等待客户端连接。当连接到来时,accept,vio_new,my_net_init(&thd->net, vio_tmp),create_new_thread()处理连接;然后主线程继续循环等待新的连接。注意:对于本地,使用的是unix套接字。
备注:vio_new()初始化一个struct st_vio,设置了write、read等处理函数,封装了buffer相关处理;my_net_init()用这个st_vio去初始化thd->net(类型为struct st_net,该结构可看做client connection descriptor)。这样对io的处理进行了虚拟化。
29、当上述循环退出时,主线程等待ready_to_exit为1时,调用clean_up()和mysqld_exit()退出。
三、init_common_variables
1、init_thread_environment()初始化多个线程相关的锁;初始化connection_attrib(类型为pthread_attr_t);pthread_key_create(&THR_THD, NULL)。
2、初始化mysql_bin_log(类型为MYSQL_BIN_LOG,class MYSQL_BIN_LOG: public TC_LOG, private MYSQL_LOG)
3、设置pidfile_name为“hostname+.pid”,本例为“ubuntu.pid”。
4、default_storage_engine= const_cast<char *>("InnoDB")
5、add_status_vars(status_vars)创建all_status_vars这个动态数组,将status_vars各个数组的各项的指针存入动态数组中,类似于前面的all_early_options。
6、get_options(&remaining_argc, &remaining_argv)这里继续处理命令行和my.cnf中设置的参数。操作的是struct my_option my_long_options[ ]。不过还有一些关于innoDB的参数没有被处理。
7、设置open_files_limit(本例为1024)
8、unireg_init()设置error_handler_hook = my_message_stderr;my_disable_async_io=1
9、设置my_default_lc_messages为"en_US";global_system_variables.lc_messages= my_default_lc_messages
10、init_errmessage()初始化DEFAULT_ERRMSGS(即my_default_lc_messages->errmsgs->errmsgs,类型为char**,指向各种错误提示字符串)
11、init_client_errs():Register client error messages for use with my_error()
12、mysql_client_plugin_init():Initializes the client plugin layer
13、lex_init()初始化SYMBOL symbols[ ]
14、item_create_init():Load the hash table for native functions;将Native_func_registry func_array[ ]中的各项(好像是各种函数,位于sql/item_create.cc中)加入native_functions_hash这个哈希表。
15、item_init()初始化hash_user_locks哈希表和LOCK_user_locks锁。
16、get_charset_by_csname()初始化default_charset_info(本例初始化为utf8);初始化character_set_filesystem(本例为binary);my_locale_by_name()设置my_default_lc_time_names(本例为en_US)。这些量都被保存于global_system_variables中。
17、本例设置opt_logname为"/var/lib/mysql2/ubuntu.log",opt_slow_logname为"/var/lib/mysql2/ubuntu-slow.log"
18、bitmap_init()设置位图。
19、my_dboptions_cache_init()初始化dboptions这个哈希表。
20、初始化table_alias_charset(本例为&my_charset_bin,为"binary")。
四、signal_hand()
1、my_thread_init():以后分析。
2、init_thr_alarm():Setup alarm handler
3、 create_pid_file():创建pid.fill。(之后就可以唤醒主线程了)
4、之后是一直等待信号的到来,并相应处理。因此次线程就是一个信号处理线程。
本篇只是对mysqld的启动做了一个大概的认识,很多函数并未深入下去,下一篇将从客户端连接后,mysqld的处理来继续学习。看了mysqld的启动,觉得mysql确实是一个很庞大的东西,要学习的东西很多,只能在此先给自己加个油。