Mysql源代码分析系列(2): 源代码结构Mysql源代码主要包括客户端程序代码,服务器端代码,测试工具和一些库构成,下面我们对比较重要的目录做些介绍。
BUILD这个目录在本系列的上篇文章中我们仔细看过,内含各种平台的编译脚本,这里就不仔细说了。
client这个目录下有如下比较让人眼熟的文件: , , , ,等等,如果你编译一下就会发现那些眼熟的程序也出现了,比如mysql。
明白了吧,这个目录就是那些客户端程序所在的目录。
这个目录的内容也比较少,而且也不是我们阅读的重点。
Docs这个目录包含了文档。
storage这个目录包含了所谓的Mysql存储引擎(storage engine)。
存储引擎是数据库系统的核心,封装了数据库文件的操作,是数据库系统是否强大最重要的因素。
Mysql实现了一个抽象接口层,叫做handler(sql/,其中定义了接口函数,比如:ha_open, ha_index_end, ha_create等等,存储引擎需要实现这些接口才能被系统使用。
这个接口定义超级复杂,有900多行:-(,不过我们暂时知道它是干什么的就好了,没必要深究每行代码。
对于具体每种引擎的特点,我推荐大家去看mysql的在线文档:应该能看到如下的目录:* innobase, innodb的目录,当前最流行的存储引擎* myisam, 最早的Mysql存储引擎,一直到innodb出现以前,使用最广的引擎。
* heap, 基于内存的存储引擎* federated, 一个比较新的存储引擎* example, csv,这几个大家可以作为自己写存储引擎时的参考实现,比较容易读懂mysys包含了对于系统调用的封装,用以方便实现跨平台。
大家看看文件名就大概知道是什么情况了。
sql这个目录是另外一个大块头,你应该会看到,没错,这里就是数据库主程序mysqld所在的地方。
大部分的系统流程都发生在这里。
你还能看到, , ,等等,分别实现了对应的SQL命令。
后面我们还要经常提到这个目录下的文件。
大概有如下及部分:SQL解析器代码: , , , 等,实现了对SQL语句的解析操作。
"handler"代码: , ,定义了存储引擎的接口。
"item"代码:, ,定义了SQL解析后的各个部分。
SQL语句执行代码: , , , ,执行SQL对应的语句。
当你要看"SELECT ..."的执行的时候,直接到去看就OK了。
辅助代码: 实现网络操作还有其他很多代码。
vio封装了virtual IO接口,主要是封装了各种协议的网络操作。
plugin插件的目录,目前有一个全文搜索插件(只能用在myisam存储引擎)。
libmysqldMysql连接库源代码。
开源函数库目录和所有的开源项目一样,Mysql也使用了一些开源的库,在其代码库中我们能看到dbug、pstack、strings、zlib等。
多说无益,主要是对于mysql的代码目录有个概念,要找的时候也有个方向。
万一要找某个东西找不到了就只能grep了...Mysql源代码分析系列(3): 主要调用流程引言本文主要介绍Mysql主要的调用流程,将从代码的角度来看一个从用户发出的"select * from test" SQL命令在服务器内部是如何被执行的。
从我个人的经验来看,阅读理解大规模项目的代码最重要的两个方面,一是了解主要的数据结构,二是了解数据流,在这里主要是调用流程。
把这两个主线把握住以后,大部分代码都是比较容易阅读的,Mysql的源代码属于比较好读的类型,因为函数的调用关系比较明确。
难读的代码一般都充斥着大量的回调、异步调用,很可能你极难找到某个函数在哪里或什么时候被调用了。
当然,算法的实现代码也很难读。
幸好Mysql不是那种难读的类型,所以我们也不要害怕,大步向前吧!主要执行过程从架构上来看,Mysql服务器对于一条SQL语句的执行过程可以分成如下几部分:接受命令包括用户验证,资源申请等|V命令解析解析SQL语句,生成语法树|V寻找执行计划根据解析出来的语法树,找到可能的执行计划。
对于一条SQL语句,很可能会有多种执行方案,特别是在SQL语句比较复杂的时候。
这里需要对于各种可能的方案进行代价评估,最快的找到最有的执行方案。
|V优化执行计划优化执行计划。
这是SQL执行中最复杂的部分之一,据说全都是由数学博士们写出来的,而且比较难懂。
我目前还处于不懂的状态。
|V执行没啥可说的,只剩执行及返回结果了系统启动所有的程序都从main开始,mysqld也不例外,打开sql/,稍加搜索,你就能看到熟悉的main函数,我们可以将其进行如下简写:int main(int argc, char* argv[]) {();init_common_variables(MYSQL_CONFIG_NAME, argc, argv,load_default_groups)); .); .); .;case COM_TABLE_DUMP: ...;case COM_CHANGE_USER: ...;...case COM_QUERY:alloc_query(thd, packet, packet_length);mysql_parse(thd, thd->query, thd->query_length, &end_of_stmt);}}进行sql语句解析void mysql_parse(THD *thd, const char *inBuf, uint length, const char ** found_semicolon) {lex_start(thd);if (query_cache_send_result_to_client(thd, (char*) inBuf, length) <= 0) { .case SQLCOM_INSERT:insert_precheck(thd, all_tables);mysql_insert(thd, all_tables, lex->field_list, lex->many_values, lex->update_list, lex->value_list, lex->duplicates, lex->ignore);break;...case SQLCOM_SELECT:check_table_access(thd, lex->exchange SELECT_ACL | FILE_ACL : SELECT_ACL, all_tables, UINT_MAX, FALSE); .);foreach value in values_list {write_record(...);}}其实里面还有很多处理trigger,错误,view之类的,我们暂时都忽略。
734 */735 if (table->next_number_field && buf == table->record[0]) c -rni *plugin/daemon_example/:187:mysql_declare_plugin(daemon_example)sql/:6269:mysql_declare_plugin(partition)sql/:5528:mysql_declare_plugin(binlog)sql/:10533:mysql_declare_plugin(ndbcluster)storage/csv/:1603:mysql_declare_plugin(csv)storage/example/:893:mysql_declare_plugin(example)storage/myisam/:2057:mysql_declare_plugin(myisam)storage/heap/:746:mysql_declare_plugin(heap)storage/innobase/handler/:8231:mysql_declare_plugin(innobase)storage/myisammrg/:1186:mysql_declare_plugin(myisammrg)storage/blackhole/:356:mysql_declare_plugin(blackhole)storage/federated/:3368:mysql_declare_plugin(federated)storage/archive/:1627:mysql_declare_plugin(archive)呵呵,连binlog都是plugin哦,不过还是storage plugin占大多数。
Plugin初始化在见面的介绍main函数的文章中我也提到了其中有个函数plugin_init()是初始化的一部分,这个东东就是所有静态链接初始化plugin的初始化入口。
该函数定义在"sql/"中。
int plugin_init(int *argc, char **argv, int flags) {.这个函数执行结束以后,在plugin_array,plugin_dl_array,plugin_hash中保存了当前加载了的所有的plugin。
到此plugin初始化结束。
在plugin_initialize函数里面,调用了每个plugin自己的init函数(参见前面的内容)。
特别要提到的是对于各种不同类型的plugin,初始化函数的参数也不一样,这是通过一个全局的plugin_type_initialize间接层来实现的。
这个数组对于每种类型的plugin定义了一个函数,比如对于storage plugin对应的是ha_initialize_handlerton,对于information scheme对应的是initialize_schema_table,然后在这些函数中再调用plugin的初始化函数。
暂时对于其他类型的plugin没有定义这个中间层初始化函数,所以就直接调用了plugin的初始化函数。
Mysql源代码分析(6): Plugin架构介绍-续上篇文章我们分析了Mysql的Plugin接口以及plugin的初始化过程,这里我们继续看plugin怎么被使用的。
基本还是通过例子看问题,主要分析myisam如何通过plugin接口被调用的。
myisam是mysql最早的和默认的storage engine,前面我们也看到在plugin初始化的时候是优先初始化myisam,然后才初始化其他的存储引擎。