返回顶部
首页 > 资讯 > 数据库 >PostgreSQL中函数AssignTransactionId的实现逻辑是什么
  • 410
分享到

PostgreSQL中函数AssignTransactionId的实现逻辑是什么

2024-04-02 19:04:59 410人浏览 八月长安
摘要

本篇内容介绍了“postgresql中函数AssignTransactionId的实现逻辑是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况

本篇内容介绍了“postgresql中函数AssignTransactionId的实现逻辑是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

一、数据结构

静态变量
当前事务状态CurrentTransactionState


static TransactionStateData TopTransactionStateData = {
    .state = TRANS_DEFAULT,
    .blockState = TBLOCK_DEFAULT,
};

static int  nUnreportedXids;
static TransactionId unreportedXids[PGPROC_MAX_CACHED_SUBXIDS];
static TransactionState CurrentTransactionState = &TopTransactionStateData;

static SubTransactionId currentSubTransactionId;
static CommandId currentCommandId;
static bool currentCommandIdUsed;

TransactionState
事务状态结构体


typedef enum TransState
{
    TRANS_DEFAULT,              
    TRANS_START,                
    TRANS_INPROGRESS,           
    TRANS_COMMIT,               
    TRANS_ABORT,                
    TRANS_PREPARE               
} TransState;

typedef enum TBlockState
{
    
    TBLOCK_DEFAULT,             
    TBLOCK_STARTED,             
    
    TBLOCK_BEGIN,               
    TBLOCK_INPROGRESS,          
    TBLOCK_IMPLICIT_INPROGRESS, 
    TBLOCK_PARALLEL_INPROGRESS, 
    TBLOCK_END,                 
    TBLOCK_ABORT,               
    TBLOCK_ABORT_END,           
    TBLOCK_ABORT_PENDING,       
    TBLOCK_PREPARE,             
    
    TBLOCK_SUBBEGIN,            
    TBLOCK_SUBINPROGRESS,       
    TBLOCK_SUBRELEASE,          
    TBLOCK_SUBCOMMIT,           
    TBLOCK_SUBABORT,            
    TBLOCK_SUBABORT_END,        
    TBLOCK_SUBABORT_PENDING,    
    TBLOCK_SUBRESTART,          
    TBLOCK_SUBABORT_RESTART     
} TBlockState;

typedef struct TransactionStateData
{
    //事务ID
    TransactionId transactionId;    
    //子事务ID
    SubTransactionId subTransactionId;  
    //保存点名称
    char       *name;           
    //保存点级别
    int         savepointLevel; 
    //低级别的事务状态
    TransState  state;          
    //高级别的事务状态
    TBlockState blockState;     
    //事务嵌套深度
    int         nestingLevel;   
    //GUC上下文嵌套深度
    int         gucNestLevel;   
    //事务生命周期上下文
    MemoryContext curTransactionContext;    
    //查询资源
    ResourceOwner curTransactionOwner;  
    //按XID顺序保存的已提交的子事务ID
    TransactionId *childXids;   
    //childXids数组大小
    int         nChildXids;     
    //分配的childXids数组空间
    int         maxChildXids;   
    //上一个CurrentUserId
    Oid         prevUser;       
    //上一个SecurityRestrictionContext
    int         prevSecContext; 
    //上一事务是否只读?
    bool        prevXactReadOnly;   
    //是否处于Recovery?
    bool        startedInRecovery;  
    //XID是否已保存在WAL Record中?
    bool        didLogXid;      
    //Enter/ExitParallelMode计数器
    int         parallelModeLevel;  
    //父事务状态
    struct TransactionStateData *parent;    
} TransactionStateData;
//结构体指针
typedef TransactionStateData *TransactionState;

二、源码解读

AssignTransactionId函数,给定的TransactionState分配一个新的持久化事务号XID,在此函数调用前,不会为事务分配XIDs.


static void
AssignTransactionId(TransactionState s)
{
    bool        isSubXact = (s->parent != NULL);
    ResourceOwner currentOwner;
    bool        log_unknown_top = false;
    
    //确保调用者没有搞砸
    Assert(!TransactionIdIsValid(s->transactionId));
    Assert(s->state == TRANS_INPROGRESS);
    
    if (IsInParallelMode() || IsParallelWorker())
        elog(ERROR, "cannot assign XIDs during a parallel operation");
    
    if (isSubXact && !TransactionIdIsValid(s->parent->transactionId))
    {
        TransactionState p = s->parent;
        TransactionState *parents;
        size_t      parentOffset = 0;
        parents = palloc(sizeof(TransactionState) * s->nestingLevel);
        while (p != NULL && !TransactionIdIsValid(p->transactionId))
        {
            parents[parentOffset++] = p;
            p = p->parent;
        }
        
        while (parentOffset != 0)
            AssignTransactionId(parents[--parentOffset]);
        pfree(parents);
    }
    
    if (isSubXact && XLogLogicalInfoActive() &&
        !TopTransactionStateData.didLogXid)
        log_unknown_top = true;
    
    s->transactionId = GetNewTransactionId(isSubXact);
    if (!isSubXact)
        XactTopTransactionId = s->transactionId;
    if (isSubXact)
        SubTransSetParent(s->transactionId, s->parent->transactionId);
    
    if (!isSubXact)
        ReGISterPredicateLockingXid(s->transactionId);
    
    currentOwner = CurrentResourceOwner;
    CurrentResourceOwner = s->curTransactionOwner;
    XactLockTableInsert(s->transactionId);
    CurrentResourceOwner = currentOwner;
    
    if (isSubXact && XLogStandbyInfoActive())
    {
        unreportedXids[nUnreportedXids] = s->transactionId;
        nUnreportedXids++;
        
        if (nUnreportedXids >= PGPROC_MAX_CACHED_SUBXIDS ||
            log_unknown_top)
        {
            xl_xact_assignment xlrec;
            
            xlrec.xtop = GetTopTransactionId();
            Assert(TransactionIdIsValid(xlrec.xtop));
            xlrec.nsubxacts = nUnreportedXids;
            XLogBeginInsert();
            XLogRegisterData((char *) &xlrec, MinSizeOfXactAssignment);
            XLogRegisterData((char *) unreportedXids,
                             nUnreportedXids * sizeof(TransactionId));
            (void) XLogInsert(RM_XACT_ID, XLOG_XACT_ASSIGNMENT);
            nUnreportedXids = 0;
            
            //标记为最顶层,而不是当前已记录日志的xact
            TopTransactionStateData.didLogXid = true;
        }
    }
}

三、跟踪分析

执行txid_current,触发函数调用

11:10:36 (xdb@[local]:5432)testdb=# begin;
BEGIN
11:40:20 (xdb@[local]:5432)testdb=#* select txid_current_if_assigned();
 txid_current_if_assigned 
--------------------------
(1 row)
11:40:43 (xdb@[local]:5432)testdb=#* select txid_current();

启动gdb,设置断点

(gdb) b AssignTransactionId
Breakpoint 5 at 0x546a4c: file xact.c, line 491.
(gdb) c
Continuing.
Breakpoint 5, AssignTransactionId (s=0xf9c720 <TopTransactionStateData>) at xact.c:491
491     bool        isSubXact = (s->parent != NULL);
(gdb)

查看调用栈

(gdb) bt
#0  AssignTransactionId (s=0xf9c720 <TopTransactionStateData>) at xact.c:491
#1  0x000000000054693D in GetTopTransactionId () at xact.c:392
#2  0x00000000009fe1f3 in txid_current (fcinfo=0x25835a0) at txid.c:443
#3  0x00000000006cfebd in ExecInterpExpr (state=0x25834b8, econtext=0x25831a8, isnull=0x7ffe3d4a31f7)
    at execExprInterp.c:654
#4  0x00000000006d1ac6 in ExecInterpExprStillValid (state=0x25834b8, econtext=0x25831a8, isNull=0x7ffe3d4a31f7)
    at execExprInterp.c:1786
#5  0x00000000007140dd in ExecEvalExprSwitchContext (state=0x25834b8, econtext=0x25831a8, isNull=0x7ffe3d4a31f7)
    at ../../../src/include/executor/executor.h:303
#6  0x000000000071414b in ExecProject (projInfo=0x25834b0) at ../../../src/include/executor/executor.h:337
#7  0x0000000000714323 in ExecResult (pstate=0x2583090) at nodeResult.c:136
#8  0x00000000006e4c30 in ExecProcNodeFirst (node=0x2583090) at execProcnode.c:445
#9  0x00000000006d9974 in ExecProcNode (node=0x2583090) at ../../../src/include/executor/executor.h:237
#10 0x00000000006dc22d in ExecutePlan (estate=0x2582e78, planstate=0x2583090, use_parallel_mode=false, 
    operation=CMD_SELECT, sendTuples=true, numberTuples=0, direction=ForwardScanDirection, dest=0x24cd0a0, 
    execute_once=true) at execMain.c:1723
#11 0x00000000006d9f5c in standard_ExecutorRun (queryDesc=0x256b0c8, direction=ForwardScanDirection, count=0, 
    execute_once=true) at execMain.c:364
#12 0x00000000006d9d7f in ExecutorRun (queryDesc=0x256b0c8, direction=ForwardScanDirection, count=0, execute_once=true)
    at execMain.c:307
#13 0x00000000008ccf5a in PortalRunSelect (portal=0x250c748, forward=true, count=0, dest=0x24cd0a0) at pquery.c:932
#14 0x00000000008ccbf3 in PortalRun (portal=0x250c748, count=9223372036854775807, isTopLevel=true, run_once=true, 
    dest=0x24cd0a0, altdest=0x24cd0a0, completionTag=0x7ffe3d4a3570 "") at pquery.c:773
#15 0x00000000008c6b1e in exec_simple_query (query_string=0x24a6ec8 "select txid_current();") at postgres.c:1145
#16 0x00000000008cae70 in PostgresMain (arGC=1, argv=0x24d2dc8, dbname=0x24d2c30 "testdb", username=0x24a3ba8 "xdb")
    at postgres.c:4182
    #17 0x000000000082642b in BackendRun (port=0x24c8c00) at postmaster.c:4361
---Type <return> to continue, or q <return> to quit---
#18 0x0000000000825b8f in BackendStartup (port=0x24c8c00) at postmaster.c:4033
#19 0x0000000000821f1c in ServerLoop () at postmaster.c:1706
#20 0x00000000008217b4 in PostmasterMain (argc=1, argv=0x24a1b60) at postmaster.c:1379
#21 0x00000000007488ef in main (argc=1, argv=0x24a1b60) at main.c:228

输入参数TransactionState(全局变量,指向TopTransactionStateData)

(gdb) p s
$13 = (TransactionState) 0xf9c720 <TopTransactionStateData>
(gdb) p *s
$14 = {transactionId = 0, subTransactionId = 1, name = 0x0, savepointLevel = 0, state = TRANS_INPROGRESS, 
  blockState = TBLOCK_INPROGRESS, nestingLevel = 1, gucNestLevel = 1, curTransactionContext = 0x2523850, 
  curTransactionOwner = 0x24d4868, childXids = 0x0, nChildXids = 0, maxChildXids = 0, prevUser = 10, prevSecContext = 0, 
  prevXactReadOnly = false, startedInRecovery = false, didLogXid = false, parallelModeLevel = 0, parent = 0x0}
(gdb)

初始化部分变量并验证

(gdb) n
493     bool        log_unknown_top = false;
(gdb) 
496     Assert(!TransactionIdIsValid(s->transactionId));
(gdb) 
497     Assert(s->state == TRANS_INPROGRESS);
(gdb)

获取事务号

(gdb) 
503     if (IsInParallelMode() || IsParallelWorker())
(gdb) 
512     if (isSubXact && !TransactionIdIsValid(s->parent->transactionId))
(gdb) 
545     if (isSubXact && XLogLogicalInfoActive() &&
(gdb) 
557     s->transactionId = GetNewTransactionId(isSubXact);
(gdb) 
558     if (!isSubXact)
(gdb) p s->transactionId
$15 = 2407
(gdb)

注册,并设置其他信息

(gdb) n
559         XactTopTransactionId = s->transactionId;
(gdb) 
561     if (isSubXact)
(gdb) 
568     if (!isSubXact)
(gdb) 
569         RegisterPredicateLockingXid(s->transactionId);
(gdb) 
576     currentOwner = CurrentResourceOwner;
(gdb) 
577     CurrentResourceOwner = s->curTransactionOwner;
(gdb) 
579     XactLockTableInsert(s->transactionId);
(gdb) 
581     CurrentResourceOwner = currentOwner;
(gdb) 
601     if (isSubXact && XLogStandbyInfoActive())
(gdb) 
635 }

完成调用

(gdb) 
GetTopTransactionId () at xact.c:393
393     return XactTopTransactionId;
(gdb)

“Postgresql中函数AssignTransactionId的实现逻辑是什么”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注编程网网站,小编将为大家输出更多高质量的实用文章!

您可能感兴趣的文档:

--结束END--

本文标题: PostgreSQL中函数AssignTransactionId的实现逻辑是什么

本文链接: https://lsjlt.com/news/64274.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作