移动云海山数据库(He3DB)-服务端启动流程&客户端连接认证

服务端启动流程

int mysqld_main(int argc, char **argv)
#执行基本线程库和malloc初始化,以便能够读取默认文件和解析选项。
|--> my_progname= argv[0];  //程序名称
|--> pre_initialize_performance_schema();  //在mysql5.5版本之后新增了performance_schema的数据库用于监视数据库性能,只有表结构文件不存在数据文件,不会记录到binlog中
|--> if (my_init())  //Initialize my_sys functions, resources and variables
|--> if (load_defaults(MYSQL_CONFIG_NAME, load_default_groups, &argc, &argv))  //从配置文件中读取选项
|--> init_pfs_instrument_array();  //Initialize the array of performance schema instrument configurations
|--> ho_error= handle_early_options();  //初始化一些需要尽早解析的选项(如与帮助有关的选项、与引导程序相关的选项)
|--> init_sql_statement_names()  //将enum_sql_command的命令(SQLCOM_SELECT等)存储到sql_statement_names[]里,映射是在com_status_vars[]中(select等)
|--> sys_var_init();  //  初始化系统变量
	|--> if (mysql_add_sys_var_chain(all_sys_vars.first))  //把all_sys_vars的内容插入哈希表
|--> adjust_related_options(&requested_open_files);  //调整相关参数
	|--> adjust_open_files_limit(requested_open_files);  //通过算式调整允许使用的最大文件描述符数量open_files_limit
	|--> adjust_max_connections(*requested_open_files);  //通过算式调整最大连接数
	|--> adjust_table_cache_size(*requested_open_files);  //通过算式调整内存中可打开表的数量table_cache_size,每个实例可打开表的数量table_cache_size_per_instance
	|--> adjust_table_def_size();  //通过计算调整表定义信息缓存table_definition_cache的大小
|--> {  //初始化performance_schema,记录运行过程中的性能、资源、wait事件等信息,包括前面调整的参数也设置到里面。
    	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;
		PSI_hook= initialize_performance_schema(&pfs_param);
	 }
|--> #ifdef HAVE_PSI_INTERFACE	//性能模式监测接口
    	|--> set_psi_server(psi_server);  //设置性能模式的PSI_server
		|--> init_server_psi_keys();  //初始化服务器使用的所有性能模式检测点。
		|--> PSI_thread *psi= PSI_THREAD_CALL(new_thread)(key_thread_main, NULL, 0);
		|--> PSI_THREAD_CALL(set_thread_os_id)(psi);
		|--> PSI_THREAD_CALL(set_thread)(psi);  //启动性能检测接口线程,开始监控main线程
		|--> my_thread_global_reinit();  //重新初始化早期初始化的组件,对于某些互斥对象销毁再次创建
|--> init_error_log();   //初始化error log
|--> mysql_audit_initialize();  //初始化审计接口,mysql的审计功能主要用于收集,监控和审计涉及MySQL实例的活动(5.5新增audit plugin插件对mysql的操作进行审计)
|--> Srv_session::module_init();  //Srv_session 模块初始化,Srv_session聚合THD, 供内部API使用
|--> query_logger.init();  //执行基本查询日志初始化,general_log & slow_log。应该在MY_INIT之后调用,因为它初始化互斥对象
|--> if (init_common_variables())  //初始化很多内部系统变量,代码500多行,初始化 timezone & replfilter & binlogfilter & global mysqlbinlog 对象的mutex ,初始化default storage engine等等  
|--> my_init_signals();  //初始化信号处理系统,mysql的信号量可以帮助mysql管理系统资源,主要应用场景为并发控制、内存管理、文件系统、网络连接
|--> my_thread_attr_setstacksize(&connection_attrib,
                            my_thread_stack_size + guardize);  //设置有关线程启动所需的最小栈大小,不得小于PTHRAD_STACK_MIN,也不得超过系统限制
|--> test_lc_time_sz();  //调试helper函数以保持locale database以及max_month_name_length和max_day_name_lengh变量值处于一致状态。
|--> if ((user_info= check_user(mysqld_user)))  //检测启动时的用户选项
|--> set_user(mysqld_user, user_info);  //设置以该用户运行
|--> if (my_setwd(mysql_real_data_home,MYF(MY_WME)) && !opt_help)  //设置数据库数据目录
|--> if (opt_bin_log && !(server_id_supplied) )  //bin_log 选项检查,如果启用binlog就必须要提供server-id
|--> if (init_server_components())  //init_server_components()代码500多行,初始化很多模块,包括Gtid、Innodb等
    	|--> if (gtid_server_init())  //初始化Gtid
		|--> if (ha_init())  //初始化存储引擎
|--> if (init_server_auto_options())  //设置server-uuid,去auto.cnf里找,如果不存在, 将自动创建。
|--> int gtid_ret= gtid_state->init();  //将server_uuid对应的sid(uuid)和sidno(server_uuid的内部表示)加入到sid_map中。
|--> if (gtid_state->read_gtid_executed_from_table() == -1)  //从mysql.gtid_executed表初始化executed_gtids
    	|--> int Gtid_state::read_gtid_executed_from_table()
			{
  				return gtid_table_persistor->fetch_gtids(&executed_gtids);
			}
			|--> int Gtid_table_persistor::fetch_gtids(Gtid_set *gtid_set)
                |--> if (gtid_set->add_gtid_text(encode_gtid_text(table).c_str()) !=RETURN_STATUS_OK)  //将读取到的一行Gtid区间加入到Gtid_state.executed_gtids中
|--> if (opt_bin_log)  //130行代码,如果开启binlog(my.cnf里设置log-bin=mysql-bin),则从GTID_EXECUTED表和binlog文件初始化GLOBAL.GTID_EXECUTED和GLOBAL.GSID_PURGED。
|--> if (init_ssl())  //初始化ssl
|--> if (network_init())  //初始化网络模块
    |--> set_ports();  //Init IP and UNIX socket,设置ports
	|--> Mysqld_socket_listener()  //监听通过socket连接到mysql的connection
    |--> init_connection_acceptor()  //connection_acceptor管理不同类型的listener
        |--> setup_listener()  //初始化listener,初始化listener mysocket port,将tcp_socket信息插入my_socket_map
|--> my_str_malloc= &my_str_malloc_mysqld;
	my_str_free= &my_str_free_mysqld;
	my_str_realloc= &my_str_realloc_mysqld;  //初始化内存管理相关的函数
|--> create_pid_file();  //创建pid文件(mysql_file_create), 并将pid(getpid())写入文件(mysql_file_write), 然后关闭文件(mysql_file_close)
|--> reload_optimizer_cost_constants();  //加载优化器成本配置表, mysql.server_cost 和 mysql.engine_cost
|--> if (mysql_rm_tmp_tables() || acl_init(opt_noacl) ||
      my_tz_init((THD *)0, default_tz_name, opt_bootstrap) ||
      grant_init(opt_noacl))  //删除临时表、初始化用户db级别权限(user/db) 、初始化时区、初始化表行级别权限(table/column)
|--> servers_init(0);  //Initialize structures responsible for servers used in federated server scheme information for them from the server table in the 'mysql' database.init the mutex,initialise our servers cache,Initialize the mem root for data
|--> udf_init();  //从mysql.func中读取所有预先声明的函数,并接收所有可以使用的函数。
|--> init_status_vars();  //初始化服务器状态
|--> check_binlog_cache_size(NULL);  //检查BINLOG_CACHE_SIZE是不是比MAX_BINLOG_CACHE_SIZE大, 是的话, 就取MAX_BINLOG_CACHE_SIZE的值 
|--> check_binlog_stmt_cache_size(NULL);  //检查 BINLOG_STMT_CACHE_SIZE是不是比MAX_BINLOG_STMT_CACHE_SIZE大
|--> binlog_unsafe_map_init();  //定义binlog异常
|--> set_slave_skip_errors(&opt_slave_skip_errors);  //Change arg to the string with the nice, human-readable skip error value,在my.cnf里面设置slave-skip-errors=xxx
|--> init_slave();  // 如果server_id != 0,初始化从库信息
|--> initialize_performance_schema_acl(opt_bootstrap);  //初始化performance_schema库的权限
|--> check_performance_schema();  //检查performance schema tables是否具有预期的结构
|--> initialize_information_schema_acl();  //初始化information_schema库的权限
|--> execute_ddl_log_recovery();  //执行内部DDL日志恢复(ddl日志为数据定义语句日志,记录数据定义语句执行的元数据操作,例如DROP TABLE、ALTER TABLE)*********mysql8.0引入原子DDL新特性
|--> start_signal_handler();  //启动信号处理线程
|--> if (opt_bootstrap)
  	{
    	start_processing_signals();  //处理启动过程中的信号量信息
	}
|--> if (opt_init_file && *opt_init_file)
  	{
    	if (read_init_file(opt_init_file))  //通过线程读取opt_init_file文件配置
      	unireg_abort(MYSQLD_ABORT_EXIT);
  	}
|--> if (mysql_audit_notify(AUDIT_EVENT(MYSQL_AUDIT_SERVER_STARTUP_STARTUP),
                         (const char **) argv, argc))  //在将error_handler_hook分配给my_message_sql之后,必须调用事件,否则my_message不会导致事件中止
|--> start_handle_manager();  //启动handle manager线程
|--> create_compress_gtid_table_thread();  //创建压缩gtid的线程
|--> start_processing_signals();  //处理启动过程中的信号量信息
|--> set_super_read_only_post_init();  //初始化super_read_only的值
|--> server_operational_state= SERVER_OPERATING;  //设置服务器状态 server_operational_state=SERVER_OPERATING,默认是SERVER_BOOTING,关闭的时候是SERVER_SHUTTING_DOWN
|--> mysql_mutex_lock(&LOCK_socket_listener_active);  //给表加互斥锁
|--> socket_listener_active= true;  //设置mysql监听状态为true
|--> mysql_mutex_unlock(&LOCK_socket_listener_active);  //解锁
|--> mysqld_socket_acceptor->connection_event_loop();  //循环处理客户端连接
	|--> void connection_event_loop()
  		{
    		Connection_handler_manager *mgr= Connection_handler_manager::get_instance();  //以Singleton方法返回此类的实例
        	while (!abort_loop)
    		{
      			Channel_info *channel_info= m_listener->listen_for_connection_event();  //根据不同的监听模式,去监听新请求, 当获取到⼀个新的监听请求时,会创建⼀个Channel_info类,⽤来存储⽤⼾的socket信息
                
                //启动到此结束,输入连接mysql客户端的命令:mysql -uroot -p 运行下面的代码
      			if (channel_info != NULL)
        			mgr->process_new_connection(channel_info);
                	
    		}
 		 }
     

    	

客户端连接认证

#接上mysqld启动后,输入连接mysql客户端的命令:mysql -uroot -p
|--> void Connection_handler_manager::process_new_connection(Channel_info* channel_info)
	|--> check_and_incr_conn_count()  //检查是否有空余连接(当前连接数是否大于 max_connections), 如果没有空余连接, 结束处理流程,这里允许 max_connections + 1 个连接,最后一个连接是为 super user保留的。
	|--> add_connection(channel_info)  //添加连接    
bool Per_thread_connection_handler::add_connection(Channel_info* channel_info)
{
  if (!check_idle_thread_and_enqueue_connection(channel_info))
    DBUG_RETURN(false);  //判断是否有空闲的thread cache,如果有的话通过waiting_channel_info_list->push_back(channel_info),将channel_info加⼊到队列

    //没有可用的空闲线程来占用新连接。创建一个新线程来处理连接
  channel_info->set_prior_thr_create_utime();  //设置线程创建的时间(微秒)
  error= mysql_thread_create(key_thread_one_connection, &id,
                             &connection_attrib,
                             handle_connection,
                             (void*) channel_info);
extern "C" void *handle_connection(void *arg)  //线程处理函数
|--> if (my_thread_init())  //线程初始化,为线程分配特定于线程的内存,由mysys和dbug使用,如果失败则删除该连接
|-->for(;;) {
	|--> init_new_thd() //初始化thd对象
    |--> if (pthread_reused)  //Reusing existing pthread: Create new instrumentation for the new THD job, and attach it to this running pthread.如果pthread_reused可用,则创建psi对象
	|--> mysql_thread_set_psi_THD(thd)//创建或重⽤psi对象,并加到thd对象
    |--> add_thd(thd) //将thd对象加入到thd list,并判断是否在list中已存在该thd()
	|--> if (thd_prepare_connection(thd)) //权限验证
        |--> lex_start  //在准备和执行每个查询之前调用lex_start(),创建select_lex和select_lex_unit对象
		|--> login_connection() //⽤⼾认证
			|--> check_connection() //执行握手、授权客户端并更新thd ACL变量
				|--> acl_check_host //检查host或IP是否能匹配,检查两个对象,一个是hash表acl_check_hosts(存放具体主机),另一个是acl_wild_hosts(存放有通配符的主机)
				|--> vio_keepalive(net->vio, TRUE) //设置keepalive,VIO对象主要用于网络通信Socket中的数据结构的封装,是底层的网络I/O socket描述符
        		|--> acl_authenticate(thd, COM_CONNECT) //密码认证
					|--> do_auth_once
						|--> native_password_authenticate //在mysql_native_password中
							|--> generate_user_salt// 服务端⽣成salt值
							|--> write_packet //向客⼾端发送handshake包
								|-->send_server_handshake_packet
							|--> read_packet // 客户端发送登录认证信息报文到服务端,服务端接收并解析报文
								|--> server_mpvio_read_packet
									|--> parse_client_handshake_packet // 报⽂解析
							|--> check_scramble // 检查加扰消息是否与密码对应;服务器使用该功能来检查接收到的回复是否真实。
								|-->check_scramble_sha1 // 涉及数据异或操作
					|--> acl_log_connect //记录认证⽇志
			|--> send_statement_status //认证成功返回ok包
		|--> prepare_new_connection_state(thd) //准备处理⽤⼾请求
	else{
        while{
            |--> do_command(thd) //循环接受⽤⼾请求并处理
        }
		|--> end_connection(thd)//关闭已建⽴的连接        
    }        
	|--> close_connection //关闭当前会话的vio,退出当前⽤⼾,db的限制,acl等上下⽂
	|--> release_resources // 资源释放
	|--> Per_thread_connection_handler::block_until_new_connection()//阻塞等待连接复⽤
|--> }// end for
  • 10
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值