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

技术PostgreSQL中函数StartTransaction的实现逻辑是什么这篇文章主要讲解了“PostgreSQL中函数StartTransaction的实现逻辑是什么”,文中的讲解内容简单清晰,易于学习与理解,下面

贺盛德贺盛德“PostgreSQL朱建安(音译)启动事务处理孙悟空(音译)",范登韦恩佐范登韦恩佐,云娥,何厚铧何厚铧何厚铧何厚铧,绿筠小姐“PostgreSQL朱建安(音译)启动事务处理孙悟空(音译)""哎哎!

一、数据结构

静态变量

你好currenttransactionstate(当前事务处理率)

/*

*当前交易速率移动当前交易速率(当前事务处理率)

*块它将指向太平洋

* transactionatall,或henianatop-level transaction(交易量高,或henianatop-level transaction ).

*当前交易率贺盛瑞贺盛瑞。

*你好你好你好,哎哎哎toptransactionstatedata

*/

静态交易数据=& amp大型旅行车的。state=TRANS_DEFAULT。blockState=TBLOCK_DEFAULT,

}:

/*

* unreported xid holds 6 to suspublications thathvnoter

* reportedianandload _ xact _ assign记录.

*未报告的氧化物云娥xload _ xact _ assignment(移转工单)405 .吴登盛。

*/

staticintnunreportedxids

静态站dun reported xis[pgproc _ max _ cached _ sub xis];

statutorsationstecurrencansatedata=顶级交易atedata

/*

* substancioniandcommandassignandcounter规则

*要完成交易,请播种edonotkeeptheminthestatestack。

*减法d你好commandID(命令身份证)李亚玲!李亚玲!李亚玲:李亚玲:李亚玲:李亚玲:李亚玲:李亚玲:李亚玲:李亚玲:李亚玲:李亚玲:李亚玲:李亚玲:李亚玲:李亚玲,吴经熊(音译),哦,天啊别动什么事。

*/

静态事务id当前事务id:

静态命令id当前命令:

静态cboolincurrentcommandidusedTransactionState

安其林安其林安其林安赛琳安赛琳安赛琳安赛琳安赛琳安赛琳安赛琳安赛琳安赛琳安赛琳安赛琳安赛琳安赛琳安赛琳安赛琳

/*

*事务状态-事务来自服务器前景

*杨俊钦先生-吴经熊,吴经熊,吴经熊,吴经熊,吴经熊,吴经熊,吴经熊,吴经熊,吴经熊,吴经熊,吴经熊,吴经熊,吴经熊,吴经熊,吴经熊,吴经熊,吴经熊,吴经熊,吴经熊,吴经熊

*/

typedefensumtransstate

{

TRANS_DEFAULT,nb

sp;           /* idle 空闲 */
    TRANS_START,                /* transaction starting 事务启动 */
    TRANS_INPROGRESS,           /* inside a valid transaction 进行中 */
    TRANS_COMMIT,               /* commit in progress 提交中 */
    TRANS_ABORT,                /* abort in progress 回滚中 */
    TRANS_PREPARE               /* prepare in progress 准备中 */
} TransState;
/*
 *  transaction block states - transaction state of client queries
 *  事务块状态 - 客户端查询的事务状态
 *
 * Note: the subtransaction states are used only for non-topmost
 * transactions; the others appear only in the topmost transaction.
 * 注意:subtransaction只用于非顶层事务;其他字段用于顶层事务.
 */
typedef enum TBlockState
{
    /* not-in-transaction-block states 未进入事务块状态 */
    TBLOCK_DEFAULT,             /* idle 空闲  */
    TBLOCK_STARTED,             /* running single-query transaction 单个查询事务 */
    /* transaction block states 事务块状态 */
    TBLOCK_BEGIN,               /* starting transaction block 开始事务块 */
    TBLOCK_INPROGRESS,          /* live transaction 进行中 */
    TBLOCK_IMPLICIT_INPROGRESS, /* live transaction after implicit BEGIN 隐式事务,进行中 */
    TBLOCK_PARALLEL_INPROGRESS, /* live transaction inside parallel worker 并行worker中的事务,进行中 */
    TBLOCK_END,                 /* COMMIT received 接收到COMMIT */
    TBLOCK_ABORT,               /* failed xact, awaiting ROLLBACK 失败,等待ROLLBACK */
    TBLOCK_ABORT_END,           /* failed xact, ROLLBACK received 失败,已接收ROLLBACK */
    TBLOCK_ABORT_PENDING,       /* live xact, ROLLBACK received 进行中,接收到ROLLBACK */
    TBLOCK_PREPARE,             /* live xact, PREPARE received 进行中,接收到PREPARE */
    /* subtransaction states 子事务状态 */
    TBLOCK_SUBBEGIN,            /* starting a subtransaction 开启 */
    TBLOCK_SUBINPROGRESS,       /* live subtransaction 进行中 */
    TBLOCK_SUBRELEASE,          /* RELEASE received 接收到RELEASE */
    TBLOCK_SUBCOMMIT,           /* COMMIT received while TBLOCK_SUBINPROGRESS 进行中,接收到COMMIT */
    TBLOCK_SUBABORT,            /* failed subxact, awaiting ROLLBACK 失败,等待ROLLBACK */
    TBLOCK_SUBABORT_END,        /* failed subxact, ROLLBACK received 失败,已接收ROLLBACK */
    TBLOCK_SUBABORT_PENDING,    /* live subxact, ROLLBACK received 进行中,接收到ROLLBACK */
    TBLOCK_SUBRESTART,          /* live subxact, ROLLBACK TO received 进行中,接收到ROLLBACK TO */
    TBLOCK_SUBABORT_RESTART     /* failed subxact, ROLLBACK TO received 失败,已接收ROLLBACK TO */
} TBlockState;
/*
 *  transaction state structure
 *  事务状态结构体
 */
typedef struct TransactionStateData
{
    //事务ID
    TransactionId transactionId;    /* my XID, or Invalid if none */
    //子事务ID
    SubTransactionId subTransactionId;  /* my subxact ID */
    //保存点名称
    char       *name;           /* savepoint name, if any */
    //保存点级别
    int         savepointLevel; /* savepoint level */
    //低级别的事务状态
    TransState  state;          /* low-level state */
    //高级别的事务状态
    TBlockState blockState;     /* high-level state */
    //事务嵌套深度
    int         nestingLevel;   /* transaction nesting depth */
    //GUC上下文嵌套深度
    int         gucNestLevel;   /* GUC context nesting depth */
    //事务生命周期上下文
    MemoryContext curTransactionContext;    /* my xact-lifetime context */
    //查询资源
    ResourceOwner curTransactionOwner;  /* my query resources */
    //按XID顺序保存的已提交的子事务ID
    TransactionId *childXids;   /* subcommitted child XIDs, in XID order */
    //childXids数组大小
    int         nChildXids;     /* # of subcommitted child XIDs */
    //分配的childXids数组空间
    int         maxChildXids;   /* allocated size of childXids[] */
    //上一个CurrentUserId
    Oid         prevUser;       /* previous CurrentUserId setting */
    //上一个SecurityRestrictionContext
    int         prevSecContext; /* previous SecurityRestrictionContext */
    //上一事务是否只读?
    bool        prevXactReadOnly;   /* entry-time xact r/o state */
    //是否处于Recovery?
    bool        startedInRecovery;  /* did we start in recovery? */
    //XID是否已保存在WAL Record中?
    bool        didLogXid;      /* has xid been included in WAL record? */
    //Enter/ExitParallelMode计数器
    int         parallelModeLevel;  /* Enter/ExitParallelMode counter */
    //父事务状态
    struct TransactionStateData *parent;    /* back link to parent */
} TransactionStateData;
//结构体指针
typedef TransactionStateData *TransactionState;

VirtualTransactionId
VirtualTransactionIDs由执行事务的后台进程BackendId和逻辑分配的LocalTransactionId组成.

/*
 * Top-level transactions are identified by VirtualTransactionIDs comprising
 * the BackendId of the backend running the xact, plus a locally-assigned
 * LocalTransactionId.  These are guaranteed unique over the short term,
 * but will be reused after a database restart; hence they should never
 * be stored on disk.
 * 最高层的事务通过VirtualTransactionIDs定义.
 * VirtualTransactionIDs由执行事务的后台进程BackendId和逻辑分配的LocalTransactionId组成.
 *
 * Note that struct VirtualTransactionId can not be assumed to be atomically
 * assignable as a whole.  However, type LocalTransactionId is assumed to
 * be atomically assignable, and the backend ID doesn't change often enough
 * to be a problem, so we can fetch or assign the two fields separately.
 * We deliberately refrain from using the struct within PGPROC, to prevent
 * coding errors from trying to use struct assignment with it; instead use
 * GET_VXID_FROM_PGPROC().
 * 请注意,不能假设struct VirtualTransactionId作为一个整体是原子可分配的。
 * 但是,类型LocalTransactionId是假定原子可分配的,同时后台进程ID不会经常变换,因此这不是一个问题,
 *   因此我们可以单独提取或者分配这两个域字段.
 * 
 */
typedef struct
{
    BackendId   backendId;      /* determined at backend startup */
    LocalTransactionId localTransactionId;  /* backend-local transaction id */
} VirtualTransactionId;

二、源码解读

StartTransaction函数,用于启动事务,设置事务状态为TRANS_INPROGRESS,CurrentTransactionState->state = TRANS_INPROGRESS.

/*
 *  StartTransaction
 *  启动事务
 */
static void
StartTransaction(void)
{
    TransactionState s;//事务状态
    VirtualTransactionId vxid;//虚拟事务ID
    /*
     * Let's just make sure the state stack is empty
     * 确保事务栈是空的
     */
    s = &TopTransactionStateData;
    CurrentTransactionState = s;
    Assert(XactTopTransactionId == InvalidTransactionId);
    /* check the current transaction state */
    //检查当前事务状态
    Assert(s->state == TRANS_DEFAULT);
    /*
     * Set the current transaction state information appropriately during
     * start processing.  Note that once the transaction status is switched
     * this process cannot fail until the user ID and the security context
     * flags are fetched below.
     * 在启动过程中设置当前事务状态信息。
     * 请注意,一旦切换了事务状态,在后续获取用户ID和安全上下文标志前,不会出现异常。
     */
    s->state = TRANS_START;
    //无效事务ID,待分配
    s->transactionId = InvalidTransactionId;    /* until assigned */
    /*
     * initialize current transaction state fields
     * 初始化当前事务状态字段
     *
     * note: prevXactReadOnly is not used at the outermost level
     * 注意:prevXactReadOnly不会在最外层中使用
     */
    s->nestingLevel = 1;
    s->gucNestLevel = 1;
    s->childXids = NULL;
    s->nChildXids = 0;
    s->maxChildXids = 0;
    /*
     * Once the current user ID and the security context flags are fetched,
     * both will be properly reset even if transaction startup fails.
     * 一旦当前用户ID和安全上下文标记已提取,即使事务启动失败,也会正确地重置它们。
     */
    GetUserIdAndSecContext(&s->prevUser, &s->prevSecContext);
    /* SecurityRestrictionContext should never be set outside a transaction */
    //SecurityRestrictionContext不应在事务外设置
    Assert(s->prevSecContext == 0);
    /*
     * Make sure we've reset xact state variables
     * 确保已重置了xact状态变量
     *
     * If recovery is still in progress, mark this transaction as read-only.
     * We have lower level defences in XLogInsert and elsewhere to stop us
     * from modifying data during recovery, but this gives the normal
     * indication to the user that the transaction is read-only.
     * 如仍处于恢复过程,标志此事务为只读.
     * 在XLogInsert中和其他地方有低级别的保护机制确保在恢复过程中不会更新数据,
     *   只是给用户正常的提示,说明事务只读.
     */
    if (RecoveryInProgress())
    {
        //只读状态
        s->startedInRecovery = true;
        XactReadOnly = true;
    }
    else
    {
        s->startedInRecovery = false;
        XactReadOnly = DefaultXactReadOnly;
    }
    XactDeferrable = DefaultXactDeferrable;
    XactIsoLevel = DefaultXactIsoLevel;
    forceSyncCommit = false;
    MyXactFlags = 0;
    /*
     * reinitialize within-transaction counters
     * 重新初始化事务内计数器
     */
    s->subTransactionId = TopSubTransactionId;
    currentSubTransactionId = TopSubTransactionId;
    currentCommandId = FirstCommandId;
    currentCommandIdUsed = false;
    /*
     * initialize reported xid accounting
     * 初始化已报告的事务计数
     */
    nUnreportedXids = 0;
    s->didLogXid = false;
    /*
     * must initialize resource-management stuff first
     * 必须首先初始化资源管理器
     */
    AtStart_Memory();
    AtStart_ResourceOwner();
    /*
     * Assign a new LocalTransactionId, and combine it with the backendId to
     * form a virtual transaction id.
     * 分配新的本地事务ID(LocalTransactionId),
     *   与backendId组成虚拟事务ID.
     */
    vxid.backendId = MyBackendId;
    vxid.localTransactionId = GetNextLocalTransactionId();
    /*
     * Lock the virtual transaction id before we announce it in the proc array
     * 在proc array声明前,锁定虚拟事务ID
     */
    VirtualXactLockTableInsert(vxid);
    /*
     * Advertise it in the proc array.  We assume assignment of
     * LocalTransactionID is atomic, and the backendId should be set already.
     * 在proc array中声明.
     * 假定LocalTransactionID是原子的,backendId已分配.
     */
    Assert(MyProc->backendId == vxid.backendId);
    MyProc->lxid = vxid.localTransactionId;
    TRACE_POSTGRESQL_TRANSACTION_START(vxid.localTransactionId);
    /*
     * set transaction_timestamp() (a/k/a now()).  Normally, we want this to
     * be the same as the first command's statement_timestamp(), so don't do a
     * fresh GetCurrentTimestamp() call (which'd be expensive anyway).  But
     * for transactions started inside procedures (i.e., nonatomic SPI
     * contexts), we do need to advance the timestamp.  Also, in a parallel
     * worker, the timestamp should already have been provided by a call to
     * SetParallelStartTimestamps().
     * 设置transaction_timestamp.
     * 正常来说,期望该值与第一条命令的statement_timestamp一样,这样就不需要
     *   调用GetCurrentTimestamp进行刷新(昂贵的操作!).
     * 但对于在过程中启动的事务(如非原子的SPI上下文),我们确实需要增加时间戳.
     * 同样的,在并行worker中,时间戳应通过外层调用SetParallelStartTimestamps提供.
     */
    if (!IsParallelWorker())
    {
        if (!SPI_inside_nonatomic_context())
            xactStartTimestamp = stmtStartTimestamp;
        else
            xactStartTimestamp = GetCurrentTimestamp();
    }
    else
        Assert(xactStartTimestamp != 0);
    pgstat_report_xact_timestamp(xactStartTimestamp);
    /* Mark xactStopTimestamp as unset. */
    //标记xactStopTimestamp未设置
    xactStopTimestamp = 0;
    /*
     * initialize other subsystems for new transaction
     * 为新事务初始化其他子系统(GUC/Cache等)
     */
    AtStart_GUC();
    AtStart_Cache();
    AfterTriggerBeginXact();
    /*
     * done with start processing, set current transaction state to "in
     * progress"
     * 已完成启动过程,设置事务状态为TRANS_INPROGRESS
     */
    s->state = TRANS_INPROGRESS;
    ShowTransactionState("StartTransaction");
}

三、跟踪分析

执行begin,触发该函数调用

11:10:36 (xdb@[local]:5432)testdb=# begin;

启动gdb,设置断点

(gdb) b StartTransaction
Breakpoint 4 at 0x54800f: file xact.c, line 1825.
(gdb) c
Continuing.
Breakpoint 4, StartTransaction () at xact.c:1825
1825        s = &TopTransactionStateData;
(gdb)

查看调用栈

(gdb) bt
#0  StartTransaction () at xact.c:1825
#1  0x0000000000548f50 in StartTransactionCommand () at xact.c:2718
#2  0x00000000008c8e7d in start_xact_command () at postgres.c:2500
#3  0x00000000008c6771 in exec_simple_query (query_string=0x24a6ec8 "begin;") at postgres.c:948
#4  0x00000000008cae70 in PostgresMain (argc=1, argv=0x24d2dc8, dbname=0x24d2c30 "testdb", username=0x24a3ba8 "xdb")
    at postgres.c:4182
#5  0x000000000082642b in BackendRun (port=0x24c8c00) at postmaster.c:4361
#6  0x0000000000825b8f in BackendStartup (port=0x24c8c00) at postmaster.c:4033
#7  0x0000000000821f1c in ServerLoop () at postmaster.c:1706
#8  0x00000000008217b4 in PostmasterMain (argc=1, argv=0x24a1b60) at postmaster.c:1379
#9  0x00000000007488ef in main (argc=1, argv=0x24a1b60) at main.c:228
(gdb)

查看TopTransactionStateData全局变量(尚未初始化)

(gdb) p TopTransactionStateData
$7 = {transactionId = 0, subTransactionId = 0, name = 0x0, savepointLevel = 0, state = TRANS_DEFAULT, 
  blockState = TBLOCK_DEFAULT, nestingLevel = 0, gucNestLevel = 0, curTransactionContext = 0x0, curTransactionOwner = 0x0, 
  childXids = 0x0, nChildXids = 0, maxChildXids = 0, prevUser = 10, prevSecContext = 0, prevXactReadOnly = false, 
  startedInRecovery = false, didLogXid = true, parallelModeLevel = 0, parent = 0x0}

设置全局变量CurrentTransactionState = & TopTransactionStateData;

(gdb) n
1826        CurrentTransactionState = s;
(gdb) 
1828        Assert(XactTopTransactionId == InvalidTransactionId);
(gdb)

初始化事务状态

(gdb) n
1833        if (s->state != TRANS_DEFAULT)
(gdb) 
1841        s->state = TRANS_START;
(gdb) 
1842        s->transactionId = InvalidTransactionId;    /* until assigned */
(gdb) 
1852        if (RecoveryInProgress())
(gdb) 
1859            s->startedInRecovery = false;
(gdb) 
1860            XactReadOnly = DefaultXactReadOnly;
(gdb) 
1862        XactDeferrable = DefaultXactDeferrable;
(gdb) 
1863        XactIsoLevel = DefaultXactIsoLevel;
(gdb) 
1864        forceSyncCommit = false;
(gdb) 
1865        MyXactFlags = 0;
(gdb) 
1870        s->subTransactionId = TopSubTransactionId;
(gdb) 
1871        currentSubTransactionId = TopSubTransactionId;
(gdb) 
1872        currentCommandId = FirstCommandId;
(gdb) 
1873        currentCommandIdUsed = false;
(gdb) 
1878        nUnreportedXids = 0;
(gdb) 
1879        s->didLogXid = false;
(gdb) 
1884        AtStart_Memory();
(gdb)

启动subsystem(内存/GUC/Cache等)

(gdb) 
1884        AtStart_Memory();
(gdb) n
1885        AtStart_ResourceOwner();
(gdb)

设置虚拟事务ID

1891        vxid.backendId = MyBackendId;
(gdb) 
1892        vxid.localTransactionId = GetNextLocalTransactionId();
(gdb) 
1897        VirtualXactLockTableInsert(vxid);
(gdb) 
1903        Assert(MyProc->backendId == vxid.backendId);
(gdb) p vxid
$8 = {backendId = 3, localTransactionId = 6}
(gdb) 
(gdb) n
1904        MyProc->lxid = vxid.localTransactionId;
(gdb)

设置时间戳

1906        TRACE_POSTGRESQL_TRANSACTION_START(vxid.localTransactionId);
(gdb) 
1917        if (!IsParallelWorker())
(gdb) 
1919            if (!SPI_inside_nonatomic_context())
(gdb) 
1920                xactStartTimestamp = stmtStartTimestamp;
(gdb) 
1926        pgstat_report_xact_timestamp(xactStartTimestamp);
(gdb) 
1928        xactStopTimestamp = 0;
(gdb) 
(gdb) p xactStartTimestamp
$9 = 601009839154257

初始化其他字段

(gdb) n
1935        s->nestingLevel = 1;
(gdb) n
1936        s->gucNestLevel = 1;
(gdb) 
1937        s->childXids = NULL;
(gdb) 
1938        s->nChildXids = 0;
(gdb) 
1939        s->maxChildXids = 0;
(gdb) 
1940        GetUserIdAndSecContext(&s->prevUser, &s->prevSecContext);
(gdb) 
1942        Assert(s->prevSecContext == 0);
(gdb) 
1947        AtStart_GUC();
(gdb) 
1948        AtStart_Cache();
(gdb) 
1949        AfterTriggerBeginXact();
(gdb) 
1955        s->state = TRANS_INPROGRESS;
(gdb) 
1957        ShowTransactionState("StartTransaction");
(gdb) 
1958    }
(gdb)

初始化后的事务状态

(gdb) p *s
$10 = {transactionId = 0, subTransactionId = 1, name = 0x0, savepointLevel = 0, state = TRANS_INPROGRESS, 
  blockState = TBLOCK_DEFAULT, 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
StartTransactionCommand () at xact.c:2719
2719                s->blockState = TBLOCK_STARTED;
(gdb) 
2720                break;
(gdb)

感谢各位的阅读,以上就是“PostgreSQL中函数StartTransaction的实现逻辑是什么”的内容了,经过本文的学习后,相信大家对PostgreSQL中函数StartTransaction的实现逻辑是什么这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是,小编将为大家推送更多相关知识点的文章,欢迎关注!

内容来源网络,如有侵权,联系删除,本文地址:https://www.230890.com/zhan/81162.html

(0)

相关推荐

  • 常见Python的Web开发框架有哪些呢

    技术常见Python的Web开发框架有哪些呢今天就跟大家聊聊有关常见Python的Web开发框架有哪些呢,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。  在今天,

    攻略 2021年11月16日
  • Python 列表

    技术Python 列表 Python 列表Python 集合(数组)
    Python 编程语言中有四种集合数据类型:
    列表(List)是一种有序和可更改的集合。允许重复的成员。列表是一个有序且可更改的集合

    礼包 2021年11月14日
  • golang中的原子操作atomic包

    技术golang中的原子操作atomic包 golang中的原子操作atomic包1. 概念 原子操作 atomic 包 加锁操作涉及到内核态的上下文切换,比较耗时,代价高, 针对基本数据类型我们还可以

    礼包 2021年11月10日
  • 临界区 sleep

    技术临界区 sleep 临界区 sleep24.1SleepIn some cases race conditions can be repeated when all but one thread a

    礼包 2021年10月28日
  • 怎么进行数据库账号管理及权限分配

    技术怎么进行数据库账号管理及权限分配怎么进行数据库账号管理及权限分配,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。在使用数据库过程中,我们通常需要添加账号以

    攻略 2021年12月2日
  • mysql中Too many connections问题怎么处理

    技术mysql中Too many connections问题怎么处理这篇文章将为大家详细讲解有关mysql中Too many connections问题怎么处理,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这

    攻略 2021年11月6日