這篇文章主要講解了“PostgreSQL中函數(shù)StartTransaction的實(shí)現(xiàn)邏輯是什么”,文中的講解內(nèi)容簡(jiǎn)單清晰,易于學(xué)習(xí)與理解,下面請(qǐng)大家跟著小編的思路慢慢深入,一起來研究和學(xué)習(xí)“PostgreSQL中函數(shù)StartTransaction的實(shí)現(xiàn)邏輯是什么”吧!

創(chuàng)新互聯(lián)公司專注為客戶提供全方位的互聯(lián)網(wǎng)綜合服務(wù),包含不限于網(wǎng)站設(shè)計(jì)、成都網(wǎng)站建設(shè)、榮縣網(wǎng)絡(luò)推廣、微信小程序定制開發(fā)、榮縣網(wǎng)絡(luò)營(yíng)銷、榮縣企業(yè)策劃、榮縣品牌公關(guān)、搜索引擎seo、人物專訪、企業(yè)宣傳片、企業(yè)代運(yùn)營(yíng)等,從售前售中售后,我們都將竭誠(chéng)為您服務(wù),您的肯定,是我們最大的嘉獎(jiǎng);創(chuàng)新互聯(lián)公司為所有大學(xué)生創(chuàng)業(yè)者提供榮縣建站搭建服務(wù),24小時(shí)服務(wù)熱線:18982081108,官方網(wǎng)址:chinadenli.net
靜態(tài)變量
當(dāng)前事務(wù)狀態(tài)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通常指向當(dāng)前事務(wù)塊.
* 如不處于事務(wù)中或者處于頂層事務(wù)中,則指向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保存所有尚未在XLOG_XACT_ASSIGNMENT記錄的子事務(wù).
*/
static int nUnreportedXids;
static TransactionId unreportedXids[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和command ID全局計(jì)數(shù)器,對(duì)事務(wù)可見,在state棧中不記錄這些信息.
*/
static SubTransactionId currentSubTransactionId;
static CommandId currentCommandId;
static bool currentCommandIdUsed;TransactionState
事務(wù)狀態(tài)結(jié)構(gòu)體
/* * transaction states - transaction state from server perspective * 事務(wù)狀態(tài)枚舉 - 服務(wù)器視角的事務(wù)狀態(tài) */ typedef enum TransState { TRANS_DEFAULT, /* idle 空閑 */ TRANS_START, /* transaction starting 事務(wù)啟動(dòng) */ TRANS_INPROGRESS, /* inside a valid transaction 進(jìn)行中 */ TRANS_COMMIT, /* commit in progress 提交中 */ TRANS_ABORT, /* abort in progress 回滾中 */ TRANS_PREPARE /* prepare in progress 準(zhǔn)備中 */ } TransState; /* * transaction block states - transaction state of client queries * 事務(wù)塊狀態(tài) - 客戶端查詢的事務(wù)狀態(tài) * * Note: the subtransaction states are used only for non-topmost * transactions; the others appear only in the topmost transaction. * 注意:subtransaction只用于非頂層事務(wù);其他字段用于頂層事務(wù). */ typedef enum TBlockState { /* not-in-transaction-block states 未進(jìn)入事務(wù)塊狀態(tài) */ TBLOCK_DEFAULT, /* idle 空閑 */ TBLOCK_STARTED, /* running single-query transaction 單個(gè)查詢事務(wù) */ /* transaction block states 事務(wù)塊狀態(tài) */ TBLOCK_BEGIN, /* starting transaction block 開始事務(wù)塊 */ TBLOCK_INPROGRESS, /* live transaction 進(jìn)行中 */ TBLOCK_IMPLICIT_INPROGRESS, /* live transaction after implicit BEGIN 隱式事務(wù),進(jìn)行中 */ TBLOCK_PARALLEL_INPROGRESS, /* live transaction inside parallel worker 并行worker中的事務(wù),進(jìn)行中 */ 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 進(jìn)行中,接收到ROLLBACK */ TBLOCK_PREPARE, /* live xact, PREPARE received 進(jìn)行中,接收到PREPARE */ /* subtransaction states 子事務(wù)狀態(tài) */ TBLOCK_SUBBEGIN, /* starting a subtransaction 開啟 */ TBLOCK_SUBINPROGRESS, /* live subtransaction 進(jìn)行中 */ TBLOCK_SUBRELEASE, /* RELEASE received 接收到RELEASE */ TBLOCK_SUBCOMMIT, /* COMMIT received while TBLOCK_SUBINPROGRESS 進(jìn)行中,接收到COMMIT */ TBLOCK_SUBABORT, /* failed subxact, awaiting ROLLBACK 失敗,等待ROLLBACK */ TBLOCK_SUBABORT_END, /* failed subxact, ROLLBACK received 失敗,已接收ROLLBACK */ TBLOCK_SUBABORT_PENDING, /* live subxact, ROLLBACK received 進(jìn)行中,接收到ROLLBACK */ TBLOCK_SUBRESTART, /* live subxact, ROLLBACK TO received 進(jìn)行中,接收到ROLLBACK TO */ TBLOCK_SUBABORT_RESTART /* failed subxact, ROLLBACK TO received 失敗,已接收ROLLBACK TO */ } TBlockState; /* * transaction state structure * 事務(wù)狀態(tài)結(jié)構(gòu)體 */ typedef struct TransactionStateData { //事務(wù)ID TransactionId transactionId; /* my XID, or Invalid if none */ //子事務(wù)ID SubTransactionId subTransactionId; /* my subxact ID */ //保存點(diǎn)名稱 char *name; /* savepoint name, if any */ //保存點(diǎn)級(jí)別 int savepointLevel; /* savepoint level */ //低級(jí)別的事務(wù)狀態(tài) TransState state; /* low-level state */ //高級(jí)別的事務(wù)狀態(tài) TBlockState blockState; /* high-level state */ //事務(wù)嵌套深度 int nestingLevel; /* transaction nesting depth */ //GUC上下文嵌套深度 int gucNestLevel; /* GUC context nesting depth */ //事務(wù)生命周期上下文 MemoryContext curTransactionContext; /* my xact-lifetime context */ //查詢資源 ResourceOwner curTransactionOwner; /* my query resources */ //按XID順序保存的已提交的子事務(wù)ID TransactionId *childXids; /* subcommitted child XIDs, in XID order */ //childXids數(shù)組大小 int nChildXids; /* # of subcommitted child XIDs */ //分配的childXids數(shù)組空間 int maxChildXids; /* allocated size of childXids[] */ //上一個(gè)CurrentUserId Oid prevUser; /* previous CurrentUserId setting */ //上一個(gè)SecurityRestrictionContext int prevSecContext; /* previous SecurityRestrictionContext */ //上一事務(wù)是否只讀? 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計(jì)數(shù)器 int parallelModeLevel; /* Enter/ExitParallelMode counter */ //父事務(wù)狀態(tài) struct TransactionStateData *parent; /* back link to parent */ } TransactionStateData; //結(jié)構(gòu)體指針 typedef TransactionStateData *TransactionState;
VirtualTransactionId
VirtualTransactionIDs由執(zhí)行事務(wù)的后臺(tái)進(jìn)程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.
* 最高層的事務(wù)通過VirtualTransactionIDs定義.
* VirtualTransactionIDs由執(zhí)行事務(wù)的后臺(tái)進(jìn)程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().
* 請(qǐng)注意,不能假設(shè)struct VirtualTransactionId作為一個(gè)整體是原子可分配的。
* 但是,類型LocalTransactionId是假定原子可分配的,同時(shí)后臺(tái)進(jìn)程ID不會(huì)經(jīng)常變換,因此這不是一個(gè)問題,
* 因此我們可以單獨(dú)提取或者分配這兩個(gè)域字段.
*
*/
typedef struct
{
BackendId backendId; /* determined at backend startup */
LocalTransactionId localTransactionId; /* backend-local transaction id */
} VirtualTransactionId;StartTransaction函數(shù),用于啟動(dòng)事務(wù),設(shè)置事務(wù)狀態(tài)為TRANS_INPROGRESS,CurrentTransactionState->state = TRANS_INPROGRESS.
/*
* StartTransaction
* 啟動(dòng)事務(wù)
*/
static void
StartTransaction(void)
{
TransactionState s;//事務(wù)狀態(tài)
VirtualTransactionId vxid;//虛擬事務(wù)ID
/*
* Let's just make sure the state stack is empty
* 確保事務(wù)棧是空的
*/
s = &TopTransactionStateData;
CurrentTransactionState = s;
Assert(XactTopTransactionId == InvalidTransactionId);
/* check the current transaction state */
//檢查當(dāng)前事務(wù)狀態(tài)
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.
* 在啟動(dòng)過程中設(shè)置當(dāng)前事務(wù)狀態(tài)信息。
* 請(qǐng)注意,一旦切換了事務(wù)狀態(tài),在后續(xù)獲取用戶ID和安全上下文標(biāo)志前,不會(huì)出現(xiàn)異常。
*/
s->state = TRANS_START;
//無效事務(wù)ID,待分配
s->transactionId = InvalidTransactionId; /* until assigned */
/*
* initialize current transaction state fields
* 初始化當(dāng)前事務(wù)狀態(tài)字段
*
* note: prevXactReadOnly is not used at the outermost level
* 注意:prevXactReadOnly不會(huì)在最外層中使用
*/
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.
* 一旦當(dāng)前用戶ID和安全上下文標(biāo)記已提取,即使事務(wù)啟動(dòng)失敗,也會(huì)正確地重置它們。
*/
GetUserIdAndSecContext(&s->prevUser, &s->prevSecContext);
/* SecurityRestrictionContext should never be set outside a transaction */
//SecurityRestrictionContext不應(yīng)在事務(wù)外設(shè)置
Assert(s->prevSecContext == 0);
/*
* Make sure we've reset xact state variables
* 確保已重置了xact狀態(tài)變量
*
* 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.
* 如仍處于恢復(fù)過程,標(biāo)志此事務(wù)為只讀.
* 在XLogInsert中和其他地方有低級(jí)別的保護(hù)機(jī)制確保在恢復(fù)過程中不會(huì)更新數(shù)據(jù),
* 只是給用戶正常的提示,說明事務(wù)只讀.
*/
if (RecoveryInProgress())
{
//只讀狀態(tài)
s->startedInRecovery = true;
XactReadOnly = true;
}
else
{
s->startedInRecovery = false;
XactReadOnly = DefaultXactReadOnly;
}
XactDeferrable = DefaultXactDeferrable;
XactIsoLevel = DefaultXactIsoLevel;
forceSyncCommit = false;
MyXactFlags = 0;
/*
* reinitialize within-transaction counters
* 重新初始化事務(wù)內(nèi)計(jì)數(shù)器
*/
s->subTransactionId = TopSubTransactionId;
currentSubTransactionId = TopSubTransactionId;
currentCommandId = FirstCommandId;
currentCommandIdUsed = false;
/*
* initialize reported xid accounting
* 初始化已報(bào)告的事務(wù)計(jì)數(shù)
*/
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.
* 分配新的本地事務(wù)ID(LocalTransactionId),
* 與backendId組成虛擬事務(wù)ID.
*/
vxid.backendId = MyBackendId;
vxid.localTransactionId = GetNextLocalTransactionId();
/*
* Lock the virtual transaction id before we announce it in the proc array
* 在proc array聲明前,鎖定虛擬事務(wù)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().
* 設(shè)置transaction_timestamp.
* 正常來說,期望該值與第一條命令的statement_timestamp一樣,這樣就不需要
* 調(diào)用GetCurrentTimestamp進(jìn)行刷新(昂貴的操作!).
* 但對(duì)于在過程中啟動(dòng)的事務(wù)(如非原子的SPI上下文),我們確實(shí)需要增加時(shí)間戳.
* 同樣的,在并行worker中,時(shí)間戳應(yīng)通過外層調(diào)用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. */
//標(biāo)記xactStopTimestamp未設(shè)置
xactStopTimestamp = 0;
/*
* initialize other subsystems for new transaction
* 為新事務(wù)初始化其他子系統(tǒng)(GUC/Cache等)
*/
AtStart_GUC();
AtStart_Cache();
AfterTriggerBeginXact();
/*
* done with start processing, set current transaction state to "in
* progress"
* 已完成啟動(dòng)過程,設(shè)置事務(wù)狀態(tài)為TRANS_INPROGRESS
*/
s->state = TRANS_INPROGRESS;
ShowTransactionState("StartTransaction");
}執(zhí)行begin,觸發(fā)該函數(shù)調(diào)用
11:10:36 (xdb@[local]:5432)testdb=# begin;
啟動(dòng)gdb,設(shè)置斷點(diǎn)
(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)
查看調(diào)用棧
(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}設(shè)置全局變量CurrentTransactionState = & TopTransactionStateData;
(gdb) n 1826 CurrentTransactionState = s; (gdb) 1828 Assert(XactTopTransactionId == InvalidTransactionId); (gdb)
初始化事務(wù)狀態(tài)
(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)
啟動(dòng)subsystem(內(nèi)存/GUC/Cache等)
(gdb) 1884 AtStart_Memory(); (gdb) n 1885 AtStart_ResourceOwner(); (gdb)
設(shè)置虛擬事務(wù)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)設(shè)置時(shí)間戳
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)初始化后的事務(wù)狀態(tài)
(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)完成調(diào)用
(gdb) n StartTransactionCommand () at xact.c:2719 2719 s->blockState = TBLOCK_STARTED; (gdb) 2720 break; (gdb)
感謝各位的閱讀,以上就是“PostgreSQL中函數(shù)StartTransaction的實(shí)現(xiàn)邏輯是什么”的內(nèi)容了,經(jīng)過本文的學(xué)習(xí)后,相信大家對(duì)PostgreSQL中函數(shù)StartTransaction的實(shí)現(xiàn)邏輯是什么這一問題有了更深刻的體會(huì),具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是創(chuàng)新互聯(lián),小編將為大家推送更多相關(guān)知識(shí)點(diǎn)的文章,歡迎關(guān)注!
分享標(biāo)題:PostgreSQL中函數(shù)StartTransaction的實(shí)現(xiàn)邏輯是什么
當(dāng)前鏈接:http://chinadenli.net/article16/jijedg.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供品牌網(wǎng)站制作、云服務(wù)器、外貿(mào)網(wǎng)站建設(shè)、微信小程序、定制開發(fā)、移動(dòng)網(wǎng)站建設(shè)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)