PostgreSQL Source Code git master
Loading...
Searching...
No Matches
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.

Typedefs

typedef enum SetHintBitsState SetHintBitsState
 

Enumerations

enum  SetHintBitsState { SHB_INITIAL , SHB_DISABLED , SHB_ENABLED }
 

Functions

static void SetHintBitsExt (HeapTupleHeader tuple, Buffer buffer, uint16 infomask, TransactionId xid, SetHintBitsState *state)
 
static void SetHintBits (HeapTupleHeader tuple, Buffer buffer, uint16 infomask, TransactionId xid)
 
void HeapTupleSetHintBits (HeapTupleHeader tuple, Buffer buffer, uint16 infomask, TransactionId xid)
 
static bool HeapTupleCleanMoved (HeapTupleHeader tuple, Buffer buffer)
 
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, SetHintBitsState *state)
 
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)
 
int HeapTupleSatisfiesMVCCBatch (Snapshot snapshot, Buffer buffer, int ntups, BatchMVCCState *batchmvcc, OffsetNumber *vistuples_dense)
 
bool HeapTupleSatisfiesVisibility (HeapTuple htup, Snapshot snapshot, Buffer buffer)
 

Typedef Documentation

◆ SetHintBitsState

Enumeration Type Documentation

◆ SetHintBitsState

Enumerator
SHB_INITIAL 
SHB_DISABLED 
SHB_ENABLED 

Definition at line 91 of file heapam_visibility.c.

92{
93 /* not yet checked if hint bits may be set */
95 /* failed to get permission to set hint bits, don't check again */
97 /* allowed to set hint bits */
SetHintBitsState
@ SHB_ENABLED
@ SHB_DISABLED
@ SHB_INITIAL

Function Documentation

◆ HeapTupleCleanMoved()

static bool HeapTupleCleanMoved ( HeapTupleHeader  tuple,
Buffer  buffer 
)
inlinestatic

Definition at line 232 of file heapam_visibility.c.

233{
235
236 /* only used by pre-9.0 binary upgrades */
237 if (likely(!(tuple->t_infomask & (HEAP_MOVED_OFF | HEAP_MOVED_IN))))
238 return true;
239
241
243 elog(ERROR, "encountered tuple with HEAP_MOVED considered current");
244
246 elog(ERROR, "encountered tuple with HEAP_MOVED considered in-progress");
247
248 if (tuple->t_infomask & HEAP_MOVED_OFF)
249 {
251 {
252 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
254 return false;
255 }
256 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
258 }
259 else if (tuple->t_infomask & HEAP_MOVED_IN)
260 {
262 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
264 else
265 {
266 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
268 return false;
269 }
270 }
271
272 return true;
273}
#define likely(x)
Definition c.h:431
uint32 TransactionId
Definition c.h:738
#define ERROR
Definition elog.h:39
#define elog(elevel,...)
Definition elog.h:226
static void SetHintBits(HeapTupleHeader tuple, Buffer buffer, uint16 infomask, TransactionId xid)
#define HEAP_MOVED_OFF
#define HEAP_XMIN_COMMITTED
static TransactionId HeapTupleHeaderGetXvac(const HeapTupleHeaderData *tup)
#define HEAP_MOVED_IN
#define HEAP_XMIN_INVALID
static int fb(int x)
bool TransactionIdIsInProgress(TransactionId xid)
Definition procarray.c:1401
bool TransactionIdDidCommit(TransactionId transactionId)
Definition transam.c:126
#define InvalidTransactionId
Definition transam.h:31
bool TransactionIdIsCurrentTransactionId(TransactionId xid)
Definition xact.c:943

References elog, ERROR, fb(), HEAP_MOVED_IN, HEAP_MOVED_OFF, HEAP_XMIN_COMMITTED, HEAP_XMIN_INVALID, HeapTupleHeaderGetXvac(), InvalidTransactionId, likely, SetHintBits(), HeapTupleHeaderData::t_infomask, TransactionIdDidCommit(), TransactionIdIsCurrentTransactionId(), and TransactionIdIsInProgress().

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

◆ HeapTupleHeaderIsOnlyLocked()

bool HeapTupleHeaderIsOnlyLocked ( HeapTupleHeader  tuple)

Definition at line 1437 of file heapam_visibility.c.

1438{
1439 TransactionId xmax;
1440
1441 /* if there's no valid Xmax, then there's obviously no update either */
1442 if (tuple->t_infomask & HEAP_XMAX_INVALID)
1443 return true;
1444
1445 if (tuple->t_infomask & HEAP_XMAX_LOCK_ONLY)
1446 return true;
1447
1448 /* invalid xmax means no update */
1450 return true;
1451
1452 /*
1453 * if HEAP_XMAX_LOCK_ONLY is not set and not a multi, then this must
1454 * necessarily have been updated
1455 */
1456 if (!(tuple->t_infomask & HEAP_XMAX_IS_MULTI))
1457 return false;
1458
1459 /* ... but if it's a multi, then perhaps the updating Xid aborted. */
1460 xmax = HeapTupleGetUpdateXid(tuple);
1461
1462 /* not LOCKED_ONLY, so it has to have an xmax */
1464
1466 return false;
1467 if (TransactionIdIsInProgress(xmax))
1468 return false;
1469 if (TransactionIdDidCommit(xmax))
1470 return false;
1471
1472 /*
1473 * not current, not in progress, not committed -- must have aborted or
1474 * crashed
1475 */
1476 return true;
1477}
#define Assert(condition)
Definition c.h:945
TransactionId HeapTupleGetUpdateXid(const HeapTupleHeaderData *tup)
Definition heapam.c:7677
#define HEAP_XMAX_LOCK_ONLY
static TransactionId HeapTupleHeaderGetRawXmax(const HeapTupleHeaderData *tup)
#define HEAP_XMAX_IS_MULTI
#define HEAP_XMAX_INVALID
#define TransactionIdIsValid(xid)
Definition transam.h:41

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

1382{
1383 HeapTupleHeader tuple = htup->t_data;
1384
1386 Assert(htup->t_tableOid != InvalidOid);
1387
1388 /*
1389 * If the inserting transaction is marked invalid, then it aborted, and
1390 * the tuple is definitely dead. If it's marked neither committed nor
1391 * invalid, then we assume it's still alive (since the presumption is that
1392 * all relevant hint bits were just set moments ago).
1393 */
1394 if (!HeapTupleHeaderXminCommitted(tuple))
1395 return HeapTupleHeaderXminInvalid(tuple);
1396
1397 /*
1398 * If the inserting transaction committed, but any deleting transaction
1399 * aborted, the tuple is still alive.
1400 */
1401 if (tuple->t_infomask & HEAP_XMAX_INVALID)
1402 return false;
1403
1404 /*
1405 * If the XMAX is just a lock, the tuple is still alive.
1406 */
1408 return false;
1409
1410 /*
1411 * If the Xmax is a MultiXact, it might be dead or alive, but we cannot
1412 * know without checking pg_multixact.
1413 */
1414 if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
1415 return false;
1416
1417 /* If deleter isn't known to have committed, assume it's still running. */
1418 if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED))
1419 return false;
1420
1421 /* Deleter committed, so tuple is dead if the XID is old enough. */
1422 return GlobalVisTestIsRemovableXid(vistest,
1424 true);
1425}
static bool HEAP_XMAX_IS_LOCKED_ONLY(uint16 infomask)
static bool HeapTupleHeaderXminInvalid(const HeapTupleHeaderData *tup)
#define HEAP_XMAX_COMMITTED
static bool HeapTupleHeaderXminCommitted(const HeapTupleHeaderData *tup)
static bool ItemPointerIsValid(const ItemPointerData *pointer)
Definition itemptr.h:83
#define InvalidOid
bool GlobalVisTestIsRemovableXid(GlobalVisState *state, TransactionId xid, bool allow_update)
Definition procarray.c:4277
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 430 of file heapam_visibility.c.

431{
432 return true;
433}

Referenced by HeapTupleSatisfiesVisibility().

◆ HeapTupleSatisfiesDirty()

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

Definition at line 759 of file heapam_visibility.c.

761{
762 HeapTupleHeader tuple = htup->t_data;
763
765 Assert(htup->t_tableOid != InvalidOid);
766
767 snapshot->xmin = snapshot->xmax = InvalidTransactionId;
768 snapshot->speculativeToken = 0;
769
771 {
773 return false;
774
775 if (!HeapTupleCleanMoved(tuple, buffer))
776 return false;
778 {
779 if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
780 return true;
781
782 if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask)) /* not deleter */
783 return true;
784
785 if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
786 {
787 TransactionId xmax;
788
789 xmax = HeapTupleGetUpdateXid(tuple);
790
791 /* not LOCKED_ONLY, so it has to have an xmax */
793
794 /* updating subtransaction must have aborted */
796 return true;
797 else
798 return false;
799 }
800
802 {
803 /* deleting subtransaction must have aborted */
804 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
806 return true;
807 }
808
809 return false;
810 }
812 {
813 /*
814 * Return the speculative token to caller. Caller can worry about
815 * xmax, since it requires a conclusively locked row version, and
816 * a concurrent update to this tuple is a conflict of its
817 * purposes.
818 */
820 {
821 snapshot->speculativeToken =
823
824 Assert(snapshot->speculativeToken != 0);
825 }
826
827 snapshot->xmin = HeapTupleHeaderGetRawXmin(tuple);
828 /* XXX shouldn't we fall through to look at xmax? */
829 return true; /* in insertion by other */
830 }
832 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
834 else
835 {
836 /* it must have aborted or crashed */
837 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
839 return false;
840 }
841 }
842
843 /* by here, the inserting transaction has committed */
844
845 if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */
846 return true;
847
848 if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
849 {
851 return true;
852 return false; /* updated by other */
853 }
854
855 if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
856 {
857 TransactionId xmax;
858
860 return true;
861
862 xmax = HeapTupleGetUpdateXid(tuple);
863
864 /* not LOCKED_ONLY, so it has to have an xmax */
866
868 return false;
870 {
871 snapshot->xmax = xmax;
872 return true;
873 }
874 if (TransactionIdDidCommit(xmax))
875 return false;
876 /* it must have aborted or crashed */
877 return true;
878 }
879
881 {
883 return true;
884 return false;
885 }
886
888 {
890 snapshot->xmax = HeapTupleHeaderGetRawXmax(tuple);
891 return true;
892 }
893
895 {
896 /* it must have aborted or crashed */
897 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
899 return true;
900 }
901
902 /* xmax transaction committed */
903
905 {
906 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
908 return true;
909 }
910
911 SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
913 return false; /* updated by other */
914}
static bool HeapTupleCleanMoved(HeapTupleHeader tuple, Buffer buffer)
static BlockNumber HeapTupleHeaderGetSpeculativeToken(const HeapTupleHeaderData *tup)
static TransactionId HeapTupleHeaderGetRawXmin(const HeapTupleHeaderData *tup)
static bool HeapTupleHeaderIsSpeculative(const HeapTupleHeaderData *tup)
TransactionId xmin
Definition snapshot.h:153
TransactionId xmax
Definition snapshot.h:154
uint32 speculativeToken
Definition snapshot.h:189

References Assert, HEAP_XMAX_COMMITTED, HEAP_XMAX_INVALID, HEAP_XMAX_IS_LOCKED_ONLY(), HEAP_XMAX_IS_MULTI, HEAP_XMIN_COMMITTED, HEAP_XMIN_INVALID, HeapTupleCleanMoved(), HeapTupleGetUpdateXid(), HeapTupleHeaderGetRawXmax(), HeapTupleHeaderGetRawXmin(), HeapTupleHeaderGetSpeculativeToken(), 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 1504 of file heapam_visibility.c.

1506{
1507 HeapTupleHeader tuple = htup->t_data;
1510
1512 Assert(htup->t_tableOid != InvalidOid);
1513
1514 /* inserting transaction aborted */
1515 if (HeapTupleHeaderXminInvalid(tuple))
1516 {
1518 return false;
1519 }
1520 /* check if it's one of our txids, toplevel is also in there */
1521 else if (TransactionIdInArray(xmin, snapshot->subxip, snapshot->subxcnt))
1522 {
1523 bool resolved;
1526
1527 /*
1528 * another transaction might have (tried to) delete this tuple or
1529 * cmin/cmax was stored in a combo CID. So we need to lookup the
1530 * actual values externally.
1531 */
1533 htup, buffer,
1534 &cmin, &cmax);
1535
1536 /*
1537 * If we haven't resolved the combo CID to cmin/cmax, that means we
1538 * have not decoded the combo CID yet. That means the cmin is
1539 * definitely in the future, and we're not supposed to see the tuple
1540 * yet.
1541 *
1542 * XXX This only applies to decoding of in-progress transactions. In
1543 * regular logical decoding we only execute this code at commit time,
1544 * at which point we should have seen all relevant combo CIDs. So
1545 * ideally, we should error out in this case but in practice, this
1546 * won't happen. If we are too worried about this then we can add an
1547 * elog inside ResolveCminCmaxDuringDecoding.
1548 *
1549 * XXX For the streaming case, we can track the largest combo CID
1550 * assigned, and error out based on this (when unable to resolve combo
1551 * CID below that observed maximum value).
1552 */
1553 if (!resolved)
1554 return false;
1555
1556 Assert(cmin != InvalidCommandId);
1557
1558 if (cmin >= snapshot->curcid)
1559 return false; /* inserted after scan started */
1560 /* fall through */
1561 }
1562 /* committed before our xmin horizon. Do a normal visibility check. */
1563 else if (TransactionIdPrecedes(xmin, snapshot->xmin))
1564 {
1566 !TransactionIdDidCommit(xmin)));
1567
1568 /* check for hint bit first, consult clog afterwards */
1569 if (!HeapTupleHeaderXminCommitted(tuple) &&
1571 return false;
1572 /* fall through */
1573 }
1574 /* beyond our xmax horizon, i.e. invisible */
1575 else if (TransactionIdFollowsOrEquals(xmin, snapshot->xmax))
1576 {
1577 return false;
1578 }
1579 /* check if it's a committed transaction in [xmin, xmax) */
1580 else if (TransactionIdInArray(xmin, snapshot->xip, snapshot->xcnt))
1581 {
1582 /* fall through */
1583 }
1584
1585 /*
1586 * none of the above, i.e. between [xmin, xmax) but hasn't committed. I.e.
1587 * invisible.
1588 */
1589 else
1590 {
1591 return false;
1592 }
1593
1594 /* at this point we know xmin is visible, go on to check xmax */
1595
1596 /* xid invalid or aborted */
1597 if (tuple->t_infomask & HEAP_XMAX_INVALID)
1598 return true;
1599 /* locked tuples are always visible */
1600 else if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
1601 return true;
1602
1603 /*
1604 * We can see multis here if we're looking at user tables or if somebody
1605 * SELECT ... FOR SHARE/UPDATE a system table.
1606 */
1607 else if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
1608 {
1609 xmax = HeapTupleGetUpdateXid(tuple);
1610 }
1611
1612 /* check if it's one of our txids, toplevel is also in there */
1613 if (TransactionIdInArray(xmax, snapshot->subxip, snapshot->subxcnt))
1614 {
1615 bool resolved;
1616 CommandId cmin;
1618
1619 /* Lookup actual cmin/cmax values */
1621 htup, buffer,
1622 &cmin, &cmax);
1623
1624 /*
1625 * If we haven't resolved the combo CID to cmin/cmax, that means we
1626 * have not decoded the combo CID yet. That means the cmax is
1627 * definitely in the future, and we're still supposed to see the
1628 * tuple.
1629 *
1630 * XXX This only applies to decoding of in-progress transactions. In
1631 * regular logical decoding we only execute this code at commit time,
1632 * at which point we should have seen all relevant combo CIDs. So
1633 * ideally, we should error out in this case but in practice, this
1634 * won't happen. If we are too worried about this then we can add an
1635 * elog inside ResolveCminCmaxDuringDecoding.
1636 *
1637 * XXX For the streaming case, we can track the largest combo CID
1638 * assigned, and error out based on this (when unable to resolve combo
1639 * CID below that observed maximum value).
1640 */
1641 if (!resolved || cmax == InvalidCommandId)
1642 return true;
1643
1644 if (cmax >= snapshot->curcid)
1645 return true; /* deleted after scan started */
1646 else
1647 return false; /* deleted before scan started */
1648 }
1649 /* below xmin horizon, normal transaction state is valid */
1650 else if (TransactionIdPrecedes(xmax, snapshot->xmin))
1651 {
1653 !TransactionIdDidCommit(xmax)));
1654
1655 /* check hint bit first */
1656 if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
1657 return false;
1658
1659 /* check clog */
1660 return !TransactionIdDidCommit(xmax);
1661 }
1662 /* above xmax horizon, we cannot possibly see the deleting transaction */
1663 else if (TransactionIdFollowsOrEquals(xmax, snapshot->xmax))
1664 return true;
1665 /* xmax is between [xmin, xmax), check known committed array */
1666 else if (TransactionIdInArray(xmax, snapshot->xip, snapshot->xcnt))
1667 return false;
1668 /* xmax is between [xmin, xmax), but known not to have committed yet */
1669 else
1670 return true;
1671}
#define InvalidCommandId
Definition c.h:755
uint32 CommandId
Definition c.h:752
static bool TransactionIdInArray(TransactionId xid, TransactionId *xip, Size num)
static CommandId HeapTupleHeaderGetRawCommandId(const HeapTupleHeaderData *tup)
static TransactionId HeapTupleHeaderGetXmin(const HeapTupleHeaderData *tup)
bool ResolveCminCmaxDuringDecoding(HTAB *tuplecid_data, Snapshot snapshot, HeapTuple htup, Buffer buffer, CommandId *cmin, CommandId *cmax)
HTAB * HistoricSnapshotGetTupleCids(void)
Definition snapmgr.c:1698
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
static bool TransactionIdFollowsOrEquals(TransactionId id1, TransactionId id2)
Definition transam.h:312
static bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition transam.h:263

References Assert, SnapshotData::curcid, fb(), 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,
SetHintBitsState state 
)
inlinestatic

Definition at line 939 of file heapam_visibility.c.

941{
942 HeapTupleHeader tuple = htup->t_data;
943
944 /*
945 * Assert that the caller has registered the snapshot. This function
946 * doesn't care about the registration as such, but in general you
947 * shouldn't try to use a snapshot without registration because it might
948 * get invalidated while it's still in use, and this is a convenient place
949 * to check for that.
950 */
951 Assert(snapshot->regd_count > 0 || snapshot->active_count > 0);
952
954 Assert(htup->t_tableOid != InvalidOid);
955
957 {
959 return false;
960
961 if (!HeapTupleCleanMoved(tuple, buffer))
962 return false;
964 {
965 if (HeapTupleHeaderGetCmin(tuple) >= snapshot->curcid)
966 return false; /* inserted after scan started */
967
968 if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
969 return true;
970
971 if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask)) /* not deleter */
972 return true;
973
974 if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
975 {
976 TransactionId xmax;
977
978 xmax = HeapTupleGetUpdateXid(tuple);
979
980 /* not LOCKED_ONLY, so it has to have an xmax */
982
983 /* updating subtransaction must have aborted */
985 return true;
986 else if (HeapTupleHeaderGetCmax(tuple) >= snapshot->curcid)
987 return true; /* updated after scan started */
988 else
989 return false; /* updated before scan started */
990 }
991
993 {
994 /* deleting subtransaction must have aborted */
995 SetHintBitsExt(tuple, buffer, HEAP_XMAX_INVALID,
997 return true;
998 }
999
1000 if (HeapTupleHeaderGetCmax(tuple) >= snapshot->curcid)
1001 return true; /* deleted after scan started */
1002 else
1003 return false; /* deleted before scan started */
1004 }
1005 else if (XidInMVCCSnapshot(HeapTupleHeaderGetRawXmin(tuple), snapshot))
1006 return false;
1008 SetHintBitsExt(tuple, buffer, HEAP_XMIN_COMMITTED,
1010 else
1011 {
1012 /* it must have aborted or crashed */
1013 SetHintBitsExt(tuple, buffer, HEAP_XMIN_INVALID,
1015 return false;
1016 }
1017 }
1018 else
1019 {
1020 /* xmin is committed, but maybe not according to our snapshot */
1021 if (!HeapTupleHeaderXminFrozen(tuple) &&
1023 return false; /* treat as still in progress */
1024 }
1025
1026 /* by here, the inserting transaction has committed */
1027
1028 if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */
1029 return true;
1030
1032 return true;
1033
1034 if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
1035 {
1036 TransactionId xmax;
1037
1038 /* already checked above */
1040
1041 xmax = HeapTupleGetUpdateXid(tuple);
1042
1043 /* not LOCKED_ONLY, so it has to have an xmax */
1045
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 if (XidInMVCCSnapshot(xmax, snapshot))
1054 return true;
1055 if (TransactionIdDidCommit(xmax))
1056 return false; /* updating transaction committed */
1057 /* it must have aborted or crashed */
1058 return true;
1059 }
1060
1061 if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED))
1062 {
1064 {
1065 if (HeapTupleHeaderGetCmax(tuple) >= snapshot->curcid)
1066 return true; /* deleted after scan started */
1067 else
1068 return false; /* deleted before scan started */
1069 }
1070
1071 if (XidInMVCCSnapshot(HeapTupleHeaderGetRawXmax(tuple), snapshot))
1072 return true;
1073
1075 {
1076 /* it must have aborted or crashed */
1077 SetHintBitsExt(tuple, buffer, HEAP_XMAX_INVALID,
1079 return true;
1080 }
1081
1082 /* xmax transaction committed */
1083 SetHintBitsExt(tuple, buffer, HEAP_XMAX_COMMITTED,
1085 }
1086 else
1087 {
1088 /* xmax is committed, but maybe not according to our snapshot */
1089 if (XidInMVCCSnapshot(HeapTupleHeaderGetRawXmax(tuple), snapshot))
1090 return true; /* treat as still in progress */
1091 }
1092
1093 /* xmax transaction committed */
1094
1095 return false;
1096}
CommandId HeapTupleHeaderGetCmin(const HeapTupleHeaderData *tup)
Definition combocid.c:104
CommandId HeapTupleHeaderGetCmax(const HeapTupleHeaderData *tup)
Definition combocid.c:118
static void SetHintBitsExt(HeapTupleHeader tuple, Buffer buffer, uint16 infomask, TransactionId xid, SetHintBitsState *state)
static bool HeapTupleHeaderXminFrozen(const HeapTupleHeaderData *tup)
bool XidInMVCCSnapshot(TransactionId xid, Snapshot snapshot)
Definition snapmgr.c:1869
uint32 regd_count
Definition snapshot.h:201
uint32 active_count
Definition snapshot.h:200

References SnapshotData::active_count, Assert, SnapshotData::curcid, HEAP_XMAX_COMMITTED, HEAP_XMAX_INVALID, HEAP_XMAX_IS_LOCKED_ONLY(), HEAP_XMAX_IS_MULTI, HEAP_XMIN_COMMITTED, HEAP_XMIN_INVALID, HeapTupleCleanMoved(), HeapTupleGetUpdateXid(), HeapTupleHeaderGetCmax(), HeapTupleHeaderGetCmin(), HeapTupleHeaderGetRawXmax(), HeapTupleHeaderGetRawXmin(), HeapTupleHeaderXminCommitted(), HeapTupleHeaderXminFrozen(), HeapTupleHeaderXminInvalid(), InvalidOid, InvalidTransactionId, ItemPointerIsValid(), SnapshotData::regd_count, SetHintBitsExt(), HeapTupleData::t_data, HeapTupleHeaderData::t_infomask, HeapTupleData::t_self, HeapTupleData::t_tableOid, TransactionIdDidCommit(), TransactionIdIsCurrentTransactionId(), TransactionIdIsValid, and XidInMVCCSnapshot().

Referenced by HeapTupleSatisfiesMVCCBatch(), and HeapTupleSatisfiesVisibility().

◆ HeapTupleSatisfiesMVCCBatch()

int HeapTupleSatisfiesMVCCBatch ( Snapshot  snapshot,
Buffer  buffer,
int  ntups,
BatchMVCCState batchmvcc,
OffsetNumber vistuples_dense 
)

Definition at line 1690 of file heapam_visibility.c.

1694{
1695 int nvis = 0;
1697
1698 Assert(IsMVCCSnapshot(snapshot));
1699
1700 for (int i = 0; i < ntups; i++)
1701 {
1702 bool valid;
1703 HeapTuple tup = &batchmvcc->tuples[i];
1704
1705 valid = HeapTupleSatisfiesMVCC(tup, snapshot, buffer, &state);
1706 batchmvcc->visible[i] = valid;
1707
1708 if (likely(valid))
1709 {
1710 vistuples_dense[nvis] = tup->t_self.ip_posid;
1711 nvis++;
1712 }
1713 }
1714
1715 if (state == SHB_ENABLED)
1716 BufferFinishSetHintBits(buffer, true, true);
1717
1718 return nvis;
1719}
void BufferFinishSetHintBits(Buffer buffer, bool mark_dirty, bool buffer_std)
Definition bufmgr.c:7050
static bool HeapTupleSatisfiesMVCC(HeapTuple htup, Snapshot snapshot, Buffer buffer, SetHintBitsState *state)
int i
Definition isn.c:77
#define IsMVCCSnapshot(snapshot)
Definition snapmgr.h:59

References Assert, BufferFinishSetHintBits(), fb(), HeapTupleSatisfiesMVCC(), i, IsMVCCSnapshot, likely, SHB_ENABLED, and SHB_INITIAL.

Referenced by page_collect_tuples().

◆ HeapTupleSatisfiesNonVacuumable()

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

Definition at line 1345 of file heapam_visibility.c.

1347{
1349 HTSV_Result res;
1350
1351 res = HeapTupleSatisfiesVacuumHorizon(htup, buffer, &dead_after);
1352
1353 if (res == HEAPTUPLE_RECENTLY_DEAD)
1354 {
1356
1357 if (GlobalVisTestIsRemovableXid(snapshot->vistest, dead_after, true))
1358 res = HEAPTUPLE_DEAD;
1359 }
1360 else
1362
1363 return res != HEAPTUPLE_DEAD;
1364}
HTSV_Result
Definition heapam.h:138
@ HEAPTUPLE_RECENTLY_DEAD
Definition heapam.h:141
@ HEAPTUPLE_DEAD
Definition heapam.h:139
HTSV_Result HeapTupleSatisfiesVacuumHorizon(HeapTuple htup, Buffer buffer, TransactionId *dead_after)
struct GlobalVisState * vistest
Definition snapshot.h:195

References Assert, fb(), 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 297 of file heapam_visibility.c.

298{
299 HeapTupleHeader tuple = htup->t_data;
300
302 Assert(htup->t_tableOid != InvalidOid);
303
305 {
307 return false;
308
309 if (!HeapTupleCleanMoved(tuple, buffer))
310 return false;
312 {
313 if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
314 return true;
315
316 if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask)) /* not deleter */
317 return true;
318
319 if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
320 {
321 TransactionId xmax;
322
323 xmax = HeapTupleGetUpdateXid(tuple);
324
325 /* not LOCKED_ONLY, so it has to have an xmax */
327
328 /* updating subtransaction must have aborted */
330 return true;
331 else
332 return false;
333 }
334
336 {
337 /* deleting subtransaction must have aborted */
338 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
340 return true;
341 }
342
343 return false;
344 }
346 return false;
348 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
350 else
351 {
352 /* it must have aborted or crashed */
353 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
355 return false;
356 }
357 }
358
359 /* by here, the inserting transaction has committed */
360
361 if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */
362 return true;
363
364 if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
365 {
367 return true;
368 return false; /* updated by other */
369 }
370
371 if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
372 {
373 TransactionId xmax;
374
376 return true;
377
378 xmax = HeapTupleGetUpdateXid(tuple);
379
380 /* not LOCKED_ONLY, so it has to have an xmax */
382
384 return false;
386 return true;
387 if (TransactionIdDidCommit(xmax))
388 return false;
389 /* it must have aborted or crashed */
390 return true;
391 }
392
394 {
396 return true;
397 return false;
398 }
399
401 return true;
402
404 {
405 /* it must have aborted or crashed */
406 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
408 return true;
409 }
410
411 /* xmax transaction committed */
412
414 {
415 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
417 return true;
418 }
419
420 SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
422 return false;
423}

References Assert, HEAP_XMAX_COMMITTED, HEAP_XMAX_INVALID, HEAP_XMAX_IS_LOCKED_ONLY(), HEAP_XMAX_IS_MULTI, HEAP_XMIN_COMMITTED, HEAP_XMIN_INVALID, HeapTupleCleanMoved(), HeapTupleGetUpdateXid(), HeapTupleHeaderGetRawXmax(), HeapTupleHeaderGetRawXmin(), 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 452 of file heapam_visibility.c.

454{
455 HeapTupleHeader tuple = htup->t_data;
456
458 Assert(htup->t_tableOid != InvalidOid);
459
461 {
463 return false;
464
465 if (!HeapTupleCleanMoved(tuple, buffer))
466 return false;
467
468 /*
469 * An invalid Xmin can be left behind by a speculative insertion that
470 * is canceled by super-deleting the tuple. This also applies to
471 * TOAST tuples created during speculative insertion.
472 */
474 return false;
475 }
476
477 /* otherwise assume the tuple is valid for TOAST. */
478 return true;
479}

References Assert, HeapTupleCleanMoved(), HeapTupleHeaderGetXmin(), HeapTupleHeaderXminCommitted(), HeapTupleHeaderXminInvalid(), InvalidOid, ItemPointerIsValid(), HeapTupleData::t_data, HeapTupleData::t_self, HeapTupleData::t_tableOid, and TransactionIdIsValid.

Referenced by HeapTupleSatisfiesVisibility().

◆ HeapTupleSatisfiesUpdate()

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

Definition at line 511 of file heapam_visibility.c.

513{
514 HeapTupleHeader tuple = htup->t_data;
515
517 Assert(htup->t_tableOid != InvalidOid);
518
520 {
522 return TM_Invisible;
523
524 else if (!HeapTupleCleanMoved(tuple, buffer))
525 return TM_Invisible;
527 {
528 if (HeapTupleHeaderGetCmin(tuple) >= curcid)
529 return TM_Invisible; /* inserted after scan started */
530
531 if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
532 return TM_Ok;
533
535 {
536 TransactionId xmax;
537
538 xmax = HeapTupleHeaderGetRawXmax(tuple);
539
540 /*
541 * Careful here: even though this tuple was created by our own
542 * transaction, it might be locked by other transactions, if
543 * the original version was key-share locked when we updated
544 * it.
545 */
546
547 if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
548 {
549 if (MultiXactIdIsRunning(xmax, true))
550 return TM_BeingModified;
551 else
552 return TM_Ok;
553 }
554
555 /*
556 * If the locker is gone, then there is nothing of interest
557 * left in this Xmax; otherwise, report the tuple as
558 * locked/updated.
559 */
560 if (!TransactionIdIsInProgress(xmax))
561 return TM_Ok;
562 return TM_BeingModified;
563 }
564
565 if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
566 {
567 TransactionId xmax;
568
569 xmax = HeapTupleGetUpdateXid(tuple);
570
571 /* not LOCKED_ONLY, so it has to have an xmax */
573
574 /* deleting subtransaction must have aborted */
576 {
578 false))
579 return TM_BeingModified;
580 return TM_Ok;
581 }
582 else
583 {
584 if (HeapTupleHeaderGetCmax(tuple) >= curcid)
585 return TM_SelfModified; /* updated after scan started */
586 else
587 return TM_Invisible; /* updated before scan started */
588 }
589 }
590
592 {
593 /* deleting subtransaction must have aborted */
594 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
596 return TM_Ok;
597 }
598
599 if (HeapTupleHeaderGetCmax(tuple) >= curcid)
600 return TM_SelfModified; /* updated after scan started */
601 else
602 return TM_Invisible; /* updated before scan started */
603 }
605 return TM_Invisible;
607 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
609 else
610 {
611 /* it must have aborted or crashed */
612 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
614 return TM_Invisible;
615 }
616 }
617
618 /* by here, the inserting transaction has committed */
619
620 if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */
621 return TM_Ok;
622
623 if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
624 {
626 return TM_Ok;
627 if (!ItemPointerEquals(&htup->t_self, &tuple->t_ctid))
628 return TM_Updated; /* updated by other */
629 else
630 return TM_Deleted; /* deleted by other */
631 }
632
633 if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
634 {
635 TransactionId xmax;
636
638 return TM_Ok;
639
641 {
643 return TM_BeingModified;
644
646 return TM_Ok;
647 }
648
649 xmax = HeapTupleGetUpdateXid(tuple);
650 if (!TransactionIdIsValid(xmax))
651 {
653 return TM_BeingModified;
654 }
655
656 /* not LOCKED_ONLY, so it has to have an xmax */
658
660 {
661 if (HeapTupleHeaderGetCmax(tuple) >= curcid)
662 return TM_SelfModified; /* updated after scan started */
663 else
664 return TM_Invisible; /* updated before scan started */
665 }
666
668 return TM_BeingModified;
669
670 if (TransactionIdDidCommit(xmax))
671 {
672 if (!ItemPointerEquals(&htup->t_self, &tuple->t_ctid))
673 return TM_Updated;
674 else
675 return TM_Deleted;
676 }
677
678 /*
679 * By here, the update in the Xmax is either aborted or crashed, but
680 * what about the other members?
681 */
682
684 {
685 /*
686 * There's no member, even just a locker, alive anymore, so we can
687 * mark the Xmax as invalid.
688 */
689 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
691 return TM_Ok;
692 }
693 else
694 {
695 /* There are lockers running */
696 return TM_BeingModified;
697 }
698 }
699
701 {
703 return TM_BeingModified;
704 if (HeapTupleHeaderGetCmax(tuple) >= curcid)
705 return TM_SelfModified; /* updated after scan started */
706 else
707 return TM_Invisible; /* updated before scan started */
708 }
709
711 return TM_BeingModified;
712
714 {
715 /* it must have aborted or crashed */
716 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
718 return TM_Ok;
719 }
720
721 /* xmax transaction committed */
722
724 {
725 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
727 return TM_Ok;
728 }
729
730 SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
732 if (!ItemPointerEquals(&htup->t_self, &tuple->t_ctid))
733 return TM_Updated; /* updated by other */
734 else
735 return TM_Deleted; /* deleted by other */
736}
static bool HEAP_LOCKED_UPGRADED(uint16 infomask)
bool ItemPointerEquals(const ItemPointerData *pointer1, const ItemPointerData *pointer2)
Definition itemptr.c:35
bool MultiXactIdIsRunning(MultiXactId multi, bool isLockOnly)
Definition multixact.c:511
ItemPointerData t_ctid
@ TM_Ok
Definition tableam.h:78
@ TM_BeingModified
Definition tableam.h:100
@ TM_Deleted
Definition tableam.h:93
@ TM_Updated
Definition tableam.h:90
@ TM_SelfModified
Definition tableam.h:84
@ TM_Invisible
Definition tableam.h:81

References Assert, HEAP_LOCKED_UPGRADED(), HEAP_XMAX_COMMITTED, HEAP_XMAX_INVALID, HEAP_XMAX_IS_LOCKED_ONLY(), HEAP_XMAX_IS_MULTI, HEAP_XMIN_COMMITTED, HEAP_XMIN_INVALID, HeapTupleCleanMoved(), HeapTupleGetUpdateXid(), HeapTupleHeaderGetCmax(), HeapTupleHeaderGetCmin(), HeapTupleHeaderGetRawXmax(), HeapTupleHeaderGetRawXmin(), 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()

◆ HeapTupleSatisfiesVacuumHorizon()

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

Definition at line 1147 of file heapam_visibility.c.

1148{
1149 HeapTupleHeader tuple = htup->t_data;
1150
1152 Assert(htup->t_tableOid != InvalidOid);
1154
1156
1157 /*
1158 * Has inserting transaction committed?
1159 *
1160 * If the inserting transaction aborted, then the tuple was never visible
1161 * to any other transaction, so we can delete it immediately.
1162 */
1163 if (!HeapTupleHeaderXminCommitted(tuple))
1164 {
1165 if (HeapTupleHeaderXminInvalid(tuple))
1166 return HEAPTUPLE_DEAD;
1167 else if (!HeapTupleCleanMoved(tuple, buffer))
1168 return HEAPTUPLE_DEAD;
1170 {
1171 if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
1173 /* only locked? run infomask-only check first, for performance */
1177 /* inserted and then deleted by same xact */
1180 /* deleting subtransaction must have aborted */
1182 }
1184 {
1185 /*
1186 * It'd be possible to discern between INSERT/DELETE in progress
1187 * here by looking at xmax - but that doesn't seem beneficial for
1188 * the majority of callers and even detrimental for some. We'd
1189 * rather have callers look at/wait for xmin than xmax. It's
1190 * always correct to return INSERT_IN_PROGRESS because that's
1191 * what's happening from the view of other backends.
1192 */
1194 }
1196 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
1198 else
1199 {
1200 /*
1201 * Not in Progress, Not Committed, so either Aborted or crashed
1202 */
1203 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
1205 return HEAPTUPLE_DEAD;
1206 }
1207
1208 /*
1209 * At this point the xmin is known committed, but we might not have
1210 * been able to set the hint bit yet; so we can no longer Assert that
1211 * it's set.
1212 */
1213 }
1214
1215 /*
1216 * Okay, the inserter committed, so it was good at some point. Now what
1217 * about the deleting transaction?
1218 */
1219 if (tuple->t_infomask & HEAP_XMAX_INVALID)
1220 return HEAPTUPLE_LIVE;
1221
1223 {
1224 /*
1225 * "Deleting" xact really only locked it, so the tuple is live in any
1226 * case. However, we should make sure that either XMAX_COMMITTED or
1227 * XMAX_INVALID gets set once the xact is gone, to reduce the costs of
1228 * examining the tuple for future xacts.
1229 */
1230 if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED))
1231 {
1232 if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
1233 {
1234 /*
1235 * If it's a pre-pg_upgrade tuple, the multixact cannot
1236 * possibly be running; otherwise have to check.
1237 */
1238 if (!HEAP_LOCKED_UPGRADED(tuple->t_infomask) &&
1240 true))
1241 return HEAPTUPLE_LIVE;
1243 }
1244 else
1245 {
1247 return HEAPTUPLE_LIVE;
1248 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
1250 }
1251 }
1252
1253 /*
1254 * We don't really care whether xmax did commit, abort or crash. We
1255 * know that xmax did lock the tuple, but it did not and will never
1256 * actually update it.
1257 */
1258
1259 return HEAPTUPLE_LIVE;
1260 }
1261
1262 if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
1263 {
1265
1266 /* already checked above */
1268
1269 /* not LOCKED_ONLY, so it has to have an xmax */
1271
1272 if (TransactionIdIsInProgress(xmax))
1274 else if (TransactionIdDidCommit(xmax))
1275 {
1276 /*
1277 * The multixact might still be running due to lockers. Need to
1278 * allow for pruning if below the xid horizon regardless --
1279 * otherwise we could end up with a tuple where the updater has to
1280 * be removed due to the horizon, but is not pruned away. It's
1281 * not a problem to prune that tuple, because any remaining
1282 * lockers will also be present in newer tuple versions.
1283 */
1284 *dead_after = xmax;
1286 }
1287 else if (!MultiXactIdIsRunning(HeapTupleHeaderGetRawXmax(tuple), false))
1288 {
1289 /*
1290 * Not in Progress, Not Committed, so either Aborted or crashed.
1291 * Mark the Xmax as invalid.
1292 */
1294 }
1295
1296 return HEAPTUPLE_LIVE;
1297 }
1298
1299 if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED))
1300 {
1304 SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
1306 else
1307 {
1308 /*
1309 * Not in Progress, Not Committed, so either Aborted or crashed
1310 */
1311 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
1313 return HEAPTUPLE_LIVE;
1314 }
1315
1316 /*
1317 * At this point the xmax is known committed, but we might not have
1318 * been able to set the hint bit yet; so we can no longer Assert that
1319 * it's set.
1320 */
1321 }
1322
1323 /*
1324 * Deleter committed, allow caller to check if it was recent enough that
1325 * some open transactions could still see the tuple.
1326 */
1329}
@ HEAPTUPLE_INSERT_IN_PROGRESS
Definition heapam.h:142
@ HEAPTUPLE_LIVE
Definition heapam.h:140
@ HEAPTUPLE_DELETE_IN_PROGRESS
Definition heapam.h:143
bool HeapTupleHeaderIsOnlyLocked(HeapTupleHeader tuple)
static TransactionId HeapTupleHeaderGetUpdateXid(const HeapTupleHeaderData *tup)

References Assert, fb(), HEAP_LOCKED_UPGRADED(), 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, HeapTupleCleanMoved(), HeapTupleGetUpdateXid(), HeapTupleHeaderGetRawXmax(), HeapTupleHeaderGetRawXmin(), HeapTupleHeaderGetUpdateXid(), 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_page_would_be_all_visible(), heap_prune_satisfies_vacuum(), heapam_scan_analyze_next_tuple(), HeapTupleSatisfiesNonVacuumable(), and HeapTupleSatisfiesVacuum().

◆ HeapTupleSatisfiesVisibility()

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

Definition at line 1732 of file heapam_visibility.c.

1733{
1734 switch (snapshot->snapshot_type)
1735 {
1736 case SNAPSHOT_MVCC:
1737 return HeapTupleSatisfiesMVCC(htup, snapshot, buffer, NULL);
1738 case SNAPSHOT_SELF:
1739 return HeapTupleSatisfiesSelf(htup, snapshot, buffer);
1740 case SNAPSHOT_ANY:
1741 return HeapTupleSatisfiesAny(htup, snapshot, buffer);
1742 case SNAPSHOT_TOAST:
1743 return HeapTupleSatisfiesToast(htup, snapshot, buffer);
1744 case SNAPSHOT_DIRTY:
1745 return HeapTupleSatisfiesDirty(htup, snapshot, buffer);
1747 return HeapTupleSatisfiesHistoricMVCC(htup, snapshot, buffer);
1749 return HeapTupleSatisfiesNonVacuumable(htup, snapshot, buffer);
1750 }
1751
1752 return false; /* keep compiler quiet */
1753}
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 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 fb(), 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(), pgstat_heap(), SampleHeapTupleVisible(), and ScanSourceDatabasePgClassPage().

◆ HeapTupleSetHintBits()

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

Definition at line 212 of file heapam_visibility.c.

214{
215 /*
216 * The uses from heapam.c rely on being able to perform the hint bit
217 * updates, which can only be guaranteed if we are holding an exclusive
218 * lock on the buffer - which all callers are doing.
219 */
221
222 SetHintBits(tuple, buffer, infomask, xid);
223}
bool BufferIsLockedByMeInMode(Buffer buffer, BufferLockMode mode)
Definition bufmgr.c:3072
@ BUFFER_LOCK_EXCLUSIVE
Definition bufmgr.h:222

References Assert, BUFFER_LOCK_EXCLUSIVE, BufferIsLockedByMeInMode(), fb(), and SetHintBits().

Referenced by UpdateXmaxHintBits().

◆ SetHintBits()

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

◆ SetHintBitsExt()

static void SetHintBitsExt ( HeapTupleHeader  tuple,
Buffer  buffer,
uint16  infomask,
TransactionId  xid,
SetHintBitsState state 
)
inlinestatic

Definition at line 142 of file heapam_visibility.c.

144{
145 /*
146 * In batched mode, if we previously did not get permission to set hint
147 * bits, don't try again - in all likelihood IO is still going on.
148 */
149 if (state && *state == SHB_DISABLED)
150 return;
151
152 if (TransactionIdIsValid(xid))
153 {
154 if (BufferIsPermanent(buffer))
155 {
156 /* NB: xid must be known committed here! */
158
161 {
162 /* not flushed and no LSN interlock, so don't set hint */
163 return;
164 }
165 }
166 }
167
168 /*
169 * If we're not operating in batch mode, use BufferSetHintBits16() to mark
170 * the page dirty, that's cheaper than
171 * BufferBeginSetHintBits()/BufferFinishSetHintBits(). That's important
172 * for cases where we set a lot of hint bits on a page individually.
173 */
174 if (!state)
175 {
177 tuple->t_infomask | infomask, buffer);
178 return;
179 }
180
181 if (*state == SHB_INITIAL)
182 {
183 if (!BufferBeginSetHintBits(buffer))
184 {
186 return;
187 }
188
190 }
191 tuple->t_infomask |= infomask;
192}
bool BufferSetHintBits16(uint16 *ptr, uint16 val, Buffer buffer)
Definition bufmgr.c:7073
bool BufferIsPermanent(Buffer buffer)
Definition bufmgr.c:4657
XLogRecPtr BufferGetLSNAtomic(Buffer buffer)
Definition bufmgr.c:4693
bool BufferBeginSetHintBits(Buffer buffer)
Definition bufmgr.c:7022
XLogRecPtr TransactionIdGetCommitLSN(TransactionId xid)
Definition transam.c:318
bool XLogNeedsFlush(XLogRecPtr record)
Definition xlog.c:3129
uint64 XLogRecPtr
Definition xlogdefs.h:21

References BufferBeginSetHintBits(), BufferGetLSNAtomic(), BufferIsPermanent(), BufferSetHintBits16(), fb(), SHB_DISABLED, SHB_ENABLED, SHB_INITIAL, HeapTupleHeaderData::t_infomask, TransactionIdGetCommitLSN(), TransactionIdIsValid, and XLogNeedsFlush().

Referenced by HeapTupleSatisfiesMVCC(), and SetHintBits().

◆ TransactionIdInArray()

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

Definition at line 1483 of file heapam_visibility.c.

1484{
1485 return num > 0 &&
1486 bsearch(&xid, xip, num, sizeof(TransactionId), xidComparator) != NULL;
1487}
int xidComparator(const void *arg1, const void *arg2)
Definition xid.c:152

References fb(), and xidComparator().

Referenced by HeapTupleSatisfiesHistoricMVCC().