PostgreSQL数据库事务系统Low Layer——StartTransaction

网友投稿 940 2022-10-14

PostgreSQL数据库事务系统Low Layer——StartTransaction

PostgreSQL数据库事务系统Low Layer——StartTransaction

/* 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. */static TransactionStateData TopTransactionStateData = { .state = TRANS_DEFAULT, .blockState = TBLOCK_DEFAULT,};/* transaction state structure */typedef struct TransactionStateData { FullTransactionId fullTransactionId; /* my FullTransactionId */ // 当前事务XID SubTransactionId subTransactionId; /* my subxact ID */ // 子事务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 */ int gucNestLevel; /* GUC context nesting depth */ MemoryContext curTransactionContext; /* my xact-lifetime context */ ResourceOwner curTransactionOwner; /* my query resources */ TransactionId *childXids; /* subcommitted child XIDs, in XID order */ int nChildXids; /* # of subcommitted child XIDs */ int maxChildXids; /* allocated size of childXids[] */ Oid prevUser; /* previous CurrentUserId setting */ int prevSecContext; /* previous SecurityRestrictionContext */ bool prevXactReadOnly; /* entry-time xact r/o state */ bool startedInRecovery; /* did we start in recovery? */ bool didLogXid; /* has xid been included in WAL record? */ int parallelModeLevel; /* Enter/ExitParallelMode counter */ bool chain; /* start a new block after this one */ struct TransactionStateData *parent; /* back link to parent */} TransactionStateData;

StartTransaction函数的执行过程如下:

将全局变量CurrentTransactionState指向TopTransactionStateData,然后设置底层事务的状态为TRANS_START(从TRANS_DEFAULT到TRANS_START)。​​s = &TopTransactionStateData; CurrentTransactionState = s; s->state = TRANS_START;​​确保旧快照已经被释放,重置事务状态变量,并初始化事务内部计数器。

static void StartTransaction(void) { TransactionState s; VirtualTransactionId vxid; /* Let's just make sure the state stack is empty */ s = &TopTransactionStateData; CurrentTransactionState = s; Assert(!FullTransactionIdIsValid(XactTopFullTransactionId)); /* 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. */ s->state = TRANS_START; s->fullTransactionId = InvalidFullTransactionId; /* until assigned */ /* Determine if statements are logged in this transaction */ xact_is_sampled = log_xact_sample_rate != 0 && (log_xact_sample_rate == 1 || random() <= log_xact_sample_rate * MAX_RANDOM_VALUE); /* initialize current transaction state fields note: prevXactReadOnly is not used at the outermost level */ 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. */ GetUserIdAndSecContext(&s->prevUser, &s->prevSecContext); /* SecurityRestrictionContext should never be set outside a transaction */ Assert(s->prevSecContext == 0); /* Make sure we've reset 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 (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;

使用AtStart_Memory和AtStart_ResourceOwner函数分别完成内存上下文和资源-的初始化。​​PostgreSQL数据库事务系统——ResourceOwner​​

/* must initialize resource-management stuff first */ AtStart_Memory(); AtStart_ResourceOwner();

产生一个事务标识VXID给当前事务。顶层事务通过VirtualTransactionID来识别,VirtualTransactionID包含两个部分:BackendId和LocalTransactionId。其中BackendId就是运行此事务的进程ID号。LocalTransactionId通过调用GetNextLocalTransactionId函数进行分配。GetNextLocalTransactionId实现非常简单,通过一个全局变量nextLocalTransactionId来产生LocalTransactionId。分配完VirtualTransactionId之后,调用函数VirtualXactLockTableInsert锁住这个虚拟事务ID,最后再把VirtualTransactionID中的LocalTransactionId插入到当前进程队列PGPROC中。

/* Assign a new LocalTransactionId, and combine it with the backendId to form a virtual transaction id. */ vxid.backendId = MyBackendId; vxid.localTransactionId = GetNextLocalTransactionId(); /* Lock the virtual transaction id before we announce it in the proc array */ VirtualXactLockTableInsert(vxid); /* Advertise it in the proc array. We assume assignment of * LocalTransactionID is atomic, and the backendId should be set already. */ Assert(MyProc->backendId == vxid.backendId); MyProc->lxid = vxid.localTransactionId; TRACE_POSTGRESQL_TRANSACTION_START(vxid.localTransactionId);

设置时间戳。设置事务的开始时间戳(xactStartTimestamp)为当前命令开始的时间戳(stmtStartTimestamp),并初始化事务的结束时间戳为0。

/* 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(). */ 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 = 0;

初始化GUC、Cache等结构。到这里,启动事务所需要的操作已经基本完成。最后,把事务状态设置为TRANS_INPROGRESS。

/* initialize other subsystems for new transaction */ AtStart_GUC(); AtStart_Cache(); AfterTriggerBeginXact(); /* done with start processing, set current transaction state to "in progress" */ s->state = TRANS_INPROGRESS; ShowTransactionState("StartTransaction");

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:详解西部数据SMR叠瓦式硬盘的190二级编译器(译码表)模块
下一篇:PDF手册|1666页 Zabbix6.0官方中文 操作手册PDF免费领!
相关文章

 发表评论

暂时没有评论,来抢沙发吧~