海山数据库(He3DB)源码详解:RollbackToSavepoint函数

海山数据库(He3DB)源码详解:RollbackToSavepoint函数

1. 执行条件

执行ROLLBACK TO <savepoint>命令时,底层调用RollbackToSavepoint函数执行子事务回滚。

2. 执行流程

当然可以,下面是一个简化的 RollbackToSavepoint 语句的执行流程的框架图:
在这里插入图片描述

ROLLBACK过程执行流程

这个流程图描述了从开始执行 RollbackToSavepoint 命令到最终完成或发生错误的整个过程。每个步骤都是决策点或操作,其中:

  • B 代表解析 ROLLBACK TO SAVEPOINT 命令。
  • C 是一个决策点,检查保存点是否存在。
  • DJ 描述了正常的回滚流程。
  • K 是另一个决策点,检查在回滚过程中是否发生错误。
  • L 表示如果发生错误,则进行完全回滚。
  • M 表示成功返回回滚状态给客户端。
  • N 表示如果发生错误,则通知客户端。
  • O 表示操作完成。

请注意,这个流程图是一个高层次的抽象,实际的 PostgreSQL 源码实现会更加复杂,并且涉及到许多底层的函数和数据结构,因此本文会在下一节详细介绍源码的执行结果。

3. 源码解读

1、设定事务状态

获取当前事务状态,创建目标父节点和临时事务状态变量。

	TransactionState s = CurrentTransactionState;
	TransactionState target, xact;
	if (IsInParallelMode())
		ereport(ERROR,
			(errcode(ERRCODE_INVALID_TRANSACTION_STATE),
			 errmsg("cannot rollback to savepoints during a parallel 
                             operation")));
  1. 通过全局变量CurrentTransactionState获得当前事务状态,创建目标父节点事务状态变量target和临时事务状态变量xact;
  2. 检查当前事务是否为并行事务,是则报错退出。

2、检查事务块状态

通过switch-case结构检查当前事务块的状态。

    /* We can't rollback to a savepoint if there is no savepoint defined.*/
    case TBLOCK_INPROGRESS:
    case TBLOCK_ABORT:
        ereport(ERROR,
            (errcode(ERRCODE_S_E_INVALID_SPECIFICATION),
             errmsg("savepoint \"%s\" does not exist", name)));
        break;
    case TBLOCK_IMPLICIT_INPROGRESS:
        ereport(ERROR,
            (errcode(ERRCODE_NO_ACTIVE_SQL_TRANSACTION),
             errmsg("%s can only be used in transaction blocks", 
                     "ROLLBACK TO SAVEPOINT")));
        break;
    /* There is at least one savepoint, so proceed. */
    case TBLOCK_SUBINPROGRESS:
    case TBLOCK_SUBABORT:
        break;  
    /* These cases are invalid. */
    case TBLOCK_DEFAULT:
    /* ... */
        elog(FATAL, "RollbackToSavepoint: unexpected state %s",
                BlockStateAsString(s->blockState));
        break;
  1. 事务处于TBLOCK_SUBINPROGRESS或TBLOCK_SUBABORT状态:正确状态,跳出switch-case结构;
  2. 事务处于TBLOCK_INPROGRESS或TBLOCK_ABORT状态:错误的状态,两种状态下不存在SAVEPOINT,无法执行子事务回滚;
  3. 事务处于TBLOCK_IMPLICIT_INPROGRESS状态:无效的状态,隐式事务状态下无法执行子事务回归状态,不能执行ROLLBACK TO <savepoint> 命令;
  4. 事务处于除上述之外的其他状态:无效的状态,提交FATAL日志。

3、回溯寻找目标节点

通过for循环回溯链栈,寻找目标节点target。

	for (target = s; PointerIsValid(target); target = target->parent)
	{
		if (PointerIsValid(target->name) && strcmp(target->name, name) == 0)
			break;
	}
  1. PointerIsValid本质为宏定义,作用为判断参数是否为NULL;
  2. 判断target->name是否为空,且是否等于目标节点的name。如果为True,则跳出for循环;

4、检查目标节点

检查目标节点target的状态,同时检查保存点等级。

	if (!PointerIsValid(target))
		ereport(ERROR,
				(errcode(ERRCODE_S_E_INVALID_SPECIFICATION),
				 errmsg("savepoint \"%s\" does not exist", name)));
	/* disallow crossing savepoint level boundaries */
	if (target->savepointLevel != s->savepointLevel)
		ereport(ERROR,
				(errcode(ERRCODE_S_E_INVALID_SPECIFICATION),
				 errmsg("savepoint \"%s\" does not exist within current 
                                    savepoint level", name)));
  1. 跳出循环后,检查目标节点target是否有效;
  2. 检查目标节点的保存点等级和当前子事务点的保存点等级是否一致。

5、修改目标点之前的状态

将当前事务到目标节点之间的状态标记为ABORT PENDING或ABORT END状态。

	xact = CurrentTransactionState;
	for (;;)
	{
		if (xact == target)
			break;
		if (xact->blockState == TBLOCK_SUBINPROGRESS)
			xact->blockState = TBLOCK_SUBABORT_PENDING;
		else if (xact->blockState == TBLOCK_SUBABORT)
			xact->blockState = TBLOCK_SUBABORT_END;
		else
			elog(FATAL, "RollbackToSavepoint: unexpected state %s",
				 BlockStateAsString(xact->blockState));
		xact = xact->parent;
		Assert(PointerIsValid(xact));
	}
  1. 将全局状态变量CurrentTransactionState赋值给临时事务状态变量xact;
  2. 死循环中,检查临时变量xact是否为target节点,相同则跳出死循环;
  3. 如果临时变量xact的blockState为TBLOCK_SUBINPROGRESS,将事务块状态修改为TBLOCK_SUBABORT_PENDING;
  4. 如果临时变量xact的blockState为TBLOCK_SUBABORT,将事务块状态修改为TBLOCK_SUBABORT_END;
  5. 如果临时变量xact的事务块状态为其他状态,则提交FATAL日志;
  6. 将xact修改为父节点事务状态,判断修改后的事务状态是否有效,继续死循环。

6、修改目标点的状态

修改xact作为目标节点的事务块状态。

	/* And mark the target as "restart pending" */
	if (xact->blockState == TBLOCK_SUBINPROGRESS)
		xact->blockState = TBLOCK_SUBRESTART;
	else if (xact->blockState == TBLOCK_SUBABORT)
		xact->blockState = TBLOCK_SUBABORT_RESTART;
	else
		elog(FATAL, "RollbackToSavepoint: unexpected state %s",
			 BlockStateAsString(xact->blockState));
  1. 如果临时变量xact的blockState为TBLOCK_SUBINPROGRESS,将事务块状态修改为TBLOCK_SUBRESTART;
  2. 如果临时变量xact的blockState为TBLOCK_SUBABORT,将事务块状态修改为TBLOCK_SUBABORT_RESTART;
  3. 如果临时变量xact的事务块状态为其他状态,则提交FATAL日志;

完成RollbackToSavepoint函数。

作者介绍

李超,移动云数据库工程师,负责云原生数据库He3DB的研发。
RT,将事务块状态修改为TBLOCK_SUBABORT_RESTART;
3. 如果临时变量xact的事务块状态为其他状态,则提交FATAL日志;

完成RollbackToSavepoint函数。

作者介绍

李超,移动云数据库工程师,负责云原生数据库He3DB的研发。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值