MySQL · 源码分析 · 参数解析流程
背景
mysql有很多参数,innodb存储引擎也有自己独立的参数,这篇文章分析一下参数解析的流程。代码版本:8.0.13
mysql参数
sys_vars.cc 里面定义了很多参数,各种类型都有,这些参数都是sys_var的子类,所有的参数在构造函数里面都会加到all_sys_vars链表中。
在看实际参数之前,我们先学习一下 sys_var类的主要成员变量
class sys_var {
public:
sys_var *next; //next指针,all_sys_vars链表遍历的时候使用
LEX_CSTRING name; //参数名字
protected:
int flags; //参数标记,比如说global变量,session变量
int m_parse_flag; //PARSE_EARLY 优先解析,PARSE_NORMAL 正常解析.
my_option option; //参数min, max, default值
ptrdiff_t offset; //距离global_system_variables的offset值,实际的参数存储地址空间
on_check_function on_check; //check函数
on_update_function on_update; //update函数
};
下面看一个例子:basedir。 我们先看下这个参数的定义
static Sys_var_charptr Sys_basedir(
"basedir", //参数名字,和配置文件里面对应
"Path to installation directory. All paths are "
"usually resolved relative to this", //注释
READ_ONLY NON_PERSIST GLOBAL_VAR(mysql_home_ptr), //flag标记,offset偏移量,size
CMD_LINE(REQUIRED_ARG, 'b'), IN_FS_CHARSET, DEFAULT(0)); //参数校验,编码, 默认值
参数的flag是read_only + 非持久化 + 全局变量
persisted_variables_cache
set PERSIST命令持久化全局变量到mysqld-auto.cnf,mysql启动的时候先读这个文件。保证启动的时候参数修改不会丢失。
early_options
主要是一些基础参数,其他参数会依赖这些参数。struct my_option my_long_early_options 里面定义了那些参数是要提前解析的。
此外还有Sys_max_connections,Sys_open_files_limit,performance_schema等参数也是属于提前解析的。
handle_early_options函数找出这些需要提前解析的参数,然后调用handle_options解析参数。
handle_options函数会遍历argv参数,然后和option对应起来,调用setval设置value。
update
参数更新会调用定义的类里面的update函数。下面举个例子:
#0 Sys_var_struct<CHARSET_INFO, (anonymous namespace)::Get_csname>::global_update (this=0x6db4980 <Sys_character_set_server>,
var=0x7efe7f21c160) at sql/sys_vars.h:1892
#1 0x0000000002c51f34 in sys_var::update (this=0x6db4980 <Sys_character_set_server>, thd=0x7efe7fe0b000, var=0x7efe7f21c160)
at sql/set_var.cc:252
#2 0x0000000002c544f9 in set_var::update (this=0x7efe7f21c160, thd=0x7efe7fe0b000)
at sql/set_var.cc:1005
#3 0x0000000002c53978 in sql_set_variables (thd=0x7efe7fe0b000, var_list=0x7efe7fe352c8, opened=true)
at sql/set_var.cc:770
#4 0x0000000002d4e935 in mysql_execute_command (thd=0x7efe7fe0b000, first_level=true)
at sql/sql_parse.cc:3880
#5 0x0000000002d543f3 in mysql_parse (thd=0x7efe7fe0b000, parser_state=0x7eff35737860, force_primary_storage_engine=false)
at sql/sql_parse.cc:5728
#6 0x0000000002d48b0d in dispatch_command (thd=0x7efe7fe0b000, com_data=0x7eff35738330, command=COM_QUERY)
at sql/sql_parse.cc:1874
#7 0x0000000002d46db0 in do_command(THD*, std::function<bool (THD*, COM_DATA const*, enum_server_command)>*) (
thd=0x7efe7fe0b000, dispatcher=0x0) at sql/sql_parse.cc:1336
#8 0x0000000002d46f4e in do_command (thd=0x7efe7fe0b000) at sql/sql_parse.cc:1373
全局参数就直接修改对应的内存值。
再来看一个innodb参数的例子:
#0 innodb_undo_tablespaces_update (thd=0x7efe7fe0b000, var=0x6b7d060 <mysql_sysvar_undo_tablespaces>,
var_ptr=0x6b89f90 <srv_undo_tablespaces>, save=0x7efe7f181150)
at storage/innobase/handler/ha_innodb.cc:23160
#1 0x0000000002da2163 in sys_var_pluginvar::global_update (this=0x7eff3fd9fa40, thd=0x7efe7fe0b000, var=0x7efe7f181130)
at sql/sql_plugin_var.cc:416
#2 0x0000000002c51f34 in sys_var::update (this=0x7eff3fd9fa40, thd=0x7efe7fe0b000, var=0x7efe7f181130)
at sql/set_var.cc:252
#3 0x0000000002c544f9 in set_var::update (this=0x7efe7f181130, thd=0x7efe7fe0b000)
at sql/set_var.cc:1005
#4 0x0000000002c53978 in sql_set_variables (thd=0x7efe7fe0b000, var_list=0x7efe7fe352c8, opened=true)
at sql/set_var.cc:770
#5 0x0000000002d4e935 in mysql_execute_command (thd=0x7efe7fe0b000, first_level=true)
at sql/sql_parse.cc:3880
#6 0x0000000002d543f3 in mysql_parse (thd=0x7efe7fe0b000, parser_state=0x7eff35737860, force_primary_storage_engine=false)
at sql/sql_parse.cc:5728
#7 0x0000000002d48b0d in dispatch_command (thd=0x7efe7fe0b000, com_data=0x7eff35738330, command=COM_QUERY)
at sql/sql_parse.cc:1874
#8 0x0000000002d46db0 in do_command(THD*, std::function<bool (THD*, COM_DATA const*, enum_server_command)>*) (
thd=0x7efe7fe0b000, dispatcher=0x0) at sql/sql_parse.cc:1336
#9 0x0000000002d46f4e in do_command (thd=0x7efe7fe0b000) at sql/sql_parse.cc:1373
有自定义update函数的参数,最终都会回调自定义的update函数。
参数prefix
特殊前缀有”skip”, “disable”, “enable”, “maximum”, “loose”, disable和skip是一样的,设置参数off, enable刚好相反,有个特殊情况–skip-option=0这种双重否定表示肯定,等价于option = true
maximum限制客户端设置session 变量的最大值
loose前缀表示参数不能识别,程序不会退出。
比较参数的时候认为-和_是相同的。
innodb插件参数
参数都在innobase_system_variables结构里面。test_plugin_options 里面会给所有的参数加上前缀innodb_, 这样可以和配置文件里面参数名称对齐
my.cnf 文件解析
search_default_file_with_ext函数会解析配置文件,并且把参数拼成–前缀, 然后会重新设置argc, argv。后续解析参数直接就从argv里面获取。
特殊情况
有少部分参数,修改一个参数值,另外一个参数值也会一起修改,原因是2个参数对应的同一个内存数据结构。
比如说:character_set_server和collation_server。它们组合需要遵守相应的规则。