if (BufferIsPermanent(buffer) && XLogNeedsFlush(commitLSN) &&
BufferGetLSNAtomic(buffer) < commitLSN)
{ /* not flushed and no LSN interlock, so don't set hint */ return;
}
}
if (!HeapTupleHeaderXminCommitted(tuple))
{ if (HeapTupleHeaderXminInvalid(tuple)) returnfalse;
/* Used by pre-9.0 binary upgrades */ if (tuple->t_infomask & HEAP_MOVED_OFF)
{
TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
if (TransactionIdIsCurrentTransactionId(xvac)) returnfalse; if (!TransactionIdIsInProgress(xvac))
{ if (TransactionIdDidCommit(xvac))
{
SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
InvalidTransactionId); returnfalse;
}
SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
InvalidTransactionId);
}
} /* Used by pre-9.0 binary upgrades */ elseif (tuple->t_infomask & HEAP_MOVED_IN)
{
TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
if (!TransactionIdIsCurrentTransactionId(xvac))
{ if (TransactionIdIsInProgress(xvac)) returnfalse; if (TransactionIdDidCommit(xvac))
SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
InvalidTransactionId); else
{
SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
InvalidTransactionId); returnfalse;
}
}
} elseif (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmin(tuple)))
{ if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */ returntrue;
if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask)) /* not deleter */ returntrue;
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)) returntrue; else returnfalse;
}
if (!TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmax(tuple)))
{ /* deleting subtransaction must have aborted */
SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
InvalidTransactionId); returntrue;
}
returnfalse;
} elseif (TransactionIdIsInProgress(HeapTupleHeaderGetRawXmin(tuple))) returnfalse; elseif (TransactionIdDidCommit(HeapTupleHeaderGetRawXmin(tuple)))
SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
HeapTupleHeaderGetRawXmin(tuple)); else
{ /* it must have aborted or crashed */
SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
InvalidTransactionId); returnfalse;
}
}
/* by here, the inserting transaction has committed */
if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */ returntrue;
if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
{ if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask)) returntrue; returnfalse; /* updated by other */
}
if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
{
TransactionId xmax;
if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask)) returntrue;
xmax = HeapTupleGetUpdateXid(tuple);
/* not LOCKED_ONLY, so it has to have an xmax */
Assert(TransactionIdIsValid(xmax));
if (TransactionIdIsCurrentTransactionId(xmax)) returnfalse; if (TransactionIdIsInProgress(xmax)) returntrue; if (TransactionIdDidCommit(xmax)) returnfalse; /* it must have aborted or crashed */ returntrue;
}
if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmax(tuple)))
{ if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask)) returntrue; returnfalse;
}
if (TransactionIdIsInProgress(HeapTupleHeaderGetRawXmax(tuple))) returntrue;
if (!TransactionIdDidCommit(HeapTupleHeaderGetRawXmax(tuple)))
{ /* it must have aborted or crashed */
SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
InvalidTransactionId); returntrue;
}
/* xmax transaction committed */
if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
{
SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
InvalidTransactionId); returntrue;
}
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));
/* deleting subtransaction must have aborted */ if (!TransactionIdIsCurrentTransactionId(xmax))
{ if (MultiXactIdIsRunning(HeapTupleHeaderGetRawXmax(tuple), false)) return TM_BeingModified; return TM_Ok;
} else
{ if (HeapTupleHeaderGetCmax(tuple) >= curcid) return TM_SelfModified; /* updated after scan started */ else return TM_Invisible; /* updated before scan started */
}
}
if (!TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmax(tuple)))
{ /* deleting subtransaction must have aborted */
SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
InvalidTransactionId); return TM_Ok;
}
if (HeapTupleHeaderGetCmax(tuple) >= curcid) return TM_SelfModified; /* updated after scan started */ else return TM_Invisible; /* updated before scan started */
} elseif (TransactionIdIsInProgress(HeapTupleHeaderGetRawXmin(tuple))) return TM_Invisible; elseif (TransactionIdDidCommit(HeapTupleHeaderGetRawXmin(tuple)))
SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
HeapTupleHeaderGetRawXmin(tuple)); else
{ /* it must have aborted or crashed */
SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
InvalidTransactionId); return TM_Invisible;
}
}
/* by here, the inserting transaction has committed */
if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */ return TM_Ok;
if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
{ if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask)) return TM_Ok; if (!ItemPointerEquals(&htup->t_self, &tuple->t_ctid)) return TM_Updated; /* updated by other */ else return TM_Deleted; /* deleted by other */
}
if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
{
TransactionId xmax;
if (HEAP_LOCKED_UPGRADED(tuple->t_infomask)) return TM_Ok;
if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
{ if (MultiXactIdIsRunning(HeapTupleHeaderGetRawXmax(tuple), true)) return TM_BeingModified;
xmax = HeapTupleGetUpdateXid(tuple); if (!TransactionIdIsValid(xmax))
{ if (MultiXactIdIsRunning(HeapTupleHeaderGetRawXmax(tuple), false)) return TM_BeingModified;
}
/* not LOCKED_ONLY, so it has to have an xmax */
Assert(TransactionIdIsValid(xmax));
if (TransactionIdIsCurrentTransactionId(xmax))
{ if (HeapTupleHeaderGetCmax(tuple) >= curcid) return TM_SelfModified; /* updated after scan started */ else return TM_Invisible; /* updated before scan started */
}
if (MultiXactIdIsRunning(HeapTupleHeaderGetRawXmax(tuple), false)) return TM_BeingModified;
if (TransactionIdDidCommit(xmax))
{ if (!ItemPointerEquals(&htup->t_self, &tuple->t_ctid)) return TM_Updated; else return TM_Deleted;
}
if (!MultiXactIdIsRunning(HeapTupleHeaderGetRawXmax(tuple), false))
{ /* *There'snomember,evenjustalocker,aliveanymore,sowecan *marktheXmaxasinvalid.
*/
SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
InvalidTransactionId); return TM_Ok;
} else
{ /* There are lockers running */ return TM_BeingModified;
}
}
if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmax(tuple)))
{ if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask)) return TM_BeingModified; if (HeapTupleHeaderGetCmax(tuple) >= curcid) return TM_SelfModified; /* updated after scan started */ else return TM_Invisible; /* updated before scan started */
}
if (TransactionIdIsInProgress(HeapTupleHeaderGetRawXmax(tuple))) return TM_BeingModified;
if (!TransactionIdDidCommit(HeapTupleHeaderGetRawXmax(tuple)))
{ /* it must have aborted or crashed */
SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
InvalidTransactionId); return TM_Ok;
}
/* xmax transaction committed */
if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
{
SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
InvalidTransactionId); return TM_Ok;
}
SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
HeapTupleHeaderGetRawXmax(tuple)); if (!ItemPointerEquals(&htup->t_self, &tuple->t_ctid)) return TM_Updated; /* updated by other */ else return TM_Deleted; /* deleted by other */
}
snapshot->xmin = HeapTupleHeaderGetRawXmin(tuple); /* XXX shouldn't we fall through to look at xmax? */ returntrue; /* in insertion by other */
} elseif (TransactionIdDidCommit(HeapTupleHeaderGetRawXmin(tuple)))
SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
HeapTupleHeaderGetRawXmin(tuple)); else
{ /* it must have aborted or crashed */
SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
InvalidTransactionId); returnfalse;
}
}
/* by here, the inserting transaction has committed */
if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */ returntrue;
if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
{ if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask)) returntrue; returnfalse; /* updated by other */
}
if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
{
TransactionId xmax;
if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask)) returntrue;
xmax = HeapTupleGetUpdateXid(tuple);
/* not LOCKED_ONLY, so it has to have an xmax */
Assert(TransactionIdIsValid(xmax));
if (TransactionIdIsCurrentTransactionId(xmax)) returnfalse; if (TransactionIdIsInProgress(xmax))
{
snapshot->xmax = xmax; returntrue;
} if (TransactionIdDidCommit(xmax)) returnfalse; /* it must have aborted or crashed */ returntrue;
}
if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmax(tuple)))
{ if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask)) returntrue; returnfalse;
}
if (TransactionIdIsInProgress(HeapTupleHeaderGetRawXmax(tuple)))
{ if (!HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
snapshot->xmax = HeapTupleHeaderGetRawXmax(tuple); returntrue;
}
if (!TransactionIdDidCommit(HeapTupleHeaderGetRawXmax(tuple)))
{ /* it must have aborted or crashed */
SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
InvalidTransactionId); returntrue;
}
/* xmax transaction committed */
if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
{
SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
InvalidTransactionId); returntrue;
}
SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
HeapTupleHeaderGetRawXmax(tuple)); returnfalse; /* updated by other */
}
if (!HeapTupleHeaderXminCommitted(tuple))
{ if (HeapTupleHeaderXminInvalid(tuple)) returnfalse;
/* Used by pre-9.0 binary upgrades */ if (tuple->t_infomask & HEAP_MOVED_OFF)
{
TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
if (TransactionIdIsCurrentTransactionId(xvac)) returnfalse; if (!XidInMVCCSnapshot(xvac, snapshot))
{ if (TransactionIdDidCommit(xvac))
{
SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
InvalidTransactionId); returnfalse;
}
SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
InvalidTransactionId);
}
} /* Used by pre-9.0 binary upgrades */ elseif (tuple->t_infomask & HEAP_MOVED_IN)
{
TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
if (!TransactionIdIsCurrentTransactionId(xvac))
{ if (XidInMVCCSnapshot(xvac, snapshot)) returnfalse; if (TransactionIdDidCommit(xvac))
SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
InvalidTransactionId); else
{
SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
InvalidTransactionId); returnfalse;
}
}
} elseif (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmin(tuple)))
{ if (HeapTupleHeaderGetCmin(tuple) >= snapshot->curcid) returnfalse; /* inserted after scan started */
if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */ returntrue;
if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask)) /* not deleter */ returntrue;
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)) returntrue; elseif (HeapTupleHeaderGetCmax(tuple) >= snapshot->curcid) returntrue; /* updated after scan started */ else returnfalse; /* updated before scan started */
}
if (!TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmax(tuple)))
{ /* deleting subtransaction must have aborted */
SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
InvalidTransactionId); returntrue;
}
if (HeapTupleHeaderGetCmax(tuple) >= snapshot->curcid) returntrue; /* deleted after scan started */ else returnfalse; /* deleted before scan started */
} elseif (XidInMVCCSnapshot(HeapTupleHeaderGetRawXmin(tuple), snapshot)) returnfalse; elseif (TransactionIdDidCommit(HeapTupleHeaderGetRawXmin(tuple)))
SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
HeapTupleHeaderGetRawXmin(tuple)); else
{ /* it must have aborted or crashed */
SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
InvalidTransactionId); returnfalse;
}
} else
{ /* xmin is committed, but maybe not according to our snapshot */ if (!HeapTupleHeaderXminFrozen(tuple) &&
XidInMVCCSnapshot(HeapTupleHeaderGetRawXmin(tuple), snapshot)) returnfalse; /* treat as still in progress */
}
/* by here, the inserting transaction has committed */
if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */ returntrue;
if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask)) returntrue;
if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
{
TransactionId xmax;
/* not LOCKED_ONLY, so it has to have an xmax */
Assert(TransactionIdIsValid(xmax));
if (TransactionIdIsCurrentTransactionId(xmax))
{ if (HeapTupleHeaderGetCmax(tuple) >= snapshot->curcid) returntrue; /* deleted after scan started */ else returnfalse; /* deleted before scan started */
} if (XidInMVCCSnapshot(xmax, snapshot)) returntrue; if (TransactionIdDidCommit(xmax)) returnfalse; /* updating transaction committed */ /* it must have aborted or crashed */ returntrue;
}
if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED))
{ if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmax(tuple)))
{ if (HeapTupleHeaderGetCmax(tuple) >= snapshot->curcid) returntrue; /* deleted after scan started */ else returnfalse; /* deleted before scan started */
}
if (XidInMVCCSnapshot(HeapTupleHeaderGetRawXmax(tuple), snapshot)) returntrue;
if (!TransactionIdDidCommit(HeapTupleHeaderGetRawXmax(tuple)))
{ /* it must have aborted or crashed */
SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
InvalidTransactionId); returntrue;
}
/* xmax transaction committed */
SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
HeapTupleHeaderGetRawXmax(tuple));
} else
{ /* xmax is committed, but maybe not according to our snapshot */ if (XidInMVCCSnapshot(HeapTupleHeaderGetRawXmax(tuple), snapshot)) returntrue; /* treat as still in progress */
}
/* if there's no valid Xmax, then there's obviously no update either */ if (tuple->t_infomask & HEAP_XMAX_INVALID) returntrue;
if (tuple->t_infomask & HEAP_XMAX_LOCK_ONLY) returntrue;
/* invalid xmax means no update */ if (!TransactionIdIsValid(HeapTupleHeaderGetRawXmax(tuple))) returntrue;
/* *ifHEAP_XMAX_LOCK_ONLYisnotsetandnotamulti,thenthismust *necessarilyhavebeenupdated
*/ if (!(tuple->t_infomask & HEAP_XMAX_IS_MULTI)) returnfalse;
/* ... but if it's a multi, then perhaps the updating Xid aborted. */
xmax = HeapTupleGetUpdateXid(tuple);
/* not LOCKED_ONLY, so it has to have an xmax */
Assert(TransactionIdIsValid(xmax));
if (TransactionIdIsCurrentTransactionId(xmax)) returnfalse; if (TransactionIdIsInProgress(xmax)) returnfalse; if (TransactionIdDidCommit(xmax)) returnfalse;
/* inserting transaction aborted */ if (HeapTupleHeaderXminInvalid(tuple))
{
Assert(!TransactionIdDidCommit(xmin)); returnfalse;
} /* check if it's one of our txids, toplevel is also in there */ elseif (TransactionIdInArray(xmin, snapshot->subxip, snapshot->subxcnt))
{ bool resolved;
CommandId cmin = HeapTupleHeaderGetRawCommandId(tuple);
CommandId cmax = InvalidCommandId;
if (cmin >= snapshot->curcid) returnfalse; /* inserted after scan started */ /* fall through */
} /* committed before our xmin horizon. Do a normal visibility check. */ elseif (TransactionIdPrecedes(xmin, snapshot->xmin))
{
Assert(!(HeapTupleHeaderXminCommitted(tuple) &&
!TransactionIdDidCommit(xmin)));
/* check for hint bit first, consult clog afterwards */ if (!HeapTupleHeaderXminCommitted(tuple) &&
!TransactionIdDidCommit(xmin)) returnfalse; /* fall through */
} /* beyond our xmax horizon, i.e. invisible */ elseif (TransactionIdFollowsOrEquals(xmin, snapshot->xmax))
{ returnfalse;
} /* check if it's a committed transaction in [xmin, xmax) */ elseif (TransactionIdInArray(xmin, snapshot->xip, snapshot->xcnt))
{ /* fall through */
}
/* check if it's one of our txids, toplevel is also in there */ if (TransactionIdInArray(xmax, snapshot->subxip, snapshot->subxcnt))
{ bool resolved;
CommandId cmin;
CommandId cmax = HeapTupleHeaderGetRawCommandId(tuple);
if (cmax >= snapshot->curcid) returntrue; /* deleted after scan started */ else returnfalse; /* deleted before scan started */
} /* below xmin horizon, normal transaction state is valid */ elseif (TransactionIdPrecedes(xmax, snapshot->xmin))
{
Assert(!(tuple->t_infomask & HEAP_XMAX_COMMITTED &&
!TransactionIdDidCommit(xmax)));
/* check hint bit first */ if (tuple->t_infomask & HEAP_XMAX_COMMITTED) returnfalse;
/* check clog */ return !TransactionIdDidCommit(xmax);
} /* above xmax horizon, we cannot possibly see the deleting transaction */ elseif (TransactionIdFollowsOrEquals(xmax, snapshot->xmax)) returntrue; /* xmax is between [xmin, xmax), check known committed array */ elseif (TransactionIdInArray(xmax, snapshot->xip, snapshot->xcnt)) returnfalse; /* xmax is between [xmin, xmax), but known not to have committed yet */ else returntrue;
}
/* *HeapTupleSatisfiesVisibility *Trueiffheaptuplesatisfiesatimequal. * *Notes: *Assumesheaptupleisvalid,andbufferatleastsharelocked. * *HintbitsintheHeapTuple'st_infomaskmaybeupdatedasasideeffect; *ifso,theindicatedbufferismarkeddirty.
*/ bool
HeapTupleSatisfiesVisibility(HeapTuple htup, Snapshot snapshot, Buffer buffer)
{ switch (snapshot->snapshot_type)
{ case SNAPSHOT_MVCC: return HeapTupleSatisfiesMVCC(htup, snapshot, buffer); case SNAPSHOT_SELF: return HeapTupleSatisfiesSelf(htup, snapshot, buffer); case SNAPSHOT_ANY: return HeapTupleSatisfiesAny(htup, snapshot, buffer); case SNAPSHOT_TOAST: return HeapTupleSatisfiesToast(htup, snapshot, buffer); case SNAPSHOT_DIRTY: return HeapTupleSatisfiesDirty(htup, snapshot, buffer); case SNAPSHOT_HISTORIC_MVCC: return HeapTupleSatisfiesHistoricMVCC(htup, snapshot, buffer); case SNAPSHOT_NON_VACUUMABLE: return HeapTupleSatisfiesNonVacuumable(htup, snapshot, buffer);
}
returnfalse; /* keep compiler quiet */
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.43 Sekunden
(vorverarbeitet am 2026-08-08)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.