主页 > 手机  > 

Postgresql源码(121)事务状态中childXids的作用


总结

PG的子事务回滚是真回滚(直接回滚了,不管顶层事务提交还是回滚)。

PG的子事务提交是假提交(子事务提交后会把决定权交给顶层事务,随顶层事务提交、回滚)。

子事务提交后,将xid记录到父事务的childXids,父事务的childXids就表示下面已经提交的子事务,这些子事务xid在后续mvcc计算中,会完全等效与所属父事务xid。

childXids

在Postgresql的事务状态中,存在childXids数组,本篇分析该结构的用途和原理。

typedef struct TransactionStateData { ... TransactionId *childXids; /* subcommitted child XIDs, in XID order */ int nChildXids; /* # of subcommitted child XIDs */ int maxChildXids; /* allocated size of childXids[] */ ... struct TransactionStateData *parent; /* back link to parent */ } TransactionStateData; typedef TransactionStateData *TransactionState; 用途 1 读取childXids:TransactionIdIsCurrentTransactionId

判断事务ID是否为当前事务。

如果xid和当前事务的xid不同,另外会从当前事务记录的childXids中再找一遍。

因为childXids里面记录了当前事务下,已经提交了的子事务(只有提交了的,没有回滚的),所以这些提交的子事务xid就等同于主事务xid。childXids是有序的,二分法即可。 bool TransactionIdIsCurrentTransactionId(TransactionId xid) { ... if (TransactionIdEquals(xid, GetTopTransactionIdIfAny())) return true; ... for (s = CurrentTransactionState; s != NULL; s = s->parent) { ... low = 0; high = s->nChildXids - 1; while (low <= high) { int middle; TransactionId probe; middle = low + (high - low) / 2; probe = s->childXids[middle]; if (TransactionIdEquals(probe, xid)) return true; else if (TransactionIdPrecedes(probe, xid)) low = middle + 1; else high = middle - 1; } } return false; } 2 写入childXids:AtSubCommit_childXids

在子事务提交时,会执行AtSubCommit_childXids:

将本层的xid添加到上层事务的childXids中。将本层记录的childXids传递到上层事务的childXids中。 static void AtSubCommit_childXids(void) { ... new_nChildXids = s->parent->nChildXids + s->nChildXids + 1; ... s->parent->childXids[s->parent->nChildXids] = XidFromFullTransactionId(s->fullTransactionId); if (s->nChildXids > 0) memcpy(&s->parent->childXids[s->parent->nChildXids + 1], s->childXids, s->nChildXids * sizeof(TransactionId)); s->parent->nChildXids = new_nChildXids; /* Release child's array to avoid leakage */ if (s->childXids != NULL) pfree(s->childXids); /* We must reset these to avoid double-free if fail later in commit */ s->childXids = NULL; s->nChildXids = 0; s->maxChildXids = 0; }

PG子事务维护链式结构,当子事务提交时,需要把自己记录“commited childs”信息逐层上交。

例如三层子事务的场景下:

childXids top-transaction [] sub-transaction-16401 [] sub-transaction-16402 [] sub-transaction-16403 [] <-- will commit childXids top-transaction [] sub-transaction-16401 [] sub-transaction-16402 [] ^ | sub-transaction-16403 [] <-- committing childXids top-transaction [] sub-transaction-16401 [] sub-transaction-16402 [16403] <-- committed childXids top-transaction [] sub-transaction-16401 [] sub-transaction-16402 [16403] <-- will commit childXids top-transaction [] sub-transaction-16401 [16402, 16403] <-- committed

当前事务记录的childXids在进行mvcc判断时,完全等效于自己的xid。

3 其他

AtSubAbort_childXids:子事务回滚时,需要清理childXids。

SerializeTransactionState:序列化事务状态。

其他还有初始化、清理等,不在列举。

标签:

Postgresql源码(121)事务状态中childXids的作用由讯客互联手机栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“Postgresql源码(121)事务状态中childXids的作用