MySQL 代码结构与基本流程
一、MySQL基本架构
二、MySQL目录结构
build: 内含有各个平台、各种编译器下进行编译的脚本。如compile-pentium-debug表示在pentium架构上进行调试编译的脚本。
client: 客户端工具,如mysql,mysqladmin之类。
cmd-line-utils: readline,libedit工具。
config: 给aclocal使用的配置文件。
dbug: 提供一些调试用的宏定义。
Docs: MySQL在不同平台下的参考手册
extra: 提供innochecksum,resolveip等额外的小工具。
include: 包含的头文件
libmysql: 库文件,生产libmysqlclient.so。
libmysql_r: 线程安全的库文件,生成libmysqlclient_r.so。
libmysqld: 嵌入式MySQL Server库.
libservices: 5.5.0中新加的目录,实现了打印功能。
man: 适合man命令查看的帮助文件。
mysql-test: mysqld的测试工具套件。
mysys: 为实现跨平台,MySQL自己实现了一套常用的数据结构和算法,如string, hash等。还包含一些底层函数的跨平台封装,一般以my_开头。
netware: 在netware平台上进行编译时需要的工具和库。
plugin: MySQL 5.1开始支持一个插件式API接口,不需要重启mysqld即可动态载入插件,FullText就是一个例子。
pstack: GNU异步栈追踪工具。
regex: 正则表达式实现(来自多伦多大学Henry Spencer大牛的源码)。
scripts: 提供脚本工具,如mysql_install_db/mysqld_safe等。
server-tools: 包含instance_manager子目录,负责实例的本地和远程管理。
sql: MySQL Server主要代码,将会生成mysqld文件。
sql-bench: 一些基准测试代码代码,主要是Perl程序(虽然后缀是sh)。
sql-common: 存放部分服务器端和客户端都会用到的代码,有些地方的同名文件是这里lin过去的。
storage: 存储引擎所在目录。
strings: string库,包含很多字符串处理的函数。
support-files: my.cnf示例配置文件及编译所需的一些工具。
tests: 测试文件所在目录。
unittest: 单元测试文件。
vio: 虚拟io系统,是对network io的封装,把不同的协议封装成统一的IO函数。
win: 在windows平台编译所需的文件和一些说明。
zlib: zlib算法库(GNU)
三、InnoDB目录结构
btr: B+树的实现
buf: 缓冲池的实现,包括LRU算法,Flush刷新算法等
dict: InnoDB内存数据字典的实现
dyn: InnoDB动态数组的实现
fil: InnoDB文件数据结构以及对于文件的一些操作
fsp: 对InnoDB物理文件的管理,如页/区/段等(即File Space)
ha: 哈希算法的实现
handler: 继承与MySQL的handler,实现handler API与Server交互
ibuf: 插入缓冲(Insert Buffer)的实现
include: InnoDB所有头文件都放在这个目录,是查找结构定义的最佳地点
lock: InnoDB的锁实现及三种锁算法实现
log: 日志缓冲(Log Buffer)和重做日志组(Redo Log)的实现
mem: 辅助缓冲池(Additional Memory Pool)的实现,用来申请一些内部数据结构的内存
mtr: 事务的底层实现(日志,缓冲)
os: 封装一些对于操作系统的操作
page: 页的实现,研究InnoDB文件结构,这个目录至关重要
pars: 重载部分MySQL的SQL Parser(有待商榷)
que: Query graph,基本上没啥用
read: 读取游标的实现
rem: 行管理操作(比较操作,打印等)
row: 对于各种类型行数据操作的实现
srv: InnoDB后台线程,启动服务,Master Thread,SQL队列等
sync: InnoDB互斥变量(Mutex)的实现,基本同步机制
thr: InnoDB封装的可移植线程库
trx: 事务的实现
usr: Session管理
ut: 各种通用小工具
四、核心类库
THD: 线程类
Item: Item类(查询条目,函数,WHERE,ORDER,GROUP,ON子句等)
TABLE: 表描述符
TABEL_LIST: JOIN操作描述符
Field: 列数据类型及属性定义
LEX: 语法树
Protocol: 通讯协议
NET: 网络描述符
handler: 存储引擎接口
五、核心函数库
内存操作:
init_alloc_root: 内存池初始化,生成内存池根(MEM_ROOT)
alloc_root: 申请内存池内存,从mem_root指定的内存池申请内存块
free_root: 释放内存池,通过MyFlags指定哪种内存可以被释放
文件操作:
my_open: 打开一个文件
my_close: 关闭一个文件
my_b_flush_io_cache: 将数据从内存缓冲写到物理磁盘
end_io_cache: 释放一个IO_CACHE对象
哈希操作:
_hash_init: 初始化HASH描述符
hash_search: 搜索哈希表,调用hash_first
hash_first: 返回哈希表中找到的第一个行指针,否则返回0
字符串操作:
strappend:填充字符串
strmov: 移动字符串到新地址
六、核心算法
Bitmaps
bitmap_init/bimap_free: 创建与释放一个位图 (8*n个位为单位)
bitmap_set_bit/bitmap_fast_test_and_set: 设置位图的一个位
bitmap_clear_all/bitmap_set_all: 清空或全部设置一个位图
bitmap_cmp: 对两个位图的特定位比较
Join Buffer
如果存在条件过滤,则第一次过滤完的记录将放入Join Buffer,避免第二次再判断
Sort Buffer
算法一: 将排序字段和主键放入Sort Buffer排序,按照结果用主键取出数据返回
算法二: 将整行数据放入Sort Buffer,排序完成后直接从Sort Buffer返回数据
七、MySQL数据流
八、MySQL启动流程
主要代码在sql/mysqld.cc中,精简后的代码如下:
int main(int argc, char **argv) //标准入口函数
MY_INIT(argv[0]);//调用mysys/My_init.c->my_init(),初始化mysql内部的系统库
logger.init_base(); //初始化日志功能
init_common_variables(MYSQL_CONFIG_NAME,argc, argv, load_default_groups) //调用load_defaults(conf_file_name, groups, &argc, &argv),读取配置信息
user_info = check_user(mysqld_user);//检测启动时的用户选项
set_user(mysqld_user, user_info);//设置以该用户运行
init_server_components();//初始化内部的一些组件,如table_cache, query_cache等。
network_init();//初始化网络模块,创建socket监听
start_signal_handler();// 创建pid文件
mysql_rm_tmp_tables() || acl_init(opt_noacl)//删除tmp_table并初始化数据库级别的权限。
init_status_vars(); // 初始化mysql中的status变量
start_handle_manager();//创建manager线程
handle_connections_sockets();//主要处理函数,处理新的连接并创建新的线程处理
九、MySQL监听连接
主要代码在sql/mysqld.cc中(handle_connections_sockets),精简后的代码如下:
pthread_handler_t handle_connections_sockets(void *arg __attribute__((unused))) {
FD_SET(unix_sock,&clientFDs); // unix_socket在network_init中被打开
while (!abort_loop) { // abort_loop是全局变量,在某些情况下被置为1表示要退出。
readFDs=clientFDs; // 需要监听的socket
select((int) max_used_connection,&readFDs,0,0,0); // select异步(?科学家解释下是同步还是异步)监听,当接收到??以后返回。
new_sock = accept(sock, my_reinterpret_cast(struct sockaddr *) (&cAddr), &length); // 接受请求
thd= new THD; // 创建mysqld任务线程描述符,它封装了一个客户端连接请求的所有信息
vio_tmp=vio_new(new_sock, VIO_TYPE_SOCKET, VIO_LOCALHOST); // 网络操作抽象层
my_net_init(&thd->net,vio_tmp)); // 初始化任务线程描述符的网络操作
create_new_thread(thd); // 创建任务线程
}
}
十、MySQL创建连接
主要代码在sql/mysqld.cc中(create_new_thread/create_thread_to_handle_connection),精简后的代码如下:
static void create_new_thread(THD *thd) {
NET *net=&thd->net;
if (connection_count >= max_connections + 1 || abort_loop) { // 看看当前连接数是不是超过了系统配置允许的最大值,如果是就断开连接。
close_connection(thd, ER_CON_COUNT_ERROR, 1);
delete thd;
}
++connection_count;
thread_scheduler.add_connection(thd); // 将新连接加入到thread_scheduler的连接队列中。
}
而thread_scheduler转而调用create_thread_to_handle_connection,精简后的代码如下:
void create_thread_to_handle_connection(THD *thd) {
if (cached_thread_count > wake_thread) { //看当前工作线程缓存(thread_cache)中有否空余的线程
thread_cache.append(thd);
pthread_cond_signal(&COND_thread_cache); // 有的话则唤醒一个线程来用
} else {
threads.append(thd);
pthread_create(&thd->real_id,&connection_attrib, handle_one_connection, (void*) thd))); //没有可用空闲线程则创建一个新的线程
}
}
创建连接使用handle_one_connection函数,精简代码如下:
pthread_handler_t handle_one_connection(void *arg) {
thread_scheduler.init_new_connection_thread(); // 初始化线程预处理操作
setup_connection_thread_globals(thd); //载入一些Session级变量
for (;;) {
lex_start(thd); //初始化LEX词法解析器
login_connection(thd); // 进行连接身份验证
prepare_new_connection_state(thd); // 初始化线程Status,即show status看到的
do_command(thd); // 处理命令
end_connection(thd); //没事做了关闭连接,丢入线程池
}
}
十一、MySQL执行Query
do_command函数在sql/sql_parse.cc定义,代码如下:
bool do_command(THD *thd) {
NET *net= &thd->net;
packet_length = my_net_read(net);
packet = (char*) net->read_pos;
command = (enum enum_server_command) (uchar) packet[0]; // 解析客户端传过来的命令类型
dispatch_command(command, thd, packet+1, (uint) (packet_length-1));
}
再看dispatch_command函数在sql/sql_parse.cc定义,精简代码如下:
bool dispatch_command(enum enum_server_command command, THD *thd, char* packet, uint packet_length) {
NET *net = &thd->net;
thd->command = command;
switch (command) { //判断命令类型
case COM_INIT_DB: ...;
case COM_TABLE_DUMP: ...;
case COM_CHANGE_USER: ...;
...
case COM_QUERY: //如果是Query
alloc_query(thd, packet, packet_length); //从网络数据包中读取Query并存入thd->query
mysql_parse(thd, thd->query, thd->query_length, &end_of_stmt); //送去解析
}
}
mysql_parse函数负责解析SQL(sql/sql_parse.cc),精简代码如下:
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) { // 看query cache中有否命中,有就直接返回结果,否则进行查找
Parser_state parser_state(thd, inBuf, length);
parse_sql(thd, & parser_state, NULL); // 解析SQL语句
mysql_execute_command(thd); // 执行
}
}
终于开始执行鸟~mysql_execute_command接近3k行......,非常精简代码如下:
int mysql_execute_command(THD *thd) {
LEX *lex= thd->lex; // 解析过后的SQL语句的语法结构
TABLE_LIST *all_tables = lex->query_tables; // 该语句要访问的表的列表
switch (lex->sql_command) {
...
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); // 检查用户对数据表的访问权限
execute_sqlcom_select(thd, all_tables); // 执行select语句
break;
}
}
我们看一个例子, mysql_insert (在sql/sql_insert.cc),精简代码如下:
bool mysql_insert(THD *thd,
TABLE_LIST *table_list, // 该INSERT要用到的表
List<Item> &fields, // 使用的项
....) {
open_and_lock_tables(thd, table_list); // 这里的锁只是防止表结构修改
mysql_prepare_insert(...);
foreach value in values_list {
write_record(...);
}
} //里面还有很多处理trigger,错误,view之类的杂七杂八的东西,我们都忽略。
我们接着看真正写数据的函数write_record (在sql/sql_insert.cc),精简代码如下:
int write_record(THD *thd, TABLE *table,COPY_INFO *info) { // 写数据记录
if (info->handle_duplicates == DUP_REPLACE || info->handle_duplicates == DUP_UPDATE) { //如果是REPLACE或UPDATE则替换数据
table->file->ha_write_row(table->record[0]);
table->file->ha_update_row(table->record[1], table->record[0]));
} else {
table->file->ha_write_row(table->record[0]);
}
}
int handler::ha_write_row(uchar *buf) { //这是啥? Handler API !
write_row(buf); // 调用具体的实现
binlog_log_row(table, 0, buf, log_func)); // 写binlog
}
十二、Query流程
转载于:https://blog.51cto.com/happytree007/1952524
相关文章:
【怎样写代码】复杂对象的组装与创建 -- 建造者模式(五):关于Director的进一步讨论
如果喜欢这里的内容,你能够给我最大的帮助就是转发,告诉你的朋友,鼓励他们一起来学习。 If you like the content here, you can give me the greatest help is forwarding, tell your friends, encourage them to learn together.

如何进行app的兼容性测试?需要考虑哪些方面?
考虑的方面: 1. 系统 a. Android 1). 官方版:官方发型的版本 数据来源:https://mta.qq.com/mta/data/device/os 2). 定制版:华为、魅族、小米、三星。 (前三:华为、oppo、vivo) 数据来源:https://mta.qq.com/mta…

.NET Framework 4.0的新特性
本文将揭示.NET 4.0中的3个新特性:图表控件、SEO支持以及ASP.NET 4可扩展的输出缓存。 图表控件 微软向开发者提供了大量可免费下载的图表控件,可以在.NET 3.5 ASP.NET或WinForms项目中使用这些控件。要想在Visual Studio 2008中使用这些控件则需要安装一…
【怎样写代码】确保对象的唯一性 -- 单例模式(一):问题案例
如果喜欢这里的内容,你能够给我最大的帮助就是转发,告诉你的朋友,鼓励他们一起来学习。 If you like the content here, you can give me the greatest help is forwarding, tell your friends, encourage them to learn together.

《Kinect应用开发实战:用最自然的方式与机器对话》一3.4 深度图像成像原理...
3.4 深度图像成像原理 Kinect有发射、捕捉、计算视觉重现的类似过程。严格说来,Kinect的“深度眼睛”是由一个红外投影机和红外摄像头组合而成的,投影和接收互为重叠,如图3-27所示。 可以说,Kinect的成功也在于其能廉价而有效地捕…

UI设计不够高端?这5个小技巧可以试试
UI培训设计是对软件的人机交互、操作逻辑、界面美观度的整体设计。好的UI设计不仅要让软件变得漂亮舒适,还要充分考虑到用户的操作问题。 从事UI设计的朋友们,肯定知道我们在做UI设计时,其实是可以通过一些小技巧来帮我们设计的界面更加的漂…

Apache学习路线
参考资料: 1、《Apache源代码全景分析》 2、《鸟哥服务器架设篇》 一、不同的开发人员应该关注的知识点 Apache管理员 配置文件、配置指令 模块开发人员 全部内容 服务器开发人员 MPM并发处理框架 普通人员 …

大火的Apache Spark也有诸多不完美
现在如果你想要选择一个解决方案来处理企业中的大数据并不是难事,毕竟有很多数据处理框架可以任君选择,如Apache Samza,Apache Storm 、Apache Spark等等。Apache Spark应该是2016年风头最劲的数据处理框架,它在数据的批处理和实时…
【怎样写代码】确保对象的唯一性 -- 单例模式(二):解决方案
如果喜欢这里的内容,你能够给我最大的帮助就是转发,告诉你的朋友,鼓励他们一起来学习。 If you like the content here, you can give me the greatest help is forwarding, tell your friends, encourage them to learn together.

零基础如何学习java技术?
想要学习java技术,担心自己是零基础学不会?最近有很多同学会问到这样的问题,千锋教育小编告诉你,零基础是可以学习java技术的,但是要去正规的java培训机构学习,下面来看看详细的介绍。 零基础如何学习java技术?我们…

Rank() over()的用法
Rank() over()的用法 创建一个test表,并插入6条数据。CREATE TABLE test (a INT,b INT,c CHAR ) INSERT INTO test VALUES(1,3,E) INSERT INTO test VALUES(2,4,A) INSERT INTO test VALUES(3,2,D) INSERT INTO test VALUES(3,5,B) INSERT INTO test VALUES(4,2,C) …

5G将成开启物联网时代的金钥匙
物联网其实并非新鲜事物,在互联网兴起之初,就有人提出了万物皆可通过网络互联,这被认为是物联网最早的定义。其实早在1995年比尔盖茨在其书《未来之路》也提到了物联网,当初并未引起重视。如今,随着互联网与先进通信技…
【怎样写代码】确保对象的唯一性 -- 单例模式(三):单例模式
如果喜欢这里的内容,你能够给我最大的帮助就是转发,告诉你的朋友,鼓励他们一起来学习。 If you like the content here, you can give me the greatest help is forwarding, tell your friends, encourage them to learn together.

学习Python有什么优势?
学习Python的人越来越多,很多人就想知道,编程语言有那么多种,学习Python有什么优势?为什么这么多人会选择学习Python技术?今天我们就来聊一聊Python语言。 学习Python有什么优势? 入手快。Python语言相对于其他编程语言来说&am…

取消水晶报表的数据库登录框 分享
这两天在和斌做后台中的报表,暂定使用水晶报表,目前还只是处于对水晶报表的初级应用阶段,也就是知道如何 汇个总、写个函数、传个参数。 问题总是层出不穷,在最后整合报表,进行报表显示测试的时候,发现每次…

有光照就能上网 0.2秒即可下载一部高清电影
再也不用费尽心思询问 WIFI 密码了,以后,哪里有光照,哪里就可以上网。中国“可见光通信系统关键技术研究”近日取得重大突破,实时通信速率提升至 50Gbps,也就是说: 0.2 秒即可完成一部高清电影的下载。 有光…
【怎样写代码】确保对象的唯一性 -- 单例模式(四):饿汉式单例类与懒汉式单例类的讨论
如果喜欢这里的内容,你能够给我最大的帮助就是转发,告诉你的朋友,鼓励他们一起来学习。 If you like the content here, you can give me the greatest help is forwarding, tell your friends, encourage them to learn together.

学Java需要学哪些书?
java技术所要学到的东西是很多的,只要入了这一行,学习是不能停止的,工作节奏在加快,新知识也源源不断,学习的最好途径就是看书,小编给大家推荐这几本java方面的书,搭配学习课程,让学…
【怎样写代码】确保对象的唯一性 -- 单例模式(五):一种更好的单例实现方法(静态内部类)
如果喜欢这里的内容,你能够给我最大的帮助就是转发,告诉你的朋友,鼓励他们一起来学习。 If you like the content here, you can give me the greatest help is forwarding, tell your friends, encourage them to learn together.

郭为:大数据时代的企业管理挑战
互联网时代,创新使得财富积累的速度前所未有的快,贫富不均也前所未有地分化。这个时代,世界的竞争变成人与人的竞争,人与人的竞争就是智慧的竞争,就是人的创新能力的竞争。如何才能提高人的竞争力,是管理科…

如何挑选靠谱的Java培训机构
想要学习java技术的人越来越多,市面上出现的java培训机构也越来越多,很多人都想找一个靠谱的java培训机构,那么到底该如何挑选靠谱的Java培训机构呢?看看下面小编为大家做的详细介绍吧。 如何挑选靠谱的Java培训机构? 首先挑选java培训机…

ActiveMQ在C#中的应用
ActiveMQ是个好东东,不必多说。ActiveMQ提供多种语言支持,如Java, C, C, C#, Ruby, Perl, Python, PHP等。由于我在windows下开发GUI,比较关心C和C#,其中C#的ActiveMQ很简单,Apache提供NMS(.Net Messaging …

数据中心防雷SPD技术漫谈
雷电是大自然里一种普遍现象,在世界的任意角落都会有雷电天气出现,只不过数量不同而已。雷电对大地及地面物体的放电现象成为雷击,这种放电过程会产生强烈的闪电并伴随巨大的声音,对被击物体有严重的危害,会在物体的两…
【怎样写代码】确保对象的唯一性 -- 单例模式(六):扩展案例
如果喜欢这里的内容,你能够给我最大的帮助就是转发,告诉你的朋友,鼓励他们一起来学习。 If you like the content here, you can give me the greatest help is forwarding, tell your friends, encourage them to learn together.

Python数据分析可以应用到哪些领域
随着大数据的应用越来越广泛,应用的行业也越来越多,我们每天都可以看到一些关于数据分析的新鲜应用,从而帮助人们获取到有价值的信息。例如,网购时经常发现电商平台向我们推荐商品,往往这类商品都是我们最近浏览的&…
printf(%d, -10u); 这个输出什么呀, 0或1?
printf("%d", -1<0u); 这个输出什么呀, 0或1?周银辉 既然我这么问了, 那么答案自然不是1,而是0看看下面的代码: 对于-10u输出为-1,似乎理所当然,但为什么-1<0u却输出0呢,也就是说-1不小于0u,好神奇啊…

Enterprise Library 4 缓存应用程序块的设计
缓存应用程序为以下目的而设计: 提供一个大小可管理的 API 集合。允许开发人员添加标准的缓存操作到他们的应用程序中,而不用学习应用程序块的内部工作。用 Enterprise Library 配置控制台来简化配置。有效率的执行。线程安全。某些东西在被多个程序线程…

【软件测试培训】了解jmeter分布式测试
一提到分布式测试,大家肯定会觉得,哇!好高大上,一定很高深的吧,这里老师推出不做傻白甜系列文章,带同学们一步一步理解jmeter的分布式测试。 首先我们来看下jmeter自动化测试的流程 ,见如下图1 【软件测试…

存储过程中返回结果集
存储过程中返回结果 从存储过程中返回结果有三种方式: 1、 返回结果集 这是客户端应用程序返回结果的最通用的方法。结果集是通过使用select语句选择数据产生的。结果集可以从永久表、临时表或局部变量中产生。将结果返回到另一个存储过程不是一种有效的方法。存储…

我的股票交易策略
投资股市已经成为我们进行资产配置的一个重要选择。在这个市场中主流的投资方式无外乎 价值投资 和 趋势投资 两种。价值投资需要了解各种财务指标来评价各支股票,在被市场低估时买入,在被市场高估时卖出。这对于非财务背景的人来说门槛偏高。趋势投资需…