PostgreSQL Source Code  git master
heapam_visibility.c File Reference
#include "postgres.h"
#include "access/heapam.h"
#include "access/htup_details.h"
#include "access/multixact.h"
#include "access/subtrans.h"
#include "access/tableam.h"
#include "access/transam.h"
#include "access/xact.h"
#include "access/xlog.h"
#include "storage/bufmgr.h"
#include "storage/procarray.h"
#include "utils/builtins.h"
#include "utils/combocid.h"
#include "utils/snapmgr.h"
Include dependency graph for heapam_visibility.c:

Go to the source code of this file.

Functions

static void SetHintBits (HeapTupleHeader tuple, Buffer buffer, uint16 infomask, TransactionId xid)
 
void HeapTupleSetHintBits (HeapTupleHeader tuple, Buffer buffer, uint16 infomask, TransactionId xid)
 
static bool HeapTupleSatisfiesSelf (HeapTuple htup, Snapshot snapshot, Buffer buffer)
 
static bool HeapTupleSatisfiesAny (HeapTuple htup, Snapshot snapshot, Buffer buffer)
 
static bool HeapTupleSatisfiesToast (HeapTuple htup, Snapshot snapshot, Buffer buffer)
 
TM_Result HeapTupleSatisfiesUpdate (HeapTuple htup, CommandId curcid, Buffer buffer)
 
static bool HeapTupleSatisfiesDirty (HeapTuple htup, Snapshot snapshot, Buffer buffer)
 
static bool HeapTupleSatisfiesMVCC (HeapTuple htup, Snapshot snapshot, Buffer buffer)
 
HTSV_Result HeapTupleSatisfiesVacuum (HeapTuple htup, TransactionId OldestXmin, Buffer buffer)
 
HTSV_Result HeapTupleSatisfiesVacuumHorizon (HeapTuple htup, Buffer buffer, TransactionId *dead_after)
 
static bool HeapTupleSatisfiesNonVacuumable (HeapTuple htup, Snapshot snapshot, Buffer buffer)
 
bool HeapTupleIsSurelyDead (HeapTuple htup, GlobalVisState *vistest)
 
bool HeapTupleHeaderIsOnlyLocked (HeapTupleHeader tuple)
 
static bool TransactionIdInArray (TransactionId xid, TransactionId *xip, Size num)
 
static bool HeapTupleSatisfiesHistoricMVCC (HeapTuple htup, Snapshot snapshot, Buffer buffer)
 
bool HeapTupleSatisfiesVisibility (HeapTuple htup, Snapshot snapshot, Buffer buffer)
 

Function Documentation

◆ HeapTupleHeaderIsOnlyLocked()

bool HeapTupleHeaderIsOnlyLocked ( HeapTupleHeader  tuple)

Definition at line 1522 of file heapam_visibility.c.

1523 {
1524  TransactionId xmax;
1525 
1526  /* if there's no valid Xmax, then there's obviously no update either */
1527  if (tuple->t_infomask & HEAP_XMAX_INVALID)
1528  return true;
1529 
1530  if (tuple->t_infomask & HEAP_XMAX_LOCK_ONLY)
1531  return true;
1532 
1533  /* invalid xmax means no update */
1535  return true;
1536 
1537  /*
1538  * if HEAP_XMAX_LOCK_ONLY is not set and not a multi, then this must
1539  * necessarily have been updated
1540  */
1541  if (!(tuple->t_infomask & HEAP_XMAX_IS_MULTI))
1542  return false;
1543 
1544  /* ... but if it's a multi, then perhaps the updating Xid aborted. */
1545  xmax = HeapTupleGetUpdateXid(tuple);
1546 
1547  /* not LOCKED_ONLY, so it has to have an xmax */
1549 
1551  return false;
1552  if (TransactionIdIsInProgress(xmax))
1553  return false;
1554  if (TransactionIdDidCommit(xmax))
1555  return false;
1556 
1557  /*
1558  * not current, not in progress, not committed -- must have aborted or
1559  * crashed
1560  */
1561  return true;
1562 }
uint32 TransactionId
Definition: c.h:641
TransactionId HeapTupleGetUpdateXid(HeapTupleHeader tuple)
Definition: heapam.c:7110
#define HEAP_XMAX_LOCK_ONLY
Definition: htup_details.h:197
#define HEAP_XMAX_IS_MULTI
Definition: htup_details.h:209
#define HEAP_XMAX_INVALID
Definition: htup_details.h:208
#define HeapTupleHeaderGetRawXmax(tup)
Definition: htup_details.h:371
Assert(fmt[strlen(fmt) - 1] !='\n')
bool TransactionIdIsInProgress(TransactionId xid)
Definition: procarray.c:1391
bool TransactionIdDidCommit(TransactionId transactionId)
Definition: transam.c:126
#define TransactionIdIsValid(xid)
Definition: transam.h:41
bool TransactionIdIsCurrentTransactionId(TransactionId xid)
Definition: xact.c:926

References Assert(), 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(), HeapTupleSatisfiesVacuumHorizon(), and rewrite_heap_tuple().

◆ HeapTupleIsSurelyDead()

bool HeapTupleIsSurelyDead ( HeapTuple  htup,
GlobalVisState vistest 
)

Definition at line 1467 of file heapam_visibility.c.

1468 {
1469  HeapTupleHeader tuple = htup->t_data;
1470 
1471  Assert(ItemPointerIsValid(&htup->t_self));
1472  Assert(htup->t_tableOid != InvalidOid);
1473 
1474  /*
1475  * If the inserting transaction is marked invalid, then it aborted, and
1476  * the tuple is definitely dead. If it's marked neither committed nor
1477  * invalid, then we assume it's still alive (since the presumption is that
1478  * all relevant hint bits were just set moments ago).
1479  */
1480  if (!HeapTupleHeaderXminCommitted(tuple))
1481  return HeapTupleHeaderXminInvalid(tuple);
1482 
1483  /*
1484  * If the inserting transaction committed, but any deleting transaction
1485  * aborted, the tuple is still alive.
1486  */
1487  if (tuple->t_infomask & HEAP_XMAX_INVALID)
1488  return false;
1489 
1490  /*
1491  * If the XMAX is just a lock, the tuple is still alive.
1492  */
1494  return false;
1495 
1496  /*
1497  * If the Xmax is a MultiXact, it might be dead or alive, but we cannot
1498  * know without checking pg_multixact.
1499  */
1500  if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
1501  return false;
1502 
1503  /* If deleter isn't known to have committed, assume it's still running. */
1504  if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED))
1505  return false;
1506 
1507  /* Deleter committed, so tuple is dead if the XID is old enough. */
1508  return GlobalVisTestIsRemovableXid(vistest,
1509  HeapTupleHeaderGetRawXmax(tuple));
1510 }
#define HEAP_XMAX_IS_LOCKED_ONLY(infomask)
Definition: htup_details.h:227
#define HEAP_XMAX_COMMITTED
Definition: htup_details.h:207
#define HeapTupleHeaderXminCommitted(tup)
Definition: htup_details.h:320
#define HeapTupleHeaderXminInvalid(tup)
Definition: htup_details.h:325
static bool ItemPointerIsValid(const ItemPointerData *pointer)
Definition: itemptr.h:83
#define InvalidOid
Definition: postgres_ext.h:36
bool GlobalVisTestIsRemovableXid(GlobalVisState *state, TransactionId xid)
Definition: procarray.c:4175
ItemPointerData t_self
Definition: htup.h:65
HeapTupleHeader t_data
Definition: htup.h:68
Oid t_tableOid
Definition: htup.h:66

References Assert(), GlobalVisTestIsRemovableXid(), HEAP_XMAX_COMMITTED, HEAP_XMAX_INVALID, HEAP_XMAX_IS_LOCKED_ONLY, HEAP_XMAX_IS_MULTI, HeapTupleHeaderGetRawXmax, HeapTupleHeaderXminCommitted, HeapTupleHeaderXminInvalid, InvalidOid, ItemPointerIsValid(), HeapTupleData::t_data, HeapTupleHeaderData::t_infomask, HeapTupleData::t_self, and HeapTupleData::t_tableOid.

Referenced by heap_hot_search_buffer().

◆ HeapTupleSatisfiesAny()

static bool HeapTupleSatisfiesAny ( HeapTuple  htup,
Snapshot  snapshot,
Buffer  buffer 
)
static

Definition at line 342 of file heapam_visibility.c.

343 {
344  return true;
345 }

Referenced by HeapTupleSatisfiesVisibility().

◆ HeapTupleSatisfiesDirty()

static bool HeapTupleSatisfiesDirty ( HeapTuple  htup,
Snapshot  snapshot,
Buffer  buffer 
)
static

Definition at line 745 of file heapam_visibility.c.

747 {
748  HeapTupleHeader tuple = htup->t_data;
749 
751  Assert(htup->t_tableOid != InvalidOid);
752 
753  snapshot->xmin = snapshot->xmax = InvalidTransactionId;
754  snapshot->speculativeToken = 0;
755 
756  if (!HeapTupleHeaderXminCommitted(tuple))
757  {
758  if (HeapTupleHeaderXminInvalid(tuple))
759  return false;
760 
761  /* Used by pre-9.0 binary upgrades */
762  if (tuple->t_infomask & HEAP_MOVED_OFF)
763  {
765 
767  return false;
768  if (!TransactionIdIsInProgress(xvac))
769  {
770  if (TransactionIdDidCommit(xvac))
771  {
772  SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
774  return false;
775  }
776  SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
778  }
779  }
780  /* Used by pre-9.0 binary upgrades */
781  else if (tuple->t_infomask & HEAP_MOVED_IN)
782  {
784 
786  {
787  if (TransactionIdIsInProgress(xvac))
788  return false;
789  if (TransactionIdDidCommit(xvac))
790  SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
792  else
793  {
794  SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
796  return false;
797  }
798  }
799  }
801  {
802  if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
803  return true;
804 
805  if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask)) /* not deleter */
806  return true;
807 
808  if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
809  {
810  TransactionId xmax;
811 
812  xmax = HeapTupleGetUpdateXid(tuple);
813 
814  /* not LOCKED_ONLY, so it has to have an xmax */
816 
817  /* updating subtransaction must have aborted */
819  return true;
820  else
821  return false;
822  }
823 
825  {
826  /* deleting subtransaction must have aborted */
827  SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
829  return true;
830  }
831 
832  return false;
833  }
835  {
836  /*
837  * Return the speculative token to caller. Caller can worry about
838  * xmax, since it requires a conclusively locked row version, and
839  * a concurrent update to this tuple is a conflict of its
840  * purposes.
841  */
842  if (HeapTupleHeaderIsSpeculative(tuple))
843  {
844  snapshot->speculativeToken =
846 
847  Assert(snapshot->speculativeToken != 0);
848  }
849 
850  snapshot->xmin = HeapTupleHeaderGetRawXmin(tuple);
851  /* XXX shouldn't we fall through to look at xmax? */
852  return true; /* in insertion by other */
853  }
855  SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
857  else
858  {
859  /* it must have aborted or crashed */
860  SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
862  return false;
863  }
864  }
865 
866  /* by here, the inserting transaction has committed */
867 
868  if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */
869  return true;
870 
871  if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
872  {
874  return true;
875  return false; /* updated by other */
876  }
877 
878  if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
879  {
880  TransactionId xmax;
881 
883  return true;
884 
885  xmax = HeapTupleGetUpdateXid(tuple);
886 
887  /* not LOCKED_ONLY, so it has to have an xmax */
889 
891  return false;
892  if (TransactionIdIsInProgress(xmax))
893  {
894  snapshot->xmax = xmax;
895  return true;
896  }
897  if (TransactionIdDidCommit(xmax))
898  return false;
899  /* it must have aborted or crashed */
900  return true;
901  }
902 
904  {
906  return true;
907  return false;
908  }
909 
911  {
913  snapshot->xmax = HeapTupleHeaderGetRawXmax(tuple);
914  return true;
915  }
916 
918  {
919  /* it must have aborted or crashed */
920  SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
922  return true;
923  }
924 
925  /* xmax transaction committed */
926 
928  {
929  SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
931  return true;
932  }
933 
934  SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
936  return false; /* updated by other */
937 }
static void SetHintBits(HeapTupleHeader tuple, Buffer buffer, uint16 infomask, TransactionId xid)
#define HEAP_MOVED_OFF
Definition: htup_details.h:211
#define HEAP_XMIN_COMMITTED
Definition: htup_details.h:204
#define HeapTupleHeaderGetXvac(tup)
Definition: htup_details.h:411
#define HEAP_MOVED_IN
Definition: htup_details.h:212
#define HeapTupleHeaderGetSpeculativeToken(tup)
Definition: htup_details.h:433
#define HEAP_XMIN_INVALID
Definition: htup_details.h:205
#define HeapTupleHeaderGetRawXmin(tup)
Definition: htup_details.h:304
#define HeapTupleHeaderIsSpeculative(tup)
Definition: htup_details.h:428
TransactionId xmin
Definition: snapshot.h:157
TransactionId xmax
Definition: snapshot.h:158
uint32 speculativeToken
Definition: snapshot.h:193
#define InvalidTransactionId
Definition: transam.h:31

References Assert(), 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, HeapTupleHeaderGetRawXmin, HeapTupleHeaderGetSpeculativeToken, HeapTupleHeaderGetXvac, HeapTupleHeaderIsSpeculative, HeapTupleHeaderXminCommitted, HeapTupleHeaderXminInvalid, InvalidOid, InvalidTransactionId, ItemPointerIsValid(), SetHintBits(), SnapshotData::speculativeToken, HeapTupleData::t_data, HeapTupleHeaderData::t_infomask, HeapTupleData::t_self, HeapTupleData::t_tableOid, TransactionIdDidCommit(), TransactionIdIsCurrentTransactionId(), TransactionIdIsInProgress(), TransactionIdIsValid, SnapshotData::xmax, and SnapshotData::xmin.

Referenced by HeapTupleSatisfiesVisibility().

◆ HeapTupleSatisfiesHistoricMVCC()

static bool HeapTupleSatisfiesHistoricMVCC ( HeapTuple  htup,
Snapshot  snapshot,
Buffer  buffer 
)
static

Definition at line 1589 of file heapam_visibility.c.

1591 {
1592  HeapTupleHeader tuple = htup->t_data;
1593  TransactionId xmin = HeapTupleHeaderGetXmin(tuple);
1595 
1596  Assert(ItemPointerIsValid(&htup->t_self));
1597  Assert(htup->t_tableOid != InvalidOid);
1598 
1599  /* inserting transaction aborted */
1600  if (HeapTupleHeaderXminInvalid(tuple))
1601  {
1603  return false;
1604  }
1605  /* check if it's one of our txids, toplevel is also in there */
1606  else if (TransactionIdInArray(xmin, snapshot->subxip, snapshot->subxcnt))
1607  {
1608  bool resolved;
1610  CommandId cmax = InvalidCommandId;
1611 
1612  /*
1613  * another transaction might have (tried to) delete this tuple or
1614  * cmin/cmax was stored in a combo CID. So we need to lookup the
1615  * actual values externally.
1616  */
1618  htup, buffer,
1619  &cmin, &cmax);
1620 
1621  /*
1622  * If we haven't resolved the combo CID to cmin/cmax, that means we
1623  * have not decoded the combo CID yet. That means the cmin is
1624  * definitely in the future, and we're not supposed to see the tuple
1625  * yet.
1626  *
1627  * XXX This only applies to decoding of in-progress transactions. In
1628  * regular logical decoding we only execute this code at commit time,
1629  * at which point we should have seen all relevant combo CIDs. So
1630  * ideally, we should error out in this case but in practice, this
1631  * won't happen. If we are too worried about this then we can add an
1632  * elog inside ResolveCminCmaxDuringDecoding.
1633  *
1634  * XXX For the streaming case, we can track the largest combo CID
1635  * assigned, and error out based on this (when unable to resolve combo
1636  * CID below that observed maximum value).
1637  */
1638  if (!resolved)
1639  return false;
1640 
1641  Assert(cmin != InvalidCommandId);
1642 
1643  if (cmin >= snapshot->curcid)
1644  return false; /* inserted after scan started */
1645  /* fall through */
1646  }
1647  /* committed before our xmin horizon. Do a normal visibility check. */
1648  else if (TransactionIdPrecedes(xmin, snapshot->xmin))
1649  {
1651  !TransactionIdDidCommit(xmin)));
1652 
1653  /* check for hint bit first, consult clog afterwards */
1654  if (!HeapTupleHeaderXminCommitted(tuple) &&
1655  !TransactionIdDidCommit(xmin))
1656  return false;
1657  /* fall through */
1658  }
1659  /* beyond our xmax horizon, i.e. invisible */
1660  else if (TransactionIdFollowsOrEquals(xmin, snapshot->xmax))
1661  {
1662  return false;
1663  }
1664  /* check if it's a committed transaction in [xmin, xmax) */
1665  else if (TransactionIdInArray(xmin, snapshot->xip, snapshot->xcnt))
1666  {
1667  /* fall through */
1668  }
1669 
1670  /*
1671  * none of the above, i.e. between [xmin, xmax) but hasn't committed. I.e.
1672  * invisible.
1673  */
1674  else
1675  {
1676  return false;
1677  }
1678 
1679  /* at this point we know xmin is visible, go on to check xmax */
1680 
1681  /* xid invalid or aborted */
1682  if (tuple->t_infomask & HEAP_XMAX_INVALID)
1683  return true;
1684  /* locked tuples are always visible */
1685  else if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
1686  return true;
1687 
1688  /*
1689  * We can see multis here if we're looking at user tables or if somebody
1690  * SELECT ... FOR SHARE/UPDATE a system table.
1691  */
1692  else if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
1693  {
1694  xmax = HeapTupleGetUpdateXid(tuple);
1695  }
1696 
1697  /* check if it's one of our txids, toplevel is also in there */
1698  if (TransactionIdInArray(xmax, snapshot->subxip, snapshot->subxcnt))
1699  {
1700  bool resolved;
1701  CommandId cmin;
1703 
1704  /* Lookup actual cmin/cmax values */
1706  htup, buffer,
1707  &cmin, &cmax);
1708 
1709  /*
1710  * If we haven't resolved the combo CID to cmin/cmax, that means we
1711  * have not decoded the combo CID yet. That means the cmax is
1712  * definitely in the future, and we're still supposed to see the
1713  * tuple.
1714  *
1715  * XXX This only applies to decoding of in-progress transactions. In
1716  * regular logical decoding we only execute this code at commit time,
1717  * at which point we should have seen all relevant combo CIDs. So
1718  * ideally, we should error out in this case but in practice, this
1719  * won't happen. If we are too worried about this then we can add an
1720  * elog inside ResolveCminCmaxDuringDecoding.
1721  *
1722  * XXX For the streaming case, we can track the largest combo CID
1723  * assigned, and error out based on this (when unable to resolve combo
1724  * CID below that observed maximum value).
1725  */
1726  if (!resolved || cmax == InvalidCommandId)
1727  return true;
1728 
1729  if (cmax >= snapshot->curcid)
1730  return true; /* deleted after scan started */
1731  else
1732  return false; /* deleted before scan started */
1733  }
1734  /* below xmin horizon, normal transaction state is valid */
1735  else if (TransactionIdPrecedes(xmax, snapshot->xmin))
1736  {
1737  Assert(!(tuple->t_infomask & HEAP_XMAX_COMMITTED &&
1738  !TransactionIdDidCommit(xmax)));
1739 
1740  /* check hint bit first */
1741  if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
1742  return false;
1743 
1744  /* check clog */
1745  return !TransactionIdDidCommit(xmax);
1746  }
1747  /* above xmax horizon, we cannot possibly see the deleting transaction */
1748  else if (TransactionIdFollowsOrEquals(xmax, snapshot->xmax))
1749  return true;
1750  /* xmax is between [xmin, xmax), check known committed array */
1751  else if (TransactionIdInArray(xmax, snapshot->xip, snapshot->xcnt))
1752  return false;
1753  /* xmax is between [xmin, xmax), but known not to have committed yet */
1754  else
1755  return true;
1756 }
#define InvalidCommandId
Definition: c.h:658
uint32 CommandId
Definition: c.h:655
static bool TransactionIdInArray(TransactionId xid, TransactionId *xip, Size num)
#define HeapTupleHeaderGetXmin(tup)
Definition: htup_details.h:309
#define HeapTupleHeaderGetRawCommandId(tup)
Definition: htup_details.h:387
bool ResolveCminCmaxDuringDecoding(HTAB *tuplecid_data, Snapshot snapshot, HeapTuple htup, Buffer buffer, CommandId *cmin, CommandId *cmax)
HTAB * HistoricSnapshotGetTupleCids(void)
Definition: snapmgr.c:1684
int32 subxcnt
Definition: snapshot.h:181
CommandId curcid
Definition: snapshot.h:187
uint32 xcnt
Definition: snapshot.h:169
TransactionId * subxip
Definition: snapshot.h:180
TransactionId * xip
Definition: snapshot.h:168
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition: transam.c:280
bool TransactionIdFollowsOrEquals(TransactionId id1, TransactionId id2)
Definition: transam.c:329

References Assert(), SnapshotData::curcid, HEAP_XMAX_COMMITTED, HEAP_XMAX_INVALID, HEAP_XMAX_IS_LOCKED_ONLY, HEAP_XMAX_IS_MULTI, HeapTupleGetUpdateXid(), HeapTupleHeaderGetRawCommandId, HeapTupleHeaderGetRawXmax, HeapTupleHeaderGetXmin, HeapTupleHeaderXminCommitted, HeapTupleHeaderXminInvalid, HistoricSnapshotGetTupleCids(), InvalidCommandId, InvalidOid, ItemPointerIsValid(), ResolveCminCmaxDuringDecoding(), SnapshotData::subxcnt, SnapshotData::subxip, HeapTupleData::t_data, HeapTupleHeaderData::t_infomask, HeapTupleData::t_self, HeapTupleData::t_tableOid, TransactionIdDidCommit(), TransactionIdFollowsOrEquals(), TransactionIdInArray(), TransactionIdPrecedes(), SnapshotData::xcnt, SnapshotData::xip, SnapshotData::xmax, and SnapshotData::xmin.

Referenced by HeapTupleSatisfiesVisibility().

◆ HeapTupleSatisfiesMVCC()

static bool HeapTupleSatisfiesMVCC ( HeapTuple  htup,
Snapshot  snapshot,
Buffer  buffer 
)
static

Definition at line 962 of file heapam_visibility.c.

964 {
965  HeapTupleHeader tuple = htup->t_data;
966 
968  Assert(htup->t_tableOid != InvalidOid);
969 
970  if (!HeapTupleHeaderXminCommitted(tuple))
971  {
972  if (HeapTupleHeaderXminInvalid(tuple))
973  return false;
974 
975  /* Used by pre-9.0 binary upgrades */
976  if (tuple->t_infomask & HEAP_MOVED_OFF)
977  {
979 
981  return false;
982  if (!XidInMVCCSnapshot(xvac, snapshot))
983  {
984  if (TransactionIdDidCommit(xvac))
985  {
986  SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
988  return false;
989  }
990  SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
992  }
993  }
994  /* Used by pre-9.0 binary upgrades */
995  else if (tuple->t_infomask & HEAP_MOVED_IN)
996  {
998 
1000  {
1001  if (XidInMVCCSnapshot(xvac, snapshot))
1002  return false;
1003  if (TransactionIdDidCommit(xvac))
1004  SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
1006  else
1007  {
1008  SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
1010  return false;
1011  }
1012  }
1013  }
1015  {
1016  if (HeapTupleHeaderGetCmin(tuple) >= snapshot->curcid)
1017  return false; /* inserted after scan started */
1018 
1019  if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
1020  return true;
1021 
1022  if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask)) /* not deleter */
1023  return true;
1024 
1025  if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
1026  {
1027  TransactionId xmax;
1028 
1029  xmax = HeapTupleGetUpdateXid(tuple);
1030 
1031  /* not LOCKED_ONLY, so it has to have an xmax */
1033 
1034  /* updating subtransaction must have aborted */
1036  return true;
1037  else if (HeapTupleHeaderGetCmax(tuple) >= snapshot->curcid)
1038  return true; /* updated after scan started */
1039  else
1040  return false; /* updated before scan started */
1041  }
1042 
1044  {
1045  /* deleting subtransaction must have aborted */
1046  SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
1048  return true;
1049  }
1050 
1051  if (HeapTupleHeaderGetCmax(tuple) >= snapshot->curcid)
1052  return true; /* deleted after scan started */
1053  else
1054  return false; /* deleted before scan started */
1055  }
1056  else if (XidInMVCCSnapshot(HeapTupleHeaderGetRawXmin(tuple), snapshot))
1057  return false;
1059  SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
1060  HeapTupleHeaderGetRawXmin(tuple));
1061  else
1062  {
1063  /* it must have aborted or crashed */
1064  SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
1066  return false;
1067  }
1068  }
1069  else
1070  {
1071  /* xmin is committed, but maybe not according to our snapshot */
1072  if (!HeapTupleHeaderXminFrozen(tuple) &&
1073  XidInMVCCSnapshot(HeapTupleHeaderGetRawXmin(tuple), snapshot))
1074  return false; /* treat as still in progress */
1075  }
1076 
1077  /* by here, the inserting transaction has committed */
1078 
1079  if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */
1080  return true;
1081 
1083  return true;
1084 
1085  if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
1086  {
1087  TransactionId xmax;
1088 
1089  /* already checked above */
1091 
1092  xmax = HeapTupleGetUpdateXid(tuple);
1093 
1094  /* not LOCKED_ONLY, so it has to have an xmax */
1096 
1098  {
1099  if (HeapTupleHeaderGetCmax(tuple) >= snapshot->curcid)
1100  return true; /* deleted after scan started */
1101  else
1102  return false; /* deleted before scan started */
1103  }
1104  if (XidInMVCCSnapshot(xmax, snapshot))
1105  return true;
1106  if (TransactionIdDidCommit(xmax))
1107  return false; /* updating transaction committed */
1108  /* it must have aborted or crashed */
1109  return true;
1110  }
1111 
1112  if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED))
1113  {
1115  {
1116  if (HeapTupleHeaderGetCmax(tuple) >= snapshot->curcid)
1117  return true; /* deleted after scan started */
1118  else
1119  return false; /* deleted before scan started */
1120  }
1121 
1122  if (XidInMVCCSnapshot(HeapTupleHeaderGetRawXmax(tuple), snapshot))
1123  return true;
1124 
1126  {
1127  /* it must have aborted or crashed */
1128  SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
1130  return true;
1131  }
1132 
1133  /* xmax transaction committed */
1134  SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
1135  HeapTupleHeaderGetRawXmax(tuple));
1136  }
1137  else
1138  {
1139  /* xmax is committed, but maybe not according to our snapshot */
1140  if (XidInMVCCSnapshot(HeapTupleHeaderGetRawXmax(tuple), snapshot))
1141  return true; /* treat as still in progress */
1142  }
1143 
1144  /* xmax transaction committed */
1145 
1146  return false;
1147 }
CommandId HeapTupleHeaderGetCmin(HeapTupleHeader tup)
Definition: combocid.c:104
CommandId HeapTupleHeaderGetCmax(HeapTupleHeader tup)
Definition: combocid.c:118
#define HeapTupleHeaderXminFrozen(tup)
Definition: htup_details.h:331
bool XidInMVCCSnapshot(TransactionId xid, Snapshot snapshot)
Definition: snapmgr.c:1862

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, HeapTupleHeaderGetRawXmin, HeapTupleHeaderGetXvac, HeapTupleHeaderXminCommitted, HeapTupleHeaderXminFrozen, HeapTupleHeaderXminInvalid, InvalidOid, InvalidTransactionId, ItemPointerIsValid(), SetHintBits(), HeapTupleData::t_data, HeapTupleHeaderData::t_infomask, HeapTupleData::t_self, HeapTupleData::t_tableOid, TransactionIdDidCommit(), TransactionIdIsCurrentTransactionId(), TransactionIdIsValid, and XidInMVCCSnapshot().

Referenced by HeapTupleSatisfiesVisibility().

◆ HeapTupleSatisfiesNonVacuumable()

static bool HeapTupleSatisfiesNonVacuumable ( HeapTuple  htup,
Snapshot  snapshot,
Buffer  buffer 
)
static

Definition at line 1431 of file heapam_visibility.c.

1433 {
1434  TransactionId dead_after = InvalidTransactionId;
1435  HTSV_Result res;
1436 
1437  res = HeapTupleSatisfiesVacuumHorizon(htup, buffer, &dead_after);
1438 
1440  {
1441  Assert(TransactionIdIsValid(dead_after));
1442 
1443  if (GlobalVisTestIsRemovableXid(snapshot->vistest, dead_after))
1444  res = HEAPTUPLE_DEAD;
1445  }
1446  else
1447  Assert(!TransactionIdIsValid(dead_after));
1448 
1449  return res != HEAPTUPLE_DEAD;
1450 }
HTSV_Result
Definition: heapam.h:95
@ HEAPTUPLE_RECENTLY_DEAD
Definition: heapam.h:98
@ HEAPTUPLE_DEAD
Definition: heapam.h:96
HTSV_Result HeapTupleSatisfiesVacuumHorizon(HeapTuple htup, Buffer buffer, TransactionId *dead_after)
struct GlobalVisState * vistest
Definition: snapshot.h:199

References Assert(), GlobalVisTestIsRemovableXid(), HEAPTUPLE_DEAD, HEAPTUPLE_RECENTLY_DEAD, HeapTupleSatisfiesVacuumHorizon(), InvalidTransactionId, res, TransactionIdIsValid, and SnapshotData::vistest.

Referenced by HeapTupleSatisfiesVisibility().

◆ HeapTupleSatisfiesSelf()

static bool HeapTupleSatisfiesSelf ( HeapTuple  htup,
Snapshot  snapshot,
Buffer  buffer 
)
static

Definition at line 172 of file heapam_visibility.c.

173 {
174  HeapTupleHeader tuple = htup->t_data;
175 
177  Assert(htup->t_tableOid != InvalidOid);
178 
179  if (!HeapTupleHeaderXminCommitted(tuple))
180  {
181  if (HeapTupleHeaderXminInvalid(tuple))
182  return false;
183 
184  /* Used by pre-9.0 binary upgrades */
185  if (tuple->t_infomask & HEAP_MOVED_OFF)
186  {
188 
190  return false;
191  if (!TransactionIdIsInProgress(xvac))
192  {
193  if (TransactionIdDidCommit(xvac))
194  {
195  SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
197  return false;
198  }
199  SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
201  }
202  }
203  /* Used by pre-9.0 binary upgrades */
204  else if (tuple->t_infomask & HEAP_MOVED_IN)
205  {
207 
209  {
210  if (TransactionIdIsInProgress(xvac))
211  return false;
212  if (TransactionIdDidCommit(xvac))
213  SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
215  else
216  {
217  SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
219  return false;
220  }
221  }
222  }
224  {
225  if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
226  return true;
227 
228  if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask)) /* not deleter */
229  return true;
230 
231  if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
232  {
233  TransactionId xmax;
234 
235  xmax = HeapTupleGetUpdateXid(tuple);
236 
237  /* not LOCKED_ONLY, so it has to have an xmax */
239 
240  /* updating subtransaction must have aborted */
242  return true;
243  else
244  return false;
245  }
246 
248  {
249  /* deleting subtransaction must have aborted */
250  SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
252  return true;
253  }
254 
255  return false;
256  }
258  return false;
260  SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
262  else
263  {
264  /* it must have aborted or crashed */
265  SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
267  return false;
268  }
269  }
270 
271  /* by here, the inserting transaction has committed */
272 
273  if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */
274  return true;
275 
276  if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
277  {
279  return true;
280  return false; /* updated by other */
281  }
282 
283  if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
284  {
285  TransactionId xmax;
286 
288  return true;
289 
290  xmax = HeapTupleGetUpdateXid(tuple);
291 
292  /* not LOCKED_ONLY, so it has to have an xmax */
294 
296  return false;
297  if (TransactionIdIsInProgress(xmax))
298  return true;
299  if (TransactionIdDidCommit(xmax))
300  return false;
301  /* it must have aborted or crashed */
302  return true;
303  }
304 
306  {
308  return true;
309  return false;
310  }
311 
313  return true;
314 
316  {
317  /* it must have aborted or crashed */
318  SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
320  return true;
321  }
322 
323  /* xmax transaction committed */
324 
326  {
327  SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
329  return true;
330  }
331 
332  SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
334  return false;
335 }

References Assert(), 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, HeapTupleHeaderGetRawXmin, HeapTupleHeaderGetXvac, HeapTupleHeaderXminCommitted, HeapTupleHeaderXminInvalid, InvalidOid, InvalidTransactionId, ItemPointerIsValid(), SetHintBits(), HeapTupleData::t_data, HeapTupleHeaderData::t_infomask, HeapTupleData::t_self, HeapTupleData::t_tableOid, TransactionIdDidCommit(), TransactionIdIsCurrentTransactionId(), TransactionIdIsInProgress(), and TransactionIdIsValid.

Referenced by HeapTupleSatisfiesVisibility().

◆ HeapTupleSatisfiesToast()

static bool HeapTupleSatisfiesToast ( HeapTuple  htup,
Snapshot  snapshot,
Buffer  buffer 
)
static

Definition at line 364 of file heapam_visibility.c.

366 {
367  HeapTupleHeader tuple = htup->t_data;
368 
370  Assert(htup->t_tableOid != InvalidOid);
371 
372  if (!HeapTupleHeaderXminCommitted(tuple))
373  {
374  if (HeapTupleHeaderXminInvalid(tuple))
375  return false;
376 
377  /* Used by pre-9.0 binary upgrades */
378  if (tuple->t_infomask & HEAP_MOVED_OFF)
379  {
381 
383  return false;
384  if (!TransactionIdIsInProgress(xvac))
385  {
386  if (TransactionIdDidCommit(xvac))
387  {
388  SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
390  return false;
391  }
392  SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
394  }
395  }
396  /* Used by pre-9.0 binary upgrades */
397  else if (tuple->t_infomask & HEAP_MOVED_IN)
398  {
400 
402  {
403  if (TransactionIdIsInProgress(xvac))
404  return false;
405  if (TransactionIdDidCommit(xvac))
406  SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
408  else
409  {
410  SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
412  return false;
413  }
414  }
415  }
416 
417  /*
418  * An invalid Xmin can be left behind by a speculative insertion that
419  * is canceled by super-deleting the tuple. This also applies to
420  * TOAST tuples created during speculative insertion.
421  */
423  return false;
424  }
425 
426  /* otherwise assume the tuple is valid for TOAST. */
427  return true;
428 }

References Assert(), HEAP_MOVED_IN, HEAP_MOVED_OFF, HEAP_XMIN_COMMITTED, HEAP_XMIN_INVALID, HeapTupleHeaderGetXmin, HeapTupleHeaderGetXvac, HeapTupleHeaderXminCommitted, HeapTupleHeaderXminInvalid, InvalidOid, InvalidTransactionId, ItemPointerIsValid(), SetHintBits(), HeapTupleData::t_data, HeapTupleHeaderData::t_infomask, HeapTupleData::t_self, HeapTupleData::t_tableOid, TransactionIdDidCommit(), TransactionIdIsCurrentTransactionId(), TransactionIdIsInProgress(), and TransactionIdIsValid.

Referenced by HeapTupleSatisfiesVisibility().

◆ HeapTupleSatisfiesUpdate()

TM_Result HeapTupleSatisfiesUpdate ( HeapTuple  htup,
CommandId  curcid,
Buffer  buffer 
)

Definition at line 460 of file heapam_visibility.c.

462 {
463  HeapTupleHeader tuple = htup->t_data;
464 
466  Assert(htup->t_tableOid != InvalidOid);
467 
468  if (!HeapTupleHeaderXminCommitted(tuple))
469  {
470  if (HeapTupleHeaderXminInvalid(tuple))
471  return TM_Invisible;
472 
473  /* Used by pre-9.0 binary upgrades */
474  if (tuple->t_infomask & HEAP_MOVED_OFF)
475  {
477 
479  return TM_Invisible;
480  if (!TransactionIdIsInProgress(xvac))
481  {
482  if (TransactionIdDidCommit(xvac))
483  {
484  SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
486  return TM_Invisible;
487  }
488  SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
490  }
491  }
492  /* Used by pre-9.0 binary upgrades */
493  else if (tuple->t_infomask & HEAP_MOVED_IN)
494  {
496 
498  {
499  if (TransactionIdIsInProgress(xvac))
500  return TM_Invisible;
501  if (TransactionIdDidCommit(xvac))
502  SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
504  else
505  {
506  SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
508  return TM_Invisible;
509  }
510  }
511  }
513  {
514  if (HeapTupleHeaderGetCmin(tuple) >= curcid)
515  return TM_Invisible; /* inserted after scan started */
516 
517  if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
518  return TM_Ok;
519 
521  {
522  TransactionId xmax;
523 
524  xmax = HeapTupleHeaderGetRawXmax(tuple);
525 
526  /*
527  * Careful here: even though this tuple was created by our own
528  * transaction, it might be locked by other transactions, if
529  * the original version was key-share locked when we updated
530  * it.
531  */
532 
533  if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
534  {
535  if (MultiXactIdIsRunning(xmax, true))
536  return TM_BeingModified;
537  else
538  return TM_Ok;
539  }
540 
541  /*
542  * If the locker is gone, then there is nothing of interest
543  * left in this Xmax; otherwise, report the tuple as
544  * locked/updated.
545  */
546  if (!TransactionIdIsInProgress(xmax))
547  return TM_Ok;
548  return TM_BeingModified;
549  }
550 
551  if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
552  {
553  TransactionId xmax;
554 
555  xmax = HeapTupleGetUpdateXid(tuple);
556 
557  /* not LOCKED_ONLY, so it has to have an xmax */
559 
560  /* deleting subtransaction must have aborted */
562  {
564  false))
565  return TM_BeingModified;
566  return TM_Ok;
567  }
568  else
569  {
570  if (HeapTupleHeaderGetCmax(tuple) >= curcid)
571  return TM_SelfModified; /* updated after scan started */
572  else
573  return TM_Invisible; /* updated before scan started */
574  }
575  }
576 
578  {
579  /* deleting subtransaction must have aborted */
580  SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
582  return TM_Ok;
583  }
584 
585  if (HeapTupleHeaderGetCmax(tuple) >= curcid)
586  return TM_SelfModified; /* updated after scan started */
587  else
588  return TM_Invisible; /* updated before scan started */
589  }
591  return TM_Invisible;
593  SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
595  else
596  {
597  /* it must have aborted or crashed */
598  SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
600  return TM_Invisible;
601  }
602  }
603 
604  /* by here, the inserting transaction has committed */
605 
606  if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */
607  return TM_Ok;
608 
609  if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
610  {
612  return TM_Ok;
613  if (!ItemPointerEquals(&htup->t_self, &tuple->t_ctid))
614  return TM_Updated; /* updated by other */
615  else
616  return TM_Deleted; /* deleted by other */
617  }
618 
619  if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
620  {
621  TransactionId xmax;
622 
623  if (HEAP_LOCKED_UPGRADED(tuple->t_infomask))
624  return TM_Ok;
625 
627  {
629  return TM_BeingModified;
630 
632  return TM_Ok;
633  }
634 
635  xmax = HeapTupleGetUpdateXid(tuple);
636  if (!TransactionIdIsValid(xmax))
637  {
639  return TM_BeingModified;
640  }
641 
642  /* not LOCKED_ONLY, so it has to have an xmax */
644 
646  {
647  if (HeapTupleHeaderGetCmax(tuple) >= curcid)
648  return TM_SelfModified; /* updated after scan started */
649  else
650  return TM_Invisible; /* updated before scan started */
651  }
652 
654  return TM_BeingModified;
655 
656  if (TransactionIdDidCommit(xmax))
657  {
658  if (!ItemPointerEquals(&htup->t_self, &tuple->t_ctid))
659  return TM_Updated;
660  else
661  return TM_Deleted;
662  }
663 
664  /*
665  * By here, the update in the Xmax is either aborted or crashed, but
666  * what about the other members?
667  */
668 
670  {
671  /*
672  * There's no member, even just a locker, alive anymore, so we can
673  * mark the Xmax as invalid.
674  */
675  SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
677  return TM_Ok;
678  }
679  else
680  {
681  /* There are lockers running */
682  return TM_BeingModified;
683  }
684  }
685 
687  {
689  return TM_BeingModified;
690  if (HeapTupleHeaderGetCmax(tuple) >= curcid)
691  return TM_SelfModified; /* updated after scan started */
692  else
693  return TM_Invisible; /* updated before scan started */
694  }
695 
697  return TM_BeingModified;
698 
700  {
701  /* it must have aborted or crashed */
702  SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
704  return TM_Ok;
705  }
706 
707  /* xmax transaction committed */
708 
710  {
711  SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
713  return TM_Ok;
714  }
715 
716  SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
718  if (!ItemPointerEquals(&htup->t_self, &tuple->t_ctid))
719  return TM_Updated; /* updated by other */
720  else
721  return TM_Deleted; /* deleted by other */
722 }
#define HEAP_LOCKED_UPGRADED(infomask)
Definition: htup_details.h:249
bool ItemPointerEquals(ItemPointer pointer1, ItemPointer pointer2)
Definition: itemptr.c:35
bool MultiXactIdIsRunning(MultiXactId multi, bool isLockOnly)
Definition: multixact.c:552
ItemPointerData t_ctid
Definition: htup_details.h:161
@ TM_Ok
Definition: tableam.h:77
@ TM_BeingModified
Definition: tableam.h:99
@ TM_Deleted
Definition: tableam.h:92
@ TM_Updated
Definition: tableam.h:89
@ TM_SelfModified
Definition: tableam.h:83
@ TM_Invisible
Definition: tableam.h:80

References Assert(), HEAP_LOCKED_UPGRADED, 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, HeapTupleHeaderGetRawXmin, HeapTupleHeaderGetXvac, HeapTupleHeaderXminCommitted, HeapTupleHeaderXminInvalid, InvalidOid, InvalidTransactionId, ItemPointerEquals(), ItemPointerIsValid(), MultiXactIdIsRunning(), SetHintBits(), HeapTupleHeaderData::t_ctid, HeapTupleData::t_data, HeapTupleHeaderData::t_infomask, HeapTupleData::t_self, HeapTupleData::t_tableOid, TM_BeingModified, TM_Deleted, TM_Invisible, TM_Ok, TM_SelfModified, TM_Updated, TransactionIdDidCommit(), TransactionIdIsCurrentTransactionId(), TransactionIdIsInProgress(), and TransactionIdIsValid.

Referenced by heap_delete(), heap_lock_tuple(), heap_update(), and pgrowlocks().

◆ HeapTupleSatisfiesVacuum()

HTSV_Result HeapTupleSatisfiesVacuum ( HeapTuple  htup,
TransactionId  OldestXmin,
Buffer  buffer 
)

◆ HeapTupleSatisfiesVacuumHorizon()

HTSV_Result HeapTupleSatisfiesVacuumHorizon ( HeapTuple  htup,
Buffer  buffer,
TransactionId dead_after 
)

Definition at line 1198 of file heapam_visibility.c.

1199 {
1200  HeapTupleHeader tuple = htup->t_data;
1201 
1202  Assert(ItemPointerIsValid(&htup->t_self));
1203  Assert(htup->t_tableOid != InvalidOid);
1204  Assert(dead_after != NULL);
1205 
1206  *dead_after = InvalidTransactionId;
1207 
1208  /*
1209  * Has inserting transaction committed?
1210  *
1211  * If the inserting transaction aborted, then the tuple was never visible
1212  * to any other transaction, so we can delete it immediately.
1213  */
1214  if (!HeapTupleHeaderXminCommitted(tuple))
1215  {
1216  if (HeapTupleHeaderXminInvalid(tuple))
1217  return HEAPTUPLE_DEAD;
1218  /* Used by pre-9.0 binary upgrades */
1219  else if (tuple->t_infomask & HEAP_MOVED_OFF)
1220  {
1221  TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
1222 
1225  if (TransactionIdIsInProgress(xvac))
1227  if (TransactionIdDidCommit(xvac))
1228  {
1229  SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
1231  return HEAPTUPLE_DEAD;
1232  }
1233  SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
1235  }
1236  /* Used by pre-9.0 binary upgrades */
1237  else if (tuple->t_infomask & HEAP_MOVED_IN)
1238  {
1239  TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
1240 
1243  if (TransactionIdIsInProgress(xvac))
1245  if (TransactionIdDidCommit(xvac))
1246  SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
1248  else
1249  {
1250  SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
1252  return HEAPTUPLE_DEAD;
1253  }
1254  }
1256  {
1257  if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
1259  /* only locked? run infomask-only check first, for performance */
1260  if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask) ||
1263  /* inserted and then deleted by same xact */
1266  /* deleting subtransaction must have aborted */
1268  }
1270  {
1271  /*
1272  * It'd be possible to discern between INSERT/DELETE in progress
1273  * here by looking at xmax - but that doesn't seem beneficial for
1274  * the majority of callers and even detrimental for some. We'd
1275  * rather have callers look at/wait for xmin than xmax. It's
1276  * always correct to return INSERT_IN_PROGRESS because that's
1277  * what's happening from the view of other backends.
1278  */
1280  }
1282  SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
1283  HeapTupleHeaderGetRawXmin(tuple));
1284  else
1285  {
1286  /*
1287  * Not in Progress, Not Committed, so either Aborted or crashed
1288  */
1289  SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
1291  return HEAPTUPLE_DEAD;
1292  }
1293 
1294  /*
1295  * At this point the xmin is known committed, but we might not have
1296  * been able to set the hint bit yet; so we can no longer Assert that
1297  * it's set.
1298  */
1299  }
1300 
1301  /*
1302  * Okay, the inserter committed, so it was good at some point. Now what
1303  * about the deleting transaction?
1304  */
1305  if (tuple->t_infomask & HEAP_XMAX_INVALID)
1306  return HEAPTUPLE_LIVE;
1307 
1309  {
1310  /*
1311  * "Deleting" xact really only locked it, so the tuple is live in any
1312  * case. However, we should make sure that either XMAX_COMMITTED or
1313  * XMAX_INVALID gets set once the xact is gone, to reduce the costs of
1314  * examining the tuple for future xacts.
1315  */
1316  if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED))
1317  {
1318  if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
1319  {
1320  /*
1321  * If it's a pre-pg_upgrade tuple, the multixact cannot
1322  * possibly be running; otherwise have to check.
1323  */
1324  if (!HEAP_LOCKED_UPGRADED(tuple->t_infomask) &&
1326  true))
1327  return HEAPTUPLE_LIVE;
1329  }
1330  else
1331  {
1333  return HEAPTUPLE_LIVE;
1334  SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
1336  }
1337  }
1338 
1339  /*
1340  * We don't really care whether xmax did commit, abort or crash. We
1341  * know that xmax did lock the tuple, but it did not and will never
1342  * actually update it.
1343  */
1344 
1345  return HEAPTUPLE_LIVE;
1346  }
1347 
1348  if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
1349  {
1350  TransactionId xmax = HeapTupleGetUpdateXid(tuple);
1351 
1352  /* already checked above */
1354 
1355  /* not LOCKED_ONLY, so it has to have an xmax */
1357 
1358  if (TransactionIdIsInProgress(xmax))
1360  else if (TransactionIdDidCommit(xmax))
1361  {
1362  /*
1363  * The multixact might still be running due to lockers. Need to
1364  * allow for pruning if below the xid horizon regardless --
1365  * otherwise we could end up with a tuple where the updater has to
1366  * be removed due to the horizon, but is not pruned away. It's
1367  * not a problem to prune that tuple, because any remaining
1368  * lockers will also be present in newer tuple versions.
1369  */
1370  *dead_after = xmax;
1371  return HEAPTUPLE_RECENTLY_DEAD;
1372  }
1373  else if (!MultiXactIdIsRunning(HeapTupleHeaderGetRawXmax(tuple), false))
1374  {
1375  /*
1376  * Not in Progress, Not Committed, so either Aborted or crashed.
1377  * Mark the Xmax as invalid.
1378  */
1380  }
1381 
1382  return HEAPTUPLE_LIVE;
1383  }
1384 
1385  if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED))
1386  {
1390  SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
1391  HeapTupleHeaderGetRawXmax(tuple));
1392  else
1393  {
1394  /*
1395  * Not in Progress, Not Committed, so either Aborted or crashed
1396  */
1397  SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
1399  return HEAPTUPLE_LIVE;
1400  }
1401 
1402  /*
1403  * At this point the xmax is known committed, but we might not have
1404  * been able to set the hint bit yet; so we can no longer Assert that
1405  * it's set.
1406  */
1407  }
1408 
1409  /*
1410  * Deleter committed, allow caller to check if it was recent enough that
1411  * some open transactions could still see the tuple.
1412  */
1413  *dead_after = HeapTupleHeaderGetRawXmax(tuple);
1414  return HEAPTUPLE_RECENTLY_DEAD;
1415 }
@ HEAPTUPLE_INSERT_IN_PROGRESS
Definition: heapam.h:99
@ HEAPTUPLE_LIVE
Definition: heapam.h:97
@ HEAPTUPLE_DELETE_IN_PROGRESS
Definition: heapam.h:100
bool HeapTupleHeaderIsOnlyLocked(HeapTupleHeader tuple)
#define HeapTupleHeaderGetUpdateXid(tup)
Definition: htup_details.h:361

References Assert(), HEAP_LOCKED_UPGRADED, 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, HEAPTUPLE_DEAD, HEAPTUPLE_DELETE_IN_PROGRESS, HEAPTUPLE_INSERT_IN_PROGRESS, HEAPTUPLE_LIVE, HEAPTUPLE_RECENTLY_DEAD, HeapTupleGetUpdateXid(), HeapTupleHeaderGetRawXmax, HeapTupleHeaderGetRawXmin, HeapTupleHeaderGetUpdateXid, HeapTupleHeaderGetXvac, HeapTupleHeaderIsOnlyLocked(), HeapTupleHeaderXminCommitted, HeapTupleHeaderXminInvalid, InvalidOid, InvalidTransactionId, ItemPointerIsValid(), MultiXactIdIsRunning(), SetHintBits(), HeapTupleData::t_data, HeapTupleHeaderData::t_infomask, HeapTupleData::t_self, HeapTupleData::t_tableOid, TransactionIdDidCommit(), TransactionIdIsCurrentTransactionId(), TransactionIdIsInProgress(), and TransactionIdIsValid.

Referenced by heap_prune_satisfies_vacuum(), HeapTupleSatisfiesNonVacuumable(), and HeapTupleSatisfiesVacuum().

◆ HeapTupleSatisfiesVisibility()

bool HeapTupleSatisfiesVisibility ( HeapTuple  htup,
Snapshot  snapshot,
Buffer  buffer 
)

Definition at line 1769 of file heapam_visibility.c.

1770 {
1771  switch (snapshot->snapshot_type)
1772  {
1773  case SNAPSHOT_MVCC:
1774  return HeapTupleSatisfiesMVCC(htup, snapshot, buffer);
1775  case SNAPSHOT_SELF:
1776  return HeapTupleSatisfiesSelf(htup, snapshot, buffer);
1777  case SNAPSHOT_ANY:
1778  return HeapTupleSatisfiesAny(htup, snapshot, buffer);
1779  case SNAPSHOT_TOAST:
1780  return HeapTupleSatisfiesToast(htup, snapshot, buffer);
1781  case SNAPSHOT_DIRTY:
1782  return HeapTupleSatisfiesDirty(htup, snapshot, buffer);
1784  return HeapTupleSatisfiesHistoricMVCC(htup, snapshot, buffer);
1786  return HeapTupleSatisfiesNonVacuumable(htup, snapshot, buffer);
1787  }
1788 
1789  return false; /* keep compiler quiet */
1790 }
static bool HeapTupleSatisfiesAny(HeapTuple htup, Snapshot snapshot, Buffer buffer)
static bool HeapTupleSatisfiesNonVacuumable(HeapTuple htup, Snapshot snapshot, Buffer buffer)
static bool HeapTupleSatisfiesToast(HeapTuple htup, Snapshot snapshot, Buffer buffer)
static bool HeapTupleSatisfiesDirty(HeapTuple htup, Snapshot snapshot, Buffer buffer)
static bool HeapTupleSatisfiesMVCC(HeapTuple htup, Snapshot snapshot, Buffer buffer)
static bool HeapTupleSatisfiesSelf(HeapTuple htup, Snapshot snapshot, Buffer buffer)
static bool HeapTupleSatisfiesHistoricMVCC(HeapTuple htup, Snapshot snapshot, Buffer buffer)
@ SNAPSHOT_TOAST
Definition: snapshot.h:74
@ SNAPSHOT_SELF
Definition: snapshot.h:64
@ SNAPSHOT_NON_VACUUMABLE
Definition: snapshot.h:118
@ SNAPSHOT_MVCC
Definition: snapshot.h:50
@ SNAPSHOT_ANY
Definition: snapshot.h:69
@ SNAPSHOT_HISTORIC_MVCC
Definition: snapshot.h:109
@ SNAPSHOT_DIRTY
Definition: snapshot.h:102
SnapshotType snapshot_type
Definition: snapshot.h:144

References HeapTupleSatisfiesAny(), HeapTupleSatisfiesDirty(), HeapTupleSatisfiesHistoricMVCC(), HeapTupleSatisfiesMVCC(), HeapTupleSatisfiesNonVacuumable(), HeapTupleSatisfiesSelf(), HeapTupleSatisfiesToast(), SNAPSHOT_ANY, SNAPSHOT_DIRTY, SNAPSHOT_HISTORIC_MVCC, SNAPSHOT_MVCC, SNAPSHOT_NON_VACUUMABLE, SNAPSHOT_SELF, SNAPSHOT_TOAST, and SnapshotData::snapshot_type.

Referenced by heap_delete(), heap_fetch(), heap_get_latest_tid(), heap_hot_search_buffer(), heap_update(), heapam_scan_bitmap_next_block(), heapam_tuple_satisfies_snapshot(), heapgetpage(), heapgettup(), pgstat_heap(), SampleHeapTupleVisible(), and ScanSourceDatabasePgClassPage().

◆ HeapTupleSetHintBits()

void HeapTupleSetHintBits ( HeapTupleHeader  tuple,
Buffer  buffer,
uint16  infomask,
TransactionId  xid 
)

Definition at line 143 of file heapam_visibility.c.

145 {
146  SetHintBits(tuple, buffer, infomask, xid);
147 }

References SetHintBits().

Referenced by UpdateXmaxHintBits().

◆ SetHintBits()

static void SetHintBits ( HeapTupleHeader  tuple,
Buffer  buffer,
uint16  infomask,
TransactionId  xid 
)
inlinestatic

Definition at line 116 of file heapam_visibility.c.

118 {
119  if (TransactionIdIsValid(xid))
120  {
121  /* NB: xid must be known committed here! */
122  XLogRecPtr commitLSN = TransactionIdGetCommitLSN(xid);
123 
124  if (BufferIsPermanent(buffer) && XLogNeedsFlush(commitLSN) &&
125  BufferGetLSNAtomic(buffer) < commitLSN)
126  {
127  /* not flushed and no LSN interlock, so don't set hint */
128  return;
129  }
130  }
131 
132  tuple->t_infomask |= infomask;
133  MarkBufferDirtyHint(buffer, true);
134 }
bool BufferIsPermanent(Buffer buffer)
Definition: bufmgr.c:3609
XLogRecPtr BufferGetLSNAtomic(Buffer buffer)
Definition: bufmgr.c:3639
void MarkBufferDirtyHint(Buffer buffer, bool buffer_std)
Definition: bufmgr.c:4625
XLogRecPtr TransactionIdGetCommitLSN(TransactionId xid)
Definition: transam.c:382
bool XLogNeedsFlush(XLogRecPtr record)
Definition: xlog.c:3066
uint64 XLogRecPtr
Definition: xlogdefs.h:21

References BufferGetLSNAtomic(), BufferIsPermanent(), MarkBufferDirtyHint(), HeapTupleHeaderData::t_infomask, TransactionIdGetCommitLSN(), TransactionIdIsValid, and XLogNeedsFlush().

Referenced by HeapTupleSatisfiesDirty(), HeapTupleSatisfiesMVCC(), HeapTupleSatisfiesSelf(), HeapTupleSatisfiesToast(), HeapTupleSatisfiesUpdate(), HeapTupleSatisfiesVacuumHorizon(), and HeapTupleSetHintBits().

◆ TransactionIdInArray()

static bool TransactionIdInArray ( TransactionId  xid,
TransactionId xip,
Size  num 
)
static

Definition at line 1568 of file heapam_visibility.c.

1569 {
1570  return num > 0 &&
1571  bsearch(&xid, xip, num, sizeof(TransactionId), xidComparator) != NULL;
1572 }
int xidComparator(const void *arg1, const void *arg2)
Definition: xid.c:139

References xidComparator().

Referenced by HeapTupleSatisfiesHistoricMVCC().