MySQL源码分析-启动初始化&连接与线程管理

目录

0. 背景

1. MySQL初始化

1.1 初始化的内容

1.2 MySQL启动初始化-终止流程图

1.3 全量源码

1.4 源码函数调用链详细分析

2,连接与线程管理

2.1 MySQL中的线程

2.2 类关系解读

2.3  主要连接处理流程分析

整体流程

精简流程-源码分析

1, 监听处理框架

2,Mysqld_socket_listener

3,处理新连接(process_new_connection)

3,THD与类/结构的依赖

3.1 父类/接口类

3.2 锁相关的

3.3 接口语法语义相关

3.4 日志/复制相关

3.5 处理过程中上下文

3.6 事务相关

3.7 执行过程中的数据

3.8 诊断优化相关

3.9 其他


0. 背景

参加公司早读会分享-MySQL源码学习,本次分享打算从最初始的代码开始,一起看一下MySQL初始化、连接与线程管理和THD相关类的一些梳理。

MySQL源码阅读1-启动初始化

1. MySQL初始化

源码学习个人习惯从最开始的各种准备初始化展开深入,mysql也一样,我们从mysql的启动初始化一直到终止阶段分析逻辑。以下是mysql初始化的简单小结,详细的源码栈在后续接着分析。

1.1 初始化的内容

  • 参数配置解析:
    • 分别从/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中的线程

1.2 MySQL启动初始化-终止流程图

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;
  }
  ......
  heo_error = handle_early_options();

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

  ......
  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);

  ......

  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 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();
  ......
  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_co
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值