Mysql能够启动起来了,应该怎么学习呢?总不能从main开始一步一步的 看吧,Mysql做为比较底层的大型软件,涉及到数据库实现的方方面面,没有厚实的数据库理论基础和对Mysql各个模块至关的熟悉,从main开始势必 会把本身引入某个死胡同啊,什么都看,最后啥也不会,咱伤不起。 mysql
通过思考后,我想仍是经过客户端来调试服务器,从而学习服务器代码比较现实。 也就是经过客户端的动做,看服务器的反应。好比从客户端的登陆动做来看SERVER如何进行通讯、用户识别、鉴定以及任务分配的,经过CREATE TABLE,来看SERVER如何解析DDL语句以及针对不一样的存储引擎采起的不一样的物理存储方式,经过INSERT语句,来看SERVER如何进行 Btree的操做。经过SELECT语句来看如何进行SQL语句语法树的建立和优化的,经过ROLL BACK,来看SERVER事务是如何实现的。这里主要是经过跟踪代码学习Mysql数据库实现的思想,对于具体的代码不去作过多的追究(主要是我对 C++不是很熟悉),好读书,不求甚解,呵呵。 sql
由此,暂时准备了如下几条SQL语句,来有针对的进行SERVER的分析 数据库
你们都知道,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的,先粗略看下源码。 socket
if (!(map=malloc(sizeof(*map))))
DBUG_RETURN(-1);
map->func=func;
map->param=param;
pthread_mutex_lock(&THR_LOCK_thread);
#ifdef __BORLANDC__
hThread=(HANDLE)_beginthread((void(_USERENTRY *)(void *)) pthread_start,
attr->dwStackSize ? attr->dwStackSize :
65535, (void*) map);
#else
hThread=(HANDLE)_beginthread((void( __cdecl *)(void *)) pthread_start,
attr->dwStackSize ? attr->dwStackSize :
65535, (void*) map);
#endif
DBUG_PRINT(“info”, (“hThread=%lu”,(long) hThread));
*thread_id=map->pthreadself=hThread;
pthread_mutex_unlock(&THR_LOCK_thread); 函数
if (hThread == (HANDLE) -1)
{
int error=errno;
DBUG_PRINT(“error”,
(“Can’t create thread to handle request (error %d)”,error));
DBUG_RETURN(error ? error : -1);
}
VOID(SetThreadPriority(hThread, attr->priority)) ;
DBUG_RETURN(0);
} 学习
关键的代码是下面三句: 优化
从这能够看出,建立的新线程的名字是个固定的函数——pthread_start,而咱们传进来的想建立的函数func是挂载在了map上了,函数的参数一样的挂载在map上了,这样咱们就能够推理出在pthread_start函数中,确定会出现这样的代码: spa
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_thread | handle_shutdown |
start_handle_manager | handle_manager |
handle_connections_methods | handle_connections_sockets |
建立者:调用pthread_create进行建立线程的函数。
处理函数:调用pthread_create所建立的线程的具体的线程函数。
由名称咱们就能够看出,handle_connections_sockets应该是处理链接的线程了,从顺序上看,也应该是这样,只有系统中全部的其余必须的线程建立完毕后,才能建立监听线程(链接线程),即监听线程应该是系统最后建立的。
找到了咱们LOGIN须要的线程了,下次针对这个线程,分析下如何进行登陆的,以及登陆后为用户分配哪些资源。时间不早啦,洗洗睡了