PostgreSQL Source Code  git master
heapam.h File Reference
#include "access/relation.h"
#include "access/relscan.h"
#include "access/sdir.h"
#include "access/skey.h"
#include "access/table.h"
#include "access/tableam.h"
#include "nodes/lockoptions.h"
#include "nodes/primnodes.h"
#include "storage/bufpage.h"
#include "storage/lockdefs.h"
#include "utils/relcache.h"
#include "utils/snapshot.h"
Include dependency graph for heapam.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  HeapScanDescData
 
struct  IndexFetchHeapData
 

Macros

#define HEAP_INSERT_SKIP_WAL   TABLE_INSERT_SKIP_WAL
 
#define HEAP_INSERT_SKIP_FSM   TABLE_INSERT_SKIP_FSM
 
#define HEAP_INSERT_FROZEN   TABLE_INSERT_FROZEN
 
#define HEAP_INSERT_NO_LOGICAL   TABLE_INSERT_NO_LOGICAL
 
#define HEAP_INSERT_SPECULATIVE   0x0010
 
#define MaxLockTupleMode   LockTupleExclusive
 
#define HeapScanIsValid(scan)   PointerIsValid(scan)
 

Typedefs

typedef struct BulkInsertStateDataBulkInsertState
 
typedef struct HeapScanDescData HeapScanDescData
 
typedef struct HeapScanDescDataHeapScanDesc
 
typedef struct IndexFetchHeapData IndexFetchHeapData
 

Enumerations

enum  HTSV_Result {
  HEAPTUPLE_DEAD, HEAPTUPLE_LIVE, HEAPTUPLE_RECENTLY_DEAD, HEAPTUPLE_INSERT_IN_PROGRESS,
  HEAPTUPLE_DELETE_IN_PROGRESS
}
 

Functions

TableScanDesc heap_beginscan (Relation relation, Snapshot snapshot, int nkeys, ScanKey key, ParallelTableScanDesc parallel_scan, uint32 flags)
 
void heap_setscanlimits (TableScanDesc scan, BlockNumber startBlk, BlockNumber numBlks)
 
void heapgetpage (TableScanDesc scan, BlockNumber page)
 
void heap_rescan (TableScanDesc scan, ScanKey key, bool set_params, bool allow_strat, bool allow_sync, bool allow_pagemode)
 
void heap_endscan (TableScanDesc scan)
 
HeapTuple heap_getnext (TableScanDesc scan, ScanDirection direction)
 
bool heap_getnextslot (TableScanDesc sscan, ScanDirection direction, struct TupleTableSlot *slot)
 
bool heap_fetch (Relation relation, Snapshot snapshot, HeapTuple tuple, Buffer *userbuf)
 
bool heap_hot_search_buffer (ItemPointer tid, Relation relation, Buffer buffer, Snapshot snapshot, HeapTuple heapTuple, bool *all_dead, bool first_call)
 
void heap_get_latest_tid (TableScanDesc scan, ItemPointer tid)
 
void setLastTid (const ItemPointer tid)
 
BulkInsertState GetBulkInsertState (void)
 
void FreeBulkInsertState (BulkInsertState)
 
void ReleaseBulkInsertStatePin (BulkInsertState bistate)
 
void heap_insert (Relation relation, HeapTuple tup, CommandId cid, int options, BulkInsertState bistate)
 
void heap_multi_insert (Relation relation, struct TupleTableSlot **slots, int ntuples, CommandId cid, int options, BulkInsertState bistate)
 
TM_Result heap_delete (Relation relation, ItemPointer tid, CommandId cid, Snapshot crosscheck, bool wait, struct TM_FailureData *tmfd, bool changingPart)
 
void heap_finish_speculative (Relation relation, ItemPointer tid)
 
void heap_abort_speculative (Relation relation, ItemPointer tid)
 
TM_Result heap_update (Relation relation, ItemPointer otid, HeapTuple newtup, CommandId cid, Snapshot crosscheck, bool wait, struct TM_FailureData *tmfd, LockTupleMode *lockmode)
 
TM_Result heap_lock_tuple (Relation relation, HeapTuple tuple, CommandId cid, LockTupleMode mode, LockWaitPolicy wait_policy, bool follow_update, Buffer *buffer, struct TM_FailureData *tmfd)
 
void heap_inplace_update (Relation relation, HeapTuple tuple)
 
bool heap_freeze_tuple (HeapTupleHeader tuple, TransactionId relfrozenxid, TransactionId relminmxid, TransactionId cutoff_xid, TransactionId cutoff_multi)
 
bool heap_tuple_needs_freeze (HeapTupleHeader tuple, TransactionId cutoff_xid, MultiXactId cutoff_multi, Buffer buf)
 
bool heap_tuple_needs_eventual_freeze (HeapTupleHeader tuple)
 
void simple_heap_insert (Relation relation, HeapTuple tup)
 
void simple_heap_delete (Relation relation, ItemPointer tid)
 
void simple_heap_update (Relation relation, ItemPointer otid, HeapTuple tup)
 
void heap_sync (Relation relation)
 
TransactionId heap_compute_xid_horizon_for_tuples (Relation rel, ItemPointerData *items, int nitems)
 
void heap_page_prune_opt (Relation relation, Buffer buffer)
 
int heap_page_prune (Relation relation, Buffer buffer, TransactionId OldestXmin, bool report_stats, TransactionId *latestRemovedXid)
 
void heap_page_prune_execute (Buffer buffer, OffsetNumber *redirected, int nredirected, OffsetNumber *nowdead, int ndead, OffsetNumber *nowunused, int nunused)
 
void heap_get_root_tuples (Page page, OffsetNumber *root_offsets)
 
void ss_report_location (Relation rel, BlockNumber location)
 
BlockNumber ss_get_location (Relation rel, BlockNumber relnblocks)
 
void SyncScanShmemInit (void)
 
Size SyncScanShmemSize (void)
 
void heap_vacuum_rel (Relation onerel, struct VacuumParams *params, BufferAccessStrategy bstrategy)
 
bool HeapTupleSatisfiesVisibility (HeapTuple stup, Snapshot snapshot, Buffer buffer)
 
TM_Result HeapTupleSatisfiesUpdate (HeapTuple stup, CommandId curcid, Buffer buffer)
 
HTSV_Result HeapTupleSatisfiesVacuum (HeapTuple stup, TransactionId OldestXmin, Buffer buffer)
 
void HeapTupleSetHintBits (HeapTupleHeader tuple, Buffer buffer, uint16 infomask, TransactionId xid)
 
bool HeapTupleHeaderIsOnlyLocked (HeapTupleHeader tuple)
 
bool XidInMVCCSnapshot (TransactionId xid, Snapshot snapshot)
 
bool HeapTupleIsSurelyDead (HeapTuple htup, TransactionId OldestXmin)
 
bool ResolveCminCmaxDuringDecoding (struct HTAB *tuplecid_data, Snapshot snapshot, HeapTuple htup, Buffer buffer, CommandId *cmin, CommandId *cmax)
 

Macro Definition Documentation

◆ HEAP_INSERT_FROZEN

#define HEAP_INSERT_FROZEN   TABLE_INSERT_FROZEN

Definition at line 34 of file heapam.h.

Referenced by heap_prepare_insert().

◆ HEAP_INSERT_NO_LOGICAL

#define HEAP_INSERT_NO_LOGICAL   TABLE_INSERT_NO_LOGICAL

Definition at line 35 of file heapam.h.

Referenced by heap_insert(), heap_multi_insert(), and raw_heap_insert().

◆ HEAP_INSERT_SKIP_FSM

#define HEAP_INSERT_SKIP_FSM   TABLE_INSERT_SKIP_FSM

Definition at line 33 of file heapam.h.

Referenced by raw_heap_insert(), and RelationGetBufferForTuple().

◆ HEAP_INSERT_SKIP_WAL

#define HEAP_INSERT_SKIP_WAL   TABLE_INSERT_SKIP_WAL

◆ HEAP_INSERT_SPECULATIVE

#define HEAP_INSERT_SPECULATIVE   0x0010

◆ HeapScanIsValid

#define HeapScanIsValid (   scan)    PointerIsValid(scan)

Definition at line 108 of file heapam.h.

◆ MaxLockTupleMode

#define MaxLockTupleMode   LockTupleExclusive

Definition at line 41 of file heapam.h.

Typedef Documentation

◆ BulkInsertState

Definition at line 38 of file heapam.h.

◆ HeapScanDesc

typedef struct HeapScanDescData* HeapScanDesc

Definition at line 72 of file heapam.h.

◆ HeapScanDescData

◆ IndexFetchHeapData

Enumeration Type Documentation

◆ HTSV_Result

Enumerator
HEAPTUPLE_DEAD 
HEAPTUPLE_LIVE 
HEAPTUPLE_RECENTLY_DEAD 
HEAPTUPLE_INSERT_IN_PROGRESS 
HEAPTUPLE_DELETE_IN_PROGRESS 

Definition at line 86 of file heapam.h.

87 {
88  HEAPTUPLE_DEAD, /* tuple is dead and deletable */
89  HEAPTUPLE_LIVE, /* tuple is live (committed, no deleter) */
90  HEAPTUPLE_RECENTLY_DEAD, /* tuple is dead, but not deletable yet */
91  HEAPTUPLE_INSERT_IN_PROGRESS, /* inserting xact is still in progress */
92  HEAPTUPLE_DELETE_IN_PROGRESS /* deleting xact is still in progress */
93 } HTSV_Result;
HTSV_Result
Definition: heapam.h:86

Function Documentation

◆ FreeBulkInsertState()

void FreeBulkInsertState ( BulkInsertState  )

Definition at line 1829 of file heapam.c.

References BulkInsertStateData::current_buf, FreeAccessStrategy(), InvalidBuffer, pfree(), ReleaseBuffer(), and BulkInsertStateData::strategy.

Referenced by ATRewriteTable(), CopyFrom(), CopyMultiInsertBufferCleanup(), intorel_shutdown(), and transientrel_shutdown().

1830 {
1831  if (bistate->current_buf != InvalidBuffer)
1832  ReleaseBuffer(bistate->current_buf);
1833  FreeAccessStrategy(bistate->strategy);
1834  pfree(bistate);
1835 }
#define InvalidBuffer
Definition: buf.h:25
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3365
void pfree(void *pointer)
Definition: mcxt.c:1056
void FreeAccessStrategy(BufferAccessStrategy strategy)
Definition: freelist.c:597

◆ GetBulkInsertState()

BulkInsertState GetBulkInsertState ( void  )

Definition at line 1815 of file heapam.c.

References BAS_BULKWRITE, BulkInsertStateData::current_buf, GetAccessStrategy(), InvalidBuffer, palloc(), and BulkInsertStateData::strategy.

Referenced by ATRewriteTable(), CopyFrom(), CopyMultiInsertBufferInit(), intorel_startup(), and transientrel_startup().

1816 {
1817  BulkInsertState bistate;
1818 
1819  bistate = (BulkInsertState) palloc(sizeof(BulkInsertStateData));
1821  bistate->current_buf = InvalidBuffer;
1822  return bistate;
1823 }
BufferAccessStrategy GetAccessStrategy(BufferAccessStrategyType btype)
Definition: freelist.c:542
#define InvalidBuffer
Definition: buf.h:25
struct BulkInsertStateData * BulkInsertState
Definition: heapam.h:38
BufferAccessStrategy strategy
Definition: hio.h:32
void * palloc(Size size)
Definition: mcxt.c:949
Buffer current_buf
Definition: hio.h:33

◆ heap_abort_speculative()

void heap_abort_speculative ( Relation  relation,
ItemPointer  tid 
)

Definition at line 5567 of file heapam.c.

References Assert, BUFFER_LOCK_EXCLUSIVE, BUFFER_LOCK_UNLOCK, BufferGetPage, compute_infobits(), elog, END_CRIT_SECTION, ERROR, xl_heap_delete::flags, GetCurrentTransactionId(), HEAP_KEYS_UPDATED, HEAP_MOVED, heap_toast_delete(), HEAP_XMAX_BITS, HeapTupleHasExternal, HeapTupleHeaderIsHeapOnly, HeapTupleHeaderIsSpeculative, HeapTupleHeaderSetXmin, xl_heap_delete::infobits_set, InvalidTransactionId, IsToastRelation(), ItemIdGetLength, ItemIdIsNormal, ItemPointerGetBlockNumber, ItemPointerGetOffsetNumber, ItemPointerIsValid, LockBuffer(), MarkBufferDirty(), xl_heap_delete::offnum, PageGetItem, PageGetItemId, PageIsAllVisible, PageSetLSN, PageSetPrunable, pgstat_count_heap_delete(), ReadBuffer(), RecentGlobalXmin, REGBUF_STANDARD, RelationGetRelid, RelationNeedsWAL, ReleaseBuffer(), SizeOfHeapDelete, START_CRIT_SECTION, HeapTupleHeaderData::t_choice, HeapTupleHeaderData::t_ctid, HeapTupleData::t_data, HeapTupleHeaderData::t_heap, HeapTupleHeaderData::t_infomask, HeapTupleHeaderData::t_infomask2, HeapTupleData::t_len, HeapTupleData::t_self, HeapTupleData::t_tableOid, HeapTupleFields::t_xmin, TransactionIdIsValid, XLH_DELETE_IS_SUPER, XLOG_HEAP_DELETE, XLogBeginInsert(), XLogInsert(), XLogRegisterBuffer(), XLogRegisterData(), and xl_heap_delete::xmax.

Referenced by heapam_tuple_complete_speculative(), and toast_delete_datum().

5568 {
5570  ItemId lp;
5571  HeapTupleData tp;
5572  Page page;
5573  BlockNumber block;
5574  Buffer buffer;
5575 
5576  Assert(ItemPointerIsValid(tid));
5577 
5578  block = ItemPointerGetBlockNumber(tid);
5579  buffer = ReadBuffer(relation, block);
5580  page = BufferGetPage(buffer);
5581 
5583 
5584  /*
5585  * Page can't be all visible, we just inserted into it, and are still
5586  * running.
5587  */
5588  Assert(!PageIsAllVisible(page));
5589 
5590  lp = PageGetItemId(page, ItemPointerGetOffsetNumber(tid));
5591  Assert(ItemIdIsNormal(lp));
5592 
5593  tp.t_tableOid = RelationGetRelid(relation);
5594  tp.t_data = (HeapTupleHeader) PageGetItem(page, lp);
5595  tp.t_len = ItemIdGetLength(lp);
5596  tp.t_self = *tid;
5597 
5598  /*
5599  * Sanity check that the tuple really is a speculatively inserted tuple,
5600  * inserted by us.
5601  */
5602  if (tp.t_data->t_choice.t_heap.t_xmin != xid)
5603  elog(ERROR, "attempted to kill a tuple inserted by another transaction");
5604  if (!(IsToastRelation(relation) || HeapTupleHeaderIsSpeculative(tp.t_data)))
5605  elog(ERROR, "attempted to kill a non-speculative tuple");
5607 
5608  /*
5609  * No need to check for serializable conflicts here. There is never a
5610  * need for a combocid, either. No need to extract replica identity, or
5611  * do anything special with infomask bits.
5612  */
5613 
5615 
5616  /*
5617  * The tuple will become DEAD immediately. Flag that this page
5618  * immediately is a candidate for pruning by setting xmin to
5619  * RecentGlobalXmin. That's not pretty, but it doesn't seem worth
5620  * inventing a nicer API for this.
5621  */
5624 
5625  /* store transaction information of xact deleting the tuple */
5628 
5629  /*
5630  * Set the tuple header xmin to InvalidTransactionId. This makes the
5631  * tuple immediately invisible everyone. (In particular, to any
5632  * transactions waiting on the speculative token, woken up later.)
5633  */
5635 
5636  /* Clear the speculative insertion token too */
5637  tp.t_data->t_ctid = tp.t_self;
5638 
5639  MarkBufferDirty(buffer);
5640 
5641  /*
5642  * XLOG stuff
5643  *
5644  * The WAL records generated here match heap_delete(). The same recovery
5645  * routines are used.
5646  */
5647  if (RelationNeedsWAL(relation))
5648  {
5649  xl_heap_delete xlrec;
5650  XLogRecPtr recptr;
5651 
5652  xlrec.flags = XLH_DELETE_IS_SUPER;
5654  tp.t_data->t_infomask2);
5656  xlrec.xmax = xid;
5657 
5658  XLogBeginInsert();
5659  XLogRegisterData((char *) &xlrec, SizeOfHeapDelete);
5660  XLogRegisterBuffer(0, buffer, REGBUF_STANDARD);
5661 
5662  /* No replica identity & replication origin logged */
5663 
5664  recptr = XLogInsert(RM_HEAP_ID, XLOG_HEAP_DELETE);
5665 
5666  PageSetLSN(page, recptr);
5667  }
5668 
5669  END_CRIT_SECTION();
5670 
5671  LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
5672 
5673  if (HeapTupleHasExternal(&tp))
5674  {
5675  Assert(!IsToastRelation(relation));
5676  heap_toast_delete(relation, &tp, true);
5677  }
5678 
5679  /*
5680  * Never need to mark tuple for invalidation, since catalogs don't support
5681  * speculative insertion
5682  */
5683 
5684  /* Now we can release the buffer */
5685  ReleaseBuffer(buffer);
5686 
5687  /* count deletion, as we counted the insertion too */
5688  pgstat_count_heap_delete(relation);
5689 }
#define ItemPointerIsValid(pointer)
Definition: itemptr.h:82
#define BUFFER_LOCK_UNLOCK
Definition: bufmgr.h:86
bool IsToastRelation(Relation relation)
Definition: catalog.c:142
#define HEAP_XMAX_BITS
Definition: htup_details.h:270
union HeapTupleHeaderData::@45 t_choice
#define XLH_DELETE_IS_SUPER
Definition: heapam_xlog.h:95
static uint8 compute_infobits(uint16 infomask, uint16 infomask2)
Definition: heapam.c:2397
HeapTupleFields t_heap
Definition: htup_details.h:156
#define PageIsAllVisible(page)
Definition: bufpage.h:385
uint32 TransactionId
Definition: c.h:507
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:1458
void XLogRegisterBuffer(uint8 block_id, Buffer buffer, uint8 flags)
Definition: xloginsert.c:213
HeapTupleHeaderData * HeapTupleHeader
Definition: htup.h:23
#define END_CRIT_SECTION()
Definition: miscadmin.h:134
#define HeapTupleHeaderIsSpeculative(tup)
Definition: htup_details.h:429
#define PageSetPrunable(page, xid)
Definition: bufpage.h:398
#define START_CRIT_SECTION()
Definition: miscadmin.h:132
uint32 BlockNumber
Definition: block.h:31
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3365
#define BUFFER_LOCK_EXCLUSIVE
Definition: bufmgr.h:88
OffsetNumber offnum
Definition: heapam_xlog.h:106
HeapTupleHeader t_data
Definition: htup.h:68
#define HeapTupleHeaderIsHeapOnly(tup)
Definition: htup_details.h:501
#define ItemIdGetLength(itemId)
Definition: itemid.h:59
#define ERROR
Definition: elog.h:43
ItemPointerData t_ctid
Definition: htup_details.h:160
ItemPointerData t_self
Definition: htup.h:65
TransactionId xmax
Definition: heapam_xlog.h:105
void heap_toast_delete(Relation rel, HeapTuple oldtup, bool is_speculative)
Definition: heaptoast.c:41
TransactionId GetCurrentTransactionId(void)
Definition: xact.c:423
uint32 t_len
Definition: htup.h:64
#define SizeOfHeapDelete
Definition: heapam_xlog.h:111
TransactionId RecentGlobalXmin
Definition: snapmgr.c:168
#define REGBUF_STANDARD
Definition: xloginsert.h:35
#define InvalidTransactionId
Definition: transam.h:31
Oid t_tableOid
Definition: htup.h:66
#define BufferGetPage(buffer)
Definition: bufmgr.h:159
TransactionId t_xmin
Definition: htup_details.h:123
#define PageGetItemId(page, offsetNumber)
Definition: bufpage.h:235
void XLogRegisterData(char *data, int len)
Definition: xloginsert.c:323
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:415
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3602
#define HEAP_KEYS_UPDATED
Definition: htup_details.h:278
#define HEAP_MOVED
Definition: htup_details.h:216
uint64 XLogRecPtr
Definition: xlogdefs.h:21
#define Assert(condition)
Definition: c.h:732
uint8 infobits_set
Definition: heapam_xlog.h:107
#define ItemIdIsNormal(itemId)
Definition: itemid.h:99
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition: bufmgr.c:596
#define ItemPointerGetOffsetNumber(pointer)
Definition: itemptr.h:117
#define RelationNeedsWAL(relation)
Definition: rel.h:521
void pgstat_count_heap_delete(Relation rel)
Definition: pgstat.c:1994
#define HeapTupleHasExternal(tuple)
Definition: htup_details.h:673
#define elog(elevel,...)
Definition: elog.h:226
#define ItemPointerGetBlockNumber(pointer)
Definition: itemptr.h:98
#define TransactionIdIsValid(xid)
Definition: transam.h:41
void XLogBeginInsert(void)
Definition: xloginsert.c:120
#define PageSetLSN(page, lsn)
Definition: bufpage.h:368
int Buffer
Definition: buf.h:23
#define XLOG_HEAP_DELETE
Definition: heapam_xlog.h:33
#define RelationGetRelid(relation)
Definition: rel.h:419
#define PageGetItem(page, itemId)
Definition: bufpage.h:340
Pointer Page
Definition: bufpage.h:78
#define HeapTupleHeaderSetXmin(tup, xid)
Definition: htup_details.h:319

◆ heap_beginscan()

TableScanDesc heap_beginscan ( Relation  relation,
Snapshot  snapshot,
int  nkeys,
ScanKey  key,
ParallelTableScanDesc  parallel_scan,
uint32  flags 
)

Definition at line 1132 of file heapam.c.

References Assert, initscan(), IsMVCCSnapshot, palloc(), PredicateLockRelation(), RelationGetRelid, RelationIncrementReferenceCount(), HeapScanDescData::rs_base, HeapScanDescData::rs_ctup, TableScanDescData::rs_flags, TableScanDescData::rs_key, TableScanDescData::rs_nkeys, TableScanDescData::rs_parallel, TableScanDescData::rs_rd, TableScanDescData::rs_snapshot, HeapScanDescData::rs_strategy, SO_ALLOW_PAGEMODE, SO_TYPE_SAMPLESCAN, SO_TYPE_SEQSCAN, and HeapTupleData::t_tableOid.

Referenced by SampleHeapTupleVisible().

1136 {
1137  HeapScanDesc scan;
1138 
1139  /*
1140  * increment relation ref count while scanning relation
1141  *
1142  * This is just to make really sure the relcache entry won't go away while
1143  * the scan has a pointer to it. Caller should be holding the rel open
1144  * anyway, so this is redundant in all normal scenarios...
1145  */
1147 
1148  /*
1149  * allocate and initialize scan descriptor
1150  */
1151  scan = (HeapScanDesc) palloc(sizeof(HeapScanDescData));
1152 
1153  scan->rs_base.rs_rd = relation;
1154  scan->rs_base.rs_snapshot = snapshot;
1155  scan->rs_base.rs_nkeys = nkeys;
1156  scan->rs_base.rs_flags = flags;
1157  scan->rs_base.rs_parallel = parallel_scan;
1158  scan->rs_strategy = NULL; /* set in initscan */
1159 
1160  /*
1161  * Disable page-at-a-time mode if it's not a MVCC-safe snapshot.
1162  */
1163  if (!(snapshot && IsMVCCSnapshot(snapshot)))
1165 
1166  /*
1167  * For seqscan and sample scans in a serializable transaction, acquire a
1168  * predicate lock on the entire relation. This is required not only to
1169  * lock all the matching tuples, but also to conflict with new insertions
1170  * into the table. In an indexscan, we take page locks on the index pages
1171  * covering the range specified in the scan qual, but in a heap scan there
1172  * is nothing more fine-grained to lock. A bitmap scan is a different
1173  * story, there we have already scanned the index and locked the index
1174  * pages covering the predicate. But in that case we still have to lock
1175  * any matching heap tuples. For sample scan we could optimize the locking
1176  * to be at least page-level granularity, but we'd need to add per-tuple
1177  * locking for that.
1178  */
1180  {
1181  /*
1182  * Ensure a missing snapshot is noticed reliably, even if the
1183  * isolation mode means predicate locking isn't performed (and
1184  * therefore the snapshot isn't used here).
1185  */
1186  Assert(snapshot);
1187  PredicateLockRelation(relation, snapshot);
1188  }
1189 
1190  /* we only need to set this up once */
1191  scan->rs_ctup.t_tableOid = RelationGetRelid(relation);
1192 
1193  /*
1194  * we do this here instead of in initscan() because heap_rescan also calls
1195  * initscan() and we don't want to allocate memory again
1196  */
1197  if (nkeys > 0)
1198  scan->rs_base.rs_key = (ScanKey) palloc(sizeof(ScanKeyData) * nkeys);
1199  else
1200  scan->rs_base.rs_key = NULL;
1201 
1202  initscan(scan, key, false);
1203 
1204  return (TableScanDesc) scan;
1205 }
TableScanDescData rs_base
Definition: heapam.h:48
void PredicateLockRelation(Relation relation, Snapshot snapshot)
Definition: predicate.c:2503
uint32 rs_flags
Definition: relscan.h:43
struct HeapScanDescData * HeapScanDesc
Definition: heapam.h:72
HeapTupleData rs_ctup
Definition: heapam.h:65
ScanKeyData * ScanKey
Definition: skey.h:75
Oid t_tableOid
Definition: htup.h:66
struct ScanKeyData * rs_key
Definition: relscan.h:37
void RelationIncrementReferenceCount(Relation rel)
Definition: relcache.c:2056
BufferAccessStrategy rs_strategy
Definition: heapam.h:63
#define IsMVCCSnapshot(snapshot)
Definition: snapmgr.h:97
#define Assert(condition)
Definition: c.h:732
Relation rs_rd
Definition: relscan.h:34
struct SnapshotData * rs_snapshot
Definition: relscan.h:35
void * palloc(Size size)
Definition: mcxt.c:949
struct ParallelTableScanDescData * rs_parallel
Definition: relscan.h:45
static void initscan(HeapScanDesc scan, ScanKey key, bool keep_startblock)
Definition: heapam.c:208
#define RelationGetRelid(relation)
Definition: rel.h:419

◆ heap_compute_xid_horizon_for_tuples()

TransactionId heap_compute_xid_horizon_for_tuples ( Relation  rel,
ItemPointerData items,
int  nitems 
)

Definition at line 6986 of file heapam.c.

References Assert, buf, BUFFER_LOCK_SHARE, BUFFER_LOCK_UNLOCK, BufferGetPage, BufferIsValid, CHECK_FOR_INTERRUPTS, effective_io_concurrency, get_tablespace_io_concurrency(), HeapTupleHeaderAdvanceLatestRemovedXid(), i, InvalidBlockNumber, InvalidBuffer, InvalidTransactionId, IsCatalogRelation(), ItemIdGetRedirect, ItemIdHasStorage, ItemIdIsDead, ItemIdIsRedirected, ItemIdIsUsed, ItemPointerCompare(), ItemPointerGetBlockNumber, ItemPointerGetOffsetNumber, LockBuffer(), MAX_IO_CONCURRENCY, Min, PageGetItem, PageGetItemId, qsort, RelationData::rd_rel, ReadBuffer(), and ReleaseBuffer().

Referenced by SampleHeapTupleVisible().

6989 {
6990  TransactionId latestRemovedXid = InvalidTransactionId;
6991  BlockNumber hblkno;
6993  Page hpage;
6994 #ifdef USE_PREFETCH
6995  XidHorizonPrefetchState prefetch_state;
6996  int io_concurrency;
6997  int prefetch_distance;
6998 #endif
6999 
7000  /*
7001  * Sort to avoid repeated lookups for the same page, and to make it more
7002  * likely to access items in an efficient order. In particular, this
7003  * ensures that if there are multiple pointers to the same page, they all
7004  * get processed looking up and locking the page just once.
7005  */
7006  qsort((void *) tids, nitems, sizeof(ItemPointerData),
7007  (int (*) (const void *, const void *)) ItemPointerCompare);
7008 
7009 #ifdef USE_PREFETCH
7010  /* Initialize prefetch state. */
7011  prefetch_state.cur_hblkno = InvalidBlockNumber;
7012  prefetch_state.next_item = 0;
7013  prefetch_state.nitems = nitems;
7014  prefetch_state.tids = tids;
7015 
7016  /*
7017  * Compute the prefetch distance that we will attempt to maintain.
7018  *
7019  * We don't use the regular formula to determine how much to prefetch
7020  * here, but instead just add a constant to effective_io_concurrency.
7021  * That's because it seems best to do some prefetching here even when
7022  * effective_io_concurrency is set to 0, but if the DBA thinks it's OK to
7023  * do more prefetching for other operations, then it's probably OK to do
7024  * more prefetching in this case, too. It may be that this formula is too
7025  * simplistic, but at the moment there is no evidence of that or any idea
7026  * about what would work better.
7027  *
7028  * Since the caller holds a buffer lock somewhere in rel, we'd better make
7029  * sure that isn't a catalog relation before we call code that does
7030  * syscache lookups, to avoid risk of deadlock.
7031  */
7032  if (IsCatalogRelation(rel))
7033  io_concurrency = effective_io_concurrency;
7034  else
7035  io_concurrency = get_tablespace_io_concurrency(rel->rd_rel->reltablespace);
7036  prefetch_distance = Min((io_concurrency) + 10, MAX_IO_CONCURRENCY);
7037 
7038  /* Start prefetching. */
7039  xid_horizon_prefetch_buffer(rel, &prefetch_state, prefetch_distance);
7040 #endif
7041 
7042  /* Iterate over all tids, and check their horizon */
7043  hblkno = InvalidBlockNumber;
7044  hpage = NULL;
7045  for (int i = 0; i < nitems; i++)
7046  {
7047  ItemPointer htid = &tids[i];
7048  ItemId hitemid;
7049  OffsetNumber hoffnum;
7050 
7051  /*
7052  * Read heap buffer, but avoid refetching if it's the same block as
7053  * required for the last tid.
7054  */
7055  if (hblkno == InvalidBlockNumber ||
7056  ItemPointerGetBlockNumber(htid) != hblkno)
7057  {
7058  /* release old buffer */
7059  if (BufferIsValid(buf))
7060  {
7062  ReleaseBuffer(buf);
7063  }
7064 
7065  hblkno = ItemPointerGetBlockNumber(htid);
7066 
7067  buf = ReadBuffer(rel, hblkno);
7068 
7069 #ifdef USE_PREFETCH
7070 
7071  /*
7072  * To maintain the prefetch distance, prefetch one more page for
7073  * each page we read.
7074  */
7075  xid_horizon_prefetch_buffer(rel, &prefetch_state, 1);
7076 #endif
7077 
7078  hpage = BufferGetPage(buf);
7079 
7081  }
7082 
7083  hoffnum = ItemPointerGetOffsetNumber(htid);
7084  hitemid = PageGetItemId(hpage, hoffnum);
7085 
7086  /*
7087  * Follow any redirections until we find something useful.
7088  */
7089  while (ItemIdIsRedirected(hitemid))
7090  {
7091  hoffnum = ItemIdGetRedirect(hitemid);
7092  hitemid = PageGetItemId(hpage, hoffnum);
7094  }
7095 
7096  /*
7097  * If the heap item has storage, then read the header and use that to
7098  * set latestRemovedXid.
7099  *
7100  * Some LP_DEAD items may not be accessible, so we ignore them.
7101  */
7102  if (ItemIdHasStorage(hitemid))
7103  {
7104  HeapTupleHeader htuphdr;
7105 
7106  htuphdr = (HeapTupleHeader) PageGetItem(hpage, hitemid);
7107 
7108  HeapTupleHeaderAdvanceLatestRemovedXid(htuphdr, &latestRemovedXid);
7109  }
7110  else if (ItemIdIsDead(hitemid))
7111  {
7112  /*
7113  * Conjecture: if hitemid is dead then it had xids before the xids
7114  * marked on LP_NORMAL items. So we just ignore this item and move
7115  * onto the next, for the purposes of calculating
7116  * latestRemovedXid.
7117  */
7118  }
7119  else
7120  Assert(!ItemIdIsUsed(hitemid));
7121 
7122  }
7123 
7124  if (BufferIsValid(buf))
7125  {
7127  ReleaseBuffer(buf);
7128  }
7129 
7130  /*
7131  * If all heap tuples were LP_DEAD then we will be returning
7132  * InvalidTransactionId here, which avoids conflicts. This matches
7133  * existing logic which assumes that LP_DEAD tuples must already be older
7134  * than the latestRemovedXid on the cleanup record that set them as
7135  * LP_DEAD, hence must already have generated a conflict.
7136  */
7137 
7138  return latestRemovedXid;
7139 }
int32 ItemPointerCompare(ItemPointer arg1, ItemPointer arg2)
Definition: itemptr.c:52
void HeapTupleHeaderAdvanceLatestRemovedXid(HeapTupleHeader tuple, TransactionId *latestRemovedXid)
Definition: heapam.c:6895
#define MAX_IO_CONCURRENCY
Definition: bufmgr.h:78
#define BUFFER_LOCK_UNLOCK
Definition: bufmgr.h:86
bool IsCatalogRelation(Relation relation)
Definition: catalog.c:100
#define ItemIdIsRedirected(itemId)
Definition: itemid.h:106
uint32 TransactionId
Definition: c.h:507
HeapTupleHeaderData * HeapTupleHeader
Definition: htup.h:23
#define ItemIdGetRedirect(itemId)
Definition: itemid.h:78
#define Min(x, y)
Definition: c.h:904
#define ItemIdIsUsed(itemId)
Definition: itemid.h:92
#define InvalidBuffer
Definition: buf.h:25
int get_tablespace_io_concurrency(Oid spcid)
Definition: spccache.c:215
uint32 BlockNumber
Definition: block.h:31
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3365
Form_pg_class rd_rel
Definition: rel.h:83
#define ItemIdIsDead(itemId)
Definition: itemid.h:113
int effective_io_concurrency
Definition: bufmgr.c:113
uint16 OffsetNumber
Definition: off.h:24
static char * buf
Definition: pg_test_fsync.c:68
#define InvalidTransactionId
Definition: transam.h:31
#define BufferGetPage(buffer)
Definition: bufmgr.h:159
#define PageGetItemId(page, offsetNumber)
Definition: bufpage.h:235
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3602
#define ItemIdHasStorage(itemId)
Definition: itemid.h:120
#define Assert(condition)
Definition: c.h:732
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition: bufmgr.c:596
#define InvalidBlockNumber
Definition: block.h:33
#define BufferIsValid(bufnum)
Definition: bufmgr.h:113
#define ItemPointerGetOffsetNumber(pointer)
Definition: itemptr.h:117
int i
#define BUFFER_LOCK_SHARE
Definition: bufmgr.h:87
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:99
#define ItemPointerGetBlockNumber(pointer)
Definition: itemptr.h:98
#define qsort(a, b, c, d)
Definition: port.h:492
int Buffer
Definition: buf.h:23
#define PageGetItem(page, itemId)
Definition: bufpage.h:340
Pointer Page
Definition: bufpage.h:78

◆ heap_delete()

TM_Result heap_delete ( Relation  relation,
ItemPointer  tid,
CommandId  cid,
Snapshot  crosscheck,
bool  wait,
struct TM_FailureData tmfd,
bool  changingPart 
)

Definition at line 2442 of file heapam.c.

References Assert, BUFFER_LOCK_EXCLUSIVE, BUFFER_LOCK_UNLOCK, BufferGetBlockNumber(), BufferGetPage, CacheInvalidateHeapTuple(), CheckForSerializableConflictIn(), TM_FailureData::cmax, compute_infobits(), compute_new_xmax_infomask(), TM_FailureData::ctid, DoesMultiXactIdConflict(), END_CRIT_SECTION, ereport, errcode(), errmsg(), ERROR, ExtractReplicaIdentity(), xl_heap_delete::flags, GetCurrentTransactionId(), heap_acquire_tuplock(), heap_freetuple(), HEAP_KEYS_UPDATED, HEAP_MOVED, heap_toast_delete(), HEAP_XMAX_BITS, HEAP_XMAX_INVALID, HEAP_XMAX_IS_LOCKED_ONLY, HEAP_XMAX_IS_MULTI, HeapTupleHasExternal, HeapTupleHeaderAdjustCmax(), HeapTupleHeaderClearHotUpdated, HeapTupleHeaderGetCmax(), HeapTupleHeaderGetRawXmax, HeapTupleHeaderGetUpdateXid, HeapTupleHeaderIndicatesMovedPartitions, HeapTupleHeaderIsOnlyLocked(), HeapTupleHeaderSetCmax, HeapTupleHeaderSetMovedPartitions, HeapTupleHeaderSetXmax, HeapTupleSatisfiesUpdate(), HeapTupleSatisfiesVisibility(), xl_heap_delete::infobits_set, InvalidBuffer, InvalidCommandId, InvalidSnapshot, IsInParallelMode(), ItemIdGetLength, ItemIdIsNormal, ItemPointerEquals(), ItemPointerGetBlockNumber, ItemPointerGetOffsetNumber, ItemPointerIsValid, LockBuffer(), LockTupleExclusive, LockWaitBlock, log_heap_new_cid(), MarkBufferDirty(), MultiXactIdSetOldestMember(), MultiXactIdWait(), MultiXactStatusUpdate, xl_heap_delete::offnum, PageClearAllVisible, PageGetItem, PageGetItemId, PageIsAllVisible, PageSetLSN, PageSetPrunable, pgstat_count_heap_delete(), RelationData::rd_rel, ReadBuffer(), REGBUF_STANDARD, RelationGetRelid, RelationIsAccessibleInLogicalDecoding, RelationNeedsWAL, ReleaseBuffer(), SizeOfHeapDelete, SizeOfHeapHeader, SizeofHeapTupleHeader, START_CRIT_SECTION, HeapTupleHeaderData::t_ctid, HeapTupleData::t_data, xl_heap_header::t_hoff, HeapTupleHeaderData::t_hoff, xl_heap_header::t_infomask, HeapTupleHeaderData::t_infomask, xl_heap_header::t_infomask2, HeapTupleHeaderData::t_infomask2, HeapTupleData::t_len, HeapTupleData::t_self, HeapTupleData::t_tableOid, TM_BeingModified, TM_Deleted, TM_Invisible, TM_Ok, TM_SelfModified, TM_Updated, TransactionIdEquals, TransactionIdIsCurrentTransactionId(), UnlockReleaseBuffer(), UnlockTupleTuplock, UpdateXmaxHintBits(), visibilitymap_clear(), visibilitymap_pin(), VISIBILITYMAP_VALID_BITS, XactLockTableWait(), XLH_DELETE_ALL_VISIBLE_CLEARED, XLH_DELETE_CONTAINS_OLD_KEY, XLH_DELETE_CONTAINS_OLD_TUPLE, XLH_DELETE_IS_PARTITION_MOVE, XLOG_HEAP_DELETE, XLOG_INCLUDE_ORIGIN, XLogBeginInsert(), XLogInsert(), XLogRegisterBuffer(), XLogRegisterData(), XLogSetRecordFlags(), XLTW_Delete, xl_heap_delete::xmax, TM_FailureData::xmax, and xmax_infomask_changed().

Referenced by heapam_tuple_delete(), and simple_heap_delete().

2445 {
2446  TM_Result result;
2448  ItemId lp;
2449  HeapTupleData tp;
2450  Page page;
2451  BlockNumber block;
2452  Buffer buffer;
2453  Buffer vmbuffer = InvalidBuffer;
2454  TransactionId new_xmax;
2455  uint16 new_infomask,
2456  new_infomask2;
2457  bool have_tuple_lock = false;
2458  bool iscombo;
2459  bool all_visible_cleared = false;
2460  HeapTuple old_key_tuple = NULL; /* replica identity of the tuple */
2461  bool old_key_copied = false;
2462 
2463  Assert(ItemPointerIsValid(tid));
2464 
2465  /*
2466  * Forbid this during a parallel operation, lest it allocate a combocid.
2467  * Other workers might need that combocid for visibility checks, and we
2468  * have no provision for broadcasting it to them.
2469  */
2470  if (IsInParallelMode())
2471  ereport(ERROR,
2472  (errcode(ERRCODE_INVALID_TRANSACTION_STATE),
2473  errmsg("cannot delete tuples during a parallel operation")));
2474 
2475  block = ItemPointerGetBlockNumber(tid);
2476  buffer = ReadBuffer(relation, block);
2477  page = BufferGetPage(buffer);
2478 
2479  /*
2480  * Before locking the buffer, pin the visibility map page if it appears to
2481  * be necessary. Since we haven't got the lock yet, someone else might be
2482  * in the middle of changing this, so we'll need to recheck after we have
2483  * the lock.
2484  */
2485  if (PageIsAllVisible(page))
2486  visibilitymap_pin(relation, block, &vmbuffer);
2487 
2489 
2490  /*
2491  * If we didn't pin the visibility map page and the page has become all
2492  * visible while we were busy locking the buffer, we'll have to unlock and
2493  * re-lock, to avoid holding the buffer lock across an I/O. That's a bit
2494  * unfortunate, but hopefully shouldn't happen often.
2495  */
2496  if (vmbuffer == InvalidBuffer && PageIsAllVisible(page))
2497  {
2498  LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
2499  visibilitymap_pin(relation, block, &vmbuffer);
2501  }
2502 
2503  lp = PageGetItemId(page, ItemPointerGetOffsetNumber(tid));
2504  Assert(ItemIdIsNormal(lp));
2505 
2506  tp.t_tableOid = RelationGetRelid(relation);
2507  tp.t_data = (HeapTupleHeader) PageGetItem(page, lp);
2508  tp.t_len = ItemIdGetLength(lp);
2509  tp.t_self = *tid;
2510 
2511 l1:
2512  result = HeapTupleSatisfiesUpdate(&tp, cid, buffer);
2513 
2514  if (result == TM_Invisible)
2515  {
2516  UnlockReleaseBuffer(buffer);
2517  ereport(ERROR,
2518  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
2519  errmsg("attempted to delete invisible tuple")));
2520  }
2521  else if (result == TM_BeingModified && wait)
2522  {
2523  TransactionId xwait;
2524  uint16 infomask;
2525 
2526  /* must copy state data before unlocking buffer */
2527  xwait = HeapTupleHeaderGetRawXmax(tp.t_data);
2528  infomask = tp.t_data->t_infomask;
2529 
2530  /*
2531  * Sleep until concurrent transaction ends -- except when there's a
2532  * single locker and it's our own transaction. Note we don't care
2533  * which lock mode the locker has, because we need the strongest one.
2534  *
2535  * Before sleeping, we need to acquire tuple lock to establish our
2536  * priority for the tuple (see heap_lock_tuple). LockTuple will
2537  * release us when we are next-in-line for the tuple.
2538  *
2539  * If we are forced to "start over" below, we keep the tuple lock;
2540  * this arranges that we stay at the head of the line while rechecking
2541  * tuple state.
2542  */
2543  if (infomask & HEAP_XMAX_IS_MULTI)
2544  {
2545  bool current_is_member = false;
2546 
2547  if (DoesMultiXactIdConflict((MultiXactId) xwait, infomask,
2548  LockTupleExclusive, &current_is_member))
2549  {
2550  LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
2551 
2552  /*
2553  * Acquire the lock, if necessary (but skip it when we're
2554  * requesting a lock and already have one; avoids deadlock).
2555  */
2556  if (!current_is_member)
2558  LockWaitBlock, &have_tuple_lock);
2559 
2560  /* wait for multixact */
2562  relation, &(tp.t_self), XLTW_Delete,
2563  NULL);
2565 
2566  /*
2567  * If xwait had just locked the tuple then some other xact
2568  * could update this tuple before we get to this point. Check
2569  * for xmax change, and start over if so.
2570  */
2571  if (xmax_infomask_changed(tp.t_data->t_infomask, infomask) ||
2573  xwait))
2574  goto l1;
2575  }
2576 
2577  /*
2578  * You might think the multixact is necessarily done here, but not
2579  * so: it could have surviving members, namely our own xact or
2580  * other subxacts of this backend. It is legal for us to delete
2581  * the tuple in either case, however (the latter case is
2582  * essentially a situation of upgrading our former shared lock to
2583  * exclusive). We don't bother changing the on-disk hint bits
2584  * since we are about to overwrite the xmax altogether.
2585  */
2586  }
2587  else if (!TransactionIdIsCurrentTransactionId(xwait))
2588  {
2589  /*
2590  * Wait for regular transaction to end; but first, acquire tuple
2591  * lock.
2592  */
2593  LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
2595  LockWaitBlock, &have_tuple_lock);
2596  XactLockTableWait(xwait, relation, &(tp.t_self), XLTW_Delete);
2598 
2599  /*
2600  * xwait is done, but if xwait had just locked the tuple then some
2601  * other xact could update this tuple before we get to this point.
2602  * Check for xmax change, and start over if so.
2603  */
2604  if (xmax_infomask_changed(tp.t_data->t_infomask, infomask) ||
2606  xwait))
2607  goto l1;
2608 
2609  /* Otherwise check if it committed or aborted */
2610  UpdateXmaxHintBits(tp.t_data, buffer, xwait);
2611  }
2612 
2613  /*
2614  * We may overwrite if previous xmax aborted, or if it committed but
2615  * only locked the tuple without updating it.
2616  */
2617  if ((tp.t_data->t_infomask & HEAP_XMAX_INVALID) ||
2620  result = TM_Ok;
2621  else if (!ItemPointerEquals(&tp.t_self, &tp.t_data->t_ctid) ||
2623  result = TM_Updated;
2624  else
2625  result = TM_Deleted;
2626  }
2627 
2628  if (crosscheck != InvalidSnapshot && result == TM_Ok)
2629  {
2630  /* Perform additional check for transaction-snapshot mode RI updates */
2631  if (!HeapTupleSatisfiesVisibility(&tp, crosscheck, buffer))
2632  result = TM_Updated;
2633  }
2634 
2635  if (result != TM_Ok)
2636  {
2637  Assert(result == TM_SelfModified ||
2638  result == TM_Updated ||
2639  result == TM_Deleted ||
2640  result == TM_BeingModified);
2642  Assert(result != TM_Updated ||
2643  !ItemPointerEquals(&tp.t_self, &tp.t_data->t_ctid));
2644  tmfd->ctid = tp.t_data->t_ctid;
2646  if (result == TM_SelfModified)
2647  tmfd->cmax = HeapTupleHeaderGetCmax(tp.t_data);
2648  else
2649  tmfd->cmax = InvalidCommandId;
2650  UnlockReleaseBuffer(buffer);
2651  if (have_tuple_lock)
2652  UnlockTupleTuplock(relation, &(tp.t_self), LockTupleExclusive);
2653  if (vmbuffer != InvalidBuffer)
2654  ReleaseBuffer(vmbuffer);
2655  return result;
2656  }
2657 
2658  /*
2659  * We're about to do the actual delete -- check for conflict first, to
2660  * avoid possibly having to roll back work we've just done.
2661  *
2662  * This is safe without a recheck as long as there is no possibility of
2663  * another process scanning the page between this check and the delete
2664  * being visible to the scan (i.e., an exclusive buffer content lock is
2665  * continuously held from this point until the tuple delete is visible).
2666  */
2667  CheckForSerializableConflictIn(relation, &tp, buffer);
2668 
2669  /* replace cid with a combo cid if necessary */
2670  HeapTupleHeaderAdjustCmax(tp.t_data, &cid, &iscombo);
2671 
2672  /*
2673  * Compute replica identity tuple before entering the critical section so
2674  * we don't PANIC upon a memory allocation failure.
2675  */
2676  old_key_tuple = ExtractReplicaIdentity(relation, &tp, true, &old_key_copied);
2677 
2678  /*
2679  * If this is the first possibly-multixact-able operation in the current
2680  * transaction, set my per-backend OldestMemberMXactId setting. We can be
2681  * certain that the transaction will never become a member of any older
2682  * MultiXactIds than that. (We have to do this even if we end up just
2683  * using our own TransactionId below, since some other backend could
2684  * incorporate our XID into a MultiXact immediately afterwards.)
2685  */
2687 
2690  xid, LockTupleExclusive, true,
2691  &new_xmax, &new_infomask, &new_infomask2);
2692 
2694 
2695  /*
2696  * If this transaction commits, the tuple will become DEAD sooner or
2697  * later. Set flag that this page is a candidate for pruning once our xid
2698  * falls below the OldestXmin horizon. If the transaction finally aborts,
2699  * the subsequent page pruning will be a no-op and the hint will be
2700  * cleared.
2701  */
2702  PageSetPrunable(page, xid);
2703 
2704  if (PageIsAllVisible(page))
2705  {
2706  all_visible_cleared = true;
2707  PageClearAllVisible(page);
2708  visibilitymap_clear(relation, BufferGetBlockNumber(buffer),
2709  vmbuffer, VISIBILITYMAP_VALID_BITS);
2710  }
2711 
2712  /* store transaction information of xact deleting the tuple */
2715  tp.t_data->t_infomask |= new_infomask;
2716  tp.t_data->t_infomask2 |= new_infomask2;
2718  HeapTupleHeaderSetXmax(tp.t_data, new_xmax);
2719  HeapTupleHeaderSetCmax(tp.t_data, cid, iscombo);
2720  /* Make sure there is no forward chain link in t_ctid */
2721  tp.t_data->t_ctid = tp.t_self;
2722 
2723  /* Signal that this is actually a move into another partition */
2724  if (changingPart)
2726 
2727  MarkBufferDirty(buffer);
2728 
2729  /*
2730  * XLOG stuff
2731  *
2732  * NB: heap_abort_speculative() uses the same xlog record and replay
2733  * routines.
2734  */
2735  if (RelationNeedsWAL(relation))
2736  {
2737  xl_heap_delete xlrec;
2738  xl_heap_header xlhdr;
2739  XLogRecPtr recptr;
2740 
2741  /* For logical decode we need combocids to properly decode the catalog */
2743  log_heap_new_cid(relation, &tp);
2744 
2745  xlrec.flags = 0;
2746  if (all_visible_cleared)
2748  if (changingPart)
2751  tp.t_data->t_infomask2);
2753  xlrec.xmax = new_xmax;
2754 
2755  if (old_key_tuple != NULL)
2756  {
2757  if (relation->rd_rel->relreplident == REPLICA_IDENTITY_FULL)
2759  else
2761  }
2762 
2763  XLogBeginInsert();
2764  XLogRegisterData((char *) &xlrec, SizeOfHeapDelete);
2765 
2766  XLogRegisterBuffer(0, buffer, REGBUF_STANDARD);
2767 
2768  /*
2769  * Log replica identity of the deleted tuple if there is one
2770  */
2771  if (old_key_tuple != NULL)
2772  {
2773  xlhdr.t_infomask2 = old_key_tuple->t_data->t_infomask2;
2774  xlhdr.t_infomask = old_key_tuple->t_data->t_infomask;
2775  xlhdr.t_hoff = old_key_tuple->t_data->t_hoff;
2776 
2777  XLogRegisterData((char *) &xlhdr, SizeOfHeapHeader);
2778  XLogRegisterData((char *) old_key_tuple->t_data
2780  old_key_tuple->t_len
2782  }
2783 
2784  /* filtering by origin on a row level is much more efficient */
2786 
2787  recptr = XLogInsert(RM_HEAP_ID, XLOG_HEAP_DELETE);
2788 
2789  PageSetLSN(page, recptr);
2790  }
2791 
2792  END_CRIT_SECTION();
2793 
2794  LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
2795 
2796  if (vmbuffer != InvalidBuffer)
2797  ReleaseBuffer(vmbuffer);
2798 
2799  /*
2800  * If the tuple has toasted out-of-line attributes, we need to delete
2801  * those items too. We have to do this before releasing the buffer
2802  * because we need to look at the contents of the tuple, but it's OK to
2803  * release the content lock on the buffer first.
2804  */
2805  if (relation->rd_rel->relkind != RELKIND_RELATION &&
2806  relation->rd_rel->relkind != RELKIND_MATVIEW)
2807  {
2808  /* toast table entries should never be recursively toasted */
2810  }
2811  else if (HeapTupleHasExternal(&tp))
2812  heap_toast_delete(relation, &tp, false);
2813 
2814  /*
2815  * Mark tuple for invalidation from system caches at next command
2816  * boundary. We have to do this before releasing the buffer because we
2817  * need to look at the contents of the tuple.
2818  */
2819  CacheInvalidateHeapTuple(relation, &tp, NULL);
2820 
2821  /* Now we can release the buffer */
2822  ReleaseBuffer(buffer);
2823 
2824  /*
2825  * Release the lmgr tuple lock, if we had it.
2826  */
2827  if (have_tuple_lock)
2828  UnlockTupleTuplock(relation, &(tp.t_self), LockTupleExclusive);
2829 
2830  pgstat_count_heap_delete(relation);
2831 
2832  if (old_key_tuple != NULL && old_key_copied)
2833  heap_freetuple(old_key_tuple);
2834 
2835  return TM_Ok;
2836 }
#define HeapTupleHeaderGetUpdateXid(tup)
Definition: htup_details.h:365
#define ItemPointerIsValid(pointer)
Definition: itemptr.h:82
ItemPointerData ctid
Definition: tableam.h:123
#define BUFFER_LOCK_UNLOCK
Definition: bufmgr.h:86
#define SizeofHeapTupleHeader
Definition: htup_details.h:184
static XLogRecPtr log_heap_new_cid(Relation relation, HeapTuple tup)
Definition: heapam.c:7523
#define HEAP_XMAX_BITS
Definition: htup_details.h:270
static uint8 compute_infobits(uint16 infomask, uint16 infomask2)
Definition: heapam.c:2397
void CacheInvalidateHeapTuple(Relation relation, HeapTuple tuple, HeapTuple newtuple)
Definition: inval.c:1114
#define TransactionIdEquals(id1, id2)
Definition: transam.h:43
#define PageIsAllVisible(page)
Definition: bufpage.h:385
uint32 TransactionId
Definition: c.h:507
bool TransactionIdIsCurrentTransactionId(TransactionId xid)
Definition: xact.c:854
void visibilitymap_pin(Relation rel, BlockNumber heapBlk, Buffer *buf)
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:1458
void XLogRegisterBuffer(uint8 block_id, Buffer buffer, uint8 flags)
Definition: xloginsert.c:213
HeapTupleHeaderData * HeapTupleHeader
Definition: htup.h:23
static HeapTuple ExtractReplicaIdentity(Relation rel, HeapTuple tup, bool key_changed, bool *copy)
Definition: heapam.c:7605
static bool xmax_infomask_changed(uint16 new_infomask, uint16 old_infomask)
Definition: heapam.c:2419
#define HeapTupleHeaderClearHotUpdated(tup)
Definition: htup_details.h:496
#define END_CRIT_SECTION()
Definition: miscadmin.h:134
CommandId cmax
Definition: tableam.h:125
bool HeapTupleHeaderIsOnlyLocked(HeapTupleHeader tuple)
#define InvalidBuffer
Definition: buf.h:25
uint16 t_infomask2
Definition: heapam_xlog.h:144
#define PageSetPrunable(page, xid)
Definition: bufpage.h:398
#define START_CRIT_SECTION()
Definition: miscadmin.h:132
int errcode(int sqlerrcode)
Definition: elog.c:570
#define XLOG_INCLUDE_ORIGIN
Definition: xlog.h:228
#define HeapTupleHeaderIndicatesMovedPartitions(tup)
Definition: htup_details.h:445
uint32 BlockNumber
Definition: block.h:31
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3365
#define BUFFER_LOCK_EXCLUSIVE
Definition: bufmgr.h:88
Form_pg_class rd_rel
Definition: rel.h:83
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
TM_Result HeapTupleSatisfiesUpdate(HeapTuple htup, CommandId curcid, Buffer buffer)
void CheckForSerializableConflictIn(Relation relation, HeapTuple tuple, Buffer buffer)
Definition: predicate.c:4442
#define UnlockTupleTuplock(rel, tup, mode)
Definition: heapam.c:161
OffsetNumber offnum
Definition: heapam_xlog.h:106
void MultiXactIdSetOldestMember(void)
Definition: multixact.c:625
#define VISIBILITYMAP_VALID_BITS
Definition: visibilitymap.h:28
HeapTupleHeader t_data
Definition: htup.h:68
#define HeapTupleHeaderGetRawXmax(tup)
Definition: htup_details.h:375
unsigned short uint16
Definition: c.h:357
#define ItemIdGetLength(itemId)
Definition: itemid.h:59
bool IsInParallelMode(void)
Definition: xact.c:994
bool visibilitymap_clear(Relation rel, BlockNumber heapBlk, Buffer buf, uint8 flags)
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3388
TransactionId xmax
Definition: tableam.h:124
#define ERROR
Definition: elog.h:43
#define HEAP_XMAX_INVALID
Definition: htup_details.h:207
ItemPointerData t_ctid
Definition: htup_details.h:160
#define HeapTupleHeaderSetMovedPartitions(tup)
Definition: htup_details.h:449
ItemPointerData t_self
Definition: htup.h:65
TransactionId xmax
Definition: heapam_xlog.h:105
static void MultiXactIdWait(MultiXactId multi, MultiXactStatus status, uint16 infomask, Relation rel, ItemPointer ctid, XLTW_Oper oper, int *remaining)
Definition: heapam.c:6725
void heap_toast_delete(Relation rel, HeapTuple oldtup, bool is_speculative)
Definition: heaptoast.c:41
TransactionId GetCurrentTransactionId(void)
Definition: xact.c:423
uint32 t_len
Definition: htup.h:64
#define SizeOfHeapDelete
Definition: heapam_xlog.h:111
#define REGBUF_STANDARD
Definition: xloginsert.h:35
#define XLH_DELETE_CONTAINS_OLD_KEY
Definition: heapam_xlog.h:94
#define HeapTupleHeaderSetXmax(tup, xid)
Definition: htup_details.h:380
Oid t_tableOid
Definition: htup.h:66
void XLogSetRecordFlags(uint8 flags)
Definition: xloginsert.c:397
#define HeapTupleHeaderSetCmax(tup, cid, iscombo)
Definition: htup_details.h:405
#define BufferGetPage(buffer)
Definition: bufmgr.h:159
#define ereport(elevel, rest)
Definition: elog.h:141
static void compute_new_xmax_infomask(TransactionId xmax, uint16 old_infomask, uint16 old_infomask2, TransactionId add_to_xmax, LockTupleMode mode, bool is_update, TransactionId *result_xmax, uint16 *result_infomask, uint16 *result_infomask2)
Definition: heapam.c:4713
#define PageGetItemId(page, offsetNumber)
Definition: bufpage.h:235
#define InvalidSnapshot
Definition: snapshot.h:123
void XLogRegisterData(char *data, int len)
Definition: xloginsert.c:323
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:415
TM_Result
Definition: tableam.h:68
#define RelationIsAccessibleInLogicalDecoding(relation)
Definition: rel.h:575
#define InvalidCommandId
Definition: c.h:524
#define HEAP_XMAX_IS_LOCKED_ONLY(infomask)
Definition: htup_details.h:230
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3602
#define HEAP_KEYS_UPDATED
Definition: htup_details.h:278
#define HEAP_XMAX_IS_MULTI
Definition: htup_details.h:208
static void UpdateXmaxHintBits(HeapTupleHeader tuple, Buffer buffer, TransactionId xid)
Definition: heapam.c:1793
#define HEAP_MOVED
Definition: htup_details.h:216
static bool heap_acquire_tuplock(Relation relation, ItemPointer tid, LockTupleMode mode, LockWaitPolicy wait_policy, bool *have_tuple_lock)
Definition: heapam.c:4664
TransactionId MultiXactId
Definition: c.h:517
#define PageClearAllVisible(page)
Definition: bufpage.h:389
void XactLockTableWait(TransactionId xid, Relation rel, ItemPointer ctid, XLTW_Oper oper)
Definition: lmgr.c:624
uint64 XLogRecPtr
Definition: xlogdefs.h:21
#define Assert(condition)
Definition: c.h:732
uint8 infobits_set
Definition: heapam_xlog.h:107
CommandId HeapTupleHeaderGetCmax(HeapTupleHeader tup)
Definition: combocid.c:119
Definition: tableam.h:74
#define ItemIdIsNormal(itemId)
Definition: itemid.h:99
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition: bufmgr.c:596
uint16 t_infomask
Definition: heapam_xlog.h:145
#define ItemPointerGetOffsetNumber(pointer)
Definition: itemptr.h:117
static bool DoesMultiXactIdConflict(MultiXactId multi, uint16 infomask, LockTupleMode lockmode, bool *current_is_member)
Definition: heapam.c:6548
#define RelationNeedsWAL(relation)
Definition: rel.h:521
bool ItemPointerEquals(ItemPointer pointer1, ItemPointer pointer2)
Definition: itemptr.c:29
void pgstat_count_heap_delete(Relation rel)
Definition: pgstat.c:1994
void HeapTupleHeaderAdjustCmax(HeapTupleHeader tup, CommandId *cmax, bool *iscombo)
Definition: combocid.c:154
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:2613
#define HeapTupleHasExternal(tuple)
Definition: htup_details.h:673
int errmsg(const char *fmt,...)
Definition: elog.c:784
#define XLH_DELETE_ALL_VISIBLE_CLEARED
Definition: heapam_xlog.h:92
#define XLH_DELETE_IS_PARTITION_MOVE
Definition: heapam_xlog.h:96
#define ItemPointerGetBlockNumber(pointer)
Definition: itemptr.h:98
void XLogBeginInsert(void)
Definition: xloginsert.c:120
#define PageSetLSN(page, lsn)
Definition: bufpage.h:368
int Buffer
Definition: buf.h:23
#define XLOG_HEAP_DELETE
Definition: heapam_xlog.h:33
#define RelationGetRelid(relation)
Definition: rel.h:419
#define PageGetItem(page, itemId)
Definition: bufpage.h:340
#define SizeOfHeapHeader
Definition: heapam_xlog.h:149
Pointer Page
Definition: bufpage.h:78
bool HeapTupleSatisfiesVisibility(HeapTuple tup, Snapshot snapshot, Buffer buffer)
#define XLH_DELETE_CONTAINS_OLD_TUPLE
Definition: heapam_xlog.h:93

◆ heap_endscan()

void heap_endscan ( TableScanDesc  scan)

Definition at line 1245 of file heapam.c.

References BufferIsValid, FreeAccessStrategy(), pfree(), RelationDecrementReferenceCount(), ReleaseBuffer(), HeapScanDescData::rs_base, HeapScanDescData::rs_cbuf, TableScanDescData::rs_flags, TableScanDescData::rs_key, TableScanDescData::rs_rd, TableScanDescData::rs_snapshot, HeapScanDescData::rs_strategy, SO_TEMP_SNAPSHOT, and UnregisterSnapshot().

Referenced by SampleHeapTupleVisible().

1246 {
1247  HeapScanDesc scan = (HeapScanDesc) sscan;
1248 
1249  /* Note: no locking manipulations needed */
1250 
1251  /*
1252  * unpin scan buffers
1253  */
1254  if (BufferIsValid(scan->rs_cbuf))
1255  ReleaseBuffer(scan->rs_cbuf);
1256 
1257  /*
1258  * decrement relation reference count and free scan descriptor storage
1259  */
1261 
1262  if (scan->rs_base.rs_key)
1263  pfree(scan->rs_base.rs_key);
1264 
1265  if (scan->rs_strategy != NULL)
1267 
1268  if (scan->rs_base.rs_flags & SO_TEMP_SNAPSHOT)
1270 
1271  pfree(scan);
1272 }
TableScanDescData rs_base
Definition: heapam.h:48
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3365
uint32 rs_flags
Definition: relscan.h:43
struct HeapScanDescData * HeapScanDesc
Definition: heapam.h:72
void pfree(void *pointer)
Definition: mcxt.c:1056
void RelationDecrementReferenceCount(Relation rel)
Definition: relcache.c:2069
struct ScanKeyData * rs_key
Definition: relscan.h:37
void UnregisterSnapshot(Snapshot snapshot)
Definition: snapmgr.c:907
BufferAccessStrategy rs_strategy
Definition: heapam.h:63
Buffer rs_cbuf
Definition: heapam.h:59
void FreeAccessStrategy(BufferAccessStrategy strategy)
Definition: freelist.c:597
#define BufferIsValid(bufnum)
Definition: bufmgr.h:113
Relation rs_rd
Definition: relscan.h:34
struct SnapshotData * rs_snapshot
Definition: relscan.h:35

◆ heap_fetch()

bool heap_fetch ( Relation  relation,
Snapshot  snapshot,
HeapTuple  tuple,
Buffer userbuf 
)

Definition at line 1412 of file heapam.c.

References BUFFER_LOCK_SHARE, BUFFER_LOCK_UNLOCK, BufferGetPage, CheckForSerializableConflictOut(), HeapTupleSatisfiesVisibility(), InvalidBuffer, ItemIdGetLength, ItemIdIsNormal, ItemPointerGetBlockNumber, ItemPointerGetOffsetNumber, LockBuffer(), PageGetItem, PageGetItemId, PageGetMaxOffsetNumber, PredicateLockTuple(), ReadBuffer(), RelationGetRelid, ReleaseBuffer(), HeapTupleData::t_data, HeapTupleData::t_len, HeapTupleData::t_self, HeapTupleData::t_tableOid, and TestForOldSnapshot().

Referenced by heap_lock_updated_tuple_rec(), heapam_fetch_row_version(), and heapam_tuple_lock().

1416 {
1417  ItemPointer tid = &(tuple->t_self);
1418  ItemId lp;
1419  Buffer buffer;
1420  Page page;
1421  OffsetNumber offnum;
1422  bool valid;
1423 
1424  /*
1425  * Fetch and pin the appropriate page of the relation.
1426  */
1427  buffer = ReadBuffer(relation, ItemPointerGetBlockNumber(tid));
1428 
1429  /*
1430  * Need share lock on buffer to examine tuple commit status.
1431  */
1432  LockBuffer(buffer, BUFFER_LOCK_SHARE);
1433  page = BufferGetPage(buffer);
1434  TestForOldSnapshot(snapshot, relation, page);
1435 
1436  /*
1437  * We'd better check for out-of-range offnum in case of VACUUM since the
1438  * TID was obtained.
1439  */
1440  offnum = ItemPointerGetOffsetNumber(tid);
1441  if (offnum < FirstOffsetNumber || offnum > PageGetMaxOffsetNumber(page))
1442  {
1443  LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
1444  ReleaseBuffer(buffer);
1445  *userbuf = InvalidBuffer;
1446  tuple->t_data = NULL;
1447  return false;
1448  }
1449 
1450  /*
1451  * get the item line pointer corresponding to the requested tid
1452  */
1453  lp = PageGetItemId(page, offnum);
1454 
1455  /*
1456  * Must check for deleted tuple.
1457  */
1458  if (!ItemIdIsNormal(lp))
1459  {
1460  LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
1461  ReleaseBuffer(buffer);
1462  *userbuf = InvalidBuffer;
1463  tuple->t_data = NULL;
1464  return false;
1465  }
1466 
1467  /*
1468  * fill in *tuple fields
1469  */
1470  tuple->t_data = (HeapTupleHeader) PageGetItem(page, lp);
1471  tuple->t_len = ItemIdGetLength(lp);
1472  tuple->t_tableOid = RelationGetRelid(relation);
1473 
1474  /*
1475  * check tuple visibility, then release lock
1476  */
1477  valid = HeapTupleSatisfiesVisibility(tuple, snapshot, buffer);
1478 
1479  if (valid)
1480  PredicateLockTuple(relation, tuple, snapshot);
1481 
1482  CheckForSerializableConflictOut(valid, relation, tuple, buffer, snapshot);
1483 
1484  LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
1485 
1486  if (valid)
1487  {
1488  /*
1489  * All checks passed, so return the tuple as valid. Caller is now
1490  * responsible for releasing the buffer.
1491  */
1492  *userbuf = buffer;
1493 
1494  return true;
1495  }
1496 
1497  /* Tuple failed time qual */
1498  ReleaseBuffer(buffer);
1499  *userbuf = InvalidBuffer;
1500 
1501  return false;
1502 }
#define BUFFER_LOCK_UNLOCK
Definition: bufmgr.h:86
static void TestForOldSnapshot(Snapshot snapshot, Relation relation, Page page)
Definition: bufmgr.h:264
HeapTupleHeaderData * HeapTupleHeader
Definition: htup.h:23
#define InvalidBuffer
Definition: buf.h:25
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3365
#define PageGetMaxOffsetNumber(page)
Definition: bufpage.h:357
void CheckForSerializableConflictOut(bool visible, Relation relation, HeapTuple tuple, Buffer buffer, Snapshot snapshot)
Definition: predicate.c:4057
uint16 OffsetNumber
Definition: off.h:24
HeapTupleHeader t_data
Definition: htup.h:68
#define ItemIdGetLength(itemId)
Definition: itemid.h:59
ItemPointerData t_self
Definition: htup.h:65
uint32 t_len
Definition: htup.h:64
Oid t_tableOid
Definition: htup.h:66
#define BufferGetPage(buffer)
Definition: bufmgr.h:159
#define PageGetItemId(page, offsetNumber)
Definition: bufpage.h:235
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3602
#define ItemIdIsNormal(itemId)
Definition: itemid.h:99
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition: bufmgr.c:596
#define ItemPointerGetOffsetNumber(pointer)
Definition: itemptr.h:117
void PredicateLockTuple(Relation relation, HeapTuple tuple, Snapshot snapshot)
Definition: predicate.c:2548
#define BUFFER_LOCK_SHARE
Definition: bufmgr.h:87
#define ItemPointerGetBlockNumber(pointer)
Definition: itemptr.h:98
int Buffer
Definition: buf.h:23
#define RelationGetRelid(relation)
Definition: rel.h:419
#define PageGetItem(page, itemId)
Definition: bufpage.h:340
Pointer Page
Definition: bufpage.h:78
bool HeapTupleSatisfiesVisibility(HeapTuple tup, Snapshot snapshot, Buffer buffer)

◆ heap_finish_speculative()

void heap_finish_speculative ( Relation  relation,
ItemPointer  tid 
)

Definition at line 5476 of file heapam.c.

References Assert, BUFFER_LOCK_EXCLUSIVE, BufferGetPage, elog, END_CRIT_SECTION, ERROR, HeapTupleHeaderIsSpeculative, ItemIdIsNormal, ItemPointerGetBlockNumber, ItemPointerGetOffsetNumber, LockBuffer(), MarkBufferDirty(), MaxOffsetNumber, xl_heap_confirm::offnum, PageGetItem, PageGetItemId, PageGetMaxOffsetNumber, PageSetLSN, ReadBuffer(), REGBUF_STANDARD, RelationNeedsWAL, SizeOfHeapConfirm, SpecTokenOffsetNumber, START_CRIT_SECTION, StaticAssertStmt, HeapTupleHeaderData::t_ctid, UnlockReleaseBuffer(), XLOG_HEAP_CONFIRM, XLOG_INCLUDE_ORIGIN, XLogBeginInsert(), XLogInsert(), XLogRegisterBuffer(), XLogRegisterData(), and XLogSetRecordFlags().

Referenced by heapam_tuple_complete_speculative().

5477 {
5478  Buffer buffer;
5479  Page page;
5480  OffsetNumber offnum;
5481  ItemId lp = NULL;
5482  HeapTupleHeader htup;
5483 
5484  buffer = ReadBuffer(relation, ItemPointerGetBlockNumber(tid));
5486  page = (Page) BufferGetPage(buffer);
5487 
5488  offnum = ItemPointerGetOffsetNumber(tid);
5489  if (PageGetMaxOffsetNumber(page) >= offnum)
5490  lp = PageGetItemId(page, offnum);
5491 
5492  if (PageGetMaxOffsetNumber(page) < offnum || !ItemIdIsNormal(lp))
5493  elog(ERROR, "invalid lp");
5494 
5495  htup = (HeapTupleHeader) PageGetItem(page, lp);
5496 
5497  /* SpecTokenOffsetNumber should be distinguishable from any real offset */
5499  "invalid speculative token constant");
5500 
5501  /* NO EREPORT(ERROR) from here till changes are logged */
5503 
5505 
5506  MarkBufferDirty(buffer);
5507 
5508  /*
5509  * Replace the speculative insertion token with a real t_ctid, pointing to
5510  * itself like it does on regular tuples.
5511  */
5512  htup->t_ctid = *tid;
5513 
5514  /* XLOG stuff */
5515  if (RelationNeedsWAL(relation))
5516  {
5517  xl_heap_confirm xlrec;
5518  XLogRecPtr recptr;
5519 
5520  xlrec.offnum = ItemPointerGetOffsetNumber(tid);
5521 
5522  XLogBeginInsert();
5523 
5524  /* We want the same filtering on this as on a plain insert */
5526 
5527  XLogRegisterData((char *) &xlrec, SizeOfHeapConfirm);
5528  XLogRegisterBuffer(0, buffer, REGBUF_STANDARD);
5529 
5530  recptr = XLogInsert(RM_HEAP_ID, XLOG_HEAP_CONFIRM);
5531 
5532  PageSetLSN(page, recptr);
5533  }
5534 
5535  END_CRIT_SECTION();
5536 
5537  UnlockReleaseBuffer(buffer);
5538 }
OffsetNumber offnum
Definition: heapam_xlog.h:296
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:1458
void XLogRegisterBuffer(uint8 block_id, Buffer buffer, uint8 flags)
Definition: xloginsert.c:213
HeapTupleHeaderData * HeapTupleHeader
Definition: htup.h:23
#define MaxOffsetNumber
Definition: off.h:28
#define END_CRIT_SECTION()
Definition: miscadmin.h:134
#define HeapTupleHeaderIsSpeculative(tup)
Definition: htup_details.h:429
#define START_CRIT_SECTION()
Definition: miscadmin.h:132
#define XLOG_INCLUDE_ORIGIN
Definition: xlog.h:228
#define BUFFER_LOCK_EXCLUSIVE
Definition: bufmgr.h:88
#define SpecTokenOffsetNumber
Definition: itemptr.h:63
#define PageGetMaxOffsetNumber(page)
Definition: bufpage.h:357
uint16 OffsetNumber
Definition: off.h:24
#define StaticAssertStmt(condition, errmessage)
Definition: c.h:842
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3388
#define ERROR
Definition: elog.h:43
ItemPointerData t_ctid
Definition: htup_details.h:160
#define REGBUF_STANDARD
Definition: xloginsert.h:35
void XLogSetRecordFlags(uint8 flags)
Definition: xloginsert.c:397
#define BufferGetPage(buffer)
Definition: bufmgr.h:159
#define SizeOfHeapConfirm
Definition: heapam_xlog.h:299
#define PageGetItemId(page, offsetNumber)
Definition: bufpage.h:235
void XLogRegisterData(char *data, int len)
Definition: xloginsert.c:323
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:415
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3602
uint64 XLogRecPtr
Definition: xlogdefs.h:21
#define Assert(condition)
Definition: c.h:732
#define ItemIdIsNormal(itemId)
Definition: itemid.h:99
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition: bufmgr.c:596
#define ItemPointerGetOffsetNumber(pointer)
Definition: itemptr.h:117
#define RelationNeedsWAL(relation)
Definition: rel.h:521
#define elog(elevel,...)
Definition: elog.h:226
#define ItemPointerGetBlockNumber(pointer)
Definition: itemptr.h:98
void XLogBeginInsert(void)
Definition: xloginsert.c:120
#define PageSetLSN(page, lsn)
Definition: bufpage.h:368
int Buffer
Definition: buf.h:23
#define PageGetItem(page, itemId)
Definition: bufpage.h:340
Pointer Page
Definition: bufpage.h:78
#define XLOG_HEAP_CONFIRM
Definition: heapam_xlog.h:37

◆ heap_freeze_tuple()

bool heap_freeze_tuple ( HeapTupleHeader  tuple,
TransactionId  relfrozenxid,
TransactionId  relminmxid,
TransactionId  cutoff_xid,
TransactionId  cutoff_multi 
)

Definition at line 6368 of file heapam.c.

References heap_execute_freeze_tuple(), and heap_prepare_freeze_tuple().

Referenced by rewrite_heap_tuple().

6371 {
6373  bool do_freeze;
6374  bool tuple_totally_frozen;
6375 
6376  do_freeze = heap_prepare_freeze_tuple(tuple,
6378  cutoff_xid, cutoff_multi,
6379  &frz, &tuple_totally_frozen);
6380 
6381  /*
6382  * Note that because this is not a WAL-logged operation, we don't need to
6383  * fill in the offset in the freeze record.
6384  */
6385 
6386  if (do_freeze)
6387  heap_execute_freeze_tuple(tuple, &frz);
6388  return do_freeze;
6389 }
bool heap_prepare_freeze_tuple(HeapTupleHeader tuple, TransactionId relfrozenxid, TransactionId relminmxid, TransactionId cutoff_xid, TransactionId cutoff_multi, xl_heap_freeze_tuple *frz, bool *totally_frozen_p)
Definition: heapam.c:6118
void heap_execute_freeze_tuple(HeapTupleHeader tuple, xl_heap_freeze_tuple *frz)
Definition: heapam.c:6347
TransactionId relminmxid
Definition: pg_class.h:126
TransactionId relfrozenxid
Definition: pg_class.h:123

◆ heap_get_latest_tid()

void heap_get_latest_tid ( TableScanDesc  scan,
ItemPointer  tid 
)

Definition at line 1670 of file heapam.c.

References Assert, BUFFER_LOCK_SHARE, BufferGetPage, CheckForSerializableConflictOut(), HEAP_XMAX_INVALID, HeapTupleHeaderGetUpdateXid, HeapTupleHeaderGetXmin, HeapTupleHeaderIndicatesMovedPartitions, HeapTupleHeaderIsOnlyLocked(), HeapTupleSatisfiesVisibility(), InvalidTransactionId, ItemIdGetLength, ItemIdIsNormal, ItemPointerEquals(), ItemPointerGetBlockNumber, ItemPointerGetOffsetNumber, ItemPointerIsValid, LockBuffer(), PageGetItem, PageGetItemId, PageGetMaxOffsetNumber, ReadBuffer(), RelationGetRelid, TableScanDescData::rs_rd, TableScanDescData::rs_snapshot, HeapTupleHeaderData::t_ctid, HeapTupleData::t_data, HeapTupleHeaderData::t_infomask, HeapTupleData::t_len, HeapTupleData::t_self, HeapTupleData::t_tableOid, TestForOldSnapshot(), TransactionIdEquals, TransactionIdIsValid, and UnlockReleaseBuffer().

Referenced by SampleHeapTupleVisible().

1672 {
1673  Relation relation = sscan->rs_rd;
1674  Snapshot snapshot = sscan->rs_snapshot;
1675  ItemPointerData ctid;
1676  TransactionId priorXmax;
1677 
1678  /*
1679  * table_get_latest_tid verified that the passed in tid is valid. Assume
1680  * that t_ctid links are valid however - there shouldn't be invalid ones
1681  * in the table.
1682  */
1683  Assert(ItemPointerIsValid(tid));
1684 
1685  /*
1686  * Loop to chase down t_ctid links. At top of loop, ctid is the tuple we
1687  * need to examine, and *tid is the TID we will return if ctid turns out
1688  * to be bogus.
1689  *
1690  * Note that we will loop until we reach the end of the t_ctid chain.
1691  * Depending on the snapshot passed, there might be at most one visible
1692  * version of the row, but we don't try to optimize for that.
1693  */
1694  ctid = *tid;
1695  priorXmax = InvalidTransactionId; /* cannot check first XMIN */
1696  for (;;)
1697  {
1698  Buffer buffer;
1699  Page page;
1700  OffsetNumber offnum;
1701  ItemId lp;
1702  HeapTupleData tp;
1703  bool valid;
1704 
1705  /*
1706  * Read, pin, and lock the page.
1707  */
1708  buffer = ReadBuffer(relation, ItemPointerGetBlockNumber(&ctid));
1709  LockBuffer(buffer, BUFFER_LOCK_SHARE);
1710  page = BufferGetPage(buffer);
1711  TestForOldSnapshot(snapshot, relation, page);
1712 
1713  /*
1714  * Check for bogus item number. This is not treated as an error
1715  * condition because it can happen while following a t_ctid link. We
1716  * just assume that the prior tid is OK and return it unchanged.
1717  */
1718  offnum = ItemPointerGetOffsetNumber(&ctid);
1719  if (offnum < FirstOffsetNumber || offnum > PageGetMaxOffsetNumber(page))
1720  {
1721  UnlockReleaseBuffer(buffer);
1722  break;
1723  }
1724  lp = PageGetItemId(page, offnum);
1725  if (!ItemIdIsNormal(lp))
1726  {
1727  UnlockReleaseBuffer(buffer);
1728  break;
1729  }
1730 
1731  /* OK to access the tuple */
1732  tp.t_self = ctid;
1733  tp.t_data = (HeapTupleHeader) PageGetItem(page, lp);
1734  tp.t_len = ItemIdGetLength(lp);
1735  tp.t_tableOid = RelationGetRelid(relation);
1736 
1737  /*
1738  * After following a t_ctid link, we might arrive at an unrelated
1739  * tuple. Check for XMIN match.
1740  */
1741  if (TransactionIdIsValid(priorXmax) &&
1743  {
1744  UnlockReleaseBuffer(buffer);
1745  break;
1746  }
1747 
1748  /*
1749  * Check tuple visibility; if visible, set it as the new result
1750  * candidate.
1751  */
1752  valid = HeapTupleSatisfiesVisibility(&tp, snapshot, buffer);
1753  CheckForSerializableConflictOut(valid, relation, &tp, buffer, snapshot);
1754  if (valid)
1755  *tid = ctid;
1756 
1757  /*
1758  * If there's a valid t_ctid link, follow it, else we're done.
1759  */
1760  if ((tp.t_data->t_infomask & HEAP_XMAX_INVALID) ||
1764  {
1765  UnlockReleaseBuffer(buffer);
1766  break;
1767  }
1768 
1769  ctid = tp.t_data->t_ctid;
1770  priorXmax = HeapTupleHeaderGetUpdateXid(tp.t_data);
1771  UnlockReleaseBuffer(buffer);
1772  } /* end of loop */
1773 }
#define HeapTupleHeaderGetUpdateXid(tup)
Definition: htup_details.h:365
#define ItemPointerIsValid(pointer)
Definition: itemptr.h:82
static void TestForOldSnapshot(Snapshot snapshot, Relation relation, Page page)
Definition: bufmgr.h:264
#define TransactionIdEquals(id1, id2)
Definition: transam.h:43
uint32 TransactionId
Definition: c.h:507
HeapTupleHeaderData * HeapTupleHeader
Definition: htup.h:23
bool HeapTupleHeaderIsOnlyLocked(HeapTupleHeader tuple)
#define HeapTupleHeaderIndicatesMovedPartitions(tup)
Definition: htup_details.h:445
#define PageGetMaxOffsetNumber(page)
Definition: bufpage.h:357
void CheckForSerializableConflictOut(bool visible, Relation relation, HeapTuple tuple, Buffer buffer, Snapshot snapshot)
Definition: predicate.c:4057
uint16 OffsetNumber
Definition: off.h:24
HeapTupleHeader t_data
Definition: htup.h:68
#define ItemIdGetLength(itemId)
Definition: itemid.h:59
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3388
#define HEAP_XMAX_INVALID
Definition: htup_details.h:207
ItemPointerData t_ctid
Definition: htup_details.h:160
ItemPointerData t_self
Definition: htup.h:65
uint32 t_len
Definition: htup.h:64
#define InvalidTransactionId
Definition: transam.h:31
Oid t_tableOid
Definition: htup.h:66
#define BufferGetPage(buffer)
Definition: bufmgr.h:159
#define PageGetItemId(page, offsetNumber)
Definition: bufpage.h:235
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3602
#define Assert(condition)
Definition: c.h:732
#define ItemIdIsNormal(itemId)
Definition: itemid.h:99
#define HeapTupleHeaderGetXmin(tup)
Definition: htup_details.h:313
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition: bufmgr.c:596
#define ItemPointerGetOffsetNumber(pointer)
Definition: itemptr.h:117
bool ItemPointerEquals(ItemPointer pointer1, ItemPointer pointer2)
Definition: itemptr.c:29
#define BUFFER_LOCK_SHARE
Definition: bufmgr.h:87
#define ItemPointerGetBlockNumber(pointer)
Definition: itemptr.h:98
#define TransactionIdIsValid(xid)
Definition: transam.h:41
int Buffer
Definition: buf.h:23
#define RelationGetRelid(relation)
Definition: rel.h:419
#define PageGetItem(page, itemId)
Definition: bufpage.h:340
Pointer Page
Definition: bufpage.h:78
bool HeapTupleSatisfiesVisibility(HeapTuple tup, Snapshot snapshot, Buffer buffer)

◆ heap_get_root_tuples()

void heap_get_root_tuples ( Page  page,
OffsetNumber root_offsets 
)

Definition at line 745 of file pruneheap.c.

References Assert, FirstOffsetNumber, HeapTupleHeaderGetUpdateXid, HeapTupleHeaderGetXmin, HeapTupleHeaderIndicatesMovedPartitions, HeapTupleHeaderIsHeapOnly, HeapTupleHeaderIsHotUpdated, InvalidTransactionId, ItemIdGetRedirect, ItemIdIsDead, ItemIdIsNormal, ItemIdIsRedirected, ItemIdIsUsed, ItemPointerGetOffsetNumber, MaxHeapTuplesPerPage, MemSet, OffsetNumberNext, PageGetItem, PageGetItemId, PageGetMaxOffsetNumber, HeapTupleHeaderData::t_ctid, TransactionIdEquals, and TransactionIdIsValid.

Referenced by heapam_index_build_range_scan(), and heapam_index_validate_scan().

746 {
747  OffsetNumber offnum,
748  maxoff;
749 
750  MemSet(root_offsets, 0, MaxHeapTuplesPerPage * sizeof(OffsetNumber));
751 
752  maxoff = PageGetMaxOffsetNumber(page);
753  for (offnum = FirstOffsetNumber; offnum <= maxoff; offnum = OffsetNumberNext(offnum))
754  {
755  ItemId lp = PageGetItemId(page, offnum);
756  HeapTupleHeader htup;
757  OffsetNumber nextoffnum;
758  TransactionId priorXmax;
759 
760  /* skip unused and dead items */
761  if (!ItemIdIsUsed(lp) || ItemIdIsDead(lp))
762  continue;
763 
764  if (ItemIdIsNormal(lp))
765  {
766  htup = (HeapTupleHeader) PageGetItem(page, lp);
767 
768  /*
769  * Check if this tuple is part of a HOT-chain rooted at some other
770  * tuple. If so, skip it for now; we'll process it when we find
771  * its root.
772  */
773  if (HeapTupleHeaderIsHeapOnly(htup))
774  continue;
775 
776  /*
777  * This is either a plain tuple or the root of a HOT-chain.
778  * Remember it in the mapping.
779  */
780  root_offsets[offnum - 1] = offnum;
781 
782  /* If it's not the start of a HOT-chain, we're done with it */
783  if (!HeapTupleHeaderIsHotUpdated(htup))
784  continue;
785 
786  /* Set up to scan the HOT-chain */
787  nextoffnum = ItemPointerGetOffsetNumber(&htup->t_ctid);
788  priorXmax = HeapTupleHeaderGetUpdateXid(htup);
789  }
790  else
791  {
792  /* Must be a redirect item. We do not set its root_offsets entry */
794  /* Set up to scan the HOT-chain */
795  nextoffnum = ItemIdGetRedirect(lp);
796  priorXmax = InvalidTransactionId;
797  }
798 
799  /*
800  * Now follow the HOT-chain and collect other tuples in the chain.
801  *
802  * Note: Even though this is a nested loop, the complexity of the
803  * function is O(N) because a tuple in the page should be visited not
804  * more than twice, once in the outer loop and once in HOT-chain
805  * chases.
806  */
807  for (;;)
808  {
809  lp = PageGetItemId(page, nextoffnum);
810 
811  /* Check for broken chains */
812  if (!ItemIdIsNormal(lp))
813  break;
814 
815  htup = (HeapTupleHeader) PageGetItem(page, lp);
816 
817  if (TransactionIdIsValid(priorXmax) &&
818  !TransactionIdEquals(priorXmax, HeapTupleHeaderGetXmin(htup)))
819  break;
820 
821  /* Remember the root line pointer for this item */
822  root_offsets[nextoffnum - 1] = offnum;
823 
824  /* Advance to next chain member, if any */
825  if (!HeapTupleHeaderIsHotUpdated(htup))
826  break;
827 
828  /* HOT implies it can't have moved to different partition */
830 
831  nextoffnum = ItemPointerGetOffsetNumber(&htup->t_ctid);
832  priorXmax = HeapTupleHeaderGetUpdateXid(htup);
833  }
834  }
835 }
#define HeapTupleHeaderGetUpdateXid(tup)
Definition: htup_details.h:365
#define ItemIdIsRedirected(itemId)
Definition: itemid.h:106
#define TransactionIdEquals(id1, id2)
Definition: transam.h:43
uint32 TransactionId
Definition: c.h:507
HeapTupleHeaderData * HeapTupleHeader
Definition: htup.h:23
#define ItemIdGetRedirect(itemId)
Definition: itemid.h:78
#define ItemIdIsUsed(itemId)
Definition: itemid.h:92
#define MaxHeapTuplesPerPage
Definition: htup_details.h:574
#define MemSet(start, val, len)
Definition: c.h:955
#define HeapTupleHeaderIndicatesMovedPartitions(tup)
Definition: htup_details.h:445
#define ItemIdIsDead(itemId)
Definition: itemid.h:113
#define PageGetMaxOffsetNumber(page)
Definition: bufpage.h:357
uint16 OffsetNumber
Definition: off.h:24
#define HeapTupleHeaderIsHeapOnly(tup)
Definition: htup_details.h:501
ItemPointerData t_ctid
Definition: htup_details.h:160
#define FirstOffsetNumber
Definition: off.h:27
#define InvalidTransactionId
Definition: transam.h:31
#define HeapTupleHeaderIsHotUpdated(tup)
Definition: htup_details.h:484
#define PageGetItemId(page, offsetNumber)
Definition: bufpage.h:235
#define Assert(condition)
Definition: c.h:732
#define ItemIdIsNormal(itemId)
Definition: itemid.h:99
#define HeapTupleHeaderGetXmin(tup)
Definition: htup_details.h:313
#define OffsetNumberNext(offsetNumber)
Definition: off.h:52
#define ItemPointerGetOffsetNumber(pointer)
Definition: itemptr.h:117
#define TransactionIdIsValid(xid)
Definition: transam.h:41
#define PageGetItem(page, itemId)
Definition: bufpage.h:340

◆ heap_getnext()

HeapTuple heap_getnext ( TableScanDesc  scan,
ScanDirection  direction 
)

Definition at line 1290 of file heapam.c.

References ereport, errcode(), errmsg_internal(), ERROR, GetHeapamTableAmRoutine(), HEAPDEBUG_1, HEAPDEBUG_2, HEAPDEBUG_3, heapgettup(), heapgettup_pagemode(), pgstat_count_heap_getnext, RelationData::rd_tableam, HeapScanDescData::rs_base, HeapScanDescData::rs_ctup, TableScanDescData::rs_flags, TableScanDescData::rs_key, TableScanDescData::rs_nkeys, TableScanDescData::rs_rd, SO_ALLOW_PAGEMODE, HeapTupleData::t_data, and unlikely.

Referenced by AlterTableMoveAll(), AlterTableSpaceOptions(), boot_openrel(), check_db_file_conflict(), createdb(), do_autovacuum(), DropSetting(), DropTableSpace(), find_typed_table_dependencies(), get_all_vacuum_rels(), get_database_list(), get_subscription_list(), get_tables_to_cluster(), get_tablespace_name(), get_tablespace_oid(), GetAllTablesPublicationRelations(), getRelationsInNamespace(), gettype(), heapam_index_build_range_scan(), heapam_index_validate_scan(), index_update_stats(), objectsInSchemaToOids(), pgrowlocks(), pgstat_collect_oids(), pgstat_heap(), ReindexMultipleTables(), remove_dbtablespaces(), RemoveConversionById(), RemoveSubscriptionRel(), RenameTableSpace(), ThereIsAtLeastOneRole(), and vac_truncate_clog().

1291 {
1292  HeapScanDesc scan = (HeapScanDesc) sscan;
1293 
1294  /*
1295  * This is still widely used directly, without going through table AM, so
1296  * add a safety check. It's possible we should, at a later point,
1297  * downgrade this to an assert. The reason for checking the AM routine,
1298  * rather than the AM oid, is that this allows to write regression tests
1299  * that create another AM reusing the heap handler.
1300  */
1301  if (unlikely(sscan->rs_rd->rd_tableam != GetHeapamTableAmRoutine()))
1302  ereport(ERROR,
1303  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1304  errmsg_internal("only heap AM is supported")));
1305 
1306  /* Note: no locking manipulations needed */
1307 
1308  HEAPDEBUG_1; /* heap_getnext( info ) */
1309 
1310  if (scan->rs_base.rs_flags & SO_ALLOW_PAGEMODE)
1311  heapgettup_pagemode(scan, direction,
1312  scan->rs_base.rs_nkeys, scan->rs_base.rs_key);
1313  else
1314  heapgettup(scan, direction,
1315  scan->rs_base.rs_nkeys, scan->rs_base.rs_key);
1316 
1317  if (scan->rs_ctup.t_data == NULL)
1318  {
1319  HEAPDEBUG_2; /* heap_getnext returning EOS */
1320  return NULL;
1321  }
1322 
1323  /*
1324  * if we get here it means we have a new current scan tuple, so point to
1325  * the proper return buffer and return the tuple.
1326  */
1327  HEAPDEBUG_3; /* heap_getnext returning tuple */
1328 
1330 
1331  return &scan->rs_ctup;
1332 }
TableScanDescData rs_base
Definition: heapam.h:48
int errcode(int sqlerrcode)
Definition: elog.c:570
uint32 rs_flags
Definition: relscan.h:43
#define HEAPDEBUG_2
Definition: heapam.c:1284
struct HeapScanDescData * HeapScanDesc
Definition: heapam.h:72
HeapTupleData rs_ctup
Definition: heapam.h:65
HeapTupleHeader t_data
Definition: htup.h:68
#define ERROR
Definition: elog.h:43
struct ScanKeyData * rs_key
Definition: relscan.h:37
#define ereport(elevel, rest)
Definition: elog.h:141
#define HEAPDEBUG_1
Definition: heapam.c:1283
static void heapgettup(HeapScanDesc scan, ScanDirection dir, int nkeys, ScanKey key)
Definition: heapam.c:487
int errmsg_internal(const char *fmt,...)
Definition: elog.c:814
#define HEAPDEBUG_3
Definition: heapam.c:1285
Relation rs_rd
Definition: relscan.h:34
#define unlikely(x)
Definition: c.h:208
#define pgstat_count_heap_getnext(rel)
Definition: pgstat.h:1363
static void heapgettup_pagemode(HeapScanDesc scan, ScanDirection dir, int nkeys, ScanKey key)
Definition: heapam.c:801
const TableAmRoutine * GetHeapamTableAmRoutine(void)

◆ heap_getnextslot()

bool heap_getnextslot ( TableScanDesc  sscan,
ScanDirection  direction,
struct TupleTableSlot slot 
)

Definition at line 1349 of file heapam.c.

References ExecClearTuple(), ExecStoreBufferHeapTuple(), HEAPAMSLOTDEBUG_1, HEAPAMSLOTDEBUG_2, HEAPAMSLOTDEBUG_3, heapgettup(), heapgettup_pagemode(), pgstat_count_heap_getnext, HeapScanDescData::rs_base, HeapScanDescData::rs_cbuf, HeapScanDescData::rs_ctup, TableScanDescData::rs_flags, TableScanDescData::rs_key, TableScanDescData::rs_nkeys, TableScanDescData::rs_rd, SO_ALLOW_PAGEMODE, and HeapTupleData::t_data.

Referenced by SampleHeapTupleVisible().

1350 {
1351  HeapScanDesc scan = (HeapScanDesc) sscan;
1352 
1353  /* Note: no locking manipulations needed */
1354 
1355  HEAPAMSLOTDEBUG_1; /* heap_getnextslot( info ) */
1356 
1357  if (sscan->rs_flags & SO_ALLOW_PAGEMODE)
1358  heapgettup_pagemode(scan, direction, sscan->rs_nkeys, sscan->rs_key);
1359  else
1360  heapgettup(scan, direction, sscan->rs_nkeys, sscan->rs_key);
1361 
1362  if (scan->rs_ctup.t_data == NULL)
1363  {
1364  HEAPAMSLOTDEBUG_2; /* heap_getnextslot returning EOS */
1365  ExecClearTuple(slot);
1366  return false;
1367  }
1368 
1369  /*
1370  * if we get here it means we have a new current scan tuple, so point to
1371  * the proper return buffer and return the tuple.
1372  */
1373  HEAPAMSLOTDEBUG_3; /* heap_getnextslot returning tuple */
1374 
1376 
1377  ExecStoreBufferHeapTuple(&scan->rs_ctup, slot,
1378  scan->rs_cbuf);
1379  return true;
1380 }
#define HEAPAMSLOTDEBUG_2
Definition: heapam.c:1344
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:426
#define HEAPAMSLOTDEBUG_1
Definition: heapam.c:1343
TableScanDescData rs_base
Definition: heapam.h:48
uint32 rs_flags
Definition: relscan.h:43
struct HeapScanDescData * HeapScanDesc
Definition: heapam.h:72
HeapTupleData rs_ctup
Definition: heapam.h:65
HeapTupleHeader t_data
Definition: htup.h:68
struct ScanKeyData * rs_key
Definition: relscan.h:37
static void heapgettup(HeapScanDesc scan, ScanDirection dir, int nkeys, ScanKey key)
Definition: heapam.c:487
TupleTableSlot * ExecStoreBufferHeapTuple(HeapTuple tuple, TupleTableSlot *slot, Buffer buffer)
Definition: execTuples.c:1357
Buffer rs_cbuf
Definition: heapam.h:59
Relation rs_rd
Definition: relscan.h:34
#define HEAPAMSLOTDEBUG_3
Definition: heapam.c:1345
#define pgstat_count_heap_getnext(rel)
Definition: pgstat.h:1363
static void heapgettup_pagemode(HeapScanDesc scan, ScanDirection dir, int nkeys, ScanKey key)
Definition: heapam.c:801

◆ heap_hot_search_buffer()

bool heap_hot_search_buffer ( ItemPointer  tid,
Relation  relation,
Buffer  buffer,
Snapshot  snapshot,
HeapTuple  heapTuple,
bool all_dead,
bool  first_call 
)

Definition at line 1526 of file heapam.c.

References Assert, BufferGetBlockNumber(), BufferGetPage, CheckForSerializableConflictOut(), HeapTupleHeaderGetUpdateXid, HeapTupleHeaderGetXmin, HeapTupleIsHeapOnly, HeapTupleIsHotUpdated, HeapTupleIsSurelyDead(), HeapTupleSatisfiesVisibility(), InvalidTransactionId, ItemIdGetLength, ItemIdGetRedirect, ItemIdIsNormal, ItemIdIsRedirected, ItemPointerGetBlockNumber, ItemPointerGetOffsetNumber, ItemPointerSet, ItemPointerSetOffsetNumber, PageGetItem, PageGetItemId, PageGetMaxOffsetNumber, PredicateLockTuple(), RecentGlobalXmin, RelationGetRelid, skip, HeapTupleHeaderData::t_ctid, HeapTupleData::t_data, HeapTupleData::t_len, HeapTupleData::t_self, HeapTupleData::t_tableOid, TransactionIdEquals, and TransactionIdIsValid.

Referenced by heapam_index_fetch_tuple(), and heapam_scan_bitmap_next_block().

1529 {
1530  Page dp = (Page) BufferGetPage(buffer);
1531  TransactionId prev_xmax = InvalidTransactionId;
1532  BlockNumber blkno;
1533  OffsetNumber offnum;
1534  bool at_chain_start;
1535  bool valid;
1536  bool skip;
1537 
1538  /* If this is not the first call, previous call returned a (live!) tuple */
1539  if (all_dead)
1540  *all_dead = first_call;
1541 
1542  blkno = ItemPointerGetBlockNumber(tid);
1543  offnum = ItemPointerGetOffsetNumber(tid);
1544  at_chain_start = first_call;
1545  skip = !first_call;
1546 
1548  Assert(BufferGetBlockNumber(buffer) == blkno);
1549 
1550  /* Scan through possible multiple members of HOT-chain */
1551  for (;;)
1552  {
1553  ItemId lp;
1554 
1555  /* check for bogus TID */
1556  if (offnum < FirstOffsetNumber || offnum > PageGetMaxOffsetNumber(dp))
1557  break;
1558 
1559  lp = PageGetItemId(dp, offnum);
1560 
1561  /* check for unused, dead, or redirected items */
1562  if (!ItemIdIsNormal(lp))
1563  {
1564  /* We should only see a redirect at start of chain */
1565  if (ItemIdIsRedirected(lp) && at_chain_start)
1566  {
1567  /* Follow the redirect */
1568  offnum = ItemIdGetRedirect(lp);
1569  at_chain_start = false;
1570  continue;
1571  }
1572  /* else must be end of chain */
1573  break;
1574  }
1575 
1576  /*
1577  * Update heapTuple to point to the element of the HOT chain we're
1578  * currently investigating. Having t_self set correctly is important
1579  * because the SSI checks and the *Satisfies routine for historical
1580  * MVCC snapshots need the correct tid to decide about the visibility.
1581  */
1582  heapTuple->t_data = (HeapTupleHeader) PageGetItem(dp, lp);
1583  heapTuple->t_len = ItemIdGetLength(lp);
1584  heapTuple->t_tableOid = RelationGetRelid(relation);
1585  ItemPointerSet(&heapTuple->t_self, blkno, offnum);
1586 
1587  /*
1588  * Shouldn't see a HEAP_ONLY tuple at chain start.
1589  */
1590  if (at_chain_start && HeapTupleIsHeapOnly(heapTuple))
1591  break;
1592 
1593  /*
1594  * The xmin should match the previous xmax value, else chain is
1595  * broken.
1596  */
1597  if (TransactionIdIsValid(prev_xmax) &&
1598  !TransactionIdEquals(prev_xmax,
1599  HeapTupleHeaderGetXmin(heapTuple->t_data)))
1600  break;
1601 
1602  /*
1603  * When first_call is true (and thus, skip is initially false) we'll
1604  * return the first tuple we find. But on later passes, heapTuple
1605  * will initially be pointing to the tuple we returned last time.
1606  * Returning it again would be incorrect (and would loop forever), so
1607  * we skip it and return the next match we find.
1608  */
1609  if (!skip)
1610  {
1611  /* If it's visible per the snapshot, we must return it */
1612  valid = HeapTupleSatisfiesVisibility(heapTuple, snapshot, buffer);
1613  CheckForSerializableConflictOut(valid, relation, heapTuple,
1614  buffer, snapshot);
1615 
1616  if (valid)
1617  {
1618  ItemPointerSetOffsetNumber(tid, offnum);
1619  PredicateLockTuple(relation, heapTuple, snapshot);
1620  if (all_dead)
1621  *all_dead = false;
1622  return true;
1623  }
1624  }
1625  skip = false;
1626 
1627  /*
1628  * If we can't see it, maybe no one else can either. At caller
1629  * request, check whether all chain members are dead to all
1630  * transactions.
1631  *
1632  * Note: if you change the criterion here for what is "dead", fix the
1633  * planner's get_actual_variable_range() function to match.
1634  */
1635  if (all_dead && *all_dead &&
1637  *all_dead = false;
1638 
1639  /*
1640  * Check to see if HOT chain continues past this tuple; if so fetch
1641  * the next offnum and loop around.
1642  */
1643  if (HeapTupleIsHotUpdated(heapTuple))
1644  {
1646  blkno);
1647  offnum = ItemPointerGetOffsetNumber(&heapTuple->t_data->t_ctid);
1648  at_chain_start = false;
1649  prev_xmax = HeapTupleHeaderGetUpdateXid(heapTuple->t_data);
1650  }
1651  else
1652  break; /* end of chain */
1653  }
1654 
1655  return false;
1656 }
#define HeapTupleHeaderGetUpdateXid(tup)
Definition: htup_details.h:365
#define ItemIdIsRedirected(itemId)
Definition: itemid.h:106
#define TransactionIdEquals(id1, id2)
Definition: transam.h:43
uint32 TransactionId
Definition: c.h:507
HeapTupleHeaderData * HeapTupleHeader
Definition: htup.h:23
#define ItemIdGetRedirect(itemId)
Definition: itemid.h:78
uint32 BlockNumber
Definition: block.h:31
#define PageGetMaxOffsetNumber(page)
Definition: bufpage.h:357
void CheckForSerializableConflictOut(bool visible, Relation relation, HeapTuple tuple, Buffer buffer, Snapshot snapshot)
Definition: predicate.c:4057
static const char *const skip[]
Definition: pg_checksums.c:99
uint16 OffsetNumber
Definition: off.h:24
HeapTupleHeader t_data
Definition: htup.h:68
#define HeapTupleIsHotUpdated(tuple)
Definition: htup_details.h:676
#define ItemIdGetLength(itemId)
Definition: itemid.h:59
ItemPointerData t_ctid
Definition: htup_details.h:160
ItemPointerData t_self
Definition: htup.h:65
uint32 t_len
Definition: htup.h:64
TransactionId RecentGlobalXmin
Definition: snapmgr.c:168
#define InvalidTransactionId
Definition: transam.h:31
Oid t_tableOid
Definition: htup.h:66
#define BufferGetPage(buffer)
Definition: bufmgr.h:159
#define PageGetItemId(page, offsetNumber)
Definition: bufpage.h:235
bool HeapTupleIsSurelyDead(HeapTuple htup, TransactionId OldestXmin)
#define HeapTupleIsHeapOnly(tuple)
Definition: htup_details.h:685
#define Assert(condition)
Definition: c.h:732
#define ItemIdIsNormal(itemId)
Definition: itemid.h:99
#define HeapTupleHeaderGetXmin(tup)
Definition: htup_details.h:313
#define ItemPointerGetOffsetNumber(pointer)
Definition: itemptr.h:117
void PredicateLockTuple(Relation relation, HeapTuple tuple, Snapshot snapshot)
Definition: predicate.c:2548
#define ItemPointerSetOffsetNumber(pointer, offsetNumber)
Definition: itemptr.h:148
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:2613
#define ItemPointerGetBlockNumber(pointer)
Definition: itemptr.h:98
#define TransactionIdIsValid(xid)
Definition: transam.h:41
#define RelationGetRelid(relation)
Definition: rel.h:419
#define PageGetItem(page, itemId)
Definition: bufpage.h:340
Pointer Page
Definition: bufpage.h:78
#define ItemPointerSet(pointer, blockNumber, offNum)
Definition: itemptr.h:127
bool HeapTupleSatisfiesVisibility(HeapTuple tup, Snapshot snapshot, Buffer buffer)

◆ heap_inplace_update()

void heap_inplace_update ( Relation  relation,
HeapTuple  tuple 
)

Definition at line 5707 of file heapam.c.

References BUFFER_LOCK_EXCLUSIVE, BufferGetPage, CacheInvalidateHeapTuple(), elog, END_CRIT_SECTION, ereport, errcode(), errmsg(), ERROR, IsBootstrapProcessingMode, IsInParallelMode(), ItemIdGetLength, ItemIdIsNormal, ItemPointerGetBlockNumber, ItemPointerGetOffsetNumber, LockBuffer(), MarkBufferDirty(), xl_heap_inplace::offnum, PageGetItem, PageGetItemId, PageGetMaxOffsetNumber, PageSetLSN, ReadBuffer(), REGBUF_STANDARD, RelationNeedsWAL, SizeOfHeapInplace, START_CRIT_SECTION, HeapTupleData::t_data, HeapTupleHeaderData::t_hoff, HeapTupleData::t_len, HeapTupleData::t_self, UnlockReleaseBuffer(), XLOG_HEAP_INPLACE, XLogBeginInsert(), XLogInsert(), XLogRegisterBufData(), XLogRegisterBuffer(), and XLogRegisterData().

Referenced by create_toast_table(), index_set_state_flags(), index_update_stats(), vac_update_datfrozenxid(), and vac_update_relstats().

5708 {
5709  Buffer buffer;
5710  Page page;
5711  OffsetNumber offnum;
5712  ItemId lp = NULL;
5713  HeapTupleHeader htup;
5714  uint32 oldlen;
5715  uint32 newlen;
5716 
5717  /*
5718  * For now, parallel operations are required to be strictly read-only.
5719  * Unlike a regular update, this should never create a combo CID, so it
5720  * might be possible to relax this restriction, but not without more
5721  * thought and testing. It's not clear that it would be useful, anyway.
5722  */
5723  if (IsInParallelMode())
5724  ereport(ERROR,
5725  (errcode(ERRCODE_INVALID_TRANSACTION_STATE),
5726  errmsg("cannot update tuples during a parallel operation")));
5727 
5728  buffer = ReadBuffer(relation, ItemPointerGetBlockNumber(&(tuple->t_self)));
5730  page = (Page) BufferGetPage(buffer);
5731 
5732  offnum = ItemPointerGetOffsetNumber(&(tuple->t_self));
5733  if (PageGetMaxOffsetNumber(page) >= offnum)
5734  lp = PageGetItemId(page, offnum);
5735 
5736  if (PageGetMaxOffsetNumber(page) < offnum || !ItemIdIsNormal(lp))
5737  elog(ERROR, "invalid lp");
5738 
5739  htup = (HeapTupleHeader) PageGetItem(page, lp);
5740 
5741  oldlen = ItemIdGetLength(lp) - htup->t_hoff;
5742  newlen = tuple->t_len - tuple->t_data->t_hoff;
5743  if (oldlen != newlen || htup->t_hoff != tuple->t_data->t_hoff)
5744  elog(ERROR, "wrong tuple length");
5745 
5746  /* NO EREPORT(ERROR) from here till changes are logged */
5748 
5749  memcpy((char *) htup + htup->t_hoff,
5750  (char *) tuple->t_data + tuple->t_data->t_hoff,
5751  newlen);
5752 
5753  MarkBufferDirty(buffer);
5754 
5755  /* XLOG stuff */
5756  if (RelationNeedsWAL(relation))
5757  {
5758  xl_heap_inplace xlrec;
5759  XLogRecPtr recptr;
5760 
5761  xlrec.offnum = ItemPointerGetOffsetNumber(&tuple->t_self);
5762 
5763  XLogBeginInsert();
5764  XLogRegisterData((char *) &xlrec, SizeOfHeapInplace);
5765 
5766  XLogRegisterBuffer(0, buffer, REGBUF_STANDARD);
5767  XLogRegisterBufData(0, (char *) htup + htup->t_hoff, newlen);
5768 
5769  /* inplace updates aren't decoded atm, don't log the origin */
5770 
5771  recptr = XLogInsert(RM_HEAP_ID, XLOG_HEAP_INPLACE);
5772 
5773  PageSetLSN(page, recptr);
5774  }
5775 
5776  END_CRIT_SECTION();
5777 
5778  UnlockReleaseBuffer(buffer);
5779 
5780  /*
5781  * Send out shared cache inval if necessary. Note that because we only
5782  * pass the new version of the tuple, this mustn't be used for any
5783  * operations that could change catcache lookup keys. But we aren't
5784  * bothering with index updates either, so that's true a fortiori.
5785  */
5787  CacheInvalidateHeapTuple(relation, tuple, NULL);
5788 }
void XLogRegisterBufData(uint8 block_id, char *data, int len)
Definition: xloginsert.c:361
void CacheInvalidateHeapTuple(Relation relation, HeapTuple tuple, HeapTuple newtuple)
Definition: inval.c:1114
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:1458
void XLogRegisterBuffer(uint8 block_id, Buffer buffer, uint8 flags)
Definition: xloginsert.c:213
HeapTupleHeaderData * HeapTupleHeader
Definition: htup.h:23
#define END_CRIT_SECTION()
Definition: miscadmin.h:134
#define SizeOfHeapInplace
Definition: heapam_xlog.h:308
#define START_CRIT_SECTION()
Definition: miscadmin.h:132
int errcode(int sqlerrcode)
Definition: elog.c:570
#define BUFFER_LOCK_EXCLUSIVE
Definition: bufmgr.h:88
#define PageGetMaxOffsetNumber(page)
Definition: bufpage.h:357
uint16 OffsetNumber
Definition: off.h:24
HeapTupleHeader t_data
Definition: htup.h:68
#define ItemIdGetLength(itemId)
Definition: itemid.h:59
bool IsInParallelMode(void)
Definition: xact.c:994
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3388
#define ERROR
Definition: elog.h:43
ItemPointerData t_self
Definition: htup.h:65
uint32 t_len
Definition: htup.h:64
#define REGBUF_STANDARD
Definition: xloginsert.h:35
unsigned int uint32
Definition: c.h:358
#define BufferGetPage(buffer)
Definition: bufmgr.h:159
#define ereport(elevel, rest)
Definition: elog.h:141
#define PageGetItemId(page, offsetNumber)
Definition: bufpage.h:235
void XLogRegisterData(char *data, int len)
Definition: xloginsert.c:323
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:415
OffsetNumber offnum
Definition: heapam_xlog.h:304
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3602
uint64 XLogRecPtr
Definition: xlogdefs.h:21
#define ItemIdIsNormal(itemId)
Definition: itemid.h:99
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition: bufmgr.c:596
#define ItemPointerGetOffsetNumber(pointer)
Definition: itemptr.h:117
#define XLOG_HEAP_INPLACE
Definition: heapam_xlog.h:39
#define RelationNeedsWAL(relation)
Definition: rel.h:521
#define IsBootstrapProcessingMode()
Definition: miscadmin.h:374
int errmsg(const char *fmt,...)
Definition: elog.c:784
#define elog(elevel,...)
Definition: elog.h:226
#define ItemPointerGetBlockNumber(pointer)
Definition: itemptr.h:98
void XLogBeginInsert(void)
Definition: xloginsert.c:120
#define PageSetLSN(page, lsn)
Definition: bufpage.h:368
int Buffer
Definition: buf.h:23
#define PageGetItem(page, itemId)
Definition: bufpage.h:340
Pointer Page
Definition: bufpage.h:78

◆ heap_insert()

void heap_insert ( Relation  relation,
HeapTuple  tup,
CommandId  cid,
int  options,
BulkInsertState  bistate 
)

Definition at line 1868 of file heapam.c.

References Assert, BufferGetBlockNumber(), BufferGetPage, CacheInvalidateHeapTuple(), CheckForSerializableConflictIn(), END_CRIT_SECTION, FirstOffsetNumber, xl_heap_insert::flags, GetCurrentTransactionId(), heap_freetuple(), HEAP_INSERT_NO_LOGICAL, HEAP_INSERT_SKIP_WAL, HEAP_INSERT_SPECULATIVE, heap_prepare_insert(), InvalidBuffer, ItemPointerGetBlockNumber, ItemPointerGetOffsetNumber, log_heap_new_cid(), MarkBufferDirty(), xl_heap_insert::offnum, PageClearAllVisible, PageGetMaxOffsetNumber, PageIsAllVisible, PageSetLSN, pgstat_count_heap_insert(), REGBUF_KEEP_DATA, REGBUF_STANDARD, REGBUF_WILL_INIT, RelationGetBufferForTuple(), RelationIsAccessibleInLogicalDecoding, RelationIsLogicallyLogged, RelationNeedsWAL, RelationPutHeapTuple(), ReleaseBuffer(), SizeOfHeapHeader, SizeOfHeapInsert, SizeofHeapTupleHeader, START_CRIT_SECTION, HeapTupleData::t_data, xl_heap_header::t_hoff, HeapTupleHeaderData::t_hoff, xl_heap_header::t_infomask, HeapTupleHeaderData::t_infomask, xl_heap_header::t_infomask2, HeapTupleHeaderData::t_infomask2, HeapTupleData::t_len, HeapTupleData::t_self, UnlockReleaseBuffer(), visibilitymap_clear(), VISIBILITYMAP_VALID_BITS, XLH_INSERT_ALL_VISIBLE_CLEARED, XLH_INSERT_CONTAINS_NEW_TUPLE, XLH_INSERT_IS_SPECULATIVE, XLOG_HEAP_INIT_PAGE, XLOG_HEAP_INSERT, XLOG_INCLUDE_ORIGIN, XLogBeginInsert(), XLogInsert(), XLogRegisterBufData(), XLogRegisterBuffer(), XLogRegisterData(), and XLogSetRecordFlags().

Referenced by heapam_tuple_insert(), heapam_tuple_insert_speculative(), simple_heap_insert(), and toast_save_datum().

1870 {
1872  HeapTuple heaptup;
1873  Buffer buffer;
1874  Buffer vmbuffer = InvalidBuffer;
1875  bool all_visible_cleared = false;
1876 
1877  /*
1878  * Fill in tuple header fields and toast the tuple if necessary.
1879  *
1880  * Note: below this point, heaptup is the data we actually intend to store
1881  * into the relation; tup is the caller's original untoasted data.
1882  */
1883  heaptup = heap_prepare_insert(relation, tup, xid, cid, options);
1884 
1885  /*
1886  * Find buffer to insert this tuple into. If the page is all visible,
1887  * this will also pin the requisite visibility map page.
1888  */
1889  buffer = RelationGetBufferForTuple(relation, heaptup->t_len,
1890  InvalidBuffer, options, bistate,
1891  &vmbuffer, NULL);
1892 
1893  /*
1894  * We're about to do the actual insert -- but check for conflict first, to
1895  * avoid possibly having to roll back work we've just done.
1896  *
1897  * This is safe without a recheck as long as there is no possibility of
1898  * another process scanning the page between this check and the insert
1899  * being visible to the scan (i.e., an exclusive buffer content lock is
1900  * continuously held from this point until the tuple insert is visible).
1901  *
1902  * For a heap insert, we only need to check for table-level SSI locks. Our
1903  * new tuple can't possibly conflict with existing tuple locks, and heap
1904  * page locks are only consolidated versions of tuple locks; they do not
1905  * lock "gaps" as index page locks do. So we don't need to specify a
1906  * buffer when making the call, which makes for a faster check.
1907  */
1909 
1910  /* NO EREPORT(ERROR) from here till changes are logged */
1912 
1913  RelationPutHeapTuple(relation, buffer, heaptup,
1914  (options & HEAP_INSERT_SPECULATIVE) != 0);
1915 
1916  if (PageIsAllVisible(BufferGetPage(buffer)))
1917  {
1918  all_visible_cleared = true;
1920  visibilitymap_clear(relation,
1921  ItemPointerGetBlockNumber(&(heaptup->t_self)),
1922  vmbuffer, VISIBILITYMAP_VALID_BITS);
1923  }
1924 
1925  /*
1926  * XXX Should we set PageSetPrunable on this page ?
1927  *
1928  * The inserting transaction may eventually abort thus making this tuple
1929  * DEAD and hence available for pruning. Though we don't want to optimize
1930  * for aborts, if no other tuple in this page is UPDATEd/DELETEd, the
1931  * aborted tuple will never be pruned until next vacuum is triggered.
1932  *
1933  * If you do add PageSetPrunable here, add it in heap_xlog_insert too.
1934  */
1935 
1936  MarkBufferDirty(buffer);
1937 
1938  /* XLOG stuff */
1939  if (!(options & HEAP_INSERT_SKIP_WAL) && RelationNeedsWAL(relation))
1940  {
1941  xl_heap_insert xlrec;
1942  xl_heap_header xlhdr;
1943  XLogRecPtr recptr;
1944  Page page = BufferGetPage(buffer);
1945  uint8 info = XLOG_HEAP_INSERT;
1946  int bufflags = 0;
1947 
1948  /*
1949  * If this is a catalog, we need to transmit combocids to properly
1950  * decode, so log that as well.
1951  */
1953  log_heap_new_cid(relation, heaptup);
1954 
1955  /*
1956  * If this is the single and first tuple on page, we can reinit the
1957  * page instead of restoring the whole thing. Set flag, and hide
1958  * buffer references from XLogInsert.
1959  */
1960  if (ItemPointerGetOffsetNumber(&(heaptup->t_self)) == FirstOffsetNumber &&
1962  {
1963  info |= XLOG_HEAP_INIT_PAGE;
1964  bufflags |= REGBUF_WILL_INIT;
1965  }
1966 
1967  xlrec.offnum = ItemPointerGetOffsetNumber(&heaptup->t_self);
1968  xlrec.flags = 0;
1969  if (all_visible_cleared)
1974 
1975  /*
1976  * For logical decoding, we need the tuple even if we're doing a full
1977  * page write, so make sure it's included even if we take a full-page
1978  * image. (XXX We could alternatively store a pointer into the FPW).
1979  */
1980  if (RelationIsLogicallyLogged(relation) &&
1982  {
1984  bufflags |= REGBUF_KEEP_DATA;
1985  }
1986 
1987  XLogBeginInsert();
1988  XLogRegisterData((char *) &xlrec, SizeOfHeapInsert);
1989 
1990  xlhdr.t_infomask2 = heaptup->t_data->t_infomask2;
1991  xlhdr.t_infomask = heaptup->t_data->t_infomask;
1992  xlhdr.t_hoff = heaptup->t_data->t_hoff;
1993 
1994  /*
1995  * note we mark xlhdr as belonging to buffer; if XLogInsert decides to
1996  * write the whole page to the xlog, we don't need to store
1997  * xl_heap_header in the xlog.
1998  */
1999  XLogRegisterBuffer(0, buffer, REGBUF_STANDARD | bufflags);
2000  XLogRegisterBufData(0, (char *) &xlhdr, SizeOfHeapHeader);
2001  /* PG73FORMAT: write bitmap [+ padding] [+ oid] + data */
2003  (char *) heaptup->t_data + SizeofHeapTupleHeader,
2004  heaptup->t_len - SizeofHeapTupleHeader);
2005 
2006  /* filtering by origin on a row level is much more efficient */
2008 
2009  recptr = XLogInsert(RM_HEAP_ID, info);
2010 
2011  PageSetLSN(page, recptr);
2012  }
2013 
2014  END_CRIT_SECTION();
2015 
2016  UnlockReleaseBuffer(buffer);
2017  if (vmbuffer != InvalidBuffer)
2018  ReleaseBuffer(vmbuffer);
2019 
2020  /*
2021  * If tuple is cachable, mark it for invalidation from the caches in case
2022  * we abort. Note it is OK to do this after releasing the buffer, because
2023  * the heaptup data structure is all in local memory, not in the shared
2024  * buffer.
2025  */
2026  CacheInvalidateHeapTuple(relation, heaptup, NULL);
2027 
2028  /* Note: speculative insertions are counted too, even if aborted later */
2029  pgstat_count_heap_insert(relation, 1);
2030 
2031  /*
2032  * If heaptup is a private copy, release it. Don't forget to copy t_self
2033  * back to the caller's image, too.
2034  */
2035  if (heaptup != tup)
2036  {
2037  tup->t_self = heaptup->t_self;
2038  heap_freetuple(heaptup);
2039  }
2040 }
void XLogRegisterBufData(uint8 block_id, char *data, int len)
Definition: xloginsert.c:361
#define SizeofHeapTupleHeader
Definition: htup_details.h:184
#define XLOG_HEAP_INSERT
Definition: heapam_xlog.h:32
static XLogRecPtr log_heap_new_cid(Relation relation, HeapTuple tup)
Definition: heapam.c:7523
void CacheInvalidateHeapTuple(Relation relation, HeapTuple tuple, HeapTuple newtuple)
Definition: inval.c:1114
static HeapTuple heap_prepare_insert(Relation relation, HeapTuple tup, TransactionId xid, CommandId cid, int options)
Definition: heapam.c:2049
#define PageIsAllVisible(page)
Definition: bufpage.h:385
uint32 TransactionId
Definition: c.h:507
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:1458
void XLogRegisterBuffer(uint8 block_id, Buffer buffer, uint8 flags)
Definition: xloginsert.c:213
#define END_CRIT_SECTION()
Definition: miscadmin.h:134
unsigned char uint8
Definition: c.h:356
#define XLH_INSERT_IS_SPECULATIVE
Definition: heapam_xlog.h:68
#define InvalidBuffer
Definition: buf.h:25
#define REGBUF_WILL_INIT
Definition: xloginsert.h:33
uint16 t_infomask2
Definition: heapam_xlog.h:144
#define START_CRIT_SECTION()
Definition: miscadmin.h:132
#define XLOG_INCLUDE_ORIGIN
Definition: xlog.h:228
#define HEAP_INSERT_SKIP_WAL
Definition: heapam.h:32
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3365
#define RelationIsLogicallyLogged(relation)
Definition: rel.h:591
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
#define PageGetMaxOffsetNumber(page)
Definition: bufpage.h:357
void RelationPutHeapTuple(Relation relation, Buffer buffer, HeapTuple tuple, bool token)
Definition: hio.c:36
void CheckForSerializableConflictIn(Relation relation, HeapTuple tuple, Buffer buffer)
Definition: predicate.c:4442
#define XLOG_HEAP_INIT_PAGE
Definition: heapam_xlog.h:46
#define HEAP_INSERT_SPECULATIVE
Definition: heapam.h:36
#define VISIBILITYMAP_VALID_BITS
Definition: visibilitymap.h:28
HeapTupleHeader t_data
Definition: htup.h:68
bool visibilitymap_clear(Relation rel, BlockNumber heapBlk, Buffer buf, uint8 flags)
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3388
#define XLH_INSERT_CONTAINS_NEW_TUPLE
Definition: heapam_xlog.h:69
ItemPointerData t_self
Definition: htup.h:65
TransactionId GetCurrentTransactionId(void)
Definition: xact.c:423
uint32 t_len
Definition: htup.h:64
#define FirstOffsetNumber
Definition: off.h:27
#define REGBUF_STANDARD
Definition: xloginsert.h:35
Buffer RelationGetBufferForTuple(Relation relation, Size len, Buffer otherBuffer, int options, BulkInsertState bistate, Buffer *vmbuffer, Buffer *vmbuffer_other)
Definition: hio.c:320
void XLogSetRecordFlags(uint8 flags)
Definition: xloginsert.c:397
#define BufferGetPage(buffer)
Definition: bufmgr.h:159
void XLogRegisterData(char *data, int len)
Definition: xloginsert.c:323
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:415
#define RelationIsAccessibleInLogicalDecoding(relation)
Definition: rel.h:575
#define REGBUF_KEEP_DATA
Definition: xloginsert.h:38
#define PageClearAllVisible(page)
Definition: bufpage.h:389
uint64 XLogRecPtr
Definition: xlogdefs.h:21
#define Assert(condition)
Definition: c.h:732
uint16 t_infomask
Definition: heapam_xlog.h:145
#define ItemPointerGetOffsetNumber(pointer)
Definition: itemptr.h:117
#define RelationNeedsWAL(relation)
Definition: rel.h:521
#define SizeOfHeapInsert
Definition: heapam_xlog.h:160
#define XLH_INSERT_ALL_VISIBLE_CLEARED
Definition: heapam_xlog.h:66
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:2613
void pgstat_count_heap_insert(Relation rel, PgStat_Counter n)
Definition: pgstat.c:1948
#define HEAP_INSERT_NO_LOGICAL
Definition: heapam.h:35
#define ItemPointerGetBlockNumber(pointer)
Definition: itemptr.h:98
void XLogBeginInsert(void)
Definition: xloginsert.c:120
#define PageSetLSN(page, lsn)
Definition: bufpage.h:368
int Buffer
Definition: buf.h:23
OffsetNumber offnum
Definition: heapam_xlog.h:154
#define SizeOfHeapHeader
Definition: heapam_xlog.h:149
Pointer Page
Definition: bufpage.h:78

◆ heap_lock_tuple()

TM_Result heap_lock_tuple ( Relation  relation,
HeapTuple  tuple,
CommandId  cid,
LockTupleMode  mode,
LockWaitPolicy  wait_policy,
bool  follow_update,
Buffer buffer,
struct TM_FailureData tmfd 
)

Definition at line 3973 of file heapam.c.

References Assert, BUFFER_LOCK_EXCLUSIVE, BUFFER_LOCK_UNLOCK, BufferGetPage, BufferIsValid, TM_FailureData::cmax, compute_infobits(), compute_new_xmax_infomask(), ConditionalMultiXactIdWait(), ConditionalXactLockTableWait(), TM_FailureData::ctid, DoesMultiXactIdConflict(), elog, END_CRIT_SECTION, ereport, errcode(), errmsg(), ERROR, xl_heap_lock::flags, get_mxact_status_for_lock(), GetCurrentTransactionId(), GetMultiXactIdMembers(), heap_acquire_tuplock(), HEAP_KEYS_UPDATED, heap_lock_updated_tuple(), HEAP_XMAX_BITS, HEAP_XMAX_INVALID, HEAP_XMAX_IS_EXCL_LOCKED, HEAP_XMAX_IS_KEYSHR_LOCKED, HEAP_XMAX_IS_LOCKED_ONLY, HEAP_XMAX_IS_MULTI, HEAP_XMAX_IS_SHR_LOCKED, HeapTupleHeaderClearHotUpdated, HeapTupleHeaderGetCmax(), HeapTupleHeaderGetRawXmax, HeapTupleHeaderGetUpdateXid, HeapTupleHeaderIndicatesMovedPartitions, HeapTupleHeaderIsOnlyLocked(), HeapTupleHeaderSetXmax, HeapTupleSatisfiesUpdate(), i, xl_heap_lock::infobits_set, InvalidBuffer, InvalidCommandId, ItemIdGetLength, ItemIdIsNormal, ItemPointerCopy, ItemPointerEquals(), ItemPointerGetBlockNumber, ItemPointerGetOffsetNumber, LockBuffer(), xl_heap_lock::locking_xid, LockTupleExclusive, LockTupleKeyShare, LockTupleNoKeyExclusive, LockTupleShare, LockWaitBlock, LockWaitError, LockWaitSkip, MarkBufferDirty(), MultiXactIdSetOldestMember(), MultiXactIdWait(), MultiXactStatusNoKeyUpdate, xl_heap_lock::offnum, PageGetItem, PageGetItemId, PageIsAllVisible, PageSetLSN, pfree(), ReadBuffer(), REGBUF_STANDARD, RelationGetRelationName, RelationGetRelid, RelationNeedsWAL, ReleaseBuffer(), SizeOfHeapLock, START_CRIT_SECTION, status(), HeapTupleHeaderData::t_ctid, HeapTupleData::t_data, HeapTupleHeaderData::t_infomask, HeapTupleHeaderData::t_infomask2, HeapTupleData::t_len, HeapTupleData::t_self, HeapTupleData::t_tableOid, TM_BeingModified, TM_Deleted, TM_Invisible, TM_Ok, TM_SelfModified, TM_Updated, TM_WouldBlock, TransactionIdEquals, TransactionIdIsCurrentTransactionId(), TUPLOCK_from_mxstatus, UnlockTupleTuplock, UpdateXmaxHintBits(), VISIBILITYMAP_ALL_FROZEN, visibilitymap_clear(), visibilitymap_pin(), XactLockTableWait(), XLH_LOCK_ALL_FROZEN_CLEARED, XLOG_HEAP_LOCK, XLogBeginInsert(), XLogInsert(), XLogRegisterBuffer(), XLogRegisterData(), XLTW_Lock, TM_FailureData::xmax, and xmax_infomask_changed().

Referenced by heapam_tuple_lock().

3977 {
3978  TM_Result result;
3979  ItemPointer tid = &(tuple->t_self);
3980  ItemId lp;
3981  Page page;
3982  Buffer vmbuffer = InvalidBuffer;
3983  BlockNumber block;
3984  TransactionId xid,
3985  xmax;
3986  uint16 old_infomask,
3987  new_infomask,
3988  new_infomask2;
3989  bool first_time = true;
3990  bool skip_tuple_lock = false;
3991  bool have_tuple_lock = false;
3992  bool cleared_all_frozen = false;
3993 
3994  *buffer = ReadBuffer(relation, ItemPointerGetBlockNumber(tid));
3995  block = ItemPointerGetBlockNumber(tid);
3996 
3997  /*
3998  * Before locking the buffer, pin the visibility map page if it appears to
3999  * be necessary. Since we haven't got the lock yet, someone else might be
4000  * in the middle of changing this, so we'll need to recheck after we have
4001  * the lock.
4002  */
4003  if (PageIsAllVisible(BufferGetPage(*buffer)))
4004  visibilitymap_pin(relation, block, &vmbuffer);
4005 
4007 
4008  page = BufferGetPage(*buffer);
4009  lp = PageGetItemId(page, ItemPointerGetOffsetNumber(tid));
4010  Assert(ItemIdIsNormal(lp));
4011 
4012  tuple->t_data = (HeapTupleHeader) PageGetItem(page, lp);
4013  tuple->t_len = ItemIdGetLength(lp);
4014  tuple->t_tableOid = RelationGetRelid(relation);
4015 
4016 l3:
4017  result = HeapTupleSatisfiesUpdate(tuple, cid, *buffer);
4018 
4019  if (result == TM_Invisible)
4020  {
4021  /*
4022  * This is possible, but only when locking a tuple for ON CONFLICT
4023  * UPDATE. We return this value here rather than throwing an error in
4024  * order to give that case the opportunity to throw a more specific
4025  * error.
4026  */
4027  result = TM_Invisible;
4028  goto out_locked;
4029  }
4030  else if (result == TM_BeingModified ||
4031  result == TM_Updated ||
4032  result == TM_Deleted)
4033  {
4034  TransactionId xwait;
4035  uint16 infomask;
4036  uint16 infomask2;
4037  bool require_sleep;
4038  ItemPointerData t_ctid;
4039 
4040  /* must copy state data before unlocking buffer */
4041  xwait = HeapTupleHeaderGetRawXmax(tuple->t_data);
4042  infomask = tuple->t_data->t_infomask;
4043  infomask2 = tuple->t_data->t_infomask2;
4044  ItemPointerCopy(&tuple->t_data->t_ctid, &t_ctid);
4045 
4046  LockBuffer(*buffer, BUFFER_LOCK_UNLOCK);
4047 
4048  /*
4049  * If any subtransaction of the current top transaction already holds
4050  * a lock as strong as or stronger than what we're requesting, we
4051  * effectively hold the desired lock already. We *must* succeed
4052  * without trying to take the tuple lock, else we will deadlock
4053  * against anyone wanting to acquire a stronger lock.
4054  *
4055  * Note we only do this the first time we loop on the HTSU result;
4056  * there is no point in testing in subsequent passes, because
4057  * evidently our own transaction cannot have acquired a new lock after
4058  * the first time we checked.
4059  */
4060  if (first_time)
4061  {
4062  first_time = false;
4063 
4064  if (infomask & HEAP_XMAX_IS_MULTI)
4065  {
4066  int i;
4067  int nmembers;
4068  MultiXactMember *members;
4069 
4070  /*
4071  * We don't need to allow old multixacts here; if that had
4072  * been the case, HeapTupleSatisfiesUpdate would have returned
4073  * MayBeUpdated and we wouldn't be here.
4074  */
4075  nmembers =
4076  GetMultiXactIdMembers(xwait, &members, false,
4077  HEAP_XMAX_IS_LOCKED_ONLY(infomask));
4078 
4079  for (i = 0; i < nmembers; i++)
4080  {
4081  /* only consider members of our own transaction */
4082  if (!TransactionIdIsCurrentTransactionId(members[i].xid))
4083  continue;
4084 
4085  if (TUPLOCK_from_mxstatus(members[i].status) >= mode)
4086  {
4087  pfree(members);
4088  result = TM_Ok;
4089  goto out_unlocked;
4090  }
4091  else
4092  {
4093  /*
4094  * Disable acquisition of the heavyweight tuple lock.
4095  * Otherwise, when promoting a weaker lock, we might
4096  * deadlock with another locker that has acquired the
4097  * heavyweight tuple lock and is waiting for our
4098  * transaction to finish.
4099  *
4100  * Note that in this case we still need to wait for
4101  * the multixact if required, to avoid acquiring
4102  * conflicting locks.
4103  */
4104  skip_tuple_lock = true;
4105  }
4106  }
4107 
4108  if (members)
4109  pfree(members);
4110  }
4111  else if (TransactionIdIsCurrentTransactionId(xwait))
4112  {
4113  switch (mode)
4114  {
4115  case LockTupleKeyShare:
4116  Assert(HEAP_XMAX_IS_KEYSHR_LOCKED(infomask) ||
4117  HEAP_XMAX_IS_SHR_LOCKED(infomask) ||
4118  HEAP_XMAX_IS_EXCL_LOCKED(infomask));
4119  result = TM_Ok;
4120  goto out_unlocked;
4121  case LockTupleShare:
4122  if (HEAP_XMAX_IS_SHR_LOCKED(infomask) ||
4123  HEAP_XMAX_IS_EXCL_LOCKED(infomask))
4124  {
4125  result = TM_Ok;
4126  goto out_unlocked;
4127  }
4128  break;
4130  if (HEAP_XMAX_IS_EXCL_LOCKED(infomask))
4131  {
4132  result = TM_Ok;
4133  goto out_unlocked;
4134  }
4135  break;
4136  case LockTupleExclusive:
4137  if (HEAP_XMAX_IS_EXCL_LOCKED(infomask) &&
4138  infomask2 & HEAP_KEYS_UPDATED)
4139  {
4140  result = TM_Ok;
4141  goto out_unlocked;
4142  }
4143  break;
4144  }
4145  }
4146  }
4147 
4148  /*
4149  * Initially assume that we will have to wait for the locking
4150  * transaction(s) to finish. We check various cases below in which
4151  * this can be turned off.
4152  */
4153  require_sleep = true;
4154  if (mode == LockTupleKeyShare)
4155  {
4156  /*
4157  * If we're requesting KeyShare, and there's no update present, we
4158  * don't need to wait. Even if there is an update, we can still
4159  * continue if the key hasn't been modified.
4160  *
4161  * However, if there are updates, we need to walk the update chain
4162  * to mark future versions of the row as locked, too. That way,
4163  * if somebody deletes that future version, we're protected
4164  * against the key going away. This locking of future versions
4165  * could block momentarily, if a concurrent transaction is
4166  * deleting a key; or it could return a value to the effect that
4167  * the transaction deleting the key has already committed. So we
4168  * do this before re-locking the buffer; otherwise this would be
4169  * prone to deadlocks.
4170  *
4171  * Note that the TID we're locking was grabbed before we unlocked
4172  * the buffer. For it to change while we're not looking, the
4173  * other properties we're testing for below after re-locking the
4174  * buffer would also change, in which case we would restart this
4175  * loop above.
4176  */
4177  if (!(infomask2 & HEAP_KEYS_UPDATED))
4178  {
4179  bool updated;
4180 
4181  updated = !HEAP_XMAX_IS_LOCKED_ONLY(infomask);
4182 
4183  /*
4184  * If there are updates, follow the update chain; bail out if
4185  * that cannot be done.
4186  */
4187  if (follow_updates && updated)
4188  {
4189  TM_Result res;
4190 
4191  res = heap_lock_updated_tuple(relation, tuple, &t_ctid,
4193  mode);
4194  if (res != TM_Ok)
4195  {
4196  result = res;
4197  /* recovery code expects to have buffer lock held */
4199  goto failed;
4200  }
4201  }
4202 
4204 
4205  /*
4206  * Make sure it's still an appropriate lock, else start over.
4207  * Also, if it wasn't updated before we released the lock, but
4208  * is updated now, we start over too; the reason is that we
4209  * now need to follow the update chain to lock the new
4210  * versions.
4211  */
4212  if (!HeapTupleHeaderIsOnlyLocked(tuple->t_data) &&
4213  ((tuple->t_data->t_infomask2 & HEAP_KEYS_UPDATED) ||
4214  !updated))
4215  goto l3;
4216 
4217  /* Things look okay, so we can skip sleeping */
4218  require_sleep = false;
4219 
4220  /*
4221  * Note we allow Xmax to change here; other updaters/lockers
4222  * could have modified it before we grabbed the buffer lock.
4223  * However, this is not a problem, because with the recheck we
4224  * just did we ensure that they still don't conflict with the
4225  * lock we want.
4226  */
4227  }
4228  }
4229  else if (mode == LockTupleShare)
4230  {
4231  /*
4232  * If we're requesting Share, we can similarly avoid sleeping if
4233  * there's no update and no exclusive lock present.
4234  */
4235  if (HEAP_XMAX_IS_LOCKED_ONLY(infomask) &&
4236  !HEAP_XMAX_IS_EXCL_LOCKED(infomask))
4237  {
4239 
4240  /*
4241  * Make sure it's still an appropriate lock, else start over.
4242  * See above about allowing xmax to change.
4243  */
4244  if (!HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_data->t_infomask) ||
4246  goto l3;
4247  require_sleep = false;
4248  }
4249  }
4250  else if (mode == LockTupleNoKeyExclusive)
4251  {
4252  /*
4253  * If we're requesting NoKeyExclusive, we might also be able to
4254  * avoid sleeping; just ensure that there no conflicting lock
4255  * already acquired.
4256  */
4257  if (infomask & HEAP_XMAX_IS_MULTI)
4258  {
4259  if (!DoesMultiXactIdConflict((MultiXactId) xwait, infomask,
4260  mode, NULL))
4261  {
4262  /*
4263  * No conflict, but if the xmax changed under us in the
4264  * meantime, start over.
4265  */
4267  if (xmax_infomask_changed(tuple->t_data->t_infomask, infomask) ||
4269  xwait))
4270  goto l3;
4271 
4272  /* otherwise, we're good */
4273  require_sleep = false;
4274  }
4275  }
4276  else if (HEAP_XMAX_IS_KEYSHR_LOCKED(infomask))
4277  {
4279 
4280  /* if the xmax changed in the meantime, start over */
4281  if (xmax_infomask_changed(tuple->t_data->t_infomask, infomask) ||
4284  xwait))
4285  goto l3;
4286  /* otherwise, we're good */
4287  require_sleep = false;
4288  }
4289  }
4290 
4291  /*
4292  * As a check independent from those above, we can also avoid sleeping
4293  * if the current transaction is the sole locker of the tuple. Note
4294  * that the strength of the lock already held is irrelevant; this is
4295  * not about recording the lock in Xmax (which will be done regardless
4296  * of this optimization, below). Also, note that the cases where we
4297  * hold a lock stronger than we are requesting are already handled
4298  * above by not doing anything.
4299  *
4300  * Note we only deal with the non-multixact case here; MultiXactIdWait
4301  * is well equipped to deal with this situation on its own.
4302  */
4303  if (require_sleep && !(infomask & HEAP_XMAX_IS_MULTI) &&
4305  {
4306  /* ... but if the xmax changed in the meantime, start over */
4308  if (xmax_infomask_changed(tuple->t_data->t_infomask, infomask) ||
4310  xwait))
4311  goto l3;
4313  require_sleep = false;
4314  }
4315 
4316  /*
4317  * Time to sleep on the other transaction/multixact, if necessary.
4318  *
4319  * If the other transaction is an update/delete that's already
4320  * committed, then sleeping cannot possibly do any good: if we're
4321  * required to sleep, get out to raise an error instead.
4322  *
4323  * By here, we either have already acquired the buffer exclusive lock,
4324  * or we must wait for the locking transaction or multixact; so below
4325  * we ensure that we grab buffer lock after the sleep.
4326  */
4327  if (require_sleep && (result == TM_Updated || result == TM_Deleted))
4328  {
4330  goto failed;
4331  }
4332  else if (require_sleep)
4333  {
4334  /*
4335  * Acquire tuple lock to establish our priority for the tuple, or
4336  * die trying. LockTuple will release us when we are next-in-line
4337  * for the tuple. We must do this even if we are share-locking,
4338  * but not if we already have a weaker lock on the tuple.
4339  *
4340  * If we are forced to "start over" below, we keep the tuple lock;
4341  * this arranges that we stay at the head of the line while
4342  * rechecking tuple state.
4343  */
4344  if (!skip_tuple_lock &&
4345  !heap_acquire_tuplock(relation, tid, mode, wait_policy,
4346  &have_tuple_lock))
4347  {
4348  /*
4349  * This can only happen if wait_policy is Skip and the lock
4350  * couldn't be obtained.
4351  */
4352  result = TM_WouldBlock;
4353  /* recovery code expects to have buffer lock held */
4355  goto failed;
4356  }
4357 
4358  if (infomask & HEAP_XMAX_IS_MULTI)
4359  {
4361 
4362  /* We only ever lock tuples, never update them */
4363  if (status >= MultiXactStatusNoKeyUpdate)
4364  elog(ERROR, "invalid lock mode in heap_lock_tuple");
4365 
4366  /* wait for multixact to end, or die trying */
4367  switch (wait_policy)
4368  {
4369  case LockWaitBlock:
4370  MultiXactIdWait((MultiXactId) xwait, status, infomask,
4371  relation, &tuple->t_self, XLTW_Lock, NULL);
4372  break;
4373  case LockWaitSkip:
4375  status, infomask, relation,
4376  NULL))
4377  {
4378  result = TM_WouldBlock;
4379  /* recovery code expects to have buffer lock held */
4381  goto failed;
4382  }
4383  break;
4384  case LockWaitError:
4386  status, infomask, relation,
4387  NULL))
4388  ereport(ERROR,
4389  (errcode(ERRCODE_LOCK_NOT_AVAILABLE),
4390  errmsg("could not obtain lock on row in relation \"%s\"",
4391  RelationGetRelationName(relation))));
4392 
4393  break;
4394  }
4395 
4396  /*
4397  * Of course, the multixact might not be done here: if we're
4398  * requesting a light lock mode, other transactions with light
4399  * locks could still be alive, as well as locks owned by our
4400  * own xact or other subxacts of this backend. We need to
4401  * preserve the surviving MultiXact members. Note that it
4402  * isn't absolutely necessary in the latter case, but doing so
4403  * is simpler.
4404  */
4405  }
4406  else
4407  {
4408  /* wait for regular transaction to end, or die trying */
4409  switch (wait_policy)
4410  {
4411  case LockWaitBlock:
4412  XactLockTableWait(xwait, relation, &tuple->t_self,
4413  XLTW_Lock);
4414  break;
4415  case LockWaitSkip:
4416  if (!ConditionalXactLockTableWait(xwait))
4417  {
4418  result = TM_WouldBlock;
4419  /* recovery code expects to have buffer lock held */
4421  goto failed;
4422  }
4423  break;
4424  case LockWaitError:
4425  if (!ConditionalXactLockTableWait(xwait))
4426  ereport(ERROR,
4427  (errcode(ERRCODE_LOCK_NOT_AVAILABLE),
4428  errmsg("could not obtain lock on row in relation \"%s\"",
4429  RelationGetRelationName(relation))));
4430  break;
4431  }
4432  }
4433 
4434  /* if there are updates, follow the update chain */
4435  if (follow_updates && !HEAP_XMAX_IS_LOCKED_ONLY(infomask))
4436  {
4437  TM_Result res;
4438 
4439  res = heap_lock_updated_tuple(relation, tuple, &t_ctid,
4441  mode);
4442  if (res != TM_Ok)
4443  {
4444  result = res;
4445  /* recovery code expects to have buffer lock held */
4447  goto failed;
4448  }
4449  }
4450 
4452 
4453  /*
4454  * xwait is done, but if xwait had just locked the tuple then some
4455  * other xact could update this tuple before we get to this point.
4456  * Check for xmax change, and start over if so.
4457  */
4458  if (xmax_infomask_changed(tuple->t_data->t_infomask, infomask) ||
4460  xwait))
4461  goto l3;
4462 
4463  if (!(infomask & HEAP_XMAX_IS_MULTI))
4464  {
4465  /*
4466  * Otherwise check if it committed or aborted. Note we cannot
4467  * be here if the tuple was only locked by somebody who didn't
4468  * conflict with us; that would have been handled above. So
4469  * that transaction must necessarily be gone by now. But
4470  * don't check for this in the multixact case, because some
4471  * locker transactions might still be running.
4472  */
4473  UpdateXmaxHintBits(tuple->t_data, *buffer, xwait);
4474  }
4475  }
4476 
4477  /* By here, we're certain that we hold buffer exclusive lock again */
4478 
4479  /*
4480  * We may lock if previous xmax aborted, or if it committed but only
4481  * locked the tuple without updating it; or if we didn't have to wait
4482  * at all for whatever reason.
4483  */
4484  if (!require_sleep ||
4485  (tuple->t_data->t_infomask & HEAP_XMAX_INVALID) ||
4488  result = TM_Ok;
4489  else if (!ItemPointerEquals(&tuple->t_self, &tuple->t_data->t_ctid) ||
4491  result = TM_Updated;
4492  else
4493  result = TM_Deleted;
4494  }
4495 
4496 failed:
4497  if (result != TM_Ok)
4498  {
4499  Assert(result == TM_SelfModified || result == TM_Updated ||
4500  result == TM_Deleted || result == TM_WouldBlock);
4501  Assert(!(tuple->t_data->t_infomask & HEAP_XMAX_INVALID));
4502  Assert(result != TM_Updated ||
4503  !ItemPointerEquals(&tuple->t_self, &tuple->t_data->t_ctid));
4504  tmfd->ctid = tuple->t_data->t_ctid;
4505  tmfd->xmax = HeapTupleHeaderGetUpdateXid(tuple->t_data);
4506  if (result == TM_SelfModified)
4507  tmfd->cmax = HeapTupleHeaderGetCmax(tuple->t_data);
4508  else
4509  tmfd->cmax = InvalidCommandId;
4510  goto out_locked;
4511  }
4512 
4513  /*
4514  * If we didn't pin the visibility map page and the page has become all
4515  * visible while we were busy locking the buffer, or during some
4516  * subsequent window during which we had it unlocked, we'll have to unlock
4517  * and re-lock, to avoid holding the buffer lock across I/O. That's a bit
4518  * unfortunate, especially since we'll now have to recheck whether the
4519  * tuple has been locked or updated under us, but hopefully it won't
4520  * happen very often.
4521  */
4522  if (vmbuffer == InvalidBuffer && PageIsAllVisible(page))
4523  {
4524  LockBuffer(*buffer, BUFFER_LOCK_UNLOCK);
4525  visibilitymap_pin(relation, block, &vmbuffer);
4527  goto l3;
4528  }
4529 
4530  xmax = HeapTupleHeaderGetRawXmax(tuple->t_data);
4531  old_infomask = tuple->t_data->t_infomask;
4532 
4533  /*
4534  * If this is the first possibly-multixact-able operation in the current
4535  * transaction, set my per-backend OldestMemberMXactId setting. We can be
4536  * certain that the transaction will never become a member of any older
4537  * MultiXactIds than that. (We have to do this even if we end up just
4538  * using our own TransactionId below, since some other backend could
4539  * incorporate our XID into a MultiXact immediately afterwards.)
4540  */
4542 
4543  /*
4544  * Compute the new xmax and infomask to store into the tuple. Note we do
4545  * not modify the tuple just yet, because that would leave it in the wrong
4546  * state if multixact.c elogs.
4547  */
4548  compute_new_xmax_infomask(xmax, old_infomask, tuple->t_data->t_infomask2,
4549  GetCurrentTransactionId(), mode, false,
4550  &xid, &new_infomask, &new_infomask2);
4551 
4553 
4554  /*
4555  * Store transaction information of xact locking the tuple.
4556  *
4557  * Note: Cmax is meaningless in this context, so don't set it; this avoids
4558  * possibly generating a useless combo CID. Moreover, if we're locking a
4559  * previously updated tuple, it's important to preserve the Cmax.
4560  *
4561  * Also reset the HOT UPDATE bit, but only if there's no update; otherwise
4562  * we would break the HOT chain.
4563  */
4564  tuple->t_data->t_infomask &= ~HEAP_XMAX_BITS;
4565  tuple->t_data->t_infomask2 &= ~HEAP_KEYS_UPDATED;
4566  tuple->t_data->t_infomask |= new_infomask;
4567  tuple->t_data->t_infomask2 |= new_infomask2;
4568  if (HEAP_XMAX_IS_LOCKED_ONLY(new_infomask))
4570  HeapTupleHeaderSetXmax(tuple->t_data, xid);
4571 
4572  /*
4573  * Make sure there is no forward chain link in t_ctid. Note that in the
4574  * cases where the tuple has been updated, we must not overwrite t_ctid,
4575  * because it was set by the updater. Moreover, if the tuple has been
4576  * updated, we need to follow the update chain to lock the new versions of
4577  * the tuple as well.
4578  */
4579  if (HEAP_XMAX_IS_LOCKED_ONLY(new_infomask))
4580  tuple->t_data->t_ctid = *tid;
4581 
4582  /* Clear only the all-frozen bit on visibility map if needed */
4583  if (PageIsAllVisible(page) &&
4584  visibilitymap_clear(relation, block, vmbuffer,
4586  cleared_all_frozen = true;
4587 
4588 
4589  MarkBufferDirty(*buffer);
4590 
4591  /*
4592  * XLOG stuff. You might think that we don't need an XLOG record because
4593  * there is no state change worth restoring after a crash. You would be
4594  * wrong however: we have just written either a TransactionId or a
4595  * MultiXactId that may never have been seen on disk before, and we need
4596  * to make sure that there are XLOG entries covering those ID numbers.
4597  * Else the same IDs might be re-used after a crash, which would be
4598  * disastrous if this page made it to disk before the crash. Essentially
4599  * we have to enforce the WAL log-before-data rule even in this case.
4600  * (Also, in a PITR log-shipping or 2PC environment, we have to have XLOG
4601  * entries for everything anyway.)
4602  */
4603  if (RelationNeedsWAL(relation))
4604  {
4605  xl_heap_lock xlrec;
4606  XLogRecPtr recptr;
4607 
4608  XLogBeginInsert();
4609  XLogRegisterBuffer(0, *buffer, REGBUF_STANDARD);
4610 
4611  xlrec.offnum = ItemPointerGetOffsetNumber(&tuple->t_self);
4612  xlrec.locking_xid = xid;
4613  xlrec.infobits_set = compute_infobits(new_infomask,
4614  tuple->t_data->t_infomask2);
4615  xlrec.flags = cleared_all_frozen ? XLH_LOCK_ALL_FROZEN_CLEARED : 0;
4616  XLogRegisterData((char *) &xlrec, SizeOfHeapLock);
4617 
4618  /* we don't decode row locks atm, so no need to log the origin */
4619 
4620  recptr = XLogInsert(RM_HEAP_ID, XLOG_HEAP_LOCK);
4621 
4622  PageSetLSN(page, recptr);
4623  }
4624 
4625  END_CRIT_SECTION();
4626 
4627  result = TM_Ok;
4628 
4629 out_locked:
4630  LockBuffer(*buffer, BUFFER_LOCK_UNLOCK);
4631 
4632 out_unlocked:
4633  if (BufferIsValid(vmbuffer))
4634  ReleaseBuffer(vmbuffer);
4635 
4636  /*
4637  * Don't update the visibility map here. Locking a tuple doesn't change
4638  * visibility info.
4639  */
4640 
4641  /*
4642  * Now that we have successfully marked the tuple as locked, we can
4643  * release the lmgr tuple lock, if we had it.
4644  */
4645  if (have_tuple_lock)
4646  UnlockTupleTuplock(relation, tid, mode);
4647 
4648  return result;
4649 }
#define HeapTupleHeaderGetUpdateXid(tup)
Definition: htup_details.h:365
ItemPointerData ctid
Definition: tableam.h:123
static PgChecksumMode mode
Definition: pg_checksums.c:61
MultiXactStatus
Definition: multixact.h:40
#define BUFFER_LOCK_UNLOCK
Definition: bufmgr.h:86
#define HEAP_XMAX_BITS
Definition: htup_details.h:270
OffsetNumber offnum
Definition: heapam_xlog.h:275
static uint8 compute_infobits(uint16 infomask, uint16 infomask2)
Definition: heapam.c:2397
#define TransactionIdEquals(id1, id2)
Definition: transam.h:43
#define PageIsAllVisible(page)
Definition: bufpage.h:385
#define XLH_LOCK_ALL_FROZEN_CLEARED
Definition: heapam_xlog.h:269
TransactionId locking_xid
Definition: heapam_xlog.h:274
uint32 TransactionId
Definition: c.h:507
bool TransactionIdIsCurrentTransactionId(TransactionId xid)
Definition: xact.c:854
void visibilitymap_pin(Relation rel, BlockNumber heapBlk, Buffer *buf)
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:1458
void XLogRegisterBuffer(uint8 block_id, Buffer buffer, uint8 flags)
Definition: xloginsert.c:213
HeapTupleHeaderData * HeapTupleHeader
Definition: htup.h:23
#define VISIBILITYMAP_ALL_FROZEN
Definition: visibilitymap.h:27
static bool xmax_infomask_changed(uint16 new_infomask, uint16 old_infomask)
Definition: heapam.c:2419
#define HeapTupleHeaderClearHotUpdated(tup)
Definition: htup_details.h:496
#define END_CRIT_SECTION()
Definition: miscadmin.h:134
CommandId cmax
Definition: tableam.h:125
bool HeapTupleHeaderIsOnlyLocked(HeapTupleHeader tuple)
#define InvalidBuffer
Definition: buf.h:25
#define START_CRIT_SECTION()
Definition: miscadmin.h:132
int errcode(int sqlerrcode)
Definition: elog.c:570
#define HeapTupleHeaderIndicatesMovedPartitions(tup)
Definition: htup_details.h:445
uint32 BlockNumber
Definition: block.h:31
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3365
#define BUFFER_LOCK_EXCLUSIVE
Definition: bufmgr.h:88
TM_Result HeapTupleSatisfiesUpdate(HeapTuple htup, CommandId curcid, Buffer buffer)
#define UnlockTupleTuplock(rel, tup, mode)
Definition: heapam.c:161
bool ConditionalXactLockTableWait(TransactionId xid)
Definition: lmgr.c:697
#define HEAP_XMAX_IS_SHR_LOCKED(infomask)
Definition: htup_details.h:262
void MultiXactIdSetOldestMember(void)
Definition: multixact.c:625
HeapTupleHeader t_data
Definition: htup.h:68
#define HeapTupleHeaderGetRawXmax(tup)
Definition: htup_details.h:375
unsigned short uint16
Definition: c.h:357
void pfree(void *pointer)
Definition: mcxt.c:1056
#define ItemIdGetLength(itemId)
Definition: itemid.h:59
bool visibilitymap_clear(Relation rel, BlockNumber heapBlk, Buffer buf, uint8 flags)
TransactionId xmax
Definition: tableam.h:124
#define ERROR
Definition: elog.h:43
#define HEAP_XMAX_INVALID
Definition: htup_details.h:207
int8 infobits_set
Definition: heapam_xlog.h:276
ItemPointerData t_ctid
Definition: htup_details.h:160
ItemPointerData t_self
Definition: htup.h:65
static void MultiXactIdWait(MultiXactId multi, MultiXactStatus status, uint16 infomask, Relation rel, ItemPointer ctid, XLTW_Oper oper, int *remaining)
Definition: heapam.c:6725
TransactionId GetCurrentTransactionId(void)
Definition: xact.c:423
uint32 t_len
Definition: htup.h:64
#define REGBUF_STANDARD
Definition: xloginsert.h:35
#define HeapTupleHeaderSetXmax(tup, xid)
Definition: htup_details.h:380
#define RelationGetRelationName(relation)
Definition: rel.h:453
Oid t_tableOid
Definition: htup.h:66
#define SizeOfHeapLock
Definition: heapam_xlog.h:280
#define BufferGetPage(buffer)
Definition: bufmgr.h:159
#define ereport(elevel, rest)
Definition: elog.h:141
static void compute_new_xmax_infomask(TransactionId xmax, uint16 old_infomask, uint16 old_infomask2, TransactionId add_to_xmax, LockTupleMode mode, bool is_update, TransactionId *result_xmax, uint16 *result_infomask, uint16 *result_infomask2)
Definition: heapam.c:4713
#define PageGetItemId(page, offsetNumber)
Definition: bufpage.h:235
void XLogRegisterData(char *data, int len)
Definition: xloginsert.c:323
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:415
TM_Result
Definition: tableam.h:68
#define InvalidCommandId
Definition: c.h:524
#define HEAP_XMAX_IS_LOCKED_ONLY(infomask)
Definition: htup_details.h:230
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3602
#define HEAP_KEYS_UPDATED
Definition: htup_details.h:278
#define HEAP_XMAX_IS_MULTI
Definition: htup_details.h:208
static void UpdateXmaxHintBits(HeapTupleHeader tuple, Buffer buffer, TransactionId xid)
Definition: heapam.c:1793
static bool heap_acquire_tuplock(Relation relation, ItemPointer tid, LockTupleMode mode, LockWaitPolicy wait_policy, bool *have_tuple_lock)
Definition: heapam.c:4664
TransactionId MultiXactId
Definition: c.h:517
void XactLockTableWait(TransactionId xid, Relation rel, ItemPointer ctid, XLTW_Oper oper)
Definition: lmgr.c:624
uint64 XLogRecPtr
Definition: xlogdefs.h:21
#define Assert(condition)
Definition: c.h:732
static TM_Result heap_lock_updated_tuple(Relation rel, HeapTuple tuple, ItemPointer ctid, TransactionId xid, LockTupleMode mode)
Definition: heapam.c:5431
Definition: lmgr.h:29
CommandId HeapTupleHeaderGetCmax(HeapTupleHeader tup)
Definition: combocid.c:119
Definition: tableam.h:74
#define ItemIdIsNormal(itemId)
Definition: itemid.h:99
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition: bufmgr.c:596
#define BufferIsValid(bufnum)
Definition: bufmgr.h:113
#define ItemPointerGetOffsetNumber(pointer)
Definition: itemptr.h:117
static bool DoesMultiXactIdConflict(MultiXactId multi, uint16 infomask, LockTupleMode lockmode, bool *current_is_member)
Definition: heapam.c:6548
#define RelationNeedsWAL(relation)
Definition: rel.h:521
bool ItemPointerEquals(ItemPointer pointer1, ItemPointer pointer2)
Definition: itemptr.c:29
#define TUPLOCK_from_mxstatus(status)
Definition: heapam.c:195
int errmsg(const char *fmt,...)
Definition: elog.c:784
#define XLOG_HEAP_LOCK
Definition: heapam_xlog.h:38
#define elog(elevel,...)
Definition: elog.h:226
int i
static MultiXactStatus get_mxact_status_for_lock(LockTupleMode mode, bool is_update)
Definition: heapam.c:3925
#define HEAP_XMAX_IS_EXCL_LOCKED(infomask)
Definition: htup_details.h:264
int GetMultiXactIdMembers(MultiXactId multi, MultiXactMember **members, bool from_pgupgrade, bool onlyLock)
Definition: multixact.c:1204
#define ItemPointerGetBlockNumber(pointer)
Definition: itemptr.h:98
#define HEAP_XMAX_IS_KEYSHR_LOCKED(infomask)
Definition: htup_details.h:266
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:227
void XLogBeginInsert(void)
Definition: xloginsert.c:120
#define PageSetLSN(page, lsn)
Definition: bufpage.h:368
int Buffer
Definition: buf.h:23
#define RelationGetRelid(relation)
Definition: rel.h:419
static bool ConditionalMultiXactIdWait(MultiXactId multi, MultiXactStatus status, uint16 infomask, Relation rel, int *remaining)
Definition: heapam.c:6747
#define PageGetItem(page, itemId)
Definition: bufpage.h:340
Pointer Page
Definition: bufpage.h:78
#define ItemPointerCopy(fromPointer, toPointer)
Definition: itemptr.h:161

◆ heap_multi_insert()

void heap_multi_insert ( Relation  relation,
struct TupleTableSlot **  slots,
int  ntuples,
CommandId  cid,
int  options,
BulkInsertState  bistate 
)

Definition at line 2105 of file heapam.c.

References Assert, AssertArg, BufferGetBlockNumber(), BufferGetPage, CacheInvalidateHeapTuple(), CHECK_FOR_INTERRUPTS, CheckForSerializableConflictIn(), PGAlignedBlock::data, xl_multi_insert_tuple::datalen, END_CRIT_SECTION, ExecFetchSlotHeapTuple(), FirstOffsetNumber, xl_heap_multi_insert::flags, GetCurrentTransactionId(), HEAP_DEFAULT_FILLFACTOR, HEAP_INSERT_NO_LOGICAL, HEAP_INSERT_SKIP_WAL, heap_prepare_insert(), i, init, InvalidBuffer, IsCatalogRelation(), ItemPointerGetOffsetNumber, log_heap_new_cid(), MarkBufferDirty(), MAXALIGN, xl_heap_multi_insert::ntuples, xl_heap_multi_insert::offsets, PageClearAllVisible, PageGetHeapFreeSpace(), PageGetMaxOffsetNumber, PageIsAllVisible, PageSetLSN, palloc(), pgstat_count_heap_insert(), REGBUF_KEEP_DATA, REGBUF_STANDARD, REGBUF_WILL_INIT, RelationGetBufferForTuple(), RelationGetRelid, RelationGetTargetPageFreeSpace, RelationIsAccessibleInLogicalDecoding, RelationIsLogicallyLogged, RelationNeedsWAL, RelationPutHeapTuple(), ReleaseBuffer(), SHORTALIGN, SizeOfHeapMultiInsert, SizeofHeapTupleHeader, SizeOfMultiInsertTuple, START_CRIT_SECTION, HeapTupleData::t_data, HeapTupleHeaderData::t_hoff, xl_multi_insert_tuple::t_hoff, HeapTupleHeaderData::t_infomask, xl_multi_insert_tuple::t_infomask, HeapTupleHeaderData::t_infomask2, xl_multi_insert_tuple::t_infomask2, HeapTupleData::t_len, HeapTupleData::t_self, HeapTupleData::t_tableOid, TupleTableSlot::tts_tableOid, UnlockReleaseBuffer(), visibilitymap_clear(), VISIBILITYMAP_VALID_BITS, XLH_INSERT_ALL_VISIBLE_CLEARED, XLH_INSERT_CONTAINS_NEW_TUPLE, XLH_INSERT_LAST_IN_MULTI, XLOG_HEAP2_MULTI_INSERT, XLOG_HEAP_INIT_PAGE, XLOG_INCLUDE_ORIGIN, XLogBeginInsert(), XLogInsert(), XLogRegisterBufData(), XLogRegisterBuffer(), XLogRegisterData(), and XLogSetRecordFlags().

Referenced by SampleHeapTupleVisible().

2107 {
2109  HeapTuple *heaptuples;
2110  int i;
2111  int ndone;
2112  PGAlignedBlock scratch;
2113  Page page;
2114  bool needwal;
2115  Size saveFreeSpace;
2116  bool need_tuple_data = RelationIsLogicallyLogged(relation);
2117  bool need_cids = RelationIsAccessibleInLogicalDecoding(relation);
2118 
2119  /* currently not needed (thus unsupported) for heap_multi_insert() */
2121 
2122  needwal = !(options & HEAP_INSERT_SKIP_WAL) && RelationNeedsWAL(relation);
2123  saveFreeSpace = RelationGetTargetPageFreeSpace(relation,
2125 
2126  /* Toast and set header data in all the slots */
2127  heaptuples = palloc(ntuples * sizeof(HeapTuple));
2128  for (i = 0; i < ntuples; i++)
2129  {
2130  HeapTuple tuple;
2131 
2132  tuple = ExecFetchSlotHeapTuple(slots[i], true, NULL);
2133  slots[i]->tts_tableOid = RelationGetRelid(relation);
2134  tuple->t_tableOid = slots[i]->tts_tableOid;
2135  heaptuples[i] = heap_prepare_insert(relation, tuple, xid, cid,
2136  options);
2137  }
2138 
2139  /*
2140  * We're about to do the actual inserts -- but check for conflict first,
2141  * to minimize the possibility of having to roll back work we've just
2142  * done.
2143  *
2144  * A check here does not definitively prevent a serialization anomaly;
2145  * that check MUST be done at least past the point of acquiring an
2146  * exclusive buffer content lock on every buffer that will be affected,
2147  * and MAY be done after all inserts are reflected in the buffers and
2148  * those locks are released; otherwise there race condition. Since
2149  * multiple buffers can be locked and unlocked in the loop below, and it
2150  * would not be feasible to identify and lock all of those buffers before
2151  * the loop, we must do a final check at the end.
2152  *
2153  * The check here could be omitted with no loss of correctness; it is
2154  * present strictly as an optimization.
2155  *
2156  * For heap inserts, we only need to check for table-level SSI locks. Our
2157  * new tuples can't possibly conflict with existing tuple locks, and heap
2158  * page locks are only consolidated versions of tuple locks; they do not
2159  * lock "gaps" as index page locks do. So we don't need to specify a
2160  * buffer when making the call, which makes for a faster check.
2161  */
2163 
2164  ndone = 0;
2165  while (ndone < ntuples)
2166  {
2167  Buffer buffer;
2168  Buffer vmbuffer = InvalidBuffer;
2169  bool all_visible_cleared = false;
2170  int nthispage;
2171 
2173 
2174  /*
2175  * Find buffer where at least the next tuple will fit. If the page is
2176  * all-visible, this will also pin the requisite visibility map page.
2177  */
2178  buffer = RelationGetBufferForTuple(relation, heaptuples[ndone]->t_len,
2179  InvalidBuffer, options, bistate,
2180  &vmbuffer, NULL);
2181  page = BufferGetPage(buffer);
2182 
2183  /* NO EREPORT(ERROR) from here till changes are logged */
2185 
2186  /*
2187  * RelationGetBufferForTuple has ensured that the first tuple fits.
2188  * Put that on the page, and then as many other tuples as fit.
2189  */
2190  RelationPutHeapTuple(relation, buffer, heaptuples[ndone], false);
2191  for (nthispage = 1; ndone + nthispage < ntuples; nthispage++)
2192  {
2193  HeapTuple heaptup = heaptuples[ndone + nthispage];
2194 
2195  if (PageGetHeapFreeSpace(page) < MAXALIGN(heaptup->t_len) + saveFreeSpace)
2196  break;
2197 
2198  RelationPutHeapTuple(relation, buffer, heaptup, false);
2199 
2200  /*
2201  * We don't use heap_multi_insert for catalog tuples yet, but
2202  * better be prepared...
2203  */
2204  if (needwal && need_cids)
2205  log_heap_new_cid(relation, heaptup);
2206  }
2207 
2208  if (PageIsAllVisible(page))
2209  {
2210  all_visible_cleared = true;
2211  PageClearAllVisible(page);
2212  visibilitymap_clear(relation,
2213  BufferGetBlockNumber(buffer),
2214  vmbuffer, VISIBILITYMAP_VALID_BITS);
2215  }
2216 
2217  /*
2218  * XXX Should we set PageSetPrunable on this page ? See heap_insert()
2219  */
2220 
2221  MarkBufferDirty(buffer);
2222 
2223  /* XLOG stuff */
2224  if (needwal)
2225  {
2226  XLogRecPtr recptr;
2227  xl_heap_multi_insert *xlrec;
2229  char *tupledata;
2230  int totaldatalen;
2231  char *scratchptr = scratch.data;
2232  bool init;
2233  int bufflags = 0;
2234 
2235  /*
2236  * If the page was previously empty, we can reinit the page
2237  * instead of restoring the whole thing.
2238  */
2239  init = (ItemPointerGetOffsetNumber(&(heaptuples[ndone]->t_self)) == FirstOffsetNumber &&
2240  PageGetMaxOffsetNumber(page) == FirstOffsetNumber + nthispage - 1);
2241 
2242  /* allocate xl_heap_multi_insert struct from the scratch area */
2243  xlrec = (xl_heap_multi_insert *) scratchptr;
2244  scratchptr += SizeOfHeapMultiInsert;
2245 
2246  /*
2247  * Allocate offsets array. Unless we're reinitializing the page,
2248  * in that case the tuples are stored in order starting at
2249  * FirstOffsetNumber and we don't need to store the offsets
2250  * explicitly.
2251  */
2252  if (!init)
2253  scratchptr += nthispage * sizeof(OffsetNumber);
2254 
2255  /* the rest of the scratch space is used for tuple data */
2256  tupledata = scratchptr;
2257 
2258  xlrec->flags = all_visible_cleared ? XLH_INSERT_ALL_VISIBLE_CLEARED : 0;
2259  xlrec->ntuples = nthispage;
2260 
2261  /*
2262  * Write out an xl_multi_insert_tuple and the tuple data itself
2263  * for each tuple.
2264  */
2265  for (i = 0; i < nthispage; i++)
2266  {
2267  HeapTuple heaptup = heaptuples[ndone + i];
2268  xl_multi_insert_tuple *tuphdr;
2269  int datalen;
2270 
2271  if (!init)
2272  xlrec->offsets[i] = ItemPointerGetOffsetNumber(&heaptup->t_self);
2273  /* xl_multi_insert_tuple needs two-byte alignment. */
2274  tuphdr = (xl_multi_insert_tuple *) SHORTALIGN(scratchptr);
2275  scratchptr = ((char *) tuphdr) + SizeOfMultiInsertTuple;
2276 
2277  tuphdr->t_infomask2 = heaptup->t_data->t_infomask2;
2278  tuphdr->t_infomask = heaptup->t_data->t_infomask;
2279  tuphdr->t_hoff = heaptup->t_data->t_hoff;
2280 
2281  /* write bitmap [+ padding] [+ oid] + data */
2282  datalen = heaptup->t_len - SizeofHeapTupleHeader;
2283  memcpy(scratchptr,
2284  (char *) heaptup->t_data + SizeofHeapTupleHeader,
2285  datalen);
2286  tuphdr->datalen = datalen;
2287  scratchptr += datalen;
2288  }
2289  totaldatalen = scratchptr - tupledata;
2290  Assert((scratchptr - scratch.data) < BLCKSZ);
2291 
2292  if (need_tuple_data)
2294 
2295  /*
2296  * Signal that this is the last xl_heap_multi_insert record
2297  * emitted by this call to heap_multi_insert(). Needed for logical
2298  * decoding so it knows when to cleanup temporary data.
2299  */
2300  if (ndone + nthispage == ntuples)
2301  xlrec->flags |= XLH_INSERT_LAST_IN_MULTI;
2302 
2303  if (init)
2304  {
2305  info |= XLOG_HEAP_INIT_PAGE;
2306  bufflags |= REGBUF_WILL_INIT;
2307  }
2308 
2309  /*
2310  * If we're doing logical decoding, include the new tuple data
2311  * even if we take a full-page image of the page.
2312  */
2313  if (need_tuple_data)
2314  bufflags |= REGBUF_KEEP_DATA;
2315 
2316  XLogBeginInsert();
2317  XLogRegisterData((char *) xlrec, tupledata - scratch.data);
2318  XLogRegisterBuffer(0, buffer, REGBUF_STANDARD | bufflags);
2319 
2320  XLogRegisterBufData(0, tupledata, totaldatalen);
2321 
2322  /* filtering by origin on a row level is much more efficient */
2324 
2325  recptr = XLogInsert(RM_HEAP2_ID, info);
2326 
2327  PageSetLSN(page, recptr);
2328  }
2329 
2330  END_CRIT_SECTION();
2331 
2332  UnlockReleaseBuffer(buffer);
2333  if (vmbuffer != InvalidBuffer)
2334  ReleaseBuffer(vmbuffer);
2335 
2336  ndone += nthispage;
2337  }
2338 
2339  /*
2340  * We're done with the actual inserts. Check for conflicts again, to
2341  * ensure that all rw-conflicts in to these inserts are detected. Without
2342  * this final check, a sequential scan of the heap may have locked the
2343  * table after the "before" check, missing one opportunity to detect the
2344  * conflict, and then scanned the table before the new tuples were there,
2345  * missing the other chance to detect the conflict.
2346  *
2347  * For heap inserts, we only need to check for table-level SSI locks. Our
2348  * new tuples can't possibly conflict with existing tuple locks, and heap
2349  * page locks are only consolidated versions of tuple locks; they do not
2350  * lock "gaps" as index page locks do. So we don't need to specify a
2351  * buffer when making the call.
2352  */
2354 
2355  /*
2356  * If tuples are cachable, mark them for invalidation from the caches in
2357  * case we abort. Note it is OK to do this after releasing the buffer,
2358  * because the heaptuples data structure is all in local memory, not in
2359  * the shared buffer.
2360  */
2361  if (IsCatalogRelation(relation))
2362  {
2363  for (i = 0; i < ntuples; i++)
2364  CacheInvalidateHeapTuple(relation, heaptuples[i], NULL);
2365  }
2366 
2367  /* copy t_self fields back to the caller's slots */
2368  for (i = 0; i < ntuples; i++)
2369  slots[i]->tts_tid = heaptuples[i]->t_self;
2370 
2371  pgstat_count_heap_insert(relation, ntuples);
2372 }
void XLogRegisterBufData(uint8 block_id, char *data, int len)
Definition: xloginsert.c:361
Oid tts_tableOid
Definition: tuptable.h:131
#define SizeofHeapTupleHeader
Definition: htup_details.h:184
bool IsCatalogRelation(Relation relation)
Definition: catalog.c:100
static XLogRecPtr log_heap_new_cid(Relation relation, HeapTuple tup)
Definition: heapam.c:7523
void CacheInvalidateHeapTuple(Relation relation, HeapTuple tuple, HeapTuple newtuple)
Definition: inval.c:1114
static HeapTuple heap_prepare_insert(Relation relation, HeapTuple tup, TransactionId xid, CommandId cid, int options)
Definition: heapam.c:2049
#define PageIsAllVisible(page)
Definition: bufpage.h:385
uint32 TransactionId
Definition: c.h:507
OffsetNumber offsets[FLEXIBLE_ARRAY_MEMBER]
Definition: heapam_xlog.h:177
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:1458
void XLogRegisterBuffer(uint8 block_id, Buffer buffer, uint8 flags)
Definition: xloginsert.c:213
#define END_CRIT_SECTION()
Definition: miscadmin.h:134
unsigned char uint8
Definition: c.h:356
#define InvalidBuffer
Definition: buf.h:25
#define SizeOfHeapMultiInsert
Definition: heapam_xlog.h:180
#define REGBUF_WILL_INIT
Definition: xloginsert.h:33
#define START_CRIT_SECTION()
Definition: miscadmin.h:132
#define XLOG_INCLUDE_ORIGIN
Definition: xlog.h:228
#define HEAP_INSERT_SKIP_WAL
Definition: heapam.h:32
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3365
#define RelationIsLogicallyLogged(relation)
Definition: rel.h:591
#define PageGetMaxOffsetNumber(page)
Definition: bufpage.h:357
void RelationPutHeapTuple(Relation relation, Buffer buffer, HeapTuple tuple, bool token)
Definition: hio.c:36
void CheckForSerializableConflictIn(Relation relation, HeapTuple tuple, Buffer buffer)
Definition: predicate.c:4442
#define XLOG_HEAP_INIT_PAGE
Definition: heapam_xlog.h:46
#define XLOG_HEAP2_MULTI_INSERT
Definition: heapam_xlog.h:58
uint16 OffsetNumber
Definition: off.h:24
#define VISIBILITYMAP_VALID_BITS
Definition: visibilitymap.h:28
HeapTupleHeader t_data
Definition: htup.h:68
char data[BLCKSZ]
Definition: c.h:1060
bool visibilitymap_clear(Relation rel, BlockNumber heapBlk, Buffer buf, uint8 flags)
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3388
Size PageGetHeapFreeSpace(Page page)
Definition: bufpage.c:665
#define XLH_INSERT_CONTAINS_NEW_TUPLE
Definition: heapam_xlog.h:69
ItemPointerData t_self
Definition: htup.h:65
TransactionId GetCurrentTransactionId(void)
Definition: xact.c:423
uint32 t_len
Definition: htup.h:64
#define FirstOffsetNumber
Definition: off.h:27
#define REGBUF_STANDARD
Definition: xloginsert.h:35
Buffer RelationGetBufferForTuple(Relation relation, Size len, Buffer otherBuffer, int options, BulkInsertState bistate, Buffer *vmbuffer, Buffer *vmbuffer_other)
Definition: hio.c:320
Oid t_tableOid
Definition: htup.h:66
void XLogSetRecordFlags(uint8 flags)
Definition: xloginsert.c:397
#define init()
#define BufferGetPage(buffer)
Definition: bufmgr.h:159
#define AssertArg(condition)
Definition: c.h:734
HeapTuple ExecFetchSlotHeapTuple(TupleTableSlot *slot, bool materialize, bool *shouldFree)
Definition: execTuples.c:1609
#define RelationGetTargetPageFreeSpace(relation, defaultff)
Definition: rel.h:307
#define XLH_INSERT_LAST_IN_MULTI
Definition: heapam_xlog.h:67
void XLogRegisterData(char *data, int len)
Definition: xloginsert.c:323
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:415
#define RelationIsAccessibleInLogicalDecoding(relation)
Definition: rel.h:575
#define REGBUF_KEEP_DATA
Definition: xloginsert.h:38
#define PageClearAllVisible(page)
Definition: bufpage.h:389
uint64 XLogRecPtr
Definition: xlogdefs.h:21
#define Assert(condition)
Definition: c.h:732
size_t Size
Definition: c.h:466
#define MAXALIGN(LEN)
Definition: c.h:685
#define ItemPointerGetOffsetNumber(pointer)
Definition: itemptr.h:117
#define RelationNeedsWAL(relation)
Definition: rel.h:521
#define XLH_INSERT_ALL_VISIBLE_CLEARED
Definition: heapam_xlog.h:66
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:2613
void pgstat_count_heap_insert(Relation rel, PgStat_Counter n)
Definition: pgstat.c:1948
void * palloc(Size size)
Definition: mcxt.c:949
#define HEAP_INSERT_NO_LOGICAL
Definition: heapam.h:35
int i
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:99
#define HEAP_DEFAULT_FILLFACTOR
Definition: rel.h:278
#define SHORTALIGN(LEN)
Definition: c.h:681
void XLogBeginInsert(void)
Definition: xloginsert.c:120
#define PageSetLSN(page, lsn)
Definition: bufpage.h:368
int Buffer
Definition: buf.h:23
#define RelationGetRelid(relation)
Definition: rel.h:419
Pointer Page
Definition: bufpage.h:78
#define SizeOfMultiInsertTuple
Definition: heapam_xlog.h:191

◆ heap_page_prune()

int heap_page_prune ( Relation  relation,
Buffer  buffer,
TransactionId  OldestXmin,
bool  report_stats,
TransactionId latestRemovedXid 
)

Definition at line 180 of file pruneheap.c.

References BufferGetPage, END_CRIT_SECTION, FirstOffsetNumber, heap_page_prune_execute(), heap_prune_chain(), InvalidTransactionId, ItemIdIsDead, ItemIdIsUsed, PruneState::latestRemovedXid, log_heap_clean(), MarkBufferDirty(), MarkBufferDirtyHint(), PruneState::marked, PruneState::ndead, PruneState::new_prune_xid, PruneState::nowdead, PruneState::nowunused, PruneState::nredirected, PruneState::nunused, OffsetNumberNext, PageClearFull, PageGetItemId, PageGetMaxOffsetNumber, PageIsFull, PageSetLSN, pgstat_update_heap_dead_tuples(), PruneState::redirected, RelationNeedsWAL, and START_CRIT_SECTION.

Referenced by heap_page_prune_opt(), and lazy_scan_heap().

182 {
183  int ndeleted = 0;
184  Page page = BufferGetPage(buffer);
185  OffsetNumber offnum,
186  maxoff;
187  PruneState prstate;
188 
189  /*
190  * Our strategy is to scan the page and make lists of items to change,
191  * then apply the changes within a critical section. This keeps as much
192  * logic as possible out of the critical section, and also ensures that
193  * WAL replay will work the same as the normal case.
194  *
195  * First, initialize the new pd_prune_xid value to zero (indicating no
196  * prunable tuples). If we find any tuples which may soon become
197  * prunable, we will save the lowest relevant XID in new_prune_xid. Also
198  * initialize the rest of our working state.
199  */
201  prstate.latestRemovedXid = *latestRemovedXid;
202  prstate.nredirected = prstate.ndead = prstate.nunused = 0;
203  memset(prstate.marked, 0, sizeof(prstate.marked));
204 
205  /* Scan the page */
206  maxoff = PageGetMaxOffsetNumber(page);
207  for (offnum = FirstOffsetNumber;
208  offnum <= maxoff;
209  offnum = OffsetNumberNext(offnum))
210  {
211  ItemId itemid;
212 
213  /* Ignore items already processed as part of an earlier chain */
214  if (prstate.marked[offnum])
215  continue;
216 
217  /* Nothing to do if slot is empty or already dead */
218  itemid = PageGetItemId(page, offnum);
219  if (!ItemIdIsUsed(itemid) || ItemIdIsDead(itemid))
220  continue;
221 
222  /* Process this item or chain of items */
223  ndeleted += heap_prune_chain(relation, buffer, offnum,
224  OldestXmin,
225  &prstate);
226  }
227 
228  /* Any error while applying the changes is critical */
230 
231  /* Have we found any prunable items? */
232  if (prstate.nredirected > 0 || prstate.ndead > 0 || prstate.nunused > 0)
233  {
234  /*
235  * Apply the planned item changes, then repair page fragmentation, and
236  * update the page's hint bit about whether it has free line pointers.
237  */
239  prstate.redirected, prstate.nredirected,
240  prstate.nowdead, prstate.ndead,
241  prstate.nowunused, prstate.nunused);
242 
243  /*
244  * Update the page's pd_prune_xid field to either zero, or the lowest
245  * XID of any soon-prunable tuple.
246  */
247  ((PageHeader) page)->pd_prune_xid = prstate.new_prune_xid;
248 
249  /*
250  * Also clear the "page is full" flag, since there's no point in
251  * repeating the prune/defrag process until something else happens to
252  * the page.
253  */
254  PageClearFull(page);
255 
256  MarkBufferDirty(buffer);
257 
258  /*
259  * Emit a WAL XLOG_HEAP2_CLEAN record showing what we did
260  */
261  if (RelationNeedsWAL(relation))
262  {
263  XLogRecPtr recptr;
264 
265  recptr = log_heap_clean(relation, buffer,
266  prstate.redirected, prstate.nredirected,
267  prstate.nowdead, prstate.ndead,
268  prstate.nowunused, prstate.nunused,
269  prstate.latestRemovedXid);
270 
271  PageSetLSN(BufferGetPage(buffer), recptr);
272  }
273  }
274  else
275  {
276  /*
277  * If we didn't prune anything, but have found a new value for the
278  * pd_prune_xid field, update it and mark the buffer dirty. This is
279  * treated as a non-WAL-logged hint.
280  *
281  * Also clear the "page is full" flag if it is set, since there's no
282  * point in repeating the prune/defrag process until something else
283  * happens to the page.
284  */
285  if (((PageHeader) page)->pd_prune_xid != prstate.new_prune_xid ||
286  PageIsFull(page))
287  {
288  ((PageHeader) page)->pd_prune_xid = prstate.new_prune_xid;
289  PageClearFull(page);
290  MarkBufferDirtyHint(buffer, true);
291  }
292  }
293 
295 
296  /*
297  * If requested, report the number of tuples reclaimed to pgstats. This is
298  * ndeleted minus ndead, because we don't want to count a now-DEAD root
299  * item as a deletion for this purpose.
300  */
301  if (report_stats && ndeleted > prstate.ndead)
302  pgstat_update_heap_dead_tuples(relation, ndeleted - prstate.ndead);
303 
304  *latestRemovedXid = prstate.latestRemovedXid;
305 
306  /*
307  * XXX Should we update the FSM information of this page ?
308  *
309  * There are two schools of thought here. We may not want to update FSM
310  * information so that the page is not used for unrelated UPDATEs/INSERTs
311  * and any free space in this page will remain available for further
312  * UPDATEs in *this* page, thus improving chances for doing HOT updates.
313  *
314  * But for a large table and where a page does not receive further UPDATEs
315  * for a long time, we might waste this space by not updating the FSM
316  * information. The relation may get extended and fragmented further.
317  *
318  * One possibility is to leave "fillfactor" worth of space in this page
319  * and update FSM with the remaining space.
320  */
321 
322  return ndeleted;
323 }
static int heap_prune_chain(Relation relation, Buffer buffer, OffsetNumber rootoffnum, TransactionId OldestXmin, PruneState *prstate)
Definition: pruneheap.c:352
int nredirected
Definition: pruneheap.c:34
void pgstat_update_heap_dead_tuples(Relation rel, int delta)
Definition: pgstat.c:2078
void MarkBufferDirtyHint(Buffer buffer, bool buffer_std)
Definition: bufmgr.c:3435
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:1458
#define END_CRIT_SECTION()
Definition: miscadmin.h:134
#define ItemIdIsUsed(itemId)
Definition: itemid.h:92
#define START_CRIT_SECTION()
Definition: miscadmin.h:132
OffsetNumber nowdead[MaxHeapTuplesPerPage]
Definition: pruneheap.c:39
#define ItemIdIsDead(itemId)
Definition: itemid.h:113
bool marked[MaxHeapTuplesPerPage+1]
Definition: pruneheap.c:42
#define PageGetMaxOffsetNumber(page)
Definition: bufpage.h:357
TransactionId new_prune_xid
Definition: pruneheap.c:32
#define PageIsFull(page)
Definition: bufpage.h:378
int nunused
Definition: pruneheap.c:36
uint16 OffsetNumber
Definition: off.h:24
TransactionId latestRemovedXid
Definition: pruneheap.c:33
#define FirstOffsetNumber
Definition: off.h:27
#define InvalidTransactionId
Definition: transam.h:31
static TransactionId OldestXmin
Definition: vacuumlazy.c:145
#define BufferGetPage(buffer)
Definition: bufmgr.h:159
#define PageClearFull(page)
Definition: bufpage.h:382
#define PageGetItemId(page, offsetNumber)
Definition: bufpage.h:235
void heap_page_prune_execute(Buffer buffer, OffsetNumber *redirected, int nredirected, OffsetNumber *nowdead, int ndead, OffsetNumber *nowunused, int nunused)
Definition: pruneheap.c:681
PageHeaderData * PageHeader
Definition: bufpage.h:166
uint64 XLogRecPtr
Definition: xlogdefs.h:21
#define OffsetNumberNext(offsetNumber)
Definition: off.h:52
OffsetNumber nowunused[MaxHeapTuplesPerPage]
Definition: pruneheap.c:40
XLogRecPtr log_heap_clean(Relation reln, Buffer buffer, OffsetNumber *redirected, int nredirected, OffsetNumber *nowdead, int ndead, OffsetNumber *nowunused, int nunused, TransactionId latestRemovedXid)
Definition: heapam.c:7177
#define RelationNeedsWAL(relation)
Definition: rel.h:521
OffsetNumber redirected[MaxHeapTuplesPerPage *2]
Definition: pruneheap.c:38
int ndead
Definition: pruneheap.c:35
#define PageSetLSN(page, lsn)
Definition: bufpage.h:368
Pointer Page
Definition: bufpage.h:78

◆ heap_page_prune_execute()

void heap_page_prune_execute ( Buffer  buffer,
OffsetNumber redirected,
int  nredirected,
OffsetNumber nowdead,
int  ndead,
OffsetNumber nowunused,
int  nunused 
)

Definition at line 681 of file pruneheap.c.

References BufferGetPage, i, ItemIdSetDead, ItemIdSetRedirect, ItemIdSetUnused, PageGetItemId, and PageRepairFragmentation().

Referenced by heap_page_prune(), and heap_xlog_clean().

685 {
686  Page page = (Page) BufferGetPage(buffer);
687  OffsetNumber *offnum;
688  int i;
689 
690  /* Update all redirected line pointers */
691  offnum = redirected;
692  for (i = 0; i < nredirected; i++)
693  {
694  OffsetNumber fromoff = *offnum++;
695  OffsetNumber tooff = *offnum++;
696  ItemId fromlp = PageGetItemId(page, fromoff);
697 
698  ItemIdSetRedirect(fromlp, tooff);
699  }
700 
701  /* Update all now-dead line pointers */
702  offnum = nowdead;
703  for (i = 0; i < ndead; i++)
704  {
705  OffsetNumber off = *offnum++;
706  ItemId lp = PageGetItemId(page, off);
707 
708  ItemIdSetDead(lp);
709  }
710 
711  /* Update all now-unused line pointers */
712  offnum = nowunused;
713  for (i = 0; i < nunused; i++)
714  {
715  OffsetNumber off = *offnum++;
716  ItemId lp = PageGetItemId(page, off);
717 
718  ItemIdSetUnused(lp);
719  }
720 
721  /*
722  * Finally, repair any fragmentation, and update the page's hint bit about
723  * whether it has free pointers.
724  */
726 }
uint16 OffsetNumber
Definition: off.h:24
#define ItemIdSetRedirect(itemId, link)
Definition: itemid.h:152
#define BufferGetPage(buffer)
Definition: bufmgr.h:159
#define PageGetItemId(page, offsetNumber)
Definition: bufpage.h:235
void PageRepairFragmentation(Page page)
Definition: bufpage.c:482
int i
#define ItemIdSetDead(itemId)
Definition: itemid.h:164
#define ItemIdSetUnused(itemId)
Definition: itemid.h:128
Pointer Page
Definition: bufpage.h:78

◆ heap_page_prune_opt()

void heap_page_prune_opt ( Relation  relation,
Buffer  buffer 
)

Definition at line 73 of file pruneheap.c.

References Assert, BUFFER_LOCK_UNLOCK, BufferGetPage, ConditionalLockBufferForCleanup(), HEAP_DEFAULT_FILLFACTOR, heap_page_prune(), InvalidTransactionId, IsCatalogRelation(), LockBuffer(), Max, OldestXmin, PageGetHeapFreeSpace(), PageIsFull, PageIsPrunable, RecentGlobalDataXmin, RecentGlobalXmin, RecoveryInProgress(), RelationGetTargetPageFreeSpace, RelationIsAccessibleInLogicalDecoding, TransactionIdIsValid, and TransactionIdLimitedForOldSnapshots().

Referenced by heapam_index_fetch_tuple(), heapam_scan_bitmap_next_block(), and heapgetpage().

74 {
75  Page page = BufferGetPage(buffer);
76  Size minfree;
78 
79  /*
80  * We can't write WAL in recovery mode, so there's no point trying to
81  * clean the page. The master will likely issue a cleaning WAL record soon
82  * anyway, so this is no particular loss.
83  */
84  if (RecoveryInProgress())
85  return;
86 
87  /*
88  * Use the appropriate xmin horizon for this relation. If it's a proper
89  * catalog relation or a user defined, additional, catalog relation, we
90  * need to use the horizon that includes slots, otherwise the data-only
91  * horizon can be used. Note that the toast relation of user defined
92  * relations are *not* considered catalog relations.
93  *
94  * It is OK to apply the old snapshot limit before acquiring the cleanup
95  * lock because the worst that can happen is that we are not quite as
96  * aggressive about the cleanup (by however many transaction IDs are
97  * consumed between this point and acquiring the lock). This allows us to
98  * save significant overhead in the case where the page is found not to be
99  * prunable.
100  */
101  if (IsCatalogRelation(relation) ||
103  OldestXmin = RecentGlobalXmin;
104  else
105  OldestXmin =
107  relation);
108 
109  Assert(TransactionIdIsValid(OldestXmin));
110 
111  /*
112  * Let's see if we really need pruning.
113  *
114  * Forget it if page is not hinted to contain something prunable that's
115  * older than OldestXmin.
116  */
117  if (!PageIsPrunable(page, OldestXmin))
118  return;
119 
120  /*
121  * We prune when a previous UPDATE failed to find enough space on the page
122  * for a new tuple version, or when free space falls below the relation's
123  * fill-factor target (but not less than 10%).
124  *
125  * Checking free space here is questionable since we aren't holding any
126  * lock on the buffer; in the worst case we could get a bogus answer. It's
127  * unlikely to be *seriously* wrong, though, since reading either pd_lower
128  * or pd_upper is probably atomic. Avoiding taking a lock seems more
129  * important than sometimes getting a wrong answer in what is after all
130  * just a heuristic estimate.
131  */
132  minfree = RelationGetTargetPageFreeSpace(relation,
134  minfree = Max(minfree, BLCKSZ / 10);
135 
136  if (PageIsFull(page) || PageGetHeapFreeSpace(page) < minfree)
137  {
138  /* OK, try to get exclusive buffer lock */
139  if (!ConditionalLockBufferForCleanup(buffer))
140  return;
141 
142  /*
143  * Now that we have buffer lock, get accurate information about the
144  * page's free space, and recheck the heuristic about whether to
145  * prune. (We needn't recheck PageIsPrunable, since no one else could
146  * have pruned while we hold pin.)
147  */
148  if (PageIsFull(page) || PageGetHeapFreeSpace(page) < minfree)
149  {
150  TransactionId ignore = InvalidTransactionId; /* return value not
151  * needed */
152 
153  /* OK to prune */
154  (void) heap_page_prune(relation, buffer, OldestXmin, true, &ignore);
155  }
156 
157  /* And release buffer lock */
159  }
160 }
#define BUFFER_LOCK_UNLOCK
Definition: bufmgr.h:86
int heap_page_prune(Relation relation, Buffer buffer, TransactionId OldestXmin, bool report_stats, TransactionId *latestRemovedXid)
Definition: pruneheap.c:180
bool IsCatalogRelation(Relation relation)
Definition: catalog.c:100
uint32 TransactionId
Definition: c.h:507
TransactionId TransactionIdLimitedForOldSnapshots(TransactionId recentXmin, Relation relation)
Definition: snapmgr.c:1775
bool RecoveryInProgress(void)
Definition: xlog.c:7917
#define PageIsFull(page)
Definition: bufpage.h:378
bool ConditionalLockBufferForCleanup(Buffer buffer)
Definition: bufmgr.c:3774
Size PageGetHeapFreeSpace(Page page)
Definition: bufpage.c:665
TransactionId RecentGlobalXmin
Definition: snapmgr.c:168
#define InvalidTransactionId
Definition: transam.h:31
static TransactionId OldestXmin
Definition: vacuumlazy.c:145
#define BufferGetPage(buffer)
Definition: bufmgr.h:159
TransactionId RecentGlobalDataXmin
Definition: snapmgr.c:169
#define RelationGetTargetPageFreeSpace(relation, defaultff)
Definition: rel.h:307
#define RelationIsAccessibleInLogicalDecoding(relation)
Definition: rel.h:575
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3602
#define Max(x, y)
Definition: c.h:898
#define Assert(condition)
Definition: c.h:732
size_t Size
Definition: c.h:466
#define PageIsPrunable(page, oldestxmin)
Definition: bufpage.h:392
#define HEAP_DEFAULT_FILLFACTOR
Definition: rel.h:278
#define TransactionIdIsValid(xid)
Definition: transam.h:41
Pointer Page
Definition: bufpage.h:78

◆ heap_rescan()

void heap_rescan ( TableScanDesc  scan,
ScanKey  key,
bool  set_params,
bool  allow_strat,
bool  allow_sync,
bool  allow_pagemode 
)

Definition at line 1208 of file heapam.c.

References BufferIsValid, initscan(), IsMVCCSnapshot, ReleaseBuffer(), HeapScanDescData::rs_base, HeapScanDescData::rs_cbuf, TableScanDescData::rs_flags, TableScanDescData::rs_snapshot, SO_ALLOW_PAGEMODE, SO_ALLOW_STRAT, and SO_ALLOW_SYNC.

Referenced by SampleHeapTupleVisible().

1210 {
1211  HeapScanDesc scan = (HeapScanDesc) sscan;
1212 
1213  if (set_params)
1214  {
1215  if (allow_strat)
1216  scan->rs_base.rs_flags |= SO_ALLOW_STRAT;
1217  else
1218  scan->rs_base.rs_flags &= ~SO_ALLOW_STRAT;
1219 
1220  if (allow_sync)
1221  scan->rs_base.rs_flags |= SO_ALLOW_SYNC;
1222  else
1223  scan->rs_base.rs_flags &= ~SO_ALLOW_SYNC;
1224 
1225  if (allow_pagemode && scan->rs_base.rs_snapshot &&
1228  else
1230  }
1231 
1232  /*
1233  * unpin scan buffers
1234  */
1235  if (BufferIsValid(scan->rs_cbuf))
1236  ReleaseBuffer(scan->rs_cbuf);
1237 
1238  /*
1239  * reinitialize scan descriptor
1240  */
1241  initscan(scan, key, true);
1242 }
TableScanDescData rs_base
Definition: heapam.h:48
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3365
uint32 rs_flags
Definition: relscan.h:43
struct HeapScanDescData * HeapScanDesc
Definition: heapam.h:72
#define IsMVCCSnapshot(snapshot)
Definition: snapmgr.h:97
Buffer rs_cbuf
Definition: heapam.h:59
#define BufferIsValid(bufnum)
Definition: bufmgr.h:113
struct SnapshotData * rs_snapshot
Definition: relscan.h:35
static void initscan(HeapScanDesc scan, ScanKey key, bool keep_startblock)
Definition: heapam.c:208

◆ heap_setscanlimits()

void heap_setscanlimits ( TableScanDesc  scan,
BlockNumber  startBlk,
BlockNumber  numBlks 
)

Definition at line 329 of file heapam.c.

References Assert, HeapScanDescData::rs_base, TableScanDescData::rs_flags, HeapScanDescData::rs_inited, HeapScanDescData::rs_numblocks, HeapScanDescData::rs_startblock, and SO_ALLOW_SYNC.

Referenced by heapam_index_build_range_scan().

330 {
331  HeapScanDesc scan = (HeapScanDesc) sscan;
332 
333  Assert(!scan->rs_inited); /* else too late to change */
334  /* else rs_startblock is significant */
335  Assert(!(scan->rs_base.rs_flags & SO_ALLOW_SYNC));
336 
337  /* Check startBlk is valid (but allow case of zero blocks...) */
338  Assert(startBlk == 0 || startBlk < scan->rs_nblocks);
339 
340  scan->rs_startblock = startBlk;
341  scan->rs_numblocks = numBlks;
342 }
TableScanDescData rs_base
Definition: heapam.h:48
uint32 rs_flags
Definition: relscan.h:43
struct HeapScanDescData * HeapScanDesc
Definition: heapam.h:72
BlockNumber rs_numblocks
Definition: heapam.h:53
bool rs_inited
Definition: heapam.h:57
BlockNumber rs_startblock
Definition: heapam.h:52
#define Assert(condition)
Definition: c.h:732

◆ heap_sync()

void heap_sync ( Relation  relation)

Definition at line 8938 of file heapam.c.

References AccessShareLock, FlushRelationBuffers(), MAIN_FORKNUM, OidIsValid, RelationData::rd_rel, RelationData::rd_smgr, RelationNeedsWAL, smgrimmedsync(), table_close(), and table_open().

Referenced by end_heap_rewrite(), and heapam_finish_bulk_insert().

8939 {
8940  /* non-WAL-logged tables never need fsync */
8941  if (!RelationNeedsWAL(rel))
8942  return;
8943 
8944  /* main heap */
8945  FlushRelationBuffers(rel);
8946  /* FlushRelationBuffers will have opened rd_smgr */
8947  smgrimmedsync(rel->rd_smgr, MAIN_FORKNUM);
8948 
8949  /* FSM is not critical, don't bother syncing it */
8950 
8951  /* toast heap, if any */
8952  if (OidIsValid(rel->rd_rel->reltoastrelid))
8953  {
8954  Relation toastrel;
8955 
8956  toastrel = table_open(rel->rd_rel->reltoastrelid, AccessShareLock);
8957  FlushRelationBuffers(toastrel);
8958  smgrimmedsync(toastrel->rd_smgr, MAIN_FORKNUM);
8959  table_close(toastrel, AccessShareLock);
8960  }
8961 }
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
struct SMgrRelationData * rd_smgr
Definition: rel.h:56
#define AccessShareLock
Definition: lockdefs.h:36
#define OidIsValid(objectId)
Definition: c.h:638
void FlushRelationBuffers(Relation rel)
Definition: bufmgr.c:3204
#define RelationNeedsWAL(relation)
Definition: rel.h:521
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
void smgrimmedsync(SMgrRelation reln, ForkNumber forknum)
Definition: smgr.c:637

◆ heap_tuple_needs_eventual_freeze()

bool heap_tuple_needs_eventual_freeze ( HeapTupleHeader  tuple)

Definition at line 6763 of file heapam.c.

References HEAP_MOVED, HEAP_XMAX_IS_MULTI, HeapTupleHeaderGetRawXmax, HeapTupleHeaderGetXmin, HeapTupleHeaderGetXvac, MultiXactIdIsValid, HeapTupleHeaderData::t_infomask, and TransactionIdIsNormal.

Referenced by collect_corrupt_items(), and heap_page_is_all_visible().

6764 {
6765  TransactionId xid;
6766 
6767  /*
6768  * If xmin is a normal transaction ID, this tuple is definitely not
6769  * frozen.
6770  */
6771  xid = HeapTupleHeaderGetXmin(tuple);
6772  if (TransactionIdIsNormal(xid))
6773  return true;
6774 
6775  /*
6776  * If xmax is a valid xact or multixact, this tuple is also not frozen.
6777  */
6778  if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
6779  {
6780  MultiXactId multi;
6781 
6782  multi = HeapTupleHeaderGetRawXmax(tuple);
6783  if (MultiXactIdIsValid(multi))
6784  return true;
6785  }
6786  else
6787  {
6788  xid = HeapTupleHeaderGetRawXmax(tuple);
6789  if (TransactionIdIsNormal(xid))
6790  return true;
6791  }
6792 
6793  if (tuple->t_infomask & HEAP_MOVED)
6794  {
6795  xid = HeapTupleHeaderGetXvac(tuple);
6796  if (TransactionIdIsNormal(xid))
6797  return true;
6798  }
6799 
6800  return false;
6801 }
uint32 TransactionId
Definition: c.h:507
#define HeapTupleHeaderGetRawXmax(tup)
Definition: htup_details.h:375
#define HeapTupleHeaderGetXvac(tup)
Definition: htup_details.h:415
#define MultiXactIdIsValid(multi)
Definition: multixact.h:27
#define HEAP_XMAX_IS_MULTI
Definition: htup_details.h:208
#define HEAP_MOVED
Definition: htup_details.h:216
TransactionId MultiXactId
Definition: c.h:517
#define HeapTupleHeaderGetXmin(tup)
Definition: htup_details.h:313
#define TransactionIdIsNormal(xid)
Definition: transam.h:42

◆ heap_tuple_needs_freeze()