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

1530{
1531 TransactionId xmax;
1532
1533 /* if there's no valid Xmax, then there's obviously no update either */
1534 if (tuple->t_infomask & HEAP_XMAX_INVALID)
1535 return true;
1536
1537 if (tuple->t_infomask & HEAP_XMAX_LOCK_ONLY)
1538 return true;
1539
1540 /* invalid xmax means no update */
1542 return true;
1543
1544 /*
1545 * if HEAP_XMAX_LOCK_ONLY is not set and not a multi, then this must
1546 * necessarily have been updated
1547 */
1548 if (!(tuple->t_infomask & HEAP_XMAX_IS_MULTI))
1549 return false;
1550
1551 /* ... but if it's a multi, then perhaps the updating Xid aborted. */
1552 xmax = HeapTupleGetUpdateXid(tuple);
1553
1554 /* not LOCKED_ONLY, so it has to have an xmax */
1556
1558 return false;
1559 if (TransactionIdIsInProgress(xmax))
1560 return false;
1561 if (TransactionIdDidCommit(xmax))
1562 return false;
1563
1564 /*
1565 * not current, not in progress, not committed -- must have aborted or
1566 * crashed
1567 */
1568 return true;
1569}
uint32 TransactionId
Definition: c.h:623
Assert(PointerIsAligned(start, uint64))
TransactionId HeapTupleGetUpdateXid(const HeapTupleHeaderData *tup)
Definition: heapam.c:7568
#define HEAP_XMAX_LOCK_ONLY
Definition: htup_details.h:197
static TransactionId HeapTupleHeaderGetRawXmax(const HeapTupleHeaderData *tup)
Definition: htup_details.h:377
#define HEAP_XMAX_IS_MULTI
Definition: htup_details.h:209
#define HEAP_XMAX_INVALID
Definition: htup_details.h:208
bool TransactionIdIsInProgress(TransactionId xid)
Definition: procarray.c:1402
bool TransactionIdDidCommit(TransactionId transactionId)
Definition: transam.c:126
#define TransactionIdIsValid(xid)
Definition: transam.h:41
bool TransactionIdIsCurrentTransactionId(TransactionId xid)
Definition: xact.c:941

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

1475{
1476 HeapTupleHeader tuple = htup->t_data;
1477
1479 Assert(htup->t_tableOid != InvalidOid);
1480
1481 /*
1482 * If the inserting transaction is marked invalid, then it aborted, and
1483 * the tuple is definitely dead. If it's marked neither committed nor
1484 * invalid, then we assume it's still alive (since the presumption is that
1485 * all relevant hint bits were just set moments ago).
1486 */
1487 if (!HeapTupleHeaderXminCommitted(tuple))
1488 return HeapTupleHeaderXminInvalid(tuple);
1489
1490 /*
1491 * If the inserting transaction committed, but any deleting transaction
1492 * aborted, the tuple is still alive.
1493 */
1494 if (tuple->t_infomask & HEAP_XMAX_INVALID)
1495 return false;
1496
1497 /*
1498 * If the XMAX is just a lock, the tuple is still alive.
1499 */
1501 return false;
1502
1503 /*
1504 * If the Xmax is a MultiXact, it might be dead or alive, but we cannot
1505 * know without checking pg_multixact.
1506 */
1507 if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
1508 return false;
1509
1510 /* If deleter isn't known to have committed, assume it's still running. */
1511 if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED))
1512 return false;
1513
1514 /* Deleter committed, so tuple is dead if the XID is old enough. */
1515 return GlobalVisTestIsRemovableXid(vistest,
1517}
static bool HEAP_XMAX_IS_LOCKED_ONLY(uint16 infomask)
Definition: htup_details.h:226
static bool HeapTupleHeaderXminInvalid(const HeapTupleHeaderData *tup)
Definition: htup_details.h:343
#define HEAP_XMAX_COMMITTED
Definition: htup_details.h:207
static bool HeapTupleHeaderXminCommitted(const HeapTupleHeaderData *tup)
Definition: htup_details.h:337
static bool ItemPointerIsValid(const ItemPointerData *pointer)
Definition: itemptr.h:83
#define InvalidOid
Definition: postgres_ext.h:37
bool GlobalVisTestIsRemovableXid(GlobalVisState *state, TransactionId xid)
Definition: procarray.c:4264
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
755 {
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 {
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 */
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;
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
static TransactionId HeapTupleHeaderGetXvac(const HeapTupleHeaderData *tup)
Definition: htup_details.h:442
#define HEAP_MOVED_IN
Definition: htup_details.h:212
#define HEAP_XMIN_INVALID
Definition: htup_details.h:205
static BlockNumber HeapTupleHeaderGetSpeculativeToken(const HeapTupleHeaderData *tup)
Definition: htup_details.h:467
static TransactionId HeapTupleHeaderGetRawXmin(const HeapTupleHeaderData *tup)
Definition: htup_details.h:318
static bool HeapTupleHeaderIsSpeculative(const HeapTupleHeaderData *tup)
Definition: htup_details.h:461
TransactionId xmin
Definition: snapshot.h:153
TransactionId xmax
Definition: snapshot.h:154
uint32 speculativeToken
Definition: snapshot.h:189
#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 1596 of file heapam_visibility.c.

1598{
1599 HeapTupleHeader tuple = htup->t_data;
1602
1604 Assert(htup->t_tableOid != InvalidOid);
1605
1606 /* inserting transaction aborted */
1607 if (HeapTupleHeaderXminInvalid(tuple))
1608 {
1610 return false;
1611 }
1612 /* check if it's one of our txids, toplevel is also in there */
1613 else if (TransactionIdInArray(xmin, snapshot->subxip, snapshot->subxcnt))
1614 {
1615 bool resolved;
1618
1619 /*
1620 * another transaction might have (tried to) delete this tuple or
1621 * cmin/cmax was stored in a combo CID. So we need to lookup the
1622 * actual values externally.
1623 */
1625 htup, buffer,
1626 &cmin, &cmax);
1627
1628 /*
1629 * If we haven't resolved the combo CID to cmin/cmax, that means we
1630 * have not decoded the combo CID yet. That means the cmin is
1631 * definitely in the future, and we're not supposed to see the tuple
1632 * yet.
1633 *
1634 * XXX This only applies to decoding of in-progress transactions. In
1635 * regular logical decoding we only execute this code at commit time,
1636 * at which point we should have seen all relevant combo CIDs. So
1637 * ideally, we should error out in this case but in practice, this
1638 * won't happen. If we are too worried about this then we can add an
1639 * elog inside ResolveCminCmaxDuringDecoding.
1640 *
1641 * XXX For the streaming case, we can track the largest combo CID
1642 * assigned, and error out based on this (when unable to resolve combo
1643 * CID below that observed maximum value).
1644 */
1645 if (!resolved)
1646 return false;
1647
1648 Assert(cmin != InvalidCommandId);
1649
1650 if (cmin >= snapshot->curcid)
1651 return false; /* inserted after scan started */
1652 /* fall through */
1653 }
1654 /* committed before our xmin horizon. Do a normal visibility check. */
1655 else if (TransactionIdPrecedes(xmin, snapshot->xmin))
1656 {
1658 !TransactionIdDidCommit(xmin)));
1659
1660 /* check for hint bit first, consult clog afterwards */
1661 if (!HeapTupleHeaderXminCommitted(tuple) &&
1663 return false;
1664 /* fall through */
1665 }
1666 /* beyond our xmax horizon, i.e. invisible */
1667 else if (TransactionIdFollowsOrEquals(xmin, snapshot->xmax))
1668 {
1669 return false;
1670 }
1671 /* check if it's a committed transaction in [xmin, xmax) */
1672 else if (TransactionIdInArray(xmin, snapshot->xip, snapshot->xcnt))
1673 {
1674 /* fall through */
1675 }
1676
1677 /*
1678 * none of the above, i.e. between [xmin, xmax) but hasn't committed. I.e.
1679 * invisible.
1680 */
1681 else
1682 {
1683 return false;
1684 }
1685
1686 /* at this point we know xmin is visible, go on to check xmax */
1687
1688 /* xid invalid or aborted */
1689 if (tuple->t_infomask & HEAP_XMAX_INVALID)
1690 return true;
1691 /* locked tuples are always visible */
1692 else if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
1693 return true;
1694
1695 /*
1696 * We can see multis here if we're looking at user tables or if somebody
1697 * SELECT ... FOR SHARE/UPDATE a system table.
1698 */
1699 else if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
1700 {
1701 xmax = HeapTupleGetUpdateXid(tuple);
1702 }
1703
1704 /* check if it's one of our txids, toplevel is also in there */
1705 if (TransactionIdInArray(xmax, snapshot->subxip, snapshot->subxcnt))
1706 {
1707 bool resolved;
1708 CommandId cmin;
1710
1711 /* Lookup actual cmin/cmax values */
1713 htup, buffer,
1714 &cmin, &cmax);
1715
1716 /*
1717 * If we haven't resolved the combo CID to cmin/cmax, that means we
1718 * have not decoded the combo CID yet. That means the cmax is
1719 * definitely in the future, and we're still supposed to see the
1720 * tuple.
1721 *
1722 * XXX This only applies to decoding of in-progress transactions. In
1723 * regular logical decoding we only execute this code at commit time,
1724 * at which point we should have seen all relevant combo CIDs. So
1725 * ideally, we should error out in this case but in practice, this
1726 * won't happen. If we are too worried about this then we can add an
1727 * elog inside ResolveCminCmaxDuringDecoding.
1728 *
1729 * XXX For the streaming case, we can track the largest combo CID
1730 * assigned, and error out based on this (when unable to resolve combo
1731 * CID below that observed maximum value).
1732 */
1733 if (!resolved || cmax == InvalidCommandId)
1734 return true;
1735
1736 if (cmax >= snapshot->curcid)
1737 return true; /* deleted after scan started */
1738 else
1739 return false; /* deleted before scan started */
1740 }
1741 /* below xmin horizon, normal transaction state is valid */
1742 else if (TransactionIdPrecedes(xmax, snapshot->xmin))
1743 {
1745 !TransactionIdDidCommit(xmax)));
1746
1747 /* check hint bit first */
1748 if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
1749 return false;
1750
1751 /* check clog */
1752 return !TransactionIdDidCommit(xmax);
1753 }
1754 /* above xmax horizon, we cannot possibly see the deleting transaction */
1755 else if (TransactionIdFollowsOrEquals(xmax, snapshot->xmax))
1756 return true;
1757 /* xmax is between [xmin, xmax), check known committed array */
1758 else if (TransactionIdInArray(xmax, snapshot->xip, snapshot->xcnt))
1759 return false;
1760 /* xmax is between [xmin, xmax), but known not to have committed yet */
1761 else
1762 return true;
1763}
#define InvalidCommandId
Definition: c.h:640
uint32 CommandId
Definition: c.h:637
static bool TransactionIdInArray(TransactionId xid, TransactionId *xip, Size num)
static CommandId HeapTupleHeaderGetRawCommandId(const HeapTupleHeaderData *tup)
Definition: htup_details.h:415
static TransactionId HeapTupleHeaderGetXmin(const HeapTupleHeaderData *tup)
Definition: htup_details.h:324
bool ResolveCminCmaxDuringDecoding(HTAB *tuplecid_data, Snapshot snapshot, HeapTuple htup, Buffer buffer, CommandId *cmin, CommandId *cmax)
HTAB * HistoricSnapshotGetTupleCids(void)
Definition: snapmgr.c:1685
int32 subxcnt
Definition: snapshot.h:177
CommandId curcid
Definition: snapshot.h:183
uint32 xcnt
Definition: snapshot.h:165
TransactionId * subxip
Definition: snapshot.h:176
TransactionId * xip
Definition: snapshot.h:164
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
965 /*
966 * Assert that the caller has registered the snapshot. This function
967 * doesn't care about the registration as such, but in general you
968 * shouldn't try to use a snapshot without registration because it might
969 * get invalidated while it's still in use, and this is a convenient place
970 * to check for that.
971 */
972 Assert(snapshot->regd_count > 0 || snapshot->active_count > 0);
973
975 Assert(htup->t_tableOid != InvalidOid);
976
978 {
980 return false;
981
982 /* Used by pre-9.0 binary upgrades */
983 if (tuple->t_infomask & HEAP_MOVED_OFF)
984 {
986
988 return false;
989 if (!XidInMVCCSnapshot(xvac, snapshot))
990 {
991 if (TransactionIdDidCommit(xvac))
992 {
993 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
995 return false;
996 }
997 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
999 }
1000 }
1001 /* Used by pre-9.0 binary upgrades */
1002 else if (tuple->t_infomask & HEAP_MOVED_IN)
1003 {
1005
1007 {
1008 if (XidInMVCCSnapshot(xvac, snapshot))
1009 return false;
1010 if (TransactionIdDidCommit(xvac))
1011 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
1013 else
1014 {
1015 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
1017 return false;
1018 }
1019 }
1020 }
1022 {
1023 if (HeapTupleHeaderGetCmin(tuple) >= snapshot->curcid)
1024 return false; /* inserted after scan started */
1025
1026 if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
1027 return true;
1028
1029 if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask)) /* not deleter */
1030 return true;
1031
1032 if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
1033 {
1034 TransactionId xmax;
1035
1036 xmax = HeapTupleGetUpdateXid(tuple);
1037
1038 /* not LOCKED_ONLY, so it has to have an xmax */
1040
1041 /* updating subtransaction must have aborted */
1043 return true;
1044 else if (HeapTupleHeaderGetCmax(tuple) >= snapshot->curcid)
1045 return true; /* updated after scan started */
1046 else
1047 return false; /* updated before scan started */
1048 }
1049
1051 {
1052 /* deleting subtransaction must have aborted */
1053 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
1055 return true;
1056 }
1057
1058 if (HeapTupleHeaderGetCmax(tuple) >= snapshot->curcid)
1059 return true; /* deleted after scan started */
1060 else
1061 return false; /* deleted before scan started */
1062 }
1063 else if (XidInMVCCSnapshot(HeapTupleHeaderGetRawXmin(tuple), snapshot))
1064 return false;
1066 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
1068 else
1069 {
1070 /* it must have aborted or crashed */
1071 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
1073 return false;
1074 }
1075 }
1076 else
1077 {
1078 /* xmin is committed, but maybe not according to our snapshot */
1079 if (!HeapTupleHeaderXminFrozen(tuple) &&
1081 return false; /* treat as still in progress */
1082 }
1083
1084 /* by here, the inserting transaction has committed */
1085
1086 if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */
1087 return true;
1088
1090 return true;
1091
1092 if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
1093 {
1094 TransactionId xmax;
1095
1096 /* already checked above */
1098
1099 xmax = HeapTupleGetUpdateXid(tuple);
1100
1101 /* not LOCKED_ONLY, so it has to have an xmax */
1103
1105 {
1106 if (HeapTupleHeaderGetCmax(tuple) >= snapshot->curcid)
1107 return true; /* deleted after scan started */
1108 else
1109 return false; /* deleted before scan started */
1110 }
1111 if (XidInMVCCSnapshot(xmax, snapshot))
1112 return true;
1113 if (TransactionIdDidCommit(xmax))
1114 return false; /* updating transaction committed */
1115 /* it must have aborted or crashed */
1116 return true;
1117 }
1118
1119 if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED))
1120 {
1122 {
1123 if (HeapTupleHeaderGetCmax(tuple) >= snapshot->curcid)
1124 return true; /* deleted after scan started */
1125 else
1126 return false; /* deleted before scan started */
1127 }
1128
1129 if (XidInMVCCSnapshot(HeapTupleHeaderGetRawXmax(tuple), snapshot))
1130 return true;
1131
1133 {
1134 /* it must have aborted or crashed */
1135 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
1137 return true;
1138 }
1139
1140 /* xmax transaction committed */
1141 SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
1143 }
1144 else
1145 {
1146 /* xmax is committed, but maybe not according to our snapshot */
1147 if (XidInMVCCSnapshot(HeapTupleHeaderGetRawXmax(tuple), snapshot))
1148 return true; /* treat as still in progress */
1149 }
1150
1151 /* xmax transaction committed */
1152
1153 return false;
1154}
CommandId HeapTupleHeaderGetCmin(const HeapTupleHeaderData *tup)
Definition: combocid.c:104
CommandId HeapTupleHeaderGetCmax(const HeapTupleHeaderData *tup)
Definition: combocid.c:118
static bool HeapTupleHeaderXminFrozen(const HeapTupleHeaderData *tup)
Definition: htup_details.h:350
bool XidInMVCCSnapshot(TransactionId xid, Snapshot snapshot)
Definition: snapmgr.c:1859
uint32 regd_count
Definition: snapshot.h:201
uint32 active_count
Definition: snapshot.h:200

References SnapshotData::active_count, 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(), SnapshotData::regd_count, 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 1438 of file heapam_visibility.c.

1440{
1442 HTSV_Result res;
1443
1444 res = HeapTupleSatisfiesVacuumHorizon(htup, buffer, &dead_after);
1445
1446 if (res == HEAPTUPLE_RECENTLY_DEAD)
1447 {
1448 Assert(TransactionIdIsValid(dead_after));
1449
1450 if (GlobalVisTestIsRemovableXid(snapshot->vistest, dead_after))
1451 res = HEAPTUPLE_DEAD;
1452 }
1453 else
1454 Assert(!TransactionIdIsValid(dead_after));
1455
1456 return res != HEAPTUPLE_DEAD;
1457}
HTSV_Result
Definition: heapam.h:133
@ HEAPTUPLE_RECENTLY_DEAD
Definition: heapam.h:136
@ HEAPTUPLE_DEAD
Definition: heapam.h:134
HTSV_Result HeapTupleSatisfiesVacuumHorizon(HeapTuple htup, Buffer buffer, TransactionId *dead_after)
struct GlobalVisState * vistest
Definition: snapshot.h:195

References Assert(), GlobalVisTestIsRemovableXid(), HEAPTUPLE_DEAD, HEAPTUPLE_RECENTLY_DEAD, HeapTupleSatisfiesVacuumHorizon(), InvalidTransactionId, 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
178 {
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 {
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;
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
371 {
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 {
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
467 {
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 {
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
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}
static bool HEAP_LOCKED_UPGRADED(uint16 infomask)
Definition: htup_details.h:251
bool ItemPointerEquals(ItemPointer pointer1, ItemPointer pointer2)
Definition: itemptr.c:35
bool MultiXactIdIsRunning(MultiXactId multi, bool isLockOnly)
Definition: multixact.c:599
ItemPointerData t_ctid
Definition: htup_details.h:161
@ TM_Ok
Definition: tableam.h:84
@ TM_BeingModified
Definition: tableam.h:106
@ TM_Deleted
Definition: tableam.h:99
@ TM_Updated
Definition: tableam.h:96
@ TM_SelfModified
Definition: tableam.h:90
@ TM_Invisible
Definition: tableam.h:87

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_inplace_lock(), 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 1205 of file heapam_visibility.c.

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

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

1777{
1778 switch (snapshot->snapshot_type)
1779 {
1780 case SNAPSHOT_MVCC:
1781 return HeapTupleSatisfiesMVCC(htup, snapshot, buffer);
1782 case SNAPSHOT_SELF:
1783 return HeapTupleSatisfiesSelf(htup, snapshot, buffer);
1784 case SNAPSHOT_ANY:
1785 return HeapTupleSatisfiesAny(htup, snapshot, buffer);
1786 case SNAPSHOT_TOAST:
1787 return HeapTupleSatisfiesToast(htup, snapshot, buffer);
1788 case SNAPSHOT_DIRTY:
1789 return HeapTupleSatisfiesDirty(htup, snapshot, buffer);
1791 return HeapTupleSatisfiesHistoricMVCC(htup, snapshot, buffer);
1793 return HeapTupleSatisfiesNonVacuumable(htup, snapshot, buffer);
1794 }
1795
1796 return false; /* keep compiler quiet */
1797}
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:70
@ SNAPSHOT_SELF
Definition: snapshot.h:60
@ SNAPSHOT_NON_VACUUMABLE
Definition: snapshot.h:114
@ SNAPSHOT_MVCC
Definition: snapshot.h:46
@ SNAPSHOT_ANY
Definition: snapshot.h:65
@ SNAPSHOT_HISTORIC_MVCC
Definition: snapshot.h:105
@ SNAPSHOT_DIRTY
Definition: snapshot.h:98
SnapshotType snapshot_type
Definition: snapshot.h:140

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 BitmapHeapScanNextBlock(), heap_delete(), heap_fetch(), heap_get_latest_tid(), heap_hot_search_buffer(), heap_update(), heapam_tuple_satisfies_snapshot(), heapgettup(), page_collect_tuples(), 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:3964
XLogRecPtr BufferGetLSNAtomic(Buffer buffer)
Definition: bufmgr.c:3994
void MarkBufferDirtyHint(Buffer buffer, bool buffer_std)
Definition: bufmgr.c:4919
XLogRecPtr TransactionIdGetCommitLSN(TransactionId xid)
Definition: transam.c:382
bool XLogNeedsFlush(XLogRecPtr record)
Definition: xlog.c:3121
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 1575 of file heapam_visibility.c.

1576{
1577 return num > 0 &&
1578 bsearch(&xid, xip, num, sizeof(TransactionId), xidComparator) != NULL;
1579}
int xidComparator(const void *arg1, const void *arg2)
Definition: xid.c:152

References xidComparator().

Referenced by HeapTupleSatisfiesHistoricMVCC().