暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

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

wukong 2024-09-20
63

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

1. 执行条件

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

2. 执行操作

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的研发。

「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论