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 tup, Snapshot snapshot, Buffer buffer)
 

Function Documentation

◆ HeapTupleHeaderIsOnlyLocked()

bool HeapTupleHeaderIsOnlyLocked ( HeapTupleHeader  tuple)

Definition at line 1519 of file heapam_visibility.c.

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

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

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

340 {
341  return true;
342 }

Referenced by HeapTupleSatisfiesVisibility().

◆ HeapTupleSatisfiesDirty()

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

Definition at line 742 of file heapam_visibility.c.

744 {
745  HeapTupleHeader tuple = htup->t_data;
746 
748  Assert(htup->t_tableOid != InvalidOid);
749 
750  snapshot->xmin = snapshot->xmax = InvalidTransactionId;
751  snapshot->speculativeToken = 0;
752 
753  if (!HeapTupleHeaderXminCommitted(tuple))
754  {
755  if (HeapTupleHeaderXminInvalid(tuple))
756  return false;
757 
758  /* Used by pre-9.0 binary upgrades */
759  if (tuple->t_infomask & HEAP_MOVED_OFF)
760  {
762 
764  return false;
765  if (!TransactionIdIsInProgress(xvac))
766  {
767  if (TransactionIdDidCommit(xvac))
768  {
769  SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
771  return false;
772  }
773  SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
775  }
776  }
777  /* Used by pre-9.0 binary upgrades */
778  else if (tuple->t_infomask & HEAP_MOVED_IN)
779  {
781 
783  {
784  if (TransactionIdIsInProgress(xvac))
785  return false;
786  if (TransactionIdDidCommit(xvac))
787  SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
789  else
790  {
791  SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
793  return false;
794  }
795  }
796  }
798  {
799  if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
800  return true;
801 
802  if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask)) /* not deleter */
803  return true;
804 
805  if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
806  {
807  TransactionId xmax;
808 
809  xmax = HeapTupleGetUpdateXid(tuple);
810 
811  /* not LOCKED_ONLY, so it has to have an xmax */
813 
814  /* updating subtransaction must have aborted */
816  return true;
817  else
818  return false;
819  }
820 
822  {
823  /* deleting subtransaction must have aborted */
824  SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
826  return true;
827  }
828 
829  return false;
830  }
832  {
833  /*
834  * Return the speculative token to caller. Caller can worry about
835  * xmax, since it requires a conclusively locked row version, and
836  * a concurrent update to this tuple is a conflict of its
837  * purposes.
838  */
839  if (HeapTupleHeaderIsSpeculative(tuple))
840  {
841  snapshot->speculativeToken =
843 
844  Assert(snapshot->speculativeToken != 0);
845  }
846 
847  snapshot->xmin = HeapTupleHeaderGetRawXmin(tuple);
848  /* XXX shouldn't we fall through to look at xmax? */
849  return true; /* in insertion by other */
850  }
852  SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
854  else
855  {
856  /* it must have aborted or crashed */
857  SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
859  return false;
860  }
861  }
862 
863  /* by here, the inserting transaction has committed */
864 
865  if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */
866  return true;
867 
868  if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
869  {
871  return true;
872  return false; /* updated by other */
873  }
874 
875  if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
876  {
877  TransactionId xmax;
878 
880  return true;
881 
882  xmax = HeapTupleGetUpdateXid(tuple);
883 
884  /* not LOCKED_ONLY, so it has to have an xmax */
886 
888  return false;
889  if (TransactionIdIsInProgress(xmax))
890  {
891  snapshot->xmax = xmax;
892  return true;
893  }
894  if (TransactionIdDidCommit(xmax))
895  return false;
896  /* it must have aborted or crashed */
897  return true;
898  }
899 
901  {
903  return true;
904  return false;
905  }
906 
908  {
910  snapshot->xmax = HeapTupleHeaderGetRawXmax(tuple);
911  return true;
912  }
913 
915  {
916  /* it must have aborted or crashed */
917  SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
919  return true;
920  }
921 
922  /* xmax transaction committed */
923 
925  {
926  SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
928  return true;
929  }
930 
931  SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
933  return false; /* updated by other */
934 }
static void SetHintBits(HeapTupleHeader tuple, Buffer buffer, uint16 infomask, TransactionId xid)
#define HEAP_MOVED_OFF
Definition: htup_details.h:210
#define HEAP_XMIN_COMMITTED
Definition: htup_details.h:203
#define HeapTupleHeaderGetXvac(tup)
Definition: htup_details.h:410
#define HEAP_MOVED_IN
Definition: htup_details.h:211
#define HeapTupleHeaderGetSpeculativeToken(tup)
Definition: htup_details.h:429
#define HEAP_XMIN_INVALID
Definition: htup_details.h:204
#define HeapTupleHeaderGetRawXmin(tup)
Definition: htup_details.h:303
#define HeapTupleHeaderIsSpeculative(tup)
Definition: htup_details.h:424
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 1586 of file heapam_visibility.c.

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

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

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

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

1430 {
1431  TransactionId dead_after = InvalidTransactionId;
1432  HTSV_Result res;
1433 
1434  res = HeapTupleSatisfiesVacuumHorizon(htup, buffer, &dead_after);
1435 
1437  {
1438  Assert(TransactionIdIsValid(dead_after));
1439 
1440  if (GlobalVisTestIsRemovableXid(snapshot->vistest, dead_after))
1441  res = HEAPTUPLE_DEAD;
1442  }
1443  else
1444  Assert(!TransactionIdIsValid(dead_after));
1445 
1446  return res != HEAPTUPLE_DEAD;
1447 }
HTSV_Result
Definition: heapam.h:94
@ HEAPTUPLE_RECENTLY_DEAD
Definition: heapam.h:97
@ HEAPTUPLE_DEAD
Definition: heapam.h:95
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 169 of file heapam_visibility.c.

170 {
171  HeapTupleHeader tuple = htup->t_data;
172 
174  Assert(htup->t_tableOid != InvalidOid);
175 
176  if (!HeapTupleHeaderXminCommitted(tuple))
177  {
178  if (HeapTupleHeaderXminInvalid(tuple))
179  return false;
180 
181  /* Used by pre-9.0 binary upgrades */
182  if (tuple->t_infomask & HEAP_MOVED_OFF)
183  {
185 
187  return false;
188  if (!TransactionIdIsInProgress(xvac))
189  {
190  if (TransactionIdDidCommit(xvac))
191  {
192  SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
194  return false;
195  }
196  SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
198  }
199  }
200  /* Used by pre-9.0 binary upgrades */
201  else if (tuple->t_infomask & HEAP_MOVED_IN)
202  {
204 
206  {
207  if (TransactionIdIsInProgress(xvac))
208  return false;
209  if (TransactionIdDidCommit(xvac))
210  SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
212  else
213  {
214  SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
216  return false;
217  }
218  }
219  }
221  {
222  if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
223  return true;
224 
225  if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask)) /* not deleter */
226  return true;
227 
228  if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
229  {
230  TransactionId xmax;
231 
232  xmax = HeapTupleGetUpdateXid(tuple);
233 
234  /* not LOCKED_ONLY, so it has to have an xmax */
236 
237  /* updating subtransaction must have aborted */
239  return true;
240  else
241  return false;
242  }
243 
245  {
246  /* deleting subtransaction must have aborted */
247  SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
249  return true;
250  }
251 
252  return false;
253  }
255  return false;
257  SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
259  else
260  {
261  /* it must have aborted or crashed */
262  SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
264  return false;
265  }
266  }
267 
268  /* by here, the inserting transaction has committed */
269 
270  if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */
271  return true;
272 
273  if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
274  {
276  return true;
277  return false; /* updated by other */
278  }
279 
280  if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
281  {
282  TransactionId xmax;
283 
285  return true;
286 
287  xmax = HeapTupleGetUpdateXid(tuple);
288 
289  /* not LOCKED_ONLY, so it has to have an xmax */
291 
293  return false;
294  if (TransactionIdIsInProgress(xmax))
295  return true;
296  if (TransactionIdDidCommit(xmax))
297  return false;
298  /* it must have aborted or crashed */
299  return true;
300  }
301 
303  {
305  return true;
306  return false;
307  }
308 
310  return true;
311 
313  {
314  /* it must have aborted or crashed */
315  SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
317  return true;
318  }
319 
320  /* xmax transaction committed */
321 
323  {
324  SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
326  return true;
327  }
328 
329  SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
331  return false;
332 }

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

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

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

459 {
460  HeapTupleHeader tuple = htup->t_data;
461 
463  Assert(htup->t_tableOid != InvalidOid);
464 
465  if (!HeapTupleHeaderXminCommitted(tuple))
466  {
467  if (HeapTupleHeaderXminInvalid(tuple))
468  return TM_Invisible;
469 
470  /* Used by pre-9.0 binary upgrades */
471  if (tuple->t_infomask & HEAP_MOVED_OFF)
472  {
474 
476  return TM_Invisible;
477  if (!TransactionIdIsInProgress(xvac))
478  {
479  if (TransactionIdDidCommit(xvac))
480  {
481  SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
483  return TM_Invisible;
484  }
485  SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
487  }
488  }
489  /* Used by pre-9.0 binary upgrades */
490  else if (tuple->t_infomask & HEAP_MOVED_IN)
491  {
493 
495  {
496  if (TransactionIdIsInProgress(xvac))
497  return TM_Invisible;
498  if (TransactionIdDidCommit(xvac))
499  SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
501  else
502  {
503  SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
505  return TM_Invisible;
506  }
507  }
508  }
510  {
511  if (HeapTupleHeaderGetCmin(tuple) >= curcid)
512  return TM_Invisible; /* inserted after scan started */
513 
514  if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
515  return TM_Ok;
516 
518  {
519  TransactionId xmax;
520 
521  xmax = HeapTupleHeaderGetRawXmax(tuple);
522 
523  /*
524  * Careful here: even though this tuple was created by our own
525  * transaction, it might be locked by other transactions, if
526  * the original version was key-share locked when we updated
527  * it.
528  */
529 
530  if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
531  {
532  if (MultiXactIdIsRunning(xmax, true))
533  return TM_BeingModified;
534  else
535  return TM_Ok;
536  }
537 
538  /*
539  * If the locker is gone, then there is nothing of interest
540  * left in this Xmax; otherwise, report the tuple as
541  * locked/updated.
542  */
543  if (!TransactionIdIsInProgress(xmax))
544  return TM_Ok;
545  return TM_BeingModified;
546  }
547 
548  if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
549  {
550  TransactionId xmax;
551 
552  xmax = HeapTupleGetUpdateXid(tuple);
553 
554  /* not LOCKED_ONLY, so it has to have an xmax */
556 
557  /* deleting subtransaction must have aborted */
559  {
561  false))
562  return TM_BeingModified;
563  return TM_Ok;
564  }
565  else
566  {
567  if (HeapTupleHeaderGetCmax(tuple) >= curcid)
568  return TM_SelfModified; /* updated after scan started */
569  else
570  return TM_Invisible; /* updated before scan started */
571  }
572  }
573 
575  {
576  /* deleting subtransaction must have aborted */
577  SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
579  return TM_Ok;
580  }
581 
582  if (HeapTupleHeaderGetCmax(tuple) >= curcid)
583  return TM_SelfModified; /* updated after scan started */
584  else
585  return TM_Invisible; /* updated before scan started */
586  }
588  return TM_Invisible;
590  SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
592  else
593  {
594  /* it must have aborted or crashed */
595  SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
597  return TM_Invisible;
598  }
599  }
600 
601  /* by here, the inserting transaction has committed */
602 
603  if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */
604  return TM_Ok;
605 
606  if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
607  {
609  return TM_Ok;
610  if (!ItemPointerEquals(&htup->t_self, &tuple->t_ctid))
611  return TM_Updated; /* updated by other */
612  else
613  return TM_Deleted; /* deleted by other */
614  }
615 
616  if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
617  {
618  TransactionId xmax;
619 
620  if (HEAP_LOCKED_UPGRADED(tuple->t_infomask))
621  return TM_Ok;
622 
624  {
626  return TM_BeingModified;
627 
629  return TM_Ok;
630  }
631 
632  xmax = HeapTupleGetUpdateXid(tuple);
633  if (!TransactionIdIsValid(xmax))
634  {
636  return TM_BeingModified;
637  }
638 
639  /* not LOCKED_ONLY, so it has to have an xmax */
641 
643  {
644  if (HeapTupleHeaderGetCmax(tuple) >= curcid)
645  return TM_SelfModified; /* updated after scan started */
646  else
647  return TM_Invisible; /* updated before scan started */
648  }
649 
651  return TM_BeingModified;
652 
653  if (TransactionIdDidCommit(xmax))
654  {
655  if (!ItemPointerEquals(&htup->t_self, &tuple->t_ctid))
656  return TM_Updated;
657  else
658  return TM_Deleted;
659  }
660 
661  /*
662  * By here, the update in the Xmax is either aborted or crashed, but
663  * what about the other members?
664  */
665 
667  {
668  /*
669  * There's no member, even just a locker, alive anymore, so we can
670  * mark the Xmax as invalid.
671  */
672  SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
674  return TM_Ok;
675  }
676  else
677  {
678  /* There are lockers running */
679  return TM_BeingModified;
680  }
681  }
682 
684  {
686  return TM_BeingModified;
687  if (HeapTupleHeaderGetCmax(tuple) >= curcid)
688  return TM_SelfModified; /* updated after scan started */
689  else
690  return TM_Invisible; /* updated before scan started */
691  }
692 
694  return TM_BeingModified;
695 
697  {
698  /* it must have aborted or crashed */
699  SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
701  return TM_Ok;
702  }
703 
704  /* xmax transaction committed */
705 
707  {
708  SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
710  return TM_Ok;
711  }
712 
713  SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
715  if (!ItemPointerEquals(&htup->t_self, &tuple->t_ctid))
716  return TM_Updated; /* updated by other */
717  else
718  return TM_Deleted; /* deleted by other */
719 }
#define HEAP_LOCKED_UPGRADED(infomask)
Definition: htup_details.h:248
bool ItemPointerEquals(ItemPointer pointer1, ItemPointer pointer2)
Definition: itemptr.c:29
bool MultiXactIdIsRunning(MultiXactId multi, bool isLockOnly)
Definition: multixact.c:551
ItemPointerData t_ctid
Definition: htup_details.h:160
@ 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 1195 of file heapam_visibility.c.

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

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  tup,
Snapshot  snapshot,
Buffer  buffer 
)

Definition at line 1766 of file heapam_visibility.c.

1767 {
1768  switch (snapshot->snapshot_type)
1769  {
1770  case SNAPSHOT_MVCC:
1771  return HeapTupleSatisfiesMVCC(tup, snapshot, buffer);
1772  break;
1773  case SNAPSHOT_SELF:
1774  return HeapTupleSatisfiesSelf(tup, snapshot, buffer);
1775  break;
1776  case SNAPSHOT_ANY:
1777  return HeapTupleSatisfiesAny(tup, snapshot, buffer);
1778  break;
1779  case SNAPSHOT_TOAST:
1780  return HeapTupleSatisfiesToast(tup, snapshot, buffer);
1781  break;
1782  case SNAPSHOT_DIRTY:
1783  return HeapTupleSatisfiesDirty(tup, snapshot, buffer);
1784  break;
1786  return HeapTupleSatisfiesHistoricMVCC(tup, snapshot, buffer);
1787  break;
1789  return HeapTupleSatisfiesNonVacuumable(tup, snapshot, buffer);
1790  break;
1791  }
1792 
1793  return false; /* keep compiler quiet */
1794 }
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(), and SampleHeapTupleVisible().

◆ HeapTupleSetHintBits()

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

Definition at line 140 of file heapam_visibility.c.

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

References SetHintBits().

Referenced by UpdateXmaxHintBits().

◆ SetHintBits()

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

Definition at line 113 of file heapam_visibility.c.

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

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

References xidComparator().

Referenced by HeapTupleSatisfiesHistoricMVCC().