跟随一条insert语句, 进入TiDB的源码世界(上)

Posted lijingshanxi

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了跟随一条insert语句, 进入TiDB的源码世界(上)相关的知识,希望对你有一定的参考价值。

TiDB是google F1的开源实现;

TiDB实现了基于mvcc的乐观锁,在线表结构变更,基于时间戳的数据线性一致性,等等;

为了可靠性,TiDB和Oracle一样,维护了百万级别的自动化测试用例,跑在k8s搭建的集群之上;

TiDB里面用到的算法,都会写测试程序验证,以证明算法的正确性;

自 google F1开始,数据库被分成了两类:

  一类是传统sql,代表如Oracle,依赖于高速网络和磁盘阵列来实现海量数据的扩容和数据的高可靠,成本及其高昂,大部分银行都用了Oracle的系统;

  另一类是NewSQL,代表如F1和TiDB,依赖于各种算法,使数据库服务能运行在由廉价服务器搭建的集群之上,同样保证了海量数据的扩容和数据的高可靠;

在看TiDB源码之前, 再简单回顾一下TiDB的结构:

技术图片

 

本篇文章涉及的内容是上述橙色部分---TiDB-Server的代码;

TiDB-Server 是用go实现的,go的代码组织非常友好, 相比之下, C++ 和 Java 的各种编译脚本和代码依赖仓库管理非常复杂而且容易出错;

TiDB-Server编译之后生成的可执行文件是 tidb-server, 可以单独运行, 没有 tipd 和 tikv也能启动,实际上代码里面对 tipd和tikv实现了mock;你可以把 tidb-server理解成一个mysql-server;

因为篇幅所限, 这里只介绍一下大体流程; 让我们对数据库的实现有一个简单的认识;

假设我们在mysql客户端执行了一条insert语句---"insert into t1 values("zhangshan", 5000000);" ,这条语句是怎样被TiDB-Server执行的呢? 

先看看mysql客户端接入部分的代码:

技术图片

 

连接上来之后, 会读取mysql客户端数据, 按照mysql 客户端服务端协议进行解析;

技术图片

 

 注:我们下面对代码里面的变量举例时,用的都是这条sql---"insert into t1 values("zhangshan", 5000000);"

 我们看看cc.dispatch的实现

 技术图片

 

query类型的sql在 clientConn.handleQuery 里面处理:

技术图片

 

 一连串调用之后来到了session.execute, 我们看看实现:

技术图片

 

 session.execute里面做了这几件事:

  1. 通过语法和词法分析将sql解析为抽象语法树,进而生成一个InsertStmt结构体;

    语法分析和词法分析使用的是go语言版的yacc和lex;

    tidb用了一个工具ebnf2y(EBNF文法转 .y文件)将mysql的sql BNF文法转为了 parser.y,可以参见 github.com\\pingcap\\parser\\parser.y;

    值得一提的是,pingcap将sql解析器从tidb独立出来,可以方便的供其他项目使用;

  2. 优化sql, 生成执行计划;

    

  3. 执行sql;

    对于 insert 语句,将数据插入到 kv 中;

    tidb-server 中 mock kv 是直接把键值对保存在了 go 语言版的 leveldb 中;

 我们看看Insert语句对应的结构体:

技术图片

限于篇幅,暂时讲到这里,下篇我们一起进入 session.executeStatement 函数;

看 tidb 是怎样将列数据编码为 kv,插入到 go leveldb 中的;

 

以上是关于跟随一条insert语句, 进入TiDB的源码世界(上)的主要内容,如果未能解决你的问题,请参考以下文章

GDB 命令速查

insert带来的TiDB集群hang死血案

肤浅的聊聊关联子查询,数据集连接,TiDB代码,关系代数,等等

docker-compose.yml方式测试环境的TiDB修改事务允许的最大语句条数限制

使用insert语句SQL将数字递增1

mysql 和 TiDB 在 snapshot 隔离级别上的区别