PostgreSQL Source Code git master
heapam_visibility.c File Reference
#include "postgres.h"
#include "access/heapam.h"
#include "access/htup_details.h"
#include "access/multixact.h"
#include "access/tableam.h"
#include "access/transam.h"
#include "access/xact.h"
#include "access/xlog.h"
#include "storage/bufmgr.h"
#include "storage/procarray.h"
#include "utils/builtins.h"
#include "utils/snapmgr.h"
Include dependency graph for heapam_visibility.c:

Go to the source code of this file.

Functions

static void SetHintBits (HeapTupleHeader tuple, Buffer buffer, uint16 infomask, TransactionId xid)
 
void HeapTupleSetHintBits (HeapTupleHeader tuple, Buffer buffer, uint16 infomask, TransactionId xid)
 
static bool 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)
 
bool HeapTupleSatisfiesVisibility (HeapTuple htup, Snapshot snapshot, Buffer buffer)
 

Function Documentation

◆ HeapTupleCleanMoved()

static bool HeapTupleCleanMoved ( HeapTupleHeader  tuple,
Buffer  buffer 
)
inlinestatic

Definition at line 154 of file heapam_visibility.c.

155{
156 TransactionId xvac;
157
158 /* only used by pre-9.0 binary upgrades */
159 if (likely(!(tuple->t_infomask & (HEAP_MOVED_OFF | HEAP_MOVED_IN))))
160 return true;
161
162 xvac = HeapTupleHeaderGetXvac(tuple);
163
165 elog(ERROR, "encountered tuple with HEAP_MOVED considered current");
166
168 elog(ERROR, "encountered tuple with HEAP_MOVED considered in-progress");
169
170 if (tuple->t_infomask & HEAP_MOVED_OFF)
171 {
172 if (TransactionIdDidCommit(xvac))
173 {
174 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
176 return false;
177 }
178 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
180 }
181 else if (tuple->t_infomask & HEAP_MOVED_IN)
182 {
183 if (TransactionIdDidCommit(xvac))
184 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
186 else
187 {
188 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
190 return false;
191 }
192 }
193
194 return true;
195}
#define likely(x)
Definition: c.h:417
uint32 TransactionId
Definition: c.h:672
#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
Definition: htup_details.h:211
#define HEAP_XMIN_COMMITTED
Definition: htup_details.h:204
static TransactionId HeapTupleHeaderGetXvac(const HeapTupleHeaderData *tup)
Definition: htup_details.h:442
#define HEAP_MOVED_IN
Definition: htup_details.h:212
#define HEAP_XMIN_INVALID
Definition: htup_details.h:205
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, 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 1358 of file heapam_visibility.c.

1359{
1360 TransactionId xmax;
1361
1362 /* if there's no valid Xmax, then there's obviously no update either */
1363 if (tuple->t_infomask & HEAP_XMAX_INVALID)
1364 return true;
1365
1366 if (tuple->t_infomask & HEAP_XMAX_LOCK_ONLY)
1367 return true;
1368
1369 /* invalid xmax means no update */
1371 return true;
1372
1373 /*
1374 * if HEAP_XMAX_LOCK_ONLY is not set and not a multi, then this must
1375 * necessarily have been updated
1376 */
1377 if (!(tuple->t_infomask & HEAP_XMAX_IS_MULTI))
1378 return false;
1379
1380 /* ... but if it's a multi, then perhaps the updating Xid aborted. */
1381 xmax = HeapTupleGetUpdateXid(tuple);
1382
1383 /* not LOCKED_ONLY, so it has to have an xmax */
1385
1387 return false;
1388 if (TransactionIdIsInProgress(xmax))
1389 return false;
1390 if (TransactionIdDidCommit(xmax))
1391 return false;
1392
1393 /*
1394 * not current, not in progress, not committed -- must have aborted or
1395 * crashed
1396 */
1397 return true;
1398}
Assert(PointerIsAligned(start, uint64))
TransactionId HeapTupleGetUpdateXid(const HeapTupleHeaderData *tup)
Definition: heapam.c:7624
#define HEAP_XMAX_LOCK_ONLY
Definition: htup_details.h:197
static TransactionId HeapTupleHeaderGetRawXmax(const HeapTupleHeaderData *tup)
Definition: htup_details.h:377
#define HEAP_XMAX_IS_MULTI
Definition: htup_details.h:209
#define HEAP_XMAX_INVALID
Definition: htup_details.h:208
#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 1303 of file heapam_visibility.c.

1304{
1305 HeapTupleHeader tuple = htup->t_data;
1306
1308 Assert(htup->t_tableOid != InvalidOid);
1309
1310 /*
1311 * If the inserting transaction is marked invalid, then it aborted, and
1312 * the tuple is definitely dead. If it's marked neither committed nor
1313 * invalid, then we assume it's still alive (since the presumption is that
1314 * all relevant hint bits were just set moments ago).
1315 */
1316 if (!HeapTupleHeaderXminCommitted(tuple))
1317 return HeapTupleHeaderXminInvalid(tuple);
1318
1319 /*
1320 * If the inserting transaction committed, but any deleting transaction
1321 * aborted, the tuple is still alive.
1322 */
1323 if (tuple->t_infomask & HEAP_XMAX_INVALID)
1324 return false;
1325
1326 /*
1327 * If the XMAX is just a lock, the tuple is still alive.
1328 */
1330 return false;
1331
1332 /*
1333 * If the Xmax is a MultiXact, it might be dead or alive, but we cannot
1334 * know without checking pg_multixact.
1335 */
1336 if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
1337 return false;
1338
1339 /* If deleter isn't known to have committed, assume it's still running. */
1340 if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED))
1341 return false;
1342
1343 /* Deleter committed, so tuple is dead if the XID is old enough. */
1344 return GlobalVisTestIsRemovableXid(vistest,
1346}
static bool HEAP_XMAX_IS_LOCKED_ONLY(uint16 infomask)
Definition: htup_details.h:226
static bool HeapTupleHeaderXminInvalid(const HeapTupleHeaderData *tup)
Definition: htup_details.h:343
#define HEAP_XMAX_COMMITTED
Definition: htup_details.h:207
static bool HeapTupleHeaderXminCommitted(const HeapTupleHeaderData *tup)
Definition: htup_details.h:337
static bool ItemPointerIsValid(const ItemPointerData *pointer)
Definition: itemptr.h:83
#define InvalidOid
Definition: postgres_ext.h:37
bool GlobalVisTestIsRemovableXid(GlobalVisState *state, TransactionId xid)
Definition: procarray.c: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 352 of file heapam_visibility.c.

353{
354 return true;
355}

Referenced by HeapTupleSatisfiesVisibility().

◆ HeapTupleSatisfiesDirty()

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

Definition at line 681 of file heapam_visibility.c.

683{
684 HeapTupleHeader tuple = htup->t_data;
685
687 Assert(htup->t_tableOid != InvalidOid);
688
689 snapshot->xmin = snapshot->xmax = InvalidTransactionId;
690 snapshot->speculativeToken = 0;
691
693 {
695 return false;
696
697 if (!HeapTupleCleanMoved(tuple, buffer))
698 return false;
700 {
701 if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
702 return true;
703
704 if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask)) /* not deleter */
705 return true;
706
707 if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
708 {
709 TransactionId xmax;
710
711 xmax = HeapTupleGetUpdateXid(tuple);
712
713 /* not LOCKED_ONLY, so it has to have an xmax */
715
716 /* updating subtransaction must have aborted */
718 return true;
719 else
720 return false;
721 }
722
724 {
725 /* deleting subtransaction must have aborted */
726 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
728 return true;
729 }
730
731 return false;
732 }
734 {
735 /*
736 * Return the speculative token to caller. Caller can worry about
737 * xmax, since it requires a conclusively locked row version, and
738 * a concurrent update to this tuple is a conflict of its
739 * purposes.
740 */
742 {
743 snapshot->speculativeToken =
745
746 Assert(snapshot->speculativeToken != 0);
747 }
748
749 snapshot->xmin = HeapTupleHeaderGetRawXmin(tuple);
750 /* XXX shouldn't we fall through to look at xmax? */
751 return true; /* in insertion by other */
752 }
754 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
756 else
757 {
758 /* it must have aborted or crashed */
759 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
761 return false;
762 }
763 }
764
765 /* by here, the inserting transaction has committed */
766
767 if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */
768 return true;
769
770 if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
771 {
773 return true;
774 return false; /* updated by other */
775 }
776
777 if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
778 {
779 TransactionId xmax;
780
782 return true;
783
784 xmax = HeapTupleGetUpdateXid(tuple);
785
786 /* not LOCKED_ONLY, so it has to have an xmax */
788
790 return false;
792 {
793 snapshot->xmax = xmax;
794 return true;
795 }
796 if (TransactionIdDidCommit(xmax))
797 return false;
798 /* it must have aborted or crashed */
799 return true;
800 }
801
803 {
805 return true;
806 return false;
807 }
808
810 {
812 snapshot->xmax = HeapTupleHeaderGetRawXmax(tuple);
813 return true;
814 }
815
817 {
818 /* it must have aborted or crashed */
819 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
821 return true;
822 }
823
824 /* xmax transaction committed */
825
827 {
828 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
830 return true;
831 }
832
833 SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
835 return false; /* updated by other */
836}
static bool HeapTupleCleanMoved(HeapTupleHeader tuple, Buffer buffer)
static BlockNumber HeapTupleHeaderGetSpeculativeToken(const HeapTupleHeaderData *tup)
Definition: htup_details.h:467
static TransactionId HeapTupleHeaderGetRawXmin(const HeapTupleHeaderData *tup)
Definition: htup_details.h:318
static bool HeapTupleHeaderIsSpeculative(const HeapTupleHeaderData *tup)
Definition: htup_details.h:461
TransactionId xmin
Definition: snapshot.h:153
TransactionId xmax
Definition: snapshot.h:154
uint32 speculativeToken
Definition: snapshot.h:189

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

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

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

◆ HeapTupleSatisfiesNonVacuumable()

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

Definition at line 1267 of file heapam_visibility.c.

1269{
1271 HTSV_Result res;
1272
1273 res = HeapTupleSatisfiesVacuumHorizon(htup, buffer, &dead_after);
1274
1275 if (res == HEAPTUPLE_RECENTLY_DEAD)
1276 {
1277 Assert(TransactionIdIsValid(dead_after));
1278
1279 if (GlobalVisTestIsRemovableXid(snapshot->vistest, dead_after))
1280 res = HEAPTUPLE_DEAD;
1281 }
1282 else
1283 Assert(!TransactionIdIsValid(dead_after));
1284
1285 return res != HEAPTUPLE_DEAD;
1286}
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(), 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 219 of file heapam_visibility.c.

220{
221 HeapTupleHeader tuple = htup->t_data;
222
224 Assert(htup->t_tableOid != InvalidOid);
225
227 {
229 return false;
230
231 if (!HeapTupleCleanMoved(tuple, buffer))
232 return false;
234 {
235 if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
236 return true;
237
238 if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask)) /* not deleter */
239 return true;
240
241 if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
242 {
243 TransactionId xmax;
244
245 xmax = HeapTupleGetUpdateXid(tuple);
246
247 /* not LOCKED_ONLY, so it has to have an xmax */
249
250 /* updating subtransaction must have aborted */
252 return true;
253 else
254 return false;
255 }
256
258 {
259 /* deleting subtransaction must have aborted */
260 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
262 return true;
263 }
264
265 return false;
266 }
268 return false;
270 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
272 else
273 {
274 /* it must have aborted or crashed */
275 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
277 return false;
278 }
279 }
280
281 /* by here, the inserting transaction has committed */
282
283 if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */
284 return true;
285
286 if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
287 {
289 return true;
290 return false; /* updated by other */
291 }
292
293 if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
294 {
295 TransactionId xmax;
296
298 return true;
299
300 xmax = HeapTupleGetUpdateXid(tuple);
301
302 /* not LOCKED_ONLY, so it has to have an xmax */
304
306 return false;
308 return true;
309 if (TransactionIdDidCommit(xmax))
310 return false;
311 /* it must have aborted or crashed */
312 return true;
313 }
314
316 {
318 return true;
319 return false;
320 }
321
323 return true;
324
326 {
327 /* it must have aborted or crashed */
328 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
330 return true;
331 }
332
333 /* xmax transaction committed */
334
336 {
337 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
339 return true;
340 }
341
342 SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
344 return false;
345}

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

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

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

435{
436 HeapTupleHeader tuple = htup->t_data;
437
439 Assert(htup->t_tableOid != InvalidOid);
440
442 {
444 return TM_Invisible;
445
446 else if (!HeapTupleCleanMoved(tuple, buffer))
447 return TM_Invisible;
449 {
450 if (HeapTupleHeaderGetCmin(tuple) >= curcid)
451 return TM_Invisible; /* inserted after scan started */
452
453 if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */
454 return TM_Ok;
455
457 {
458 TransactionId xmax;
459
460 xmax = HeapTupleHeaderGetRawXmax(tuple);
461
462 /*
463 * Careful here: even though this tuple was created by our own
464 * transaction, it might be locked by other transactions, if
465 * the original version was key-share locked when we updated
466 * it.
467 */
468
469 if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
470 {
471 if (MultiXactIdIsRunning(xmax, true))
472 return TM_BeingModified;
473 else
474 return TM_Ok;
475 }
476
477 /*
478 * If the locker is gone, then there is nothing of interest
479 * left in this Xmax; otherwise, report the tuple as
480 * locked/updated.
481 */
482 if (!TransactionIdIsInProgress(xmax))
483 return TM_Ok;
484 return TM_BeingModified;
485 }
486
487 if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
488 {
489 TransactionId xmax;
490
491 xmax = HeapTupleGetUpdateXid(tuple);
492
493 /* not LOCKED_ONLY, so it has to have an xmax */
495
496 /* deleting subtransaction must have aborted */
498 {
500 false))
501 return TM_BeingModified;
502 return TM_Ok;
503 }
504 else
505 {
506 if (HeapTupleHeaderGetCmax(tuple) >= curcid)
507 return TM_SelfModified; /* updated after scan started */
508 else
509 return TM_Invisible; /* updated before scan started */
510 }
511 }
512
514 {
515 /* deleting subtransaction must have aborted */
516 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
518 return TM_Ok;
519 }
520
521 if (HeapTupleHeaderGetCmax(tuple) >= curcid)
522 return TM_SelfModified; /* updated after scan started */
523 else
524 return TM_Invisible; /* updated before scan started */
525 }
527 return TM_Invisible;
529 SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
531 else
532 {
533 /* it must have aborted or crashed */
534 SetHintBits(tuple, buffer, HEAP_XMIN_INVALID,
536 return TM_Invisible;
537 }
538 }
539
540 /* by here, the inserting transaction has committed */
541
542 if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */
543 return TM_Ok;
544
545 if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
546 {
548 return TM_Ok;
549 if (!ItemPointerEquals(&htup->t_self, &tuple->t_ctid))
550 return TM_Updated; /* updated by other */
551 else
552 return TM_Deleted; /* deleted by other */
553 }
554
555 if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
556 {
557 TransactionId xmax;
558
560 return TM_Ok;
561
563 {
565 return TM_BeingModified;
566
568 return TM_Ok;
569 }
570
571 xmax = HeapTupleGetUpdateXid(tuple);
572 if (!TransactionIdIsValid(xmax))
573 {
575 return TM_BeingModified;
576 }
577
578 /* not LOCKED_ONLY, so it has to have an xmax */
580
582 {
583 if (HeapTupleHeaderGetCmax(tuple) >= curcid)
584 return TM_SelfModified; /* updated after scan started */
585 else
586 return TM_Invisible; /* updated before scan started */
587 }
588
590 return TM_BeingModified;
591
592 if (TransactionIdDidCommit(xmax))
593 {
594 if (!ItemPointerEquals(&htup->t_self, &tuple->t_ctid))
595 return TM_Updated;
596 else
597 return TM_Deleted;
598 }
599
600 /*
601 * By here, the update in the Xmax is either aborted or crashed, but
602 * what about the other members?
603 */
604
606 {
607 /*
608 * There's no member, even just a locker, alive anymore, so we can
609 * mark the Xmax as invalid.
610 */
611 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
613 return TM_Ok;
614 }
615 else
616 {
617 /* There are lockers running */
618 return TM_BeingModified;
619 }
620 }
621
623 {
625 return TM_BeingModified;
626 if (HeapTupleHeaderGetCmax(tuple) >= curcid)
627 return TM_SelfModified; /* updated after scan started */
628 else
629 return TM_Invisible; /* updated before scan started */
630 }
631
633 return TM_BeingModified;
634
636 {
637 /* it must have aborted or crashed */
638 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
640 return TM_Ok;
641 }
642
643 /* xmax transaction committed */
644
646 {
647 SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
649 return TM_Ok;
650 }
651
652 SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
654 if (!ItemPointerEquals(&htup->t_self, &tuple->t_ctid))
655 return TM_Updated; /* updated by other */
656 else
657 return TM_Deleted; /* deleted by other */
658}
static bool HEAP_LOCKED_UPGRADED(uint16 infomask)
Definition: htup_details.h:251
bool ItemPointerEquals(const ItemPointerData *pointer1, const ItemPointerData *pointer2)
Definition: itemptr.c:35
bool MultiXactIdIsRunning(MultiXactId multi, bool isLockOnly)
Definition: multixact.c:465
ItemPointerData t_ctid
Definition: htup_details.h:161
@ 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 1069 of file heapam_visibility.c.

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

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

1606{
1607 switch (snapshot->snapshot_type)
1608 {
1609 case SNAPSHOT_MVCC:
1610 return HeapTupleSatisfiesMVCC(htup, snapshot, buffer);
1611 case SNAPSHOT_SELF:
1612 return HeapTupleSatisfiesSelf(htup, snapshot, buffer);
1613 case SNAPSHOT_ANY:
1614 return HeapTupleSatisfiesAny(htup, snapshot, buffer);
1615 case SNAPSHOT_TOAST:
1616 return HeapTupleSatisfiesToast(htup, snapshot, buffer);
1617 case SNAPSHOT_DIRTY:
1618 return HeapTupleSatisfiesDirty(htup, snapshot, buffer);
1620 return HeapTupleSatisfiesHistoricMVCC(htup, snapshot, buffer);
1622 return HeapTupleSatisfiesNonVacuumable(htup, snapshot, buffer);
1623 }
1624
1625 return false; /* keep compiler quiet */
1626}
static bool HeapTupleSatisfiesAny(HeapTuple htup, Snapshot snapshot, Buffer buffer)
static bool HeapTupleSatisfiesNonVacuumable(HeapTuple htup, Snapshot snapshot, Buffer buffer)
static bool HeapTupleSatisfiesToast(HeapTuple htup, Snapshot snapshot, Buffer buffer)
static bool HeapTupleSatisfiesDirty(HeapTuple htup, Snapshot snapshot, Buffer buffer)
static bool HeapTupleSatisfiesMVCC(HeapTuple htup, Snapshot snapshot, Buffer buffer)
static bool HeapTupleSatisfiesSelf(HeapTuple htup, Snapshot snapshot, Buffer buffer)
static bool HeapTupleSatisfiesHistoricMVCC(HeapTuple htup, Snapshot snapshot, Buffer buffer)
@ SNAPSHOT_TOAST
Definition: snapshot.h:70
@ SNAPSHOT_SELF
Definition: snapshot.h:60
@ SNAPSHOT_NON_VACUUMABLE
Definition: snapshot.h:114
@ SNAPSHOT_MVCC
Definition: snapshot.h:46
@ SNAPSHOT_ANY
Definition: snapshot.h:65
@ SNAPSHOT_HISTORIC_MVCC
Definition: snapshot.h:105
@ SNAPSHOT_DIRTY
Definition: snapshot.h:98
SnapshotType snapshot_type
Definition: snapshot.h:140

References HeapTupleSatisfiesAny(), HeapTupleSatisfiesDirty(), HeapTupleSatisfiesHistoricMVCC(), HeapTupleSatisfiesMVCC(), HeapTupleSatisfiesNonVacuumable(), HeapTupleSatisfiesSelf(), HeapTupleSatisfiesToast(), SNAPSHOT_ANY, SNAPSHOT_DIRTY, SNAPSHOT_HISTORIC_MVCC, SNAPSHOT_MVCC, SNAPSHOT_NON_VACUUMABLE, SNAPSHOT_SELF, SNAPSHOT_TOAST, and SnapshotData::snapshot_type.

Referenced by BitmapHeapScanNextBlock(), heap_delete(), heap_fetch(), heap_get_latest_tid(), heap_hot_search_buffer(), heap_update(), heapam_tuple_satisfies_snapshot(), heapgettup(), page_collect_tuples(), pgstat_heap(), SampleHeapTupleVisible(), and ScanSourceDatabasePgClassPage().

◆ HeapTupleSetHintBits()

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

Definition at line 141 of file heapam_visibility.c.

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

References SetHintBits().

Referenced by UpdateXmaxHintBits().

◆ SetHintBits()

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

Definition at line 114 of file heapam_visibility.c.

116{
117 if (TransactionIdIsValid(xid))
118 {
119 /* NB: xid must be known committed here! */
120 XLogRecPtr commitLSN = TransactionIdGetCommitLSN(xid);
121
122 if (BufferIsPermanent(buffer) && XLogNeedsFlush(commitLSN) &&
123 BufferGetLSNAtomic(buffer) < commitLSN)
124 {
125 /* not flushed and no LSN interlock, so don't set hint */
126 return;
127 }
128 }
129
130 tuple->t_infomask |= infomask;
131 MarkBufferDirtyHint(buffer, true);
132}
bool BufferIsPermanent(Buffer buffer)
Definition: bufmgr.c:4564
XLogRecPtr BufferGetLSNAtomic(Buffer buffer)
Definition: bufmgr.c:4594
void MarkBufferDirtyHint(Buffer buffer, bool buffer_std)
Definition: bufmgr.c:5525
XLogRecPtr TransactionIdGetCommitLSN(TransactionId xid)
Definition: transam.c:318
bool XLogNeedsFlush(XLogRecPtr record)
Definition: xlog.c:3146
uint64 XLogRecPtr
Definition: xlogdefs.h:21

References BufferGetLSNAtomic(), BufferIsPermanent(), 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 1404 of file heapam_visibility.c.

1405{
1406 return num > 0 &&
1407 bsearch(&xid, xip, num, sizeof(TransactionId), xidComparator) != NULL;
1408}
int xidComparator(const void *arg1, const void *arg2)
Definition: xid.c:152

References xidComparator().

Referenced by HeapTupleSatisfiesHistoricMVCC().