mysql源码启动调用栈

代码的主要功能如下:
boost:这个版本是自带Boost的库相关文件的,放在此处,如果是其它的版本就没有这个文件夹
client:客户端相关的软件和工具代码
cmake:CMAKE相关的脚本命令文件
components:组件工具
Docs:文档文件夹
doxyen_resources:doxyen工具相关资源
extra:引入的一些其它包,如网络消息谁的SSL包以及一些小工具。
include:源码用的相关的头文件放置的文件夹,但不包括存储引擎的头文件。
libbinlogevents:解析Binlog的lib服务,5.7后提供。
libbinlogstandalone:脱机配置CMAKE
libmysql:可嵌入式的客户端API
libservices:动态服务插件管理
man:帮助文档
mysql-test:服务端mysqlid的测试工具。
mysys:MySql自己实现的数据结构和一些基本算法。如数组和链表等。
packaging:打包相关
plugin:插件管理文件夹,包括一些动态加入的插件。
router:集群路由
scripts:系统工具运行的脚本。
share:共享信息,err和字符集
source_downloads:
sql:服务端的主要代码,包括main函数。
sql-common:服务端和客户端通用的一些代码。
storage:存储引擎相关文件。
strings:字符串库
support-files:.conf的示例文件和相关工具。
testclients:客户框架测试。
unittest:单元测试,这个搞程序的都知道。
utilities:公用的一些文件,有ZLIB等
vio:虚拟网络IO处理系统,不同平台或不同协议的网络通信API的二次封装。


MySQL初始化

mysql的启动初始化一直到终止阶段分析逻辑
初始化的内容
参数配置解析:
分别从/etc/my.conf, /etc/mysql/my.conf, SYSCONFDIR/my.cnf, "$MYSQL_HOME"/my.conf, defaults-extra-file, ~/my.conf, DATADIR/mysqld-auto.cnf, 命令行 加载配置文件中的配置项。SYSCONFDIR/my.cnf是在编译时指定的路径,DATADIR是指定的数据目录 ,如果不指定特定的配置的,将按照上面逐步查找配置。
performance schema interface(PSI)初始化;PSI主要用于监控/诊断MySQL服务运行状态,可以阅读官方文档:https://dev.mysql.com/doc/refman/8.0/en/performance-schema.html 和(PFS)初始化
初始化定时器timer;
时间相关的
基础的锁结构;
资源池,通知消息等初始化;
字符集/collation
元数据
系统库表,information_schema
DDL/DQL/DML/ACL支持的命令
plugin,存储引擎
binlog
优化器optimizer代价
恢复持久化中的事务数据,
ACL相关的初始化,授权相关的初始化
SSL
信号处理
审计相关初始化
各类管理器
MySQL中的线程

MySQL中的线程
MySQL中主要会启动以下线程处理各种任务:
连接监听主线程,用于监听处理客户端的连接请求,然后将连接请求分发到单独的线程,并处理该连接上的所有请求;
处理线程,是一个线程池,具体在后面会介绍;
slave/relay线程,连接到主服务的线程,并且从主服务器中读取binlog更新,在本机上应用更新;
信号处理线程,用来处理信号,具体的信号包括了:SIGTERM, SIGQUIT, SIGHUP, SIGUSR1 and SIGUSR2
event_scheduler_thread,事件调度线程,用来调度执行每个表上定义事件,即Event。
compress_gtid_table_thread,开启一个线程用来压缩GTID_Table,具体的压缩逻辑在mysql-server-8.0/sql/http://rpl_gtid_persist.cc中,估计后续会进一步阅读。
helper_thread,辅助线程来分发计时器timer到期通知消息,具体逻辑在timer_notify_thread_func。
admin_socket_thread,如果开启了该线程,并且以端口监听,则可以用handle_admin_socket处理请求的逻辑,具体的连接也会用一个新的线程处理。


1.3 全量源码


int mysqld_main(int argc, char **argv)
#endif
{
  // Substitute the full path to the executable in argv[0]
  //将命令行的程序名替换成全路径的程序名,可能是“全路径”,home路径解释,环境变量PATH解释。
  substitute_progpath(argv);
  //在环境变量(“NOTIFY_SOCKET“)中查找socket的文件名,如果存在的话则连接该Socket
  sysd::notify_connect();
  //向Notify Socket发送正在启动的消息
  sysd::notify("STATUS=Server startup in progress\n");

  /*
    Perform basic thread library and malloc initialization,
    to be able to read defaults files and parse options.
  */
  my_progname = argv[0];
  calculate_mysql_home_from_my_progname();

#ifndef _WIN32
#ifdef WITH_PERFSCHEMA_STORAGE_ENGINE
  pre_initialize_performance_schema();
#endif /*WITH_PERFSCHEMA_STORAGE_ENGINE */
  // For windows, my_init() is called from the win specific mysqld_main
  if (my_init())  // init my_sys library & pthreads
  {
    LogErr(ERROR_LEVEL, ER_MYINIT_FAILED);
    flush_error_log_messages();
    return 1;
  }
#endif /* _WIN32 */

  orig_argc = argc;
  orig_argv = argv;
  my_getopt_use_args_separator = true;
  my_defaults_read_login_file = false;
  if (load_defaults(MYSQL_CONFIG_NAME, load_default_groups, &argc, &argv,
                    &argv_alloc)) {
    flush_error_log_messages();
    return 1;
  }

  /* Set data dir directory paths */
  strmake(mysql_real_data_home, get_relative_path(MYSQL_DATADIR),
          sizeof(mysql_real_data_home) - 1);

  /*
   Initialize variables cache for persisted variables, load persisted
   config file and append read only persisted variables to command line
   options if present.
  */
  if (persisted_variables_cache.init(&argc, &argv) ||
      persisted_variables_cache.load_persist_file() ||
      persisted_variables_cache.append_read_only_variables(&argc, &argv)) {
    flush_error_log_messages();
    return 1;
  }
  my_getopt_use_args_separator = false;
  remaining_argc = argc;
  remaining_argv = argv;

  init_variable_default_paths();

  /* Must be initialized early for comparison of options name */
  system_charset_info = &my_charset_utf8_general_ci;

  /* Write mysys error messages to the error log. */
  local_message_hook = error_log_print;

  int heo_error;

#ifdef WITH_PERFSCHEMA_STORAGE_ENGINE
  /*
    Initialize the array of performance schema instrument configurations.
  */
  init_pfs_instrument_array();
#endif /* WITH_PERFSCHEMA_STORAGE_ENGINE */

  heo_error = handle_early_options();

  init_sql_statement_names();
  sys_var_init();
  ulong requested_open_files = 0;

  //  Init error log subsystem. This does not actually open the log yet.
  if (init_error_log()) unireg_abort(MYSQLD_ABORT_EXIT);
  if (!opt_validate_config) adjust_related_options(&requested_open_files);

#ifdef WITH_PERFSCHEMA_STORAGE_ENGINE
  if (heo_error == 0) {
    if (!is_help_or_validate_option() && !opt_initialize) {
      int pfs_rc;
      /* Add sizing hints from the server sizing parameters. */
      pfs_param.m_hints.m_table_definition_cache = table_def_size;
      pfs_param.m_hints.m_table_open_cache = table_cache_size;
      pfs_param.m_hints.m_max_connections = max_connections;
      pfs_param.m_hints.m_open_files_limit = requested_open_files;
      pfs_param.m_hints.m_max_prepared_stmt_count = max_prepared_stmt_count;

      pfs_rc = initialize_performance_schema(
          &pfs_param, &psi_thread_hook, &psi_mutex_hook, &psi_rwlock_hook,
          &psi_cond_hook, &psi_file_hook, &psi_socket_hook, &psi_table_hook,
          &psi_mdl_hook, &psi_idle_hook, &psi_stage_hook, &psi_statement_hook,
          &psi_transaction_hook, &psi_memory_hook, &psi_error_hook,
          &psi_data_lock_hook, &psi_system_hook);
      if ((pfs_rc != 0) && pfs_param.m_enabled) {
        pfs_param.m_enabled = false;
        LogErr(WARNING_LEVEL, ER_PERFSCHEMA_INIT_FAILED);
      }
    }
  }
#endif /* WITH_PERFSCHEMA_STORAGE_ENGINE */

#ifdef WITH_LOCK_ORDER
  if (heo_error == 0) {
    if (lo_param.m_enabled && !opt_help && !opt_initialize) {
      int lo_rc;
      lo_rc = LO_init(&lo_param, &psi_thread_hook, &psi_mutex_hook,
                      &psi_rwlock_hook, &psi_cond_hook, &psi_file_hook,
                      &psi_socket_hook, &psi_table_hook, &psi_mdl_hook,
                      &psi_idle_hook, &psi_stage_hook, &psi_statement_hook,
                      &psi_transaction_hook, &psi_memory_hook);
      if (lo_rc != 0) {
        LogErr(WARNING_LEVEL, ER_LOCK_ORDER_INIT_FAILED);
      }
    }
  }
#endif /* WITH_LOCK_ORDER */

  /*
    Other provider of the instrumentation interface should
    initialize PSI_hook here:
    - HAVE_PSI_INTERFACE is for the instrumentation interface
    - WITH_PERFSCHEMA_STORAGE_ENGINE is for one implementation
      of the interface,
    but there could be alternate implementations, which is why
    these two defines are kept separate.
  */

#ifdef HAVE_PSI_INTERFACE
  /*
    Obtain the current performance schema instrumentation interface,
    if available.
  */

  void *service;

  if (psi_thread_hook != nullptr) {
    service = psi_thread_hook->get_interface(PSI_CURRENT_THREAD_VERSION);
    if (service != nullptr) {
      set_psi_thread_service(service);
    }
  }

  if (psi_mutex_hook != nullptr) {
    service = psi_mutex_hook->get_interface(PSI_CURRENT_MUTEX_VERSION);
    if (service != nullptr) {
      set_psi_mutex_service(service);
    }
  }

  if (psi_rwlock_hook != nullptr) {
    service = psi_rwlock_hook->get_interface(PSI_CURRENT_RWLOCK_VERSION);
    if (service != nullptr) {
      set_psi_rwlock_service(service);
    }
  }

  if (psi_cond_hook != nullptr) {
    service = psi_cond_hook->get_interface(PSI_CURRENT_COND_VERSION);
    if (service != nullptr) {
      set_psi_cond_service(service);
    }
  }

  if (psi_file_hook != nullptr) {
    service = psi_file_hook->get_interface(PSI_CURRENT_FILE_VERSION);
    if (service != nullptr) {
      set_psi_file_service(service);
    }
  }

  if (psi_socket_hook != nullptr) {
    service = psi_socket_hook->get_interface(PSI_CURRENT_SOCKET_VERSION);
    if (service != nullptr) {
      set_psi_socket_service(service);
    }
  }

  if (psi_table_hook != nullptr) {
    service = psi_table_hook->get_interface(PSI_CURRENT_TABLE_VERSION);
    if (service != nullptr) {
      set_psi_table_service(service);
    }
  }

  if (psi_mdl_hook != nullptr) {
    service = psi_mdl_hook->get_interface(PSI_CURRENT_MDL_VERSION);
    if (service != nullptr) {
      set_psi_mdl_service(service);
    }
  }

  if (psi_idle_hook != nullptr) {
    service = psi_idle_hook->get_interface(PSI_CURRENT_IDLE_VERSION);
    if (service != nullptr) {
      set_psi_idle_service(service);
    }
  }

  if (psi_stage_hook != nullptr) {
    service = psi_stage_hook->get_interface(PSI_CURRENT_STAGE_VERSION);
    if (service != nullptr) {
      set_psi_stage_service(service);
    }
  }

  if (psi_statement_hook != nullptr) {
    service = psi_statement_hook->get_interface(PSI_CURRENT_STATEMENT_VERSION);
    if (service != nullptr) {
      set_psi_statement_service(service);
    }
  }

  if (psi_transaction_hook != nullptr) {
    service =
        psi_transaction_hook->get_interface(PSI_CURRENT_TRANSACTION_VERSION);
    if (service != nullptr) {
      set_psi_transaction_service(service);
    }
  }

  if (psi_memory_hook != nullptr) {
    service = psi_memory_hook->get_interface(PSI_CURRENT_MEMORY_VERSION);
    if (service != nullptr) {
      set_psi_memory_service(service);
    }
  }

  if (psi_error_hook != nullptr) {
    service = psi_error_hook->get_interface(PSI_CURRENT_ERROR_VERSION);
    if (service != nullptr) {
      set_psi_error_service(service);
    }
  }

  if (psi_data_lock_hook != nullptr) {
    service = psi_data_lock_hook->get_interface(PSI_CURRENT_DATA_LOCK_VERSION);
    if (service != nullptr) {
      set_psi_data_lock_service(service);
    }
  }

  if (psi_system_hook != nullptr) {
    service = psi_system_hook->get_interface(PSI_CURRENT_SYSTEM_VERSION);
    if (service != nullptr) {
      set_psi_system_service(service);
    }
  }

  /*
    Now that we have parsed the command line arguments, and have initialized
    the performance schema itself, the next step is to register all the
    server instruments.
  */
  init_server_psi_keys();

  /*
    Now that some instrumentation is in place,
    recreate objects which were initialised early,
    so that they are instrumented as well.
  */
  my_thread_global_reinit();
#endif /* HAVE_PSI_INTERFACE */

  /*
    Initialize Components core subsystem early on, once we have PSI, which it
    uses. This part doesn't use any more MySQL-specific functionalities but
    error logging and PFS.
  */
  if (component_infrastructure_init()) unireg_abort(MYSQLD_ABORT_EXIT);

    /*
      Initialize Performance Schema component services.
    */
#ifdef HAVE_PSI_THREAD_INTERFACE
  if (!is_help_or_validate_option() && !opt_initialize) {
    register_pfs_notification_service();
    register_pfs_resource_group_service();
  }
#endif

  // Initialize the resource group subsystem.
  auto res_grp_mgr = resourcegroups::Resource_group_mgr::instance();
  if (!is_help_or_validate_option() && !opt_initialize) {
    if (res_grp_mgr->init()) {
      LogErr(ERROR_LEVEL, ER_RESOURCE_GROUP_SUBSYSTEM_INIT_FAILED);
      unireg_abort(MYSQLD_ABORT_EXIT);
    }
  }

#ifdef HAVE_PSI_THREAD_INTERFACE
  /* Instrument the main thread */
  PSI_thread *psi = PSI_THREAD_CALL(new_thread)(key_thread_main, nullptr, 0);
  PSI_THREAD_CALL(set_thread_os_id)(psi);
  PSI_THREAD_CALL(set_thread)(psi);
#endif /* HAVE_PSI_THREAD_INTERFACE */

  /* Initialize audit interface globals. Audit plugins are inited later. */
  mysql_audit_initialize();

  Srv_session::module_init();

  /*
    Perform basic query log initialization. Should be called after
    MY_INIT, as it initializes mutexes.
  */
  query_logger.init();

  if (heo_error) {
    /*
      Parsing command line option failed,
      Since we don't have a workable remaining_argc/remaining_argv
      to continue the server initialization, this is as far as this
      code can go.
      This is the best effort to log meaningful messages:
      - messages will be printed to stderr, which is not redirected yet,
      - messages will be printed in the NT event log, for windows.
    */
    flush_error_log_messages();
    /*
      Not enough initializations for unireg_abort()
      Using exit() for windows.
    */
    exit(MYSQLD_ABORT_EXIT);
  }

  if (init_common_variables()) {
    setup_error_log();
    unireg_abort(MYSQLD_ABORT_EXIT);  // Will do exit
  }

  my_init_signals();

  size_t guardize = 0;
#ifndef _WIN32
  int retval = pthread_attr_getguardsize(&connection_attrib, &guardize);
  DBUG_ASSERT(retval == 0);
  if (retval != 0) guardize = my_thread_stack_size;
#endif

#if defined(__ia64__) || defined(__ia64)
  /*
    Peculiar things with ia64 platforms - it seems we only have half the
    stack size in reality, so we have to double it here
  */
  guardize = my_thread_stack_size;
#endif

  if (0 != my_thread_attr_setstacksize(&connection_attrib,
                                       my_thread_stack_size + guardize)) {
    DBUG_ASSERT(false);
  }

  {
    /* Retrieve used stack size;  Needed for checking stack overflows */
    size_t stack_size = 0;
    my_thread_attr_getstacksize(&connection_attrib, &stack_size);

    /* We must check if stack_size = 0 as Solaris 2.9 can return 0 here */
    if (stack_size && stack_size < (my_thread_stack_size + guardize)) {
      LogErr(WARNING_LEVEL, ER_STACKSIZE_UNEXPECTED,
             my_thread_stack_size + guardize, (long)stack_size);
#if defined(__ia64__) || defined(__ia64)
      my_thread_stack_size = stack_size / 2;
#else
      my_thread_stack_size = static_cast<ulong>(stack_size - guardize);
#endif
    }
  }

#ifndef DBUG_OFF
  test_lc_time_sz();
  srand(static_cast<uint>(time(nullptr)));
#endif

#if !defined(_WIN32)

  if (opt_initialize && opt_daemonize) {
    fprintf(stderr, "Initialize and daemon options are incompatible.\n");
    unireg_abort(MYSQLD_ABORT_EXIT);
  }

  if (opt_daemonize && log_error_dest == disabled_my_option &&
      (isatty(STDOUT_FILENO) || isatty(STDERR_FILENO))) {
    // Just use the default in this case.
    log_error_dest = "";
  }

  if (opt_daemonize && !opt_validate_config) {
    if (chdir("/") < 0) {
      LogErr(ERROR_LEVEL, ER_CANNOT_CHANGE_TO_ROOT_DIR, strerror(errno));
      unireg_abort(MYSQLD_ABORT_EXIT);
    }

    if ((pipe_write_fd = mysqld::runtime::mysqld_daemonize()) < -1) {
      LogErr(ERROR_LEVEL, ER_FAILED_START_MYSQLD_DAEMON);
      unireg_abort(MYSQLD_ABORT_EXIT);
    }

    if (pipe_write_fd < 0) {
      // This is the launching process and the daemon appears to have
      // started ok (Need to call unireg_abort with success here to
      // clean up resources in the lauching process.
      unireg_abort(MYSQLD_SUCCESS_EXIT);
    }

    // Need to update the value of current_pid so that it reflects the
    // pid of the daemon (the previous value was set by unireg_init()
    // while still in the launcher process.
    current_pid = static_cast<ulong>(getpid());
  }
#endif

#ifndef _WIN32
  user_info = check_user(mysqld_user);
  if (!user_info.IsVoid()) {
#if HAVE_CHOWN
    if (unlikely(opt_initialize)) {
      /* need to change the owner of the freshly created data directory */
      MY_STAT stat;
      char errbuf[MYSYS_STRERROR_SIZE];
      bool must_chown = true;

      /* fetch the directory's owner */
      if (!my_stat(mysql_real_data_home, &stat, MYF(0))) {
        LogErr(INFORMATION_LEVEL, ER_CANT_STAT_DATADIR, my_errno(),
               my_strerror(errbuf, sizeof(errbuf), my_errno()));
      }
      /* Don't change it if it's already the same as SElinux stops this */
      else if (stat.st_uid == user_info.pw_uid &&
               stat.st_gid == user_info.pw_gid)
        must_chown = false;

      if (must_chown &&
          chown(mysql_real_data_home, user_info.pw_uid, user_info.pw_gid)) {
        LogErr(ERROR_LEVEL, ER_CANT_CHOWN_DATADIR, mysqld_user);
        unireg_abort(1);
      }
    }
#endif

#if defined(HAVE_MLOCKALL) && defined(MCL_CURRENT)
    if (locked_in_memory)  // getuid() == 0 here
      set_effective_user(user_info);
    else
#endif
      set_user(mysqld_user, user_info);
  }
#endif  // !_WIN32

  /*
   initiate key migration if any one of the migration specific
   options are provided.
  */
  if (opt_keyring_migration_source || opt_keyring_migration_destination ||
      migrate_connect_options) {
    Migrate_keyring mk;
    my_getopt_skip_unknown = TRUE;
    if (mk.init(remaining_argc, remaining_argv, opt_keyring_migration_source,
                opt_keyring_migration_destination, opt_keyring_migration_user,
                opt_keyring_migration_host, opt_keyring_migration_password,
                opt_keyring_migration_socket, opt_keyring_migration_port)) {
      LogErr(ERROR_LEVEL, ER_KEYRING_MIGRATION_FAILED);
      log_error_dest = "stderr";
      flush_error_log_messages();
      unireg_abort(MYSQLD_ABORT_EXIT);
    }

    if (mk.execute()) {
      LogErr(ERROR_LEVEL, ER_KEYRING_MIGRATION_FAILED);
      log_error_dest = "stderr";
      flush_error_log_messages();
      unireg_abort(MYSQLD_ABORT_EXIT);
    }

    my_getopt_skip_unknown = false;
    LogErr(INFORMATION_LEVEL, ER_KEYRING_MIGRATION_SUCCESSFUL);
    log_error_dest = "stderr";
    flush_error_log_messages();
    unireg_abort(MYSQLD_SUCCESS_EXIT);
  }

  /*
   We have enough space for fiddling with the argv, continue
  */
  if (!(is_help_or_validate_option()) &&
      my_setwd(mysql_real_data_home, MYF(0))) {
    char errbuf[MYSYS_STRERROR_SIZE];

    LogErr(ERROR_LEVEL, ER_CANT_SET_DATA_DIR, mysql_real_data_home, errno,
           my_strerror(errbuf, sizeof(errbuf), errno));
    unireg_abort(MYSQLD_ABORT_EXIT); /* purecov: inspected */
  }

  /*
   The subsequent calls may take a long time : e.g. innodb log read.
   Thus set the long running service control manager timeout
  */
#if defined(_WIN32)
  if (windows_service) {
    if (setup_service_status_cmd_processed_handle())
      unireg_abort(MYSQLD_ABORT_EXIT);

    char buf[32];
    snprintf(buf, sizeof(buf), "T %lu", slow_start_timeout);
    Service_status_msg msg(buf);
    send_service_status(msg);
  }
#endif

  /* Determine default TCP port and unix socket name */
  set_ports();

  if (init_server_components()) unireg_abort(MYSQLD_ABORT_EXIT);

  if (!server_id_supplied)
    LogErr(INFORMATION_LEVEL, ER_WARN_NO_SERVERID_SPECIFIED);

  /*
    Add server_uuid to the sid_map.  This must be done after
    server_uuid has been initialized in init_server_auto_options and
    after the binary log (and sid_map file) has been initialized in
    init_server_components().

    No error message is needed: init_sid_map() prints a message.

    Strictly speaking, this is not currently needed when
    opt_bin_log==0, since the variables that gtid_state->init
    initializes are not currently used in that case.  But we call it
    regardless to avoid possible future bugs if gtid_state ever
    needs to do anything else.
  */
  global_sid_lock->wrlock();
  int gtid_ret = gtid_state->init();
  global_sid_lock->unlock();

  if (gtid_ret) unireg_abort(MYSQLD_ABORT_EXIT);

  if (!opt_initialize && !opt_initialize_insecure) {
    // Initialize executed_gtids from mysql.gtid_executed table.
    if (gtid_state->read_gtid_executed_from_table() == -1) unireg_abort(1);
  }

  if (opt_bin_log) {
    /*
      Initialize GLOBAL.GTID_EXECUTED and GLOBAL.GTID_PURGED from
      gtid_executed table and binlog files during server startup.
    */
    Gtid_set *executed_gtids =
        const_cast<Gtid_set *>(gtid_state->get_executed_gtids());
    Gtid_set *lost_gtids = const_cast<Gtid_set *>(gtid_state->get_lost_gtids());
    Gtid_set *gtids_only_in_table =
        const_cast<Gtid_set *>(gtid_state->get_gtids_only_in_table());
    Gtid_set *previous_gtids_logged =
        const_cast<Gtid_set *>(gtid_state->get_previous_gtids_logged());

    Gtid_set purged_gtids_from_binlog(global_sid_map, global_sid_lock);
    Gtid_set gtids_in_binlog(global_sid_map, global_sid_lock);
    Gtid_set gtids_in_binlog_not_in_table(global_sid_map, global_sid_lock);

    if (mysql_bin_log.init_gtid_sets(
            &gtids_in_binlog, &purged_gtids_from_binlog,
            opt_master_verify_checksum, true /*true=need lock*/,
            nullptr /*trx_parser*/, nullptr /*partial_trx*/,
            true /*is_server_starting*/))
      unireg_abort(MYSQLD_ABORT_EXIT);

    global_sid_lock->wrlock();

    purged_gtids_from_binlog.dbug_print("purged_gtids_from_binlog");
    gtids_in_binlog.dbug_print("gtids_in_binlog");

    if (!gtids_in_binlog.is_empty() &&
        !gtids_in_binlog.is_subset(executed_gtids)) {
      gtids_in_binlog_not_in_table.add_gtid_set(&gtids_in_binlog);
      if (!executed_gtids->is_empty())
        gtids_in_binlog_not_in_table.remove_gtid_set(executed_gtids);
      /*
        Save unsaved GTIDs into gtid_executed table, in the following
        four cases:
          1. the upgrade case.
          2. the case that a slave is provisioned from a backup of
             the master and the slave is cleaned by RESET MASTER
             and RESET SLAVE before this.
          3. the case that no binlog rotation happened from the
             last RESET MASTER on the server before it crashes.
          4. The set of GTIDs of the last binlog is not saved into the
             gtid_executed table if server crashes, so we save it into
             gtid_executed table and executed_gtids during recovery
             from the crash.
      */
      if (gtid_state->save(&gtids_in_binlog_not_in_table) == -1) {
        global_sid_lock->unlock();
        unireg_abort(MYSQLD_ABORT_EXIT);
      }
      executed_gtids->add_gtid_set(&gtids_in_binlog_not_in_table);
    }

    /* gtids_only_in_table= executed_gtids - gtids_in_binlog */
    if (gtids_only_in_table->add_gtid_set(executed_gtids) != RETURN_STATUS_OK) {
      global_sid_lock->unlock();
      unireg_abort(MYSQLD_ABORT_EXIT);
    }
    gtids_only_in_table->remove_gtid_set(&gtids_in_binlog);
    /*
      lost_gtids = executed_gtids -
                   (gtids_in_binlog - purged_gtids_from_binlog)
                 = gtids_only_in_table + purged_gtids_from_binlog;
    */
    DBUG_ASSERT(lost_gtids->is_empty());
    if (lost_gtids->add_gtid_set(gtids_only_in_table) != RETURN_STATUS_OK ||
        lost_gtids->add_gtid_set(&purged_gtids_from_binlog) !=
            RETURN_STATUS_OK) {
      global_sid_lock->unlock();
      unireg_abort(MYSQLD_ABORT_EXIT);
    }

    /* Prepare previous_gtids_logged for next binlog */
    if (previous_gtids_logged->add_gtid_set(&gtids_in_binlog) !=
        RETURN_STATUS_OK) {
      global_sid_lock->unlock();
      unireg_abort(MYSQLD_ABORT_EXIT);
    }

    /*
      Write the previous set of gtids at this point because during
      the creation of the binary log this is not done as we cannot
      move the init_gtid_sets() to a place before openning the binary
      log. This requires some investigation.

      /Alfranio
    */
    Previous_gtids_log_event prev_gtids_ev(&gtids_in_binlog);

    global_sid_lock->unlock();

    (prev_gtids_ev.common_footer)->checksum_alg =
        static_cast<enum_binlog_checksum_alg>(binlog_checksum_options);

    if (mysql_bin_log.write_event_to_binlog_and_sync(&prev_gtids_ev))
      unireg_abort(MYSQLD_ABORT_EXIT);

    (void)RUN_HOOK(server_state, after_engine_recovery, (nullptr));
  }

  if (init_ssl_communication()) unireg_abort(MYSQLD_ABORT_EXIT);
  if (network_init()) unireg_abort(MYSQLD_ABORT_EXIT);

#ifdef _WIN32
  if (opt_require_secure_transport && !opt_enable_shared_memory &&
      !SslAcceptorContext::have_ssl() && !opt_initialize) {
    LogErr(ERROR_LEVEL, ER_TRANSPORTS_WHAT_TRANSPORTS);
    unireg_abort(MYSQLD_ABORT_EXIT);
  }
#endif

  /*
   Initialize my_str_malloc(), my_str_realloc() and my_str_free()
  */
  my_str_malloc = &my_str_malloc_mysqld;
  my_str_free = &my_str_free_mysqld;
  my_str_realloc = &my_str_realloc_mysqld;

  error_handler_hook = my_message_sql;

  bool abort = false;

  /* Save pid of this process in a file */
  if (!opt_initialize) {
    if (create_pid_file()) abort = true;
  }

  /* Read the optimizer cost model configuration tables */
  if (!opt_initialize) reload_optimizer_cost_constants();

  if (
      /*
        Read components table to restore previously installed components. This
        requires read access to mysql.component table.
      */
      (!opt_initialize && mysql_component_infrastructure_init()) ||
      mysql_rm_tmp_tables()) {
    abort = true;
  }

  /* we do want to exit if there are any other unknown options */
  if (remaining_argc > 1) {
    int ho_error;
    struct my_option no_opts[] = {<!-- -->{nullptr, 0, nullptr, nullptr, nullptr,
                                   nullptr, GET_NO_ARG, NO_ARG, 0, 0, 0,
                                   nullptr, 0, nullptr}};
    /*
      We need to eat any 'loose' arguments first before we conclude
      that there are unprocessed options.
    */
    my_getopt_skip_unknown = false;

    if ((ho_error = handle_options(&remaining_argc, &remaining_argv, no_opts,
                                   mysqld_get_one_option)))
      abort = true;
    else {
      /* Add back the program name handle_options removes */
      remaining_argc++;
      remaining_argv--;
      my_getopt_skip_unknown = true;

      if (remaining_argc > 1) {
        LogErr(ERROR_LEVEL, ER_EXCESS_ARGUMENTS, remaining_argv[1]);
        LogErr(INFORMATION_LEVEL, ER_VERBOSE_HINT);
        abort = true;
      }
    }
  }

  if (abort || acl_init(opt_noacl)) {
    if (!abort) LogErr(ERROR_LEVEL, ER_PRIVILEGE_SYSTEM_INIT_FAILED);
    abort = true;
    opt_noacl = true;
  }

  /*
   if running with --initialize, explicitly allocate the memory
   to be used by ACL objects.
  */
  if (opt_initialize) init_acl_memory();

  /*
    Turn ON the system variable '@@partial_revokes' during server
    start in case there exist at least one restrictions instance.
  */
  if (mysqld_partial_revokes() == false && is_partial_revoke_exists(nullptr)) {
    set_mysqld_partial_revokes(true);
    LogErr(WARNING_LEVEL, ER_TURNING_ON_PARTIAL_REVOKES);
  }

  if (abort || my_tz_init((THD *)nullptr, default_tz_name, opt_initialize) ||
      grant_init(opt_noacl)) {
    set_connection_events_loop_aborted(true);

    delete_pid_file(MYF(MY_WME));

    unireg_abort(MYSQLD_ABORT_EXIT);
  }

  /*
    Bootstrap the dynamic privilege service implementation
  */
  if (dynamic_privilege_init()) {
    LogErr(WARNING_LEVEL, ER_PERSISTENT_PRIVILEGES_BOOTSTRAP);
  }

  if (!opt_initialize) servers_init(false);

  if (!opt_noacl) {
    udf_read_functions_table();
  }

  init_status_vars();
  /* If running with --initialize, do not start replication. */
  if (opt_initialize) opt_skip_slave_start = true;

  check_binlog_cache_size(nullptr);
  check_binlog_stmt_cache_size(nullptr);

  binlog_unsafe_map_init();

  /* If running with --initialize, do not start replication. */
  if (!opt_initialize) {
    // Make @@slave_skip_errors show the nice human-readable value.
    set_slave_skip_errors(&opt_slave_skip_errors);
    /*
      Group replication filters should be discarded before init_slave(),
      otherwise the pre-configured filters will be referenced by group
      replication channels.
    */
    rpl_channel_filters.discard_group_replication_filters();

    /*
      init_slave() must be called after the thread keys are created.
    */
    if (server_id != 0)
      init_slave(); /* Ignoring errors while configuring replication. */

    /*
      If the user specifies a per-channel replication filter through a
      command-line option (or in a configuration file) for a slave
      replication channel which does not exist as of now (i.e not
      present in slave info tables yet), then the per-channel
      replication filter is discarded with a warning.
      If the user specifies a per-channel replication filter through
      a command-line option (or in a configuration file) for group
      replication channels 'group_replication_recovery' and
      'group_replication_applier' which is disallowed, then the
      per-channel replication filter is discarded with a warning.
    */
    rpl_channel_filters.discard_all_unattached_filters();
  }

#ifdef WITH_LOCK_ORDER
  if (!opt_initialize) {
    LO_activate();
  }
#endif /* WITH_LOCK_ORDER */

#ifdef WITH_PERFSCHEMA_STORAGE_ENGINE
  initialize_performance_schema_acl(opt_initialize);
#endif /* WITH_PERFSCHEMA_STORAGE_ENGINE */

  initialize_information_schema_acl();

  (void)RUN_HOOK(server_state, after_recovery, (nullptr));

  if (Events::init(opt_noacl || opt_initialize))
    unireg_abort(MYSQLD_ABORT_EXIT);

#ifndef _WIN32
  //  Start signal handler thread.
  start_signal_handler();
#endif

  /* set all persistent options */
  if (persisted_variables_cache.set_persist_options()) {
    LogErr(ERROR_LEVEL, ER_CANT_SET_UP_PERSISTED_VALUES);
    flush_error_log_messages();
    return 1;
  }

  /*
    Activate loadable error logging components, if any.
    First, check configuration value -- is it well-formed, and do
    the requested services exist?
  */
  if (log_builtins_error_stack(opt_log_error_services, true, nullptr) == 0) {
    // Syntax is OK and services exist; let's try to initialize them:
    size_t pos;

    if (log_builtins_error_stack(opt_log_error_services, false, &pos) < 0) {
      char *problem = opt_log_error_services; /* purecov: begin inspected */
      const char *var_name = "log_error_services";

      /*
        We failed to set the requested configuration. This can happen
        e.g. when a given log-writer does not have sufficient permissions
        to open its log files. pos should mark the position in the
        configuration string where we ran into trouble. Make a char-pointer
        from it so we can inform the user what log-service we could not
        initialize.
      */
      if (pos < strlen(opt_log_error_services))
        problem = &((char *)opt_log_error_services)[pos];

      flush_error_log_messages();

      /*
        We could not set the requested pipeline.
        Try to fall back to default error logging stack
        (by looking up the system variable for this configuration
        item and extracting the default value from it).
        If that's impossible, print diagnostics, then exit.
      */
      sys_var *var = intern_find_sys_var(var_name, strlen(var_name));

      if (var != nullptr) {
        // We found the system variable, now extract the default value:
        opt_log_error_services = (char *)var->get_default();
        if (log_builtins_error_stack(opt_log_error_services, false, nullptr) >=
            0) {
          /*
            We managed to set the default pipeline. Now log what was wrong
            about the user-supplied value, then shut down.
          */
          LogErr(ERROR_LEVEL, ER_CANT_START_ERROR_LOG_SERVICE, var_name,
                 problem);
          unireg_abort(MYSQLD_ABORT_EXIT);
        }
        /*
          If we arrive here, the user-supplied value was valid, but could
          not be set. The default value was found, but also could not be
          set. Something is very wrong. Fall-through to below where we
          low-level write diagnostics, then abort.
        */
      }

      /*
        We failed to set the default error logging stack (or failed to look
        up the default setting). At this point, we don't know whether ANY of
        the requested sinks work, so our best bet is to write directly to the
        error stream. Then, we abort.
      */
      {
        char buff[512];
        size_t len;

        len = snprintf(buff, sizeof(buff),
                       ER_DEFAULT(ER_CANT_START_ERROR_LOG_SERVICE), var_name,
                       problem);
        len = std::min(len, sizeof(buff) - 1);

        // Trust nothing. Write directly. Quit.
        log_write_errstream(buff, len);

        unireg_abort(MYSQLD_ABORT_EXIT);
      } /* purecov: end */
    }   // value was OK, but could not be set
    // If we arrive here, the value was OK, and was set successfully.
  } else {
    /*
      We were given an illegal value at start-up, so the default was
      used instead. Let's now point our variable back at the default
      (i.e. the value actually used) so SELECT @@GLOBAL.log_error_services
      will render correct results.
    */
    sys_var *var = intern_find_sys_var(STRING_WITH_LEN("log_error_services"));
    char *default_services = nullptr;

    if ((var != nullptr) &&
        ((default_services = (char *)var->get_default()) != nullptr))
      log_builtins_error_stack(default_services, false, nullptr);

    // Report that we're falling back to the default value.
    LogErr(WARNING_LEVEL, ER_CANNOT_SET_LOG_ERROR_SERVICES,
           opt_log_error_services);

    if (default_services != nullptr) opt_log_error_services = default_services;
  }

  /*
    Now that the error-logging stack is fully set up, loadable components
    and all, flush buffered log-events to the log-services the user actually
    wants!
  */
  log_error_stage_set(LOG_ERROR_STAGE_EXTERNAL_SERVICES_AVAILABLE);
  flush_error_log_messages();

  /*
    Invoke the bootstrap thread, if required.
  */
  process_bootstrap();

  /*
    Event must be invoked after error_handler_hook is assigned to
    my_message_sql, otherwise my_message will not cause the event to abort.
  */
  void *argv_p = argv;
  if (mysql_audit_notify(AUDIT_EVENT(MYSQL_AUDIT_SERVER_STARTUP_STARTUP),
                         static_cast<const char **>(argv_p), argc))
    unireg_abort(MYSQLD_ABORT_EXIT);

#ifdef _WIN32
  create_shutdown_and_restart_thread();
#endif
  if (mysqld_process_must_end_at_startup) {
#if !defined(_WIN32)
    if (opt_daemonize) mysqld::runtime::signal_parent(pipe_write_fd, 1);
#endif
    unireg_abort(MYSQLD_SUCCESS_EXIT);
  }

  start_handle_manager();

  create_compress_gtid_table_thread();

  LogEvent()
      .type(LOG_TYPE_ERROR)
      .subsys(LOG_SUBSYSTEM_TAG)
      .prio(SYSTEM_LEVEL)
      .lookup(ER_SERVER_STARTUP_MSG, my_progname, server_version,
#ifdef HAVE_SYS_UN_H
              (opt_initialize ? "" : mysqld_unix_port),
#else
              "",
#endif
              mysqld_port, MYSQL_COMPILATION_COMMENT_SERVER);

  if (!opt_disable_networking && my_admin_bind_addr_str)
    LogEvent()
        .type(LOG_TYPE_ERROR)
        .subsys(LOG_SUBSYSTEM_TAG)
        .prio(SYSTEM_LEVEL)
        .lookup(ER_SERVER_STARTUP_ADMIN_INTERFACE, my_admin_bind_addr_str,
                mysqld_admin_port, MYSQL_COMPILATION_COMMENT);

#if defined(_WIN32)
  if (windows_service) {
    Service_status_msg s("R");
    send_service_status(s);
  }
#endif

  server_components_initialized();

  /*
    Set opt_super_readonly here because if opt_super_readonly is set
    in get_option, it will create problem while setting up event scheduler.
  */
  set_super_read_only_post_init();

  DBUG_PRINT("info", ("Block, listening for incoming connections"));

  (void)MYSQL_SET_STAGE(0, __FILE__, __LINE__);

  server_operational_state = SERVER_OPERATING;
  sysd::notify("READY=1\nSTATUS=Server is operational\nMAIN_PID=", getpid(),
               "\n");

  (void)RUN_HOOK(server_state, before_handle_connection, (nullptr));

#if defined(_WIN32)
  setup_conn_event_handler_threads();
#else
  mysql_mutex_lock(&LOCK_socket_listener_active);
  // Make it possible for the signal handler to kill the listener.
  socket_listener_active = true;
  mysql_mutex_unlock(&LOCK_socket_listener_active);

  if (opt_daemonize) {
    if (nstdout != nullptr) {
      // Show the pid on stdout if deamonizing and connected to tty
      fprintf(nstdout, "mysqld is running as pid %lu\n", current_pid);
      fclose(nstdout);
      nstdout = nullptr;
    }

    mysqld::runtime::signal_parent(pipe_write_fd, 1);
  }

  mysqld_socket_acceptor->connection_event_loop();
#endif /* _WIN32 */
  server_operational_state = SERVER_SHUTTING_DOWN;
  sysd::notify("STOPPING=1\nSTATUS=Server shutdown in progress\n");

  DBUG_PRINT("info", ("No longer listening for incoming connections"));

  mysql_audit_notify(MYSQL_AUDIT_SERVER_SHUTDOWN_SHUTDOWN,
                     MYSQL_AUDIT_SERVER_SHUTDOWN_REASON_SHUTDOWN,
                     MYSQLD_SUCCESS_EXIT);

  terminate_compress_gtid_table_thread();
  /*
    Save set of GTIDs of the last binlog into gtid_executed table
    on server shutdown.
  */
  if (opt_bin_log)
    if (gtid_state->save_gtids_of_last_binlog_into_table())
      LogErr(WARNING_LEVEL, ER_CANT_SAVE_GTIDS);

#ifndef _WIN32
  mysql_mutex_lock(&LOCK_socket_listener_active);
  // Notify the signal handler that we have stopped listening for connections.
  socket_listener_active = false;
  mysql_cond_broadcast(&COND_socket_listener_active);
  mysql_mutex_unlock(&LOCK_socket_listener_active);
#endif  // !_WIN32

#ifdef HAVE_PSI_THREAD_INTERFACE
  /*
    Disable the main thread instrumentation,
    to avoid recording events during the shutdown.
  */
  PSI_THREAD_CALL(delete_current_thread)();
#endif /* HAVE_PSI_THREAD_INTERFACE */

  DBUG_PRINT("info", ("Waiting for shutdown proceed"));
  int ret = 0;
#ifdef _WIN32
  if (shutdown_restart_thr_handle.handle)
    ret = my_thread_join(&shutdown_restart_thr_handle, NULL);
  shutdown_restart_thr_handle.handle = NULL;
  if (0 != ret)
    LogErr(WARNING_LEVEL, ER_CANT_JOIN_SHUTDOWN_THREAD, "shutdown ", ret);
#else
  if (signal_thread_id.thread != 0)
    ret = my_thread_join(&signal_thread_id, nullptr);
  signal_thread_id.thread = 0;
  if (0 != ret)
    LogErr(WARNING_LEVEL, ER_CANT_JOIN_SHUTDOWN_THREAD, "signal_", ret);
#endif  // _WIN32

  clean_up(true);
  sysd::notify("STATUS=Server shutdown complete");
  mysqld_exit(signal_hand_thr_exit_code);
}
1.4 源码函数调用链

substitute_progpath:将命令行的程序名替换成全路径的程序名,可能是“全路径”,home路径解释,环境变量PATH解释。

sysd::notify_connect:在环境变量(“NOTIFY_SOCKET“)中查找socket的文件名,如果存在的话则连接该Socket

sysd::notify:向Notify Socket发送正在启动的消息。

my_init:初始化my_sys函数,资源和变量
    my_thread_global_init:初始化线程的环境(初始化一堆资源锁)
        PSI_mutex_key 结构
    my_thread_init:申请mysys线程的内存,主要用于debug

load_defaults -> my_load_defaults:从配置文件中读取配置项
    init_default_directories:获取配置的目录
    my_search_option_files:处理在缺省目录下的配置文件,即上一步结果
        get_defaults_options:从命令行中获取配置选项;
        init_variable_default_paths:初始化配置文件的作用域(enum_variable_source)
        search_default_file:如果是绝对路径,直接读取;
        search_default_file_with_ext:从输入配置的文件中读取;
    my_default_get_login_file:从login集群中读取配置。
        my_search_option_files
    set_args_separator:分隔符

persisted_variables_cache:持久化的参数配置缓存,采用JSON进行存储,
    Init:初始化,从命令行或者是环境变量“MYSQL_DATADIR“中获取文件
        my_handle_options:主要处理参数的逻辑。
    load_persist_file:加载持久化文件的配置,并且转成JSON格式,分析出K/V结构;
    append_read_only_variables:将上一步分解出的只读配置参数追加到命令行参数中。

init_variable_default_paths:初始化配置文件的作用域(enum_variable_source)

init_pfs_instrument_array: PSI: performance schema interface; PFS:performance storage

handle_early_options:处理早期的选项,包括:performance schema;与help或者启动相关的参数
    sys_var_add_options:增加系统参数;
    增加命令行中的早期选项;
    add_terminator:增加终结。
    handle_options->my_handle_options:处理参数

init_sql_statement_names: 初始化与sql语句相关的名字(com_status_vars),包括各种dml/ddl/acl/dql等

sys_var_init:初始化系统变量(mysql-server-8.0/sql/sys_vars.cc中定义静态变量)
    mysql_add_sys_var_chain

init_error_log:初始化错误日志

adjust_related_options:调整相关的参数,
    adjust_open_files_limit
    adjust_max_connections
    adjust_table_cache_size
    adjust_table_def_size

initialize_performance_schema:初始化performance_schema
    pfs_automated_sizing:将ps相关的参数都置为0;
    init_timers:根据系统进行初始化performance_schema的计数器,并且获得当前值;可以从performance_timers表获取
        my_timer_init
        my_timer_cycles
        my_timer_nanoseconds
        my_timer_milliseconds
    初始化histograms(表的统计量)的定时器,
    init_event_name_sizing:初始化全局表I/O,表锁/元数据等的事件
    register_global_classes:初始化全局的仪表,包括类型有:表I/O,表锁,Idle类,元数据类,错误类,事物类。
    接下来是申请一堆仪表的内存
    并且从参数里头获取配置
    init_pfs_plugin_table:初始化pfs内置的table
        PFS_dynamic_table_shares::init_mutex
        init_pfs_plugin_table

LO_init:初始化Lock Order,主要用Lock Order Graph描述锁依赖关系:https://dev.mysql.com/doc/refman/8.0/en/lock-order-tool.html

//START与psi相关的服务  
设置psi相关的服务:thread_service,mutex_service,rwlock_service,cond_service,file_service,socket_service,table_service,mdl_service,idle_service,stage_service,statement_service,transaction_service,memory_service,error_service,data_lock_service,system_service

init_server_psi_keys:注册psi key的函数,包括psi服务的mutex,rwlock,conds,threads,files,stage,socket;内存的key,sql语句的信息(init_sql_statement_names中提到的),psi_api,与store procedures相关的key,与调度(scheduler)相关的(主要是evengt),与client公用的key,vio的key(与通信相关的)

my_thread_global_reinit:重新初始化一些比较开始与锁相关的,因为需要考虑一些仪表
// 与psi相关的服务 END

component_infrastructure_init
    mysql_services_bootstrap:启动服务注册,动态加载器,和基础的服务
        registry_init:创建注册服务套件,内部的结构mysql_registry
        把加载器的实现写入到服务注册表
        dynamic_loader_init:初始化动态加载器,其实就是初始化锁
        dynamic_loader_scheme_file_init:初始化scheme文件
    pfs_init_services: ps是performance storage

register_pfs_notification_service

register_pfs_resource_group_service

Resource_group_mgr::init:初始化资源组管理器,
    与资源相关的服务,包括: registry service,mysql_service_pfs_resource_group_v3_t,mysql_service_pfs_notification_v3_t
    注册线程创建/断开连接的回调
    创建用户级/系统级的资源组对象

调用psi_thread_service相关函数:new_thread,set_thread_os_id,set_thread

mysql_audit_initialize:初始化与audit相关的变量;

Srv_session::module_init:初始化srv_session模块

query_logger.init:查询日志初始化

init_common_variables:
    init_thread_environment:初始化与线程相关的锁;
    mysql_init_variables:初始化全局变量为缺省值
    mysql_bin_log.set_psi_keys完成bin log的初始化,让仪表相关的对bin log可见
    mysql_bin_log.init_pthread_objects:初始化bin log与线程相关的锁
    get_options,剩余的可选项,binlog,压缩算法,页的大小,线程缓存大小,back_log
        Connection_handler_manager::init,初始化连接池
            Per_thread_connection_handler::init,初始化Per_thread_connection_handler,初始化锁
    初始化mysql client的plugin
    选字符集/collation
    日志配置
    创建数据目录
    表的大小写等

my_init_signals:初始化信号处理

线程栈大小检查

Migrate_keyring::init:初始化Migrate_keyring(一种mysql数据搬运模式)相关的,如压缩方式,并且连接到数据源主机
Migrate_keyring::execute
    fetch_and_store_keys
// 如果启动方式为Migrate_keyring,则数据搬完后退出

set_ports:确定tcp端口

init_server_components
    mdl_init:metadata locking subsystem元数据锁子系统,
    MDL_map::init, MDL_key,一个重要的数据结构:元数据锁
    partitioning_init
    table_def_init:表定义缓存(Table_definition_cache)
        Table_cache_manager::init:表缓存初始化
            Table_cache::init
    hostname_cache_init:初始化(client)主机名缓存,Host_entry
    my_timer_initialize:初始化内部组建,fd,
        start_helper_thread:时间通知线程,timer_notify_thread_func
    init_slave_list:初始化从机列表
    transaction_cache_init:初始化事务缓存的psi键
    MDL_context_backup_manager::init,MDL_context_backup_manager
    :维护XA事务中元数据锁
    delegates_init:初始化外部observer的委托,包括事务,bin log,服务状态,bin log传输,relay IO
    与bin/relay log相关的初始化
    process_key_caches:用ha_init_key_cache函数初始化所有的key缓存
    ha_init_errors:初始化错误信息
    gtid_server_init:GTID server初始化
    udf_init_globals:初始化udf结构体
    init_ssl:配置SSL包
        ssl_start:
            SSL_library_init
            OpenSSL_add_all_algorithms
            init_ssl_locks:初始化ssl锁,
            init_lock_callback_functions:锁回调函数
    plugin_register_early_plugins
        plugin_init_internals:初始化内部plugin,资源/锁
        plugin_load_list
            plugin_dl_add
            plugin_add
            plugin_init_initialize_and_reap:重试失败的plugin
    plugin_register_builtin_and_init_core_se,初始化内置plugin,包含MyIsam,CSV,InnoDB
    init_sql_command_flags:初始化sql命令flag
    dd::init:
        cache::Shared_dictionary_cache::init,包括字符/collation,抽象表,事件,routine,schema,column,tablespace,资源组等字典初始化
        System_tables::instance()->add_inert_dd_tables()
        System_views::instance()->init() 系统视图,主要是information_schema下的
        Dictionary_impl::init
    plugin_register_dynamic_and_init_all,注册动态的plugin和初始化所有的plugin
    确定线程池组织方式:SCHEDULER_ONE_THREAD_PER_CONNECTION/SCHEDULER_NO_THREADS
    从5.7升级到8.0相关的处理
    dd::performance_schema::init_pfs_tables:处理好pfs相关的表
    upgrade_system_schemas:升级系统库表
    Resource_group_mgr::post_init从磁盘读取资源组数据
    handle_options:处理剩余的参数可选项
    ha_init:初始化
    query_logger相关的处理
    initialize_storage_engine:初始化缺省(或临时)的存储引擎
    Recovered_xa_transactions::init:恢复XA事务初始化
    Recovered_xa_transactions::recover_prepared_xa_transactions恢复预处理的XA事务
    init_server_auto_options:初始化服务自动项,
    MYSQL_BIN_LOG::open_binlog,打开一个bin log文件,分析主备bin log,也会purge一些日志
    init_optimizer_cost_module:初始化优化器(应该是物理优化器)代价的模块
        init_cache_tmp_engine_properties
            Cache_temp_engine_properties::init,临时的引擎特性,HEAP/TempTable/INNODB
    ft_init_stopwords:停用词
    init_max_user_conn:client连接

Gtid_state::init,将server_uuid放至sid_map中

MYSQL_BIN_LOG::init_gtid_sets,从gtid_executed表和binlog文件中初始化GLOBAL.GTID_EXECUTED 和 GLOBAL.GTID_PURGED 的值,分别应该是已经执行的GTID和回收的GTID

init_ssl_communication:
    set_fips_mode:设置openssl包的fips
    SslAcceptorContext::singleton_init,初始化ssl接收器
        do_auto_cert_generation,生成证书
    init_rsa_keys,从磁盘中加载RSA键值对,sha256

network_init,初始化服务的listener,三种,Mysqld_socket_listener/Named_pipe_listener/Shared_mem_listener,后两者仅在windows下会启动
    Connection_acceptor::init_connection_acceptor
        Mysqld_socket_listener::setup_listener,如果是Mysqld_socket_listener,并且需要开通管理员socket
            spawn_admin_thread,启动admin的listener线程。
                admin_socket_thread
                    handle_admin_socket,开始监听管理请求

create_pid_file,创建pid文件

reload_optimizer_cost_constants,重新加载优化器的计算成本常量
    Cost_constant_cache::reload

mysql_component_infrastructure_init,通过初始化动态加载器来初始化mysql服务组建
    persistent_dynamic_loader_init,恢复持久化文件中的数据
        mysql_persistent_dynamic_loader_imp::init
            open_component_table
            读取组件table中的数据
            mysql_dynamic_loader_imp::load
                dd::sdi_file::load
    trans_rollback_stmt:回滚单语句的事务
        ha_rollback_trans
    trans_rollback:回滚当前的事务
    server_component_init,除第一个函数外,其他均为dummy空函数,
        mysql_comp_sys_var_services_init
        mysql_string_services_init();
        mysql_comp_status_var_services_init();
        mysql_comp_system_variable_source_init();
        mysql_backup_lock_service_init();
        clone_protocol_service_init();
        page_track_service_init();
        mysql_security_context_init();
        mysql_server_ongoing_transactions_query_init();
        host_application_signal_imp_init();
        mysql_audit_api_service_init();
        mysql_current_thread_reader_imp_init();
        mysql_keyring_iterator_service_init();
        mysql_comp_udf_extension_init();
        mysql_connection_attributes_iterator_imp_init();
    trans_commit_stmt,提交语句事务
    trans_commit,提交当前事务

mysql_rm_tmp_tables,删除之前服务遗留的临时文件

acl_init
    init_acl_cache
    check_engine_type_for_acl_table,
    check_acl_tables_intact
    notify_flush_event

init_acl_memory,出事acl的内存

my_tz_init:初始化时区
    open_trans_system_tables_for_read
        open_tables
            open_tables_check_upgradable_mdl
                find_table_for_mdl_upgrade
            lock_table_names
        lock_tables
            mysql_lock_tables
                lock_tables_check
                get_lock_data:获得表的锁结构
            check_lock_and_start_stmt
    闰秒相关的初始化逻辑

grant_init:
    grant_reload:加载授权
        open_and_lock_tables
        grant_load:从授权表中加载表/列的权限检查信息
        grant_reload_procs_priv:从procs_priv表中读取权限信息
        commit_and_close_mysql_tables:

dynamic_privilege_init:
    mysql_plugin_registry_acquire
    初始化管理相关的权限

servers_init:从mysql库中初始化结构数据
    servers_reload:初始化mysql.servers表的数据

udf_read_functions_table:从mysql.func中加载数据

init_status_vars:

init_slave:初始化slave线程,并开启
    Rpl_info_factory::create_slave_info_objects
    start_slave_threads,对多个channel开启
        start_slave_thread::handle_slave_sql处理relay日志

initialize_performance_schema_acl
    ACL_internal_schema_registry::register_schema

Events::init:初始化event结构
    load_events_from_db
    Event_scheduler::start
        pre_init_event_thread
        event_scheduler_thread

start_signal_handler,启动单独的线程signal_hand来处理信号,如SIGTERM, SIGQUIT, SIGHUP, SIGUSR1 and SIGUSR2  

process_bootstrap:
    server_components_initialized
    run_bootstrap_thread:启动单独处理init_file 中的sql语句
        handle_bootstrap
            handle_bootstrap_impl
                process_iterator
    dd::init

mysql_audit_notify:
    mysql_audit_acquire_plugins,获取plugins
    event_class_dispatch
        plugins_dispatch,通过调用plugin的event_notify函数分发时间

start_handle_manager,开启handler管理线程
    handle_manager,线程函数,监听COND_manager信号等

create_compress_gtid_table_thread,开启一个线程调用以下函数
    compress_gtid_table,根据压缩COND_compress_gtid_table信号对gtid_executed表进行压缩
        Gtid_state::compress
            Gtid_table_persistor::compress,更多详细的逻辑在mysql-server-8.0/sql/rpl_gtid_persist.cc中

Connection_acceptor::connection_event_loop:开启监听服务。 window会进入setup_conn_event_handler_threads函数,并启动三个单独线程处理不同的连接方式,即Mysqld_socket_listener/Named_pipe_listener/Shared_mem_listener

// 以下为结束阶段的代码
待收到结束信号后,
terminate_compress_gtid_table_thread,终止compress_gtid_table_thread

save_gtids_of_last_binlog_into_table,保存gtid的最新值到表中

发送信号给监听线程

close_connections:关闭连接,SIGQUIT信号
    Per_thread_connection_handler::kill_blocked_pthreads
    Mysqld_socket_listener/Shared_mem_listener/Named_pipe_listener::close_listener
        mysql_socket_shutdown
        mysql_socket_close
            Connection_acceptor::close_listener
    Events::stop,停止Event调度器
    Set_kill_conn,对连接设置KILL_CONNECTION flag
    Events::deinit,清理调度器的资源,
    关闭所有连接,Call_close_conn::close_connection
    Connection_handler_manager::wait_till_no_connection,等待所有连接结束
    delete_slave_info_objects,释放slave线程占用的资源

终止仪表线程


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值