MySQL启动过程详解二:核心模块启动 init_server_components()
mysqld_main() 函数中,init_server_components() 函数负责MySQL核心模块的启动,包括mdl系统,Innodb存储引擎的启动等等:
1. mdl子系统初始化。
2. 初始化 table definition cache 和 hostname cache hash表
3. 初始化 timer组件
4. 初始化 query cache
5. 随机数模块和浮点数计算器初始化
6. 初始化 slave list
7. 启动 error log
8. 初始化各种 xxx_delegate 类型的指针, 为他们分配对象, 对动态插件的支持
9. 初始化 storage engins 之前配置 binlog
10. 初始化 gtid server
11. tc_log 尽早指向 TC_LOG_DUMMY, 以便允许 plugin_init() 在读取 mysql.plugin 表之后提交附加的事务;tc_log为事务两阶段提交过程中的协调者
12. plugin_register_builtin_and_init_core_se(),注册内置插件,初始化 MyISAM、CSV、InnoDB 插件。
13. plugin_register_dynamic_and_init_all(),注册并初始化动态插件,已经注册但尚未初始化的插件也要初始化。
14. 处理命令行选项
15. 打开 slow log file 和 general log file
16. 设置默认的存储引擎
17. 设置并打开 tc_log
18. xa recovery 操作
19. 打开 binlog
20. 初始化优化器cost 模块
21. 初始化 max_user_conns 和 sql_command_flags & server_command_flags 数组。
/*
* 核心模块
*/
static int init_server_components()
{
DBUG_ENTER("init_server_components");
/*
We need to call each of these following functions to ensure that
all things are initialized so that unireg_abort() doesn't fail
需要调用以下每个函数来确保所有内容都已初始化
*/
// 初始化 mdl 子系统。特别是, 初始化新的全局变量锁和相关的条件变量: LOCK_mdl 和 COND_mdl。
mdl_init();
// 初始化 partitioning, 当前只有 PSI Keys。
partitioning_init();
// 初始化 table definition cache hash表 和 hostname cache hash表
if (table_def_init() | hostname_cache_init(host_cache_size))
unireg_abort(MYSQLD_ABORT_EXIT);
// 初始化 timer 组件
if (my_timer_initialize())
sql_print_error("Failed to initialize timer component (errno %d).", errno);
else
have_statement_timeout = SHOW_OPTION_YES;
// 初始化 query cache
init_server_query_cache();
// 随机数模块初始化
randominit(&sql_rand, (ulong)server_start_time, (ulong)server_start_time / 2);
// 浮点运算器
setup_fpu();
#ifdef HAVE_REPLICATION
// 初始化 slave list
init_slave_list();
#endif
/* Setup logs */
/*
Enable old-fashioned error log, except when the user has requested
help information. Since the implementation of plugin server
variables the help output is now written much later.
log_error_dest can be:
disabled_my_option --log-error was not used or --log-error=
"" --log-error without arguments (no '=')
filename --log-error=filename
*/
#ifdef _WIN32
/*
Enable the error log file only if console option is not specified
and --help is not used.
*/
bool log_errors_to_file = !opt_help && !opt_console;
#else
/*
Enable the error log file only if --log-error=filename or --log-error
was used. Logging to file is disabled by default unlike on Windows.
*/
// 是否启用 error log
bool log_errors_to_file = !opt_help && (log_error_dest != disabled_my_option);
#endif
// 启用 error log
if (log_errors_to_file)
{
// Construct filename if no filename was given by the user.
// 如果 没有指定 error log filename, 则自动生成
if (!log_error_dest[0] || log_error_dest == disabled_my_option)
fn_format(errorlog_filename_buff, pidfile_name, mysql_data_home, ".err",
MY_REPLACE_EXT); /* replace '.<domain>' by '.err', bug#4997 */
else
fn_format(errorlog_filename_buff, log_error_dest, mysql_data_home, ".err",
MY_UNPACK_FILENAME);
/*
log_error_dest may have been set to disabled_my_option or "" if no
argument was passed, but we need to show the real name in SHOW VARIABLES.
*/
log_error_dest = errorlog_filename_buff;
// open error log
if (open_error_log(errorlog_filename_buff, false))
unireg_abort(MYSQLD_ABORT_EXIT);
}
else
{
// We are logging to stderr and SHOW VARIABLES should reflect that.
// 记录 error log 到 stderr
log_error_dest = "stderr";
// Flush messages buffered so far.
flush_error_log_messages();
}
enter_cond_hook = thd_enter_cond;
exit_cond_hook = thd_exit_cond;
is_killed_hook = (int (*)(const void *))thd_killed;
// transaction_cache init
if (transaction_cache_init())
{
sql_print_error("Out of memory");
unireg_abort(MYSQLD_ABORT_EXIT);
}
/*
initialize delegates for extension observers, errors have already
been reported in the function
初始化各种 xxx_delegate 类型的指针, 为他们分配对象, 对动态插件的支持
*/
if (delegates_init())
unireg_abort(MYSQLD_ABORT_EXIT);
/* need to configure logging before initializing storage engines
在初始化 storage engines 之前需要配置 binlog.
*/
if (opt_log_slave_updates && !opt_bin_log)
{
sql_print_warning("You need to use --log-bin to make "
"--log-slave-updates work.");
}
if (binlog_format_used && !opt_bin_log)
sql_print_warning("You need to use --log-bin to make "
"--binlog-format work.");
/* Check that we have not let the format to unspecified at this point */
assert((uint)global_system_variables.binlog_format <=
array_elements(binlog_format_names) - 1);
#ifdef HAVE_REPLICATION
// replicate_same_server_id
if (opt_log_slave_updates && replicate_same_server_id)
{
if (opt_bin_log)
{
sql_print_error("using --replicate-same-server-id in conjunction with \
--log-slave-updates is impossible, it would lead to infinite loops in this \
server.");
unireg_abort(MYSQLD_ABORT_EXIT);
}
else
sql_print_warning("using --replicate-same-server-id in conjunction with \
--log-slave-updates would lead to infinite loops in this server. However this \
will be ignored as the --log-bin option is not defined.");
}
#endif
opt_server_id_mask = ~ulong(0);
#ifdef HAVE_REPLICATION
// 检查 serverid 超长
opt_server_id_mask = (opt_server_id_bits == 32) ? ~ulong(0) : (1 << opt_server_id_bits) - 1;
if (server_id != (server_id & opt_server_id_mask))
{
sql_print_error("server-id configured is too large to represent with"
"server-id-bits configured.");
unireg_abort(MYSQLD_ABORT_EXIT);
}
#endif
//
if (opt_bin_log)
{
/* Reports an error and aborts, if the --log-bin's path
is a directory.
--log-bin 指向一个目录
*/
if (opt_bin_logname &&
opt_bin_logname[strlen(opt_bin_logname) - 1] == FN_LIBCHAR)
{
sql_print_error("Path '%s' is a directory name, please specify \
a file name for --log-bin option",
opt_bin_logname);
unireg_abort(MYSQLD_ABORT_EXIT);
}
/* Reports an error and aborts, if the --log-bin-index's path
is a directory.
--log-bin-index 指向一个目录
*/
if (opt_binlog_index_name &&
opt_binlog_index_name[strlen(opt_binlog_index_name) - 1] == FN_LIBCHAR)
{
sql_print_error("Path '%s' is a directory name, please specify \
a file name for --log-bin-index option",
opt_binlog_index_name);
unireg_abort(MYSQLD_ABORT_EXIT);
}
char buf[FN_REFLEN];
const char *ln;
ln = mysql_bin_log.generate_name(opt_bin_logname, "-bin", buf);
if (!opt_bin_logname && !opt_binlog_index_name)
{
/*
User didn't give us info to name the binlog index file.
Picking `hostname`-bin.index like did in 4.x, causes replication to
fail if the hostname is changed later. So, we would like to instead
require a name. But as we don't want to break many existing setups, we
only give warning, not error.
*/
sql_print_warning("No argument was provided to --log-bin, and "
"--log-bin-index was not used; so replication "
"may break when this MySQL server acts as a "
"master and has his hostname changed!! Please "
"use '--log-bin=%s' to avoid this problem.",
ln);
}
if (ln == buf)
{
my_free(opt_bin_logname);
opt_bin_logname = my_strdup(key_memory_opt_bin_logname,
buf, MYF(0));
}
/*
Skip opening the index file if we start with --help. This is necessary
to avoid creating the file in an otherwise empty datadir, which will
cause a succeeding 'mysqld --initialize' to fail.
*/
if (!opt_help && mysql_bin_log.open_index_file(opt_binlog_index_name, ln, TRUE))
{
unireg_abort(MYSQLD_ABORT_EXIT);
}
}
if (opt_bin_log)
{
/*
opt_bin_logname[0] needs to be checked to make sure opt binlog name is
not an empty string, incase it is an empty string default file
extension will be passed
log_bin basename 和 log_bin index 检查
*/
log_bin_basename =
rpl_make_log_name(key_memory_MYSQL_BIN_LOG_basename,
opt_bin_logname, default_logfile_name,
(opt_bin_logname && opt_bin_logname[0]) ? "" : "-bin");
log_bin_index =
rpl_make_log_name(key_memory_MYSQL_BIN_LOG_index,
opt_binlog_index_name, log_bin_basename, ".index");
if (log_bin_basename == NULL || log_bin_index == NULL)
{
sql_print_error("Unable to create replication path names:"
" out of memory or path names too long"
" (path name exceeds " STRINGIFY_ARG(FN_REFLEN) " or file name exceeds " STRINGIFY_ARG(FN_LEN) ").");
unireg_abort(MYSQLD_ABORT_EXIT);
}
}
#ifndef EMBEDDED_LIBRARY
// reply_log basename & index
DBUG_PRINT("debug",
("opt_bin_logname: %s, opt_relay_logname: %s, pidfile_name: %s",
opt_bin_logname, opt_relay_logname, pidfile_name));
/*
opt_relay_logname[0] needs to be checked to make sure opt relaylog name is
not an empty string, incase it is an empty string default file
extension will be passed
*/
relay_log_basename =
rpl_make_log_name(key_memory_MYSQL_RELAY_LOG_basename,
opt_relay_logname, default_logfile_name,
(opt_relay_logname && opt_relay_logname[0]) ? "" : "-relay-bin");
if (relay_log_basename != NULL)
relay_log_index =
rpl_make_log_name(key_memory_MYSQL_RELAY_LOG_index,
opt_relaylog_index_name, relay_log_basename, ".index");
if (relay_log_basename == NULL || relay_log_index == NULL)
{
sql_print_error("Unable to create replication path names:"
" out of memory or path names too long"
" (path name exceeds " STRINGIFY_ARG(FN_REFLEN) " or file name exceeds " STRINGIFY_ARG(FN_LEN) ").");
unireg_abort(MYSQLD_ABORT_EXIT);
}
#endif /* !EMBEDDED_LIBRARY */
/* call ha_init_key_cache() on all key caches to init them
key cache handle, 仅适用于ISAM 表
*/
process_key_caches(&ha_init_key_cache);
/* Allow storage engine to give real error messages */
if (ha_init_errors())
DBUG_RETURN(1);
if (opt_ignore_builtin_innodb)
sql_print_warning("ignore-builtin-innodb is ignored "
"and will be removed in future releases.");
// 初始化 GTID server
if (gtid_server_init())
{
sql_print_error("Failed to initialize GTID structures.");
unireg_abort(MYSQLD_ABORT_EXIT);
}
/*
Set tc_log to point to TC_LOG_DUMMY early in order to allow plugin_init()
to commit attachable transaction after reading from mysql.plugin table.
If necessary tc_log will be adjusted to point to correct TC_LOG instance
later.
tc_log 尽早指向 TC_LOG_DUMMY, 以便允许 plugin_init() 在读取 mysql.plugin 表之后提交附加的事务。
*/
tc_log = &tc_log_dummy;
/*Load early plugins */
if (plugin_register_early_plugins(&remaining_argc, remaining_argv,
opt_help ? PLUGIN_INIT_SKIP_INITIALIZATION : 0))
{
sql_print_error("Failed to initialize early plugins.");
unireg_abort(MYSQLD_ABORT_EXIT);
}
/* Load builtin plugins, initialize MyISAM, CSV and InnoDB
注册内置插件, 初始化 MyYSAM, CSV, InnoDB
核心部分。
*/
if (plugin_register_builtin_and_init_core_se(&remaining_argc,
remaining_argv))
{
sql_print_error("Failed to initialize builtin plugins.");
unireg_abort(MYSQLD_ABORT_EXIT);
}
/*
Skip reading the plugin table when starting with --help in order
to also skip initializing InnoDB. This provides a simpler and more
uniform handling of various startup use cases, e.g. when the data
directory does not exist, exists but is empty, exists with InnoDB
system tablespaces present etc.
*/
// 注册并初始化动态插件。还要初始化尚未初始化的内置插件[MyISAM CSV INNODB 外的其他内置插件]。
if (plugin_register_dynamic_and_init_all(&remaining_argc, remaining_argv,
(opt_noacl ? PLUGIN_INIT_SKIP_PLUGIN_TABLE : 0) |
(opt_help ? (PLUGIN_INIT_SKIP_INITIALIZATION |
PLUGIN_INIT_SKIP_PLUGIN_TABLE)
: 0)))
{
sql_print_error("Failed to initialize dynamic plugins.");
unireg_abort(MYSQLD_ABORT_EXIT);
}
plugins_are_initialized = TRUE; /* Don't separate from init function */
// session_track_system_variables变量检查: 控制server是否跟踪分配给会话系统变量的任务
Session_tracker session_track_system_variables_check;
LEX_STRING var_list;
char *tmp_str;
size_t len = strlen(global_system_variables.track_sysvars_ptr);
tmp_str = (char *)my_malloc(PSI_NOT_INSTRUMENTED, len * sizeof(char) + 2,
MYF(MY_WME));
strcpy(tmp_str, global_system_variables.track_sysvars_ptr);
var_list.length = len;
var_list.str = tmp_str;
if (session_track_system_variables_check.server_boot_verify(system_charset_info,
var_list))
{
sql_print_error("The variable session_track_system_variables either has "
"duplicate values or invalid values.");
if (tmp_str)
my_free(tmp_str);
unireg_abort(MYSQLD_ABORT_EXIT);
}
if (tmp_str)
my_free(tmp_str);
/* we do want to exit if there are any other unknown options */
if (remaining_argc > 1)
{
int ho_error;
struct my_option no_opts[] =
{
{0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}};
/*
We need to eat any 'loose' arguments first before we conclude
that there are unprocessed options.
*/
my_getopt_skip_unknown = 0;
// 处理命令行选项
if ((ho_error = handle_options(&remaining_argc, &remaining_argv, no_opts,
mysqld_get_one_option)))
unireg_abort(MYSQLD_ABORT_EXIT);
/* Add back the program name handle_options removes */
remaining_argc++;
remaining_argv--;
my_getopt_skip_unknown = TRUE;
if (remaining_argc > 1)
{
sql_print_error("Too many arguments (first extra is '%s').",
remaining_argv[1]);
sql_print_information("Use --verbose --help to get a list "
"of available options!");
unireg_abort(MYSQLD_ABORT_EXIT);
}
}
if (opt_help)
unireg_abort(MYSQLD_SUCCESS_EXIT);
/* if the errmsg.sys is not loaded, terminate to maintain behaviour
如果 errmsg.sys 未加载, 则中止
*/
if (!my_default_lc_messages->errmsgs->is_loaded())
{
sql_print_error("Unable to read errmsg.sys file");
unireg_abort(MYSQLD_ABORT_EXIT);
}
/* We have to initialize the storage engines before CSV logging
在 CSV logging之前, 我们必须初始化存储引擎
*/
// 初始化 system database name cache【当前system database 只有 mysql】
if (ha_init())
{
sql_print_error("Can't init databases");
unireg_abort(MYSQLD_ABORT_EXIT);
}
if (opt_bootstrap)
log_output_options = LOG_FILE;
/*
Issue a warning if there were specified additional options to the
log-output along with NONE. Probably this wasn't what user wanted.
*/
if ((log_output_options & LOG_NONE) && (log_output_options & ~LOG_NONE))
sql_print_warning("There were other values specified to "
"log-output besides NONE. Disabling slow "
"and general logs anyway.");
if (log_output_options & LOG_TABLE)
{
/* Fall back to log files if the csv engine is not loaded. */
LEX_CSTRING csv_name = {C_STRING_WITH_LEN("csv")};
if (!plugin_is_ready(csv_name, MYSQL_STORAGE_ENGINE_PLUGIN))
{
sql_print_error("CSV engine is not present, falling back to the "
"log files");
log_output_options = (log_output_options & ~LOG_TABLE) | LOG_FILE;
}
}
query_logger.set_handlers(log_output_options);
// Open slow log file if enabled. 打开 slow log 文件
if (opt_slow_log && query_logger.reopen_log_file(QUERY_LOG_SLOW))
opt_slow_log = false;
// Open general log file if enabled. 打开 general log 文件
if (opt_general_log && query_logger.reopen_log_file(QUERY_LOG_GENERAL))
opt_general_log = false;
/*
Set the default storage engines; 设置默认存储引擎
*/
// 检查Innodb存储引擎是否初始化
if (initialize_storage_engine(default_storage_engine, "",
&global_system_variables.table_plugin))
unireg_abort(MYSQLD_ABORT_EXIT);
// 检查 Innodb 存储引擎
if (initialize_storage_engine(default_tmp_storage_engine, " temp",
&global_system_variables.temp_table_plugin))
unireg_abort(MYSQLD_ABORT_EXIT);
if (!opt_bootstrap && !opt_noacl)
{
std::string disabled_se_str(opt_disabled_storage_engines);
ha_set_normalized_disabled_se_str(disabled_se_str);
// Log warning if default_storage_engine is a disabled storage engine.
handlerton *default_se_handle =
plugin_data<handlerton *>(global_system_variables.table_plugin);
if (ha_is_storage_engine_disabled(default_se_handle))
sql_print_warning("default_storage_engine is set to a "
"disabled storage engine %s.",
default_storage_engine);
// Log warning if default_tmp_storage_engine is a disabled storage engine.
handlerton *default_tmp_se_handle =
plugin_data<handlerton *>(global_system_variables.temp_table_plugin);
if (ha_is_storage_engine_disabled(default_tmp_se_handle))
sql_print_warning("default_tmp_storage_engine is set to a "
"disabled storage engine %s.",
default_tmp_storage_engine);
}
// 两阶段提交 tc_log
if (total_ha_2pc > 1 || (1 == total_ha_2pc && opt_bin_log))
{
if (opt_bin_log)
tc_log = &mysql_bin_log;
else
tc_log = &tc_log_mmap;
}
// init tc_log
if (tc_log->open(opt_bin_log ? opt_bin_logname : opt_tc_log_file))
{
sql_print_error("Can't init tc log");
unireg_abort(MYSQLD_ABORT_EXIT);
}
// before recovery
(void)RUN_HOOK(server_state, before_recovery, (NULL));
// xa recovery 操作
if (ha_recover(0))
{
unireg_abort(MYSQLD_ABORT_EXIT);
}
/// @todo: this looks suspicious, revisit this /sven
// gtid_mode
enum_gtid_mode gtid_mode = get_gtid_mode(GTID_MODE_LOCK_NONE);
// ENFORCE_GTID_CONSISTENCY
if (gtid_mode == GTID_MODE_ON &&
_gtid_consistency_mode != GTID_CONSISTENCY_MODE_ON)
{
sql_print_error("GTID_MODE = ON requires ENFORCE_GTID_CONSISTENCY = ON.");
unireg_abort(MYSQLD_ABORT_EXIT);
}
if (opt_bin_log)
{
/*
Configures what object is used by the current log to store processed
gtid(s). This is necessary in the MYSQL_BIN_LOG::MYSQL_BIN_LOG to
corretly compute the set of previous gtids.
*/
assert(!mysql_bin_log.is_relay_log);
mysql_mutex_t *log_lock = mysql_bin_log.get_log_lock();
mysql_mutex_lock(log_lock);
// 打开 binlog 文件
if (mysql_bin_log.open_binlog(opt_bin_logname, 0,
max_binlog_size, false,
true /*need_lock_index=true*/,
true /*need_sid_lock=true*/,
NULL))
{
mysql_mutex_unlock(log_lock);
unireg_abort(MYSQLD_ABORT_EXIT);
}
mysql_mutex_unlock(log_lock);
}
if (opt_myisam_log)
(void)mi_log(1);
#if defined(HAVE_MLOCKALL) && defined(MCL_CURRENT) && !defined(EMBEDDED_LIBRARY)
if (locked_in_memory && !getuid())
{
if (setreuid((uid_t)-1, 0) == -1)
{ // this should never happen
sql_print_error("setreuid: %s", strerror(errno));
unireg_abort(MYSQLD_ABORT_EXIT);
}
if (mlockall(MCL_CURRENT))
{
sql_print_warning("Failed to lock memory. Errno: %d\n", errno); /* purecov: inspected */
locked_in_memory = 0;
}
#ifndef _WIN32
if (user_info)
set_user(mysqld_user, user_info);
#endif
}
else
#endif
locked_in_memory = 0;
/* Initialize the optimizer cost module
初始化优化器成本模块
*/
init_optimizer_cost_module(true);
ft_init_stopwords();
// 初始化 max_user_conns
init_max_user_conn();
// 初始化 sql_command_flags 和 server_command_flags 数组。
init_update_queries();
DBUG_RETURN(0);
}
注册内置插件,初始化 MyISAM、CSV、INNODB插件。
bool plugin_register_builtin_and_init_core_se(int *argc, char **argv) { bool mandatory= true; DBUG_ENTER("plugin_register_builtin_and_init_core_se"); /* Don't allow initializing twice */ assert(!initialized); /* Allocate the temporary mem root, will be freed before returning */ MEM_ROOT tmp_root; init_alloc_root(key_memory_plugin_init_tmp, &tmp_root, 4096, 4096); mysql_mutex_lock(&LOCK_plugin); initialized= true; /* First we register the builtin mandatory and optional plugins
首先, 我们注册内置强制插件和可选插件。包括:binlog, sha256_password,CSV 引擎, MEMORY 引擎,InnoDB 引擎, MyISAM, MGR_MYISAM, Performance_schema等等 */ for (struct st_mysql_plugin **builtins= mysql_mandatory_plugins; *builtins || mandatory; builtins++) { /* Switch to optional plugins when done with the mandatory ones */ if (!*builtins) { builtins= mysql_optional_plugins; mandatory= false; if (!*builtins) break; } for (struct st_mysql_plugin *plugin= *builtins; plugin->info; plugin++) { struct st_plugin_int tmp; memset(&tmp, 0, sizeof(tmp)); tmp.plugin= plugin; tmp.name.str= (char *)plugin->name; tmp.name.length= strlen(plugin->name); tmp.state= 0; tmp.load_option= mandatory ? PLUGIN_FORCE : PLUGIN_ON; /* If the performance schema is compiled in, treat the storage engine plugin as 'mandatory', to suppress any plugin-level options such as '--performance-schema'. This is specific to the performance schema, and is done on purpose: the server-level option '--performance-schema' controls the overall performance schema initialization, which consists of much more that the underlying storage engine initialization. See mysqld.cc, set_vars.cc. Suppressing ways to interfere directly with the storage engine alone prevents awkward situations where: - the user wants the performance schema functionality, by using '--enable-performance-schema' (the server option), - yet disable explicitly a component needed for the functionality to work, by using '--skip-performance-schema' (the plugin) */ if (!my_strcasecmp(&my_charset_latin1, plugin->name, "PERFORMANCE_SCHEMA")) { tmp.load_option= PLUGIN_FORCE; } free_root(&tmp_root, MYF(MY_MARK_BLOCKS_FREE)); if (test_plugin_options(&tmp_root, &tmp, argc, argv)) tmp.state= PLUGIN_IS_DISABLED; else tmp.state= PLUGIN_IS_UNINITIALIZED; struct st_plugin_int *plugin_ptr; // Pointer to registered plugin // 注册插件 if (register_builtin(plugin, &tmp, &plugin_ptr)) goto err_unlock; /* Only initialize MyISAM, InnoDB and CSV at this stage. Note that when the --help option is supplied, InnoDB is not initialized because the plugin table will not be read anyway, as indicated by the flag set when the plugin_init() function is called. 在此阶段只 初始化 MyISAM InnoDB CSV。 */ bool is_myisam= !my_strcasecmp(&my_charset_latin1, plugin->name, "MyISAM"); bool is_innodb= !my_strcasecmp(&my_charset_latin1, plugin->name, "InnoDB"); if (!is_myisam && (!is_innodb || opt_help) && my_strcasecmp(&my_charset_latin1, plugin->name, "CSV")) continue; // 初始化存储引擎 if (plugin_ptr->state != PLUGIN_IS_UNINITIALIZED || plugin_initialize(plugin_ptr)) goto err_unlock; /* Initialize the global default storage engine so that it may not be null in any child thread. */ if (is_myisam) { assert(!global_system_variables.table_plugin); assert(!global_system_variables.temp_table_plugin); global_system_variables.table_plugin= my_intern_plugin_lock(NULL, plugin_int_to_ref(plugin_ptr)); global_system_variables.temp_table_plugin= my_intern_plugin_lock(NULL, plugin_int_to_ref(plugin_ptr)); assert(plugin_ptr->ref_count == 2); } } } /* Should now be set to MyISAM storage engine */ assert(global_system_variables.table_plugin); assert(global_system_variables.temp_table_plugin); mysql_mutex_unlock(&LOCK_plugin); free_root(&tmp_root, MYF(0)); DBUG_RETURN(false); err_unlock: mysql_mutex_unlock(&LOCK_plugin); free_root(&tmp_root, MYF(0)); DBUG_RETURN(true); }
static int plugin_initialize(st_plugin_int *plugin)
{
int ret = 1;
DBUG_ENTER("plugin_initialize");
mysql_mutex_assert_owner(&LOCK_plugin);
uint state = plugin->state;
assert(state == PLUGIN_IS_UNINITIALIZED);
mysql_mutex_unlock(&LOCK_plugin);
if (plugin_type_initialize[plugin->plugin->type])
{
if ((*plugin_type_initialize[plugin->plugin->type])(plugin))
{
sql_print_error("Plugin '%s' registration as a %s failed.",
plugin->name.str, plugin_type_names[plugin->plugin->type].str);
goto err;
}
/* FIXME: Need better solution to transfer the callback function
array to memcached */
if (strcmp(plugin->name.str, "InnoDB") == 0)
{
innodb_callback_data = ((handlerton *)plugin->data)->data;
}
}
else if (plugin->plugin->init)
{
if (strcmp(plugin->name.str, "daemon_memcached") == 0)
{
plugin->data = innodb_callback_data;
}
if (plugin->plugin->init(plugin))
{
sql_print_error("Plugin '%s' init function returned error.",
plugin->name.str);
goto err;
}
}
state = PLUGIN_IS_READY; // plugin->init() succeeded
if (plugin->plugin->status_vars)
{
if (add_status_vars(plugin->plugin->status_vars))
goto err;
}
/*
set the plugin attribute of plugin's sys vars so they are pointing
to the active plugin
*/
if (plugin->system_vars)
{
sys_var_pluginvar *var = plugin->system_vars->cast_pluginvar();
for (;;)
{
var->plugin = plugin;
if (!var->next)
break;
var = var->next->cast_pluginvar();
}
}
ret = 0;
err:
mysql_mutex_lock(&LOCK_plugin);
plugin->state = state;
DBUG_RETURN(ret);
}
int ha_initialize_handlerton(st_plugin_int *plugin)
{
handlerton *hton;
DBUG_ENTER("ha_initialize_handlerton");
DBUG_PRINT("plugin", ("initialize plugin: '%s'", plugin->name.str));
hton= (handlerton *)my_malloc(key_memory_handlerton,
sizeof(handlerton),
MYF(MY_WME | MY_ZEROFILL));
if (hton == NULL)
{
sql_print_error("Unable to allocate memory for plugin '%s' handlerton.",
plugin->name.str);
goto err_no_hton_memory;
}
hton->slot= HA_SLOT_UNDEF;
/* Historical Requirement */
plugin->data= hton; // shortcut for the future
if (plugin->plugin->init && plugin->plugin->init(hton))
{
sql_print_error("Plugin '%s' init function returned error.",
plugin->name.str);
goto err;
}
/*
the switch below and hton->state should be removed when
command-line options for plugins will be implemented
*/
DBUG_PRINT("info", ("hton->state=%d", hton->state));
switch (hton->state) {
case SHOW_OPTION_NO:
break;
case SHOW_OPTION_YES:
{
uint tmp;
ulong fslot;
/* now check the db_type for conflict */
if (hton->db_type <= DB_TYPE_UNKNOWN ||
hton->db_type >= DB_TYPE_DEFAULT ||
installed_htons[hton->db_type])
{
int idx= (int) DB_TYPE_FIRST_DYNAMIC;
while (idx < (int) DB_TYPE_DEFAULT && installed_htons[idx])
idx++;
if (idx == (int) DB_TYPE_DEFAULT)
{
sql_print_warning("Too many storage engines!");
goto err_deinit;
}
if (hton->db_type != DB_TYPE_UNKNOWN)
sql_print_warning("Storage engine '%s' has conflicting typecode. "
"Assigning value %d.", plugin->plugin->name, idx);
hton->db_type= (enum legacy_db_type) idx;
}
/*
In case a plugin is uninstalled and re-installed later, it should
reuse an array slot. Otherwise the number of uninstall/install
cycles would be limited. So look for a free slot.
*/
DBUG_PRINT("plugin", ("total_ha: %lu", total_ha));
for (fslot= 0; fslot < total_ha; fslot++)
{
if (!hton2plugin[fslot])
break;
}
if (fslot < total_ha)
hton->slot= fslot;
else
{
if (total_ha >= MAX_HA)
{
sql_print_error("Too many plugins loaded. Limit is %lu. "
"Failed on '%s'", (ulong) MAX_HA, plugin->name.str);
goto err_deinit;
}
hton->slot= total_ha++;
}
installed_htons[hton->db_type]= hton;
tmp= hton->savepoint_offset;
hton->savepoint_offset= savepoint_alloc_size;
savepoint_alloc_size+= tmp;
hton2plugin[hton->slot]=plugin;
builtin_htons[hton->slot]= (plugin->plugin_dl == NULL);
if (hton->prepare)
total_ha_2pc++;
break;
}
/* fall through */
default:
hton->state= SHOW_OPTION_DISABLED;
break;
}
/*
This is entirely for legacy. We will create a new "disk based" hton and a
"memory" hton which will be configurable longterm. We should be able to
remove partition and myisammrg.
*/
switch (hton->db_type) {
case DB_TYPE_HEAP:
heap_hton= hton;
break;
case DB_TYPE_MYISAM:
myisam_hton= hton;
break;
case DB_TYPE_INNODB:
innodb_hton= hton;
break;
default:
break;
};
接下来我们会重点关注Innodb存储引擎的启动流程。