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

     

  • 相关阅读:
    [日常] Go语言圣经--示例: 并发的Echo服务
    [日常] Go语言圣经--示例: 并发的Clock服务习题
    [日常] Go语言圣经--接口约定习题2
    [日常] Go语言圣经--接口约定习题
    [日常] Linux下的docker实践
    [日常] Go语言圣经-指针对象的方法-bit数组习题2
    [日常] Go语言圣经-指针对象的方法-bit数组习题
    [日常] Go语言圣经-Panic异常,Recover捕获异常习题
    [日常] Go语言圣经-Deferred函数
    [日常] Go语言圣经-可变参数习题
  • 原文地址:https://www.cnblogs.com/juanmaofeifei/p/16111523.html
Copyright © 2020-2023  润新知