MySQL系列之源码浅析

2023-05-16

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

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; // 需要监听的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); // 创建任务线程
    }
}

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: //如果是Query
            alloc_query(thd, packet, packet_length); //从网络数据包中读取Query并存入thd->query
            mysql_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) { //如果是REPLACEUPDATE则替换数据
        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
}

请求数据流


这里写图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

MySQL系列之源码浅析 的相关文章

  • 可以替代树莓派4(raspberry pi 4B)的tinker board 2

    近几年 xff0c 随着国产芯片的飞速发展 xff0c 一批基于国产SOC的 xff0c 性价比高 xff0c 能运行Android Linux的开发板在市场上出现 xff0c 此前 xff0c 如果要用到Android Linux的开发板
  • 全国大学生电子设计竞赛参赛分享

    在你想要放弃的那一刻 想想为什么当初走到了这里 努力走自己喜欢且有意义的路 xff0c 遇见以后不平凡的自己 时隔九年 xff0c 再次回想起大学时候参见电子设计竞赛的经历 xff0c 依然历历在目 大赛简介 全国大学生电子设计竞赛 xff
  • Turtlebot 3 rplidar bringup

    Turtlebot 3上安装rplidar A1驱动并配置相关的sh及launch文件 xff0c 实现SBC端的bringup xff0c 以及PC上的rviz Turtlebot 3默认的雷达是HLS Hitachi LG Sensor
  • LiDAR 1 基础

    激光的形成过程 xff1a 原子内的电子有低能量状态和高能量状态 xff0c 低能量电子吸收能量进入高能量活跃态 xff0c 恢复低能量时发射光子 通过高电压在谐振腔内触发激光 不同的介质可以触发不同频段的激光 激光雷达使用的是红外波段的非
  • LiDAR 4 固态激光雷达 (Flash LiDAR)

    固态激光雷达分为Flash LiDAR和OPA Optical Phased Array LiDAR xff0c Flash LiDAR是非扫描式的 xff0c OPA LiDAR 是扫描式的 Flash LiDAR的发射光源和接收部件都是
  • LiDAR 5 相控阵激光雷达 (OPA LiDAR)

    OPA LiDAR相控阵激光雷达的技术核心是OPA scanner Quanergy S3激光雷达Transmitter OPA xff1a Leddar Tech OPA LiDAR模块 xff1a 相控阵Phase array实现方式
  • LiDAR 6 FMCW

    FMCW是TOF之外的另一种方式 xff0c 利用光波的调频实现目标的探测 光的波粒二象性 多普勒效应 系统架构 当系统的复杂程度上升后 xff0c 能够采集到的信息也更多 xff0c 包括距离和速度 采用OPA扫描的FMCW激光雷达设计
  • LiDAR 7 消费电子3D应用

    消费电子3D应用 Depth Camera xff0c AR Glass xff0c 类似 Microsoft Azure Kinect xff0c Intel RealSense xff0c iPhone iPad 等产品 Microso
  • LiDAR 8 激光雷达行业

    激光雷达应用的领域特别广泛 xff0c 在无人驾驶上的应用受到很大的关注 全球汽车领域激光雷达的厂商 xff0c 生态链厂商 xff0c 相信激光雷达在产品和技术上的发展还会有很广阔的天地
  • FOC - SVPWM

    FOC vector control 电机矢量控制FOC通过转子坐标系的转换 xff0c 实现动态电流控制 实现的几个环节 xff0c 相电流phase current gt Park Ialpha Ibeta gt Clarke Iq I
  • STL- 容器特点总结

    关于 STL1 序列式容器2 关联式容器3 容器适配器 关于 STL STL即标准模板库 xff08 Standard Template Library xff09 STL包含 6大组件 43 13个头文件 六大组件 xff1a 容器 算法
  • C++ 迭代器失效 ++报错

    迭代器失效 xff0c 迭代器 43 43 报错 Program terminated with signal SIGSEGV Segmentation fault 0 0x00007f5a4be6ffb4 in std Rb tree i
  • 将.bib转换内容为bibitem(bbl)格式

    部分期刊要求使用一些小众的参考文献格式 xff0c 或者不允许使用biblatex包 xff08 不兼容 xff09 xff0c 这是就需要将 bib里的参考文献转成bibitemx并放在 tex文件的末尾 Latex排版引用问题 xff1
  • 杰卡德相似系数(Jaccardsimilarity coefficient)

    xff08 1 xff09 杰卡德相似系数 两个集合A和B交集元素的个数在A B并集中所占的比例 xff0c 称为这两个集合的杰卡德系数 xff0c 用符号 J A B 表示 杰卡德相似系数是衡量两个集合相似度的一种指标 xff08 余弦距
  • argmax()函数和max()函数区别

    是求f x 的最大值 是求x的最大值 举个列子 xff1a 设 当x 61 2时 xff0c f x 最大 xff0c argmax f x xff09 就是使f x 值最大的那个自变量
  • Python 优先级队列PriorityQueue 用法示例

    优先队列 xff08 PriorityQueue xff09 是队列的变体 xff0c 按优先级顺序 xff08 最低优先 xff09 检索打开的条目 条目通常是以下格式的元组 xff1a 插入格式 xff1a q put priority
  • Python 优先级字典SortedDict 用法实例

    安装 sudo pip install sortedcontainers 默认为增序 用法示例 coding utf 8 导入模块库 from sortedcontainers import SortedDict 初始化 sorted di
  • python SortedDict 遍历删除 不对

    topLevel 61 SortedDict neg 从大到小排序 for priority Id in topLevel items print 34 topLevel1 34 topLevel 将Id从topLevel中删除 topLe
  • Python字典遍历 未遍历所有元素

    不能在遍历的时候往字典中新增 删除元素 xff01 xff01 xff01 下面是我的python脚本 xff0c 它需要遍历所有具有逻辑路径和直接磁盘的物理磁盘 如果我们找到了任何逻辑路径 xff0c 那么我们得到了相应的物理磁盘 xff
  • 以太坊 事务ID txID transaction ID transaction hash怎么计算

    The transaction can then be sent to the network and will be tracked by a 256 bit transaction id This transaction can be

随机推荐

  • 比特币 事务ID txID transaction hash怎么计算

    A TXID Transaction ID is basically an identification number for a bitcoin transaction A TXID is always 32 bytes 64 chara
  • 使用Android studio开发jni,并实现单步调试c/c++代码

    一 环境搭建 本文讲解的是在一个现有的工程中增加JNI的支持 我们从新建一个工程说起 xff0c 本文假设你已经知道怎么设置sdk和ndk 新建工程的时候我们故意不勾选这个选项 xff0c 方便后面说明 一直默认点下一步 xff0c 直到工
  • 以太坊 分片是什么

    Ethereum Sharding An Introduction to Blockchain Sharding Alchemy Team May 18 2022 For years the question of blockchain s
  • 跨链桥——原子交换(Atomic Swaps),哈希时间锁(HTLC) 原理介绍

    什么是原子交换 xff1f xff08 Atomic swaps xff09 跨链原子交换 xff08 Atomic swaps xff09 是在两个平行链之间直接交换不同的加密货币的方法 就像用美元兑换人民币一样 xff0c 这是一个过程
  • OR-Tools|带你了解谷歌开源优化工具(Google Optimization Tools)

    转眼间暑假已经过去一大半了 xff0c 大家有没有度过一个充实的假期呢 xff1f 小编这两天可忙了 xff0c boss突然说发现了一个很有趣的开源求解器 xff1a OR Tools 经过一番了解 xff0c 小编发现它对于为解决优化问
  • 最小费用流 求解

    增广路径 匈牙利算法 二分图 https blog csdn net qq 37457202 article details 80161274 增广路径取反 xff1a 增广路上的边性质改变 xff0c 连上的变为可以连的 xff0c 可以
  • 区块链DAPP开发 以太坊智能合约框架有哪些

    一 truffle xff08 JavaScript xff09 Truffle 是一个在以太坊进行 DApp 开发的世界级开发环境 测试框架 使用 Truffle 开发有一以下优点 xff1a 内置智能合约编译 xff0c 链接 xff0
  • 区块链DAPP开发 智能合约开发工具IDE有哪些

    Remix http remix ethereum org ChainIDE https chainide cn zh CN ChainIDE提供云端编译功能 xff0c 无需繁琐的安装设置 xff0c 加速开发迭代速度 ChainIDE提
  • NFT和数字藏品的区别

    来源 xff1a 德勤 Web3 0模式分析及中国应用创新探索
  • Pycharm 增加 run 控制台缓冲行数

    找到 pycharm 安装目录的 bin 目录下 idea properties 文件 xff0c 修改 idea cycle buffer 值 xff0c 原来默认为 1024
  • python 类的定义一定要注意静态变量

    class A 静态变量 a 61 12 def init self a 成员变量 self a 61 a 静态变量通过 类名 变量名 来访问 print A a 12 成员变量通过 对象 变量名 访问的 print A 0 a 0 cla
  • python open按行读取txt 去掉\n

    加 strip 39 n 39
  • OOQP安装指南

    文章目录 1 OOQP的github链接 xff1a 2 准备工作 xff1a 3 安装OOQP xff1a 4 简单使用 xff1a 1 OOQP的github链接 xff1a ompl的官网网址为 xff1a https github
  • 海康摄像头实时显示与字符叠加详解

    1 说明 文章详细叙述了海康摄像头的两种实时显示方法 基于SDK 解码显示和基于数据流回调显示 xff0c 并且讲述了这在两种显示方法下如何往画面添加字符和图像 xff0c 最后比较了这两种方法的优劣 文章全程给以详细的程序说明 xff0c
  • Proto3序列化协议

    Proto3序列化协议 简介 对于互联网应用来说 xff0c 客户端 客户端 客户端 服务端之间需要数据的交互 xff0c 其数据传输是二进制流的方式在互联网上传输 xff0c 因为需要一种手段将数据对象编码为一种可以在网络上传输的二进制流
  • 一文读懂数据库分库分表

    阅读此文你将了解 xff1a 什么是分库分表以及为什么分库分表如何分库分表分库分表常见几种方式以及优缺点如何选择分库分表的方式 数据库常见优化方案 对于后端程序员来说 xff0c 绕不开数据库的使用与方案选型 xff0c 那么随着业务规模的
  • 从操作系统漫谈GOLang GPM模型

    前言 本文从操作系统谈起 xff0c 简单介绍操作系统基本知识 xff0c 引出进程 线程调度的基本原理和基本模型 xff0c 然后从0到1设计Golang调度器 xff0c 通过方案的逐步演进升级 xff0c 可以了解到GPM模型设计理念
  • 卡尔曼滤波经典讲解,C++算法实现

    请移步跳转文章排版更加清晰 在学习卡尔曼滤波器之前 xff0c 首先看看为什么叫 卡尔曼 跟其他著名的理论 xff08 例如傅立叶变换 xff0c 泰勒级数等等 xff09 一样 xff0c 卡尔曼也是一个人的名字 xff0c 而跟他们不同
  • 解决linux不能安装g++问题

    问题描述 xff1a Ubuntu如何通过重新安装G 43 43 编译器 xff0c 修复不能安装使用g 43 43 的问题 我刚安装的Ubuntu 14 10的g 43 43 编译器不能使用 xff0c 用sudo apt get ins
  • MySQL系列之源码浅析

    源码才是王道 真正的高手从来不是临场发挥 xff0c 随机应变是外人看来的错觉 1 主函数sql mysqld cc中 xff0c 代码如下 xff1a span class hljs keyword int span main span