在这一章节,我们将实现从客户端输入 SQL 到数据写入分布式的 KV 数据库中的全链路。
详细的资料可以参考文章 TiDB 源码阅读系列文章(三)SQL 的一生,此处仅做简要说明。
- 1.
server/conn.go,当客户端连接到 TinySQL/TiDB 时,会开启一个 goroutine,会启动一个clientConn.Run函数,这个函数会不停的循环从客户端读取请求数据并执行。 - 2.
server/conn.go,不同种类的请求会在clientConn.dispatch进行分类,我们主要关注的 SQL 请求会在这里被解析为 SQL 字符串,然后交给clientConn.handleQuery函数执行。 - 3.
session/session.go,SQL 的执行会调用到TiDBContext.Execute函数进而调用session.Execute和session.execute,session.execute函数会负责一条 SQL 执行的生命周期,包括语法分析、优化、执行等阶段。- 3.1.
session/session.go,首先调用session.ParseSQL将 SQL 字符串转化为一颗或一些语法树,然后逐个执行。 - 3.2.
executor/compiler.go,Compiler.Compile将一颗语法树进行优化,依次生成逻辑执行计划和物理执行计划。 - 3.3.
session/session.go,通过session.executeStatement在runStmt函数中调用执行器的Exec函数。 - 3.4.
session/tidb.go,在执行完 Exec 函数后,如果没有出现错误,则调用session.StmtCommit方法将这一条语句 Commit 到整个事务所属的 membuffer 当中去。
- 3.1.
- 4.
executor/adapter.go,我们将ExecStmt.Exec函数的执行作为一个阶段,展开描述。- 4.1.
executor/adapter.go,ExecStmt.Exec会调用ExecStmt.buildExecutor,通过物理执行计划,构建执行器。 - 4.2.
executor/adapter.go,Executor是一个层叠的结构,在调用顶层的Executor.Open方法后,会传递到其中的子Executor当中,这一操作会递归地将所有的Executor都初始化。 - 4.3.
executor/adapter.go,在ExecStmt.handleNoDelay中,如果这个Executor不会返回结果,那么它会在ExecStmt.handleNoDelayExecutor函数内部立即执行。- 4.3.1.
executor/adapter.go,在ExecStmt.handleNoDelayExecutor通过Next函数递归执行Executor,这里会使用newFirstChunk函数来生成存储结果的Chunk,Chunk是一种使用 Apache Arrow 表达的数据格式。
- 4.3.1.
- 4.4.
executor/adapter.go,如果这个Executor会返回结果,那么执行器会被层层返回到第 2 步的clientConn.handleQuery中,随后在clientConn.writeResultset中调用执行clientConn.writeChunks执行,这么做的原因是为了流式的将执行的结果返回给客户端,而不是将所有结果存放在 DBMS 的内存中。在clientConn.writeChunks中,会调用ResultSet.Next函数来执行,每次调用会返回一条数据,直到返回的数据为空,说明执行完成。
- 4.1.
- 5.
executor/simple.go,在 4.3.1 阶段中,存在几种特殊的执行器,执行入口在SimpleExec.Next里,这里主要列举和事务相关的 Begin/Commit/Rollback。- 5.1.
executor/simple.go,SimpleExec.executeBegin会通过session/session.go中的session.NewTxn函数(被定义在sessionctx.Context接口中)来创建一个新的事务,如果此时这个 session 中有尚未提交的事务,NewTxn会先提交事务后开启一个新事务。在开启新事务后,会通过session.Txn函数(也被定义在sessionctx.Context接口中)等待这个事务获取到startTS。此外,begin 时会将环境变量中的mysql.ServerStatusInTrans设置为true。 - 5.2.
executor/simple.go,SimpleExec.executeCommit会将 5.1 中的mysql.ServerStatusInTrans变量设置为false。- 5.2.1.
session/tidb.go中的 finishStmt 会在第 4 结束时被调用,5.2 中将mysql.ServerStatusInTrans变量设置为false导致sessVars.InTxn()的返回值为false,此时会调用session.CommitTxn提交事务。
- 5.2.1.
- 5.3
executor/simple.go,SimpleExec.executeRollback也会将mysql.ServerStatusInTrans设置为false,但是会在executeRollback函数内部就对事物进行 Rollback。和 5.1 一样,会通过session.Txn函数来获取当前事务,但是不会等待事务激活(注意输入的参数)。如果获取到了事务,则会调用这个事务的Rollback方法进行清理。
- 5.1.
以上是 SQL 执行的关键链路,但是这个调用链路中的每一步都有关键函数被移除了,你需要根据调用链路的描述进行填充。