mysql-5.7.38启动流程源码解读

写在前面

阅读本教程你需要提前知道的

1.本文参考的源码版本 mysql-5.7.38, 可能和8.0有区别, 请以实际版本为主.

2.不含初始化数据库(bootstrap/initialize), 不含win32 (_WIN32), 不含ia64, 尽量不含performance_schema

3.基础编程知识(c/c++,py,go,shell,js等均可) (*表示取指针的值, &表示取值的地址(指针))

4.不含流程图(懒得画)

5.不会详细讲具体的函数(太多了)

6.能力有限, 错误之处多多包涵.

启动流程

主要是sql/mysqld.cc中的mysqld_main , 其它文件尽量不要涉及.

mysqld_main(主函数)

int mysqld_main(int argc, char **argv)

入口函数, 为啥不是main呢(1.#define mysqld_main main 2.gcc -nostartfiles -e mysqld_main). (我想起个段子 #define mian main)

实际上是在 sql/main.cc 中定义的

extern int mysqld_main(int argc, char **argv);

int main(int argc, char **argv)
{
  return mysqld_main(argc, argv);
}

//以下函数未特殊说明均在mysqld_main函数里面调用的

初始化参数

就是执行mysqld --datadir=xx --basedir=xx 的这个参数

  orig_argc= argc;
  orig_argv= argv;
  my_getopt_use_args_separator= TRUE;
  my_defaults_read_login_file= FALSE;
  my_getopt_use_args_separator= FALSE;
  defaults_argc= argc;
  defaults_argv= argv;
  remaining_argc= argc;
  remaining_argv= argv;

system_charset_info (系统字符集)

system_charset_info= &my_charset_utf8_general_ci;

local_message_hook 定义日志打印

//error_log_print(enum loglevel level, const char *format, va_list args)

local_message_hook= error_log_print;

初始化performance instrument (可选)

init_pfs_instrument_array();

所以参数 performance_schema 是只读的, 只能开机设置

ho_error参数检查(兼容以前的参数)

ho_error= handle_early_options();

忽略未知参数,添加系统变量,添加命令行选项, 检查bootstrap和initialize/opt_initialize_insecure.

应该是为了兼容性的

init_sql_statement_names

这一块不熟... (LEX后面再看)

  for (i= 0; i < ((uint) SQLCOM_END + 1); i++)
    sql_statement_names[i]= empty;

sys_var_init

系统变量初始化 (必须先初始化system_charset_info (第三步))

适配依赖关系选项(顺序不能改变,因为有依赖关系)

  adjust_open_files_limit(requested_open_files);
  adjust_max_connections(*requested_open_files);
  adjust_table_cache_size(*requested_open_files);
  adjust_table_def_size();  //依赖table_cache_size

query_logger.init

初始化查询日志 slow log 和 general log 都需要这个玩意

判断ho_error

刚才检查的参数, 现在才判断...

flush_error_log_messages();
exit (MYSQLD_ABORT_EXIT);

初始化命令行参数

init_common_variables

后初始的命令行参数, 所以命令行参数的优先级要高.

my_init_signals

初始化信号量的, 比如 SIGUSR1 is used to interrupt the socket listener

my_thread_attr_setstacksize

设置线程的堆栈大小的. pthread_attr_getstacksize

keyring_migration

和参数 --keyring-migration-xxxx 相关的, 没用过, 就不做介绍了.

opt_keyring_migration_source

opt_keyring_migration_destination

migrate_connect_options

my_setwd(mysql_real_data_home,MYF(MY_WME))

设置数据库数据目录

bin_log 选项检查

如果启用binlog就必须要server-id

(opt_bin_log && !(server_id_supplied) )

init_server_components

使用函数初始化一些内部的东西. 具体如下, 挺多的

mdl_init()    //Initialize the metadata locking subsystem
partitioning_init()
table_def_init() | hostname_cache_init(host_cache_size)
my_timer_initialize()
init_server_query_cache() //这里初始的查询缓存,8.0没有
randominit()
setup_fpu()
init_slave_list  //(ifdef HAVE_REPLICATION)

init_server_auto_options

就是server-uuid 唯一表示服务器的, 没得就会自动创建, 路径在@@datadir 下面的 auto.cnf

gtid_state->init()

初始化gtid(必须先初始化server-uuid)

read_gtid_executed_from_table

从mysql/gtid_executed.ibd表读取gtid集

初始化GLOBAL.GTID_EXECUTED和GLOBAL.GTID_PURGED

计算方式就不讲了, 太多了..... 懒得看.

init_ssl

初始化ssl 也挺复杂的....

network_init

初始化网络, 也是一堆... 成功就返回false (同init_ssl)

内存管理相关的函数

  my_str_malloc= &my_str_malloc_mysqld;  //my_malloc
  my_str_free= &my_str_free_mysqld;  //my_free
  my_str_realloc= &my_str_realloc_mysqld; //my_realloc

error_handler_hook

跟客户端错误信息有关的

error_handler_hook= my_message_sql

create_pid_file

创建pid文件, 并讲pid(getpid())写入文件(mysql_file_write), 然后关闭文件(mysql_file_close)

reload_optimizer_cost_constants

加载优化器成本配置表, 就是 mysql.server_cost 和 mysql.engine_cost

相关代码: sql/opt_costconstantcache.cc // c++写的

mysql_rm_tmp_tables

删除临时表

acl_init

初始化权限(user/db) sql/auth/sql_auth_cache.cc

my_tz_init

初始化时区

grant_init

初始化权限(table/column)

servers_init

servers_init(0) 初始化server, 0 表示要初始化 //bool servers_init(bool dont_read_servers_table)

具体内容如下:

mysql_rwlock_init //init the mutex
my_hash_init  //initialise our servers cache
init_sql_alloc //Initialize the mem root for data

init_status_vars

初始化服务器状态 sql/sql_show.cc //c++写的

check_binlog_cache_size

就是检查BINLOG_CACHE_SIZE是不是比MAX_BINLOG_CACHE_SIZE大, 是的话, 就取MAX_BINLOG_CACHE_SIZE的值 (两者取其小)

check_binlog_stmt_cache_size

就是检查 BINLOG_STMT_CACHE_SIZE是不是比MAX_BINLOG_STMT_CACHE_SIZE大.

binlog_unsafe_map_init

定义binlog异常, 在sql/sql_lex.cc里的

set_slave_skip_errors

就是配置文件里面的 slave-skip-errors=xxxx;

init_slave

初始化从库信息, 前提是server_id != 0 //其实前面还设置了opt_skip_slave_start, 但是没必要. 太罗嗦了.

initialize_information_schema_acl

初始化information_schema. //sql/auth/sql_auth_cache.cc

execute_ddl_log_recovery

执行内部DDL日志恢复.

read_init_file (可选)

就是启动的时候指定的 --init-file=name 这个是不需要权限认证的, 所以可以用来更改密码.

start_handle_manager

启动handle manager线程.(具体的后面再慢慢看)

create_compress_gtid_table_thread

创建压缩gtid的线程

sql_print_information

主要是error_log_print

start_processing_signals

设置进程信号量

set_super_read_only_post_init();

初始化super_read_only的值

server_operational_state

设置服务器状态 server_operational_state=SERVER_OPERATING //默认是SERVER_BOOTING 关闭的时候是SERVER_SHUTTING_DOWN, 下面就会说的

socket_listener_active

设置mysql监听状态 socket_listener_active= true;

opt_daemonize

就是启动时候的参数 --daemonize 俗称 放后台

mysqld::runtime::signal_parent(pipe_write_fd,1);  //1 means initialization complete and the serveris ready to accept client connections

mysqld_socket_acceptor->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);
    }

server_operational_state= SERVER_SHUTTING_DOWN

从这开始就是关闭流程了, 不在本文范围内

总结

看完差不多就忘完了. 基本上都是各种初始化. 而且是c和c++混合写的. 感兴趣的可以使用strace验证下是不是这样的.

1.开启binlog必须要server-id!=0

2.可以通过--init-file修改root密码

3.可以通过skip-slave-start参数禁止slave自动启动

4.ddl log恢复是数据库启动的时候自动做的

5.权限分为系统级(user/db)权限和表级权限(table/column)

参考文献

https://dev.mysql.com/doc/dev/mysql-server/latest/

https://dev.mysql.com/doc/refman/5.7/en/preface.html

https://dev.mysql.com/doc/internals/en/

相关文章

navicat查看某个表的所有字段的详细信息 navicat设计表只能一...
文章浏览阅读4.3k次。转载请把头部出处链接和尾部二维码一起...
文章浏览阅读488次。恢复步骤概要备份frm、ibd文件如果mysql...
文章浏览阅读225次。当MySQL单表记录数过大时,增删改查性能...
文章浏览阅读1.5k次。Mysql创建、删除用户MySql中添加用户,新...
MySQL是一种开源的关系型数据库管理系统,被广泛应用于各类应...