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/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/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 1520 of file heapam_visibility.c.

1521 {
1522  TransactionId xmax;
1523 
1524  /* if there's no valid Xmax, then there's obviously no update either */
1525  if (tuple->t_infomask & HEAP_XMAX_INVALID)
1526  return true;
1527 
1528  if (tuple->t_infomask & HEAP_XMAX_LOCK_ONLY)
1529  return true;
1530 
1531  /* invalid xmax means no update */
1533  return true;
1534 
1535  /*
1536  * if HEAP_XMAX_LOCK_ONLY is not set and not a multi, then this must
1537  * necessarily have been updated
1538  */
1539  if (!(tuple->t_infomask & HEAP_XMAX_IS_MULTI))
1540  return false;
1541 
1542  /* ... but if it's a multi, then perhaps the updating Xid aborted. */
1543  xmax = HeapTupleGetUpdateXid(tuple);
1544 
1545  /* not LOCKED_ONLY, so it has to have an xmax */
1547 
1549  return false;
1550  if (TransactionIdIsInProgress(xmax))
1551  return false;
1552  if (TransactionIdDidCommit(xmax))
1553  return false;
1554 
1555  /*
1556  * not current, not in progress, not committed -- must have aborted or
1557  * crashed
1558  */
1559  return true;
1560 }
uint32 TransactionId
Definition: c.h:639
TransactionId HeapTupleGetUpdateXid(HeapTupleHeader tuple)
Definition: heapam.c:7106
#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:1390
bool TransactionIdDidCommit(TransactionId transactionId)
Definition: transam.c:126
#define TransactionIdIsValid(xid)
Definition: transam.h:41
bool TransactionIdIsCurrentTransactionId(TransactionId xid)
Definition: xact.c:927

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 1465 of file heapam_visibility.c.

1466 {
1467  HeapTupleHeader tuple = htup->t_data;
1468 
1469  Assert(ItemPointerIsValid(&htup->t_self));
1470  Assert(htup->t_tableOid != InvalidOid);
1471 
1472  /*
1473  * If the inserting transaction is marked invalid, then it aborted, and
1474  * the tuple is definitely dead. If it's marked neither committed nor
1475  * invalid, then we assume it's still alive (since the presumption is that
1476  * all relevant hint bits were just set moments ago).
1477  */
1478  if (!HeapTupleHeaderXminCommitted(tuple))
1479  return HeapTupleHeaderXminInvalid(tuple);
1480 
1481  /*
1482  * If the inserting transaction committed, but any deleting transaction
1483  * aborted, the tuple is still alive.
1484  */
1485  if (tuple->t_infomask & HEAP_XMAX_INVALID)
1486  return false;
1487 
1488  /*
1489  * If the XMAX is just a lock, the tuple is still alive.
1490  */
1492  return false;
1493 
1494  /*
1495  * If the Xmax is a MultiXact, it might be dead or alive, but we cannot
1496  * know without checking pg_multixact.
1497  */
1498  if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
1499  return false;
1500 
1501  /* If deleter isn't known to have committed, assume it's still running. */
1502  if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED))
1503  return false;
1504 
1505  /* Deleter committed, so tuple is dead if the XID is old enough. */
1506  return GlobalVisTestIsRemovableXid(vistest,
1507  HeapTupleHeaderGetRawXmax(tuple));
1508 }
#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:4248
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 340 of file heapam_visibility.c.

341 {
342  return true;
343 }

Referenced by HeapTupleSatisfiesVisibility().

◆ HeapTupleSatisfiesDirty()

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

Definition at line 743 of file heapam_visibility.c.

745 {
746  HeapTupleHeader tuple = htup->t_data;
747 
749  Assert(htup->t_tableOid != InvalidOid);
750 
751  snapshot->xmin = snapshot->xmax = InvalidTransactionId;
752  snapshot->speculativeToken = 0;
753 
754  if (!HeapTupleHeaderXminCommitted(tuple))
755  {
756  if (HeapTupleHeaderXminInvalid(tuple))
757  return false;
758 
759  /* Used by pre-9.0 binary upgrades */
760  if (tuple->t_infomask & HEAP_MOVED_OFF)
761  {
763 
765  return false;
766  if (!TransactionIdIsInProgress(xvac))
767  {
768  if (TransactionIdDidCommit(xvac))
769  {
770  SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
772  return false;
773  }
774  SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
776  }
777  }
778  /* Used by pre-9.0 binary upgrades */
779  else if (tuple->t_infomask & HEAP_MOVED_IN)
780  {
782 
784  {
785  if (TransactionIdIsInProgress(xvac))
786  return false;
787  if (TransactionIdDidCommit(xvac))
788  SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
790  else
791  {
792  SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
794  return false;
795  }
796  }
797  }
799  {
800  if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
801  return true;
802 
803  if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask)) /* not deleter */
804  return true;
805 
806  if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
807  {
808  TransactionId xmax;
809 
810  xmax = HeapTupleGetUpdateXid(tuple);
811 
812  /* not LOCKED_ONLY, so it has to have an xmax */
814 
815  /* updating subtransaction must have aborted */
817  return true;
818  else
819  return false;
820  }
821 
823  {
824  /* deleting subtransaction must have aborted */
825  SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
827  return true;
828  }
829 
830  return false;
831  }
833  {
834  /*
835  * Return the speculative token to caller. Caller can worry about
836  * xmax, since it requires a conclusively locked row version, and
837  * a concurrent update to this tuple is a conflict of its
838  * purposes.
839  */
840  if (HeapTupleHeaderIsSpeculative(tuple))
841  {
842  snapshot->speculativeToken =
844 
845  Assert(snapshot->speculativeToken != 0);
846  }
847 
848  snapshot->xmin = HeapTupleHeaderGetRawXmin(tuple);
849  /* XXX shouldn't we fall through to look at xmax? */
850  return true; /* in insertion by other */
851  }
853  SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
855  else
856  {
857  /* it must have aborted or crashed */
858  SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
860  return false;
861  }
862  }
863 
864  /* by here, the inserting transaction has committed */
865 
866  if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */
867  return true;
868 
869  if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
870  {
872  return true;
873  return false; /* updated by other */
874  }
875 
876  if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
877  {
878  TransactionId xmax;
879 
881  return true;
882 
883  xmax = HeapTupleGetUpdateXid(tuple);
884 
885  /* not LOCKED_ONLY, so it has to have an xmax */
887 
889  return false;
890  if (TransactionIdIsInProgress(xmax))
891  {
892  snapshot->xmax = xmax;
893  return true;
894  }
895  if (TransactionIdDidCommit(xmax))
896  return false;
897  /* it must have aborted or crashed */
898  return true;
899  }
900 
902  {
904  return true;
905  return false;
906  }
907 
909  {
911  snapshot->xmax = HeapTupleHeaderGetRawXmax(tuple);
912  return true;
913  }
914 
916  {
917  /* it must have aborted or crashed */
918  SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
920  return true;
921  }
922 
923  /* xmax transaction committed */
924 
926  {
927  SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
929  return true;
930  }
931 
932  SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
934  return false; /* updated by other */
935 }
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 1587 of file heapam_visibility.c.

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

962 {
963  HeapTupleHeader tuple = htup->t_data;
964 
966  Assert(htup->t_tableOid != InvalidOid);
967 
968  if (!HeapTupleHeaderXminCommitted(tuple))
969  {
970  if (HeapTupleHeaderXminInvalid(tuple))
971  return false;
972 
973  /* Used by pre-9.0 binary upgrades */
974  if (tuple->t_infomask & HEAP_MOVED_OFF)
975  {
977 
979  return false;
980  if (!XidInMVCCSnapshot(xvac, snapshot))
981  {
982  if (TransactionIdDidCommit(xvac))
983  {
984  SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
986  return false;
987  }
988  SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
990  }
991  }
992  /* Used by pre-9.0 binary upgrades */
993  else if (tuple->t_infomask & HEAP_MOVED_IN)
994  {
996 
998  {
999  if (XidInMVCCSnapshot(xvac, snapshot))
1000  return false;
1001  if (TransactionIdDidCommit(xvac))
1002  SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
1004  else
1005  {
1006  SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
1008  return false;
1009  }
1010  }
1011  }
1013  {
1014  if (HeapTupleHeaderGetCmin(tuple) >= snapshot->curcid)
1015  return false; /* inserted after scan started */
1016 
1017  if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
1018  return true;
1019 
1020  if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask)) /* not deleter */
1021  return true;
1022 
1023  if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
1024  {
1025  TransactionId xmax;
1026 
1027  xmax = HeapTupleGetUpdateXid(tuple);
1028 
1029  /* not LOCKED_ONLY, so it has to have an xmax */
1031 
1032  /* updating subtransaction must have aborted */
1034  return true;
1035  else if (HeapTupleHeaderGetCmax(tuple) >= snapshot->curcid)
1036  return true; /* updated after scan started */
1037  else
1038  return false; /* updated before scan started */
1039  }
1040 
1042  {
1043  /* deleting subtransaction must have aborted */
1044  SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
1046  return true;
1047  }
1048 
1049  if (HeapTupleHeaderGetCmax(tuple) >= snapshot->curcid)
1050  return true; /* deleted after scan started */
1051  else
1052  return false; /* deleted before scan started */
1053  }
1054  else if (XidInMVCCSnapshot(HeapTupleHeaderGetRawXmin(tuple), snapshot))
1055  return false;
1057  SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
1058  HeapTupleHeaderGetRawXmin(tuple));
1059  else
1060  {
1061  /* it must have aborted or crashed */
1062  SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
1064  return false;
1065  }
1066  }
1067  else
1068  {
1069  /* xmin is committed, but maybe not according to our snapshot */
1070  if (!HeapTupleHeaderXminFrozen(tuple) &&
1071  XidInMVCCSnapshot(HeapTupleHeaderGetRawXmin(tuple), snapshot))
1072  return false; /* treat as still in progress */
1073  }
1074 
1075  /* by here, the inserting transaction has committed */
1076 
1077  if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */
1078  return true;
1079 
1081  return true;
1082 
1083  if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
1084  {
1085  TransactionId xmax;
1086 
1087  /* already checked above */
1089 
1090  xmax = HeapTupleGetUpdateXid(tuple);
1091 
1092  /* not LOCKED_ONLY, so it has to have an xmax */
1094 
1096  {
1097  if (HeapTupleHeaderGetCmax(tuple) >= snapshot->curcid)
1098  return true; /* deleted after scan started */
1099  else
1100  return false; /* deleted before scan started */
1101  }
1102  if (XidInMVCCSnapshot(xmax, snapshot))
1103  return true;
1104  if (TransactionIdDidCommit(xmax))
1105  return false; /* updating transaction committed */
1106  /* it must have aborted or crashed */
1107  return true;
1108  }
1109 
1110  if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED))
1111  {
1113  {
1114  if (HeapTupleHeaderGetCmax(tuple) >= snapshot->curcid)
1115  return true; /* deleted after scan started */
1116  else
1117  return false; /* deleted before scan started */
1118  }
1119 
1120  if (XidInMVCCSnapshot(HeapTupleHeaderGetRawXmax(tuple), snapshot))
1121  return true;
1122 
1124  {
1125  /* it must have aborted or crashed */
1126  SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
1128  return true;
1129  }
1130 
1131  /* xmax transaction committed */
1132  SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
1133  HeapTupleHeaderGetRawXmax(tuple));
1134  }
1135  else
1136  {
1137  /* xmax is committed, but maybe not according to our snapshot */
1138  if (XidInMVCCSnapshot(HeapTupleHeaderGetRawXmax(tuple), snapshot))
1139  return true; /* treat as still in progress */
1140  }
1141 
1142  /* xmax transaction committed */
1143 
1144  return false;
1145 }
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:1856

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 1429 of file heapam_visibility.c.

1431 {
1432  TransactionId dead_after = InvalidTransactionId;
1433  HTSV_Result res;
1434 
1435  res = HeapTupleSatisfiesVacuumHorizon(htup, buffer, &dead_after);
1436 
1438  {
1439  Assert(TransactionIdIsValid(dead_after));
1440 
1441  if (GlobalVisTestIsRemovableXid(snapshot->vistest, dead_after))
1442  res = HEAPTUPLE_DEAD;
1443  }
1444  else
1445  Assert(!TransactionIdIsValid(dead_after));
1446 
1447  return res != HEAPTUPLE_DEAD;
1448 }
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 170 of file heapam_visibility.c.

171 {
172  HeapTupleHeader tuple = htup->t_data;
173 
175  Assert(htup->t_tableOid != InvalidOid);
176 
177  if (!HeapTupleHeaderXminCommitted(tuple))
178  {
179  if (HeapTupleHeaderXminInvalid(tuple))
180  return false;
181 
182  /* Used by pre-9.0 binary upgrades */
183  if (tuple->t_infomask & HEAP_MOVED_OFF)
184  {
186 
188  return false;
189  if (!TransactionIdIsInProgress(xvac))
190  {
191  if (TransactionIdDidCommit(xvac))
192  {
193  SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
195  return false;
196  }
197  SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
199  }
200  }
201  /* Used by pre-9.0 binary upgrades */
202  else if (tuple->t_infomask & HEAP_MOVED_IN)
203  {
205 
207  {
208  if (TransactionIdIsInProgress(xvac))
209  return false;
210  if (TransactionIdDidCommit(xvac))
211  SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
213  else
214  {
215  SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
217  return false;
218  }
219  }
220  }
222  {
223  if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
224  return true;
225 
226  if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask)) /* not deleter */
227  return true;
228 
229  if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
230  {
231  TransactionId xmax;
232 
233  xmax = HeapTupleGetUpdateXid(tuple);
234 
235  /* not LOCKED_ONLY, so it has to have an xmax */
237 
238  /* updating subtransaction must have aborted */
240  return true;
241  else
242  return false;
243  }
244 
246  {
247  /* deleting subtransaction must have aborted */
248  SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
250  return true;
251  }
252 
253  return false;
254  }
256  return false;
258  SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
260  else
261  {
262  /* it must have aborted or crashed */
263  SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
265  return false;
266  }
267  }
268 
269  /* by here, the inserting transaction has committed */
270 
271  if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */
272  return true;
273 
274  if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
275  {
277  return true;
278  return false; /* updated by other */
279  }
280 
281  if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
282  {
283  TransactionId xmax;
284 
286  return true;
287 
288  xmax = HeapTupleGetUpdateXid(tuple);
289 
290  /* not LOCKED_ONLY, so it has to have an xmax */
292 
294  return false;
295  if (TransactionIdIsInProgress(xmax))
296  return true;
297  if (TransactionIdDidCommit(xmax))
298  return false;
299  /* it must have aborted or crashed */
300  return true;
301  }
302 
304  {
306  return true;
307  return false;
308  }
309 
311  return true;
312 
314  {
315  /* it must have aborted or crashed */
316  SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
318  return true;
319  }
320 
321  /* xmax transaction committed */
322 
324  {
325  SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
327  return true;
328  }
329 
330  SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
332  return false;
333 }

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 362 of file heapam_visibility.c.

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

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 458 of file heapam_visibility.c.

460 {
461  HeapTupleHeader tuple = htup->t_data;
462 
464  Assert(htup->t_tableOid != InvalidOid);
465 
466  if (!HeapTupleHeaderXminCommitted(tuple))
467  {
468  if (HeapTupleHeaderXminInvalid(tuple))
469  return TM_Invisible;
470 
471  /* Used by pre-9.0 binary upgrades */
472  if (tuple->t_infomask & HEAP_MOVED_OFF)
473  {
475 
477  return TM_Invisible;
478  if (!TransactionIdIsInProgress(xvac))
479  {
480  if (TransactionIdDidCommit(xvac))
481  {
482  SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
484  return TM_Invisible;
485  }
486  SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
488  }
489  }
490  /* Used by pre-9.0 binary upgrades */
491  else if (tuple->t_infomask & HEAP_MOVED_IN)
492  {
494 
496  {
497  if (TransactionIdIsInProgress(xvac))
498  return TM_Invisible;
499  if (TransactionIdDidCommit(xvac))
500  SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
502  else
503  {
504  SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
506  return TM_Invisible;
507  }
508  }
509  }
511  {
512  if (HeapTupleHeaderGetCmin(tuple) >= curcid)
513  return TM_Invisible; /* inserted after scan started */
514 
515  if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
516  return TM_Ok;
517 
519  {
520  TransactionId xmax;
521 
522  xmax = HeapTupleHeaderGetRawXmax(tuple);
523 
524  /*
525  * Careful here: even though this tuple was created by our own
526  * transaction, it might be locked by other transactions, if
527  * the original version was key-share locked when we updated
528  * it.
529  */
530 
531  if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
532  {
533  if (MultiXactIdIsRunning(xmax, true))
534  return TM_BeingModified;
535  else
536  return TM_Ok;
537  }
538 
539  /*
540  * If the locker is gone, then there is nothing of interest
541  * left in this Xmax; otherwise, report the tuple as
542  * locked/updated.
543  */
544  if (!TransactionIdIsInProgress(xmax))
545  return TM_Ok;
546  return TM_BeingModified;
547  }
548 
549  if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
550  {
551  TransactionId xmax;
552 
553  xmax = HeapTupleGetUpdateXid(tuple);
554 
555  /* not LOCKED_ONLY, so it has to have an xmax */
557 
558  /* deleting subtransaction must have aborted */
560  {
562  false))
563  return TM_BeingModified;
564  return TM_Ok;
565  }
566  else
567  {
568  if (HeapTupleHeaderGetCmax(tuple) >= curcid)
569  return TM_SelfModified; /* updated after scan started */
570  else
571  return TM_Invisible; /* updated before scan started */
572  }
573  }
574 
576  {
577  /* deleting subtransaction must have aborted */
578  SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
580  return TM_Ok;
581  }
582 
583  if (HeapTupleHeaderGetCmax(tuple) >= curcid)
584  return TM_SelfModified; /* updated after scan started */
585  else
586  return TM_Invisible; /* updated before scan started */
587  }
589  return TM_Invisible;
591  SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
593  else
594  {
595  /* it must have aborted or crashed */
596  SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
598  return TM_Invisible;
599  }
600  }
601 
602  /* by here, the inserting transaction has committed */
603 
604  if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */
605  return TM_Ok;
606 
607  if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
608  {
610  return TM_Ok;
611  if (!ItemPointerEquals(&htup->t_self, &tuple->t_ctid))
612  return TM_Updated; /* updated by other */
613  else
614  return TM_Deleted; /* deleted by other */
615  }
616 
617  if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
618  {
619  TransactionId xmax;
620 
621  if (HEAP_LOCKED_UPGRADED(tuple->t_infomask))
622  return TM_Ok;
623 
625  {
627  return TM_BeingModified;
628 
630  return TM_Ok;
631  }
632 
633  xmax = HeapTupleGetUpdateXid(tuple);
634  if (!TransactionIdIsValid(xmax))
635  {
637  return TM_BeingModified;
638  }
639 
640  /* not LOCKED_ONLY, so it has to have an xmax */
642 
644  {
645  if (HeapTupleHeaderGetCmax(tuple) >= curcid)
646  return TM_SelfModified; /* updated after scan started */
647  else
648  return TM_Invisible; /* updated before scan started */
649  }
650 
652  return TM_BeingModified;
653 
654  if (TransactionIdDidCommit(xmax))
655  {
656  if (!ItemPointerEquals(&htup->t_self, &tuple->t_ctid))
657  return TM_Updated;
658  else
659  return TM_Deleted;
660  }
661 
662  /*
663  * By here, the update in the Xmax is either aborted or crashed, but
664  * what about the other members?
665  */
666 
668  {
669  /*
670  * There's no member, even just a locker, alive anymore, so we can
671  * mark the Xmax as invalid.
672  */
673  SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
675  return TM_Ok;
676  }
677  else
678  {
679  /* There are lockers running */
680  return TM_BeingModified;
681  }
682  }
683 
685  {
687  return TM_BeingModified;
688  if (HeapTupleHeaderGetCmax(tuple) >= curcid)
689  return TM_SelfModified; /* updated after scan started */
690  else
691  return TM_Invisible; /* updated before scan started */
692  }
693 
695  return TM_BeingModified;
696 
698  {
699  /* it must have aborted or crashed */
700  SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
702  return TM_Ok;
703  }
704 
705  /* xmax transaction committed */
706 
708  {
709  SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
711  return TM_Ok;
712  }
713 
714  SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
716  if (!ItemPointerEquals(&htup->t_self, &tuple->t_ctid))
717  return TM_Updated; /* updated by other */
718  else
719  return TM_Deleted; /* deleted by other */
720 }
#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:550
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 1196 of file heapam_visibility.c.

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

1768 {
1769  switch (snapshot->snapshot_type)
1770  {
1771  case SNAPSHOT_MVCC:
1772  return HeapTupleSatisfiesMVCC(htup, snapshot, buffer);
1773  case SNAPSHOT_SELF:
1774  return HeapTupleSatisfiesSelf(htup, snapshot, buffer);
1775  case SNAPSHOT_ANY:
1776  return HeapTupleSatisfiesAny(htup, snapshot, buffer);
1777  case SNAPSHOT_TOAST:
1778  return HeapTupleSatisfiesToast(htup, snapshot, buffer);
1779  case SNAPSHOT_DIRTY:
1780  return HeapTupleSatisfiesDirty(htup, snapshot, buffer);
1782  return HeapTupleSatisfiesHistoricMVCC(htup, snapshot, buffer);
1784  return HeapTupleSatisfiesNonVacuumable(htup, snapshot, buffer);
1785  }
1786 
1787  return false; /* keep compiler quiet */
1788 }
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 141 of file heapam_visibility.c.

143 {
144  SetHintBits(tuple, buffer, infomask, xid);
145 }

References SetHintBits().

Referenced by UpdateXmaxHintBits().

◆ SetHintBits()

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

Definition at line 114 of file heapam_visibility.c.

116 {
117  if (TransactionIdIsValid(xid))
118  {
119  /* NB: xid must be known committed here! */
120  XLogRecPtr commitLSN = TransactionIdGetCommitLSN(xid);
121 
122  if (BufferIsPermanent(buffer) && XLogNeedsFlush(commitLSN) &&
123  BufferGetLSNAtomic(buffer) < commitLSN)
124  {
125  /* not flushed and no LSN interlock, so don't set hint */
126  return;
127  }
128  }
129 
130  tuple->t_infomask |= infomask;
131  MarkBufferDirtyHint(buffer, true);
132 }
bool BufferIsPermanent(Buffer buffer)
Definition: bufmgr.c:3608
XLogRecPtr BufferGetLSNAtomic(Buffer buffer)
Definition: bufmgr.c:3638
void MarkBufferDirtyHint(Buffer buffer, bool buffer_std)
Definition: bufmgr.c:4624
XLogRecPtr TransactionIdGetCommitLSN(TransactionId xid)
Definition: transam.c:382
bool XLogNeedsFlush(XLogRecPtr record)
Definition: xlog.c:3061
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 1566 of file heapam_visibility.c.

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

References xidComparator().

Referenced by HeapTupleSatisfiesHistoricMVCC().