当前位置:   article > 正文

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

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
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

用途

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;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

2 写入childXids:AtSubCommit_childXids

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

  1. 将本层的xid添加到上层事务的childXids中。
  2. 将本层记录的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;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

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

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

												childXids
top-transaction     		    []
  sub-transaction-16401     []
    sub-transaction-16402   []
      sub-transaction-16403 []        <-- will commit
  • 1
  • 2
  • 3
  • 4
  • 5
														childXids
top-transaction     		    		[]
  sub-transaction-16401     		[]
    sub-transaction-16402   		[]
    														^
    														|
      sub-transaction-16403 		[]				<-- committing
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
														childXids
top-transaction        					[]
  sub-transaction-16401     		[]
    sub-transaction-16402   		[16403]  	<-- committed
  • 1
  • 2
  • 3
  • 4
														childXids
top-transaction        					[]
  sub-transaction-16401     		[]
    sub-transaction-16402   		[16403]  	<-- will commit
  • 1
  • 2
  • 3
  • 4
														childXids
top-transaction        					[]
  sub-transaction-16401     		[16402, 16403]  <-- committed
  • 1
  • 2
  • 3

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

3 其他

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

SerializeTransactionState:序列化事务状态。

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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/AllinToyou/article/detail/134928
推荐阅读
相关标签
  

闽ICP备14008679号