海山数据库(He3DB)源码详解:MVCC可见性HeapTupleSatisfiesSelf函数
本文介绍了事务执行过程中,检查一个堆元组是否对当前事务可见,用于确保事务可以看到正确的数据版本。
HeapTupleSatisfiesSelf
函数源码解读
HeapTupleSatisfiesSelf
:用于判断一个元组是否对当前事务可见;
函数声明
static bool
HeapTupleSatisfiesSelf(HeapTuple htup, Snapshot snapshot, Buffer buffer)
参数说明:
HeapTuple htup
:指向堆元组的指针;Snapshot snapshot
:元组对应的快照;Buffer buffer
:包含堆元组的缓冲区。
函数说明:
该函数用于判断一个元组(tuple)是否对其自身有效,决定了当前事务能否看到某个特定的元组版本。该函数的流程图如下:
HeapTupleSatisfiesSelf
函数过程
- 获取元组头,并确保元组的自指针和元组的表OID有效
HeapTupleHeader tuple = htup->t_data;
Assert(ItemPointerIsValid(&htup->t_self));
Assert(htup->t_tableOid != InvalidOid);
首先,检查Xmin事务是否已经提交,如果没有提交,执行以下过程;
if (!HeapTupleHeaderXminCommitted(tuple))
{
/* 1.检查元组的Xmin有效性 */
/* 2.检查元组是否被标记为HEAP_MOVED_OFF */
/* 3.检查元组是否被标记为HEAP_MOVED_IN */
/* 4.检查Xmin事务ID是否为当前事务 */
/* 5.检查Xmin事务ID是否为在运行中 */
/* 6.检查Xmin事务ID是否为已经提交 */
/* 7.其他(事务中止或系统崩溃) */
}
- 如果Xmin事务已经提交或者中止,返回false;
if (HeapTupleHeaderXminInvalid(tuple))
return false;
- 获取事务ID
xvac
,并判断是否为当前事务ID,以及是否在进行中:
- 事务ID
xvac
为当前事务ID,返回false; - 事务ID
xvac
不在进行中且已经提交,则设置Xmin的提示位为XMIN已无效,返回false; - 事务ID
xvac
不在进行中且没有提交,则设置Xmin的提示位为XMIN已提交(后续执行提交行为)。
/* Used by pre-9.0 binary upgrades */
if (tuple->t_infomask & HEAP_MOVED_OFF)
{
TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
if (TransactionIdIsCurrentTransactionId(xvac))
return false;
if (!TransactionIdIsInProgress(xvac))
{
if (TransactionIdDidCommit(xvac))
{
SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
InvalidTransactionId);
return false;
}
SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
InvalidTransactionId);
}
}
- 获取事务ID
xvac
,并判断是否为当前事务ID:
- 如果事务ID
xvac
不是当前事务,且在后台运行中,返回false; - 如果事务ID
xvac
不是当前事务,且已经提交,则设置Xmin的提示位为XMIN已提交; - 如果事务ID
xvac
不是当前事务,且没有提交,则设置Xmin的提示位为XMIN已无效,返回false。
else if (tuple->t_infomask & HEAP_MOVED_IN)
{
TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
if (!TransactionIdIsCurrentTransactionId(xvac))
{
if (TransactionIdIsInProgress(xvac))
return false;
if (TransactionIdDidCommit(xvac))
SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
InvalidTransactionId);
else
{
SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
InvalidTransactionId);
return false;
}
}
}
- 依次检查元组Xmax的提示位、锁的状态和事务ID状态:
- 如果元组的Xmax无效,返回true;
- 如果元组的Xmax仅是锁定位,返回true;
- 如果元组的Xmax是组合事务,则获取Xmax的事务ID,并判断是否为当前事务ID,是:返回true,不是:返回false;
- 如果元组的Xmax的事务ID不是当前事务,设置提示位为XMAX已无效,并返回true;
- 其他,返回false。
else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmin(tuple)))
{
if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
return true;
if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask)) /* not deleter */
return true;
if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
{
TransactionId xmax;
xmax = HeapTupleGetUpdateXid(tuple);
/* not LOCKED_ONLY, so it has to have an xmax */
Assert(TransactionIdIsValid(xmax));
/* updating subtransaction must have aborted */
if (!TransactionIdIsCurrentTransactionId(xmax))
return true;
else
return false;
}
if (!TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmax(tuple)))
{
/* deleting subtransaction must have aborted */
SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
InvalidTransactionId);
return true;
}
return false;
}
- 如果Xmin的事务还在运行中,返回false;
- 如果Xmin的事务已经提交,则设置元组提示位为XMIN已提交。
else if (TransactionIdIsInProgress(HeapTupleHeaderGetRawXmin(tuple)))
return false;
else if (TransactionIdDidCommit(HeapTupleHeaderGetRawXmin(tuple)))
SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
HeapTupleHeaderGetRawXmin(tuple));
- 其他清空,则设置元组提示位为XMIN已无效,并返回false。
else
{
/* it must have aborted or crashed */
SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
InvalidTransactionId);
return false;
}
其次,如果Xmin事务已经提交,则判断Xmax的状态:
- 如果Xmax无效,返回true;
if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */
return true;
- 如果Xmax已提交,且有锁定位,返回true;否则返回false;
if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
{
if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
return true;
return false; /* updated by other */
}
- 如果Xmax是组合事务,获取Xmax事务的ID,并判断:
- 如果Xmax仅是锁定位,返回true;
- 如果是当前事务,返回false;
- 如果是在运行中,返回true;
- 如果是已提交,返回false;
- 其他返回true(中止或者崩溃);
if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
{
TransactionId xmax;
if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
return true;
xmax = HeapTupleGetUpdateXid(tuple);
/* not LOCKED_ONLY, so it has to have an xmax */
Assert(TransactionIdIsValid(xmax));
if (TransactionIdIsCurrentTransactionId(xmax))
return false;
if (TransactionIdIsInProgress(xmax))
return true;
if (TransactionIdDidCommit(xmax))
return false;
/* it must have aborted or crashed */
return true;
}
- 如果Xmax是当前事务,且有锁定位,返回true;无锁定位,返回false;
- 如果Xmax的事务在运行中,返回true;
- 如果Xmax的事务已提交,设置元组的提示位为XMAX_INVALID,并返回true;
- 如果Xmax的事务仅有锁定位,设置元组的提示位为XMAX_INVALID,并返回true;
- 其余情况将元组的提示位设置为XMAX_COMMITTED,并返回false。
if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmax(tuple)))
{
if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
return true;
return false;
}
if (TransactionIdIsInProgress(HeapTupleHeaderGetRawXmax(tuple)))
return true;
if (!TransactionIdDidCommit(HeapTupleHeaderGetRawXmax(tuple)))
{
/* it must have aborted or crashed */
SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
InvalidTransactionId);
return true;
}
/* xmax transaction committed */
if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
{
SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
InvalidTransactionId);
return true;
}
SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
HeapTupleHeaderGetRawXmax(tuple));
return false;
该函数通过检查Xmin和Xmax事务的状态(是否已提交、是否进行中、是否是当前事务等),来确定元组对自身是否有效。并且通过设置元组的提示位以有优化未来的可见性检查。
InvalidTransactionId);
return true;
}
SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
HeapTupleHeaderGetRawXmax(tuple));
return false;
该函数通过检查**Xmin**和**Xmax**事务的状态(是否已提交、是否进行中、是否是当前事务等),来确定元组对自身是否有效。并且通过设置元组的提示位以有优化未来的可见性检查。