Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

What is the implementation logic of the function StartTransaction in PostgreSQL

2025-02-24 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Database >

Share

Shulou(Shulou.com)05/31 Report--

This article mainly explains "what is the implementation logic of function StartTransaction in PostgreSQL". The content of the explanation is simple and clear, and it is easy to learn and understand. Please follow the editor's train of thought to study and learn "what is the implementation logic of function StartTransaction in PostgreSQL".

I. data structure

Static variable

Current transaction status CurrentTransactionState

/ * * CurrentTransactionState always points to the current transaction state * block. It will point to TopTransactionStateData when not in a * transaction at all, or when in a top-level transaction. * CurrentTransactionState usually points to the current transaction block. * if you are not in a transaction or in a top-level transaction, point to TopTransactionStateData * / static TransactionStateData TopTransactionStateData = {.state = TRANS_DEFAULT, .blockState = TBLOCK_DEFAULT,}; / * unreportedXids holds XIDs of all subtransactions that have not yet been * reported in an XLOG_XACT_ASSIGNMENT record. * unreportedXids saves all sub-transactions that have not been recorded in XLOG_XACT_ASSIGNMENT. * / static int nUnreportedXids;static TransactionId unregulated Xids [PGPROC _ MAX_CACHED_SUBXIDS]; static TransactionState CurrentTransactionState = & TopTransactionStateData;/* * The subtransaction ID and command ID assignment counters are global * to a whole transaction, so we do not keep them in the state stack. * subtransaction ID and command ID global counters, visible to transactions, do not record this information in the state stack. * / static SubTransactionId currentSubTransactionId;static CommandId currentCommandId;static bool currentCommandIdUsed

TransactionState

Transaction state structure

/ * * transaction states-transaction state from server perspective * transaction status enumeration-transaction status from the server perspective * / typedef enum TransState {TRANS_DEFAULT, / * idle idle * / TRANS_START, / * transaction starting transaction startup * / TRANS_INPROGRESS, / * inside a valid transaction in progress * / TRANS_COMMIT / * commit in progress submitting * / TRANS_ABORT, / * abort in progress rollback * / TRANS_PREPARE / * prepare in progress preparing * /} TransState / * * transaction block states-transaction state of client queries * transaction block status-transaction status queried by the client * * Note: the subtransaction states are used only for non-topmost * transactions; the others appear only in the topmost transaction. * Note: subtransaction is only used for non-top-level transactions; other fields are used for top-level transactions. * / typedef enum TBlockState {/ * not-in-transaction-block states does not enter transaction block state * / TBLOCK_DEFAULT, / * idle idle * / TBLOCK_STARTED, / * running single-query transaction single query transaction * / / * transaction block states transaction block status * / TBLOCK_BEGIN, / * starting transaction block start transaction block * / TBLOCK_INPROGRESS / * live transaction in progress * / TBLOCK_IMPLICIT_INPROGRESS, / * live transaction after implicit BEGIN implicit transaction, in progress * / TBLOCK_PARALLEL_INPROGRESS, / * live transaction inside parallel worker transaction in parallel worker, in progress * / TBLOCK_END, / * COMMIT received received COMMIT * / TBLOCK_ABORT, / * failed xact, awaiting ROLLBACK failed Waiting for ROLLBACK * / TBLOCK_ABORT_END, / * failed xact, ROLLBACK received failed. Received ROLLBACK * / TBLOCK_ABORT_PENDING, / * live xact, ROLLBACK received in progress, received ROLLBACK * / TBLOCK_PREPARE, / * live xact, PREPARE received in progress, received PREPARE * / / * subtransaction states sub-transaction status * / TBLOCK_SUBBEGIN / * starting a subtransaction enabled * / TBLOCK_SUBINPROGRESS, / * live subtransaction in progress * / TBLOCK_SUBRELEASE, / * RELEASE received received RELEASE * / TBLOCK_SUBCOMMIT, / * COMMIT received while TBLOCK_SUBINPROGRESS in progress, received COMMIT * / TBLOCK_SUBABORT, / * failed subxact, awaiting ROLLBACK failed, wait for ROLLBACK * / TBLOCK_SUBABORT_END, / * failed subxact ROLLBACK received failed, received ROLLBACK * / TBLOCK_SUBABORT_PENDING, / * live subxact, ROLLBACK received in progress, received ROLLBACK * / TBLOCK_SUBRESTART, / * live subxact, ROLLBACK TO received in progress, received ROLLBACK TO * / TBLOCK_SUBABORT_RESTART / * failed subxact, ROLLBACK TO received failed, received ROLLBACK TO * /} TBlockState / * * transaction state structure * transaction state structure * / typedef struct TransactionStateData {/ / transaction ID TransactionId transactionId; / * my XID, or Invalid if none * / / sub-transaction ID SubTransactionId subTransactionId; / * my subxact ID * / / SavePoint name char * name; / * savepoint name, if any * / / SavePoint level int savepointLevel / * savepoint level * / / low-level transaction status TransState state; / * low-level state * / / High-level transaction status TBlockState blockState; / * high-level state * / transaction nesting depth int nestingLevel; / * transaction nesting depth * / GUC context nesting depth int gucNestLevel / * GUC context nesting depth * / / transaction lifecycle context MemoryContext curTransactionContext; / * my xact-lifetime context * / / query resources ResourceOwner curTransactionOwner; / * my query resources * / / committed subtransactions ID TransactionId * childXids; / * subcommitted child XIDs, in XID order * / / childXids array size int nChildXids saved in XID order / * # of subcommitted child XIDs * / / the allocated childXids array space int maxChildXids; / * allocated size of childXids [] * / the last CurrentUserId Oid prevUser; / * previous CurrentUserId setting * / / the last SecurityRestrictionContext int prevSecContext; / * previous SecurityRestrictionContext * / is the last transaction read-only? Bool prevXactReadOnly; / * entry-time xact rbino state * / / is it in Recovery? Is bool startedInRecovery; / * did we start in recovery? * / XID saved in WAL Record? Bool didLogXid; / * has xid been included in WAL record? * / / Enter/ExitParallelMode counter int parallelModeLevel; / * Enter/ExitParallelMode counter * / / parent transaction status struct TransactionStateData * parent; / * back link to parent * /} TransactionStateData;// structure pointer typedef TransactionStateData * TransactionState

VirtualTransactionId

VirtualTransactionIDs consists of the background process BackendId that executes the transaction and the LocalTransactionId that is logically allocated.

/ * 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. * the highest-level transaction is defined by VirtualTransactionIDs. * VirtualTransactionIDs consists of BackendId, a background process that executes transactions, and LocalTransactionId, which is logically allocated. * 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 () * Please note that struct VirtualTransactionId as a whole cannot be assumed to be atomically distributable. * however, the type LocalTransactionId assumes that the atom can be allocated, and the background process ID does not change often, so this is not a problem, * so we can extract or allocate these two fields separately. * * / typedef struct {BackendId backendId; / * determined at backend startup * / LocalTransactionId localTransactionId; / * backend-local transaction id * /} VirtualTransactionId; II. Source code interpretation

StartTransaction function, used to start the transaction, set the transaction state to TRANS_INPROGRESS,CurrentTransactionState- > state = TRANS_INPROGRESS.

/ * * StartTransaction * start transaction * / static voidStartTransaction (void) {TransactionState XactTopTransactionId / transaction status VirtualTransactionId vxid;// virtual transaction ID / * * Let's just make sure the state stack is empty * make sure the transaction stack is empty * / s = & TopTransactionStateData; CurrentTransactionState = s; Assert (XactTopTransactionId = = InvalidTransactionId) / * check the current transaction state * / / check the current transaction status 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. * set the current transaction status information during startup. * Please note that once the transaction status is switched, no exception will occur before obtaining the user ID and security context flag. * / s-> state = TRANS_START; / / invalid transaction ID, to be assigned s-> transactionId = InvalidTransactionId; / * until assigned * / / * * initialize current transaction state fields * initialize the current transaction status field * * note: prevXactReadOnly is not used at the outermost level * Note: prevXactReadOnly will not use * / s-> nestingLevel = 1 in the outermost layer; 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. * once the current user ID and security context tags have been extracted, they will be reset correctly even if the transaction fails to start. * / GetUserIdAndSecContext (& s-> prevUser, & s-> prevSecContext); / * SecurityRestrictionContext should never be set outside a transaction * / / SecurityRestrictionContext should not set Assert outside the transaction (s-> prevSecContext = = 0); / * * Make sure we've reset xact state variables * ensure that the xact state variables * * 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. * if it is still in the recovery process, it marks that the transaction is read-only. * there are low-level protection mechanisms in XLogInsert and elsewhere to ensure that data is not updated during recovery, * just to give users a normal hint that the transaction is read-only. * / if (RecoveryInProgress ()) {/ / read-only status s-> startedInRecovery = true; XactReadOnly = true;} else {s-> startedInRecovery = false; XactReadOnly = DefaultXactReadOnly;} XactDeferrable = DefaultXactDeferrable; XactIsoLevel = DefaultXactIsoLevel; forceSyncCommit = false; MyXactFlags = 0 / * * reinitialize within-transaction counters * reinitialize intra-transaction counters * / s-> subTransactionId = TopSubTransactionId; currentSubTransactionId = TopSubTransactionId; currentCommandId = FirstCommandId; currentCommandIdUsed = false; / * * initialize reported xid accounting * initialize reported transactions * / nUnreportedXids = 0; s-> didLogXid = false / * * must initialize resource-management stuff first * must first initialize the resource manager * / AtStart_Memory (); AtStart_ResourceOwner (); / * Assign a new LocalTransactionId, and combine it with the backendId to * form a virtual transaction id. * assign a new local transaction ID (LocalTransactionId), * form a virtual transaction ID. * / vxid.backendId = MyBackendId; vxid.localTransactionId = GetNextLocalTransactionId () with backendId; / * * Lock the virtual transaction id before we announce it in the proc array * lock the virtual transaction ID * / VirtualXactLockTableInsert (vxid) before the proc array declaration; / * Advertise it in the proc array. We assume assignment of * LocalTransactionID is atomic, and the backendId should be set already. * declare in proc array. * assume that LocalTransactionID is atomic and backendId has been allocated. * / 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 () * set transaction_timestamp. * normally, this value is expected to be the same as the statement_timestamp of the first command, so there is no need to * call GetCurrentTimestamp for refresh (expensive operation!). * but for transactions started during the process (such as non-atomic SPI contexts), we do need to add a timestamp. * similarly, in parallel worker, the timestamp should be provided through an outer call to SetParallelStartTimestamps. * / if (! IsParallelWorker ()) {if (! SPI_inside_nonatomic_context ()) xactStartTimestamp = stmtStartTimest else xactStartTimestamp = GetCurrentTimestamp ();} else Assert (xactStartTimestamp! = 0); pgstat_report_xact_timestamp (xactStartTimestamp); / * Mark xactStopTimestamp as unset. * / / Mark xactStopTimestamp not set xactStopTimestamp = 0; / * * initialize other subsystems for new transaction * initialize other subsystems for new transactions (GUC/Cache, etc.) * / AtStart_GUC (); AtStart_Cache (); AfterTriggerBeginXact () / * * done with start processing, set current transaction state to "in * progress" * has completed the startup process. Set the transaction status to TRANS_INPROGRESS * / s-> state = TRANS_INPROGRESS; ShowTransactionState ("StartTransaction").

Execute begin to trigger the function call

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

Start gdb and set breakpoint

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

View the call stack

(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)

View TopTransactionStateData global variables (not initialized yet)

(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}

Set the global variable CurrentTransactionState = & TopTransactionStateData

(gdb) n1826 CurrentTransactionState = s; (gdb) 1828 Assert (XactTopTransactionId = = InvalidTransactionId); (gdb)

Initialize the transaction state

(gdb) n1833 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)

Start subsystem (memory / GUC/Cache, etc.)

(gdb) 1884 AtStart_Memory (); (gdb) n1885 AtStart_ResourceOwner (); (gdb)

Set up virtual transaction 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) n1904 MyProc- > lxid = vxid.localTransactionId; (gdb)

Set timestamp

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

Initialize other fields

(gdb) n1935 s-> nestingLevel = 1; (gdb) n1936 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)

Transaction status after initialization

(gdb) p * swatches 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)

Complete the call

(gdb) nStartTransactionCommand () at xact.c:27192719 s-> blockState = TBLOCK_STARTED; (gdb) 2720 break; (gdb) Thank you for reading, this is the content of "what is the implementation logic of function StartTransaction in PostgreSQL". After the study of this article, I believe you have a deeper understanding of what the implementation logic of function StartTransaction in PostgreSQL is, and the specific use needs to be verified in practice. Here is, the editor will push for you more related knowledge points of the article, welcome to follow!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Database

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report