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.

Functions

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)
 
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)
 

Function Documentation

◆ HeapTupleCleanMoved()

static bool HeapTupleCleanMoved ( HeapTupleHeader  tuple,
Buffer  buffer 
)
inlinestatic

Definition at line 161 of file heapam_visibility.c.

162{
164
165 /* only used by pre-9.0 binary upgrades */
166 if (likely(!(tuple->t_infomask & (HEAP_MOVED_OFF | HEAP_MOVED_IN))))
167 return true;
168
170
172 elog(ERROR, "encountered tuple with HEAP_MOVED considered current");
173
175 elog(ERROR, "encountered tuple with HEAP_MOVED considered in-progress");
176
177 if (tuple->t_infomask & HEAP_MOVED_OFF)
178 {
180 {
181 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
183 return false;
184 }
185 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
187 }
188 else if (tuple->t_infomask & HEAP_MOVED_IN)
189 {
191 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
193 else
194 {
195 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
197 return false;
198 }
199 }
200
201 return true;
202}
#define likely(x)
Definition c.h:411
uint32 TransactionId
Definition c.h:666
#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:1404
bool TransactionIdDidCommit(TransactionId transactionId)
Definition transam.c:126
#define InvalidTransactionId
Definition transam.h:31
bool TransactionIdIsCurrentTransactionId(TransactionId xid)
Definition xact.c:942

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

1366{
1367 TransactionId xmax;
1368
1369 /* if there's no valid Xmax, then there's obviously no update either */
1370 if (tuple->t_infomask & HEAP_XMAX_INVALID)
1371 return true;
1372
1373 if (tuple->t_infomask & HEAP_XMAX_LOCK_ONLY)
1374 return true;
1375
1376 /* invalid xmax means no update */
1378 return true;
1379
1380 /*
1381 * if HEAP_XMAX_LOCK_ONLY is not set and not a multi, then this must
1382 * necessarily have been updated
1383 */
1384 if (!(tuple->t_infomask & HEAP_XMAX_IS_MULTI))
1385 return false;
1386
1387 /* ... but if it's a multi, then perhaps the updating Xid aborted. */
1388 xmax = HeapTupleGetUpdateXid(tuple);
1389
1390 /* not LOCKED_ONLY, so it has to have an xmax */
1392
1394 return false;
1395 if (TransactionIdIsInProgress(xmax))
1396 return false;
1397 if (TransactionIdDidCommit(xmax))
1398 return false;
1399
1400 /*
1401 * not current, not in progress, not committed -- must have aborted or
1402 * crashed
1403 */
1404 return true;
1405}
#define Assert(condition)
Definition c.h:873
TransactionId HeapTupleGetUpdateXid(const HeapTupleHeaderData *tup)
Definition heapam.c:7659
#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 1310 of file heapam_visibility.c.

1311{
1312 HeapTupleHeader tuple = htup->t_data;
1313
1315 Assert(htup->t_tableOid != InvalidOid);
1316
1317 /*
1318 * If the inserting transaction is marked invalid, then it aborted, and
1319 * the tuple is definitely dead. If it's marked neither committed nor
1320 * invalid, then we assume it's still alive (since the presumption is that
1321 * all relevant hint bits were just set moments ago).
1322 */
1323 if (!HeapTupleHeaderXminCommitted(tuple))
1324 return HeapTupleHeaderXminInvalid(tuple);
1325
1326 /*
1327 * If the inserting transaction committed, but any deleting transaction
1328 * aborted, the tuple is still alive.
1329 */
1330 if (tuple->t_infomask & HEAP_XMAX_INVALID)
1331 return false;
1332
1333 /*
1334 * If the XMAX is just a lock, the tuple is still alive.
1335 */
1337 return false;
1338
1339 /*
1340 * If the Xmax is a MultiXact, it might be dead or alive, but we cannot
1341 * know without checking pg_multixact.
1342 */
1343 if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
1344 return false;
1345
1346 /* If deleter isn't known to have committed, assume it's still running. */
1347 if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED))
1348 return false;
1349
1350 /* Deleter committed, so tuple is dead if the XID is old enough. */
1351 return GlobalVisTestIsRemovableXid(vistest,
1353}
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)
Definition procarray.c:4243
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 359 of file heapam_visibility.c.

360{
361 return true;
362}

Referenced by HeapTupleSatisfiesVisibility().

◆ HeapTupleSatisfiesDirty()

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

Definition at line 688 of file heapam_visibility.c.

690{
691 HeapTupleHeader tuple = htup->t_data;
692
694 Assert(htup->t_tableOid != InvalidOid);
695
696 snapshot->xmin = snapshot->xmax = InvalidTransactionId;
697 snapshot->speculativeToken = 0;
698
700 {
702 return false;
703
704 if (!HeapTupleCleanMoved(tuple, buffer))
705 return false;
707 {
708 if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
709 return true;
710
711 if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask)) /* not deleter */
712 return true;
713
714 if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
715 {
716 TransactionId xmax;
717
718 xmax = HeapTupleGetUpdateXid(tuple);
719
720 /* not LOCKED_ONLY, so it has to have an xmax */
722
723 /* updating subtransaction must have aborted */
725 return true;
726 else
727 return false;
728 }
729
731 {
732 /* deleting subtransaction must have aborted */
733 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
735 return true;
736 }
737
738 return false;
739 }
741 {
742 /*
743 * Return the speculative token to caller. Caller can worry about
744 * xmax, since it requires a conclusively locked row version, and
745 * a concurrent update to this tuple is a conflict of its
746 * purposes.
747 */
749 {
750 snapshot->speculativeToken =
752
753 Assert(snapshot->speculativeToken != 0);
754 }
755
756 snapshot->xmin = HeapTupleHeaderGetRawXmin(tuple);
757 /* XXX shouldn't we fall through to look at xmax? */
758 return true; /* in insertion by other */
759 }
761 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
763 else
764 {
765 /* it must have aborted or crashed */
766 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
768 return false;
769 }
770 }
771
772 /* by here, the inserting transaction has committed */
773
774 if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */
775 return true;
776
777 if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
778 {
780 return true;
781 return false; /* updated by other */
782 }
783
784 if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
785 {
786 TransactionId xmax;
787
789 return true;
790
791 xmax = HeapTupleGetUpdateXid(tuple);
792
793 /* not LOCKED_ONLY, so it has to have an xmax */
795
797 return false;
799 {
800 snapshot->xmax = xmax;
801 return true;
802 }
803 if (TransactionIdDidCommit(xmax))
804 return false;
805 /* it must have aborted or crashed */
806 return true;
807 }
808
810 {
812 return true;
813 return false;
814 }
815
817 {
819 snapshot->xmax = HeapTupleHeaderGetRawXmax(tuple);
820 return true;
821 }
822
824 {
825 /* it must have aborted or crashed */
826 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
828 return true;
829 }
830
831 /* xmax transaction committed */
832
834 {
835 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
837 return true;
838 }
839
840 SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
842 return false; /* updated by other */
843}
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 1432 of file heapam_visibility.c.

1434{
1435 HeapTupleHeader tuple = htup->t_data;
1438
1440 Assert(htup->t_tableOid != InvalidOid);
1441
1442 /* inserting transaction aborted */
1443 if (HeapTupleHeaderXminInvalid(tuple))
1444 {
1446 return false;
1447 }
1448 /* check if it's one of our txids, toplevel is also in there */
1449 else if (TransactionIdInArray(xmin, snapshot->subxip, snapshot->subxcnt))
1450 {
1451 bool resolved;
1454
1455 /*
1456 * another transaction might have (tried to) delete this tuple or
1457 * cmin/cmax was stored in a combo CID. So we need to lookup the
1458 * actual values externally.
1459 */
1461 htup, buffer,
1462 &cmin, &cmax);
1463
1464 /*
1465 * If we haven't resolved the combo CID to cmin/cmax, that means we
1466 * have not decoded the combo CID yet. That means the cmin is
1467 * definitely in the future, and we're not supposed to see the tuple
1468 * yet.
1469 *
1470 * XXX This only applies to decoding of in-progress transactions. In
1471 * regular logical decoding we only execute this code at commit time,
1472 * at which point we should have seen all relevant combo CIDs. So
1473 * ideally, we should error out in this case but in practice, this
1474 * won't happen. If we are too worried about this then we can add an
1475 * elog inside ResolveCminCmaxDuringDecoding.
1476 *
1477 * XXX For the streaming case, we can track the largest combo CID
1478 * assigned, and error out based on this (when unable to resolve combo
1479 * CID below that observed maximum value).
1480 */
1481 if (!resolved)
1482 return false;
1483
1484 Assert(cmin != InvalidCommandId);
1485
1486 if (cmin >= snapshot->curcid)
1487 return false; /* inserted after scan started */
1488 /* fall through */
1489 }
1490 /* committed before our xmin horizon. Do a normal visibility check. */
1491 else if (TransactionIdPrecedes(xmin, snapshot->xmin))
1492 {
1494 !TransactionIdDidCommit(xmin)));
1495
1496 /* check for hint bit first, consult clog afterwards */
1497 if (!HeapTupleHeaderXminCommitted(tuple) &&
1499 return false;
1500 /* fall through */
1501 }
1502 /* beyond our xmax horizon, i.e. invisible */
1503 else if (TransactionIdFollowsOrEquals(xmin, snapshot->xmax))
1504 {
1505 return false;
1506 }
1507 /* check if it's a committed transaction in [xmin, xmax) */
1508 else if (TransactionIdInArray(xmin, snapshot->xip, snapshot->xcnt))
1509 {
1510 /* fall through */
1511 }
1512
1513 /*
1514 * none of the above, i.e. between [xmin, xmax) but hasn't committed. I.e.
1515 * invisible.
1516 */
1517 else
1518 {
1519 return false;
1520 }
1521
1522 /* at this point we know xmin is visible, go on to check xmax */
1523
1524 /* xid invalid or aborted */
1525 if (tuple->t_infomask & HEAP_XMAX_INVALID)
1526 return true;
1527 /* locked tuples are always visible */
1528 else if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
1529 return true;
1530
1531 /*
1532 * We can see multis here if we're looking at user tables or if somebody
1533 * SELECT ... FOR SHARE/UPDATE a system table.
1534 */
1535 else if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
1536 {
1537 xmax = HeapTupleGetUpdateXid(tuple);
1538 }
1539
1540 /* check if it's one of our txids, toplevel is also in there */
1541 if (TransactionIdInArray(xmax, snapshot->subxip, snapshot->subxcnt))
1542 {
1543 bool resolved;
1544 CommandId cmin;
1546
1547 /* Lookup actual cmin/cmax values */
1549 htup, buffer,
1550 &cmin, &cmax);
1551
1552 /*
1553 * If we haven't resolved the combo CID to cmin/cmax, that means we
1554 * have not decoded the combo CID yet. That means the cmax is
1555 * definitely in the future, and we're still supposed to see the
1556 * tuple.
1557 *
1558 * XXX This only applies to decoding of in-progress transactions. In
1559 * regular logical decoding we only execute this code at commit time,
1560 * at which point we should have seen all relevant combo CIDs. So
1561 * ideally, we should error out in this case but in practice, this
1562 * won't happen. If we are too worried about this then we can add an
1563 * elog inside ResolveCminCmaxDuringDecoding.
1564 *
1565 * XXX For the streaming case, we can track the largest combo CID
1566 * assigned, and error out based on this (when unable to resolve combo
1567 * CID below that observed maximum value).
1568 */
1569 if (!resolved || cmax == InvalidCommandId)
1570 return true;
1571
1572 if (cmax >= snapshot->curcid)
1573 return true; /* deleted after scan started */
1574 else
1575 return false; /* deleted before scan started */
1576 }
1577 /* below xmin horizon, normal transaction state is valid */
1578 else if (TransactionIdPrecedes(xmax, snapshot->xmin))
1579 {
1581 !TransactionIdDidCommit(xmax)));
1582
1583 /* check hint bit first */
1584 if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
1585 return false;
1586
1587 /* check clog */
1588 return !TransactionIdDidCommit(xmax);
1589 }
1590 /* above xmax horizon, we cannot possibly see the deleting transaction */
1591 else if (TransactionIdFollowsOrEquals(xmax, snapshot->xmax))
1592 return true;
1593 /* xmax is between [xmin, xmax), check known committed array */
1594 else if (TransactionIdInArray(xmax, snapshot->xip, snapshot->xcnt))
1595 return false;
1596 /* xmax is between [xmin, xmax), but known not to have committed yet */
1597 else
1598 return true;
1599}
#define InvalidCommandId
Definition c.h:683
uint32 CommandId
Definition c.h:680
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 
)
static

Definition at line 868 of file heapam_visibility.c.

870{
871 HeapTupleHeader tuple = htup->t_data;
872
873 /*
874 * Assert that the caller has registered the snapshot. This function
875 * doesn't care about the registration as such, but in general you
876 * shouldn't try to use a snapshot without registration because it might
877 * get invalidated while it's still in use, and this is a convenient place
878 * to check for that.
879 */
880 Assert(snapshot->regd_count > 0 || snapshot->active_count > 0);
881
883 Assert(htup->t_tableOid != InvalidOid);
884
886 {
888 return false;
889
890 if (!HeapTupleCleanMoved(tuple, buffer))
891 return false;
893 {
894 if (HeapTupleHeaderGetCmin(tuple) >= snapshot->curcid)
895 return false; /* inserted after scan started */
896
897 if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
898 return true;
899
900 if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask)) /* not deleter */
901 return true;
902
903 if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
904 {
905 TransactionId xmax;
906
907 xmax = HeapTupleGetUpdateXid(tuple);
908
909 /* not LOCKED_ONLY, so it has to have an xmax */
911
912 /* updating subtransaction must have aborted */
914 return true;
915 else if (HeapTupleHeaderGetCmax(tuple) >= snapshot->curcid)
916 return true; /* updated after scan started */
917 else
918 return false; /* updated before scan started */
919 }
920
922 {
923 /* deleting subtransaction must have aborted */
924 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
926 return true;
927 }
928
929 if (HeapTupleHeaderGetCmax(tuple) >= snapshot->curcid)
930 return true; /* deleted after scan started */
931 else
932 return false; /* deleted before scan started */
933 }
934 else if (XidInMVCCSnapshot(HeapTupleHeaderGetRawXmin(tuple), snapshot))
935 return false;
937 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
939 else
940 {
941 /* it must have aborted or crashed */
942 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
944 return false;
945 }
946 }
947 else
948 {
949 /* xmin is committed, but maybe not according to our snapshot */
950 if (!HeapTupleHeaderXminFrozen(tuple) &&
952 return false; /* treat as still in progress */
953 }
954
955 /* by here, the inserting transaction has committed */
956
957 if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */
958 return true;
959
961 return true;
962
963 if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
964 {
965 TransactionId xmax;
966
967 /* already checked above */
969
970 xmax = HeapTupleGetUpdateXid(tuple);
971
972 /* not LOCKED_ONLY, so it has to have an xmax */
974
976 {
977 if (HeapTupleHeaderGetCmax(tuple) >= snapshot->curcid)
978 return true; /* deleted after scan started */
979 else
980 return false; /* deleted before scan started */
981 }
982 if (XidInMVCCSnapshot(xmax, snapshot))
983 return true;
984 if (TransactionIdDidCommit(xmax))
985 return false; /* updating transaction committed */
986 /* it must have aborted or crashed */
987 return true;
988 }
989
990 if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED))
991 {
993 {
994 if (HeapTupleHeaderGetCmax(tuple) >= snapshot->curcid)
995 return true; /* deleted after scan started */
996 else
997 return false; /* deleted before scan started */
998 }
999
1000 if (XidInMVCCSnapshot(HeapTupleHeaderGetRawXmax(tuple), snapshot))
1001 return true;
1002
1004 {
1005 /* it must have aborted or crashed */
1006 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
1008 return true;
1009 }
1010
1011 /* xmax transaction committed */
1012 SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
1014 }
1015 else
1016 {
1017 /* xmax is committed, but maybe not according to our snapshot */
1018 if (XidInMVCCSnapshot(HeapTupleHeaderGetRawXmax(tuple), snapshot))
1019 return true; /* treat as still in progress */
1020 }
1021
1022 /* xmax transaction committed */
1023
1024 return false;
1025}
CommandId HeapTupleHeaderGetCmin(const HeapTupleHeaderData *tup)
Definition combocid.c:104
CommandId HeapTupleHeaderGetCmax(const HeapTupleHeaderData *tup)
Definition combocid.c:118
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, SetHintBits(), 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 1617 of file heapam_visibility.c.

1621{
1622 int nvis = 0;
1623
1624 Assert(IsMVCCSnapshot(snapshot));
1625
1626 for (int i = 0; i < ntups; i++)
1627 {
1628 bool valid;
1629 HeapTuple tup = &batchmvcc->tuples[i];
1630
1631 valid = HeapTupleSatisfiesMVCC(tup, snapshot, buffer);
1632 batchmvcc->visible[i] = valid;
1633
1634 if (likely(valid))
1635 {
1636 vistuples_dense[nvis] = tup->t_self.ip_posid;
1637 nvis++;
1638 }
1639 }
1640
1641 return nvis;
1642}
static bool HeapTupleSatisfiesMVCC(HeapTuple htup, Snapshot snapshot, Buffer buffer)
int i
Definition isn.c:77
#define IsMVCCSnapshot(snapshot)
Definition snapmgr.h:55

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

Referenced by page_collect_tuples().

◆ HeapTupleSatisfiesNonVacuumable()

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

Definition at line 1274 of file heapam_visibility.c.

1276{
1278 HTSV_Result res;
1279
1280 res = HeapTupleSatisfiesVacuumHorizon(htup, buffer, &dead_after);
1281
1282 if (res == HEAPTUPLE_RECENTLY_DEAD)
1283 {
1285
1287 res = HEAPTUPLE_DEAD;
1288 }
1289 else
1291
1292 return res != HEAPTUPLE_DEAD;
1293}
HTSV_Result
Definition heapam.h:125
@ HEAPTUPLE_RECENTLY_DEAD
Definition heapam.h:128
@ HEAPTUPLE_DEAD
Definition heapam.h:126
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 226 of file heapam_visibility.c.

227{
228 HeapTupleHeader tuple = htup->t_data;
229
231 Assert(htup->t_tableOid != InvalidOid);
232
234 {
236 return false;
237
238 if (!HeapTupleCleanMoved(tuple, buffer))
239 return false;
241 {
242 if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
243 return true;
244
245 if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask)) /* not deleter */
246 return true;
247
248 if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
249 {
250 TransactionId xmax;
251
252 xmax = HeapTupleGetUpdateXid(tuple);
253
254 /* not LOCKED_ONLY, so it has to have an xmax */
256
257 /* updating subtransaction must have aborted */
259 return true;
260 else
261 return false;
262 }
263
265 {
266 /* deleting subtransaction must have aborted */
267 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
269 return true;
270 }
271
272 return false;
273 }
275 return false;
277 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
279 else
280 {
281 /* it must have aborted or crashed */
282 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
284 return false;
285 }
286 }
287
288 /* by here, the inserting transaction has committed */
289
290 if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */
291 return true;
292
293 if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
294 {
296 return true;
297 return false; /* updated by other */
298 }
299
300 if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
301 {
302 TransactionId xmax;
303
305 return true;
306
307 xmax = HeapTupleGetUpdateXid(tuple);
308
309 /* not LOCKED_ONLY, so it has to have an xmax */
311
313 return false;
315 return true;
316 if (TransactionIdDidCommit(xmax))
317 return false;
318 /* it must have aborted or crashed */
319 return true;
320 }
321
323 {
325 return true;
326 return false;
327 }
328
330 return true;
331
333 {
334 /* it must have aborted or crashed */
335 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
337 return true;
338 }
339
340 /* xmax transaction committed */
341
343 {
344 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
346 return true;
347 }
348
349 SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
351 return false;
352}

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

383{
384 HeapTupleHeader tuple = htup->t_data;
385
387 Assert(htup->t_tableOid != InvalidOid);
388
390 {
392 return false;
393
394 if (!HeapTupleCleanMoved(tuple, buffer))
395 return false;
396
397 /*
398 * An invalid Xmin can be left behind by a speculative insertion that
399 * is canceled by super-deleting the tuple. This also applies to
400 * TOAST tuples created during speculative insertion.
401 */
403 return false;
404 }
405
406 /* otherwise assume the tuple is valid for TOAST. */
407 return true;
408}

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

442{
443 HeapTupleHeader tuple = htup->t_data;
444
446 Assert(htup->t_tableOid != InvalidOid);
447
449 {
451 return TM_Invisible;
452
453 else if (!HeapTupleCleanMoved(tuple, buffer))
454 return TM_Invisible;
456 {
457 if (HeapTupleHeaderGetCmin(tuple) >= curcid)
458 return TM_Invisible; /* inserted after scan started */
459
460 if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
461 return TM_Ok;
462
464 {
465 TransactionId xmax;
466
467 xmax = HeapTupleHeaderGetRawXmax(tuple);
468
469 /*
470 * Careful here: even though this tuple was created by our own
471 * transaction, it might be locked by other transactions, if
472 * the original version was key-share locked when we updated
473 * it.
474 */
475
476 if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
477 {
478 if (MultiXactIdIsRunning(xmax, true))
479 return TM_BeingModified;
480 else
481 return TM_Ok;
482 }
483
484 /*
485 * If the locker is gone, then there is nothing of interest
486 * left in this Xmax; otherwise, report the tuple as
487 * locked/updated.
488 */
489 if (!TransactionIdIsInProgress(xmax))
490 return TM_Ok;
491 return TM_BeingModified;
492 }
493
494 if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
495 {
496 TransactionId xmax;
497
498 xmax = HeapTupleGetUpdateXid(tuple);
499
500 /* not LOCKED_ONLY, so it has to have an xmax */
502
503 /* deleting subtransaction must have aborted */
505 {
507 false))
508 return TM_BeingModified;
509 return TM_Ok;
510 }
511 else
512 {
513 if (HeapTupleHeaderGetCmax(tuple) >= curcid)
514 return TM_SelfModified; /* updated after scan started */
515 else
516 return TM_Invisible; /* updated before scan started */
517 }
518 }
519
521 {
522 /* deleting subtransaction must have aborted */
523 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
525 return TM_Ok;
526 }
527
528 if (HeapTupleHeaderGetCmax(tuple) >= curcid)
529 return TM_SelfModified; /* updated after scan started */
530 else
531 return TM_Invisible; /* updated before scan started */
532 }
534 return TM_Invisible;
536 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
538 else
539 {
540 /* it must have aborted or crashed */
541 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
543 return TM_Invisible;
544 }
545 }
546
547 /* by here, the inserting transaction has committed */
548
549 if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */
550 return TM_Ok;
551
552 if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
553 {
555 return TM_Ok;
556 if (!ItemPointerEquals(&htup->t_self, &tuple->t_ctid))
557 return TM_Updated; /* updated by other */
558 else
559 return TM_Deleted; /* deleted by other */
560 }
561
562 if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
563 {
564 TransactionId xmax;
565
567 return TM_Ok;
568
570 {
572 return TM_BeingModified;
573
575 return TM_Ok;
576 }
577
578 xmax = HeapTupleGetUpdateXid(tuple);
579 if (!TransactionIdIsValid(xmax))
580 {
582 return TM_BeingModified;
583 }
584
585 /* not LOCKED_ONLY, so it has to have an xmax */
587
589 {
590 if (HeapTupleHeaderGetCmax(tuple) >= curcid)
591 return TM_SelfModified; /* updated after scan started */
592 else
593 return TM_Invisible; /* updated before scan started */
594 }
595
597 return TM_BeingModified;
598
599 if (TransactionIdDidCommit(xmax))
600 {
601 if (!ItemPointerEquals(&htup->t_self, &tuple->t_ctid))
602 return TM_Updated;
603 else
604 return TM_Deleted;
605 }
606
607 /*
608 * By here, the update in the Xmax is either aborted or crashed, but
609 * what about the other members?
610 */
611
613 {
614 /*
615 * There's no member, even just a locker, alive anymore, so we can
616 * mark the Xmax as invalid.
617 */
618 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
620 return TM_Ok;
621 }
622 else
623 {
624 /* There are lockers running */
625 return TM_BeingModified;
626 }
627 }
628
630 {
632 return TM_BeingModified;
633 if (HeapTupleHeaderGetCmax(tuple) >= curcid)
634 return TM_SelfModified; /* updated after scan started */
635 else
636 return TM_Invisible; /* updated before scan started */
637 }
638
640 return TM_BeingModified;
641
643 {
644 /* it must have aborted or crashed */
645 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
647 return TM_Ok;
648 }
649
650 /* xmax transaction committed */
651
653 {
654 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
656 return TM_Ok;
657 }
658
659 SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
661 if (!ItemPointerEquals(&htup->t_self, &tuple->t_ctid))
662 return TM_Updated; /* updated by other */
663 else
664 return TM_Deleted; /* deleted by other */
665}
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:463
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 1076 of file heapam_visibility.c.

1077{
1078 HeapTupleHeader tuple = htup->t_data;
1079
1081 Assert(htup->t_tableOid != InvalidOid);
1083
1085
1086 /*
1087 * Has inserting transaction committed?
1088 *
1089 * If the inserting transaction aborted, then the tuple was never visible
1090 * to any other transaction, so we can delete it immediately.
1091 */
1092 if (!HeapTupleHeaderXminCommitted(tuple))
1093 {
1094 if (HeapTupleHeaderXminInvalid(tuple))
1095 return HEAPTUPLE_DEAD;
1096 else if (!HeapTupleCleanMoved(tuple, buffer))
1097 return HEAPTUPLE_DEAD;
1099 {
1100 if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
1102 /* only locked? run infomask-only check first, for performance */
1106 /* inserted and then deleted by same xact */
1109 /* deleting subtransaction must have aborted */
1111 }
1113 {
1114 /*
1115 * It'd be possible to discern between INSERT/DELETE in progress
1116 * here by looking at xmax - but that doesn't seem beneficial for
1117 * the majority of callers and even detrimental for some. We'd
1118 * rather have callers look at/wait for xmin than xmax. It's
1119 * always correct to return INSERT_IN_PROGRESS because that's
1120 * what's happening from the view of other backends.
1121 */
1123 }
1125 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
1127 else
1128 {
1129 /*
1130 * Not in Progress, Not Committed, so either Aborted or crashed
1131 */
1132 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
1134 return HEAPTUPLE_DEAD;
1135 }
1136
1137 /*
1138 * At this point the xmin is known committed, but we might not have
1139 * been able to set the hint bit yet; so we can no longer Assert that
1140 * it's set.
1141 */
1142 }
1143
1144 /*
1145 * Okay, the inserter committed, so it was good at some point. Now what
1146 * about the deleting transaction?
1147 */
1148 if (tuple->t_infomask & HEAP_XMAX_INVALID)
1149 return HEAPTUPLE_LIVE;
1150
1152 {
1153 /*
1154 * "Deleting" xact really only locked it, so the tuple is live in any
1155 * case. However, we should make sure that either XMAX_COMMITTED or
1156 * XMAX_INVALID gets set once the xact is gone, to reduce the costs of
1157 * examining the tuple for future xacts.
1158 */
1159 if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED))
1160 {
1161 if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
1162 {
1163 /*
1164 * If it's a pre-pg_upgrade tuple, the multixact cannot
1165 * possibly be running; otherwise have to check.
1166 */
1167 if (!HEAP_LOCKED_UPGRADED(tuple->t_infomask) &&
1169 true))
1170 return HEAPTUPLE_LIVE;
1172 }
1173 else
1174 {
1176 return HEAPTUPLE_LIVE;
1177 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
1179 }
1180 }
1181
1182 /*
1183 * We don't really care whether xmax did commit, abort or crash. We
1184 * know that xmax did lock the tuple, but it did not and will never
1185 * actually update it.
1186 */
1187
1188 return HEAPTUPLE_LIVE;
1189 }
1190
1191 if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
1192 {
1194
1195 /* already checked above */
1197
1198 /* not LOCKED_ONLY, so it has to have an xmax */
1200
1201 if (TransactionIdIsInProgress(xmax))
1203 else if (TransactionIdDidCommit(xmax))
1204 {
1205 /*
1206 * The multixact might still be running due to lockers. Need to
1207 * allow for pruning if below the xid horizon regardless --
1208 * otherwise we could end up with a tuple where the updater has to
1209 * be removed due to the horizon, but is not pruned away. It's
1210 * not a problem to prune that tuple, because any remaining
1211 * lockers will also be present in newer tuple versions.
1212 */
1213 *dead_after = xmax;
1215 }
1216 else if (!MultiXactIdIsRunning(HeapTupleHeaderGetRawXmax(tuple), false))
1217 {
1218 /*
1219 * Not in Progress, Not Committed, so either Aborted or crashed.
1220 * Mark the Xmax as invalid.
1221 */
1223 }
1224
1225 return HEAPTUPLE_LIVE;
1226 }
1227
1228 if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED))
1229 {
1233 SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
1235 else
1236 {
1237 /*
1238 * Not in Progress, Not Committed, so either Aborted or crashed
1239 */
1240 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
1242 return HEAPTUPLE_LIVE;
1243 }
1244
1245 /*
1246 * At this point the xmax is known committed, but we might not have
1247 * been able to set the hint bit yet; so we can no longer Assert that
1248 * it's set.
1249 */
1250 }
1251
1252 /*
1253 * Deleter committed, allow caller to check if it was recent enough that
1254 * some open transactions could still see the tuple.
1255 */
1258}
@ HEAPTUPLE_INSERT_IN_PROGRESS
Definition heapam.h:129
@ HEAPTUPLE_LIVE
Definition heapam.h:127
@ HEAPTUPLE_DELETE_IN_PROGRESS
Definition heapam.h:130
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_prune_satisfies_vacuum(), HeapTupleSatisfiesNonVacuumable(), and HeapTupleSatisfiesVacuum().

◆ HeapTupleSatisfiesVisibility()

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

Definition at line 1655 of file heapam_visibility.c.

1656{
1657 switch (snapshot->snapshot_type)
1658 {
1659 case SNAPSHOT_MVCC:
1660 return HeapTupleSatisfiesMVCC(htup, snapshot, buffer);
1661 case SNAPSHOT_SELF:
1662 return HeapTupleSatisfiesSelf(htup, snapshot, buffer);
1663 case SNAPSHOT_ANY:
1664 return HeapTupleSatisfiesAny(htup, snapshot, buffer);
1665 case SNAPSHOT_TOAST:
1666 return HeapTupleSatisfiesToast(htup, snapshot, buffer);
1667 case SNAPSHOT_DIRTY:
1668 return HeapTupleSatisfiesDirty(htup, snapshot, buffer);
1670 return HeapTupleSatisfiesHistoricMVCC(htup, snapshot, buffer);
1672 return HeapTupleSatisfiesNonVacuumable(htup, snapshot, buffer);
1673 }
1674
1675 return false; /* keep compiler quiet */
1676}
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 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 141 of file heapam_visibility.c.

143{
144 /*
145 * The uses from heapam.c rely on being able to perform the hint bit
146 * updates, which can only be guaranteed if we are holding an exclusive
147 * lock on the buffer - which all callers are doing.
148 */
150
151 SetHintBits(tuple, buffer, infomask, xid);
152}
bool BufferIsLockedByMeInMode(Buffer buffer, BufferLockMode mode)
Definition bufmgr.c:2997
@ BUFFER_LOCK_EXCLUSIVE
Definition bufmgr.h:220

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

Definition at line 114 of file heapam_visibility.c.

116{
117 if (TransactionIdIsValid(xid))
118 {
119 /* NB: xid must be known committed here! */
121
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:4604
XLogRecPtr BufferGetLSNAtomic(Buffer buffer)
Definition bufmgr.c:4634
void MarkBufferDirtyHint(Buffer buffer, bool buffer_std)
Definition bufmgr.c:5565
XLogRecPtr TransactionIdGetCommitLSN(TransactionId xid)
Definition transam.c:318
bool XLogNeedsFlush(XLogRecPtr record)
Definition xlog.c:3145
uint64 XLogRecPtr
Definition xlogdefs.h:21

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

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

◆ TransactionIdInArray()

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

Definition at line 1411 of file heapam_visibility.c.

1412{
1413 return num > 0 &&
1414 bsearch(&xid, xip, num, sizeof(TransactionId), xidComparator) != NULL;
1415}
int xidComparator(const void *arg1, const void *arg2)
Definition xid.c:152

References fb(), and xidComparator().

Referenced by HeapTupleSatisfiesHistoricMVCC().