事务并发控制机制用来保证并发执行事务的情况下openGauss的ACID特性。下面将逐一介绍事务并发控制的各组成部分。
5.2.1 事务状态机
openGauss将事务系统分为上层(事务块TBlockState)以及底层(TransState)两个层次。
通过分层的设计,在处理上层业务时可以屏蔽具体细节,实现灵活支持客户端各类事务执行语句(BEGIN/START TRANSACTION/COMMIT/ROLLBACK/END)。
(1) 事务块TBlockState:客户端query的状态,用于提高用户操作数据的灵活性,用事务块的形式支持在一个事务中执行多条query语句。
(2) 底层事务TransState:内核端视角,记录了整个事务当前处于的具体状态。
1. 事务上层状态机
事务块上层状态机结构体代码如下:
{
/* 不在事务块中的状态:单条SQL语句 */
TBLOCK_DEFAULT,/* 事务块缺省状态 */
TBLOCK_STARTED,/*执行单条query 语句*/
/* 处于事务块中的状态:一个事务包含多条语句 */
TBLOCK_BEGIN,/* 遇到事务开始命令BEGIN/START TRANSACTION */
TBLOCK_INPROGRESS,/* 表明正在事务块处理过程中*/
TBLOCK_END,/ *遇到事务结束命令END/COMMIT */
TBLOCK_ABORT,/* 事务块内执行报错,等待客户端执行ROLLBACK */
TBLOCK_ABORT_END,/ *在事务块内执行报错后,接收客户端执行ROLLBACK */
TBLOCK_ABORT_PENDING,/* 事务块内执行成功,接收客户端执行ROLLBACK(期望事务回滚)*/
TBLOCK_PREPARE,/ *两阶段提交事务,收到PREPARE TRANSACTION命令*/
/* 子事务块状态,与上述事务块状态类似 */
TBLOCK_SUBBEGIN,/* 遇到子事务开始命令SAVEPOINT */
TBLOCK_SUBINPROGRESS,/* 表明正在子事务块处理过程中*/
TBLOCK_SUBRELEASE,/* 遇到子事务结束命令RELEASE SAVEPOINT */
TBLOCK_SUBCOMMIT,/* 遇到事务结束命令END/COMMIT 从最底层的子事务递归的提交到最顶层事务*/
TBLOCK_SUBABORT,/* 子事务块内执行报错,等待客户端ROLLBACK TO/ROLLBACK */
TBLOCK_SUBABORT_END,/* 在子事务块内执行报错后,接收到客户端ROLLBACK TO上层子事务/ROLLBACK */
TBLOCK_SUBABORT_PENDING,/* 子事务块内执行成功,接收客户端执行的ROLLBACK TO上层子事务/ROLLBACK */
TBLOCK_SUBRESTART,/* 子事务块内执行成功,收到ROLLBACK TO当前子事务*/
TBLOCK_SUBABORT_RESTART/* 子事务块内执行报错后,接收到ROLLBACK TO当前子事务*/
} TBlockState;
为了便于理解,可以先不关注子事务块的状态。当理解了主事务的状态机行为后,子事务块的状态机转换同父事务类似。父子事务的关系类似于一个栈的实现,父事务的子事务相较于父事务后开始先结束。
显式事务块的状态机及相应的转换函数如图5-2所示。
图5-2 事务块状态机
图5-2中的事务状态相对应的事务状态机结构体中的值如表5-1所示。
在无异常情形下,一个事务块的状态机如图5-2所示按照默认(TBLOCK_DEFAULT)->已开始(TBLOCK_STARTED)->事务块开启(TBLOCK_BEGIN)->事务块运行中(TBLOCK_INPROGRESS)->事务块结束(TBLOCK_END)->默认(TBLOCK_DEFAULT)循环。剩余的状态机是在上述正常场景下的各个状态点的异常处理分支。
(1) 在进入事务块运行中(TBLOCK_INPROGRESS)之前出错,因为事务还没有开启,直接报错并回滚,清理资源回到默认(TBLOCK_DEFAULT)状态。
(2) 在事务块运行中(TBLOCK_INPROGRESS)出错分为2种情形。事务执行失败:事务块运行中(TBLOCK_INPROGRESS)->回滚(TBLOCK_ABORT)->回滚结束(TBLOCK_ABORT_END)->默认(TBLOCK_DEFAULT);用户手动回滚执行成功的事务:事务块运行中(TBLOCK_INPROGRESS)->回滚等待(TBLOCK_ABORT_PENDING)->默认(TBLOCK_DEFAULT)。
(3) 在用户执行COMMIT语句时出错:事务块结束(TBLOCK_END)->默认(TBLOCK_DEFAULT)。由图5-2可以看出,事务开始后离开默认(TBLOCK_DEFAULT)状态,事务完全结束后回到默认(TBLOCK_DEFAULT)状态。
(4) openGauss同时还支持隐式事务块,当客户端执行单条SQL语句时可以自动提交,其状态机相对比较简单:按照默认(TBLOCK_DEFAULT)->已开始(TBLOCK_STARTED)->默认(TBLOCK_DEFAULT)循环。
**2. 事务底层状态
**TransState结构体代码如下:从内核视角的事务状态,真正意义上的事务状态。
{
TRANS_DEFAULT,/* 当前为空闲缺省状态,无事务开启*/
TRANS_START,/* 事务正在开启*/
TRANS_INPROGRESS,/* 事务开始完毕,进入事务运行中*/
TRANS_COMMIT,/* 事务正在提交*/
TRANS_ABORT,/* 事务正在回滚*/
TRANS_PREPARE/* 两阶段提交事务进入PREPARE TRANSACTION阶段*/
} TransState;
图5-3事务底层状态
内核内部底层状态如图5-3所示,底层状态机的描述见结构体TransState。
(1) 在事务开启前事务状态为TRANS_DEFAULT。
(2) 事务开启过程中事务状态为TRANS_START。
(3) 事务成功开启后一直处于TRANS_INPROGRESS。
(4) 事务结束/回滚的过程中为TARNS_COMMIT/ TRANS_ABORT。
(5) 事务结束后事务状态回到TRANS_DEFAULT。
3. 事务状态机系统实例
本小节给出一条SQL的状态机运转实例,有助于更好地理解内部事务如何运作。在客户端执行SQL语句:
BEGIN;
SELECT * FROM TABLE1;
END;
1) 整体流程
整体执行过程如图5-4,任何语句的执行总是先进入事务处理接口事务块中,然后调用事务底层函数处理具体命令,最后返回到事务块中。
图5-4 整体流程
2) BEGIN执行流程,如图5-5所示。
(1) 入口函数exec_simple_query处理begin命令。
(2) start_xact_command函数开始一个query命令,调用StartTransactionCommand函数,此时事务块上层状态未TBLOCK_DEFAULT,继续调用StartTransaction函数,设置事务底层状态TRANS_START,完成内存、缓存区、锁资源的初始化后将事务底层状态设为TRANS_INPROGRESS,最后在StartTransactionCommand函数中设置事务块上层状态为TBLOCK_STARTED。
(3) PortalRun函数处理begin语句,依次向下调用函数,最后调用BeginTransactionBlock函数转换事务块上层状态为TBLOCK_BEGIN。
(4) finish_xact_command函数结束一个query命令,调用CommitTransactionCommand函数设置事务块上层状态从TBLOCK_BEGIN变为TBLOCK_INPROGRESS,并等待读取下一条命令。
图5-5 BEGIN执行流程
3) SELECT执行流程,如图5-6所示。
(1) 入口函数exec_simple_query处理“SELECT * FROM table1;”命令。
(2) start_xact_command函数开始一个query命令,调用StartTransactionCommand函数,由于当前上层事务块状态为TBLOCK_INPROGRESS,说明已经在事务块内部,则直接返回,不改变事务上层以及底层的状态。
(3) PortalRun执行SELECT语句,依次向下调用函数ExecutorRun根据执行计划执行最优路径查询。
(4) finish_xact_command函数结束一条query命令,调用CommitTransactionCommand函数,当前事务块上层状态仍为TBLOCK_INPROGESS,不改变当前事务上层以及底层的状态。
图5-6 SELECT执行流程
4) END执行流程,如图5-7所示。
(1) 入口函数exec_simple_query处理end命令。
(2) start_xact_command函数开始一个query命令,调用StartTransactionCommand函数,当前上层事务块状态为TBLOCK_INPROGESS,表明事务仍然在进行,此时也不改变任何上层及底层事务状态。
(3) PortalRun函数处理end语句,依次调用processUtility函数,最后调用EndTransactionBlock函数对当前上层事务块状态机进行转换,设置事务块上层状态为TBLOCK_END。
(4) Finish_xact_command函数结束query命令,调用CommitTransactionCommand函数,当前事务块状态TBLOCK_END;继续调用CommitTransaction函数提交事务,设置事务底层状态为TRANS_COMMIT,进行事务提交流程并且清理事务资源;清理后设置底层事务状态为TRANS_DEFAULT,返回CommitTansactionCommand函数;设置事务块上层状态为TBLOCK_DEFAULT,整个事务块结束。
图5-7 END执行流程
4. 事务状态转换相关函数简述
1) 事务处理子函数:根据当前事务上层状态机,对事务的资源进行相应的申请、回收及清理。
具体介绍如表5-2所示。