可见性检查规则是一组规则,用于确定一条元组是否对一个事务可见,可见性检查规则会用到元组的t_xmin和t_xmax,提交日志clog,以及已获取的事务快照。这些规则太复杂,无法详细解释,故本书只列出了理解后续内容所需的最小规则子集。在下文中省略了与子事务相关的规则,并忽略了关于t_ctid的讨论,比如我们不会考虑在同一个事务中对一条元组多次重复更新的情况。
所选规则有十条,可以分类为三种情况。
5.6.1 t_xmin
的状态为ABORTED
t_xmin
状态为ABORTED
的元组始终不可见(规则1),因为插入此元组的事务已中止。
/* 创建元组的事务已经中止 */
Rule 1: IF t_xmin status is ABORTED THEN
RETURN Invisible
END IF
该规则明确表示为以下数学表达式。
- 规则1 :
If Status(t_xmin) = ABORTED ⇒ Invisible
5.6.2 t_xmin
的状态为IN_PROGRESS
t_xmin
状态为IN_PROGRESS
的元组基本上是不可见的(规则3和4),但在一个条件下除外。
/* 创建元组的事务正在进行中 */
IF t_xmin status is IN_PROGRESS THEN
/* 当前事务自己创建了本元组 */
IF t_xmin = current_txid THEN
/* 该元组没有被标记删除,则应当看见本事务自己创建的元组 */
Rule 2: IF t_xmax = INVALID THEN
RETURN Visible /* 例外,被自己创建的未删元组可见 */
Rule 3: ELSE
/* 这条元组被当前事务自己创建后又删除掉了,故不可见 */
RETURN Invisible
END IF
Rule 4: ELSE /* t_xmin ≠ current_txid */
/* 其他运行中的事务创建了本元组 */
RETURN Invisible
END IF
END IF
如果该元组被另一个进行中的事务插入(t_xmin
对应事务状态为IN_PROGRESS
),则该元组显然是不可见的(规则4)。
如果t_xmin
等于当前事务的txid
(即,是当前事务插入了该元组),且t_xmax ≠ 0
,则该元组是不可见的,因为它已被当前事务更新或删除(规则3)。
例外是,当前事务插入此元组且t_xmax
无效(t_xmax = 0
)的情况。 在这种情况下,此元组对当前事务中可见(规则2)。
- 规则2 :
If Status(t_xmin) = IN_PROGRESS ∧ t_xmin = current_txid ∧ t_xmax = INVAILD ⇒ Visible
- 规则3 :
If Status(t_xmin) = IN_PROGRESS ∧ t_xmin = current_txid ∧ t_xmax ≠ INVAILD ⇒ Invisible
- 规则4 :
If Status(t_xmin) = IN_PROGRESS ∧ t_xmin ≠ current_txid ⇒ Invisible
5.6.3 t_xmin
的状态为COMMITTED
t_xmin
状态为COMMITTED
的元组是可见的(规则 6,8和9),但在三个条件下除外。
/* 创建元组的事务已经提交 */
IF t_xmin status is COMMITTED THEN
/* 创建元组的事务在获取的事务快照中处于活跃状态,创建无效,不可见 */
Rule 5: IF t_xmin is active in the obtained transaction snapshot THEN
RETURN Invisible
/* 元组被删除,但删除元组的事务中止了,删除无效,可见 */
/* 创建元组的事务已提交,且非活跃,元组也没有被标记为删除,则可见 */
Rule 6: ELSE IF t_xmax = INVALID OR status of t_xmax is ABORTED THEN
RETURN Visible
/* 元组被删除,但删除元组的事务正在进行中,分情况 */
ELSE IF t_xmax status is IN_PROGRESS THEN
/* 如果恰好是被本事务自己删除的,删除有效,不可见 */
Rule 7: IF t_xmax = current_txid THEN
RETURN Invisible
/* 如果是被其他事务删除的,删除无效,可见 */
Rule 8: ELSE /* t_xmax ≠ current_txid */
RETURN Visible
END IF
/* 元组被删除,且删除元组的事务已经提交 */
ELSE IF t_xmax status is COMMITTED THEN
/* 删除元组的事务在获取的事务快照中处于活跃状态,删除无效,不可见 */
Rule 9: IF t_xmax is active in the obtained transaction snapshot THEN
RETURN Visible
Rule 10: ELSE /* 删除有效,可见 */
RETURN Invisible
END IF
END IF
END IF
规则6是显而易见的,因为t_xmax
为INVALID
,或者t_xmax
对应事务已经中止,相应元组可见。三个例外条件及规则8与规则9的描述如下。
第一个例外情况是t_xmin
在获取的事务快照中处于活跃 状态(规则5)。在这种情况下,这条元组是不可见的,因为t_xmin
应该被视为正在进行中(取快照时创建该元组的事务尚未提交,因此对于REPEATABLE READ
以及更高隔离等级而言,即使在判断时创建该元组的事务已经提交,但其结果仍然不可见)。
第二个例外情况是t_xmax
是当前的txid
(规则7)。这种情况与规则3类似,此元组是不可见的,因为它已经被此事务本身更新或删除。相反,如果t_xmax
的状态是IN_PROGRESS
并且t_xmax
不是当前的txid
(规则8),则元组是可见的,因为它尚未被删除(因为删除该元组的事务尚未提交)。
第三个例外情况是t_xmax
的状态为COMMITTED
,且t_xmax
在获取的事务快照中是非活跃 的(规则10)。在这种情况下该元组不可见,因为它已被另一个事务更新或删除。
相反,如果t_xmax
的状态为COMMITTED
,但t_xmax
在获取的事务快照中处于活跃状态(规则9),则元组可见,因为t_xmax
对应的事务应被视为正在进行中,删除尚未提交生效。
- 规则5 :
If Status(t_xmin) = COMMITTED ∧ Snapshot(t_xmin) = active ⇒ Invisible
- 规则6 :
If Status(t_xmin) = COMMITTED ∧ (t_xmax = INVALID ∨ Status(t_xmax) = ABORTED) ⇒ Visible
- 规则7 :
If Status(t_xmin) = COMMITTED ∧ Status(t_xmax) = IN_PROGRESS ∧ t_xmax = current_txid ⇒ Invisible
- 规则8 :
If Status(t_xmin) = COMMITTED ∧ Status(t_xmax) = IN_PROGRESS ∧ t_xmax ≠ current_txid ⇒ Visible
- 规则9 :
If Status(t_xmin) = COMMITTED ∧ Status(t_xmax) = COMMITTED ∧ Snapshot(t_xmax) = active ⇒ Visible
- 规则10 :
If Status(t_xmin) = COMMITTED ∧ Status(t_xmax) = COMMITTED ∧ Snapshot(t_xmax) ≠ active ⇒ Invisible
下一节:本节描述了PostgreSQL执行可见性检查的流程。可见性检查(Visiblity Check),即如何为给定事务挑选堆元组的恰当版本。本节还介绍了PostgreSQL如何防止ANSI SQL-92标准中定义的异常:脏读,可重读和幻读。