PostgreSQL Source Code  git master
heapam.c File Reference
#include "postgres.h"
#include "access/bufmask.h"
#include "access/genam.h"
#include "access/heapam.h"
#include "access/heapam_xlog.h"
#include "access/heaptoast.h"
#include "access/hio.h"
#include "access/multixact.h"
#include "access/parallel.h"
#include "access/relscan.h"
#include "access/subtrans.h"
#include "access/syncscan.h"
#include "access/sysattr.h"
#include "access/tableam.h"
#include "access/transam.h"
#include "access/valid.h"
#include "access/visibilitymap.h"
#include "access/xact.h"
#include "access/xlog.h"
#include "access/xloginsert.h"
#include "access/xlogutils.h"
#include "catalog/catalog.h"
#include "miscadmin.h"
#include "pgstat.h"
#include "port/atomics.h"
#include "port/pg_bitutils.h"
#include "storage/bufmgr.h"
#include "storage/freespace.h"
#include "storage/lmgr.h"
#include "storage/predicate.h"
#include "storage/procarray.h"
#include "storage/smgr.h"
#include "storage/spin.h"
#include "storage/standby.h"
#include "utils/datum.h"
#include "utils/inval.h"
#include "utils/lsyscache.h"
#include "utils/relcache.h"
#include "utils/snapmgr.h"
#include "utils/spccache.h"
Include dependency graph for heapam.c:

Go to the source code of this file.

Data Structures

struct  IndexDeleteCounts
 

Macros

#define LOCKMODE_from_mxstatus(status)   (tupleLockExtraInfo[TUPLOCK_from_mxstatus((status))].hwlock)
 
#define LockTupleTuplock(rel, tup, mode)   LockTuple((rel), (tup), tupleLockExtraInfo[mode].hwlock)
 
#define UnlockTupleTuplock(rel, tup, mode)   UnlockTuple((rel), (tup), tupleLockExtraInfo[mode].hwlock)
 
#define ConditionalLockTupleTuplock(rel, tup, mode)   ConditionalLockTuple((rel), (tup), tupleLockExtraInfo[mode].hwlock)
 
#define BOTTOMUP_MAX_NBLOCKS   6
 
#define BOTTOMUP_TOLERANCE_NBLOCKS   3
 
#define TUPLOCK_from_mxstatus(status)   (MultiXactStatusLock[(status)])
 
#define FRM_NOOP   0x0001
 
#define FRM_INVALIDATE_XMAX   0x0002
 
#define FRM_RETURN_IS_XID   0x0004
 
#define FRM_RETURN_IS_MULTI   0x0008
 
#define FRM_MARK_COMMITTED   0x0010
 

Typedefs

typedef struct IndexDeleteCounts IndexDeleteCounts
 

Functions

static HeapTuple heap_prepare_insert (Relation relation, HeapTuple tup, TransactionId xid, CommandId cid, int options)
 
static XLogRecPtr log_heap_update (Relation reln, Buffer oldbuf, Buffer newbuf, HeapTuple oldtup, HeapTuple newtup, HeapTuple old_key_tuple, bool all_visible_cleared, bool new_all_visible_cleared)
 
static BitmapsetHeapDetermineModifiedColumns (Relation relation, Bitmapset *interesting_cols, HeapTuple oldtup, HeapTuple newtup)
 
static bool heap_acquire_tuplock (Relation relation, ItemPointer tid, LockTupleMode mode, LockWaitPolicy wait_policy, bool *have_tuple_lock)
 
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)
 
static TM_Result heap_lock_updated_tuple (Relation rel, HeapTuple tuple, ItemPointer ctid, TransactionId xid, LockTupleMode mode)
 
static void GetMultiXactIdHintBits (MultiXactId multi, uint16 *new_infomask, uint16 *new_infomask2)
 
static TransactionId MultiXactIdGetUpdateXid (TransactionId xmax, uint16 t_infomask)
 
static bool DoesMultiXactIdConflict (MultiXactId multi, uint16 infomask, LockTupleMode lockmode, bool *current_is_member)
 
static void MultiXactIdWait (MultiXactId multi, MultiXactStatus status, uint16 infomask, Relation rel, ItemPointer ctid, XLTW_Oper oper, int *remaining)
 
static bool ConditionalMultiXactIdWait (MultiXactId multi, MultiXactStatus status, uint16 infomask, Relation rel, int *remaining)
 
static void index_delete_sort (TM_IndexDeleteOp *delstate)
 
static int bottomup_sort_and_shrink (TM_IndexDeleteOp *delstate)
 
static XLogRecPtr log_heap_new_cid (Relation relation, HeapTuple tup)
 
static HeapTuple ExtractReplicaIdentity (Relation rel, HeapTuple tup, bool key_changed, bool *copy)
 
static void initscan (HeapScanDesc scan, ScanKey key, bool keep_startblock)
 
void heap_setscanlimits (TableScanDesc sscan, BlockNumber startBlk, BlockNumber numBlks)
 
void heapgetpage (TableScanDesc sscan, BlockNumber page)
 
static void heapgettup (HeapScanDesc scan, ScanDirection dir, int nkeys, ScanKey key)
 
static void heapgettup_pagemode (HeapScanDesc scan, ScanDirection dir, int nkeys, ScanKey key)
 
TableScanDesc heap_beginscan (Relation relation, Snapshot snapshot, int nkeys, ScanKey key, ParallelTableScanDesc parallel_scan, uint32 flags)
 
void heap_rescan (TableScanDesc sscan, ScanKey key, bool set_params, bool allow_strat, bool allow_sync, bool allow_pagemode)
 
void heap_endscan (TableScanDesc sscan)
 
HeapTuple heap_getnext (TableScanDesc sscan, ScanDirection direction)
 
bool heap_getnextslot (TableScanDesc sscan, ScanDirection direction, TupleTableSlot *slot)
 
void heap_set_tidrange (TableScanDesc sscan, ItemPointer mintid, ItemPointer maxtid)
 
bool heap_getnextslot_tidrange (TableScanDesc sscan, ScanDirection direction, 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 sscan, ItemPointer tid)
 
static void UpdateXmaxHintBits (HeapTupleHeader tuple, Buffer buffer, TransactionId xid)
 
BulkInsertState GetBulkInsertState (void)
 
void FreeBulkInsertState (BulkInsertState bistate)
 
void ReleaseBulkInsertStatePin (BulkInsertState bistate)
 
void heap_insert (Relation relation, HeapTuple tup, CommandId cid, int options, BulkInsertState bistate)
 
void heap_multi_insert (Relation relation, TupleTableSlot **slots, int ntuples, CommandId cid, int options, BulkInsertState bistate)
 
void simple_heap_insert (Relation relation, HeapTuple tup)
 
static uint8 compute_infobits (uint16 infomask, uint16 infomask2)
 
static bool xmax_infomask_changed (uint16 new_infomask, uint16 old_infomask)
 
TM_Result heap_delete (Relation relation, ItemPointer tid, CommandId cid, Snapshot crosscheck, bool wait, TM_FailureData *tmfd, bool changingPart)
 
void simple_heap_delete (Relation relation, ItemPointer tid)
 
TM_Result heap_update (Relation relation, ItemPointer otid, HeapTuple newtup, CommandId cid, Snapshot crosscheck, bool wait, TM_FailureData *tmfd, LockTupleMode *lockmode)
 
static bool heap_tuple_attr_equals (TupleDesc tupdesc, int attrnum, HeapTuple tup1, HeapTuple tup2)
 
void simple_heap_update (Relation relation, ItemPointer otid, HeapTuple tup)
 
static MultiXactStatus get_mxact_status_for_lock (LockTupleMode mode, bool is_update)
 
TM_Result heap_lock_tuple (Relation relation, HeapTuple tuple, CommandId cid, LockTupleMode mode, LockWaitPolicy wait_policy, bool follow_updates, Buffer *buffer, TM_FailureData *tmfd)
 
static TM_Result test_lockmode_for_conflict (MultiXactStatus status, TransactionId xid, LockTupleMode mode, HeapTuple tup, bool *needwait)
 
static TM_Result heap_lock_updated_tuple_rec (Relation rel, ItemPointer tid, TransactionId xid, LockTupleMode mode)
 
void heap_finish_speculative (Relation relation, ItemPointer tid)
 
void heap_abort_speculative (Relation relation, ItemPointer tid)
 
void heap_inplace_update (Relation relation, HeapTuple tuple)
 
static TransactionId FreezeMultiXactId (MultiXactId multi, uint16 t_infomask, TransactionId relfrozenxid, TransactionId relminmxid, TransactionId cutoff_xid, MultiXactId cutoff_multi, uint16 *flags)
 
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)
 
void heap_execute_freeze_tuple (HeapTupleHeader tuple, xl_heap_freeze_tuple *frz)
 
bool heap_freeze_tuple (HeapTupleHeader tuple, TransactionId relfrozenxid, TransactionId relminmxid, TransactionId cutoff_xid, TransactionId cutoff_multi)
 
TransactionId HeapTupleGetUpdateXid (HeapTupleHeader tuple)
 
static bool Do_MultiXactIdWait (MultiXactId multi, MultiXactStatus status, uint16 infomask, bool nowait, Relation rel, ItemPointer ctid, XLTW_Oper oper, int *remaining)
 
bool heap_tuple_needs_eventual_freeze (HeapTupleHeader tuple)
 
bool heap_tuple_needs_freeze (HeapTupleHeader tuple, TransactionId cutoff_xid, MultiXactId cutoff_multi, Buffer buf)
 
void HeapTupleHeaderAdvanceLatestRemovedXid (HeapTupleHeader tuple, TransactionId *latestRemovedXid)
 
TransactionId heap_index_delete_tuples (Relation rel, TM_IndexDeleteOp *delstate)
 
static int index_delete_sort_cmp (TM_IndexDelete *deltid1, TM_IndexDelete *deltid2)
 
static int bottomup_nblocksfavorable (IndexDeleteCounts *blockgroups, int nblockgroups, TM_IndexDelete *deltids)
 
static int bottomup_sort_and_shrink_cmp (const void *arg1, const void *arg2)
 
XLogRecPtr log_heap_cleanup_info (RelFileNode rnode, TransactionId latestRemovedXid)
 
XLogRecPtr log_heap_clean (Relation reln, Buffer buffer, OffsetNumber *redirected, int nredirected, OffsetNumber *nowdead, int ndead, OffsetNumber *nowunused, int nunused, TransactionId latestRemovedXid)
 
XLogRecPtr log_heap_freeze (Relation reln, Buffer buffer, TransactionId cutoff_xid, xl_heap_freeze_tuple *tuples, int ntuples)
 
XLogRecPtr log_heap_visible (RelFileNode rnode, Buffer heap_buffer, Buffer vm_buffer, TransactionId cutoff_xid, uint8 vmflags)
 
static void heap_xlog_cleanup_info (XLogReaderState *record)
 
static void heap_xlog_clean (XLogReaderState *record)
 
static void heap_xlog_visible (XLogReaderState *record)
 
static void heap_xlog_freeze_page (XLogReaderState *record)
 
static void fix_infomask_from_infobits (uint8 infobits, uint16 *infomask, uint16 *infomask2)
 
static void heap_xlog_delete (XLogReaderState *record)
 
static void heap_xlog_insert (XLogReaderState *record)
 
static void heap_xlog_multi_insert (XLogReaderState *record)
 
static void heap_xlog_update (XLogReaderState *record, bool hot_update)
 
static void heap_xlog_confirm (XLogReaderState *record)
 
static void heap_xlog_lock (XLogReaderState *record)
 
static void heap_xlog_lock_updated (XLogReaderState *record)
 
static void heap_xlog_inplace (XLogReaderState *record)
 
void heap_redo (XLogReaderState *record)
 
void heap2_redo (XLogReaderState *record)
 
void heap_mask (char *pagedata, BlockNumber blkno)
 
void HeapCheckForSerializableConflictOut (bool visible, Relation relation, HeapTuple tuple, Buffer buffer, Snapshot snapshot)
 

Variables

struct {
   LOCKMODE   hwlock
 
   int   lockstatus
 
   int   updstatus
 
tupleLockExtraInfo [MaxLockTupleMode+1]
 
static const int MultiXactStatusLock [MaxMultiXactStatus+1]
 

Macro Definition Documentation

◆ BOTTOMUP_MAX_NBLOCKS

#define BOTTOMUP_MAX_NBLOCKS   6

◆ BOTTOMUP_TOLERANCE_NBLOCKS

#define BOTTOMUP_TOLERANCE_NBLOCKS   3

Definition at line 186 of file heapam.c.

Referenced by bottomup_nblocksfavorable().

◆ ConditionalLockTupleTuplock

#define ConditionalLockTupleTuplock (   rel,
  tup,
  mode 
)    ConditionalLockTuple((rel), (tup), tupleLockExtraInfo[mode].hwlock)

Definition at line 167 of file heapam.c.

Referenced by heap_acquire_tuplock().

◆ FRM_INVALIDATE_XMAX

#define FRM_INVALIDATE_XMAX   0x0002

Definition at line 6097 of file heapam.c.

Referenced by FreezeMultiXactId(), and heap_prepare_freeze_tuple().

◆ FRM_MARK_COMMITTED

#define FRM_MARK_COMMITTED   0x0010

Definition at line 6100 of file heapam.c.

Referenced by FreezeMultiXactId(), and heap_prepare_freeze_tuple().

◆ FRM_NOOP

#define FRM_NOOP   0x0001

Definition at line 6096 of file heapam.c.

Referenced by FreezeMultiXactId().

◆ FRM_RETURN_IS_MULTI

#define FRM_RETURN_IS_MULTI   0x0008

Definition at line 6099 of file heapam.c.

Referenced by FreezeMultiXactId(), and heap_prepare_freeze_tuple().

◆ FRM_RETURN_IS_XID

#define FRM_RETURN_IS_XID   0x0004

Definition at line 6098 of file heapam.c.

Referenced by FreezeMultiXactId(), and heap_prepare_freeze_tuple().

◆ LOCKMODE_from_mxstatus

#define LOCKMODE_from_mxstatus (   status)    (tupleLockExtraInfo[TUPLOCK_from_mxstatus((status))].hwlock)

◆ LockTupleTuplock

#define LockTupleTuplock (   rel,
  tup,
  mode 
)    LockTuple((rel), (tup), tupleLockExtraInfo[mode].hwlock)

Definition at line 163 of file heapam.c.

Referenced by heap_acquire_tuplock().

◆ TUPLOCK_from_mxstatus

#define TUPLOCK_from_mxstatus (   status)    (MultiXactStatusLock[(status)])

Definition at line 214 of file heapam.c.

Referenced by compute_new_xmax_infomask(), GetMultiXactIdHintBits(), and heap_lock_tuple().

◆ UnlockTupleTuplock

#define UnlockTupleTuplock (   rel,
  tup,
  mode 
)    UnlockTuple((rel), (tup), tupleLockExtraInfo[mode].hwlock)

Definition at line 165 of file heapam.c.

Referenced by heap_delete(), heap_lock_tuple(), and heap_update().

Typedef Documentation

◆ IndexDeleteCounts

Function Documentation

◆ bottomup_nblocksfavorable()

static int bottomup_nblocksfavorable ( IndexDeleteCounts blockgroups,
int  nblockgroups,
TM_IndexDelete deltids 
)
static

Definition at line 7720 of file heapam.c.

References Assert, BOTTOMUP_MAX_NBLOCKS, BOTTOMUP_TOLERANCE_NBLOCKS, IndexDeleteCounts::ifirsttid, ItemPointerGetBlockNumber, and TM_IndexDelete::tid.

Referenced by bottomup_sort_and_shrink().

7722 {
7723  int64 lastblock = -1;
7724  int nblocksfavorable = 0;
7725 
7726  Assert(nblockgroups >= 1);
7727  Assert(nblockgroups <= BOTTOMUP_MAX_NBLOCKS);
7728 
7729  /*
7730  * We tolerate heap blocks that will be accessed only slightly out of
7731  * physical order. Small blips occur when a pair of almost-contiguous
7732  * blocks happen to fall into different buckets (perhaps due only to a
7733  * small difference in npromisingtids that the bucketing scheme didn't
7734  * quite manage to ignore). We effectively ignore these blips by applying
7735  * a small tolerance. The precise tolerance we use is a little arbitrary,
7736  * but it works well enough in practice.
7737  */
7738  for (int b = 0; b < nblockgroups; b++)
7739  {
7740  IndexDeleteCounts *group = blockgroups + b;
7741  TM_IndexDelete *firstdtid = deltids + group->ifirsttid;
7742  BlockNumber block = ItemPointerGetBlockNumber(&firstdtid->tid);
7743 
7744  if (lastblock != -1 &&
7745  ((int64) block < lastblock - BOTTOMUP_TOLERANCE_NBLOCKS ||
7746  (int64) block > lastblock + BOTTOMUP_TOLERANCE_NBLOCKS))
7747  break;
7748 
7749  nblocksfavorable++;
7750  lastblock = block;
7751  }
7752 
7753  /* Always indicate that there is at least 1 favorable block */
7754  Assert(nblocksfavorable >= 1);
7755 
7756  return nblocksfavorable;
7757 }
uint32 BlockNumber
Definition: block.h:31
#define BOTTOMUP_TOLERANCE_NBLOCKS
Definition: heapam.c:186
#define BOTTOMUP_MAX_NBLOCKS
Definition: heapam.c:185
ItemPointerData tid
Definition: tableam.h:189
int16 ifirsttid
Definition: heapam.c:196
#define Assert(condition)
Definition: c.h:804
#define ItemPointerGetBlockNumber(pointer)
Definition: itemptr.h:98

◆ bottomup_sort_and_shrink()

static int bottomup_sort_and_shrink ( TM_IndexDeleteOp delstate)
static

Definition at line 7836 of file heapam.c.

References Assert, BlockNumberIsValid, TM_IndexDeleteOp::bottomup, BOTTOMUP_MAX_NBLOCKS, bottomup_nblocksfavorable(), bottomup_sort_and_shrink_cmp(), TM_IndexDeleteOp::deltids, i, TM_IndexDelete::id, IndexDeleteCounts::ifirsttid, InvalidBlockNumber, ItemPointerGetBlockNumber, Min, TM_IndexDeleteOp::ndeltids, IndexDeleteCounts::npromisingtids, IndexDeleteCounts::ntids, palloc(), pfree(), pg_nextpower2_32(), TM_IndexStatus::promising, qsort, TM_IndexDeleteOp::status, and TM_IndexDelete::tid.

Referenced by heap_index_delete_tuples().

7837 {
7838  IndexDeleteCounts *blockgroups;
7839  TM_IndexDelete *reordereddeltids;
7840  BlockNumber curblock = InvalidBlockNumber;
7841  int nblockgroups = 0;
7842  int ncopied = 0;
7843  int nblocksfavorable = 0;
7844 
7845  Assert(delstate->bottomup);
7846  Assert(delstate->ndeltids > 0);
7847 
7848  /* Calculate per-heap-block count of TIDs */
7849  blockgroups = palloc(sizeof(IndexDeleteCounts) * delstate->ndeltids);
7850  for (int i = 0; i < delstate->ndeltids; i++)
7851  {
7852  TM_IndexDelete *ideltid = &delstate->deltids[i];
7853  TM_IndexStatus *istatus = delstate->status + ideltid->id;
7854  ItemPointer htid = &ideltid->tid;
7855  bool promising = istatus->promising;
7856 
7857  if (curblock != ItemPointerGetBlockNumber(htid))
7858  {
7859  /* New block group */
7860  nblockgroups++;
7861 
7862  Assert(curblock < ItemPointerGetBlockNumber(htid) ||
7863  !BlockNumberIsValid(curblock));
7864 
7865  curblock = ItemPointerGetBlockNumber(htid);
7866  blockgroups[nblockgroups - 1].ifirsttid = i;
7867  blockgroups[nblockgroups - 1].ntids = 1;
7868  blockgroups[nblockgroups - 1].npromisingtids = 0;
7869  }
7870  else
7871  {
7872  blockgroups[nblockgroups - 1].ntids++;
7873  }
7874 
7875  if (promising)
7876  blockgroups[nblockgroups - 1].npromisingtids++;
7877  }
7878 
7879  /*
7880  * We're about ready to sort block groups to determine the optimal order
7881  * for visiting heap blocks. But before we do, round the number of
7882  * promising tuples for each block group up to the nearest power-of-two
7883  * (except for block groups where npromisingtids is already 0).
7884  *
7885  * This scheme divides heap blocks/block groups into buckets. Each bucket
7886  * contains blocks that have _approximately_ the same number of promising
7887  * TIDs as each other. The goal is to ignore relatively small differences
7888  * in the total number of promising entries, so that the whole process can
7889  * give a little weight to heapam factors (like heap block locality)
7890  * instead. This isn't a trade-off, really -- we have nothing to lose.
7891  * It would be foolish to interpret small differences in npromisingtids
7892  * values as anything more than noise.
7893  *
7894  * We tiebreak on nhtids when sorting block group subsets that have the
7895  * same npromisingtids, but this has the same issues as npromisingtids,
7896  * and so nhtids is subject to the same power-of-two bucketing scheme.
7897  * The only reason that we don't fix nhtids in the same way here too is
7898  * that we'll need accurate nhtids values after the sort. We handle
7899  * nhtids bucketization dynamically instead (in the sort comparator).
7900  *
7901  * See bottomup_nblocksfavorable() for a full explanation of when and how
7902  * heap locality/favorable blocks can significantly influence when and how
7903  * heap blocks are accessed.
7904  */
7905  for (int b = 0; b < nblockgroups; b++)
7906  {
7907  IndexDeleteCounts *group = blockgroups + b;
7908 
7909  /* Better off falling back on nhtids with low npromisingtids */
7910  if (group->npromisingtids <= 4)
7911  group->npromisingtids = 4;
7912  else
7913  group->npromisingtids =
7915  }
7916 
7917  /* Sort groups and rearrange caller's deltids array */
7918  qsort(blockgroups, nblockgroups, sizeof(IndexDeleteCounts),
7920  reordereddeltids = palloc(delstate->ndeltids * sizeof(TM_IndexDelete));
7921 
7922  nblockgroups = Min(BOTTOMUP_MAX_NBLOCKS, nblockgroups);
7923  /* Determine number of favorable blocks at the start of final deltids */
7924  nblocksfavorable = bottomup_nblocksfavorable(blockgroups, nblockgroups,
7925  delstate->deltids);
7926 
7927  for (int b = 0; b < nblockgroups; b++)
7928  {
7929  IndexDeleteCounts *group = blockgroups + b;
7930  TM_IndexDelete *firstdtid = delstate->deltids + group->ifirsttid;
7931 
7932  memcpy(reordereddeltids + ncopied, firstdtid,
7933  sizeof(TM_IndexDelete) * group->ntids);
7934  ncopied += group->ntids;
7935  }
7936 
7937  /* Copy final grouped and sorted TIDs back into start of caller's array */
7938  memcpy(delstate->deltids, reordereddeltids,
7939  sizeof(TM_IndexDelete) * ncopied);
7940  delstate->ndeltids = ncopied;
7941 
7942  pfree(reordereddeltids);
7943  pfree(blockgroups);
7944 
7945  return nblocksfavorable;
7946 }
TM_IndexDelete * deltids
Definition: tableam.h:228
static int bottomup_sort_and_shrink_cmp(const void *arg1, const void *arg2)
Definition: heapam.c:7763
#define Min(x, y)
Definition: c.h:986
int16 npromisingtids
Definition: heapam.c:194
uint32 BlockNumber
Definition: block.h:31
void pfree(void *pointer)
Definition: mcxt.c:1057
#define BOTTOMUP_MAX_NBLOCKS
Definition: heapam.c:185
static uint32 pg_nextpower2_32(uint32 num)
Definition: pg_bitutils.h:146
unsigned int uint32
Definition: c.h:441
bool promising
Definition: tableam.h:199
TM_IndexStatus * status
Definition: tableam.h:229
ItemPointerData tid
Definition: tableam.h:189
#define BlockNumberIsValid(blockNumber)
Definition: block.h:70
int16 ifirsttid
Definition: heapam.c:196
#define Assert(condition)
Definition: c.h:804
static int bottomup_nblocksfavorable(IndexDeleteCounts *blockgroups, int nblockgroups, TM_IndexDelete *deltids)
Definition: heapam.c:7720
#define InvalidBlockNumber
Definition: block.h:33
void * palloc(Size size)
Definition: mcxt.c:950
int i
#define ItemPointerGetBlockNumber(pointer)
Definition: itemptr.h:98
#define qsort(a, b, c, d)
Definition: port.h:504

◆ bottomup_sort_and_shrink_cmp()

static int bottomup_sort_and_shrink_cmp ( const void *  arg1,
const void *  arg2 
)
static

Definition at line 7763 of file heapam.c.

References IndexDeleteCounts::ifirsttid, IndexDeleteCounts::npromisingtids, IndexDeleteCounts::ntids, pg_nextpower2_32(), and pg_unreachable.

Referenced by bottomup_sort_and_shrink().

7764 {
7765  const IndexDeleteCounts *group1 = (const IndexDeleteCounts *) arg1;
7766  const IndexDeleteCounts *group2 = (const IndexDeleteCounts *) arg2;
7767 
7768  /*
7769  * Most significant field is npromisingtids (which we invert the order of
7770  * so as to sort in desc order).
7771  *
7772  * Caller should have already normalized npromisingtids fields into
7773  * power-of-two values (buckets).
7774  */
7775  if (group1->npromisingtids > group2->npromisingtids)
7776  return -1;
7777  if (group1->npromisingtids < group2->npromisingtids)
7778  return 1;
7779 
7780  /*
7781  * Tiebreak: desc ntids sort order.
7782  *
7783  * We cannot expect power-of-two values for ntids fields. We should
7784  * behave as if they were already rounded up for us instead.
7785  */
7786  if (group1->ntids != group2->ntids)
7787  {
7788  uint32 ntids1 = pg_nextpower2_32((uint32) group1->ntids);
7789  uint32 ntids2 = pg_nextpower2_32((uint32) group2->ntids);
7790 
7791  if (ntids1 > ntids2)
7792  return -1;
7793  if (ntids1 < ntids2)
7794  return 1;
7795  }
7796 
7797  /*
7798  * Tiebreak: asc offset-into-deltids-for-block (offset to first TID for
7799  * block in deltids array) order.
7800  *
7801  * This is equivalent to sorting in ascending heap block number order
7802  * (among otherwise equal subsets of the array). This approach allows us
7803  * to avoid accessing the out-of-line TID. (We rely on the assumption
7804  * that the deltids array was sorted in ascending heap TID order when
7805  * these offsets to the first TID from each heap block group were formed.)
7806  */
7807  if (group1->ifirsttid > group2->ifirsttid)
7808  return 1;
7809  if (group1->ifirsttid < group2->ifirsttid)
7810  return -1;
7811 
7812  pg_unreachable();
7813 
7814  return 0;
7815 }
#define pg_unreachable()
Definition: c.h:258
int16 npromisingtids
Definition: heapam.c:194
static uint32 pg_nextpower2_32(uint32 num)
Definition: pg_bitutils.h:146
unsigned int uint32
Definition: c.h:441
int16 ifirsttid
Definition: heapam.c:196

◆ compute_infobits()

static uint8 compute_infobits ( uint16  infomask,
uint16  infomask2 
)
static

Definition at line 2695 of file heapam.c.

References HEAP_KEYS_UPDATED, HEAP_XMAX_EXCL_LOCK, HEAP_XMAX_IS_MULTI, HEAP_XMAX_KEYSHR_LOCK, HEAP_XMAX_LOCK_ONLY, XLHL_KEYS_UPDATED, XLHL_XMAX_EXCL_LOCK, XLHL_XMAX_IS_MULTI, XLHL_XMAX_KEYSHR_LOCK, and XLHL_XMAX_LOCK_ONLY.

Referenced by heap_abort_speculative(), heap_delete(), heap_lock_tuple(), heap_lock_updated_tuple_rec(), heap_update(), and log_heap_update().

2696 {
2697  return
2698  ((infomask & HEAP_XMAX_IS_MULTI) != 0 ? XLHL_XMAX_IS_MULTI : 0) |
2699  ((infomask & HEAP_XMAX_LOCK_ONLY) != 0 ? XLHL_XMAX_LOCK_ONLY : 0) |
2700  ((infomask & HEAP_XMAX_EXCL_LOCK) != 0 ? XLHL_XMAX_EXCL_LOCK : 0) |
2701  /* note we ignore HEAP_XMAX_SHR_LOCK here */
2702  ((infomask & HEAP_XMAX_KEYSHR_LOCK) != 0 ? XLHL_XMAX_KEYSHR_LOCK : 0) |
2703  ((infomask2 & HEAP_KEYS_UPDATED) != 0 ?
2704  XLHL_KEYS_UPDATED : 0);
2705 }
#define HEAP_XMAX_KEYSHR_LOCK
Definition: htup_details.h:193
#define HEAP_XMAX_LOCK_ONLY
Definition: htup_details.h:196
#define XLHL_XMAX_LOCK_ONLY
Definition: heapam_xlog.h:265
#define XLHL_XMAX_IS_MULTI
Definition: heapam_xlog.h:264
#define HEAP_XMAX_EXCL_LOCK
Definition: htup_details.h:195
#define XLHL_XMAX_EXCL_LOCK
Definition: heapam_xlog.h:266
#define XLHL_KEYS_UPDATED
Definition: heapam_xlog.h:268
#define HEAP_KEYS_UPDATED
Definition: htup_details.h:278
#define HEAP_XMAX_IS_MULTI
Definition: htup_details.h:208
#define XLHL_XMAX_KEYSHR_LOCK
Definition: heapam_xlog.h:267

◆ compute_new_xmax_infomask()

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

Definition at line 5007 of file heapam.c.

References Assert, elog, ERROR, get_mxact_status_for_lock(), GetMultiXactIdHintBits(), HEAP_KEYS_UPDATED, HEAP_LOCKED_UPGRADED, HEAP_XMAX_COMMITTED, HEAP_XMAX_EXCL_LOCK, 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, HEAP_XMAX_KEYSHR_LOCK, HEAP_XMAX_LOCK_ONLY, HEAP_XMAX_SHR_LOCK, InvalidTransactionId, LockTupleExclusive, LockTupleKeyShare, LockTupleNoKeyExclusive, LockTupleShare, MultiXactIdCreate(), MultiXactIdExpand(), MultiXactIdGetUpdateXid(), MultiXactIdIsRunning(), MultiXactStatusForKeyShare, MultiXactStatusForNoKeyUpdate, MultiXactStatusForShare, MultiXactStatusForUpdate, MultiXactStatusNoKeyUpdate, MultiXactStatusUpdate, status(), TransactionIdDidCommit(), TransactionIdIsCurrentTransactionId(), TransactionIdIsInProgress(), TUPLOCK_from_mxstatus, and WARNING.

Referenced by heap_delete(), heap_lock_tuple(), heap_lock_updated_tuple_rec(), and heap_update().

5012 {
5013  TransactionId new_xmax;
5014  uint16 new_infomask,
5015  new_infomask2;
5016 
5018 
5019 l5:
5020  new_infomask = 0;
5021  new_infomask2 = 0;
5022  if (old_infomask & HEAP_XMAX_INVALID)
5023  {
5024  /*
5025  * No previous locker; we just insert our own TransactionId.
5026  *
5027  * Note that it's critical that this case be the first one checked,
5028  * because there are several blocks below that come back to this one
5029  * to implement certain optimizations; old_infomask might contain
5030  * other dirty bits in those cases, but we don't really care.
5031  */
5032  if (is_update)
5033  {
5034  new_xmax = add_to_xmax;
5035  if (mode == LockTupleExclusive)
5036  new_infomask2 |= HEAP_KEYS_UPDATED;
5037  }
5038  else
5039  {
5040  new_infomask |= HEAP_XMAX_LOCK_ONLY;
5041  switch (mode)
5042  {
5043  case LockTupleKeyShare:
5044  new_xmax = add_to_xmax;
5045  new_infomask |= HEAP_XMAX_KEYSHR_LOCK;
5046  break;
5047  case LockTupleShare:
5048  new_xmax = add_to_xmax;
5049  new_infomask |= HEAP_XMAX_SHR_LOCK;
5050  break;
5052  new_xmax = add_to_xmax;
5053  new_infomask |= HEAP_XMAX_EXCL_LOCK;
5054  break;
5055  case LockTupleExclusive:
5056  new_xmax = add_to_xmax;
5057  new_infomask |= HEAP_XMAX_EXCL_LOCK;
5058  new_infomask2 |= HEAP_KEYS_UPDATED;
5059  break;
5060  default:
5061  new_xmax = InvalidTransactionId; /* silence compiler */
5062  elog(ERROR, "invalid lock mode");
5063  }
5064  }
5065  }
5066  else if (old_infomask & HEAP_XMAX_IS_MULTI)
5067  {
5068  MultiXactStatus new_status;
5069 
5070  /*
5071  * Currently we don't allow XMAX_COMMITTED to be set for multis, so
5072  * cross-check.
5073  */
5074  Assert(!(old_infomask & HEAP_XMAX_COMMITTED));
5075 
5076  /*
5077  * A multixact together with LOCK_ONLY set but neither lock bit set
5078  * (i.e. a pg_upgraded share locked tuple) cannot possibly be running
5079  * anymore. This check is critical for databases upgraded by
5080  * pg_upgrade; both MultiXactIdIsRunning and MultiXactIdExpand assume
5081  * that such multis are never passed.
5082  */
5083  if (HEAP_LOCKED_UPGRADED(old_infomask))
5084  {
5085  old_infomask &= ~HEAP_XMAX_IS_MULTI;
5086  old_infomask |= HEAP_XMAX_INVALID;
5087  goto l5;
5088  }
5089 
5090  /*
5091  * If the XMAX is already a MultiXactId, then we need to expand it to
5092  * include add_to_xmax; but if all the members were lockers and are
5093  * all gone, we can do away with the IS_MULTI bit and just set
5094  * add_to_xmax as the only locker/updater. If all lockers are gone
5095  * and we have an updater that aborted, we can also do without a
5096  * multi.
5097  *
5098  * The cost of doing GetMultiXactIdMembers would be paid by
5099  * MultiXactIdExpand if we weren't to do this, so this check is not
5100  * incurring extra work anyhow.
5101  */
5102  if (!MultiXactIdIsRunning(xmax, HEAP_XMAX_IS_LOCKED_ONLY(old_infomask)))
5103  {
5104  if (HEAP_XMAX_IS_LOCKED_ONLY(old_infomask) ||
5106  old_infomask)))
5107  {
5108  /*
5109  * Reset these bits and restart; otherwise fall through to
5110  * create a new multi below.
5111  */
5112  old_infomask &= ~HEAP_XMAX_IS_MULTI;
5113  old_infomask |= HEAP_XMAX_INVALID;
5114  goto l5;
5115  }
5116  }
5117 
5118  new_status = get_mxact_status_for_lock(mode, is_update);
5119 
5120  new_xmax = MultiXactIdExpand((MultiXactId) xmax, add_to_xmax,
5121  new_status);
5122  GetMultiXactIdHintBits(new_xmax, &new_infomask, &new_infomask2);
5123  }
5124  else if (old_infomask & HEAP_XMAX_COMMITTED)
5125  {
5126  /*
5127  * It's a committed update, so we need to preserve him as updater of
5128  * the tuple.
5129  */
5131  MultiXactStatus new_status;
5132 
5133  if (old_infomask2 & HEAP_KEYS_UPDATED)
5134  status = MultiXactStatusUpdate;
5135  else
5136  status = MultiXactStatusNoKeyUpdate;
5137 
5138  new_status = get_mxact_status_for_lock(mode, is_update);
5139 
5140  /*
5141  * since it's not running, it's obviously impossible for the old
5142  * updater to be identical to the current one, so we need not check
5143  * for that case as we do in the block above.
5144  */
5145  new_xmax = MultiXactIdCreate(xmax, status, add_to_xmax, new_status);
5146  GetMultiXactIdHintBits(new_xmax, &new_infomask, &new_infomask2);
5147  }
5148  else if (TransactionIdIsInProgress(xmax))
5149  {
5150  /*
5151  * If the XMAX is a valid, in-progress TransactionId, then we need to
5152  * create a new MultiXactId that includes both the old locker or
5153  * updater and our own TransactionId.
5154  */
5155  MultiXactStatus new_status;
5156  MultiXactStatus old_status;
5157  LockTupleMode old_mode;
5158 
5159  if (HEAP_XMAX_IS_LOCKED_ONLY(old_infomask))
5160  {
5161  if (HEAP_XMAX_IS_KEYSHR_LOCKED(old_infomask))
5162  old_status = MultiXactStatusForKeyShare;
5163  else if (HEAP_XMAX_IS_SHR_LOCKED(old_infomask))
5164  old_status = MultiXactStatusForShare;
5165  else if (HEAP_XMAX_IS_EXCL_LOCKED(old_infomask))
5166  {
5167  if (old_infomask2 & HEAP_KEYS_UPDATED)
5168  old_status = MultiXactStatusForUpdate;
5169  else
5170  old_status = MultiXactStatusForNoKeyUpdate;
5171  }
5172  else
5173  {
5174  /*
5175  * LOCK_ONLY can be present alone only when a page has been
5176  * upgraded by pg_upgrade. But in that case,
5177  * TransactionIdIsInProgress() should have returned false. We
5178  * assume it's no longer locked in this case.
5179  */
5180  elog(WARNING, "LOCK_ONLY found for Xid in progress %u", xmax);
5181  old_infomask |= HEAP_XMAX_INVALID;
5182  old_infomask &= ~HEAP_XMAX_LOCK_ONLY;
5183  goto l5;
5184  }
5185  }
5186  else
5187  {
5188  /* it's an update, but which kind? */
5189  if (old_infomask2 & HEAP_KEYS_UPDATED)
5190  old_status = MultiXactStatusUpdate;
5191  else
5192  old_status = MultiXactStatusNoKeyUpdate;
5193  }
5194 
5195  old_mode = TUPLOCK_from_mxstatus(old_status);
5196 
5197  /*
5198  * If the lock to be acquired is for the same TransactionId as the
5199  * existing lock, there's an optimization possible: consider only the
5200  * strongest of both locks as the only one present, and restart.
5201  */
5202  if (xmax == add_to_xmax)
5203  {
5204  /*
5205  * Note that it's not possible for the original tuple to be
5206  * updated: we wouldn't be here because the tuple would have been
5207  * invisible and we wouldn't try to update it. As a subtlety,
5208  * this code can also run when traversing an update chain to lock
5209  * future versions of a tuple. But we wouldn't be here either,
5210  * because the add_to_xmax would be different from the original
5211  * updater.
5212  */
5213  Assert(HEAP_XMAX_IS_LOCKED_ONLY(old_infomask));
5214 
5215  /* acquire the strongest of both */
5216  if (mode < old_mode)
5217  mode = old_mode;
5218  /* mustn't touch is_update */
5219 
5220  old_infomask |= HEAP_XMAX_INVALID;
5221  goto l5;
5222  }
5223 
5224  /* otherwise, just fall back to creating a new multixact */
5225  new_status = get_mxact_status_for_lock(mode, is_update);
5226  new_xmax = MultiXactIdCreate(xmax, old_status,
5227  add_to_xmax, new_status);
5228  GetMultiXactIdHintBits(new_xmax, &new_infomask, &new_infomask2);
5229  }
5230  else if (!HEAP_XMAX_IS_LOCKED_ONLY(old_infomask) &&
5231  TransactionIdDidCommit(xmax))
5232  {
5233  /*
5234  * It's a committed update, so we gotta preserve him as updater of the
5235  * tuple.
5236  */
5238  MultiXactStatus new_status;
5239 
5240  if (old_infomask2 & HEAP_KEYS_UPDATED)
5241  status = MultiXactStatusUpdate;
5242  else
5243  status = MultiXactStatusNoKeyUpdate;
5244 
5245  new_status = get_mxact_status_for_lock(mode, is_update);
5246 
5247  /*
5248  * since it's not running, it's obviously impossible for the old
5249  * updater to be identical to the current one, so we need not check
5250  * for that case as we do in the block above.
5251  */
5252  new_xmax = MultiXactIdCreate(xmax, status, add_to_xmax, new_status);
5253  GetMultiXactIdHintBits(new_xmax, &new_infomask, &new_infomask2);
5254  }
5255  else
5256  {
5257  /*
5258  * Can get here iff the locking/updating transaction was running when
5259  * the infomask was extracted from the tuple, but finished before
5260  * TransactionIdIsInProgress got to run. Deal with it as if there was
5261  * no locker at all in the first place.
5262  */
5263  old_infomask |= HEAP_XMAX_INVALID;
5264  goto l5;
5265  }
5266 
5267  *result_infomask = new_infomask;
5268  *result_infomask2 = new_infomask2;
5269  *result_xmax = new_xmax;
5270 }
static void GetMultiXactIdHintBits(MultiXactId multi, uint16 *new_infomask, uint16 *new_infomask2)
Definition: heapam.c:6705
static PgChecksumMode mode
Definition: pg_checksums.c:61
MultiXactStatus
Definition: multixact.h:41
#define HEAP_XMAX_KEYSHR_LOCK
Definition: htup_details.h:193
LockTupleMode
Definition: lockoptions.h:49
#define HEAP_XMAX_LOCK_ONLY
Definition: htup_details.h:196
uint32 TransactionId
Definition: c.h:587
bool TransactionIdIsCurrentTransactionId(TransactionId xid)
Definition: xact.c:869
bool TransactionIdIsInProgress(TransactionId xid)
Definition: procarray.c:1320
#define HEAP_LOCKED_UPGRADED(infomask)
Definition: htup_details.h:252
#define HEAP_XMAX_COMMITTED
Definition: htup_details.h:206
bool TransactionIdDidCommit(TransactionId transactionId)
Definition: transam.c:125
#define HEAP_XMAX_SHR_LOCK
Definition: htup_details.h:199
#define HEAP_XMAX_IS_SHR_LOCKED(infomask)
Definition: htup_details.h:262
static TransactionId MultiXactIdGetUpdateXid(TransactionId xmax, uint16 t_infomask)
Definition: heapam.c:6786
unsigned short uint16
Definition: c.h:440
#define ERROR
Definition: elog.h:45
#define HEAP_XMAX_INVALID
Definition: htup_details.h:207
#define HEAP_XMAX_EXCL_LOCK
Definition: htup_details.h:195
#define InvalidTransactionId
Definition: transam.h:31
#define WARNING
Definition: elog.h:40
MultiXactId MultiXactIdCreate(TransactionId xid1, MultiXactStatus status1, TransactionId xid2, MultiXactStatus status2)
Definition: multixact.c:386
#define HEAP_XMAX_IS_LOCKED_ONLY(infomask)
Definition: htup_details.h:230
#define HEAP_KEYS_UPDATED
Definition: htup_details.h:278
#define HEAP_XMAX_IS_MULTI
Definition: htup_details.h:208
TransactionId MultiXactId
Definition: c.h:597
#define Assert(condition)
Definition: c.h:804
#define TUPLOCK_from_mxstatus(status)
Definition: heapam.c:214
#define elog(elevel,...)
Definition: elog.h:227
static MultiXactStatus get_mxact_status_for_lock(LockTupleMode mode, bool is_update)
Definition: heapam.c:4221
#define HEAP_XMAX_IS_EXCL_LOCKED(infomask)
Definition: htup_details.h:264
#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
bool MultiXactIdIsRunning(MultiXactId multi, bool isLockOnly)
Definition: multixact.c:551
MultiXactId MultiXactIdExpand(MultiXactId multi, TransactionId xid, MultiXactStatus status)
Definition: multixact.c:439

◆ ConditionalMultiXactIdWait()

static bool ConditionalMultiXactIdWait ( MultiXactId  multi,
MultiXactStatus  status,
uint16  infomask,
Relation  rel,
int *  remaining 
)
static

Definition at line 7053 of file heapam.c.

References Do_MultiXactIdWait(), and XLTW_None.

Referenced by heap_lock_tuple().

7055 {
7056  return Do_MultiXactIdWait(multi, status, infomask, true,
7057  rel, NULL, XLTW_None, remaining);
7058 }
int remaining
Definition: informix.c:667
Definition: lmgr.h:26
static bool Do_MultiXactIdWait(MultiXactId multi, MultiXactStatus status, uint16 infomask, bool nowait, Relation rel, ItemPointer ctid, XLTW_Oper oper, int *remaining)
Definition: heapam.c:6953
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:227

◆ Do_MultiXactIdWait()

static bool Do_MultiXactIdWait ( MultiXactId  multi,
MultiXactStatus  status,
uint16  infomask,
bool  nowait,
Relation  rel,
ItemPointer  ctid,
XLTW_Oper  oper,
int *  remaining 
)
static

Definition at line 6953 of file heapam.c.

References ConditionalXactLockTableWait(), DoLockModesConflict(), GetMultiXactIdMembers(), HEAP_LOCKED_UPGRADED, HEAP_XMAX_IS_LOCKED_ONLY, i, LOCKMODE_from_mxstatus, pfree(), MultiXactMember::status, TransactionIdIsCurrentTransactionId(), TransactionIdIsInProgress(), XactLockTableWait(), and MultiXactMember::xid.

Referenced by ConditionalMultiXactIdWait(), and MultiXactIdWait().

6957 {
6958  bool result = true;
6959  MultiXactMember *members;
6960  int nmembers;
6961  int remain = 0;
6962 
6963  /* for pre-pg_upgrade tuples, no need to sleep at all */
6964  nmembers = HEAP_LOCKED_UPGRADED(infomask) ? -1 :
6965  GetMultiXactIdMembers(multi, &members, false,
6966  HEAP_XMAX_IS_LOCKED_ONLY(infomask));
6967 
6968  if (nmembers >= 0)
6969  {
6970  int i;
6971 
6972  for (i = 0; i < nmembers; i++)
6973  {
6974  TransactionId memxid = members[i].xid;
6975  MultiXactStatus memstatus = members[i].status;
6976 
6978  {
6979  remain++;
6980  continue;
6981  }
6982 
6985  {
6986  if (remaining && TransactionIdIsInProgress(memxid))
6987  remain++;
6988  continue;
6989  }
6990 
6991  /*
6992  * This member conflicts with our multi, so we have to sleep (or
6993  * return failure, if asked to avoid waiting.)
6994  *
6995  * Note that we don't set up an error context callback ourselves,
6996  * but instead we pass the info down to XactLockTableWait. This
6997  * might seem a bit wasteful because the context is set up and
6998  * tore down for each member of the multixact, but in reality it
6999  * should be barely noticeable, and it avoids duplicate code.
7000  */
7001  if (nowait)
7002  {
7003  result = ConditionalXactLockTableWait(memxid);
7004  if (!result)
7005  break;
7006  }
7007  else
7008  XactLockTableWait(memxid, rel, ctid, oper);
7009  }
7010 
7011  pfree(members);
7012  }
7013 
7014  if (remaining)
7015  *remaining = remain;
7016 
7017  return result;
7018 }
int remaining
Definition: informix.c:667
MultiXactStatus
Definition: multixact.h:41
uint32 TransactionId
Definition: c.h:587
bool TransactionIdIsCurrentTransactionId(TransactionId xid)
Definition: xact.c:869
bool TransactionIdIsInProgress(TransactionId xid)
Definition: procarray.c:1320
#define HEAP_LOCKED_UPGRADED(infomask)
Definition: htup_details.h:252
#define LOCKMODE_from_mxstatus(status)
Definition: heapam.c:155
bool ConditionalXactLockTableWait(TransactionId xid)
Definition: lmgr.c:712
void pfree(void *pointer)
Definition: mcxt.c:1057
TransactionId xid
Definition: multixact.h:62
bool DoLockModesConflict(LOCKMODE mode1, LOCKMODE mode2)
Definition: lock.c:582
MultiXactStatus status
Definition: multixact.h:63
#define HEAP_XMAX_IS_LOCKED_ONLY(infomask)
Definition: htup_details.h:230
void XactLockTableWait(TransactionId xid, Relation rel, ItemPointer ctid, XLTW_Oper oper)
Definition: lmgr.c:639
int i
int GetMultiXactIdMembers(MultiXactId multi, MultiXactMember **members, bool from_pgupgrade, bool onlyLock)
Definition: multixact.c:1223
Operator oper(ParseState *pstate, List *opname, Oid ltypeId, Oid rtypeId, bool noError, int location)
Definition: parse_oper.c:382
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:227

◆ DoesMultiXactIdConflict()

static bool DoesMultiXactIdConflict ( MultiXactId  multi,
uint16  infomask,
LockTupleMode  lockmode,
bool current_is_member 
)
static

Definition at line 6854 of file heapam.c.

References DoLockModesConflict(), GetMultiXactIdMembers(), HEAP_LOCKED_UPGRADED, HEAP_XMAX_IS_LOCKED_ONLY, i, ISUPDATE_from_mxstatus, LOCKMODE_from_mxstatus, pfree(), status(), TransactionIdDidAbort(), TransactionIdIsCurrentTransactionId(), TransactionIdIsInProgress(), tupleLockExtraInfo, and MultiXactMember::xid.

Referenced by heap_delete(), heap_lock_tuple(), and heap_update().

6856 {
6857  int nmembers;
6858  MultiXactMember *members;
6859  bool result = false;
6860  LOCKMODE wanted = tupleLockExtraInfo[lockmode].hwlock;
6861 
6862  if (HEAP_LOCKED_UPGRADED(infomask))
6863  return false;
6864 
6865  nmembers = GetMultiXactIdMembers(multi, &members, false,
6866  HEAP_XMAX_IS_LOCKED_ONLY(infomask));
6867  if (nmembers >= 0)
6868  {
6869  int i;
6870 
6871  for (i = 0; i < nmembers; i++)
6872  {
6873  TransactionId memxid;
6874  LOCKMODE memlockmode;
6875 
6876  if (result && (current_is_member == NULL || *current_is_member))
6877  break;
6878 
6879  memlockmode = LOCKMODE_from_mxstatus(members[i].status);
6880 
6881  /* ignore members from current xact (but track their presence) */
6882  memxid = members[i].xid;
6884  {
6885  if (current_is_member != NULL)
6886  *current_is_member = true;
6887  continue;
6888  }
6889  else if (result)
6890  continue;
6891 
6892  /* ignore members that don't conflict with the lock we want */
6893  if (!DoLockModesConflict(memlockmode, wanted))
6894  continue;
6895 
6896  if (ISUPDATE_from_mxstatus(members[i].status))
6897  {
6898  /* ignore aborted updaters */
6899  if (TransactionIdDidAbort(memxid))
6900  continue;
6901  }
6902  else
6903  {
6904  /* ignore lockers-only that are no longer in progress */
6905  if (!TransactionIdIsInProgress(memxid))
6906  continue;
6907  }
6908 
6909  /*
6910  * Whatever remains are either live lockers that conflict with our
6911  * wanted lock, and updaters that are not aborted. Those conflict
6912  * with what we want. Set up to return true, but keep going to
6913  * look for the current transaction among the multixact members,
6914  * if needed.
6915  */
6916  result = true;
6917  }
6918  pfree(members);
6919  }
6920 
6921  return result;
6922 }
uint32 TransactionId
Definition: c.h:587
int LOCKMODE
Definition: lockdefs.h:26
bool TransactionIdIsCurrentTransactionId(TransactionId xid)
Definition: xact.c:869
bool TransactionIdIsInProgress(TransactionId xid)
Definition: procarray.c:1320
#define HEAP_LOCKED_UPGRADED(infomask)
Definition: htup_details.h:252
#define LOCKMODE_from_mxstatus(status)
Definition: heapam.c:155
void pfree(void *pointer)
Definition: mcxt.c:1057
TransactionId xid
Definition: multixact.h:62
bool DoLockModesConflict(LOCKMODE mode1, LOCKMODE mode2)
Definition: lock.c:582
#define ISUPDATE_from_mxstatus(status)
Definition: multixact.h:56
static const struct @13 tupleLockExtraInfo[MaxLockTupleMode+1]
bool TransactionIdDidAbort(TransactionId transactionId)
Definition: transam.c:181
#define HEAP_XMAX_IS_LOCKED_ONLY(infomask)
Definition: htup_details.h:230
int i
int GetMultiXactIdMembers(MultiXactId multi, MultiXactMember **members, bool from_pgupgrade, bool onlyLock)
Definition: multixact.c:1223
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:227

◆ ExtractReplicaIdentity()

static HeapTuple ExtractReplicaIdentity ( Relation  rel,
HeapTuple  tup,
bool  key_changed,
bool copy 
)
static

Definition at line 8412 of file heapam.c.

References Assert, bms_free(), bms_is_empty(), bms_is_member(), FirstLowInvalidHeapAttributeNumber, heap_deform_tuple(), heap_form_tuple(), heap_freetuple(), HeapTupleHasExternal, i, INDEX_ATTR_BITMAP_IDENTITY_KEY, MaxHeapAttributeNumber, TupleDescData::natts, RelationData::rd_rel, RelationGetDescr, RelationGetIndexAttrBitmap(), RelationIsLogicallyLogged, toast_flatten_tuple(), and values.

Referenced by heap_delete(), and heap_update().

8414 {
8415  TupleDesc desc = RelationGetDescr(relation);
8416  char replident = relation->rd_rel->relreplident;
8417  Bitmapset *idattrs;
8418  HeapTuple key_tuple;
8419  bool nulls[MaxHeapAttributeNumber];
8421 
8422  *copy = false;
8423 
8424  if (!RelationIsLogicallyLogged(relation))
8425  return NULL;
8426 
8427  if (replident == REPLICA_IDENTITY_NOTHING)
8428  return NULL;
8429 
8430  if (replident == REPLICA_IDENTITY_FULL)
8431  {
8432  /*
8433  * When logging the entire old tuple, it very well could contain
8434  * toasted columns. If so, force them to be inlined.
8435  */
8436  if (HeapTupleHasExternal(tp))
8437  {
8438  *copy = true;
8439  tp = toast_flatten_tuple(tp, desc);
8440  }
8441  return tp;
8442  }
8443 
8444  /* if the key hasn't changed and we're only logging the key, we're done */
8445  if (!key_changed)
8446  return NULL;
8447 
8448  /* find out the replica identity columns */
8449  idattrs = RelationGetIndexAttrBitmap(relation,
8451 
8452  /*
8453  * If there's no defined replica identity columns, treat as !key_changed.
8454  * (This case should not be reachable from heap_update, since that should
8455  * calculate key_changed accurately. But heap_delete just passes constant
8456  * true for key_changed, so we can hit this case in deletes.)
8457  */
8458  if (bms_is_empty(idattrs))
8459  return NULL;
8460 
8461  /*
8462  * Construct a new tuple containing only the replica identity columns,
8463  * with nulls elsewhere. While we're at it, assert that the replica
8464  * identity columns aren't null.
8465  */
8466  heap_deform_tuple(tp, desc, values, nulls);
8467 
8468  for (int i = 0; i < desc->natts; i++)
8469  {
8471  idattrs))
8472  Assert(!nulls[i]);
8473  else
8474  nulls[i] = true;
8475  }
8476 
8477  key_tuple = heap_form_tuple(desc, values, nulls);
8478  *copy = true;
8479 
8480  bms_free(idattrs);
8481 
8482  /*
8483  * If the tuple, which by here only contains indexed columns, still has
8484  * toasted columns, force them to be inlined. This is somewhat unlikely
8485  * since there's limits on the size of indexed columns, so we don't
8486  * duplicate toast_flatten_tuple()s functionality in the above loop over
8487  * the indexed columns, even if it would be more efficient.
8488  */
8489  if (HeapTupleHasExternal(key_tuple))
8490  {
8491  HeapTuple oldtup = key_tuple;
8492 
8493  key_tuple = toast_flatten_tuple(oldtup, desc);
8494  heap_freetuple(oldtup);
8495  }
8496 
8497  return key_tuple;
8498 }
#define RelationGetDescr(relation)
Definition: rel.h:483
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:27
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:1020
#define RelationIsLogicallyLogged(relation)
Definition: rel.h:636
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
HeapTuple toast_flatten_tuple(HeapTuple tup, TupleDesc tupleDesc)
Definition: heaptoast.c:350
bool bms_is_empty(const Bitmapset *a)
Definition: bitmapset.c:701
uintptr_t Datum
Definition: postgres.h:367
#define MaxHeapAttributeNumber
Definition: htup_details.h:47
void bms_free(Bitmapset *a)
Definition: bitmapset.c:208
#define Assert(condition)
Definition: c.h:804
void heap_deform_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *values, bool *isnull)
Definition: heaptuple.c:1249
static Datum values[MAXATTR]
Definition: bootstrap.c:165
#define HeapTupleHasExternal(tuple)
Definition: htup_details.h:673
int i
Bitmapset * RelationGetIndexAttrBitmap(Relation relation, IndexAttrBitmapKind attrKind)
Definition: relcache.c:4956
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:427

◆ fix_infomask_from_infobits()

static void fix_infomask_from_infobits ( uint8  infobits,
uint16 infomask,
uint16 infomask2 
)
static

Definition at line 8816 of file heapam.c.

References HEAP_KEYS_UPDATED, HEAP_XMAX_EXCL_LOCK, HEAP_XMAX_IS_MULTI, HEAP_XMAX_KEYSHR_LOCK, HEAP_XMAX_LOCK_ONLY, XLHL_KEYS_UPDATED, XLHL_XMAX_EXCL_LOCK, XLHL_XMAX_IS_MULTI, XLHL_XMAX_KEYSHR_LOCK, and XLHL_XMAX_LOCK_ONLY.

Referenced by heap_xlog_delete(), heap_xlog_lock(), heap_xlog_lock_updated(), and heap_xlog_update().

8817 {
8818  *infomask &= ~(HEAP_XMAX_IS_MULTI | HEAP_XMAX_LOCK_ONLY |
8820  *infomask2 &= ~HEAP_KEYS_UPDATED;
8821 
8822  if (infobits & XLHL_XMAX_IS_MULTI)
8823  *infomask |= HEAP_XMAX_IS_MULTI;
8824  if (infobits & XLHL_XMAX_LOCK_ONLY)
8825  *infomask |= HEAP_XMAX_LOCK_ONLY;
8826  if (infobits & XLHL_XMAX_EXCL_LOCK)
8827  *infomask |= HEAP_XMAX_EXCL_LOCK;
8828  /* note HEAP_XMAX_SHR_LOCK isn't considered here */
8829  if (infobits & XLHL_XMAX_KEYSHR_LOCK)
8830  *infomask |= HEAP_XMAX_KEYSHR_LOCK;
8831 
8832  if (infobits & XLHL_KEYS_UPDATED)
8833  *infomask2 |= HEAP_KEYS_UPDATED;
8834 }
#define HEAP_XMAX_KEYSHR_LOCK
Definition: htup_details.h:193
#define HEAP_XMAX_LOCK_ONLY
Definition: htup_details.h:196
#define XLHL_XMAX_LOCK_ONLY
Definition: heapam_xlog.h:265
#define XLHL_XMAX_IS_MULTI
Definition: heapam_xlog.h:264
#define HEAP_XMAX_EXCL_LOCK
Definition: htup_details.h:195
#define XLHL_XMAX_EXCL_LOCK
Definition: heapam_xlog.h:266
#define XLHL_KEYS_UPDATED
Definition: heapam_xlog.h:268
#define HEAP_KEYS_UPDATED
Definition: htup_details.h:278
#define HEAP_XMAX_IS_MULTI
Definition: htup_details.h:208
#define XLHL_XMAX_KEYSHR_LOCK
Definition: heapam_xlog.h:267

◆ FreeBulkInsertState()

void FreeBulkInsertState ( BulkInsertState  bistate)

Definition at line 1997 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().

1998 {
1999  if (bistate->current_buf != InvalidBuffer)
2000  ReleaseBuffer(bistate->current_buf);
2001  FreeAccessStrategy(bistate->strategy);
2002  pfree(bistate);
2003 }
#define InvalidBuffer
Definition: buf.h:25
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3700
void pfree(void *pointer)
Definition: mcxt.c:1057
void FreeAccessStrategy(BufferAccessStrategy strategy)
Definition: freelist.c:597
BufferAccessStrategy strategy
Definition: hio.h:31
Buffer current_buf
Definition: hio.h:32

◆ FreezeMultiXactId()

static TransactionId FreezeMultiXactId ( MultiXactId  multi,
uint16  t_infomask,
TransactionId  relfrozenxid,
TransactionId  relminmxid,
TransactionId  cutoff_xid,
MultiXactId  cutoff_multi,
uint16 flags 
)
static

Definition at line 6124 of file heapam.c.

References Assert, ereport, errcode(), ERRCODE_DATA_CORRUPTED, errmsg_internal(), ERROR, FRM_INVALIDATE_XMAX, FRM_MARK_COMMITTED, FRM_NOOP, FRM_RETURN_IS_MULTI, FRM_RETURN_IS_XID, GetMultiXactIdMembers(), HEAP_LOCKED_UPGRADED, HEAP_XMAX_IS_LOCKED_ONLY, HEAP_XMAX_IS_MULTI, i, InvalidTransactionId, ISUPDATE_from_mxstatus, MultiXactIdCreateFromMembers(), MultiXactIdGetUpdateXid(), MultiXactIdIsRunning(), MultiXactIdIsValid, MultiXactIdPrecedes(), palloc(), pfree(), status(), TransactionIdDidCommit(), TransactionIdIsCurrentTransactionId(), TransactionIdIsInProgress(), TransactionIdIsValid, TransactionIdPrecedes(), and MultiXactMember::xid.

Referenced by heap_prepare_freeze_tuple().

6128 {
6130  int i;
6131  MultiXactMember *members;
6132  int nmembers;
6133  bool need_replace;
6134  int nnewmembers;
6135  MultiXactMember *newmembers;
6136  bool has_lockers;
6137  TransactionId update_xid;
6138  bool update_committed;
6139 
6140  *flags = 0;
6141 
6142  /* We should only be called in Multis */
6143  Assert(t_infomask & HEAP_XMAX_IS_MULTI);
6144 
6145  if (!MultiXactIdIsValid(multi) ||
6146  HEAP_LOCKED_UPGRADED(t_infomask))
6147  {
6148  /* Ensure infomask bits are appropriately set/reset */
6149  *flags |= FRM_INVALIDATE_XMAX;
6150  return InvalidTransactionId;
6151  }
6152  else if (MultiXactIdPrecedes(multi, relminmxid))
6153  ereport(ERROR,
6155  errmsg_internal("found multixact %u from before relminmxid %u",
6156  multi, relminmxid)));
6157  else if (MultiXactIdPrecedes(multi, cutoff_multi))
6158  {
6159  /*
6160  * This old multi cannot possibly have members still running, but
6161  * verify just in case. If it was a locker only, it can be removed
6162  * without any further consideration; but if it contained an update,
6163  * we might need to preserve it.
6164  */
6165  if (MultiXactIdIsRunning(multi,
6166  HEAP_XMAX_IS_LOCKED_ONLY(t_infomask)))
6167  ereport(ERROR,
6169  errmsg_internal("multixact %u from before cutoff %u found to be still running",
6170  multi, cutoff_multi)));
6171 
6172  if (HEAP_XMAX_IS_LOCKED_ONLY(t_infomask))
6173  {
6174  *flags |= FRM_INVALIDATE_XMAX;
6175  xid = InvalidTransactionId; /* not strictly necessary */
6176  }
6177  else
6178  {
6179  /* replace multi by update xid */
6180  xid = MultiXactIdGetUpdateXid(multi, t_infomask);
6181 
6182  /* wasn't only a lock, xid needs to be valid */
6184 
6185  if (TransactionIdPrecedes(xid, relfrozenxid))
6186  ereport(ERROR,
6188  errmsg_internal("found update xid %u from before relfrozenxid %u",
6189  xid, relfrozenxid)));
6190 
6191  /*
6192  * If the xid is older than the cutoff, it has to have aborted,
6193  * otherwise the tuple would have gotten pruned away.
6194  */
6195  if (TransactionIdPrecedes(xid, cutoff_xid))
6196  {
6197  if (TransactionIdDidCommit(xid))
6198  ereport(ERROR,
6200  errmsg_internal("cannot freeze committed update xid %u", xid)));
6201  *flags |= FRM_INVALIDATE_XMAX;
6202  xid = InvalidTransactionId; /* not strictly necessary */
6203  }
6204  else
6205  {
6206  *flags |= FRM_RETURN_IS_XID;
6207  }
6208  }
6209 
6210  return xid;
6211  }
6212 
6213  /*
6214  * This multixact might have or might not have members still running, but
6215  * we know it's valid and is newer than the cutoff point for multis.
6216  * However, some member(s) of it may be below the cutoff for Xids, so we
6217  * need to walk the whole members array to figure out what to do, if
6218  * anything.
6219  */
6220 
6221  nmembers =
6222  GetMultiXactIdMembers(multi, &members, false,
6223  HEAP_XMAX_IS_LOCKED_ONLY(t_infomask));
6224  if (nmembers <= 0)
6225  {
6226  /* Nothing worth keeping */
6227  *flags |= FRM_INVALIDATE_XMAX;
6228  return InvalidTransactionId;
6229  }
6230 
6231  /* is there anything older than the cutoff? */
6232  need_replace = false;
6233  for (i = 0; i < nmembers; i++)
6234  {
6235  if (TransactionIdPrecedes(members[i].xid, cutoff_xid))
6236  {
6237  need_replace = true;
6238  break;
6239  }
6240  }
6241 
6242  /*
6243  * In the simplest case, there is no member older than the cutoff; we can
6244  * keep the existing MultiXactId as is.
6245  */
6246  if (!need_replace)
6247  {
6248  *flags |= FRM_NOOP;
6249  pfree(members);
6250  return InvalidTransactionId;
6251  }
6252 
6253  /*
6254  * If the multi needs to be updated, figure out which members do we need
6255  * to keep.
6256  */
6257  nnewmembers = 0;
6258  newmembers = palloc(sizeof(MultiXactMember) * nmembers);
6259  has_lockers = false;
6260  update_xid = InvalidTransactionId;
6261  update_committed = false;
6262 
6263  for (i = 0; i < nmembers; i++)
6264  {
6265  /*
6266  * Determine whether to keep this member or ignore it.
6267  */
6268  if (ISUPDATE_from_mxstatus(members[i].status))
6269  {
6270  TransactionId xid = members[i].xid;
6271 
6273  if (TransactionIdPrecedes(xid, relfrozenxid))
6274  ereport(ERROR,
6276  errmsg_internal("found update xid %u from before relfrozenxid %u",
6277  xid, relfrozenxid)));
6278 
6279  /*
6280  * It's an update; should we keep it? If the transaction is known
6281  * aborted or crashed then it's okay to ignore it, otherwise not.
6282  * Note that an updater older than cutoff_xid cannot possibly be
6283  * committed, because HeapTupleSatisfiesVacuum would have returned
6284  * HEAPTUPLE_DEAD and we would not be trying to freeze the tuple.
6285  *
6286  * As with all tuple visibility routines, it's critical to test
6287  * TransactionIdIsInProgress before TransactionIdDidCommit,
6288  * because of race conditions explained in detail in
6289  * heapam_visibility.c.
6290  */
6293  {
6294  Assert(!TransactionIdIsValid(update_xid));
6295  update_xid = xid;
6296  }
6297  else if (TransactionIdDidCommit(xid))
6298  {
6299  /*
6300  * The transaction committed, so we can tell caller to set
6301  * HEAP_XMAX_COMMITTED. (We can only do this because we know
6302  * the transaction is not running.)
6303  */
6304  Assert(!TransactionIdIsValid(update_xid));
6305  update_committed = true;
6306  update_xid = xid;
6307  }
6308  else
6309  {
6310  /*
6311  * Not in progress, not committed -- must be aborted or
6312  * crashed; we can ignore it.
6313  */
6314  }
6315 
6316  /*
6317  * Since the tuple wasn't marked HEAPTUPLE_DEAD by vacuum, the
6318  * update Xid cannot possibly be older than the xid cutoff. The
6319  * presence of such a tuple would cause corruption, so be paranoid
6320  * and check.
6321  */
6322  if (TransactionIdIsValid(update_xid) &&
6323  TransactionIdPrecedes(update_xid, cutoff_xid))
6324  ereport(ERROR,
6326  errmsg_internal("found update xid %u from before xid cutoff %u",
6327  update_xid, cutoff_xid)));
6328 
6329  /*
6330  * If we determined that it's an Xid corresponding to an update
6331  * that must be retained, additionally add it to the list of
6332  * members of the new Multi, in case we end up using that. (We
6333  * might still decide to use only an update Xid and not a multi,
6334  * but it's easier to maintain the list as we walk the old members
6335  * list.)
6336  */
6337  if (TransactionIdIsValid(update_xid))
6338  newmembers[nnewmembers++] = members[i];
6339  }
6340  else
6341  {
6342  /* We only keep lockers if they are still running */
6343  if (TransactionIdIsCurrentTransactionId(members[i].xid) ||
6344  TransactionIdIsInProgress(members[i].xid))
6345  {
6346  /* running locker cannot possibly be older than the cutoff */
6347  Assert(!TransactionIdPrecedes(members[i].xid, cutoff_xid));
6348  newmembers[nnewmembers++] = members[i];
6349  has_lockers = true;
6350  }
6351  }
6352  }
6353 
6354  pfree(members);
6355 
6356  if (nnewmembers == 0)
6357  {
6358  /* nothing worth keeping!? Tell caller to remove the whole thing */
6359  *flags |= FRM_INVALIDATE_XMAX;
6360  xid = InvalidTransactionId;
6361  }
6362  else if (TransactionIdIsValid(update_xid) && !has_lockers)
6363  {
6364  /*
6365  * If there's a single member and it's an update, pass it back alone
6366  * without creating a new Multi. (XXX we could do this when there's a
6367  * single remaining locker, too, but that would complicate the API too
6368  * much; moreover, the case with the single updater is more
6369  * interesting, because those are longer-lived.)
6370  */
6371  Assert(nnewmembers == 1);
6372  *flags |= FRM_RETURN_IS_XID;
6373  if (update_committed)
6374  *flags |= FRM_MARK_COMMITTED;
6375  xid = update_xid;
6376  }
6377  else
6378  {
6379  /*
6380  * Create a new multixact with the surviving members of the previous
6381  * one, to set as new Xmax in the tuple.
6382  */
6383  xid = MultiXactIdCreateFromMembers(nnewmembers, newmembers);
6384  *flags |= FRM_RETURN_IS_MULTI;
6385  }
6386 
6387  pfree(newmembers);
6388 
6389  return xid;
6390 }
#define FRM_RETURN_IS_XID
Definition: heapam.c:6098
#define FRM_MARK_COMMITTED
Definition: heapam.c:6100
uint32 TransactionId
Definition: c.h:587
bool TransactionIdIsCurrentTransactionId(TransactionId xid)
Definition: xact.c:869
bool TransactionIdIsInProgress(TransactionId xid)
Definition: procarray.c:1320
MultiXactId MultiXactIdCreateFromMembers(int nmembers, MultiXactMember *members)
Definition: multixact.c:767
#define HEAP_LOCKED_UPGRADED(infomask)
Definition: htup_details.h:252
int errcode(int sqlerrcode)
Definition: elog.c:694
bool TransactionIdDidCommit(TransactionId transactionId)
Definition: transam.c:125
static TransactionId MultiXactIdGetUpdateXid(TransactionId xmax, uint16 t_infomask)
Definition: heapam.c:6786
void pfree(void *pointer)
Definition: mcxt.c:1057
#define ERROR
Definition: elog.h:45
TransactionId xid
Definition: multixact.h:62
#define FRM_INVALIDATE_XMAX
Definition: heapam.c:6097
#define InvalidTransactionId
Definition: transam.h:31
#define ISUPDATE_from_mxstatus(status)
Definition: multixact.h:56
#define MultiXactIdIsValid(multi)
Definition: multixact.h:28
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition: transam.c:300
#define ERRCODE_DATA_CORRUPTED
Definition: pg_basebackup.c:45
#define FRM_RETURN_IS_MULTI
Definition: heapam.c:6099
#define HEAP_XMAX_IS_LOCKED_ONLY(infomask)
Definition: htup_details.h:230
#define HEAP_XMAX_IS_MULTI
Definition: htup_details.h:208
#define ereport(elevel,...)
Definition: elog.h:155
int errmsg_internal(const char *fmt,...)
Definition: elog.c:992
#define Assert(condition)
Definition: c.h:804
#define FRM_NOOP
Definition: heapam.c:6096
bool MultiXactIdPrecedes(MultiXactId multi1, MultiXactId multi2)
Definition: multixact.c:3156
void * palloc(Size size)
Definition: mcxt.c:950
int i
int GetMultiXactIdMembers(MultiXactId multi, MultiXactMember **members, bool from_pgupgrade, bool onlyLock)
Definition: multixact.c:1223
#define TransactionIdIsValid(xid)
Definition: transam.h:41
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:227
bool MultiXactIdIsRunning(MultiXactId multi, bool isLockOnly)
Definition: multixact.c:551

◆ get_mxact_status_for_lock()

static MultiXactStatus get_mxact_status_for_lock ( LockTupleMode  mode,
bool  is_update 
)
static

Definition at line 4221 of file heapam.c.

References elog, ERROR, mode, and tupleLockExtraInfo.

Referenced by compute_new_xmax_infomask(), heap_lock_tuple(), and test_lockmode_for_conflict().

4222 {
4223  int retval;
4224 
4225  if (is_update)
4226  retval = tupleLockExtraInfo[mode].updstatus;
4227  else
4228  retval = tupleLockExtraInfo[mode].lockstatus;
4229 
4230  if (retval == -1)
4231  elog(ERROR, "invalid lock tuple mode %d/%s", mode,
4232  is_update ? "true" : "false");
4233 
4234  return (MultiXactStatus) retval;
4235 }
static PgChecksumMode mode
Definition: pg_checksums.c:61
MultiXactStatus
Definition: multixact.h:41
#define ERROR
Definition: elog.h:45
static const struct @13 tupleLockExtraInfo[MaxLockTupleMode+1]
#define elog(elevel,...)
Definition: elog.h:227

◆ GetBulkInsertState()

BulkInsertState GetBulkInsertState ( void  )

Definition at line 1983 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().

1984 {
1985  BulkInsertState bistate;
1986 
1987  bistate = (BulkInsertState) palloc(sizeof(BulkInsertStateData));
1989  bistate->current_buf = InvalidBuffer;
1990  return bistate;
1991 }
BufferAccessStrategy GetAccessStrategy(BufferAccessStrategyType btype)
Definition: freelist.c:542
#define InvalidBuffer
Definition: buf.h:25
struct BulkInsertStateData * BulkInsertState
Definition: heapam.h:39
BufferAccessStrategy strategy
Definition: hio.h:31
void * palloc(Size size)
Definition: mcxt.c:950
Buffer current_buf
Definition: hio.h:32

◆ GetMultiXactIdHintBits()

static void GetMultiXactIdHintBits ( MultiXactId  multi,
uint16 new_infomask,
uint16 new_infomask2 
)
static

Definition at line 6705 of file heapam.c.

References GetMultiXactIdMembers(), HEAP_KEYS_UPDATED, HEAP_XMAX_EXCL_LOCK, HEAP_XMAX_IS_MULTI, HEAP_XMAX_KEYSHR_LOCK, HEAP_XMAX_LOCK_ONLY, HEAP_XMAX_SHR_LOCK, i, LockTupleExclusive, LockTupleKeyShare, LockTupleNoKeyExclusive, LockTupleShare, mode, MultiXactStatusForKeyShare, MultiXactStatusForNoKeyUpdate, MultiXactStatusForShare, MultiXactStatusForUpdate, MultiXactStatusNoKeyUpdate, MultiXactStatusUpdate, pfree(), status(), and TUPLOCK_from_mxstatus.

Referenced by compute_new_xmax_infomask(), heap_prepare_freeze_tuple(), and heap_update().

6707 {
6708  int nmembers;
6709  MultiXactMember *members;
6710  int i;
6711  uint16 bits = HEAP_XMAX_IS_MULTI;
6712  uint16 bits2 = 0;
6713  bool has_update = false;
6714  LockTupleMode strongest = LockTupleKeyShare;
6715 
6716  /*
6717  * We only use this in multis we just created, so they cannot be values
6718  * pre-pg_upgrade.
6719  */
6720  nmembers = GetMultiXactIdMembers(multi, &members, false, false);
6721 
6722  for (i = 0; i < nmembers; i++)
6723  {
6725 
6726  /*
6727  * Remember the strongest lock mode held by any member of the
6728  * multixact.
6729  */
6730  mode = TUPLOCK_from_mxstatus(members[i].status);
6731  if (mode > strongest)
6732  strongest = mode;
6733 
6734  /* See what other bits we need */
6735  switch (members[i].status)
6736  {
6740  break;
6741 
6743  bits2 |= HEAP_KEYS_UPDATED;
6744  break;
6745 
6747  has_update = true;
6748  break;
6749 
6750  case MultiXactStatusUpdate:
6751  bits2 |= HEAP_KEYS_UPDATED;
6752  has_update = true;
6753  break;
6754  }
6755  }
6756 
6757  if (strongest == LockTupleExclusive ||
6758  strongest == LockTupleNoKeyExclusive)
6759  bits |= HEAP_XMAX_EXCL_LOCK;
6760  else if (strongest == LockTupleShare)
6761  bits |= HEAP_XMAX_SHR_LOCK;
6762  else if (strongest == LockTupleKeyShare)
6763  bits |= HEAP_XMAX_KEYSHR_LOCK;
6764 
6765  if (!has_update)
6766  bits |= HEAP_XMAX_LOCK_ONLY;
6767 
6768  if (nmembers > 0)
6769  pfree(members);
6770 
6771  *new_infomask = bits;
6772  *new_infomask2 = bits2;
6773 }
static PgChecksumMode mode
Definition: pg_checksums.c:61
#define HEAP_XMAX_KEYSHR_LOCK
Definition: htup_details.h:193
LockTupleMode
Definition: lockoptions.h:49
#define HEAP_XMAX_LOCK_ONLY
Definition: htup_details.h:196
#define HEAP_XMAX_SHR_LOCK
Definition: htup_details.h:199
unsigned short uint16
Definition: c.h:440
void pfree(void *pointer)
Definition: mcxt.c:1057
#define HEAP_XMAX_EXCL_LOCK
Definition: htup_details.h:195
#define HEAP_KEYS_UPDATED
Definition: htup_details.h:278
#define HEAP_XMAX_IS_MULTI
Definition: htup_details.h:208
#define TUPLOCK_from_mxstatus(status)
Definition: heapam.c:214
int i
int GetMultiXactIdMembers(MultiXactId multi, MultiXactMember **members, bool from_pgupgrade, bool onlyLock)
Definition: multixact.c:1223
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:227

◆ heap2_redo()

void heap2_redo ( XLogReaderState record)

Definition at line 9707 of file heapam.c.

References elog, heap_xlog_clean(), heap_xlog_cleanup_info(), heap_xlog_freeze_page(), heap_xlog_lock_updated(), heap_xlog_logical_rewrite(), heap_xlog_multi_insert(), heap_xlog_visible(), PANIC, XLOG_HEAP2_CLEAN, XLOG_HEAP2_CLEANUP_INFO, XLOG_HEAP2_FREEZE_PAGE, XLOG_HEAP2_LOCK_UPDATED, XLOG_HEAP2_MULTI_INSERT, XLOG_HEAP2_NEW_CID, XLOG_HEAP2_REWRITE, XLOG_HEAP2_VISIBLE, XLOG_HEAP_OPMASK, XLogRecGetInfo, and XLR_INFO_MASK.

9708 {
9709  uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
9710 
9711  switch (info & XLOG_HEAP_OPMASK)
9712  {
9713  case XLOG_HEAP2_CLEAN:
9714  heap_xlog_clean(record);
9715  break;
9717  heap_xlog_freeze_page(record);
9718  break;
9720  heap_xlog_cleanup_info(record);
9721  break;
9722  case XLOG_HEAP2_VISIBLE:
9723  heap_xlog_visible(record);
9724  break;
9726  heap_xlog_multi_insert(record);
9727  break;
9729  heap_xlog_lock_updated(record);
9730  break;
9731  case XLOG_HEAP2_NEW_CID:
9732 
9733  /*
9734  * Nothing to do on a real replay, only used during logical
9735  * decoding.
9736  */
9737  break;
9738  case XLOG_HEAP2_REWRITE:
9739  heap_xlog_logical_rewrite(record);
9740  break;
9741  default:
9742  elog(PANIC, "heap2_redo: unknown op code %u", info);
9743  }
9744 }
void heap_xlog_logical_rewrite(XLogReaderState *r)
Definition: rewriteheap.c:1109
#define XLOG_HEAP2_LOCK_UPDATED
Definition: heapam_xlog.h:59
#define XLOG_HEAP2_REWRITE
Definition: heapam_xlog.h:53
unsigned char uint8
Definition: c.h:439
#define XLOG_HEAP_OPMASK
Definition: heapam_xlog.h:41
#define PANIC
Definition: elog.h:55
#define XLOG_HEAP2_MULTI_INSERT
Definition: heapam_xlog.h:58
#define XLOG_HEAP2_VISIBLE
Definition: heapam_xlog.h:57
static void heap_xlog_lock_updated(XLogReaderState *record)
Definition: heapam.c:9560
static void heap_xlog_freeze_page(XLogReaderState *record)
Definition: heapam.c:8758
#define XLOG_HEAP2_CLEAN
Definition: heapam_xlog.h:54
#define XLOG_HEAP2_CLEANUP_INFO
Definition: heapam_xlog.h:56
static void heap_xlog_multi_insert(XLogReaderState *record)
Definition: heapam.c:9034
#define XLOG_HEAP2_NEW_CID
Definition: heapam_xlog.h:60
#define XLogRecGetInfo(decoder)
Definition: xlogreader.h:305
#define XLR_INFO_MASK
Definition: xlogrecord.h:62
static void heap_xlog_cleanup_info(XLogReaderState *record)
Definition: heapam.c:8504
#define XLOG_HEAP2_FREEZE_PAGE
Definition: heapam_xlog.h:55
#define elog(elevel,...)
Definition: elog.h:227
static void heap_xlog_visible(XLogReaderState *record)
Definition: heapam.c:8618
static void heap_xlog_clean(XLogReaderState *record)
Definition: heapam.c:8525

◆ heap_abort_speculative()

void heap_abort_speculative ( Relation  relation,
ItemPointer  tid 
)

Definition at line 5860 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(), RelationData::rd_rel, ReadBuffer(), 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, TransactionIdPrecedes(), TransactionXmin, 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().

5861 {
5863  ItemId lp;
5864  HeapTupleData tp;
5865  Page page;
5866  BlockNumber block;
5867  Buffer buffer;
5868  TransactionId prune_xid;
5869 
5870  Assert(ItemPointerIsValid(tid));
5871 
5872  block = ItemPointerGetBlockNumber(tid);
5873  buffer = ReadBuffer(relation, block);
5874  page = BufferGetPage(buffer);
5875 
5877 
5878  /*
5879  * Page can't be all visible, we just inserted into it, and are still
5880  * running.
5881  */
5882  Assert(!PageIsAllVisible(page));
5883 
5884  lp = PageGetItemId(page, ItemPointerGetOffsetNumber(tid));
5885  Assert(ItemIdIsNormal(lp));
5886 
5887  tp.t_tableOid = RelationGetRelid(relation);
5888  tp.t_data = (HeapTupleHeader) PageGetItem(page, lp);
5889  tp.t_len = ItemIdGetLength(lp);
5890  tp.t_self = *tid;
5891 
5892  /*
5893  * Sanity check that the tuple really is a speculatively inserted tuple,
5894  * inserted by us.
5895  */
5896  if (tp.t_data->t_choice.t_heap.t_xmin != xid)
5897  elog(ERROR, "attempted to kill a tuple inserted by another transaction");
5898  if (!(IsToastRelation(relation) || HeapTupleHeaderIsSpeculative(tp.t_data)))
5899  elog(ERROR, "attempted to kill a non-speculative tuple");
5901 
5902  /*
5903  * No need to check for serializable conflicts here. There is never a
5904  * need for a combocid, either. No need to extract replica identity, or
5905  * do anything special with infomask bits.
5906  */
5907 
5909 
5910  /*
5911  * The tuple will become DEAD immediately. Flag that this page is a
5912  * candidate for pruning by setting xmin to TransactionXmin. While not
5913  * immediately prunable, it is the oldest xid we can cheaply determine
5914  * that's safe against wraparound / being older than the table's
5915  * relfrozenxid. To defend against the unlikely case of a new relation
5916  * having a newer relfrozenxid than our TransactionXmin, use relfrozenxid
5917  * if so (vacuum can't subsequently move relfrozenxid to beyond
5918  * TransactionXmin, so there's no race here).
5919  */
5921  if (TransactionIdPrecedes(TransactionXmin, relation->rd_rel->relfrozenxid))
5922  prune_xid = relation->rd_rel->relfrozenxid;
5923  else
5924  prune_xid = TransactionXmin;
5925  PageSetPrunable(page, prune_xid);
5926 
5927  /* store transaction information of xact deleting the tuple */
5930 
5931  /*
5932  * Set the tuple header xmin to InvalidTransactionId. This makes the
5933  * tuple immediately invisible everyone. (In particular, to any
5934  * transactions waiting on the speculative token, woken up later.)
5935  */
5937 
5938  /* Clear the speculative insertion token too */
5939  tp.t_data->t_ctid = tp.t_self;
5940 
5941  MarkBufferDirty(buffer);
5942 
5943  /*
5944  * XLOG stuff
5945  *
5946  * The WAL records generated here match heap_delete(). The same recovery
5947  * routines are used.
5948  */
5949  if (RelationNeedsWAL(relation))
5950  {
5951  xl_heap_delete xlrec;
5952  XLogRecPtr recptr;
5953 
5954  xlrec.flags = XLH_DELETE_IS_SUPER;
5956  tp.t_data->t_infomask2);
5958  xlrec.xmax = xid;
5959 
5960  XLogBeginInsert();
5961  XLogRegisterData((char *) &xlrec, SizeOfHeapDelete);
5962  XLogRegisterBuffer(0, buffer, REGBUF_STANDARD);
5963 
5964  /* No replica identity & replication origin logged */
5965 
5966  recptr = XLogInsert(RM_HEAP_ID, XLOG_HEAP_DELETE);
5967 
5968  PageSetLSN(page, recptr);
5969  }
5970 
5971  END_CRIT_SECTION();
5972 
5973  LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
5974 
5975  if (HeapTupleHasExternal(&tp))
5976  {
5977  Assert(!IsToastRelation(relation));
5978  heap_toast_delete(relation, &tp, true);
5979  }
5980 
5981  /*
5982  * Never need to mark tuple for invalidation, since catalogs don't support
5983  * speculative insertion
5984  */
5985 
5986  /* Now we can release the buffer */
5987  ReleaseBuffer(buffer);
5988 
5989  /* count deletion, as we counted the insertion too */
5990  pgstat_count_heap_delete(relation);
5991 }
#define ItemPointerIsValid(pointer)
Definition: itemptr.h:82
#define BUFFER_LOCK_UNLOCK
Definition: bufmgr.h:96
bool IsToastRelation(Relation relation)
Definition: catalog.c:138
#define HEAP_XMAX_BITS
Definition: htup_details.h:270
#define XLH_DELETE_IS_SUPER
Definition: heapam_xlog.h:99
static uint8 compute_infobits(uint16 infomask, uint16 infomask2)
Definition: heapam.c:2695
HeapTupleFields t_heap
Definition: htup_details.h:156
#define PageIsAllVisible(page)
Definition: bufpage.h:385
uint32 TransactionId
Definition: c.h:587
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:1483
void XLogRegisterBuffer(uint8 block_id, Buffer buffer, uint8 flags)
Definition: xloginsert.c:220
HeapTupleHeaderData * HeapTupleHeader
Definition: htup.h:23
#define END_CRIT_SECTION()
Definition: miscadmin.h:135
#define HeapTupleHeaderIsSpeculative(tup)
Definition: htup_details.h:429
#define PageSetPrunable(page, xid)
Definition: bufpage.h:392
#define START_CRIT_SECTION()
Definition: miscadmin.h:133
uint32 BlockNumber
Definition: block.h:31
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3700
#define BUFFER_LOCK_EXCLUSIVE
Definition: bufmgr.h:98
Form_pg_class rd_rel
Definition: rel.h:110
union HeapTupleHeaderData::@43 t_choice
OffsetNumber offnum
Definition: heapam_xlog.h:110
TransactionId TransactionXmin
Definition: snapmgr.c:112
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:45
ItemPointerData t_ctid
Definition: htup_details.h:160
ItemPointerData t_self
Definition: htup.h:65
TransactionId xmax
Definition: heapam_xlog.h:109
void heap_toast_delete(Relation rel, HeapTuple oldtup, bool is_speculative)
Definition: heaptoast.c:43
TransactionId GetCurrentTransactionId(void)
Definition: xact.c:438
uint32 t_len
Definition: htup.h:64
#define SizeOfHeapDelete
Definition: heapam_xlog.h:115
#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:169
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition: transam.c:300
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:330
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:422
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3939
#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:804
uint8 infobits_set
Definition: heapam_xlog.h:111
#define ItemIdIsNormal(itemId)
Definition: itemid.h:99
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition: bufmgr.c:619
#define ItemPointerGetOffsetNumber(pointer)
Definition: itemptr.h:117
#define RelationNeedsWAL(relation)
Definition: rel.h:563
void pgstat_count_heap_delete(Relation rel)
Definition: pgstat.c:2221
#define HeapTupleHasExternal(tuple)
Definition: htup_details.h:673
#define elog(elevel,...)
Definition: elog.h:227
#define ItemPointerGetBlockNumber(pointer)
Definition: itemptr.h:98
#define TransactionIdIsValid(xid)
Definition: transam.h:41
void XLogBeginInsert(void)
Definition: xloginsert.c:123
#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:457
#define PageGetItem(page, itemId)
Definition: bufpage.h:340
Pointer Page
Definition: bufpage.h:78
#define HeapTupleHeaderSetXmin(tup, xid)
Definition: htup_details.h:319

◆ heap_acquire_tuplock()

static bool heap_acquire_tuplock ( Relation  relation,
ItemPointer  tid,
LockTupleMode  mode,
LockWaitPolicy  wait_policy,
bool have_tuple_lock 
)
static

Definition at line 4958 of file heapam.c.

References ConditionalLockTupleTuplock, ereport, errcode(), errmsg(), ERROR, LockTupleTuplock, LockWaitBlock, LockWaitError, LockWaitSkip, and RelationGetRelationName.

Referenced by heap_delete(), heap_lock_tuple(), and heap_update().

4960 {
4961  if (*have_tuple_lock)
4962  return true;
4963 
4964  switch (wait_policy)
4965  {
4966  case LockWaitBlock:
4967  LockTupleTuplock(relation, tid, mode);
4968  break;
4969 
4970  case LockWaitSkip:
4971  if (!ConditionalLockTupleTuplock(relation, tid, mode))
4972  return false;
4973  break;
4974 
4975  case LockWaitError:
4976  if (!ConditionalLockTupleTuplock(relation, tid, mode))
4977  ereport(ERROR,
4978  (errcode(ERRCODE_LOCK_NOT_AVAILABLE),
4979  errmsg("could not obtain lock on row in relation \"%s\"",
4980  RelationGetRelationName(relation))));
4981  break;
4982  }
4983  *have_tuple_lock = true;
4984 
4985  return true;
4986 }
static PgChecksumMode mode
Definition: pg_checksums.c:61
#define LockTupleTuplock(rel, tup, mode)
Definition: heapam.c:163
#define ConditionalLockTupleTuplock(rel, tup, mode)
Definition: heapam.c:167
int errcode(int sqlerrcode)
Definition: elog.c:694
#define ERROR
Definition: elog.h:45
#define RelationGetRelationName(relation)
Definition: rel.h:491
#define ereport(elevel,...)
Definition: elog.h:155
int errmsg(const char *fmt,...)
Definition: elog.c:905

◆ heap_beginscan()

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

Definition at line 1171 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_private, 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().

1175 {
1176  HeapScanDesc scan;
1177 
1178  /*
1179  * increment relation ref count while scanning relation
1180  *
1181  * This is just to make really sure the relcache entry won't go away while
1182  * the scan has a pointer to it. Caller should be holding the rel open
1183  * anyway, so this is redundant in all normal scenarios...
1184  */
1186 
1187  /*
1188  * allocate and initialize scan descriptor
1189  */
1190  scan = (HeapScanDesc) palloc(sizeof(HeapScanDescData));
1191 
1192  scan->rs_base.rs_rd = relation;
1193  scan->rs_base.rs_snapshot = snapshot;
1194  scan->rs_base.rs_nkeys = nkeys;
1195  scan->rs_base.rs_flags = flags;
1196  scan->rs_base.rs_parallel = parallel_scan;
1197  scan->rs_base.rs_private =
1199  scan->rs_strategy = NULL; /* set in initscan */
1200 
1201  /*
1202  * Disable page-at-a-time mode if it's not a MVCC-safe snapshot.
1203  */
1204  if (!(snapshot && IsMVCCSnapshot(snapshot)))
1206 
1207  /*
1208  * For seqscan and sample scans in a serializable transaction, acquire a
1209  * predicate lock on the entire relation. This is required not only to
1210  * lock all the matching tuples, but also to conflict with new insertions
1211  * into the table. In an indexscan, we take page locks on the index pages
1212  * covering the range specified in the scan qual, but in a heap scan there
1213  * is nothing more fine-grained to lock. A bitmap scan is a different
1214  * story, there we have already scanned the index and locked the index
1215  * pages covering the predicate. But in that case we still have to lock
1216  * any matching heap tuples. For sample scan we could optimize the locking
1217  * to be at least page-level granularity, but we'd need to add per-tuple
1218  * locking for that.
1219  */
1221  {
1222  /*
1223  * Ensure a missing snapshot is noticed reliably, even if the
1224  * isolation mode means predicate locking isn't performed (and
1225  * therefore the snapshot isn't used here).
1226  */
1227  Assert(snapshot);
1228  PredicateLockRelation(relation, snapshot);
1229  }
1230 
1231  /* we only need to set this up once */
1232  scan->rs_ctup.t_tableOid = RelationGetRelid(relation);
1233 
1234  /*
1235  * we do this here instead of in initscan() because heap_rescan also calls
1236  * initscan() and we don't want to allocate memory again
1237  */
1238  if (nkeys > 0)
1239  scan->rs_base.rs_key = (ScanKey) palloc(sizeof(ScanKeyData) * nkeys);
1240  else
1241  scan->rs_base.rs_key = NULL;
1242 
1243  initscan(scan, key, false);
1244 
1245  return (TableScanDesc) scan;
1246 }
TableScanDescData rs_base
Definition: heapam.h:49
void PredicateLockRelation(Relation relation, Snapshot snapshot)
Definition: predicate.c:2569
uint32 rs_flags
Definition: relscan.h:47
struct HeapScanDescData * HeapScanDesc
Definition: heapam.h:73
HeapTupleData rs_ctup
Definition: heapam.h:66
ScanKeyData * ScanKey
Definition: skey.h:75
Oid t_tableOid
Definition: htup.h:66
struct ScanKeyData * rs_key
Definition: relscan.h:37
void * rs_private
Definition: relscan.h:49
void RelationIncrementReferenceCount(Relation rel)
Definition: relcache.c:2090
BufferAccessStrategy rs_strategy
Definition: heapam.h:64
#define IsMVCCSnapshot(snapshot)
Definition: snapmgr.h:97
#define Assert(condition)
Definition: c.h:804
Relation rs_rd
Definition: relscan.h:34
struct SnapshotData * rs_snapshot
Definition: relscan.h:35
void * palloc(Size size)
Definition: mcxt.c:950
struct ParallelTableScanDescData * rs_parallel
Definition: relscan.h:50
static void initscan(HeapScanDesc scan, ScanKey key, bool keep_startblock)
Definition: heapam.c:227
#define RelationGetRelid(relation)
Definition: rel.h:457

◆ heap_delete()

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

Definition at line 2740 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, 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().

2743 {
2744  TM_Result result;
2746  ItemId lp;
2747  HeapTupleData tp;
2748  Page page;
2749  BlockNumber block;
2750  Buffer buffer;
2751  Buffer vmbuffer = InvalidBuffer;
2752  TransactionId new_xmax;
2753  uint16 new_infomask,
2754  new_infomask2;
2755  bool have_tuple_lock = false;
2756  bool iscombo;
2757  bool all_visible_cleared = false;
2758  HeapTuple old_key_tuple = NULL; /* replica identity of the tuple */
2759  bool old_key_copied = false;
2760 
2761  Assert(ItemPointerIsValid(tid));
2762 
2763  /*
2764  * Forbid this during a parallel operation, lest it allocate a combocid.
2765  * Other workers might need that combocid for visibility checks, and we
2766  * have no provision for broadcasting it to them.
2767  */
2768  if (IsInParallelMode())
2769  ereport(ERROR,
2770  (errcode(ERRCODE_INVALID_TRANSACTION_STATE),
2771  errmsg("cannot delete tuples during a parallel operation")));
2772 
2773  block = ItemPointerGetBlockNumber(tid);
2774  buffer = ReadBuffer(relation, block);
2775  page = BufferGetPage(buffer);
2776 
2777  /*
2778  * Before locking the buffer, pin the visibility map page if it appears to
2779  * be necessary. Since we haven't got the lock yet, someone else might be
2780  * in the middle of changing this, so we'll need to recheck after we have
2781  * the lock.
2782  */
2783  if (PageIsAllVisible(page))
2784  visibilitymap_pin(relation, block, &vmbuffer);
2785 
2787 
2788  /*
2789  * If we didn't pin the visibility map page and the page has become all
2790  * visible while we were busy locking the buffer, we'll have to unlock and
2791  * re-lock, to avoid holding the buffer lock across an I/O. That's a bit
2792  * unfortunate, but hopefully shouldn't happen often.
2793  */
2794  if (vmbuffer == InvalidBuffer && PageIsAllVisible(page))
2795  {
2796  LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
2797  visibilitymap_pin(relation, block, &vmbuffer);
2799  }
2800 
2801  lp = PageGetItemId(page, ItemPointerGetOffsetNumber(tid));
2802  Assert(ItemIdIsNormal(lp));
2803 
2804  tp.t_tableOid = RelationGetRelid(relation);
2805  tp.t_data = (HeapTupleHeader) PageGetItem(page, lp);
2806  tp.t_len = ItemIdGetLength(lp);
2807  tp.t_self = *tid;
2808 
2809 l1:
2810  result = HeapTupleSatisfiesUpdate(&tp, cid, buffer);
2811 
2812  if (result == TM_Invisible)
2813  {
2814  UnlockReleaseBuffer(buffer);
2815  ereport(ERROR,
2816  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
2817  errmsg("attempted to delete invisible tuple")));
2818  }
2819  else if (result == TM_BeingModified && wait)
2820  {
2821  TransactionId xwait;
2822  uint16 infomask;
2823 
2824  /* must copy state data before unlocking buffer */
2825  xwait = HeapTupleHeaderGetRawXmax(tp.t_data);
2826  infomask = tp.t_data->t_infomask;
2827 
2828  /*
2829  * Sleep until concurrent transaction ends -- except when there's a
2830  * single locker and it's our own transaction. Note we don't care
2831  * which lock mode the locker has, because we need the strongest one.
2832  *
2833  * Before sleeping, we need to acquire tuple lock to establish our
2834  * priority for the tuple (see heap_lock_tuple). LockTuple will
2835  * release us when we are next-in-line for the tuple.
2836  *
2837  * If we are forced to "start over" below, we keep the tuple lock;
2838  * this arranges that we stay at the head of the line while rechecking
2839  * tuple state.
2840  */
2841  if (infomask & HEAP_XMAX_IS_MULTI)
2842  {
2843  bool current_is_member = false;
2844 
2845  if (DoesMultiXactIdConflict((MultiXactId) xwait, infomask,
2846  LockTupleExclusive, &current_is_member))
2847  {
2848  LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
2849 
2850  /*
2851  * Acquire the lock, if necessary (but skip it when we're
2852  * requesting a lock and already have one; avoids deadlock).
2853  */
2854  if (!current_is_member)
2856  LockWaitBlock, &have_tuple_lock);
2857 
2858  /* wait for multixact */
2860  relation, &(tp.t_self), XLTW_Delete,
2861  NULL);
2863 
2864  /*
2865  * If xwait had just locked the tuple then some other xact
2866  * could update this tuple before we get to this point. Check
2867  * for xmax change, and start over if so.
2868  */
2869  if (xmax_infomask_changed(tp.t_data->t_infomask, infomask) ||
2871  xwait))
2872  goto l1;
2873  }
2874 
2875  /*
2876  * You might think the multixact is necessarily done here, but not
2877  * so: it could have surviving members, namely our own xact or
2878  * other subxacts of this backend. It is legal for us to delete
2879  * the tuple in either case, however (the latter case is
2880  * essentially a situation of upgrading our former shared lock to
2881  * exclusive). We don't bother changing the on-disk hint bits
2882  * since we are about to overwrite the xmax altogether.
2883  */
2884  }
2885  else if (!TransactionIdIsCurrentTransactionId(xwait))
2886  {
2887  /*
2888  * Wait for regular transaction to end; but first, acquire tuple
2889  * lock.
2890  */
2891  LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
2893  LockWaitBlock, &have_tuple_lock);
2894  XactLockTableWait(xwait, relation, &(tp.t_self), XLTW_Delete);
2896 
2897  /*
2898  * xwait is done, but if xwait had just locked the tuple then some
2899  * other xact could update this tuple before we get to this point.
2900  * Check for xmax change, and start over if so.
2901  */
2902  if (xmax_infomask_changed(tp.t_data->t_infomask, infomask) ||
2904  xwait))
2905  goto l1;
2906 
2907  /* Otherwise check if it committed or aborted */
2908  UpdateXmaxHintBits(tp.t_data, buffer, xwait);
2909  }
2910 
2911  /*
2912  * We may overwrite if previous xmax aborted, or if it committed but
2913  * only locked the tuple without updating it.
2914  */
2915  if ((tp.t_data->t_infomask & HEAP_XMAX_INVALID) ||
2918  result = TM_Ok;
2919  else if (!ItemPointerEquals(&tp.t_self, &tp.t_data->t_ctid))
2920  result = TM_Updated;
2921  else
2922  result = TM_Deleted;
2923  }
2924 
2925  if (crosscheck != InvalidSnapshot && result == TM_Ok)
2926  {
2927  /* Perform additional check for transaction-snapshot mode RI updates */
2928  if (!HeapTupleSatisfiesVisibility(&tp, crosscheck, buffer))
2929  result = TM_Updated;
2930  }
2931 
2932  if (result != TM_Ok)
2933  {
2934  Assert(result == TM_SelfModified ||
2935  result == TM_Updated ||
2936  result == TM_Deleted ||
2937  result == TM_BeingModified);
2939  Assert(result != TM_Updated ||
2940  !ItemPointerEquals(&tp.t_self, &tp.t_data->t_ctid));
2941  tmfd->ctid = tp.t_data->t_ctid;
2943  if (result == TM_SelfModified)
2944  tmfd->cmax = HeapTupleHeaderGetCmax(tp.t_data);
2945  else
2946  tmfd->cmax = InvalidCommandId;
2947  UnlockReleaseBuffer(buffer);
2948  if (have_tuple_lock)
2949  UnlockTupleTuplock(relation, &(tp.t_self), LockTupleExclusive);
2950  if (vmbuffer != InvalidBuffer)
2951  ReleaseBuffer(vmbuffer);
2952  return result;
2953  }
2954 
2955  /*
2956  * We're about to do the actual delete -- check for conflict first, to
2957  * avoid possibly having to roll back work we've just done.
2958  *
2959  * This is safe without a recheck as long as there is no possibility of
2960  * another process scanning the page between this check and the delete
2961  * being visible to the scan (i.e., an exclusive buffer content lock is
2962  * continuously held from this point until the tuple delete is visible).
2963  */
2964  CheckForSerializableConflictIn(relation, tid, BufferGetBlockNumber(buffer));
2965 
2966  /* replace cid with a combo cid if necessary */
2967  HeapTupleHeaderAdjustCmax(tp.t_data, &cid, &iscombo);
2968 
2969  /*
2970  * Compute replica identity tuple before entering the critical section so
2971  * we don't PANIC upon a memory allocation failure.
2972  */
2973  old_key_tuple = ExtractReplicaIdentity(relation, &tp, true, &old_key_copied);
2974 
2975  /*
2976  * If this is the first possibly-multixact-able operation in the current
2977  * transaction, set my per-backend OldestMemberMXactId setting. We can be
2978  * certain that the transaction will never become a member of any older
2979  * MultiXactIds than that. (We have to do this even if we end up just
2980  * using our own TransactionId below, since some other backend could
2981  * incorporate our XID into a MultiXact immediately afterwards.)
2982  */
2984 
2987  xid, LockTupleExclusive, true,
2988  &new_xmax, &new_infomask, &new_infomask2);
2989 
2991 
2992  /*
2993  * If this transaction commits, the tuple will become DEAD sooner or
2994  * later. Set flag that this page is a candidate for pruning once our xid
2995  * falls below the OldestXmin horizon. If the transaction finally aborts,
2996  * the subsequent page pruning will be a no-op and the hint will be
2997  * cleared.
2998  */
2999  PageSetPrunable(page, xid);
3000 
3001  if (PageIsAllVisible(page))
3002  {
3003  all_visible_cleared = true;
3004  PageClearAllVisible(page);
3005  visibilitymap_clear(relation, BufferGetBlockNumber(buffer),
3006  vmbuffer, VISIBILITYMAP_VALID_BITS);
3007  }
3008 
3009  /* store transaction information of xact deleting the tuple */
3012  tp.t_data->t_infomask |= new_infomask;
3013  tp.t_data->t_infomask2 |= new_infomask2;
3015  HeapTupleHeaderSetXmax(tp.t_data, new_xmax);
3016  HeapTupleHeaderSetCmax(tp.t_data, cid, iscombo);
3017  /* Make sure there is no forward chain link in t_ctid */
3018  tp.t_data->t_ctid = tp.t_self;
3019 
3020  /* Signal that this is actually a move into another partition */
3021  if (changingPart)
3023 
3024  MarkBufferDirty(buffer);
3025 
3026  /*
3027  * XLOG stuff
3028  *
3029  * NB: heap_abort_speculative() uses the same xlog record and replay
3030  * routines.
3031  */
3032  if (RelationNeedsWAL(relation))
3033  {
3034  xl_heap_delete xlrec;
3035  xl_heap_header xlhdr;
3036  XLogRecPtr recptr;
3037 
3038  /* For logical decode we need combocids to properly decode the catalog */
3040  log_heap_new_cid(relation, &tp);
3041 
3042  xlrec.flags = 0;
3043  if (all_visible_cleared)
3045  if (changingPart)
3048  tp.t_data->t_infomask2);
3050  xlrec.xmax = new_xmax;
3051 
3052  if (old_key_tuple != NULL)
3053  {
3054  if (relation->rd_rel->relreplident == REPLICA_IDENTITY_FULL)
3056  else
3058  }
3059 
3060  XLogBeginInsert();
3061  XLogRegisterData((char *) &xlrec, SizeOfHeapDelete);
3062 
3063  XLogRegisterBuffer(0, buffer, REGBUF_STANDARD);
3064 
3065  /*
3066  * Log replica identity of the deleted tuple if there is one
3067  */
3068  if (old_key_tuple != NULL)
3069  {
3070  xlhdr.t_infomask2 = old_key_tuple->t_data->t_infomask2;
3071  xlhdr.t_infomask = old_key_tuple->t_data->t_infomask;
3072  xlhdr.t_hoff = old_key_tuple->t_data->t_hoff;
3073 
3074  XLogRegisterData((char *) &xlhdr, SizeOfHeapHeader);
3075  XLogRegisterData((char *) old_key_tuple->t_data
3077  old_key_tuple->t_len
3079  }
3080 
3081  /* filtering by origin on a row level is much more efficient */
3083 
3084  recptr = XLogInsert(RM_HEAP_ID, XLOG_HEAP_DELETE);
3085 
3086  PageSetLSN(page, recptr);
3087  }
3088 
3089  END_CRIT_SECTION();
3090 
3091  LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
3092 
3093  if (vmbuffer != InvalidBuffer)
3094  ReleaseBuffer(vmbuffer);
3095 
3096  /*
3097  * If the tuple has toasted out-of-line attributes, we need to delete
3098  * those items too. We have to do this before releasing the buffer
3099  * because we need to look at the contents of the tuple, but it's OK to
3100  * release the content lock on the buffer first.
3101  */
3102  if (relation->rd_rel->relkind != RELKIND_RELATION &&
3103  relation->rd_rel->relkind != RELKIND_MATVIEW)
3104  {
3105  /* toast table entries should never be recursively toasted */
3107  }
3108  else if (HeapTupleHasExternal(&tp))
3109  heap_toast_delete(relation, &tp, false);
3110 
3111  /*
3112  * Mark tuple for invalidation from system caches at next command
3113  * boundary. We have to do this before releasing the buffer because we
3114  * need to look at the contents of the tuple.
3115  */
3116  CacheInvalidateHeapTuple(relation, &tp, NULL);
3117 
3118  /* Now we can release the buffer */
3119  ReleaseBuffer(buffer);
3120 
3121  /*
3122  * Release the lmgr tuple lock, if we had it.
3123  */
3124  if (have_tuple_lock)
3125  UnlockTupleTuplock(relation, &(tp.t_self), LockTupleExclusive);
3126 
3127  pgstat_count_heap_delete(relation);
3128 
3129  if (old_key_tuple != NULL && old_key_copied)
3130  heap_freetuple(old_key_tuple);
3131 
3132  return TM_Ok;
3133 }
#define HeapTupleHeaderGetUpdateXid(tup)
Definition: htup_details.h:365
#define ItemPointerIsValid(pointer)
Definition: itemptr.h:82
ItemPointerData ctid
Definition: tableam.h:126
#define BUFFER_LOCK_UNLOCK
Definition: bufmgr.h:96
#define SizeofHeapTupleHeader
Definition: htup_details.h:184
static XLogRecPtr log_heap_new_cid(Relation relation, HeapTuple tup)
Definition: heapam.c:8330
#define HEAP_XMAX_BITS
Definition: htup_details.h:270
static uint8 compute_infobits(uint16 infomask, uint16 infomask2)
Definition: heapam.c:2695
void CacheInvalidateHeapTuple(Relation relation, HeapTuple tuple, HeapTuple newtuple)
Definition: inval.c:1122
#define TransactionIdEquals(id1, id2)
Definition: transam.h:43
#define PageIsAllVisible(page)
Definition: bufpage.h:385
uint32 TransactionId
Definition: c.h:587
bool TransactionIdIsCurrentTransactionId(TransactionId xid)
Definition: xact.c:869
void visibilitymap_pin(Relation rel, BlockNumber heapBlk, Buffer *buf)
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:1483
void XLogRegisterBuffer(uint8 block_id, Buffer buffer, uint8 flags)
Definition: xloginsert.c:220
HeapTupleHeaderData * HeapTupleHeader
Definition: htup.h:23
static HeapTuple ExtractReplicaIdentity(Relation rel, HeapTuple tup, bool key_changed, bool *copy)
Definition: heapam.c:8412
static bool xmax_infomask_changed(uint16 new_infomask, uint16 old_infomask)
Definition: heapam.c:2717
#define HeapTupleHeaderClearHotUpdated(tup)
Definition: htup_details.h:496
#define END_CRIT_SECTION()
Definition: miscadmin.h:135
CommandId cmax
Definition: tableam.h:128
bool HeapTupleHeaderIsOnlyLocked(HeapTupleHeader tuple)
#define InvalidBuffer
Definition: buf.h:25
uint16 t_infomask2
Definition: heapam_xlog.h:146
#define PageSetPrunable(page, xid)
Definition: bufpage.h:392
#define START_CRIT_SECTION()
Definition: miscadmin.h:133
int errcode(int sqlerrcode)
Definition: elog.c:694
#define XLOG_INCLUDE_ORIGIN
Definition: xlog.h:238
uint32 BlockNumber
Definition: block.h:31
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3700
#define BUFFER_LOCK_EXCLUSIVE
Definition: bufmgr.h:98
Form_pg_class rd_rel
Definition: rel.h:110
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
TM_Result HeapTupleSatisfiesUpdate(HeapTuple htup, CommandId curcid, Buffer buffer)
#define UnlockTupleTuplock(rel, tup, mode)
Definition: heapam.c:165
OffsetNumber offnum
Definition: heapam_xlog.h:110
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:440
#define ItemIdGetLength(itemId)
Definition: itemid.h:59
bool IsInParallelMode(void)
Definition: xact.c:1012
bool visibilitymap_clear(Relation rel, BlockNumber heapBlk, Buffer buf, uint8 flags)
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3723
TransactionId xmax
Definition: tableam.h:127
#define ERROR
Definition: elog.h:45
#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:109
static void MultiXactIdWait(MultiXactId multi, MultiXactStatus status, uint16 infomask, Relation rel, ItemPointer ctid, XLTW_Oper oper, int *remaining)
Definition: heapam.c:7031
void heap_toast_delete(Relation rel, HeapTuple oldtup, bool is_speculative)
Definition: heaptoast.c:43
TransactionId GetCurrentTransactionId(void)
Definition: xact.c:438
uint32 t_len
Definition: htup.h:64
#define SizeOfHeapDelete
Definition: heapam_xlog.h:115
#define REGBUF_STANDARD
Definition: xloginsert.h:35
#define XLH_DELETE_CONTAINS_OLD_KEY
Definition: heapam_xlog.h:98
#define HeapTupleHeaderSetXmax(tup, xid)
Definition: htup_details.h:380
Oid t_tableOid
Definition: htup.h:66
void XLogSetRecordFlags(uint8 flags)
Definition: xloginsert.c:404
#define HeapTupleHeaderSetCmax(tup, cid, iscombo)
Definition: htup_details.h:405
#define BufferGetPage(buffer)
Definition: bufmgr.h:169
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:5007
#define PageGetItemId(page, offsetNumber)
Definition: bufpage.h:235
#define InvalidSnapshot
Definition: snapshot.h:123
void XLogRegisterData(char *data, int len)
Definition: xloginsert.c:330
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:422
TM_Result
Definition: tableam.h:71
#define RelationIsAccessibleInLogicalDecoding(relation)
Definition: rel.h:620
#define InvalidCommandId
Definition: c.h:604
#define HEAP_XMAX_IS_LOCKED_ONLY(infomask)
Definition: htup_details.h:230
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3939
#define HEAP_KEYS_UPDATED
Definition: htup_details.h:278
#define HEAP_XMAX_IS_MULTI
Definition: htup_details.h:208
void CheckForSerializableConflictIn(Relation relation, ItemPointer tid, BlockNumber blkno)
Definition: predicate.c:4446
static void UpdateXmaxHintBits(HeapTupleHeader tuple, Buffer buffer, TransactionId xid)
Definition: heapam.c:1961
#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:4958
#define ereport(elevel,...)
Definition: elog.h:155
TransactionId MultiXactId
Definition: c.h:597
#define PageClearAllVisible(page)
Definition: bufpage.h:389
void XactLockTableWait(TransactionId xid, Relation rel, ItemPointer ctid, XLTW_Oper oper)
Definition: lmgr.c:639
uint64 XLogRecPtr
Definition: xlogdefs.h:21
#define Assert(condition)
Definition: c.h:804
uint8 infobits_set
Definition: heapam_xlog.h:111
CommandId HeapTupleHeaderGetCmax(HeapTupleHeader tup)
Definition: combocid.c:118
Definition: tableam.h:77
#define ItemIdIsNormal(itemId)
Definition: itemid.h:99
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition: bufmgr.c:619
uint16 t_infomask
Definition: heapam_xlog.h:147
#define ItemPointerGetOffsetNumber(pointer)
Definition: itemptr.h:117
static bool DoesMultiXactIdConflict(MultiXactId multi, uint16 infomask, LockTupleMode lockmode, bool *current_is_member)
Definition: heapam.c:6854
#define RelationNeedsWAL(relation)
Definition: rel.h:563
bool ItemPointerEquals(ItemPointer pointer1, ItemPointer pointer2)
Definition: itemptr.c:29
void pgstat_count_heap_delete(Relation rel)
Definition: pgstat.c:2221
void HeapTupleHeaderAdjustCmax(HeapTupleHeader tup, CommandId *cmax, bool *iscombo)
Definition: combocid.c:153
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:2674
#define HeapTupleHasExternal(tuple)
Definition: htup_details.h:673
int errmsg(const char *fmt,...)
Definition: elog.c:905
#define XLH_DELETE_ALL_VISIBLE_CLEARED
Definition: heapam_xlog.h:96
#define XLH_DELETE_IS_PARTITION_MOVE
Definition: heapam_xlog.h:100
#define ItemPointerGetBlockNumber(pointer)
Definition: itemptr.h:98
void XLogBeginInsert(void)
Definition: xloginsert.c:123
#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:457
#define PageGetItem(page, itemId)
Definition: bufpage.h:340
#define SizeOfHeapHeader
Definition: heapam_xlog.h:151
Pointer Page
Definition: bufpage.h:78
bool HeapTupleSatisfiesVisibility(HeapTuple tup, Snapshot snapshot, Buffer buffer)
#define XLH_DELETE_CONTAINS_OLD_TUPLE
Definition: heapam_xlog.h:97

◆ heap_endscan()

void heap_endscan ( TableScanDesc  sscan)

Definition at line 1286 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().

1287 {
1288  HeapScanDesc scan = (HeapScanDesc) sscan;
1289 
1290  /* Note: no locking manipulations needed */
1291 
1292  /*
1293  * unpin scan buffers
1294  */
1295  if (BufferIsValid(scan->rs_cbuf))
1296  ReleaseBuffer(scan->rs_cbuf);
1297 
1298  /*
1299  * decrement relation reference count and free scan descriptor storage
1300  */
1302 
1303  if (scan->rs_base.rs_key)
1304  pfree(scan->rs_base.rs_key);
1305 
1306  if (scan->rs_strategy != NULL)
1308 
1309  if (scan->rs_base.rs_flags & SO_TEMP_SNAPSHOT)
1311 
1312  pfree(scan);
1313 }
TableScanDescData rs_base
Definition: heapam.h:49
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3700
uint32 rs_flags
Definition: relscan.h:47
struct HeapScanDescData * HeapScanDesc
Definition: heapam.h:73
void pfree(void *pointer)
Definition: mcxt.c:1057
void RelationDecrementReferenceCount(Relation rel)
Definition: relcache.c:2103
struct ScanKeyData * rs_key
Definition: relscan.h:37
void UnregisterSnapshot(Snapshot snapshot)
Definition: snapmgr.c:852
BufferAccessStrategy rs_strategy
Definition: heapam.h:64
Buffer rs_cbuf
Definition: heapam.h:60
void FreeAccessStrategy(BufferAccessStrategy strategy)
Definition: freelist.c:597
#define BufferIsValid(bufnum)
Definition: bufmgr.h:123
Relation rs_rd
Definition: relscan.h:34
struct SnapshotData * rs_snapshot
Definition: relscan.h:35

◆ heap_execute_freeze_tuple()

void heap_execute_freeze_tuple ( HeapTupleHeader  tuple,
xl_heap_freeze_tuple frz 
)

Definition at line 6653 of file heapam.c.

References FrozenTransactionId, xl_heap_freeze_tuple::frzflags, HeapTupleHeaderSetXmax, HeapTupleHeaderSetXvac, InvalidTransactionId, HeapTupleHeaderData::t_infomask, xl_heap_freeze_tuple::t_infomask, HeapTupleHeaderData::t_infomask2, xl_heap_freeze_tuple::t_infomask2, XLH_FREEZE_XVAC, XLH_INVALID_XVAC, and xl_heap_freeze_tuple::xmax.

Referenced by heap_freeze_tuple(), heap_xlog_freeze_page(), and lazy_scan_heap().

6654 {
6655  HeapTupleHeaderSetXmax(tuple, frz->xmax);
6656 
6657  if (frz->frzflags & XLH_FREEZE_XVAC)
6659 
6660  if (frz->frzflags & XLH_INVALID_XVAC)
6662 
6663  tuple->t_infomask = frz->t_infomask;
6664  tuple->t_infomask2 = frz->t_infomask2;
6665 }
#define HeapTupleHeaderSetXvac(tup, xid)
Definition: htup_details.h:423
#define HeapTupleHeaderSetXmax(tup, xid)
Definition: htup_details.h:380
#define InvalidTransactionId
Definition: transam.h:31
#define FrozenTransactionId
Definition: transam.h:33
TransactionId xmax
Definition: heapam_xlog.h:322
#define XLH_INVALID_XVAC
Definition: heapam_xlog.h:318
#define XLH_FREEZE_XVAC
Definition: heapam_xlog.h:317

◆ heap_fetch()

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

Definition at line 1571 of file heapam.c.

References BUFFER_LOCK_SHARE, BUFFER_LOCK_UNLOCK, BufferGetPage, HeapCheckForSerializableConflictOut(), HeapTupleHeaderGetXmin, HeapTupleSatisfiesVisibility(), InvalidBuffer, ItemIdGetLength, ItemIdIsNormal, ItemPointerGetBlockNumber, ItemPointerGetOffsetNumber, LockBuffer(), PageGetItem, PageGetItemId, PageGetMaxOffsetNumber, PredicateLockTID(), 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().

1575 {
1576  ItemPointer tid = &(tuple->t_self);
1577  ItemId lp;
1578  Buffer buffer;
1579  Page page;
1580  OffsetNumber offnum;
1581  bool valid;
1582 
1583  /*
1584  * Fetch and pin the appropriate page of the relation.
1585  */
1586  buffer = ReadBuffer(relation, ItemPointerGetBlockNumber(tid));
1587 
1588  /*
1589  * Need share lock on buffer to examine tuple commit status.
1590  */
1591  LockBuffer(buffer, BUFFER_LOCK_SHARE);
1592  page = BufferGetPage(buffer);
1593  TestForOldSnapshot(snapshot, relation, page);
1594 
1595  /*
1596  * We'd better check for out-of-range offnum in case of VACUUM since the
1597  * TID was obtained.
1598  */
1599  offnum = ItemPointerGetOffsetNumber(tid);
1600  if (offnum < FirstOffsetNumber || offnum > PageGetMaxOffsetNumber(page))
1601  {
1602  LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
1603  ReleaseBuffer(buffer);
1604  *userbuf = InvalidBuffer;
1605  tuple->t_data = NULL;
1606  return false;
1607  }
1608 
1609  /*
1610  * get the item line pointer corresponding to the requested tid
1611  */
1612  lp = PageGetItemId(page, offnum);
1613 
1614  /*
1615  * Must check for deleted tuple.
1616  */
1617  if (!ItemIdIsNormal(lp))
1618  {
1619  LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
1620  ReleaseBuffer(buffer);
1621  *userbuf = InvalidBuffer;
1622  tuple->t_data = NULL;
1623  return false;
1624  }
1625 
1626  /*
1627  * fill in *tuple fields
1628  */
1629  tuple->t_data = (HeapTupleHeader) PageGetItem(page, lp);
1630  tuple->t_len = ItemIdGetLength(lp);
1631  tuple->t_tableOid = RelationGetRelid(relation);
1632 
1633  /*
1634  * check tuple visibility, then release lock
1635  */
1636  valid = HeapTupleSatisfiesVisibility(tuple, snapshot, buffer);
1637 
1638  if (valid)
1639  PredicateLockTID(relation, &(tuple->t_self), snapshot,
1640  HeapTupleHeaderGetXmin(tuple->t_data));
1641 
1642  HeapCheckForSerializableConflictOut(valid, relation, tuple, buffer, snapshot);
1643 
1644  LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
1645 
1646  if (valid)
1647  {
1648  /*
1649  * All checks passed, so return the tuple as valid. Caller is now
1650  * responsible for releasing the buffer.
1651  */
1652  *userbuf = buffer;
1653 
1654  return true;
1655  }
1656 
1657  /* Tuple failed time qual */
1658  ReleaseBuffer(buffer);
1659  *userbuf = InvalidBuffer;
1660 
1661  return false;
1662 }
#define BUFFER_LOCK_UNLOCK
Definition: bufmgr.h:96
static void TestForOldSnapshot(Snapshot snapshot, Relation relation, Page page)
Definition: bufmgr.h:277
HeapTupleHeaderData * HeapTupleHeader
Definition: htup.h:23
#define InvalidBuffer
Definition: buf.h:25
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3700
#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
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:169
#define PageGetItemId(page, offsetNumber)
Definition: bufpage.h:235
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3939
void PredicateLockTID(Relation relation, ItemPointer tid, Snapshot snapshot, TransactionId tuple_xid)
Definition: predicate.c:2614
void HeapCheckForSerializableConflictOut(bool visible, Relation relation, HeapTuple tuple, Buffer buffer, Snapshot snapshot)
Definition: heapam.c:9846
#define ItemIdIsNormal(itemId)
Definition: itemid.h:99
#define HeapTupleHeaderGetXmin(tup)
Definition: htup_details.h:313
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition: bufmgr.c:619
#define ItemPointerGetOffsetNumber(pointer)
Definition: itemptr.h:117
#define BUFFER_LOCK_SHARE
Definition: bufmgr.h:97
#define ItemPointerGetBlockNumber(pointer)
Definition: itemptr.h:98
int Buffer
Definition: buf.h:23
#define RelationGetRelid(relation)
Definition: rel.h:457
#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 5769 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().

5770 {
5771  Buffer buffer;
5772  Page page;
5773  OffsetNumber offnum;
5774  ItemId lp = NULL;
5775  HeapTupleHeader htup;
5776 
5777  buffer = ReadBuffer(relation, ItemPointerGetBlockNumber(tid));
5779  page = (Page) BufferGetPage(buffer);
5780 
5781  offnum = ItemPointerGetOffsetNumber(tid);
5782  if (PageGetMaxOffsetNumber(page) >= offnum)
5783  lp = PageGetItemId(page, offnum);
5784 
5785  if (PageGetMaxOffsetNumber(page) < offnum || !ItemIdIsNormal(lp))
5786  elog(ERROR, "invalid lp");
5787 
5788  htup = (HeapTupleHeader) PageGetItem(page, lp);
5789 
5790  /* SpecTokenOffsetNumber should be distinguishable from any real offset */
5792  "invalid speculative token constant");
5793 
5794  /* NO EREPORT(ERROR) from here till changes are logged */
5796 
5798 
5799  MarkBufferDirty(buffer);
5800 
5801  /*
5802  * Replace the speculative insertion token with a real t_ctid, pointing to
5803  * itself like it does on regular tuples.
5804  */
5805  htup->t_ctid = *tid;
5806 
5807  /* XLOG stuff */
5808  if (RelationNeedsWAL(relation))
5809  {
5810  xl_heap_confirm xlrec;
5811  XLogRecPtr recptr;
5812 
5813  xlrec.offnum = ItemPointerGetOffsetNumber(tid);
5814 
5815  XLogBeginInsert();
5816 
5817  /* We want the same filtering on this as on a plain insert */
5819 
5820  XLogRegisterData((char *) &xlrec, SizeOfHeapConfirm);
5821  XLogRegisterBuffer(0, buffer, REGBUF_STANDARD);
5822 
5823  recptr = XLogInsert(RM_HEAP_ID, XLOG_HEAP_CONFIRM);
5824 
5825  PageSetLSN(page, recptr);
5826  }
5827 
5828  END_CRIT_SECTION();
5829 
5830  UnlockReleaseBuffer(buffer);
5831 }
OffsetNumber offnum
Definition: heapam_xlog.h:298
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:1483
void XLogRegisterBuffer(uint8 block_id, Buffer buffer, uint8 flags)
Definition: xloginsert.c:220
HeapTupleHeaderData * HeapTupleHeader
Definition: htup.h:23
#define MaxOffsetNumber
Definition: off.h:28
#define END_CRIT_SECTION()
Definition: miscadmin.h:135
#define HeapTupleHeaderIsSpeculative(tup)
Definition: htup_details.h:429
#define START_CRIT_SECTION()
Definition: miscadmin.h:133
#define XLOG_INCLUDE_ORIGIN
Definition: xlog.h:238
#define BUFFER_LOCK_EXCLUSIVE
Definition: bufmgr.h:98
#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:918
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3723
#define ERROR
Definition: elog.h:45
ItemPointerData t_ctid
Definition: htup_details.h:160
#define REGBUF_STANDARD
Definition: xloginsert.h:35
void XLogSetRecordFlags(uint8 flags)
Definition: xloginsert.c:404
#define BufferGetPage(buffer)
Definition: bufmgr.h:169
#define SizeOfHeapConfirm
Definition: heapam_xlog.h:301
#define PageGetItemId(page, offsetNumber)
Definition: bufpage.h:235
void XLogRegisterData(char *data, int len)
Definition: xloginsert.c:330
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:422
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3939
uint64 XLogRecPtr
Definition: xlogdefs.h:21
#define Assert(condition)
Definition: c.h:804
#define ItemIdIsNormal(itemId)
Definition: itemid.h:99
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition: bufmgr.c:619
#define ItemPointerGetOffsetNumber(pointer)
Definition: itemptr.h:117
#define RelationNeedsWAL(relation)
Definition: rel.h:563
#define elog(elevel,...)
Definition: elog.h:227
#define ItemPointerGetBlockNumber(pointer)
Definition: itemptr.h:98
void XLogBeginInsert(void)
Definition: xloginsert.c:123
#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 6674 of file heapam.c.

References heap_execute_freeze_tuple(), and heap_prepare_freeze_tuple().

Referenced by rewrite_heap_tuple().

6677 {
6679  bool do_freeze;
6680  bool tuple_totally_frozen;
6681 
6682  do_freeze = heap_prepare_freeze_tuple(tuple,
6683  relfrozenxid, relminmxid,
6684  cutoff_xid, cutoff_multi,
6685  &frz, &tuple_totally_frozen);
6686 
6687  /*
6688  * Note that because this is not a WAL-logged operation, we don't need to
6689  * fill in the offset in the freeze record.
6690  */
6691 
6692  if (do_freeze)
6693  heap_execute_freeze_tuple(tuple, &frz);
6694  return do_freeze;
6695 }
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:6424
void heap_execute_freeze_tuple(HeapTupleHeader tuple, xl_heap_freeze_tuple *frz)
Definition: heapam.c:6653

◆ heap_get_latest_tid()

void heap_get_latest_tid ( TableScanDesc  sscan,
ItemPointer  tid 
)

Definition at line 1838 of file heapam.c.

References Assert, BUFFER_LOCK_SHARE, BufferGetPage, HEAP_XMAX_INVALID, HeapCheckForSerializableConflictOut(), 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().

1840 {
1841  Relation relation = sscan->rs_rd;
1842  Snapshot snapshot = sscan->rs_snapshot;
1843  ItemPointerData ctid;
1844  TransactionId priorXmax;
1845 
1846  /*
1847  * table_tuple_get_latest_tid() verified that the passed in tid is valid.
1848  * Assume that t_ctid links are valid however - there shouldn't be invalid
1849  * ones in the table.
1850  */
1851  Assert(ItemPointerIsValid(tid));
1852 
1853  /*
1854  * Loop to chase down t_ctid links. At top of loop, ctid is the tuple we
1855  * need to examine, and *tid is the TID we will return if ctid turns out
1856  * to be bogus.
1857  *
1858  * Note that we will loop until we reach the end of the t_ctid chain.
1859  * Depending on the snapshot passed, there might be at most one visible
1860  * version of the row, but we don't try to optimize for that.
1861  */
1862  ctid = *tid;
1863  priorXmax = InvalidTransactionId; /* cannot check first XMIN */
1864  for (;;)
1865  {
1866  Buffer buffer;
1867  Page page;
1868  OffsetNumber offnum;
1869  ItemId lp;
1870  HeapTupleData tp;
1871  bool valid;
1872 
1873  /*
1874  * Read, pin, and lock the page.
1875  */
1876  buffer = ReadBuffer(relation, ItemPointerGetBlockNumber(&ctid));
1877  LockBuffer(buffer, BUFFER_LOCK_SHARE);
1878  page = BufferGetPage(buffer);
1879  TestForOldSnapshot(snapshot, relation, page);
1880 
1881  /*
1882  * Check for bogus item number. This is not treated as an error
1883  * condition because it can happen while following a t_ctid link. We
1884  * just assume that the prior tid is OK and return it unchanged.
1885  */
1886  offnum = ItemPointerGetOffsetNumber(&ctid);
1887  if (offnum < FirstOffsetNumber || offnum > PageGetMaxOffsetNumber(page))
1888  {
1889  UnlockReleaseBuffer(buffer);
1890  break;
1891  }
1892  lp = PageGetItemId(page, offnum);
1893  if (!ItemIdIsNormal(lp))
1894  {
1895  UnlockReleaseBuffer(buffer);
1896  break;
1897  }
1898 
1899  /* OK to access the tuple */
1900  tp.t_self = ctid;
1901  tp.t_data = (HeapTupleHeader) PageGetItem(page, lp);
1902  tp.t_len = ItemIdGetLength(lp);
1903  tp.t_tableOid = RelationGetRelid(relation);
1904 
1905  /*
1906  * After following a t_ctid link, we might arrive at an unrelated
1907  * tuple. Check for XMIN match.
1908  */
1909  if (TransactionIdIsValid(priorXmax) &&
1911  {
1912  UnlockReleaseBuffer(buffer);
1913  break;
1914  }
1915 
1916  /*
1917  * Check tuple visibility; if visible, set it as the new result
1918  * candidate.
1919  */
1920  valid = HeapTupleSatisfiesVisibility(&tp, snapshot, buffer);
1921  HeapCheckForSerializableConflictOut(valid, relation, &tp, buffer, snapshot);
1922  if (valid)
1923  *tid = ctid;
1924 
1925  /*
1926  * If there's a valid t_ctid link, follow it, else we're done.
1927  */
1928  if ((tp.t_data->t_infomask & HEAP_XMAX_INVALID) ||
1932  {
1933  UnlockReleaseBuffer(buffer);
1934  break;
1935  }
1936 
1937  ctid = tp.t_data->t_ctid;
1938  priorXmax = HeapTupleHeaderGetUpdateXid(tp.t_data);
1939  UnlockReleaseBuffer(buffer);
1940  } /* end of loop */
1941 }
#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:277
#define TransactionIdEquals(id1, id2)
Definition: transam.h:43
uint32 TransactionId
Definition: c.h:587
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
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:3723
#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:169
#define PageGetItemId(page, offsetNumber)
Definition: bufpage.h:235
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3939
void HeapCheckForSerializableConflictOut(bool visible, Relation relation, HeapTuple tuple, Buffer buffer, Snapshot snapshot)
Definition: heapam.c:9846
#define Assert(condition)
Definition: c.h:804
#define ItemIdIsNormal(itemId)
Definition: itemid.h:99
#define HeapTupleHeaderGetXmin(tup)
Definition: htup_details.h:313
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition: bufmgr.c:619
#define ItemPointerGetOffsetNumber(pointer)
Definition: itemptr.h:117
bool ItemPointerEquals(ItemPointer pointer1, ItemPointer pointer2)
Definition: itemptr.c:29
Relation rs_rd
Definition: relscan.h:34
struct SnapshotData * rs_snapshot
Definition: relscan.h:35
#define BUFFER_LOCK_SHARE
Definition: bufmgr.h:97
#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:457
#define PageGetItem(page, itemId)
Definition: bufpage.h:340
Pointer Page
Definition: bufpage.h:78
bool HeapTupleSatisfiesVisibility(HeapTuple tup, Snapshot snapshot, Buffer buffer)

◆ heap_getnext()

HeapTuple heap_getnext ( TableScanDesc  sscan,
ScanDirection  direction 
)

Definition at line 1316 of file heapam.c.

References bsysscan, CheckXidAlive, elog, ereport, errcode(), errmsg_internal(), ERROR, GetHeapamTableAmRoutine(), 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, TransactionIdIsValid, and unlikely.

Referenced by AlterTableMoveAll(), AlterTableSpaceOptions(), 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(), heapam_index_build_range_scan(), heapam_index_validate_scan(), index_update_stats(), objectsInSchemaToOids(), pgrowlocks(), pgstat_collect_oids(), pgstat_heap(), populate_typ_array(), ReindexMultipleTables(), remove_dbtablespaces(), RemoveSubscriptionRel(), RenameTableSpace(), ThereIsAtLeastOneRole(), and vac_truncate_clog().

1317 {
1318  HeapScanDesc scan = (HeapScanDesc) sscan;
1319 
1320  /*
1321  * This is still widely used directly, without going through table AM, so
1322  * add a safety check. It's possible we should, at a later point,
1323  * downgrade this to an assert. The reason for checking the AM routine,
1324  * rather than the AM oid, is that this allows to write regression tests
1325  * that create another AM reusing the heap handler.
1326  */
1328  ereport(ERROR,
1329  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1330  errmsg_internal("only heap AM is supported")));
1331 
1332  /*
1333  * We don't expect direct calls to heap_getnext with valid CheckXidAlive
1334  * for catalog or regular tables. See detailed comments in xact.c where
1335  * these variables are declared. Normally we have such a check at tableam
1336  * level API but this is called from many places so we need to ensure it
1337  * here.
1338  */
1340  elog(ERROR, "unexpected heap_getnext call during logical decoding");
1341 
1342  /* Note: no locking manipulations needed */
1343 
1344  if (scan->rs_base.rs_flags & SO_ALLOW_PAGEMODE)
1345  heapgettup_pagemode(scan, direction,
1346  scan->rs_base.rs_nkeys, scan->rs_base.rs_key);
1347  else
1348  heapgettup(scan, direction,
1349  scan->rs_base.rs_nkeys, scan->rs_base.rs_key);
1350 
1351  if (scan->rs_ctup.t_data == NULL)
1352  return NULL;
1353 
1354  /*
1355  * if we get here it means we have a new current scan tuple, so point to
1356  * the proper return buffer and return the tuple.
1357  */
1358 
1360 
1361  return &scan->rs_ctup;
1362 }
TableScanDescData rs_base
Definition: heapam.h:49
int errcode(int sqlerrcode)
Definition: elog.c:694
uint32 rs_flags
Definition: relscan.h:47
struct HeapScanDescData * HeapScanDesc
Definition: heapam.h:73
HeapTupleData rs_ctup
Definition: heapam.h:66
HeapTupleHeader t_data
Definition: htup.h:68
#define ERROR
Definition: elog.h:45
bool bsysscan
Definition: xact.c:96
struct ScanKeyData * rs_key
Definition: relscan.h:37
TransactionId CheckXidAlive
Definition: xact.c:95
const struct TableAmRoutine * rd_tableam
Definition: rel.h:172
static void heapgettup(HeapScanDesc scan, ScanDirection dir, int nkeys, ScanKey key)
Definition: heapam.c:506
#define ereport(elevel,...)
Definition: elog.h:155
int errmsg_internal(const char *fmt,...)
Definition: elog.c:992
Relation rs_rd
Definition: relscan.h:34
#define elog(elevel,...)
Definition: elog.h:227
#define unlikely(x)
Definition: c.h:273
#define pgstat_count_heap_getnext(rel)
Definition: pgstat.h:1533
#define TransactionIdIsValid(xid)
Definition: transam.h:41
static void heapgettup_pagemode(HeapScanDesc scan, ScanDirection dir, int nkeys, ScanKey key)
Definition: heapam.c:830
const TableAmRoutine * GetHeapamTableAmRoutine(void)

◆ heap_getnextslot()

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

Definition at line 1365 of file heapam.c.

References ExecClearTuple(), ExecStoreBufferHeapTuple(), 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().

1366 {
1367  HeapScanDesc scan = (HeapScanDesc) sscan;
1368 
1369  /* Note: no locking manipulations needed */
1370 
1371  if (sscan->rs_flags & SO_ALLOW_PAGEMODE)
1372  heapgettup_pagemode(scan, direction, sscan->rs_nkeys, sscan->rs_key);
1373  else
1374  heapgettup(scan, direction, sscan->rs_nkeys, sscan->rs_key);
1375 
1376  if (scan->rs_ctup.t_data == NULL)
1377  {
1378  ExecClearTuple(slot);
1379  return false;
1380  }
1381 
1382  /*
1383  * if we get here it means we have a new current scan tuple, so point to
1384  * the proper return buffer and return the tuple.
1385  */
1386 
1388 
1389  ExecStoreBufferHeapTuple(&scan->rs_ctup, slot,
1390  scan->rs_cbuf);
1391  return true;
1392 }
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:425
TableScanDescData rs_base
Definition: heapam.h:49
uint32 rs_flags
Definition: relscan.h:47
struct HeapScanDescData * HeapScanDesc
Definition: heapam.h:73
HeapTupleData rs_ctup
Definition: heapam.h:66
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:506
TupleTableSlot * ExecStoreBufferHeapTuple(HeapTuple tuple, TupleTableSlot *slot, Buffer buffer)
Definition: execTuples.c:1362
Buffer rs_cbuf
Definition: heapam.h:60
Relation rs_rd
Definition: relscan.h:34
#define pgstat_count_heap_getnext(rel)
Definition: pgstat.h:1533
static void heapgettup_pagemode(HeapScanDesc scan, ScanDirection dir, int nkeys, ScanKey key)
Definition: heapam.c:830

◆ heap_getnextslot_tidrange()

bool heap_getnextslot_tidrange ( TableScanDesc  sscan,
ScanDirection  direction,
TupleTableSlot slot 
)

Definition at line 1468 of file heapam.c.

References ExecClearTuple(), ExecStoreBufferHeapTuple(), heapgettup(), heapgettup_pagemode(), ItemPointerCompare(), pgstat_count_heap_getnext, HeapScanDescData::rs_base, HeapScanDescData::rs_cbuf, HeapScanDescData::rs_ctup, TableScanDescData::rs_flags, TableScanDescData::rs_key, TableScanDescData::rs_maxtid, TableScanDescData::rs_mintid, TableScanDescData::rs_nkeys, TableScanDescData::rs_rd, ScanDirectionIsBackward, ScanDirectionIsForward, SO_ALLOW_PAGEMODE, HeapTupleData::t_data, and HeapTupleData::t_self.

Referenced by SampleHeapTupleVisible().

1470 {
1471  HeapScanDesc scan = (HeapScanDesc) sscan;
1472  ItemPointer mintid = &sscan->rs_mintid;
1473  ItemPointer maxtid = &sscan->rs_maxtid;
1474 
1475  /* Note: no locking manipulations needed */
1476  for (;;)
1477  {
1478  if (sscan->rs_flags & SO_ALLOW_PAGEMODE)
1479  heapgettup_pagemode(scan, direction, sscan->rs_nkeys, sscan->rs_key);
1480  else
1481  heapgettup(scan, direction, sscan->rs_nkeys, sscan->rs_key);
1482 
1483  if (scan->rs_ctup.t_data == NULL)
1484  {
1485  ExecClearTuple(slot);
1486  return false;
1487  }
1488 
1489  /*
1490  * heap_set_tidrange will have used heap_setscanlimits to limit the
1491  * range of pages we scan to only ones that can contain the TID range
1492  * we're scanning for. Here we must filter out any tuples from these
1493  * pages that are outwith that range.
1494  */
1495  if (ItemPointerCompare(&scan->rs_ctup.t_self, mintid) < 0)
1496  {
1497  ExecClearTuple(slot);
1498 
1499  /*
1500  * When scanning backwards, the TIDs will be in descending order.
1501  * Future tuples in this direction will be lower still, so we can
1502  * just return false to indicate there will be no more tuples.
1503  */
1504  if (ScanDirectionIsBackward(direction))
1505  return false;
1506 
1507  continue;
1508  }
1509 
1510  /*
1511  * Likewise for the final page, we must filter out TIDs greater than
1512  * maxtid.
1513  */
1514  if (ItemPointerCompare(&scan->rs_ctup.t_self, maxtid) > 0)
1515  {
1516  ExecClearTuple(slot);
1517 
1518  /*
1519  * When scanning forward, the TIDs will be in ascending order.
1520  * Future tuples in this direction will be higher still, so we can
1521  * just return false to indicate there will be no more tuples.
1522  */
1523  if (ScanDirectionIsForward(direction))
1524  return false;
1525  continue;
1526  }
1527 
1528  break;
1529  }
1530 
1531  /*
1532  * if we get here it means we have a new current scan tuple, so point to
1533  * the proper return buffer and return the tuple.
1534  */
1536 
1537  ExecStoreBufferHeapTuple(&scan->rs_ctup, slot, scan->rs_cbuf);
1538  return true;
1539 }
int32 ItemPointerCompare(ItemPointer arg1, ItemPointer arg2)
Definition: itemptr.c:52
ItemPointerData rs_mintid
Definition: relscan.h:40
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:425
#define ScanDirectionIsForward(direction)
Definition: sdir.h:55
TableScanDescData rs_base
Definition: heapam.h:49
uint32 rs_flags
Definition: relscan.h:47
struct HeapScanDescData * HeapScanDesc
Definition: heapam.h:73
HeapTupleData rs_ctup
Definition: heapam.h:66
HeapTupleHeader t_data
Definition: htup.h:68
#define ScanDirectionIsBackward(direction)
Definition: sdir.h:41
ItemPointerData t_self
Definition: htup.h:65
struct ScanKeyData * rs_key
Definition: relscan.h:37
ItemPointerData rs_maxtid
Definition: relscan.h:41
static void heapgettup(HeapScanDesc scan, ScanDirection dir, int nkeys, ScanKey key)
Definition: heapam.c:506
TupleTableSlot * ExecStoreBufferHeapTuple(HeapTuple tuple, TupleTableSlot *slot, Buffer buffer)
Definition: execTuples.c:1362
Buffer rs_cbuf
Definition: heapam.h:60
Relation rs_rd
Definition: relscan.h:34
#define pgstat_count_heap_getnext(rel)
Definition: pgstat.h:1533
static void heapgettup_pagemode(HeapScanDesc scan, ScanDirection dir, int nkeys, ScanKey key)
Definition: heapam.c:830

◆ 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 1686 of file heapam.c.

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

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

1689 {
1690  Page dp = (Page) BufferGetPage(buffer);
1691  TransactionId prev_xmax = InvalidTransactionId;
1692  BlockNumber blkno;
1693  OffsetNumber offnum;
1694  bool at_chain_start;
1695  bool valid;
1696  bool skip;
1697  GlobalVisState *vistest = NULL;
1698 
1699  /* If this is not the first call, previous call returned a (live!) tuple */
1700  if (all_dead)
1701  *all_dead = first_call;
1702 
1703  blkno = ItemPointerGetBlockNumber(tid);
1704  offnum = ItemPointerGetOffsetNumber(tid);
1705  at_chain_start = first_call;
1706  skip = !first_call;
1707 
1708  /* XXX: we should assert that a snapshot is pushed or registered */
1710  Assert(BufferGetBlockNumber(buffer) == blkno);
1711 
1712  /* Scan through possible multiple members of HOT-chain */
1713  for (;;)
1714  {
1715  ItemId lp;
1716 
1717  /* check for bogus TID */
1718  if (offnum < FirstOffsetNumber || offnum > PageGetMaxOffsetNumber(dp))
1719  break;
1720 
1721  lp = PageGetItemId(dp, offnum);
1722 
1723  /* check for unused, dead, or redirected items */
1724  if (!ItemIdIsNormal(lp))
1725  {
1726  /* We should only see a redirect at start of chain */
1727  if (ItemIdIsRedirected(lp) && at_chain_start)
1728  {
1729  /* Follow the redirect */
1730  offnum = ItemIdGetRedirect(lp);
1731  at_chain_start = false;
1732  continue;
1733  }
1734  /* else must be end of chain */
1735  break;
1736  }
1737 
1738  /*
1739  * Update heapTuple to point to the element of the HOT chain we're
1740  * currently investigating. Having t_self set correctly is important
1741  * because the SSI checks and the *Satisfies routine for historical
1742  * MVCC snapshots need the correct tid to decide about the visibility.
1743  */
1744  heapTuple->t_data = (HeapTupleHeader) PageGetItem(dp, lp);
1745  heapTuple->t_len = ItemIdGetLength(lp);
1746  heapTuple->t_tableOid = RelationGetRelid(relation);
1747  ItemPointerSet(&heapTuple->t_self, blkno, offnum);
1748 
1749  /*
1750  * Shouldn't see a HEAP_ONLY tuple at chain start.
1751  */
1752  if (at_chain_start && HeapTupleIsHeapOnly(heapTuple))
1753  break;
1754 
1755  /*
1756  * The xmin should match the previous xmax value, else chain is
1757  * broken.
1758  */
1759  if (TransactionIdIsValid(prev_xmax) &&
1760  !TransactionIdEquals(prev_xmax,
1761  HeapTupleHeaderGetXmin(heapTuple->t_data)))
1762  break;
1763 
1764  /*
1765  * When first_call is true (and thus, skip is initially false) we'll
1766  * return the first tuple we find. But on later passes, heapTuple
1767  * will initially be pointing to the tuple we returned last time.
1768  * Returning it again would be incorrect (and would loop forever), so
1769  * we skip it and return the next match we find.
1770  */
1771  if (!skip)
1772  {
1773  /* If it's visible per the snapshot, we must return it */
1774  valid = HeapTupleSatisfiesVisibility(heapTuple, snapshot, buffer);
1775  HeapCheckForSerializableConflictOut(valid, relation, heapTuple,
1776  buffer, snapshot);
1777 
1778  if (valid)
1779  {
1780  ItemPointerSetOffsetNumber(tid, offnum);
1781  PredicateLockTID(relation, &heapTuple->t_self, snapshot,
1782  HeapTupleHeaderGetXmin(heapTuple->t_data));
1783  if (all_dead)
1784  *all_dead = false;
1785  return true;
1786  }
1787  }
1788  skip = false;
1789 
1790  /*
1791  * If we can't see it, maybe no one else can either. At caller
1792  * request, check whether all chain members are dead to all
1793  * transactions.
1794  *
1795  * Note: if you change the criterion here for what is "dead", fix the
1796  * planner's get_actual_variable_range() function to match.
1797  */
1798  if (all_dead && *all_dead)
1799  {
1800  if (!vistest)
1801  vistest = GlobalVisTestFor(relation);
1802 
1803  if (!HeapTupleIsSurelyDead(heapTuple, vistest))
1804  *all_dead = false;
1805  }
1806 
1807  /*
1808  * Check to see if HOT chain continues past this tuple; if so fetch
1809  * the next offnum and loop around.
1810  */
1811  if (HeapTupleIsHotUpdated(heapTuple))
1812  {
1814  blkno);
1815  offnum = ItemPointerGetOffsetNumber(&heapTuple->t_data->t_ctid);
1816  at_chain_start = false;
1817  prev_xmax = HeapTupleHeaderGetUpdateXid(heapTuple->t_data);
1818  }
1819  else
1820  break; /* end of chain */
1821  }
1822 
1823  return false;
1824 }
#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:587
HeapTupleHeaderData * HeapTupleHeader
Definition: htup.h:23
#define ItemIdGetRedirect(itemId)
Definition: itemid.h:78
static const struct exclude_list_item skip[]
Definition: pg_checksums.c:112
TransactionId RecentXmin
Definition: snapmgr.c:113
uint32 BlockNumber
Definition: block.h:31
#define PageGetMaxOffsetNumber(page)
Definition: bufpage.h:357
uint16 OffsetNumber
Definition: off.h:24
HeapTupleHeader t_data
Definition: htup.h:68
#define HeapTupleIsHotUpdated(tuple)
Definition: htup_details.h:676
GlobalVisState * GlobalVisTestFor(Relation rel)
Definition: procarray.c:3955
#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
#define InvalidTransactionId
Definition: transam.h:31
Oid t_tableOid
Definition: htup.h:66
#define BufferGetPage(buffer)
Definition: bufmgr.h:169
#define PageGetItemId(page, offsetNumber)
Definition: bufpage.h:235
void PredicateLockTID(Relation relation, ItemPointer tid, Snapshot snapshot, TransactionId tuple_xid)
Definition: predicate.c:2614
void HeapCheckForSerializableConflictOut(bool visible, Relation relation, HeapTuple tuple, Buffer buffer, Snapshot snapshot)
Definition: heapam.c:9846
#define HeapTupleIsHeapOnly(tuple)
Definition: htup_details.h:685
#define Assert(condition)
Definition: c.h:804
#define ItemIdIsNormal(itemId)
Definition: itemid.h:99
#define HeapTupleHeaderGetXmin(tup)
Definition: htup_details.h:313
#define ItemPointerGetOffsetNumber(pointer)
Definition: itemptr.h:117
#define ItemPointerSetOffsetNumber(pointer, offsetNumber)
Definition: itemptr.h:148
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:2674
bool HeapTupleIsSurelyDead(HeapTuple htup, GlobalVisState *vistest)
#define ItemPointerGetBlockNumber(pointer)
Definition: itemptr.h:98
#define TransactionIdIsValid(xid)
Definition: transam.h:41
#define RelationGetRelid(relation)
Definition: rel.h:457
#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_index_delete_tuples()

TransactionId heap_index_delete_tuples ( Relation  rel,
TM_IndexDeleteOp delstate 
)

Definition at line 7291 of file heapam.c.

References Assert, TM_IndexDeleteOp::bottomup, BOTTOMUP_MAX_NBLOCKS, bottomup_sort_and_shrink(), TM_IndexDeleteOp::bottomupfreespace, buf, BUFFER_LOCK_SHARE, BufferGetPage, BufferIsValid, TM_IndexDeleteOp::deltids, TM_IndexStatus::freespace, get_tablespace_maintenance_io_concurrency(), GlobalVisTestFor(), heap_hot_search_buffer(), HeapTupleHeaderAdvanceLatestRemovedXid(), HeapTupleHeaderGetUpdateXid, HeapTupleHeaderGetXmin, HeapTupleHeaderIsHotUpdated, i, TM_IndexDelete::id, index_delete_sort(), InitNonVacuumableSnapshot, InvalidBlockNumber, InvalidBuffer, InvalidOffsetNumber, InvalidTransactionId, IsCatalogRelation(), ItemIdGetRedirect, ItemIdIsNormal, ItemIdIsRedirected, ItemPointerGetBlockNumber, ItemPointerGetOffsetNumber, TM_IndexStatus::knowndeletable, LockBuffer(), maintenance_io_concurrency, Min, TM_IndexDeleteOp::ndeltids, PageGetItem, PageGetItemId, PageGetMaxOffsetNumber, TM_IndexStatus::promising, RelationData::rd_rel, ReadBuffer(), TM_IndexDeleteOp::status, HeapTupleHeaderData::t_ctid, TM_IndexDelete::tid, TransactionIdEquals, TransactionIdIsValid, and UnlockReleaseBuffer().

Referenced by SampleHeapTupleVisible().

7292 {
7293  /* Initial assumption is that earlier pruning took care of conflict */
7294  TransactionId latestRemovedXid = InvalidTransactionId;
7297  Page page = NULL;
7299  TransactionId priorXmax;
7300 #ifdef USE_PREFETCH
7301  IndexDeletePrefetchState prefetch_state;
7302  int prefetch_distance;
7303 #endif
7304  SnapshotData SnapshotNonVacuumable;
7305  int finalndeltids = 0,
7306  nblocksaccessed = 0;
7307 
7308  /* State that's only used in bottom-up index deletion case */
7309  int nblocksfavorable = 0;
7310  int curtargetfreespace = delstate->bottomupfreespace,
7311  lastfreespace = 0,
7312  actualfreespace = 0;
7313  bool bottomup_final_block = false;
7314 
7315  InitNonVacuumableSnapshot(SnapshotNonVacuumable, GlobalVisTestFor(rel));
7316 
7317  /* Sort caller's deltids array by TID for further processing */
7318  index_delete_sort(delstate);
7319 
7320  /*
7321  * Bottom-up case: resort deltids array in an order attuned to where the
7322  * greatest number of promising TIDs are to be found, and determine how
7323  * many blocks from the start of sorted array should be considered
7324  * favorable. This will also shrink the deltids array in order to
7325  * eliminate completely unfavorable blocks up front.
7326  */
7327  if (delstate->bottomup)
7328  nblocksfavorable = bottomup_sort_and_shrink(delstate);
7329 
7330 #ifdef USE_PREFETCH
7331  /* Initialize prefetch state. */
7332  prefetch_state.cur_hblkno = InvalidBlockNumber;
7333  prefetch_state.next_item = 0;
7334  prefetch_state.ndeltids = delstate->ndeltids;
7335  prefetch_state.deltids = delstate->deltids;
7336 
7337  /*
7338  * Determine the prefetch distance that we will attempt to maintain.
7339  *
7340  * Since the caller holds a buffer lock somewhere in rel, we'd better make
7341  * sure that isn't a catalog relation before we call code that does
7342  * syscache lookups, to avoid risk of deadlock.
7343  */
7344  if (IsCatalogRelation(rel))
7345  prefetch_distance = maintenance_io_concurrency;
7346  else
7347  prefetch_distance =
7349 
7350  /* Cap initial prefetch distance for bottom-up deletion caller */
7351  if (delstate->bottomup)
7352  {
7353  Assert(nblocksfavorable >= 1);
7354  Assert(nblocksfavorable <= BOTTOMUP_MAX_NBLOCKS);
7355  prefetch_distance = Min(prefetch_distance, nblocksfavorable);
7356  }
7357 
7358  /* Start prefetching. */
7359  index_delete_prefetch_buffer(rel, &prefetch_state, prefetch_distance);
7360 #endif
7361 
7362  /* Iterate over deltids, determine which to delete, check their horizon */
7363  Assert(delstate->ndeltids > 0);
7364  for (int i = 0; i < delstate->ndeltids; i++)
7365  {
7366  TM_IndexDelete *ideltid = &delstate->deltids[i];
7367  TM_IndexStatus *istatus = delstate->status + ideltid->id;
7368  ItemPointer htid = &ideltid->tid;
7369  OffsetNumber offnum;
7370 
7371  /*
7372  * Read buffer, and perform required extra steps each time a new block
7373  * is encountered. Avoid refetching if it's the same block as the one
7374  * from the last htid.
7375  */
7376  if (blkno == InvalidBlockNumber ||
7377  ItemPointerGetBlockNumber(htid) != blkno)
7378  {
7379  /*
7380  * Consider giving up early for bottom-up index deletion caller
7381  * first. (Only prefetch next-next block afterwards, when it
7382  * becomes clear that we're at least going to access the next
7383  * block in line.)
7384  *
7385  * Sometimes the first block frees so much space for bottom-up
7386  * caller that the deletion process can end without accessing any
7387  * more blocks. It is usually necessary to access 2 or 3 blocks
7388  * per bottom-up deletion operation, though.
7389  */
7390  if (delstate->bottomup)
7391  {
7392  /*
7393  * We often allow caller to delete a few additional items
7394  * whose entries we reached after the point that space target
7395  * from caller was satisfied. The cost of accessing the page
7396  * was already paid at that point, so it made sense to finish
7397  * it off. When that happened, we finalize everything here
7398  * (by finishing off the whole bottom-up deletion operation
7399  * without needlessly paying the cost of accessing any more
7400  * blocks).
7401  */
7402  if (bottomup_final_block)
7403  break;
7404 
7405  /*
7406  * Give up when we didn't enable our caller to free any
7407  * additional space as a result of processing the page that we
7408  * just finished up with. This rule is the main way in which
7409  * we keep the cost of bottom-up deletion under control.
7410  */
7411  if (nblocksaccessed >= 1 && actualfreespace == lastfreespace)
7412  break;
7413  lastfreespace = actualfreespace; /* for next time */
7414 
7415  /*
7416  * Deletion operation (which is bottom-up) will definitely
7417  * access the next block in line. Prepare for that now.
7418  *
7419  * Decay target free space so that we don't hang on for too
7420  * long with a marginal case. (Space target is only truly
7421  * helpful when it allows us to recognize that we don't need
7422  * to access more than 1 or 2 blocks to satisfy caller due to
7423  * agreeable workload characteristics.)
7424  *
7425  * We are a bit more patient when we encounter contiguous
7426  * blocks, though: these are treated as favorable blocks. The
7427  * decay process is only applied when the next block in line
7428  * is not a favorable/contiguous block. This is not an
7429  * exception to the general rule; we still insist on finding
7430  * at least one deletable item per block accessed. See
7431  * bottomup_nblocksfavorable() for full details of the theory
7432  * behind favorable blocks and heap block locality in general.
7433  *
7434  * Note: The first block in line is always treated as a
7435  * favorable block, so the earliest possible point that the
7436  * decay can be applied is just before we access the second
7437  * block in line. The Assert() verifies this for us.
7438  */
7439  Assert(nblocksaccessed > 0 || nblocksfavorable > 0);
7440  if (nblocksfavorable > 0)
7441  nblocksfavorable--;
7442  else
7443  curtargetfreespace /= 2;
7444  }
7445 
7446  /* release old buffer */
7447  if (BufferIsValid(buf))
7448  UnlockReleaseBuffer(buf);
7449 
7450  blkno = ItemPointerGetBlockNumber(htid);
7451  buf = ReadBuffer(rel, blkno);
7452  nblocksaccessed++;
7453  Assert(!delstate->bottomup ||
7454  nblocksaccessed <= BOTTOMUP_MAX_NBLOCKS);
7455 
7456 #ifdef USE_PREFETCH
7457 
7458  /*
7459  * To maintain the prefetch distance, prefetch one more page for
7460  * each page we read.
7461  */
7462  index_delete_prefetch_buffer(rel, &prefetch_state, 1);
7463 #endif
7464 
7466 
7467  page = BufferGetPage(buf);
7468  maxoff = PageGetMaxOffsetNumber(page);
7469  }
7470 
7471  if (istatus->knowndeletable)
7472  Assert(!delstate->bottomup && !istatus->promising);
7473  else
7474  {
7475  ItemPointerData tmp = *htid;
7476  HeapTupleData heapTuple;
7477 
7478  /* Are any tuples from this HOT chain non-vacuumable? */
7479  if (heap_hot_search_buffer(&tmp, rel, buf, &SnapshotNonVacuumable,
7480  &heapTuple, NULL, true))
7481  continue; /* can't delete entry */
7482 
7483  /* Caller will delete, since whole HOT chain is vacuumable */
7484  istatus->knowndeletable = true;
7485 
7486  /* Maintain index free space info for bottom-up deletion case */
7487  if (delstate->bottomup)
7488  {
7489  Assert(istatus->freespace > 0);
7490  actualfreespace += istatus->freespace;
7491  if (actualfreespace >= curtargetfreespace)
7492  bottomup_final_block = true;
7493  }
7494  }
7495 
7496  /*
7497  * Maintain latestRemovedXid value for deletion operation as a whole
7498  * by advancing current value using heap tuple headers. This is
7499  * loosely based on the logic for pruning a HOT chain.
7500  */
7501  offnum = ItemPointerGetOffsetNumber(htid);
7502  priorXmax = InvalidTransactionId; /* cannot check first XMIN */
7503  for (;;)
7504  {
7505  ItemId lp;
7506  HeapTupleHeader htup;
7507 
7508  /* Some sanity checks */
7509  if (offnum < FirstOffsetNumber || offnum > maxoff)
7510  {
7511  Assert(false);
7512  break;
7513  }
7514 
7515  lp = PageGetItemId(page, offnum);
7516  if (ItemIdIsRedirected(lp))
7517  {
7518  offnum = ItemIdGetRedirect(lp);
7519  continue;
7520  }
7521 
7522  /*
7523  * We'll often encounter LP_DEAD line pointers (especially with an
7524  * entry marked knowndeletable by our caller up front). No heap
7525  * tuple headers get examined for an htid that leads us to an
7526  * LP_DEAD item. This is okay because the earlier pruning
7527  * operation that made the line pointer LP_DEAD in the first place
7528  * must have considered the original tuple header as part of
7529  * generating its own latestRemovedXid value.
7530  *
7531  * Relying on XLOG_HEAP2_CLEAN records like this is the same
7532  * strategy that index vacuuming uses in all cases. Index VACUUM
7533  * WAL records don't even have a latestRemovedXid field of their
7534  * own for this reason.
7535  */
7536  if (!ItemIdIsNormal(lp))
7537  break;
7538 
7539  htup = (HeapTupleHeader) PageGetItem(page, lp);
7540 
7541  /*
7542  * Check the tuple XMIN against prior XMAX, if any
7543  */
7544  if (TransactionIdIsValid(priorXmax) &&
7545  !TransactionIdEquals(HeapTupleHeaderGetXmin(htup), priorXmax))
7546  break;
7547 
7548  HeapTupleHeaderAdvanceLatestRemovedXid(htup, &latestRemovedXid);
7549 
7550  /*
7551  * If the tuple is not HOT-updated, then we are at the end of this
7552  * HOT-chain. No need to visit later tuples from the same update
7553  * chain (they get their own index entries) -- just move on to
7554  * next htid from index AM caller.
7555  */
7556  if (!HeapTupleHeaderIsHotUpdated(htup))
7557  break;
7558 
7559  /* Advance to next HOT chain member */
7560  Assert(ItemPointerGetBlockNumber(&htup->t_ctid) == blkno);
7561  offnum = ItemPointerGetOffsetNumber(&htup->t_ctid);
7562  priorXmax = HeapTupleHeaderGetUpdateXid(htup);
7563  }
7564 
7565  /* Enable further/final shrinking of deltids for caller */
7566  finalndeltids = i + 1;
7567  }
7568 
7569  UnlockReleaseBuffer(buf);
7570 
7571  /*
7572  * Shrink deltids array to exclude non-deletable entries at the end. This
7573  * is not just a minor optimization. Final deltids array size might be
7574  * zero for a bottom-up caller. Index AM is explicitly allowed to rely on
7575  * ndeltids being zero in all cases with zero total deletable entries.
7576  */
7577  Assert(finalndeltids > 0 || delstate->bottomup);
7578  delstate->ndeltids = finalndeltids;
7579 
7580  return latestRemovedXid;
7581 }
#define HeapTupleHeaderGetUpdateXid(tup)
Definition: htup_details.h:365
void HeapTupleHeaderAdvanceLatestRemovedXid(HeapTupleHeader tuple, TransactionId *latestRemovedXid)
Definition: heapam.c:7201
TM_IndexDelete * deltids
Definition: tableam.h:228
bool IsCatalogRelation(Relation relation)
Definition: catalog.c:96
int maintenance_io_concurrency
Definition: bufmgr.c:150
#define ItemIdIsRedirected(itemId)
Definition: itemid.h:106
#define TransactionIdEquals(id1, id2)
Definition: transam.h:43
uint32 TransactionId
Definition: c.h:587
static int bottomup_sort_and_shrink(TM_IndexDeleteOp *delstate)
Definition: heapam.c:7836
HeapTupleHeaderData * HeapTupleHeader
Definition: htup.h:23
#define ItemIdGetRedirect(itemId)
Definition: itemid.h:78
#define Min(x, y)
Definition: c.h:986
#define InvalidBuffer
Definition: buf.h:25
bool knowndeletable
Definition: tableam.h:196
#define InitNonVacuumableSnapshot(snapshotdata, vistestp)
Definition: snapmgr.h:83
uint32 BlockNumber
Definition: block.h:31
Form_pg_class rd_rel
Definition: rel.h:110
#define PageGetMaxOffsetNumber(page)
Definition: bufpage.h:357
uint16 OffsetNumber
Definition: off.h:24
bool heap_hot_search_buffer(ItemPointer tid, Relation relation, Buffer buffer, Snapshot snapshot, HeapTuple heapTuple, bool *all_dead, bool first_call)
Definition: heapam.c:1686
GlobalVisState * GlobalVisTestFor(Relation rel)
Definition: procarray.c:3955
int get_tablespace_maintenance_io_concurrency(Oid spcid)
Definition: spccache.c:228
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3723
ItemPointerData t_ctid
Definition: htup_details.h:160
static char * buf
Definition: pg_test_fsync.c:68
#define BOTTOMUP_MAX_NBLOCKS
Definition: heapam.c:185
#define InvalidTransactionId
Definition: transam.h:31
#define BufferGetPage(buffer)
Definition: bufmgr.h:169
bool promising
Definition: tableam.h:199
#define HeapTupleHeaderIsHotUpdated(tup)
Definition: htup_details.h:484
#define PageGetItemId(page, offsetNumber)
Definition: bufpage.h:235
TM_IndexStatus * status
Definition: tableam.h:229
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3939
ItemPointerData tid
Definition: tableam.h:189
#define InvalidOffsetNumber
Definition: off.h:26
static void index_delete_sort(TM_IndexDeleteOp *delstate)
Definition: heapam.c:7623
#define Assert(condition)
Definition: c.h:804
#define ItemIdIsNormal(itemId)
Definition: itemid.h:99
#define HeapTupleHeaderGetXmin(tup)
Definition: htup_details.h:313
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition: bufmgr.c:619
#define InvalidBlockNumber
Definition: block.h:33
#define BufferIsValid(bufnum)
Definition: bufmgr.h:123
#define ItemPointerGetOffsetNumber(pointer)
Definition: itemptr.h:117
int16 freespace
Definition: tableam.h:200
int i
#define BUFFER_LOCK_SHARE
Definition: bufmgr.h:97
int bottomupfreespace
Definition: tableam.h:224
#define ItemPointerGetBlockNumber(pointer)
Definition: itemptr.h:98
#define TransactionIdIsValid(xid)
Definition: transam.h:41
int Buffer
Definition: buf.h:23
#define PageGetItem(page, itemId)
Definition: bufpage.h:340
Pointer Page
Definition: bufpage.h:78

◆ heap_inplace_update()

void heap_inplace_update ( Relation  relation,
HeapTuple  tuple 
)

Definition at line 6013 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_update_stats(), vac_update_datfrozenxid(), and vac_update_relstats().

6014 {
6015  Buffer buffer;
6016  Page page;
6017  OffsetNumber offnum;
6018  ItemId lp = NULL;
6019  HeapTupleHeader htup;
6020  uint32 oldlen;
6021  uint32 newlen;
6022 
6023  /*
6024  * For now, we don't allow parallel updates. Unlike a regular update,
6025  * this should never create a combo CID, so it might be possible to relax
6026  * this restriction, but not without more thought and testing. It's not
6027  * clear that it would be useful, anyway.
6028  */
6029  if (IsInParallelMode())
6030  ereport(ERROR,
6031  (errcode(ERRCODE_INVALID_TRANSACTION_STATE),
6032  errmsg("cannot update tuples during a parallel operation")));
6033 
6034  buffer = ReadBuffer(relation, ItemPointerGetBlockNumber(&(tuple->t_self)));
6036  page = (Page) BufferGetPage(buffer);
6037 
6038  offnum = ItemPointerGetOffsetNumber(&(tuple->t_self));
6039  if (PageGetMaxOffsetNumber(page) >= offnum)
6040  lp = PageGetItemId(page, offnum);
6041 
6042  if (PageGetMaxOffsetNumber(page) < offnum || !ItemIdIsNormal(lp))
6043  elog(ERROR, "invalid lp");
6044 
6045  htup = (HeapTupleHeader) PageGetItem(page, lp);
6046 
6047  oldlen = ItemIdGetLength(lp) - htup->t_hoff;
6048  newlen = tuple->t_len - tuple->t_data->t_hoff;
6049  if (oldlen != newlen || htup->t_hoff != tuple->t_data->t_hoff)
6050  elog(ERROR, "wrong tuple length");
6051 
6052  /* NO EREPORT(ERROR) from here till changes are logged */
6054 
6055  memcpy((char *) htup + htup->t_hoff,
6056  (char *) tuple->t_data + tuple->t_data->t_hoff,
6057  newlen);
6058 
6059  MarkBufferDirty(buffer);
6060 
6061  /* XLOG stuff */
6062  if (RelationNeedsWAL(relation))
6063  {
6064  xl_heap_inplace xlrec;
6065  XLogRecPtr recptr;
6066 
6067  xlrec.offnum = ItemPointerGetOffsetNumber(&tuple->t_self);
6068 
6069  XLogBeginInsert();
6070  XLogRegisterData((char *) &xlrec, SizeOfHeapInplace);
6071 
6072  XLogRegisterBuffer(0, buffer, REGBUF_STANDARD);
6073  XLogRegisterBufData(0, (char *) htup + htup->t_hoff, newlen);
6074 
6075  /* inplace updates aren't decoded atm, don't log the origin */
6076 
6077  recptr = XLogInsert(RM_HEAP_ID, XLOG_HEAP_INPLACE);
6078 
6079  PageSetLSN(page, recptr);
6080  }
6081 
6082  END_CRIT_SECTION();
6083 
6084  UnlockReleaseBuffer(buffer);
6085 
6086  /*
6087  * Send out shared cache inval if necessary. Note that because we only
6088  * pass the new version of the tuple, this mustn't be used for any
6089  * operations that could change catcache lookup keys. But we aren't
6090  * bothering with index updates either, so that's true a fortiori.
6091  */
6093  CacheInvalidateHeapTuple(relation, tuple, NULL);
6094 }
void XLogRegisterBufData(uint8 block_id, char *data, int len)
Definition: xloginsert.c:368
void CacheInvalidateHeapTuple(Relation relation, HeapTuple tuple, HeapTuple newtuple)
Definition: inval.c:1122
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:1483
void XLogRegisterBuffer(uint8 block_id, Buffer buffer, uint8 flags)
Definition: xloginsert.c:220
HeapTupleHeaderData * HeapTupleHeader
Definition: htup.h:23
#define END_CRIT_SECTION()
Definition: miscadmin.h:135
#define SizeOfHeapInplace
Definition: heapam_xlog.h:310
#define START_CRIT_SECTION()
Definition: miscadmin.h:133
int errcode(int sqlerrcode)
Definition: elog.c:694
#define BUFFER_LOCK_EXCLUSIVE
Definition: bufmgr.h:98
#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:1012
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3723
#define ERROR
Definition: elog.h:45
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:441
#define BufferGetPage(buffer)
Definition: bufmgr.h:169
#define PageGetItemId(page, offsetNumber)
Definition: bufpage.h:235
void XLogRegisterData(char *data, int len)
Definition: xloginsert.c:330
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:422
OffsetNumber offnum
Definition: heapam_xlog.h:306
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3939
#define ereport(elevel,...)
Definition: elog.h:155
uint64 XLogRecPtr
Definition: xlogdefs.h:21
#define ItemIdIsNormal(itemId)
Definition: itemid.h:99
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition: bufmgr.c:619
#define ItemPointerGetOffsetNumber(pointer)
Definition: itemptr.h:117
#define XLOG_HEAP_INPLACE
Definition: heapam_xlog.h:39
#define RelationNeedsWAL(relation)
Definition: rel.h:563
#define IsBootstrapProcessingMode()
Definition: miscadmin.h:394
int errmsg(const char *fmt,...)
Definition: elog.c:905
#define elog(elevel,...)
Definition: elog.h:227
#define ItemPointerGetBlockNumber(pointer)
Definition: itemptr.h:98
void XLogBeginInsert(void)
Definition: xloginsert.c:123
#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 2036 of file heapam.c.

References Assert, BufferGetBlockNumber(), BufferGetPage, CacheInvalidateHeapTuple(), CheckForSerializableConflictIn(), END_CRIT_SECTION, FirstOffsetNumber, xl_heap_insert::flags, GetCurrentTransactionId(), heap_freetuple(), HEAP_INSERT_FROZEN, HEAP_INSERT_NO_LOGICAL, HEAP_INSERT_SPECULATIVE, heap_prepare_insert(), InvalidBlockNumber, InvalidBuffer, InvalidTransactionId, InvalidXLogRecPtr, IsToastRelation(), ItemPointerGetBlockNumber, ItemPointerGetOffsetNumber, log_heap_new_cid(), MarkBufferDirty(), xl_heap_insert::offnum, PageClearAllVisible, PageGetMaxOffsetNumber, PageIsAllVisible, PageSetAllVisible, 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_ALL_FROZEN, VISIBILITYMAP_ALL_VISIBLE, visibilitymap_clear(), visibilitymap_get_status(), visibilitymap_pin_ok(), visibilitymap_set(), VISIBILITYMAP_VALID_BITS, XLH_INSERT_ALL_FROZEN_SET, XLH_INSERT_ALL_VISIBLE_CLEARED, XLH_INSERT_CONTAINS_NEW_TUPLE, XLH_INSERT_IS_SPECULATIVE, XLH_INSERT_ON_TOAST_RELATION, 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().

2038 {
2040  HeapTuple heaptup;
2041  Buffer buffer;
2042  Page page = NULL;
2043  Buffer vmbuffer = InvalidBuffer;
2044  bool starting_with_empty_page;
2045  bool all_visible_cleared = false;
2046  bool all_frozen_set = false;
2047  uint8 vmstatus = 0;
2048 
2049  /*
2050  * Fill in tuple header fields and toast the tuple if necessary.
2051  *
2052  * Note: below this point, heaptup is the data we actually intend to store
2053  * into the relation; tup is the caller's original untoasted data.
2054  */
2055  heaptup = heap_prepare_insert(relation, tup, xid, cid, options);
2056 
2057  /*
2058  * Find buffer to insert this tuple into. If the page is all visible,
2059  * this will also pin the requisite visibility map page.
2060  *
2061  * Also pin visibility map page if COPY FREEZE inserts tuples into an
2062  * empty page. See all_frozen_set below.
2063  */
2064  buffer = RelationGetBufferForTuple(relation, heaptup->t_len,
2065  InvalidBuffer, options, bistate,
2066  &vmbuffer, NULL);
2067 
2068 
2069  /*
2070  * If we're inserting frozen entry into an empty page,
2071  * set visibility map bits and PageAllVisible() hint.
2072  *
2073  * If we're inserting frozen entry into already all_frozen page,
2074  * preserve this state.
2075  */
2077  {
2078  page = BufferGetPage(buffer);
2079 
2080  starting_with_empty_page = PageGetMaxOffsetNumber(page) == 0;
2081 
2082  if (visibilitymap_pin_ok(BufferGetBlockNumber(buffer), vmbuffer))
2083  vmstatus = visibilitymap_get_status(relation,
2084  BufferGetBlockNumber(buffer), &vmbuffer);
2085 
2086  if ((starting_with_empty_page || vmstatus & VISIBILITYMAP_ALL_FROZEN))
2087  all_frozen_set = true;
2088  }
2089 
2090  /*
2091  * We're about to do the actual insert -- but check for conflict first, to
2092  * avoid possibly having to roll back work we've just done.
2093  *
2094  * This is safe without a recheck as long as there is no possibility of
2095  * another process scanning the page between this check and the insert
2096  * being visible to the scan (i.e., an exclusive buffer content lock is
2097  * continuously held from this point until the tuple insert is visible).
2098  *
2099  * For a heap insert, we only need to check for table-level SSI locks. Our
2100  * new tuple can't possibly conflict with existing tuple locks, and heap
2101  * page locks are only consolidated versions of tuple locks; they do not
2102  * lock "gaps" as index page locks do. So we don't need to specify a
2103  * buffer when making the call, which makes for a faster check.
2104  */
2106 
2107  /* NO EREPORT(ERROR) from here till changes are logged */
2109 
2110  RelationPutHeapTuple(relation, buffer, heaptup,
2111  (options & HEAP_INSERT_SPECULATIVE) != 0);
2112 
2113  /*
2114  * If the page is all visible, need to clear that, unless we're only
2115  * going to add further frozen rows to it.
2116  *
2117  * If we're only adding already frozen rows to a page that was empty or
2118  * marked as all visible, mark it as all-visible.
2119  */
2120  if (PageIsAllVisible(BufferGetPage(buffer)) && !(options & HEAP_INSERT_FROZEN))
2121  {
2122  all_visible_cleared = true;
2124  visibilitymap_clear(relation,
2125  ItemPointerGetBlockNumber(&(heaptup->t_self)),
2126  vmbuffer, VISIBILITYMAP_VALID_BITS);
2127  }
2128  else if (all_frozen_set)
2129  {
2130  /* We only ever set all_frozen_set after reading the page. */
2131  Assert(page);
2132 
2133  PageSetAllVisible(page);
2134  }
2135 
2136  /*
2137  * XXX Should we set PageSetPrunable on this page ?
2138  *
2139  * The inserting transaction may eventually abort thus making this tuple
2140  * DEAD and hence available for pruning. Though we don't want to optimize
2141  * for aborts, if no other tuple in this page is UPDATEd/DELETEd, the
2142  * aborted tuple will never be pruned until next vacuum is triggered.
2143  *
2144  * If you do add PageSetPrunable here, add it in heap_xlog_insert too.
2145  */
2146 
2147  MarkBufferDirty(buffer);
2148 
2149  /* XLOG stuff */
2150  if (RelationNeedsWAL(relation))
2151  {
2152  xl_heap_insert xlrec;
2153  xl_heap_header xlhdr;
2154  XLogRecPtr recptr;
2155  Page page = BufferGetPage(buffer);
2156  uint8 info = XLOG_HEAP_INSERT;
2157  int bufflags = 0;
2158 
2159  /*
2160  * If this is a catalog, we need to transmit combocids to properly
2161  * decode, so log that as well.
2162  */
2164  log_heap_new_cid(relation, heaptup);
2165 
2166  /*
2167  * If this is the single and first tuple on page, we can reinit the
2168  * page instead of restoring the whole thing. Set flag, and hide
2169  * buffer references from XLogInsert.
2170  */
2171  if (ItemPointerGetOffsetNumber(&(heaptup->t_self)) == FirstOffsetNumber &&
2173  {
2174  info |= XLOG_HEAP_INIT_PAGE;
2175  bufflags |= REGBUF_WILL_INIT;
2176  }
2177 
2178  xlrec.offnum = ItemPointerGetOffsetNumber(&heaptup->t_self);
2179  xlrec.flags = 0;
2180  if (all_visible_cleared)
2182  if (all_frozen_set)
2187 
2188  /*
2189  * For logical decoding, we need the tuple even if we're doing a full
2190  * page write, so make sure it's included even if we take a full-page
2191  * image. (XXX We could alternatively store a pointer into the FPW).
2192  */
2193  if (RelationIsLogicallyLogged(relation) &&
2195  {
2197  bufflags |= REGBUF_KEEP_DATA;
2198 
2199  if (IsToastRelation(relation))
2201  }
2202 
2203  XLogBeginInsert();
2204  XLogRegisterData((char *) &xlrec, SizeOfHeapInsert);
2205 
2206  xlhdr.t_infomask2 = heaptup->t_data->t_infomask2;
2207  xlhdr.t_infomask = heaptup->t_data->t_infomask;
2208  xlhdr.t_hoff = heaptup->t_data->t_hoff;
2209 
2210  /*
2211  * note we mark xlhdr as belonging to buffer; if XLogInsert decides to
2212  * write the whole page to the xlog, we don't need to store
2213  * xl_heap_header in the xlog.
2214  */
2215  XLogRegisterBuffer(0, buffer, REGBUF_STANDARD | bufflags);
2216  XLogRegisterBufData(0, (char *) &xlhdr, SizeOfHeapHeader);
2217  /* PG73FORMAT: write bitmap [+ padding] [+ oid] + data */
2219  (char *) heaptup->t_data + SizeofHeapTupleHeader,
2220  heaptup->t_len - SizeofHeapTupleHeader);
2221 
2222  /* filtering by origin on a row level is much more efficient */
2224 
2225  recptr = XLogInsert(RM_HEAP_ID, info);
2226 
2227  PageSetLSN(page, recptr);
2228  }
2229 
2230  END_CRIT_SECTION();
2231 
2232  /*
2233  * If we've frozen everything on the page, update the visibilitymap.
2234  * We're already holding pin on the vmbuffer.
2235  *
2236  * No need to update the visibilitymap if it had all_frozen bit set
2237  * before this insertion.
2238  */
2239  if (all_frozen_set && ((vmstatus & VISIBILITYMAP_ALL_FROZEN) == 0))
2240  {
2241  Assert(PageIsAllVisible(page));