海山数据库(He3DB)源码详解:两阶段提交(2PC)事务块内核函数执行过程
本文介绍了两阶段提交(2PC)事务执行过程中,主要讲解事务的prepare阶段和commit阶段的内核函数执行过程。
前言
两阶段提交(2PC)是一种用于分布式系统的事务处理协议,旨在确保事务的原子性。以下是2PC从事务准备到提交或放弃的执行流程图:
graph TD
A[开始] --> B[事务发起者请求所有参与者准备]
B --> C{所有参与者是否准备好?}
C -- 是 --> D[事务发起者发送提交请求]
C -- 否 --> E[事务发起者发送放弃请求]
D --> F{所有参与者是否同意提交?}
F -- 是 --> G[所有参与者提交事务]
F -- 否 --> H[所有参与者放弃事务]
E --> I[所有参与者放弃事务]
G --> J[事务提交完成]
H --> J
I --> J
J --> K[结束]
流程说明:
- 开始:事务发起者(协调者)开始一个新的分布式事务。
- 事务发起者请求所有参与者准备:协调者向所有参与者发送准备请求,询问它们是否准备好提交事务。
- 所有参与者是否准备好?:这是一个决策点,需要等待所有参与者的响应。
- 是:如果所有参与者都准备好了,协调者将发送提交请求。
- 否:如果任何一个参与者没有准备好,协调者将发送放弃请求。
- 事务发起者发送提交请求:协调者向所有参与者发送提交事务的请求。
- 所有参与者是否同意提交?:这是另一个决策点,需要等待所有参与者的响应。
- 是:如果所有参与者都同意提交,它们将执行提交操作。
- 否:如果任何一个参与者拒绝提交,所有参与者将放弃事务。
- 所有参与者提交事务:参与者执行实际的提交操作,使事务永久生效。
- 所有参与者放弃事务:参与者执行回滚操作,撤销所有事务相关的更改。
- 事务提交完成:事务要么成功提交,要么被放弃,分布式事务到此结束。
- 结束:2PC过程完成。
处理TRANS_STMT_PREPARE
当终端输入PREPARE TRANSACTION xxx语句时,这时一个会发起2PC的事务提交准备过程。处理过程首先会调用PrepareTransactionBlock()函数,并根据返回值判断是否时错误结束发生回滚。
PrepareTransactionBlock()函数执行过程:
- 首先,该函数会调用EndTransactionBlock()函数,获得一个事务结束的返回值;
TransactionState s;
bool result;
/* Set up to commit the current transaction */
result = EndTransactionBlock(false);
- 然后,判断result的值,如果为true,修改其他block的状态;如果为false,表示事务出错,准备进行回滚;
if (result)
{
s = CurrentTransactionState;
while (s->parent != NULL)
s = s->parent;
if (s->blockState == TBLOCK_END)
{
/* Save GID where PrepareTransaction can find it again */
prepareGID = MemoryContextStrdup(TopTransactionContext, gid);
s->blockState = TBLOCK_PREPARE;
}
else
{
/*
* ignore case where we are not in a transaction;
* EndTransactionBlock already issued a warning.
*/
Assert(s->blockState == TBLOCK_STARTED ||
s->blockState == TBLOCK_IMPLICIT_INPROGRESS);
/* Don't send back a PREPARE result tag... */
result = false;
}
}
- 首先,获得当前事务的状态结构体,并找到事务的根节点;
- 之后,判断节点的状态是否为END,如果是,则将当前的gid深拷贝一份,交给全局静态变量prepareGID,并修改事务块的状态为TBLOCK_PREPARE;否则,将返回结构result改为false,准备进行回滚。
根据PrepareTransactionBlock()返回值对事务进行标记
如果PrepareTransactionBlock()函数的返回值为false,则会将事务标记为CMDTAG_ROLLBACK,这意味着当前的事务将被中止,并且事务所作的所有更新都会被丢弃,回到事务开始之前的状态。调用SetQueryCompletion()函数对传入参数qc进行修改,完成事务的标记。
处理TRANS_STMT_COMMIT_PREPARED
当终端输入COMMIT PREPARED xxx语句时,这时会发起一个2PC的事务提交过程。处理过程首先会调用PreventInTransactionBlock()函数,检查当前分