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存储引擎的启动流程。

 

posted @ 2022-04-07 14:17  卷毛狒狒  阅读(504)  评论(0编辑  收藏  举报