#include "postgres.h"
#include "access/htup_details.h"
#include "access/multixact.h"
#include "access/subtrans.h"
#include "access/transam.h"
#include "access/xact.h"
#include "storage/bufmgr.h"
#include "storage/procarray.h"
#include "utils/tqual.h"
Go to the source code of this file.
bool HeapTupleHeaderIsOnlyLocked | ( | HeapTupleHeader | tuple | ) |
Definition at line 1630 of file tqual.c.
References HEAP_XMAX_INVALID, HEAP_XMAX_IS_MULTI, HEAP_XMAX_LOCK_ONLY, HeapTupleGetUpdateXid(), HeapTupleHeaderGetRawXmax, HeapTupleHeaderData::t_infomask, TransactionIdDidCommit(), TransactionIdIsCurrentTransactionId(), TransactionIdIsInProgress(), and TransactionIdIsValid.
Referenced by heap_delete(), heap_get_latest_tid(), heap_lock_tuple(), heap_lock_updated_tuple_rec(), and rewrite_heap_tuple().
{ TransactionId xmax; /* if there's no valid Xmax, then there's obviously no update either */ if (tuple->t_infomask & HEAP_XMAX_INVALID) return true; if (tuple->t_infomask & HEAP_XMAX_LOCK_ONLY) return true; /* invalid xmax means no update */ if (!TransactionIdIsValid(HeapTupleHeaderGetRawXmax(tuple))) return true; /* * if HEAP_XMAX_LOCK_ONLY is not set and not a multi, then this * must necessarily have been updated */ if (!(tuple->t_infomask & HEAP_XMAX_IS_MULTI)) return false; /* ... but if it's a multi, then perhaps the updating Xid aborted. */ xmax = HeapTupleGetUpdateXid(tuple); if (!TransactionIdIsValid(xmax)) /* shouldn't happen .. */ return true; if (TransactionIdIsCurrentTransactionId(xmax)) return false; if (TransactionIdIsInProgress(xmax)) return false; if (TransactionIdDidCommit(xmax)) return false; /* * not current, not in progress, not committed -- must have aborted or * crashed */ return true; }
bool HeapTupleIsSurelyDead | ( | HeapTupleHeader | tuple, | |
TransactionId | OldestXmin | |||
) |
Definition at line 1466 of file tqual.c.
References HEAP_XMAX_COMMITTED, HEAP_XMAX_INVALID, HEAP_XMAX_IS_LOCKED_ONLY, HEAP_XMAX_IS_MULTI, HEAP_XMIN_COMMITTED, HEAP_XMIN_INVALID, HeapTupleHeaderGetRawXmax, HeapTupleHeaderData::t_infomask, and TransactionIdPrecedes().
Referenced by heap_hot_search_buffer().
{ /* * If the inserting transaction is marked invalid, then it aborted, and * the tuple is definitely dead. If it's marked neither committed nor * invalid, then we assume it's still alive (since the presumption is that * all relevant hint bits were just set moments ago). */ if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED)) return (tuple->t_infomask & HEAP_XMIN_INVALID) != 0 ? true : false; /* * If the inserting transaction committed, but any deleting transaction * aborted, the tuple is still alive. */ if (tuple->t_infomask & HEAP_XMAX_INVALID) return false; /* * If the XMAX is just a lock, the tuple is still alive. */ if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask)) return false; /* * If the Xmax is a MultiXact, it might be dead or alive, but we cannot * know without checking pg_multixact. */ if (tuple->t_infomask & HEAP_XMAX_IS_MULTI) return false; /* If deleter isn't known to have committed, assume it's still running. */ if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED)) return false; /* Deleter committed, so tuple is dead if the XID is old enough. */ return TransactionIdPrecedes(HeapTupleHeaderGetRawXmax(tuple), OldestXmin); }
bool HeapTupleSatisfiesAny | ( | HeapTupleHeader | tuple, | |
Snapshot | snapshot, | |||
Buffer | buffer | |||
) |
bool HeapTupleSatisfiesDirty | ( | HeapTupleHeader | tuple, | |
Snapshot | snapshot, | |||
Buffer | buffer | |||
) |
Definition at line 851 of file tqual.c.
References HEAP_MOVED_IN, HEAP_MOVED_OFF, HEAP_XMAX_COMMITTED, HEAP_XMAX_INVALID, HEAP_XMAX_IS_LOCKED_ONLY, HEAP_XMAX_IS_MULTI, HEAP_XMIN_COMMITTED, HEAP_XMIN_INVALID, HeapTupleGetUpdateXid(), HeapTupleHeaderGetRawXmax, HeapTupleHeaderGetXmin, HeapTupleHeaderGetXvac, InvalidTransactionId, SetHintBits(), HeapTupleHeaderData::t_infomask, TransactionIdDidCommit(), TransactionIdIsCurrentTransactionId(), TransactionIdIsInProgress(), TransactionIdIsValid, SnapshotData::xmax, and SnapshotData::xmin.
{ snapshot->xmin = snapshot->xmax = InvalidTransactionId; if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED)) { if (tuple->t_infomask & HEAP_XMIN_INVALID) return false; /* 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); } } /* Used by pre-9.0 binary upgrades */ 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; } } } else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmin(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); if (!TransactionIdIsValid(xmax)) return true; /* 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; } else if (TransactionIdIsInProgress(HeapTupleHeaderGetXmin(tuple))) { snapshot->xmin = HeapTupleHeaderGetXmin(tuple); /* XXX shouldn't we fall through to look at xmax? */ return true; /* in insertion by other */ } else if (TransactionIdDidCommit(HeapTupleHeaderGetXmin(tuple))) SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED, HeapTupleHeaderGetXmin(tuple)); else { /* it must have aborted or crashed */ SetHintBits(tuple, buffer, HEAP_XMIN_INVALID, InvalidTransactionId); return false; } } /* by here, the inserting transaction has committed */ if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */ return true; if (tuple->t_infomask & HEAP_XMAX_COMMITTED) { if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask)) return true; return false; /* updated by other */ } if (tuple->t_infomask & HEAP_XMAX_IS_MULTI) { TransactionId xmax; if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask)) return true; xmax = HeapTupleGetUpdateXid(tuple); if (!TransactionIdIsValid(xmax)) return true; if (TransactionIdIsCurrentTransactionId(xmax)) return false; if (TransactionIdIsInProgress(xmax)) { snapshot->xmax = xmax; return true; } if (TransactionIdDidCommit(xmax)) return false; return true; } if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmax(tuple))) { if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask)) return true; return false; } if (TransactionIdIsInProgress(HeapTupleHeaderGetRawXmax(tuple))) { snapshot->xmax = 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; /* updated by other */ }
bool HeapTupleSatisfiesMVCC | ( | HeapTupleHeader | tuple, | |
Snapshot | snapshot, | |||
Buffer | buffer | |||
) |
Definition at line 1042 of file tqual.c.
References Assert, SnapshotData::curcid, HEAP_MOVED_IN, HEAP_MOVED_OFF, HEAP_XMAX_COMMITTED, HEAP_XMAX_INVALID, HEAP_XMAX_IS_LOCKED_ONLY, HEAP_XMAX_IS_MULTI, HEAP_XMIN_COMMITTED, HEAP_XMIN_INVALID, HeapTupleGetUpdateXid(), HeapTupleHeaderGetCmax(), HeapTupleHeaderGetCmin(), HeapTupleHeaderGetRawXmax, HeapTupleHeaderGetXmin, HeapTupleHeaderGetXvac, InvalidTransactionId, SetHintBits(), HeapTupleHeaderData::t_infomask, TransactionIdDidCommit(), TransactionIdIsCurrentTransactionId(), TransactionIdIsInProgress(), TransactionIdIsValid, and XidInMVCCSnapshot().
{ if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED)) { if (tuple->t_infomask & HEAP_XMIN_INVALID) return false; /* 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); } } /* Used by pre-9.0 binary upgrades */ 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; } } } else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmin(tuple))) { if (HeapTupleHeaderGetCmin(tuple) >= snapshot->curcid) return false; /* inserted after scan started */ 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); if (!TransactionIdIsValid(xmax)) return true; /* updating subtransaction must have aborted */ if (!TransactionIdIsCurrentTransactionId(xmax)) return true; else if (HeapTupleHeaderGetCmax(tuple) >= snapshot->curcid) return true; /* updated after scan started */ else return false; /* updated before scan started */ } if (!TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmax(tuple))) { /* deleting subtransaction must have aborted */ SetHintBits(tuple, buffer, HEAP_XMAX_INVALID, InvalidTransactionId); return true; } if (HeapTupleHeaderGetCmax(tuple) >= snapshot->curcid) return true; /* deleted after scan started */ else return false; /* deleted before scan started */ } else if (TransactionIdIsInProgress(HeapTupleHeaderGetXmin(tuple))) return false; else if (TransactionIdDidCommit(HeapTupleHeaderGetXmin(tuple))) SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED, HeapTupleHeaderGetXmin(tuple)); else { /* it must have aborted or crashed */ SetHintBits(tuple, buffer, HEAP_XMIN_INVALID, InvalidTransactionId); return false; } } /* * By here, the inserting transaction has committed - have to check * when... */ if (XidInMVCCSnapshot(HeapTupleHeaderGetXmin(tuple), snapshot)) return false; /* treat as still in progress */ if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */ return true; if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask)) return true; if (tuple->t_infomask & HEAP_XMAX_IS_MULTI) { TransactionId xmax; /* already checked above */ Assert(!HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask)); xmax = HeapTupleGetUpdateXid(tuple); if (!TransactionIdIsValid(xmax)) return true; if (TransactionIdIsCurrentTransactionId(xmax)) { if (HeapTupleHeaderGetCmax(tuple) >= snapshot->curcid) return true; /* deleted after scan started */ else return false; /* deleted before scan started */ } if (TransactionIdIsInProgress(xmax)) return true; if (TransactionIdDidCommit(xmax)) { /* updating transaction committed, but when? */ if (XidInMVCCSnapshot(xmax, snapshot)) return true; /* treat as still in progress */ return false; } return true; } if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED)) { if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmax(tuple))) { if (HeapTupleHeaderGetCmax(tuple) >= snapshot->curcid) return true; /* deleted after scan started */ else return false; /* deleted before scan started */ } 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 */ SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED, HeapTupleHeaderGetRawXmax(tuple)); } /* * OK, the deleting transaction committed too ... but when? */ if (XidInMVCCSnapshot(HeapTupleHeaderGetRawXmax(tuple), snapshot)) return true; /* treat as still in progress */ return false; }
bool HeapTupleSatisfiesNow | ( | HeapTupleHeader | tuple, | |
Snapshot | snapshot, | |||
Buffer | buffer | |||
) |
Definition at line 354 of file tqual.c.
References GetCurrentCommandId(), HEAP_MOVED_IN, HEAP_MOVED_OFF, HEAP_XMAX_COMMITTED, HEAP_XMAX_INVALID, HEAP_XMAX_IS_LOCKED_ONLY, HEAP_XMAX_IS_MULTI, HEAP_XMIN_COMMITTED, HEAP_XMIN_INVALID, HeapTupleGetUpdateXid(), HeapTupleHeaderGetCmax(), HeapTupleHeaderGetCmin(), HeapTupleHeaderGetRawXmax, HeapTupleHeaderGetXmin, HeapTupleHeaderGetXvac, InvalidTransactionId, SetHintBits(), HeapTupleHeaderData::t_infomask, TransactionIdDidCommit(), TransactionIdIsCurrentTransactionId(), TransactionIdIsInProgress(), and TransactionIdIsValid.
{ if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED)) { if (tuple->t_infomask & HEAP_XMIN_INVALID) return false; /* 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); } } /* Used by pre-9.0 binary upgrades */ 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; } } } else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmin(tuple))) { if (HeapTupleHeaderGetCmin(tuple) >= GetCurrentCommandId(false)) return false; /* inserted after scan started */ 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); if (!TransactionIdIsValid(xmax)) return true; /* 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; } if (HeapTupleHeaderGetCmax(tuple) >= GetCurrentCommandId(false)) return true; /* deleted after scan started */ else return false; /* deleted before scan started */ } else if (TransactionIdIsInProgress(HeapTupleHeaderGetXmin(tuple))) return false; else if (TransactionIdDidCommit(HeapTupleHeaderGetXmin(tuple))) SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED, HeapTupleHeaderGetXmin(tuple)); else { /* it must have aborted or crashed */ SetHintBits(tuple, buffer, HEAP_XMIN_INVALID, InvalidTransactionId); return false; } } /* by here, the inserting transaction has committed */ if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */ return true; if (tuple->t_infomask & HEAP_XMAX_COMMITTED) { if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask)) return true; return false; } if (tuple->t_infomask & HEAP_XMAX_IS_MULTI) { TransactionId xmax; if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask)) return true; xmax = HeapTupleGetUpdateXid(tuple); if (!TransactionIdIsValid(xmax)) return true; if (TransactionIdIsCurrentTransactionId(xmax)) { if (HeapTupleHeaderGetCmax(tuple) >= GetCurrentCommandId(false)) return true; /* deleted after scan started */ else return false; /* deleted before scan started */ } if (TransactionIdIsInProgress(xmax)) return true; if (TransactionIdDidCommit(xmax)) return false; return true; } if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmax(tuple))) { if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask)) return true; if (HeapTupleHeaderGetCmax(tuple) >= GetCurrentCommandId(false)) return true; /* deleted after scan started */ else return false; /* deleted before scan started */ } 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; }
bool HeapTupleSatisfiesSelf | ( | HeapTupleHeader | tuple, | |
Snapshot | snapshot, | |||
Buffer | buffer | |||
) |
Definition at line 166 of file tqual.c.
References HEAP_MOVED_IN, HEAP_MOVED_OFF, HEAP_XMAX_COMMITTED, HEAP_XMAX_INVALID, HEAP_XMAX_IS_LOCKED_ONLY, HEAP_XMAX_IS_MULTI, HEAP_XMIN_COMMITTED, HEAP_XMIN_INVALID, HeapTupleGetUpdateXid(), HeapTupleHeaderGetRawXmax, HeapTupleHeaderGetXmin, HeapTupleHeaderGetXvac, InvalidTransactionId, SetHintBits(), HeapTupleHeaderData::t_infomask, TransactionIdDidCommit(), TransactionIdIsCurrentTransactionId(), TransactionIdIsInProgress(), and TransactionIdIsValid.
{ if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED)) { if (tuple->t_infomask & HEAP_XMIN_INVALID) return false; /* 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); } } /* Used by pre-9.0 binary upgrades */ 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; } } } else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmin(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); if (!TransactionIdIsValid(xmax)) return true; /* 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; } else if (TransactionIdIsInProgress(HeapTupleHeaderGetXmin(tuple))) return false; else if (TransactionIdDidCommit(HeapTupleHeaderGetXmin(tuple))) SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED, HeapTupleHeaderGetXmin(tuple)); else { /* it must have aborted or crashed */ SetHintBits(tuple, buffer, HEAP_XMIN_INVALID, InvalidTransactionId); return false; } } /* by here, the inserting transaction has committed */ if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */ return true; if (tuple->t_infomask & HEAP_XMAX_COMMITTED) { if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask)) return true; return false; /* updated by other */ } if (tuple->t_infomask & HEAP_XMAX_IS_MULTI) { TransactionId xmax; if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask)) return true; xmax = HeapTupleGetUpdateXid(tuple); if (!TransactionIdIsValid(xmax)) return true; if (TransactionIdIsCurrentTransactionId(xmax)) return false; if (TransactionIdIsInProgress(xmax)) return true; if (TransactionIdDidCommit(xmax)) return false; return true; } 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; }
bool HeapTupleSatisfiesToast | ( | HeapTupleHeader | tuple, | |
Snapshot | snapshot, | |||
Buffer | buffer | |||
) |
Definition at line 549 of file tqual.c.
References HEAP_MOVED_IN, HEAP_MOVED_OFF, HEAP_XMIN_COMMITTED, HEAP_XMIN_INVALID, HeapTupleHeaderGetXvac, InvalidTransactionId, SetHintBits(), HeapTupleHeaderData::t_infomask, TransactionIdDidCommit(), TransactionIdIsCurrentTransactionId(), and TransactionIdIsInProgress().
{ if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED)) { if (tuple->t_infomask & HEAP_XMIN_INVALID) return false; /* 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); } } /* Used by pre-9.0 binary upgrades */ 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; } } } } /* otherwise assume the tuple is valid for TOAST. */ return true; }
HTSU_Result HeapTupleSatisfiesUpdate | ( | HeapTupleHeader | tuple, | |
CommandId | curcid, | |||
Buffer | buffer | |||
) |
Definition at line 630 of file tqual.c.
References HEAP_MOVED_IN, HEAP_MOVED_OFF, HEAP_XMAX_COMMITTED, HEAP_XMAX_EXCL_LOCK, HEAP_XMAX_INVALID, HEAP_XMAX_IS_LOCKED_ONLY, HEAP_XMAX_IS_MULTI, HEAP_XMAX_KEYSHR_LOCK, HEAP_XMIN_COMMITTED, HEAP_XMIN_INVALID, HeapTupleGetUpdateXid(), HeapTupleHeaderGetCmax(), HeapTupleHeaderGetCmin(), HeapTupleHeaderGetRawXmax, HeapTupleHeaderGetXmin, HeapTupleHeaderGetXvac, InvalidTransactionId, MultiXactIdIsRunning(), SetHintBits(), HeapTupleHeaderData::t_infomask, TransactionIdDidCommit(), TransactionIdIsCurrentTransactionId(), TransactionIdIsInProgress(), and TransactionIdIsValid.
Referenced by heap_delete(), heap_lock_tuple(), heap_update(), and pgrowlocks().
{ if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED)) { if (tuple->t_infomask & HEAP_XMIN_INVALID) return HeapTupleInvisible; /* Used by pre-9.0 binary upgrades */ if (tuple->t_infomask & HEAP_MOVED_OFF) { TransactionId xvac = HeapTupleHeaderGetXvac(tuple); if (TransactionIdIsCurrentTransactionId(xvac)) return HeapTupleInvisible; if (!TransactionIdIsInProgress(xvac)) { if (TransactionIdDidCommit(xvac)) { SetHintBits(tuple, buffer, HEAP_XMIN_INVALID, InvalidTransactionId); return HeapTupleInvisible; } SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED, InvalidTransactionId); } } /* Used by pre-9.0 binary upgrades */ else if (tuple->t_infomask & HEAP_MOVED_IN) { TransactionId xvac = HeapTupleHeaderGetXvac(tuple); if (!TransactionIdIsCurrentTransactionId(xvac)) { if (TransactionIdIsInProgress(xvac)) return HeapTupleInvisible; if (TransactionIdDidCommit(xvac)) SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED, InvalidTransactionId); else { SetHintBits(tuple, buffer, HEAP_XMIN_INVALID, InvalidTransactionId); return HeapTupleInvisible; } } } else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmin(tuple))) { if (HeapTupleHeaderGetCmin(tuple) >= curcid) return HeapTupleInvisible; /* inserted after scan started */ if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */ return HeapTupleMayBeUpdated; if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask)) /* not deleter */ return HeapTupleMayBeUpdated; if (tuple->t_infomask & HEAP_XMAX_IS_MULTI) { TransactionId xmax; xmax = HeapTupleGetUpdateXid(tuple); if (!TransactionIdIsValid(xmax)) return HeapTupleMayBeUpdated; /* updating subtransaction must have aborted */ if (!TransactionIdIsCurrentTransactionId(xmax)) return HeapTupleMayBeUpdated; else { if (HeapTupleHeaderGetCmax(tuple) >= curcid) return HeapTupleSelfUpdated; /* updated after scan started */ else return HeapTupleInvisible; /* updated before scan started */ } } if (!TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmax(tuple))) { /* deleting subtransaction must have aborted */ SetHintBits(tuple, buffer, HEAP_XMAX_INVALID, InvalidTransactionId); return HeapTupleMayBeUpdated; } if (HeapTupleHeaderGetCmax(tuple) >= curcid) return HeapTupleSelfUpdated; /* updated after scan started */ else return HeapTupleInvisible; /* updated before scan started */ } else if (TransactionIdIsInProgress(HeapTupleHeaderGetXmin(tuple))) return HeapTupleInvisible; else if (TransactionIdDidCommit(HeapTupleHeaderGetXmin(tuple))) SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED, HeapTupleHeaderGetXmin(tuple)); else { /* it must have aborted or crashed */ SetHintBits(tuple, buffer, HEAP_XMIN_INVALID, InvalidTransactionId); return HeapTupleInvisible; } } /* by here, the inserting transaction has committed */ if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */ return HeapTupleMayBeUpdated; if (tuple->t_infomask & HEAP_XMAX_COMMITTED) { if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask)) return HeapTupleMayBeUpdated; return HeapTupleUpdated; /* updated by other */ } if (tuple->t_infomask & HEAP_XMAX_IS_MULTI) { TransactionId xmax; if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask)) { /* * If it's only locked but neither EXCL_LOCK nor KEYSHR_LOCK * is set, it cannot possibly be running. Otherwise need to * check. */ if ((tuple->t_infomask & (HEAP_XMAX_EXCL_LOCK | HEAP_XMAX_KEYSHR_LOCK)) && MultiXactIdIsRunning(HeapTupleHeaderGetRawXmax(tuple))) return HeapTupleBeingUpdated; SetHintBits(tuple, buffer, HEAP_XMAX_INVALID, InvalidTransactionId); return HeapTupleMayBeUpdated; } xmax = HeapTupleGetUpdateXid(tuple); if (!TransactionIdIsValid(xmax)) { if (MultiXactIdIsRunning(HeapTupleHeaderGetRawXmax(tuple))) return HeapTupleBeingUpdated; SetHintBits(tuple, buffer, HEAP_XMAX_INVALID, InvalidTransactionId); return HeapTupleMayBeUpdated; } if (TransactionIdIsCurrentTransactionId(xmax)) { if (HeapTupleHeaderGetCmax(tuple) >= curcid) return HeapTupleSelfUpdated; /* updated after scan started */ else return HeapTupleInvisible; /* updated before scan started */ } if (MultiXactIdIsRunning(HeapTupleHeaderGetRawXmax(tuple))) return HeapTupleBeingUpdated; if (TransactionIdDidCommit(xmax)) return HeapTupleUpdated; /* it must have aborted or crashed */ SetHintBits(tuple, buffer, HEAP_XMAX_INVALID, InvalidTransactionId); return HeapTupleMayBeUpdated; } if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmax(tuple))) { if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask)) return HeapTupleMayBeUpdated; if (HeapTupleHeaderGetCmax(tuple) >= curcid) return HeapTupleSelfUpdated; /* updated after scan started */ else return HeapTupleInvisible; /* updated before scan started */ } if (TransactionIdIsInProgress(HeapTupleHeaderGetRawXmax(tuple))) return HeapTupleBeingUpdated; if (!TransactionIdDidCommit(HeapTupleHeaderGetRawXmax(tuple))) { /* it must have aborted or crashed */ SetHintBits(tuple, buffer, HEAP_XMAX_INVALID, InvalidTransactionId); return HeapTupleMayBeUpdated; } /* xmax transaction committed */ if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask)) { SetHintBits(tuple, buffer, HEAP_XMAX_INVALID, InvalidTransactionId); return HeapTupleMayBeUpdated; } SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED, HeapTupleHeaderGetRawXmax(tuple)); return HeapTupleUpdated; /* updated by other */ }
HTSV_Result HeapTupleSatisfiesVacuum | ( | HeapTupleHeader | tuple, | |
TransactionId | OldestXmin, | |||
Buffer | buffer | |||
) |
Definition at line 1235 of file tqual.c.
References Assert, HEAP_MOVED_IN, HEAP_MOVED_OFF, HEAP_XMAX_COMMITTED, HEAP_XMAX_EXCL_LOCK, HEAP_XMAX_INVALID, HEAP_XMAX_IS_LOCKED_ONLY, HEAP_XMAX_IS_MULTI, HEAP_XMAX_KEYSHR_LOCK, HEAP_XMIN_COMMITTED, HEAP_XMIN_INVALID, HeapTupleGetUpdateXid(), HeapTupleHeaderGetRawXmax, HeapTupleHeaderGetXmin, HeapTupleHeaderGetXvac, InvalidTransactionId, MultiXactIdIsRunning(), SetHintBits(), HeapTupleHeaderData::t_infomask, TransactionIdDidCommit(), TransactionIdIsCurrentTransactionId(), TransactionIdIsInProgress(), TransactionIdIsValid, and TransactionIdPrecedes().
Referenced by acquire_sample_rows(), CheckForSerializableConflictOut(), copy_heap_data(), heap_page_is_all_visible(), heap_prune_chain(), IndexBuildHeapScan(), and lazy_scan_heap().
{ /* * Has inserting transaction committed? * * If the inserting transaction aborted, then the tuple was never visible * to any other transaction, so we can delete it immediately. */ if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED)) { if (tuple->t_infomask & HEAP_XMIN_INVALID) return HEAPTUPLE_DEAD; /* Used by pre-9.0 binary upgrades */ else if (tuple->t_infomask & HEAP_MOVED_OFF) { TransactionId xvac = HeapTupleHeaderGetXvac(tuple); if (TransactionIdIsCurrentTransactionId(xvac)) return HEAPTUPLE_DELETE_IN_PROGRESS; if (TransactionIdIsInProgress(xvac)) return HEAPTUPLE_DELETE_IN_PROGRESS; if (TransactionIdDidCommit(xvac)) { SetHintBits(tuple, buffer, HEAP_XMIN_INVALID, InvalidTransactionId); return HEAPTUPLE_DEAD; } SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED, InvalidTransactionId); } /* Used by pre-9.0 binary upgrades */ else if (tuple->t_infomask & HEAP_MOVED_IN) { TransactionId xvac = HeapTupleHeaderGetXvac(tuple); if (TransactionIdIsCurrentTransactionId(xvac)) return HEAPTUPLE_INSERT_IN_PROGRESS; if (TransactionIdIsInProgress(xvac)) return HEAPTUPLE_INSERT_IN_PROGRESS; if (TransactionIdDidCommit(xvac)) SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED, InvalidTransactionId); else { SetHintBits(tuple, buffer, HEAP_XMIN_INVALID, InvalidTransactionId); return HEAPTUPLE_DEAD; } } else if (TransactionIdIsInProgress(HeapTupleHeaderGetXmin(tuple))) { if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */ return HEAPTUPLE_INSERT_IN_PROGRESS; if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask)) return HEAPTUPLE_INSERT_IN_PROGRESS; /* inserted and then deleted by same xact */ return HEAPTUPLE_DELETE_IN_PROGRESS; } else if (TransactionIdDidCommit(HeapTupleHeaderGetXmin(tuple))) SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED, HeapTupleHeaderGetXmin(tuple)); else { /* * Not in Progress, Not Committed, so either Aborted or crashed */ SetHintBits(tuple, buffer, HEAP_XMIN_INVALID, InvalidTransactionId); return HEAPTUPLE_DEAD; } /* * At this point the xmin is known committed, but we might not have * been able to set the hint bit yet; so we can no longer Assert that * it's set. */ } /* * Okay, the inserter committed, so it was good at some point. Now what * about the deleting transaction? */ if (tuple->t_infomask & HEAP_XMAX_INVALID) return HEAPTUPLE_LIVE; if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask)) { /* * "Deleting" xact really only locked it, so the tuple is live in any * case. However, we should make sure that either XMAX_COMMITTED or * XMAX_INVALID gets set once the xact is gone, to reduce the costs of * examining the tuple for future xacts. Also, marking dead * MultiXacts as invalid here provides defense against MultiXactId * wraparound (see also comments in heap_freeze_tuple()). */ if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED)) { if (tuple->t_infomask & HEAP_XMAX_IS_MULTI) { /* * If it's only locked but neither EXCL_LOCK nor KEYSHR_LOCK * are set, it cannot possibly be running; otherwise have to * check. */ if ((tuple->t_infomask & (HEAP_XMAX_EXCL_LOCK | HEAP_XMAX_KEYSHR_LOCK)) && MultiXactIdIsRunning(HeapTupleHeaderGetRawXmax(tuple))) return HEAPTUPLE_LIVE; SetHintBits(tuple, buffer, HEAP_XMAX_INVALID, InvalidTransactionId); } else { if (TransactionIdIsInProgress(HeapTupleHeaderGetRawXmax(tuple))) return HEAPTUPLE_LIVE; SetHintBits(tuple, buffer, HEAP_XMAX_INVALID, InvalidTransactionId); } } /* * We don't really care whether xmax did commit, abort or crash. * We know that xmax did lock the tuple, but it did not and will * never actually update it. */ return HEAPTUPLE_LIVE; } if (tuple->t_infomask & HEAP_XMAX_IS_MULTI) { TransactionId xmax; if (MultiXactIdIsRunning(HeapTupleHeaderGetRawXmax(tuple))) { /* already checked above */ Assert(!HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask)); xmax = HeapTupleGetUpdateXid(tuple); if (!TransactionIdIsValid(xmax)) return HEAPTUPLE_LIVE; if (TransactionIdIsInProgress(xmax)) return HEAPTUPLE_DELETE_IN_PROGRESS; else if (TransactionIdDidCommit(xmax)) /* there are still lockers around -- can't return DEAD here */ return HEAPTUPLE_RECENTLY_DEAD; /* updating transaction aborted */ return HEAPTUPLE_LIVE; } Assert(!(tuple->t_infomask & HEAP_XMAX_COMMITTED)); xmax = HeapTupleGetUpdateXid(tuple); if (!TransactionIdIsValid(xmax)) return HEAPTUPLE_LIVE; /* multi is not running -- updating xact cannot be */ Assert(!TransactionIdIsInProgress(xmax)); if (TransactionIdDidCommit(xmax)) { if (!TransactionIdPrecedes(xmax, OldestXmin)) return HEAPTUPLE_RECENTLY_DEAD; else return HEAPTUPLE_DEAD; } else { /* * Not in Progress, Not Committed, so either Aborted or crashed. */ SetHintBits(tuple, buffer, HEAP_XMAX_INVALID, InvalidTransactionId); return HEAPTUPLE_LIVE; } /* * Deleter committed, but perhaps it was recent enough that some open * transactions could still see the tuple. */ /* Otherwise, it's dead and removable */ return HEAPTUPLE_DEAD; } if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED)) { if (TransactionIdIsInProgress(HeapTupleHeaderGetRawXmax(tuple))) return HEAPTUPLE_DELETE_IN_PROGRESS; else if (TransactionIdDidCommit(HeapTupleHeaderGetRawXmax(tuple))) SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED, HeapTupleHeaderGetRawXmax(tuple)); else { /* * Not in Progress, Not Committed, so either Aborted or crashed */ SetHintBits(tuple, buffer, HEAP_XMAX_INVALID, InvalidTransactionId); return HEAPTUPLE_LIVE; } /* * At this point the xmax is known committed, but we might not have * been able to set the hint bit yet; so we can no longer Assert that * it's set. */ } /* * Deleter committed, but perhaps it was recent enough that some open * transactions could still see the tuple. */ if (!TransactionIdPrecedes(HeapTupleHeaderGetRawXmax(tuple), OldestXmin)) return HEAPTUPLE_RECENTLY_DEAD; /* Otherwise, it's dead and removable */ return HEAPTUPLE_DEAD; }
void HeapTupleSetHintBits | ( | HeapTupleHeader | tuple, | |
Buffer | buffer, | |||
uint16 | infomask, | |||
TransactionId | xid | |||
) |
Definition at line 134 of file tqual.c.
References SetHintBits().
Referenced by UpdateXmaxHintBits().
{ SetHintBits(tuple, buffer, infomask, xid); }
static void SetHintBits | ( | HeapTupleHeader | tuple, | |
Buffer | buffer, | |||
uint16 | infomask, | |||
TransactionId | xid | |||
) | [inline, static] |
Definition at line 111 of file tqual.c.
References BufferIsPermanent(), MarkBufferDirtyHint(), HeapTupleHeaderData::t_infomask, TransactionIdGetCommitLSN(), TransactionIdIsValid, and XLogNeedsFlush().
Referenced by HeapTupleSatisfiesDirty(), HeapTupleSatisfiesMVCC(), HeapTupleSatisfiesNow(), HeapTupleSatisfiesSelf(), HeapTupleSatisfiesToast(), HeapTupleSatisfiesUpdate(), HeapTupleSatisfiesVacuum(), and HeapTupleSetHintBits().
{ if (TransactionIdIsValid(xid)) { /* NB: xid must be known committed here! */ XLogRecPtr commitLSN = TransactionIdGetCommitLSN(xid); if (XLogNeedsFlush(commitLSN) && BufferIsPermanent(buffer)) return; /* not flushed yet, so don't set hint */ } tuple->t_infomask |= infomask; MarkBufferDirtyHint(buffer); }
static bool XidInMVCCSnapshot | ( | TransactionId | xid, | |
Snapshot | snapshot | |||
) | [static] |
Definition at line 1515 of file tqual.c.
References i, SnapshotData::suboverflowed, SubTransGetTopmostTransaction(), SnapshotData::subxcnt, SnapshotData::subxip, SnapshotData::takenDuringRecovery, TransactionIdEquals, TransactionIdFollowsOrEquals(), TransactionIdPrecedes(), SnapshotData::xcnt, SnapshotData::xip, SnapshotData::xmax, and SnapshotData::xmin.
Referenced by HeapTupleSatisfiesMVCC().
{ uint32 i; /* * Make a quick range check to eliminate most XIDs without looking at the * xip arrays. Note that this is OK even if we convert a subxact XID to * its parent below, because a subxact with XID < xmin has surely also got * a parent with XID < xmin, while one with XID >= xmax must belong to a * parent that was not yet committed at the time of this snapshot. */ /* Any xid < xmin is not in-progress */ if (TransactionIdPrecedes(xid, snapshot->xmin)) return false; /* Any xid >= xmax is in-progress */ if (TransactionIdFollowsOrEquals(xid, snapshot->xmax)) return true; /* * Snapshot information is stored slightly differently in snapshots taken * during recovery. */ if (!snapshot->takenDuringRecovery) { /* * If the snapshot contains full subxact data, the fastest way to * check things is just to compare the given XID against both subxact * XIDs and top-level XIDs. If the snapshot overflowed, we have to * use pg_subtrans to convert a subxact XID to its parent XID, but * then we need only look at top-level XIDs not subxacts. */ if (!snapshot->suboverflowed) { /* full data, so search subxip */ int32 j; for (j = 0; j < snapshot->subxcnt; j++) { if (TransactionIdEquals(xid, snapshot->subxip[j])) return true; } /* not there, fall through to search xip[] */ } else { /* overflowed, so convert xid to top-level */ xid = SubTransGetTopmostTransaction(xid); /* * If xid was indeed a subxact, we might now have an xid < xmin, * so recheck to avoid an array scan. No point in rechecking * xmax. */ if (TransactionIdPrecedes(xid, snapshot->xmin)) return false; } for (i = 0; i < snapshot->xcnt; i++) { if (TransactionIdEquals(xid, snapshot->xip[i])) return true; } } else { int32 j; /* * In recovery we store all xids in the subxact array because it is by * far the bigger array, and we mostly don't know which xids are * top-level and which are subxacts. The xip array is empty. * * We start by searching subtrans, if we overflowed. */ if (snapshot->suboverflowed) { /* overflowed, so convert xid to top-level */ xid = SubTransGetTopmostTransaction(xid); /* * If xid was indeed a subxact, we might now have an xid < xmin, * so recheck to avoid an array scan. No point in rechecking * xmax. */ if (TransactionIdPrecedes(xid, snapshot->xmin)) return false; } /* * We now have either a top-level xid higher than xmin or an * indeterminate xid. We don't know whether it's top level or subxact * but it doesn't matter. If it's present, the xid is visible. */ for (j = 0; j < snapshot->subxcnt; j++) { if (TransactionIdEquals(xid, snapshot->subxip[j])) return true; } } return false; }
SnapshotData SnapshotAnyData = {HeapTupleSatisfiesAny} |
SnapshotData SnapshotNowData = {HeapTupleSatisfiesNow} |
SnapshotData SnapshotSelfData = {HeapTupleSatisfiesSelf} |
SnapshotData SnapshotToastData = {HeapTupleSatisfiesToast} |