源码才是王道。
真正的高手从来不是临场发挥,随机应变是外人看来的错觉。

1. 主函数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();//主要处理函数,处理新的连接并创建新的线程处理
}

2.监听连接: 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; // 需要监听的socketselect((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); // 创建任务线程}
}

3. 创建连接 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的连接队列中。
}

4. 线程调度器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))); //没有可用空闲线程则创建一个新的线程}
}

5.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); //没事做了关闭连接,丢入线程池}
}

6.执行语句 sql/sql_parse.cc - do_command函数

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));
}

7.指令分发 sql/sql_parse.cc定义dispatch_command

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: //如果是Queryalloc_query(thd, packet, packet_length); //从网络数据包中读取Query并存入thd->querymysql_parse(thd, thd->query, thd->query_length, &end_of_stmt); //送去解析}
}

8.sql/sql_parse.cc mysql_parse函数负责解析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) { // 看query cache中有否命中,有就直接返回结果,否则进行查找Parser_state parser_state(thd, inBuf, length);   parse_sql(thd, & parser_state, NULL); // 解析SQL语句mysql_execute_command(thd); // 执行}
}

9.执行命令 mysql_execute_command

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;}
}

10.接下来sql/sql_insert.cc中mysql_insert函数

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之类的杂七杂八的东西,我们都忽略

11.接着看真正写数据的函数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
}

请求数据流

MySQL系列之源码浅析相关推荐

  1. Mysql jdbc driver源码浅析(一)

    jdbc操作实例代码 //1. 加载驱动Class.forName("com.mysql.jdbc.Driver");//2. 获取连接Connection connection ...

  2. fetch first mysql_MySQL多版本并发控制机制(MVCC)源码浅析

    MySQL多版本并发控制机制(MVCC)-源码浅析 前言 作为一个数据库爱好者,自己动手写过简单的SQL解析器以及存储引擎,但感觉还是不够过瘾.<>诚然讲的非常透彻,但只能提纲挈领,不能让 ...

  3. Gradle 庖丁解牛(构建源头源码浅析)

    1 背景 陆陆续续一年多,总是有人问 Gradle 构建,总是发现很多人用 Gradle 是迷糊状态的,于是最近准备来一个"Gradle 庖丁解牛"系列,一方面作为自己的总结,一方 ...

  4. hashmap允许null键和值吗_hashMap底层源码浅析

    来源:https://blog.csdn.net/qq_35824590/article/details/111769203 hashmap是我们经常使用的一个工具类.那么知道它的一些原理和特性吗? ...

  5. Android Loader机制全面详解及源码浅析

    原文出处:csdn@工匠若水,http://blog.csdn.net/yanbober/article/details/48861457 一.概述 在Android中任何耗时的操作都不能放在UI主线 ...

  6. 内核启动流程分析(四)源码浅析

    目录 kernel(四)源码浅析 建立工程 启动简析 head.s 入口点 查询处理器 查询机器ID 启动MMU 其他操作 start_kernel 处理命令行 分区 kernel(四)源码浅析 建立 ...

  7. mysql 安装_源码安装mysql

    源码安装mysql 什么是源码 #! /bin/bash echo 'hello'高级语言 ➡️机器码01001001 源码安装mysql逻辑 1.源码包 ⬇ 2.预编译 1.检查当前的操作系统. 2 ...

  8. harbor登录验证_Harbor 源码浅析

    Harbor 源码浅析​www.qikqiak.com Harbor 是一个CNCF基金会托管的开源的可信的云原生docker registry项目,可以用于存储.签名.扫描镜像内容,Harbor 通 ...

  9. MVC系列——MVC源码学习:打造自己的MVC框架(一:核心原理)(转)

    阅读目录 一.MVC原理解析 1.MVC原理 二.HttpHandler 1.HttpHandler.IHttpHandler.MvcHandler的说明 2.IHttpHandler解析 3.Mvc ...

最新文章

  1. Python 3.9来了!这十个新特性值得关注
  2. vmware workstation无法打开内核设备问题处理办法
  3. CodeAction_beta02 斐波那契 (多维DP)
  4. Java个人学生信息的录入_java录入学生信息
  5. 用jQuery监听浏览器窗口的变化
  6. Java 基础——数组解析
  7. python字符串数组_python将字符串转换成数组的方法
  8. IPV4与IPV6的区别(史上最详细)
  9. Nodejs实现的一个静态服务器例子
  10. Ubuntu系统下Git的使用
  11. Educational Codeforces Round 12 B. Shopping 暴力
  12. HTTP与HTTPS之间的联系与连接状态
  13. android studio for android learning (十二) 查看并获取联系人信息
  14. java apdu读取社保卡_读取社保卡信息 - osc_qzrqhs9y的个人空间 - OSCHINA - 中文开源技术交流社区...
  15. 论文学习笔记-M2Det
  16. OA项目之我的会议(会议排座送审)
  17. Excel中制作目录的3种方法,你了解几种?
  18. 双色球的简单逻辑!不中五百万天理难容!
  19. Unity Application Block 1.2 学习笔记(zhuan)
  20. iOS基础_C语言第一讲

热门文章

  1. 深度学习: pooling (池化 / 降采样)
  2. 员工满意度调查表模型如何设计?
  3. 工业文明压抑与人性的异化
  4. [笔记]使用SFML来生成分形图片
  5. java方法声明无效_Java错误-“无效的方法声明;需要返回类型”
  6. JAVA 异常处理——声明、抛出异常
  7. VMware虚拟机鼠标无法移出边界
  8. SpringBoot+Euraka+Zuul实现服务路由的服务
  9. linux访问vdma的数据,zynq-7000学习笔记(十一)——Linux下VDMA的使用
  10. 【你问我答】unity实现一个刮刮乐效果