• Postgresql源码(71)子事务数据结构与DDL分析


    相关
    子事务的可见性判断、性能问题请看这篇:《Postgresql源码(25)子事务可见性判断和性能问题》
    子事务的DDL和数据结构请看这篇:《Postgresql源码(71)子事务数据结构与DDL分析》

    1 SAVEPOINT、ROLLBACK执行细节

    测试用例

    drop table table1;
    create table table1(i int);
    
    BEGIN;
        INSERT INTO table1 VALUES (1);
        -- s1
        SAVEPOINT my_savepoint1;
        INSERT INTO table1 VALUES (2);
        
        -- s2
        SAVEPOINT my_savepoint2;
        INSERT INTO table1 VALUES (3);
    
        -- rollback to s2
        ROLLBACK TO SAVEPOINT my_savepoint2;
        SELECT * FROM table1;               -- shows rows 1 and 2
        
        -- release s2
        RELEASE SAVEPOINT my_savepoint2;
    
        -- rollback to s1
        ROLLBACK TO SAVEPOINT my_savepoint1;
        SELECT * FROM table1;               -- shows only row 1
    COMMIT;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    1.1 执行SAVEPOINT my_savepoint;

    在执行时,由ProcessUtility模块执行DefineSavepoint完成DDL(因为是第一次申请,所以申请时的事务内存上下文是TopTransactionContext)完成后走到顶层事务处理模块,走finish_xact_command->CommitTransactionCommand完成事务状态转移和收尾。

    • 【DDL】:部分执行PushTransaction函数,将当前CurrentTransactionState切换为新建的子事务TransactionState。
      • nestingLevel加一;
      • 事务块流转状态变为TBLOCK_SUBBEGIN;
    • 【CommitTransactionCommand】:完成收尾工作,在顶层内存事务内存上下文申请新的CurTransactionContext,记录在CurrentTransactionState->curTransactionContext和全局变量CurTransactionContext中。
      在这里插入图片描述

    1.2 执行ROLLBACK TO SAVEPOINT my_savepoint;

    • 【DDL】:标记事务块状态。
    • 【CommitTransactionCommand】:清理资源、标记子事务ID abort、弹出父事务、重新拉起一个同名子事务。
      在这里插入图片描述

    2 子事务ID分配

    流程

    1. 事务ID都是在写发生之前申请的,savepoint语句并不会产生事务ID。
    2. 子事务ID和事务ID使用一套分配机制,区别是申请完了记录的位置不同:
    • 普通事务ID只有一个记录在PGPROC->xid中。
    • 子事务ID可能有多个(申请多个检查点),多个值记录在PGPROC->subxids数组中,同时每个PGPROC维护一个subxidStates,记录有多少个子事务、子事务数量是不是已经超了(最多存64个),参考下面第二张图。
    1. 注意SubTransSetParent保存的内容:用xid查找自己的父事务ID。参考这一篇《Postgresql源码(25)子事务可见性判断和性能问题》
      在这里插入图片描述

    子事务相关数据结构:
    在这里插入图片描述

    3 子事务pg_subtrans

    总结:通过xid找到parenet xid的slru数据结构,之前的很多文章提到过。参考这一篇《Postgresql源码(25)子事务可见性判断和性能问题》

    4 子事务的两阶段提交

    涉及子事务的事务提交时,需要把涉及到的所有子事务全部提交掉。

    按照TransactionIdSetTreeStatus函数的逻辑,如果子事务状态和顶层事务全部在一个CLOG页面,那么拿一个CLOG锁就可以搞定了。

    但是如果子事务状态 和 父事务不在一个CLOG页面上,那么由于每次还是只拿一个页面的锁,操作就变成了两阶段完成,第一阶段把所有子事务改成TRANSACTION_STATUS_SUB_COMMITTED。当所有子事务都为TRANSACTION_STATUS_SUB_COMMITTED后,在修改父事务状态为TRANSACTION_STATUS_COMMITTED,然后再把子事务的状态配置为TRANSACTION_STATUS_COMMITTED。

    下面是官方案例:

     * Example:
     *		TransactionId t commits and has subxids t1, t2, t3, t4
     *		t is on page p1, t1 is also on p1, t2 and t3 are on p2, t4 is on p3
     *		1. update pages2-3:
     *					page2: set t2,t3 as sub-committed
     *					page3: set t4 as sub-committed
     *		2. update page1:
     *					set t1 as sub-committed,
     *					then set t as committed,
    					then set t1 as committed
     *		3. update pages2-3:
     *					page2: set t2,t3 as committed
     *					page3: set t4 as committed
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
  • 相关阅读:
    【数据结构】图的广度优先遍历
    前端开发:JS中==和===的对比总结
    【网络安全自学宝典】从零开始自学网络安全,按照这个路线就可以了
    消息队列选型之 Kafka vs RabbitMQ
    【吴恩达机器学习笔记】十三、异常检测
    排序算法(Java版)
    SQL 的执行流程是什么样的
    TypeScript基础知识点
    【学习笔记】ARC147/ARC141/ARC145
    初级算法_字符串 --- 有效的字母异位词
  • 原文地址:https://blog.csdn.net/jackgo73/article/details/126366335