Postgresql源码(60)事务系统总结
相关
《Postgresql源码(23)Clog使用的Slru页面淘汰机制》
《Postgresql源码(27)为什么事务提交会通过delayChkpt阻塞checkpoint》
《Postgresql源码(59)事务ID取值和判断规律总结》
《Postgresql源码(75)notify与listen执行流程分析》
相关
《Postgresql源码(93)Postgresql函数内事务控制实现原理(附带Oracle对比)》
重新总结下PG的事务管理系统:
PG中的事务处理按提供的功能可以分为两大部分:基本事务状态管理、子事务状态管理。
PG的事务系统总结起来一句话:用户命令触发状态机函数导致事务状态流转,流转时按对应状态调用底层事务处理函数干活。
1 状态机流转系统
用户命令触发状态机函数导致事务状态流转,流转时按对应状态调用底层事务处理函数干活。
状态机流转函数
12个状态机流转函数,可以分成三类。
- 包裹所有单行SQL的两个函数(进入SQL前StartTransactionCommand、SQL执行后CommitTransactionCommand),无论你执行的是begin、还是select 1,都会走一遍这两个函数。相当于事务状态的被动流转。
b StartTransactionCommand
b CommitTransactionCommand
- 事务块处理函数,对应用户事务命令,在PortalRun里面调用,主动流转事务状态。
// 系统内部调用回滚
b AbortCurrentTransaction
// 用户执行begin
b BeginTransactionBlock
// 用户执行commit
b EndTransactionBlock
// 用户执行rollback、abort
b UserAbortTransactionBlock
- 子事务状态流转。
b DefineSavepoint
b ReleaseSavepoint
b RollbackToSavepoint
b BeginInternalSubTransaction
b RollbackAndReleaseCurrentSubTransaction
b AbortOutOfAnyTransaction
底层事务处理函数
状态机流转时会调用底层函数干活,函数分两类
- 基础事务功能
// 启动事务时调用,配置事务状态,申请资源等
StartTransaction
// 事务正常提交是调用
CommitTransaction
// 事务回滚时调用,先调AbortTransaction,在调CleanupTransaction
CleanupTransaction
// 事务回滚时调用
AbortTransaction
- 子事务功能
StartSubTransaction
CommitSubTransaction
AbortSubTransaction
CleanupSubTransaction
2 底层事务处理函数做了什么?
StartTransaction
- 拿到vxid(由backendid和localid组合值)表示虚拟的事务id(写还未发生,不能分配真实xid)
- 用vxid注册MyProc,注册后在锁表中可以查询到vxid锁,表示事务启动了
- 事务状态流转到TRANS_INPROGRESS
StartTransaction// vxid = {backendId = 3, localTransactionId = 76407}GetNextLocalTransactionIdVirtualXactLockTableInsert...s->state = TRANS_INPROGRESS;...
CommitTransaction(事务内有写操作)
已分配事务ID的场景
- 事务状态流转TRANS_COMMIT
- 开启对于checkpoint的临界区:MyProc->delayChkpt = true(《Postgresql源码(27)为什么事务提交会通过delayChkpt阻塞checkpoint》)
- 写commit的事务日志、刷事务日志
- 写clog(不刷)TransactionIdCommitTree
- 清理ProcArray中的xid信息
- 清理其他
- 事务状态流转TRANS_DEFAULT
CommitTransactions->state = TRANS_COMMITRecordTransactionCommit[START_CRIT_SECTION][[MyProc->delayChkpt = true]]XactLogCommitRecordXLogFlushTransactionIdCommitTree[[MyProc->delayChkpt = false]][END_CRIT_SECTION]ProcArrayEndTransaction// 能拿到锁正常清理,拿不到锁加到list里面等着后面清理LWLockConditionalAcquire(ProcArrayLock, LW_EXCLUSIVE)// 正常清理:清理MyProc和ProcGlobal里面记录的xid信息ProcArrayEndTransactionInternal...// 清理...s->state = TRANS_DEFAULT
CommitTransaction(事务内无写操作)
未分配事务ID
- 事务状态流转TRANS_COMMIT
- 清理
- 事务状态流转TRANS_DEFAULT
CommitTransactions->state = TRANS_COMMITRecordTransactionCommit // do nothing// 清理s->state = TRANS_DEFAULT
3 事务ID分配
在真正要写数据前,会调用GetCurrentTransactionId,比如heap_insert。
- 拿一个新的xid
- 配置到MyProc->xid
- 配置到ProcGlobal->xids[MyProc->pgxactoff]
- xid加锁XactLockTableInsert
TransactionId
GetCurrentTransactionId(void)
{TransactionState s = CurrentTransactionState;if (!FullTransactionIdIsValid(s->fullTransactionId))AssignTransactionId(s);return XidFromFullTransactionId(s->fullTransactionId);
}
如果没分配过,执行AssignTransactionId拿一个新的xid分配给TransactionState。参考这一篇(《Postgresql源码(59)事务ID取值和判断规律总结》)
AssignTransactionId...GetNewTransactionId...MyProc->xid = xid;ProcGlobal->xids[MyProc->pgxactoff] = xid;...XactLockTableInsert...
4 子事务系统
例子:
drop table t1;
create table t1 (c1 int, c2 int);
begin;
insert into t1 values (1,1);
savepoint a;
insert into t1 values (2,1);
savepoint b;
insert into t1 values (3,1);
下面记录一些和普通事务的差异点:
事务状态:子事务会使CurrentTransactionState有多层结构,之间使用parent连接。
p *CurrentTransactionState
$39 = {fullTransactionId = {value = 4000071}, subTransactionId = 3, name = 0x199ca60 "b", savepointLevel = 0, state = TRANS_INPROGRESS, blockState = TBLOCK_SUBINPROGRESS, nestingLevel = 3, gucNestLevel = 3, curTransactionContext = 0x19de090, curTransactionOwner = 0x192a458, childXids = 0x0, nChildXids = 0, maxChildXids = 0, prevUser = 10, prevSecContext = 0, prevXactReadOnly = false, startedInRecovery = false, didLogXid = false, parallelModeLevel = 0, chain = false, assigned = false, parent = 0x199c558}p *CurrentTransactionState->parent
$40 = {fullTransactionId = {value = 4000070}, subTransactionId = 2, name = 0x199c6c0 "a", savepointLevel = 0, state = TRANS_INPROGRESS, blockState = TBLOCK_SUBINPROGRESS, nestingLevel = 2, gucNestLevel = 2, curTransactionContext = 0x19d7200, curTransactionOwner = 0x19164c8, childXids = 0x0, nChildXids = 0, maxChildXids = 0, prevUser = 10, prevSecContext = 0, prevXactReadOnly = false, startedInRecovery = false, didLogXid = true, parallelModeLevel = 0, chain = false, assigned = false, parent = 0xe6a940 <TopTransactionStateData>}p *CurrentTransactionState->parent->parent
$41 = {fullTransactionId = {value = 4000069}, subTransactionId = 1, name = 0x0, savepointLevel = 0, state = TRANS_INPROGRESS, blockState = TBLOCK_INPROGRESS, nestingLevel = 1, gucNestLevel = 1, curTransactionContext = 0x199c400, curTransactionOwner = 0x191e3e8, childXids = 0x0, nChildXids = 0, maxChildXids = 0, prevUser = 10, prevSecContext = 0, prevXactReadOnly = false, startedInRecovery = false, didLogXid = true, parallelModeLevel = 0, chain = false, assigned = false, parent = 0x0}
在分配事务ID时,每个子事务都会拿到自己的XID。
AssignTransactionId...SubTransSetParent(XidFromFullTransactionId(s->fullTransactionId),XidFromFullTransactionId(s->parent->fullTransactionId));
并把自己上一层的xid记录到subtrans中(SLRU页面和CLOG使用的是相同的机制,这篇讲了一部分《Postgresql源码(23)Clog使用的Slru页面淘汰机制》)。
子事务提交
- 除了上文(CommitTransaction(事务内有写操作))提到的步骤
- 在写CLOG时,和无子事务的情况有所区别
- 如果没有子事务,直接写CLOG即可
- 存在子事务时
- 在写CLOG时首先把子事务的XID配置SUB_COMMITTED状态到CLOG中
- 然后把父XID的提交状态配置进去
- 然后再把子事务的XID的状态从SUB_COMMITTED变成提交状态(类似于两阶段提交)
CommitTransactionRecordTransactionCommitTransactionIdCommitTreeTransactionIdSetTreeStatus// 一个CLOG页面全部搞定TransactionIdSetPageStatusTransactionIdSetPageStatusInternal// 每一个subxid都配置TRANSACTION_STATUS_SUB_COMMITTEDforTransactionIdSetStatusBit// 配置主事务的TransactionIdSetStatusBit// 再配置子事务的提交forTransactionIdSetStatusBit
Postgresql源码(60)事务系统总结相关推荐
- Postgresql源码(83)执行器的结果接收系统——DestReceiver
相关 <Postgresql源码(76)执行器专用元组格式TupleTableSlot> <Postgresql源码(82)SPI模块拆解分析一:执行简单SQL获取结果> &l ...
- postgresql源码学习(27)—— 事务日志⑦-日志落盘上层函数 XLogFlush
一. 预备知识 1. XLOG什么时候需要落盘 事务commit之前 log buffer被覆盖之前 后台进程定期落盘 2. 两个核心结构体 这两个结构体定义代码在xlog.c,它们在日志落盘过程中非 ...
- postgresql源码学习(49)—— MVCC⑤-cmin与cmax 同事务内的可见性判断
一. 难以理解的场景 postgresql源码学习(十九)-- MVCC④-可见性判断 HeapTupleSatisfiesMVCC函数_Hehuyi_In的博客-CSDN博客 在前篇的可见性判断中有 ...
- PostgreSQL源码分析
PostgreSQL源码结构 PostgreSQL的使用形态 PostgreSQL采用C/S(客户机/服务器)模式结构.应用层通过INET或者Unix Socket利用既定的协议与数据库服务器进行通信 ...
- java ipc pgsql_[转]PostgreSQL源码结构
PostgreSQL采用C/S(客户机/服务器)模式结构.应用层通过INET或者Unix Socket利用既定的协议与数据库服务器进行通信. 另外,还有一种'Standalone Backend'使用 ...
- 计算机毕业设计JAVA项目实训管理系统设计与实现mybatis+源码+调试部署+系统+数据库+lw
计算机毕业设计JAVA项目实训管理系统设计与实现mybatis+源码+调试部署+系统+数据库+lw 计算机毕业设计JAVA项目实训管理系统设计与实现mybatis+源码+调试部署+系统+数据库+lw ...
- java计算机毕业设计在线交友系统2021源码+mysql数据库+系统+lw文档+部署
java计算机毕业设计在线交友系统2021源码+mysql数据库+系统+lw文档+部署 java计算机毕业设计在线交友系统2021源码+mysql数据库+系统+lw文档+部署 本源码技术栈: 项目架构 ...
- java计算机毕业设计教师管理系统源码+mysql数据库+系统+lw文档+部署
java计算机毕业设计教师管理系统源码+mysql数据库+系统+lw文档+部署 java计算机毕业设计教师管理系统源码+mysql数据库+系统+lw文档+部署 本源码技术栈: 项目架构:B/S架构 开 ...
- java毕业设计校园招聘系统设计mybatis+源码+调试部署+系统+数据库+lw
java毕业设计校园招聘系统设计mybatis+源码+调试部署+系统+数据库+lw java毕业设计校园招聘系统设计mybatis+源码+调试部署+系统+数据库+lw 本源码技术栈: 项目架构:B/S ...
最新文章
- pycharm debug后会出现 step over /step into/step into my code /force step into /step out 分别表示...
- Python3中Pillow(PIL)介绍
- oracle9201怎么安装,Solaris10上安装64位Oracle9201
- mysql getinstance_php设计模式之单例模式使用示例
- jQuery的Tooltip插件
- php通过MongoClient扩展连接mongodb库的两点建议
- 为什么用dict.get(key)而不是dict [key]?
- 完全卸载Oracle数据库步骤
- MVC数据验证Model Validation
- 转载 侃一侃编译原理的“文法” 作者 :博客网 my笔触
- siki暗黑战神项目总结,框架和主要的优化点
- Android开发案例源码解析之使用sqlite数据库记录并读取GPS信息
- AWS云lamda实时判断IoTCore上传的数据并插入RDS中
- 将博客搬至CSDN_wuli大世界_新浪博客
- BeyondCompare4完美“破解“
- 【Spring学习笔记】AOP
- 2021-05-1java基础
- 利用计算机得到阻尼振动曲线的包络线公式,波尔共振实验阻尼系数的计算机拟合...
- 海龟 (turtle) 画图终极实战:小海龟挑战大迷宫游戏
- 走进京东 | 中国空间技术研究院青年创新联盟成员莅临参观京东总部
热门文章
- vnc viewer是什么,vnc viewer是什么,怎么用
- 新装linux系统(centOs7)使用nginx驱动vue项目
- 【转】Linux那些事儿 之 戏说USB(23)设备的生命线(二)
- 云原生时代崛起的编程语言Go常用标准库实战
- 2020年焊工(技师)多少分及格及焊工(技师)复审考试
- Android 一行代码搞定将错误日志放入到sd卡中且不需要任何权限,适配到android7.0
- 【Unity】一个使用Dorween实现的血量条显示与血量变化
- 关于Qt程序运行时出现:QSocketNotifier: Invalid socket 11 and type 'Read', disabling...
- 微信小程序消息订阅完整教程前端+后端。
- 二值图像的形态学处理