一起学习MySQL源码笔记之偷窥线程

安装完Mysql后,使用VS打开源码开开眼,我嘞个去,这代码和想象中怎么差别这么大呢?感觉代码有些凌乱,注释代码都写的比较随意,好像没有什么统一的规范,不同的文件中代码风格也有差异,可能Mysql经过了很多牛人的手之后,集众牛人之长吧。也可能是我见识比较浅薄,适应了自己的代码风格,井底之蛙了,总之还是怀着敬畏的心情开始咱的源码之旅吧。本人菜鸟,大神轻拍。

Mysql可以启动起来了,应该怎么学习呢?总不能从main开始一步一步的看吧,Mysql作为比较底层的大型软件,涉及到数据库实现的方方面面,没有厚实的数据库理论基础和对Mysql各个模块相当的熟悉,从main开始势必会把自己引入某个死胡同啊,什么都看,最后啥也不会,咱伤不起。

经过思考后,我想还是通过客户端来调试服务器,从而学习服务器代码比较现实。也就是通过客户端的动作,看服务器的反应。比如从客户端的登录动作来看SERVER如何进行通信、用户识别、鉴定以及任务分配的,通过CREATE TABLE,来看SERVER如何解析DDL语句以及针对不同的存储引擎采取的不同的物理存储方式,通过INSERT语句,来看SERVER如何进行Btree的操作。通过SELECT语句来看如何进行SQL语句语法树的创建和优化的,通过ROLL BACK,来看SERVER事务是如何实现的。这里主要是通过跟踪代码学习Mysql数据库实现的思想,对于具体的代码不去做过多的追究(主要是我对C++不是很熟悉),好读书,不求甚解,呵呵。

由此,暂时准备了以下几条SQL语句,来有针对的进行SERVER的分析

  1. 1、LOGIN(登录)   
  2. mysql.exe –uroot –p  
  3. 2、DDL(建表语句)  
  4. create table tb_myisam(c1 int, c2 varchar(256)) engine = myisam;  
  5. create table tb_innodb(c1 int, c2 varchar(256)) engine = innodb;  
  6. 3、INSERT 
  7. Insert into tb_myisam values(1 , ’寂寞的肥肉’);  
  8. Insert into tb_innodb values(1 , ’寂寞的肥肉’);  
  9. 4、SELECT 
  10. Select c1 from tb_myisam;  
  11. Select * from tb_innodb;  
  12. 5、ROLLBACK 

大家都知道,mysql可以通过多个客户端,进行并发操作,当然也包括登录了。在别人登录的时候,其他的用户可能正在进行一些其它的操作,因此对于登录我们猜测应该有专门的线程负责客户端和服务器的连接的创建,以保证登录的及时性,对于每个连接的用户,应该用一个独立的线程进行任务的执行。

首先介绍下mysql中创建线程的函数,创建线程的函数貌似就是_begin_thread,CreateThread,我们通过VS在整个解决方案中进行查找,bingo!在my_winthread.c中找到了调用_begin_thread的函数pthread_create,在os0thread.c中找到了调用CreateThread的函数os_thread_create,一个系统怎么封装两个系统函数呢??再仔细看下,发现my_winthread.c是在项目mysys下,而os0thread.c是在项目innobase下。innobase!!这不就是innodb的插件式存储引擎么,原来这是存储引擎自己的封装的底层函数,哥心中豁然开朗了。我想Mysql应用范围如此之广,除了开源之外,插件式的存储引擎功不可没啊,用户可以根据自己的实际应用采取不同的存储引擎,对于大公司,估计会开发自己的存储引擎。

下面分析下pthread_create是如何调用_begin_thread的,先粗略看下源码。

  1. int pthread_create(pthread_t *thread_id, pthread_attr_t *attr,  
  2.    pthread_handler func, void *param)  
  3. {  
  4.   HANDLE hThread;  
  5.   struct pthread_map *map;  
  6.   DBUG_ENTER("pthread_create");  
  7.   if (!(map=malloc(sizeof(*map))))  
  8.     DBUG_RETURN(-1);  
  9.   map->func=func;  
  10.   map->param=param;  
  11.   pthread_mutex_lock(&THR_LOCK_thread);  
  12. #ifdef __BORLANDC__  
  13.   hThread=(HANDLE)_beginthread((void(_USERENTRY *)(void *)) pthread_start,  
  14.                    attr->dwStackSize ? attr->dwStackSize :  
  15.                    65535, (void*) map);  
  16. #else 
  17.   hThread=(HANDLE)_beginthread((void( __cdecl *)(void *)) pthread_start,  
  18.                    attr->dwStackSize ? attr->dwStackSize :  
  19.                    65535, (void*) map);  
  20. #endif  
  21.   DBUG_PRINT("info", ("hThread=%lu",(long) hThread));  
  22.   *thread_id=map->pthreadself=hThread;  
  23.   pthread_mutex_unlock(&THR_LOCK_thread);  
  24.   if (hThread == (HANDLE) -1)  
  25.   {  
  26.     int error=errno;  
  27.     DBUG_PRINT("error",  
  28.            ("Can't create thread to handle request (error %d)",error));  
  29.     DBUG_RETURN(error ? error : -1);  
  30.   }  
  31.   VOID(SetThreadPriority(hThread, attr->priority)) ;  
  32.   DBUG_RETURN(0);  
  33. }  

关键的代码是下面三句:

  1. map->func=func;  
  2. map->param=param;  
  3. _beginthread((void( __cdecl *)(void *)) pthread_start,  
  4.                    attr->dwStackSize ? attr->dwStackSize :  
  5.                    65535, (void*) map);  

从这可以看出,创建的新线程的名字是个固定的函数——pthread_start,而我们传进来的想创建的函数func是挂载在了map上了,函数的参数同样的挂载在map上了,这样我们就可以推理出在pthread_start函数中,肯定会出现这样的代码:

  1. map->func(map->param); 

mysql没有选择直接_beginthread(func, stack_size, param)的形式,而是进行了一次封装,不知道这样的好处是什么,可能牛人的思想不是我这样小菜鸟能顿悟的,跑题了~~

至此,我们只在pthread_create函数上设置断点,调试启动mysqld,断点停下来,看下系统的线程状况:

我们第一次进入pthread_create,任何线程都没开始创建呢,按理说系统线程应该就只有一个主线程,可现在多了这么多,这些应该是innodb存储引擎创建的线程了(具体是在plugin_init)。根据线程的名称,结合注释,猜测了下这些线程的作用。

 Io_handler_thread:从名称可以知道这些是I/O线程,负责进行磁盘I/O。

   Svr_error_monitor_thread:应该是服务器出错监控线程。

   Svr_lock_timeout_thread:应该是和上锁相关的线程。

   Svr_master_thread:

/*************************************************************************

The master thread controlling the server. */

   服务器控制线程,应该是具体进行作业的线程。

   Svr_monitor_thread:

/*************************************************************************

A thread prints the info output by various InnoDB monitors. */

   监控线程,负责打印信息。

淡然飘过吧,不去细究了,我们只关心pthread_create创建的线程。根据调试,发现多了几个线程同名的线程_threadstart,如下所示:

调试时看堆栈可以知道这三个线程的创建者和作用,如下所示

创建者处理函数
create_shutdown_threadhandle_shutdown
start_handle_manager handle_manager
handle_connections_methods handle_connections_sockets

创建者:调用pthread_create进行创建线程的函数。

处理函数:调用pthread_create所创建的线程的具体的线程函数。

由名称我们就可以看出,handle_connections_sockets应该是处理连接的线程了,从顺序上看,也应该是这样,只有系统中所有的其他必须的线程创建完毕后,才能创建监听线程(连接线程),即监听线程应该是系统最后创建的。

找到了我们LOGIN需要的线程了,下次针对这个线程,分析下如何进行登录的,以及登录后为用户分配哪些资源。时间不早啦,洗洗睡了

原文链接:http://www.cnblogs.com/nocode/archive/2011/04/21/2024330.html

【编辑推荐】

  1. 这些事项你注意了吗? 浅谈数据库优化注意事项
  2. 手把手教你实现MySQL双机数据同步
  3. MySQL VS SQL Server之用法差别
  4. 微博 请问你是怎么优化数据库的?

文章来源网络,作者:运维,如若转载,请注明出处:https://shuyeidc.com/wp/230775.html<

(0)
运维的头像运维
上一篇2025-04-19 09:39
下一篇 2025-04-19 09:40

相关推荐

  • 个人主题怎么制作?

    制作个人主题是一个将个人风格、兴趣或专业领域转化为视觉化或结构化内容的过程,无论是用于个人博客、作品集、社交媒体账号还是品牌形象,核心都是围绕“个人特色”展开,以下从定位、内容规划、视觉设计、技术实现四个维度,详细拆解制作个人主题的完整流程,明确主题定位:找到个人特色的核心主题定位是所有工作的起点,需要先回答……

    2025-11-20
    0
  • 社群营销管理关键是什么?

    社群营销的核心在于通过建立有温度、有价值、有归属感的社群,实现用户留存、转化和品牌传播,其管理需贯穿“目标定位-内容运营-用户互动-数据驱动-风险控制”全流程,以下从五个维度展开详细说明:明确社群定位与目标社群管理的首要任务是精准定位,需明确社群的核心价值(如行业交流、产品使用指导、兴趣分享等)、目标用户画像……

    2025-11-20
    0
  • 香港公司网站备案需要什么材料?

    香港公司进行网站备案是一个涉及多部门协调、流程相对严谨的过程,尤其需兼顾中国内地与香港两地的监管要求,由于香港公司注册地与中国内地不同,其网站若主要服务内地用户或使用内地服务器,需根据服务器位置、网站内容性质等,选择对应的备案路径(如工信部ICP备案或公安备案),以下从备案主体资格、流程步骤、材料准备、注意事项……

    2025-11-20
    0
  • 如何企业上云推广

    企业上云已成为数字化转型的核心战略,但推广过程中需结合行业特性、企业痛点与市场需求,构建系统性、多维度的推广体系,以下从市场定位、策略设计、执行落地及效果优化四个维度,详细拆解企业上云推广的实践路径,精准定位:明确目标企业与核心价值企业上云并非“一刀切”的方案,需先锁定目标客户群体,提炼差异化价值主张,客户分层……

    2025-11-20
    0
  • PS设计搜索框的实用技巧有哪些?

    在PS中设计一个美观且功能性的搜索框需要结合创意构思、视觉设计和用户体验考量,以下从设计思路、制作步骤、细节优化及交互预览等方面详细说明,帮助打造符合需求的搜索框,设计前的规划明确使用场景:根据网站或APP的整体风格确定搜索框的调性,例如极简风适合细线条和纯色,科技感适合渐变和发光效果,电商类则可能需要突出搜索……

    2025-11-20
    0

发表回复

您的邮箱地址不会被公开。必填项已用 * 标注