目录
3,处理新连接(process_new_connection)
0. 背景
参加公司早读会分享-MySQL源码学习,本次分享打算从最初始的代码开始,一起看一下MySQL初始化、连接与线程管理和THD相关类的一些梳理。
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