PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
heapam.c File Reference
#include "postgres.h"
#include "access/bufmask.h"
#include "access/heapam.h"
#include "access/heapam_xlog.h"
#include "access/hio.h"
#include "access/multixact.h"
#include "access/parallel.h"
#include "access/relscan.h"
#include "access/sysattr.h"
#include "access/transam.h"
#include "access/tuptoaster.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 "catalog/namespace.h"
#include "miscadmin.h"
#include "pgstat.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/syscache.h"
#include "utils/tqual.h"
Include dependency graph for heapam.c:

Go to the source code of this file.

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 TUPLOCK_from_mxstatus(status)   (MultiXactStatusLock[(status)])
 
#define HEAPDEBUG_1
 
#define HEAPDEBUG_2
 
#define HEAPDEBUG_3
 
#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
 

Functions

static HeapScanDesc heap_beginscan_internal (Relation relation, Snapshot snapshot, int nkeys, ScanKey key, ParallelHeapScanDesc parallel_scan, bool allow_strat, bool allow_sync, bool allow_pagemode, bool is_bitmapscan, bool is_samplescan, bool temp_snap)
 
static BlockNumber heap_parallelscan_nextpage (HeapScanDesc scan)
 
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_tup, 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 HTSU_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)
 
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 XLogRecPtr log_heap_new_cid (Relation relation, HeapTuple tup)
 
static HeapTuple ExtractReplicaIdentity (Relation rel, HeapTuple tup, bool key_modified, bool *copy)
 
static void initscan (HeapScanDesc scan, ScanKey key, bool keep_startblock)
 
void heap_setscanlimits (HeapScanDesc scan, BlockNumber startBlk, BlockNumber numBlks)
 
void heapgetpage (HeapScanDesc scan, 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)
 
Relation relation_open (Oid relationId, LOCKMODE lockmode)
 
Relation try_relation_open (Oid relationId, LOCKMODE lockmode)
 
Relation relation_openrv (const RangeVar *relation, LOCKMODE lockmode)
 
Relation relation_openrv_extended (const RangeVar *relation, LOCKMODE lockmode, bool missing_ok)
 
void relation_close (Relation relation, LOCKMODE lockmode)
 
Relation heap_open (Oid relationId, LOCKMODE lockmode)
 
Relation heap_openrv (const RangeVar *relation, LOCKMODE lockmode)
 
Relation heap_openrv_extended (const RangeVar *relation, LOCKMODE lockmode, bool missing_ok)
 
HeapScanDesc heap_beginscan (Relation relation, Snapshot snapshot, int nkeys, ScanKey key)
 
HeapScanDesc heap_beginscan_catalog (Relation relation, int nkeys, ScanKey key)
 
HeapScanDesc heap_beginscan_strat (Relation relation, Snapshot snapshot, int nkeys, ScanKey key, bool allow_strat, bool allow_sync)
 
HeapScanDesc heap_beginscan_bm (Relation relation, Snapshot snapshot, int nkeys, ScanKey key)
 
HeapScanDesc heap_beginscan_sampling (Relation relation, Snapshot snapshot, int nkeys, ScanKey key, bool allow_strat, bool allow_sync, bool allow_pagemode)
 
void heap_rescan (HeapScanDesc scan, ScanKey key)
 
void heap_rescan_set_params (HeapScanDesc scan, ScanKey key, bool allow_strat, bool allow_sync, bool allow_pagemode)
 
void heap_endscan (HeapScanDesc scan)
 
Size heap_parallelscan_estimate (Snapshot snapshot)
 
void heap_parallelscan_initialize (ParallelHeapScanDesc target, Relation relation, Snapshot snapshot)
 
HeapScanDesc heap_beginscan_parallel (Relation relation, ParallelHeapScanDesc parallel_scan)
 
void heap_update_snapshot (HeapScanDesc scan, Snapshot snapshot)
 
HeapTuple heap_getnext (HeapScanDesc scan, ScanDirection direction)
 
bool heap_fetch (Relation relation, Snapshot snapshot, HeapTuple tuple, Buffer *userbuf, bool keep_buf, Relation stats_relation)
 
bool heap_hot_search_buffer (ItemPointer tid, Relation relation, Buffer buffer, Snapshot snapshot, HeapTuple heapTuple, bool *all_dead, bool first_call)
 
bool heap_hot_search (ItemPointer tid, Relation relation, Snapshot snapshot, bool *all_dead)
 
void heap_get_latest_tid (Relation relation, Snapshot snapshot, ItemPointer tid)
 
static void UpdateXmaxHintBits (HeapTupleHeader tuple, Buffer buffer, TransactionId xid)
 
BulkInsertState GetBulkInsertState (void)
 
void FreeBulkInsertState (BulkInsertState bistate)
 
void ReleaseBulkInsertStatePin (BulkInsertState bistate)
 
Oid heap_insert (Relation relation, HeapTuple tup, CommandId cid, int options, BulkInsertState bistate)
 
void heap_multi_insert (Relation relation, HeapTuple *tuples, int ntuples, CommandId cid, int options, BulkInsertState bistate)
 
Oid 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)
 
HTSU_Result heap_delete (Relation relation, ItemPointer tid, CommandId cid, Snapshot crosscheck, bool wait, HeapUpdateFailureData *hufd)
 
void simple_heap_delete (Relation relation, ItemPointer tid)
 
HTSU_Result heap_update (Relation relation, ItemPointer otid, HeapTuple newtup, CommandId cid, Snapshot crosscheck, bool wait, HeapUpdateFailureData *hufd, 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)
 
HTSU_Result heap_lock_tuple (Relation relation, HeapTuple tuple, CommandId cid, LockTupleMode mode, LockWaitPolicy wait_policy, bool follow_updates, Buffer *buffer, HeapUpdateFailureData *hufd)
 
static HTSU_Result test_lockmode_for_conflict (MultiXactStatus status, TransactionId xid, LockTupleMode mode, bool *needwait)
 
static HTSU_Result heap_lock_updated_tuple_rec (Relation rel, ItemPointer tid, TransactionId xid, LockTupleMode mode)
 
void heap_finish_speculative (Relation relation, HeapTuple tuple)
 
void heap_abort_speculative (Relation relation, HeapTuple tuple)
 
void heap_inplace_update (Relation relation, HeapTuple tuple)
 
static TransactionId FreezeMultiXactId (MultiXactId multi, uint16 t_infomask, TransactionId cutoff_xid, MultiXactId cutoff_multi, uint16 *flags)
 
bool heap_prepare_freeze_tuple (HeapTupleHeader tuple, 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 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)
 
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_sync (Relation rel)
 
void heap_mask (char *pagedata, BlockNumber blkno)
 

Variables

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

Macro Definition Documentation

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

Definition at line 183 of file heapam.c.

Referenced by heap_acquire_tuplock().

#define FRM_INVALIDATE_XMAX   0x0002

Definition at line 6279 of file heapam.c.

Referenced by FreezeMultiXactId(), and heap_prepare_freeze_tuple().

#define FRM_MARK_COMMITTED   0x0010

Definition at line 6282 of file heapam.c.

Referenced by FreezeMultiXactId(), and heap_prepare_freeze_tuple().

#define FRM_NOOP   0x0001

Definition at line 6278 of file heapam.c.

Referenced by FreezeMultiXactId(), and heap_prepare_freeze_tuple().

#define FRM_RETURN_IS_MULTI   0x0008

Definition at line 6281 of file heapam.c.

Referenced by FreezeMultiXactId(), and heap_prepare_freeze_tuple().

#define FRM_RETURN_IS_XID   0x0004

Definition at line 6280 of file heapam.c.

Referenced by FreezeMultiXactId(), and heap_prepare_freeze_tuple().

#define HEAPDEBUG_1

Definition at line 1787 of file heapam.c.

Referenced by heap_getnext().

#define HEAPDEBUG_2

Definition at line 1788 of file heapam.c.

Referenced by heap_getnext().

#define HEAPDEBUG_3

Definition at line 1789 of file heapam.c.

Referenced by heap_getnext().

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

Definition at line 179 of file heapam.c.

Referenced by heap_acquire_tuplock().

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

Definition at line 201 of file heapam.c.

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

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

Definition at line 181 of file heapam.c.

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

Function Documentation

static uint8 compute_infobits ( uint16  infomask,
uint16  infomask2 
)
static

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

2953 {
2954  return
2955  ((infomask & HEAP_XMAX_IS_MULTI) != 0 ? XLHL_XMAX_IS_MULTI : 0) |
2956  ((infomask & HEAP_XMAX_LOCK_ONLY) != 0 ? XLHL_XMAX_LOCK_ONLY : 0) |
2957  ((infomask & HEAP_XMAX_EXCL_LOCK) != 0 ? XLHL_XMAX_EXCL_LOCK : 0) |
2958  /* note we ignore HEAP_XMAX_SHR_LOCK here */
2959  ((infomask & HEAP_XMAX_KEYSHR_LOCK) != 0 ? XLHL_XMAX_KEYSHR_LOCK : 0) |
2960  ((infomask2 & HEAP_KEYS_UPDATED) != 0 ?
2961  XLHL_KEYS_UPDATED : 0);
2962 }
#define HEAP_XMAX_KEYSHR_LOCK
Definition: htup_details.h:179
#define HEAP_XMAX_LOCK_ONLY
Definition: htup_details.h:182
#define XLHL_XMAX_LOCK_ONLY
Definition: heapam_xlog.h:241
#define XLHL_XMAX_IS_MULTI
Definition: heapam_xlog.h:240
#define HEAP_XMAX_EXCL_LOCK
Definition: htup_details.h:181
#define XLHL_XMAX_EXCL_LOCK
Definition: heapam_xlog.h:242
#define XLHL_KEYS_UPDATED
Definition: heapam_xlog.h:244
#define HEAP_KEYS_UPDATED
Definition: htup_details.h:264
#define HEAP_XMAX_IS_MULTI
Definition: htup_details.h:194
#define XLHL_XMAX_KEYSHR_LOCK
Definition: heapam_xlog.h:243
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 5255 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().

5260 {
5261  TransactionId new_xmax;
5262  uint16 new_infomask,
5263  new_infomask2;
5264 
5266 
5267 l5:
5268  new_infomask = 0;
5269  new_infomask2 = 0;
5270  if (old_infomask & HEAP_XMAX_INVALID)
5271  {
5272  /*
5273  * No previous locker; we just insert our own TransactionId.
5274  *
5275  * Note that it's critical that this case be the first one checked,
5276  * because there are several blocks below that come back to this one
5277  * to implement certain optimizations; old_infomask might contain
5278  * other dirty bits in those cases, but we don't really care.
5279  */
5280  if (is_update)
5281  {
5282  new_xmax = add_to_xmax;
5283  if (mode == LockTupleExclusive)
5284  new_infomask2 |= HEAP_KEYS_UPDATED;
5285  }
5286  else
5287  {
5288  new_infomask |= HEAP_XMAX_LOCK_ONLY;
5289  switch (mode)
5290  {
5291  case LockTupleKeyShare:
5292  new_xmax = add_to_xmax;
5293  new_infomask |= HEAP_XMAX_KEYSHR_LOCK;
5294  break;
5295  case LockTupleShare:
5296  new_xmax = add_to_xmax;
5297  new_infomask |= HEAP_XMAX_SHR_LOCK;
5298  break;
5300  new_xmax = add_to_xmax;
5301  new_infomask |= HEAP_XMAX_EXCL_LOCK;
5302  break;
5303  case LockTupleExclusive:
5304  new_xmax = add_to_xmax;
5305  new_infomask |= HEAP_XMAX_EXCL_LOCK;
5306  new_infomask2 |= HEAP_KEYS_UPDATED;
5307  break;
5308  default:
5309  new_xmax = InvalidTransactionId; /* silence compiler */
5310  elog(ERROR, "invalid lock mode");
5311  }
5312  }
5313  }
5314  else if (old_infomask & HEAP_XMAX_IS_MULTI)
5315  {
5316  MultiXactStatus new_status;
5317 
5318  /*
5319  * Currently we don't allow XMAX_COMMITTED to be set for multis, so
5320  * cross-check.
5321  */
5322  Assert(!(old_infomask & HEAP_XMAX_COMMITTED));
5323 
5324  /*
5325  * A multixact together with LOCK_ONLY set but neither lock bit set
5326  * (i.e. a pg_upgraded share locked tuple) cannot possibly be running
5327  * anymore. This check is critical for databases upgraded by
5328  * pg_upgrade; both MultiXactIdIsRunning and MultiXactIdExpand assume
5329  * that such multis are never passed.
5330  */
5331  if (HEAP_LOCKED_UPGRADED(old_infomask))
5332  {
5333  old_infomask &= ~HEAP_XMAX_IS_MULTI;
5334  old_infomask |= HEAP_XMAX_INVALID;
5335  goto l5;
5336  }
5337 
5338  /*
5339  * If the XMAX is already a MultiXactId, then we need to expand it to
5340  * include add_to_xmax; but if all the members were lockers and are
5341  * all gone, we can do away with the IS_MULTI bit and just set
5342  * add_to_xmax as the only locker/updater. If all lockers are gone
5343  * and we have an updater that aborted, we can also do without a
5344  * multi.
5345  *
5346  * The cost of doing GetMultiXactIdMembers would be paid by
5347  * MultiXactIdExpand if we weren't to do this, so this check is not
5348  * incurring extra work anyhow.
5349  */
5350  if (!MultiXactIdIsRunning(xmax, HEAP_XMAX_IS_LOCKED_ONLY(old_infomask)))
5351  {
5352  if (HEAP_XMAX_IS_LOCKED_ONLY(old_infomask) ||
5354  old_infomask)))
5355  {
5356  /*
5357  * Reset these bits and restart; otherwise fall through to
5358  * create a new multi below.
5359  */
5360  old_infomask &= ~HEAP_XMAX_IS_MULTI;
5361  old_infomask |= HEAP_XMAX_INVALID;
5362  goto l5;
5363  }
5364  }
5365 
5366  new_status = get_mxact_status_for_lock(mode, is_update);
5367 
5368  new_xmax = MultiXactIdExpand((MultiXactId) xmax, add_to_xmax,
5369  new_status);
5370  GetMultiXactIdHintBits(new_xmax, &new_infomask, &new_infomask2);
5371  }
5372  else if (old_infomask & HEAP_XMAX_COMMITTED)
5373  {
5374  /*
5375  * It's a committed update, so we need to preserve him as updater of
5376  * the tuple.
5377  */
5379  MultiXactStatus new_status;
5380 
5381  if (old_infomask2 & HEAP_KEYS_UPDATED)
5382  status = MultiXactStatusUpdate;
5383  else
5384  status = MultiXactStatusNoKeyUpdate;
5385 
5386  new_status = get_mxact_status_for_lock(mode, is_update);
5387 
5388  /*
5389  * since it's not running, it's obviously impossible for the old
5390  * updater to be identical to the current one, so we need not check
5391  * for that case as we do in the block above.
5392  */
5393  new_xmax = MultiXactIdCreate(xmax, status, add_to_xmax, new_status);
5394  GetMultiXactIdHintBits(new_xmax, &new_infomask, &new_infomask2);
5395  }
5396  else if (TransactionIdIsInProgress(xmax))
5397  {
5398  /*
5399  * If the XMAX is a valid, in-progress TransactionId, then we need to
5400  * create a new MultiXactId that includes both the old locker or
5401  * updater and our own TransactionId.
5402  */
5403  MultiXactStatus new_status;
5404  MultiXactStatus old_status;
5405  LockTupleMode old_mode;
5406 
5407  if (HEAP_XMAX_IS_LOCKED_ONLY(old_infomask))
5408  {
5409  if (HEAP_XMAX_IS_KEYSHR_LOCKED(old_infomask))
5410  old_status = MultiXactStatusForKeyShare;
5411  else if (HEAP_XMAX_IS_SHR_LOCKED(old_infomask))
5412  old_status = MultiXactStatusForShare;
5413  else if (HEAP_XMAX_IS_EXCL_LOCKED(old_infomask))
5414  {
5415  if (old_infomask2 & HEAP_KEYS_UPDATED)
5416  old_status = MultiXactStatusForUpdate;
5417  else
5418  old_status = MultiXactStatusForNoKeyUpdate;
5419  }
5420  else
5421  {
5422  /*
5423  * LOCK_ONLY can be present alone only when a page has been
5424  * upgraded by pg_upgrade. But in that case,
5425  * TransactionIdIsInProgress() should have returned false. We
5426  * assume it's no longer locked in this case.
5427  */
5428  elog(WARNING, "LOCK_ONLY found for Xid in progress %u", xmax);
5429  old_infomask |= HEAP_XMAX_INVALID;
5430  old_infomask &= ~HEAP_XMAX_LOCK_ONLY;
5431  goto l5;
5432  }
5433  }
5434  else
5435  {
5436  /* it's an update, but which kind? */
5437  if (old_infomask2 & HEAP_KEYS_UPDATED)
5438  old_status = MultiXactStatusUpdate;
5439  else
5440  old_status = MultiXactStatusNoKeyUpdate;
5441  }
5442 
5443  old_mode = TUPLOCK_from_mxstatus(old_status);
5444 
5445  /*
5446  * If the lock to be acquired is for the same TransactionId as the
5447  * existing lock, there's an optimization possible: consider only the
5448  * strongest of both locks as the only one present, and restart.
5449  */
5450  if (xmax == add_to_xmax)
5451  {
5452  /*
5453  * Note that it's not possible for the original tuple to be
5454  * updated: we wouldn't be here because the tuple would have been
5455  * invisible and we wouldn't try to update it. As a subtlety,
5456  * this code can also run when traversing an update chain to lock
5457  * future versions of a tuple. But we wouldn't be here either,
5458  * because the add_to_xmax would be different from the original
5459  * updater.
5460  */
5461  Assert(HEAP_XMAX_IS_LOCKED_ONLY(old_infomask));
5462 
5463  /* acquire the strongest of both */
5464  if (mode < old_mode)
5465  mode = old_mode;
5466  /* mustn't touch is_update */
5467 
5468  old_infomask |= HEAP_XMAX_INVALID;
5469  goto l5;
5470  }
5471 
5472  /* otherwise, just fall back to creating a new multixact */
5473  new_status = get_mxact_status_for_lock(mode, is_update);
5474  new_xmax = MultiXactIdCreate(xmax, old_status,
5475  add_to_xmax, new_status);
5476  GetMultiXactIdHintBits(new_xmax, &new_infomask, &new_infomask2);
5477  }
5478  else if (!HEAP_XMAX_IS_LOCKED_ONLY(old_infomask) &&
5479  TransactionIdDidCommit(xmax))
5480  {
5481  /*
5482  * It's a committed update, so we gotta preserve him as updater of the
5483  * tuple.
5484  */
5486  MultiXactStatus new_status;
5487 
5488  if (old_infomask2 & HEAP_KEYS_UPDATED)
5489  status = MultiXactStatusUpdate;
5490  else
5491  status = MultiXactStatusNoKeyUpdate;
5492 
5493  new_status = get_mxact_status_for_lock(mode, is_update);
5494 
5495  /*
5496  * since it's not running, it's obviously impossible for the old
5497  * updater to be identical to the current one, so we need not check
5498  * for that case as we do in the block above.
5499  */
5500  new_xmax = MultiXactIdCreate(xmax, status, add_to_xmax, new_status);
5501  GetMultiXactIdHintBits(new_xmax, &new_infomask, &new_infomask2);
5502  }
5503  else
5504  {
5505  /*
5506  * Can get here iff the locking/updating transaction was running when
5507  * the infomask was extracted from the tuple, but finished before
5508  * TransactionIdIsInProgress got to run. Deal with it as if there was
5509  * no locker at all in the first place.
5510  */
5511  old_infomask |= HEAP_XMAX_INVALID;
5512  goto l5;
5513  }
5514 
5515  *result_infomask = new_infomask;
5516  *result_infomask2 = new_infomask2;
5517  *result_xmax = new_xmax;
5518 }
static void GetMultiXactIdHintBits(MultiXactId multi, uint16 *new_infomask, uint16 *new_infomask2)
Definition: heapam.c:6797
MultiXactStatus
Definition: multixact.h:40
#define HEAP_XMAX_KEYSHR_LOCK
Definition: htup_details.h:179
#define HEAP_XMAX_LOCK_ONLY
Definition: htup_details.h:182
uint32 TransactionId
Definition: c.h:397
bool TransactionIdIsCurrentTransactionId(TransactionId xid)
Definition: xact.c:773
bool TransactionIdIsInProgress(TransactionId xid)
Definition: procarray.c:998
#define HEAP_LOCKED_UPGRADED(infomask)
Definition: htup_details.h:238
#define HEAP_XMAX_COMMITTED
Definition: htup_details.h:192
bool TransactionIdDidCommit(TransactionId transactionId)
Definition: transam.c:125
#define HEAP_XMAX_SHR_LOCK
Definition: htup_details.h:185
#define HEAP_XMAX_IS_SHR_LOCKED(infomask)
Definition: htup_details.h:248
static TransactionId MultiXactIdGetUpdateXid(TransactionId xmax, uint16 t_infomask)
Definition: heapam.c:6878
LockTupleMode
Definition: heapam.h:38
unsigned short uint16
Definition: c.h:267
#define ERROR
Definition: elog.h:43
#define HEAP_XMAX_INVALID
Definition: htup_details.h:193
#define HEAP_XMAX_EXCL_LOCK
Definition: htup_details.h:181
#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:384
#define HEAP_XMAX_IS_LOCKED_ONLY(infomask)
Definition: htup_details.h:216
#define HEAP_KEYS_UPDATED
Definition: htup_details.h:264
#define HEAP_XMAX_IS_MULTI
Definition: htup_details.h:194
TransactionId MultiXactId
Definition: c.h:407
#define Assert(condition)
Definition: c.h:675
#define TUPLOCK_from_mxstatus(status)
Definition: heapam.c:201
static MultiXactStatus get_mxact_status_for_lock(LockTupleMode mode, bool is_update)
Definition: heapam.c:4487
#define HEAP_XMAX_IS_EXCL_LOCKED(infomask)
Definition: htup_details.h:250
#define elog
Definition: elog.h:219
#define HEAP_XMAX_IS_KEYSHR_LOCKED(infomask)
Definition: htup_details.h:252
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:224
bool MultiXactIdIsRunning(MultiXactId multi, bool isLockOnly)
Definition: multixact.c:549
MultiXactId MultiXactIdExpand(MultiXactId multi, TransactionId xid, MultiXactStatus status)
Definition: multixact.c:437
static bool ConditionalMultiXactIdWait ( MultiXactId  multi,
MultiXactStatus  status,
uint16  infomask,
Relation  rel,
int *  remaining 
)
static

Definition at line 7132 of file heapam.c.

References Do_MultiXactIdWait(), and XLTW_None.

Referenced by heap_lock_tuple().

7134 {
7135  return Do_MultiXactIdWait(multi, status, infomask, true,
7136  rel, NULL, XLTW_None, remaining);
7137 }
int remaining
Definition: informix.c:692
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:7032
#define NULL
Definition: c.h:229
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:224
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 7032 of file heapam.c.

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

Referenced by ConditionalMultiXactIdWait(), and MultiXactIdWait().

7036 {
7037  bool result = true;
7038  MultiXactMember *members;
7039  int nmembers;
7040  int remain = 0;
7041 
7042  /* for pre-pg_upgrade tuples, no need to sleep at all */
7043  nmembers = HEAP_LOCKED_UPGRADED(infomask) ? -1 :
7044  GetMultiXactIdMembers(multi, &members, false,
7045  HEAP_XMAX_IS_LOCKED_ONLY(infomask));
7046 
7047  if (nmembers >= 0)
7048  {
7049  int i;
7050 
7051  for (i = 0; i < nmembers; i++)
7052  {
7053  TransactionId memxid = members[i].xid;
7054  MultiXactStatus memstatus = members[i].status;
7055 
7057  {
7058  remain++;
7059  continue;
7060  }
7061 
7064  {
7065  if (remaining && TransactionIdIsInProgress(memxid))
7066  remain++;
7067  continue;
7068  }
7069 
7070  /*
7071  * This member conflicts with our multi, so we have to sleep (or
7072  * return failure, if asked to avoid waiting.)
7073  *
7074  * Note that we don't set up an error context callback ourselves,
7075  * but instead we pass the info down to XactLockTableWait. This
7076  * might seem a bit wasteful because the context is set up and
7077  * tore down for each member of the multixact, but in reality it
7078  * should be barely noticeable, and it avoids duplicate code.
7079  */
7080  if (nowait)
7081  {
7082  result = ConditionalXactLockTableWait(memxid);
7083  if (!result)
7084  break;
7085  }
7086  else
7087  XactLockTableWait(memxid, rel, ctid, oper);
7088  }
7089 
7090  pfree(members);
7091  }
7092 
7093  if (remaining)
7094  *remaining = remain;
7095 
7096  return result;
7097 }
int remaining
Definition: informix.c:692
MultiXactStatus
Definition: multixact.h:40
uint32 TransactionId
Definition: c.h:397
bool TransactionIdIsCurrentTransactionId(TransactionId xid)
Definition: xact.c:773
bool TransactionIdIsInProgress(TransactionId xid)
Definition: procarray.c:998
#define HEAP_LOCKED_UPGRADED(infomask)
Definition: htup_details.h:238
return result
Definition: formatting.c:1632
#define LOCKMODE_from_mxstatus(status)
Definition: heapam.c:171
bool ConditionalXactLockTableWait(TransactionId xid)
Definition: lmgr.c:607
void pfree(void *pointer)
Definition: mcxt.c:950
TransactionId xid
Definition: multixact.h:61
bool DoLockModesConflict(LOCKMODE mode1, LOCKMODE mode2)
Definition: lock.c:556
MultiXactStatus status
Definition: multixact.h:62
#define HEAP_XMAX_IS_LOCKED_ONLY(infomask)
Definition: htup_details.h:216
void XactLockTableWait(TransactionId xid, Relation rel, ItemPointer ctid, XLTW_Oper oper)
Definition: lmgr.c:554
int i
int GetMultiXactIdMembers(MultiXactId multi, MultiXactMember **members, bool from_pgupgrade, bool onlyLock)
Definition: multixact.c:1202
Operator oper(ParseState *pstate, List *opname, Oid ltypeId, Oid rtypeId, bool noError, int location)
Definition: parse_oper.c:377
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:224
static bool DoesMultiXactIdConflict ( MultiXactId  multi,
uint16  infomask,
LockTupleMode  lockmode 
)
static

Definition at line 6943 of file heapam.c.

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

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

6945 {
6946  int nmembers;
6947  MultiXactMember *members;
6948  bool result = false;
6949  LOCKMODE wanted = tupleLockExtraInfo[lockmode].hwlock;
6950 
6951  if (HEAP_LOCKED_UPGRADED(infomask))
6952  return false;
6953 
6954  nmembers = GetMultiXactIdMembers(multi, &members, false,
6955  HEAP_XMAX_IS_LOCKED_ONLY(infomask));
6956  if (nmembers >= 0)
6957  {
6958  int i;
6959 
6960  for (i = 0; i < nmembers; i++)
6961  {
6962  TransactionId memxid;
6963  LOCKMODE memlockmode;
6964 
6965  memlockmode = LOCKMODE_from_mxstatus(members[i].status);
6966 
6967  /* ignore members that don't conflict with the lock we want */
6968  if (!DoLockModesConflict(memlockmode, wanted))
6969  continue;
6970 
6971  /* ignore members from current xact */
6972  memxid = members[i].xid;
6974  continue;
6975 
6976  if (ISUPDATE_from_mxstatus(members[i].status))
6977  {
6978  /* ignore aborted updaters */
6979  if (TransactionIdDidAbort(memxid))
6980  continue;
6981  }
6982  else
6983  {
6984  /* ignore lockers-only that are no longer in progress */
6985  if (!TransactionIdIsInProgress(memxid))
6986  continue;
6987  }
6988 
6989  /*
6990  * Whatever remains are either live lockers that conflict with our
6991  * wanted lock, and updaters that are not aborted. Those conflict
6992  * with what we want, so return true.
6993  */
6994  result = true;
6995  break;
6996  }
6997  pfree(members);
6998  }
6999 
7000  return result;
7001 }
uint32 TransactionId
Definition: c.h:397
int LOCKMODE
Definition: lockdefs.h:26
bool TransactionIdIsCurrentTransactionId(TransactionId xid)
Definition: xact.c:773
bool TransactionIdIsInProgress(TransactionId xid)
Definition: procarray.c:998
#define HEAP_LOCKED_UPGRADED(infomask)
Definition: htup_details.h:238
return result
Definition: formatting.c:1632
#define LOCKMODE_from_mxstatus(status)
Definition: heapam.c:171
void pfree(void *pointer)
Definition: mcxt.c:950
TransactionId xid
Definition: multixact.h:61
bool DoLockModesConflict(LOCKMODE mode1, LOCKMODE mode2)
Definition: lock.c:556
#define ISUPDATE_from_mxstatus(status)
Definition: multixact.h:55
bool TransactionIdDidAbort(TransactionId transactionId)
Definition: transam.c:181
#define HEAP_XMAX_IS_LOCKED_ONLY(infomask)
Definition: htup_details.h:216
static const struct @20 tupleLockExtraInfo[MaxLockTupleMode+1]
int i
int GetMultiXactIdMembers(MultiXactId multi, MultiXactMember **members, bool from_pgupgrade, bool onlyLock)
Definition: multixact.c:1202
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:224
static HeapTuple ExtractReplicaIdentity ( Relation  rel,
HeapTuple  tup,
bool  key_modified,
bool copy 
)
static

Definition at line 7770 of file heapam.c.

References DEBUG4, elog, ERROR, heap_deform_tuple(), heap_form_tuple(), heap_freetuple(), HeapTupleGetOid, HeapTupleHasExternal, HeapTupleSetOid, MaxHeapAttributeNumber, tupleDesc::natts, NULL, ObjectIdAttributeNumber, OidIsValid, RelationData::rd_index, RelationData::rd_rel, RelationClose(), RelationGetDescr, RelationGetRelationName, RelationGetReplicaIndex(), RelationIdGetRelation(), RelationIsLogicallyLogged, REPLICA_IDENTITY_FULL, REPLICA_IDENTITY_NOTHING, toast_flatten_tuple(), and values.

Referenced by heap_delete(), and heap_update().

7771 {
7772  TupleDesc desc = RelationGetDescr(relation);
7773  Oid replidindex;
7774  Relation idx_rel;
7775  TupleDesc idx_desc;
7776  char replident = relation->rd_rel->relreplident;
7777  HeapTuple key_tuple = NULL;
7778  bool nulls[MaxHeapAttributeNumber];
7780  int natt;
7781 
7782  *copy = false;
7783 
7784  if (!RelationIsLogicallyLogged(relation))
7785  return NULL;
7786 
7787  if (replident == REPLICA_IDENTITY_NOTHING)
7788  return NULL;
7789 
7790  if (replident == REPLICA_IDENTITY_FULL)
7791  {
7792  /*
7793  * When logging the entire old tuple, it very well could contain
7794  * toasted columns. If so, force them to be inlined.
7795  */
7796  if (HeapTupleHasExternal(tp))
7797  {
7798  *copy = true;
7799  tp = toast_flatten_tuple(tp, RelationGetDescr(relation));
7800  }
7801  return tp;
7802  }
7803 
7804  /* if the key hasn't changed and we're only logging the key, we're done */
7805  if (!key_changed)
7806  return NULL;
7807 
7808  /* find the replica identity index */
7809  replidindex = RelationGetReplicaIndex(relation);
7810  if (!OidIsValid(replidindex))
7811  {
7812  elog(DEBUG4, "could not find configured replica identity for table \"%s\"",
7813  RelationGetRelationName(relation));
7814  return NULL;
7815  }
7816 
7817  idx_rel = RelationIdGetRelation(replidindex);
7818  idx_desc = RelationGetDescr(idx_rel);
7819 
7820  /* deform tuple, so we have fast access to columns */
7821  heap_deform_tuple(tp, desc, values, nulls);
7822 
7823  /* set all columns to NULL, regardless of whether they actually are */
7824  memset(nulls, 1, sizeof(nulls));
7825 
7826  /*
7827  * Now set all columns contained in the index to NOT NULL, they cannot
7828  * currently be NULL.
7829  */
7830  for (natt = 0; natt < idx_desc->natts; natt++)
7831  {
7832  int attno = idx_rel->rd_index->indkey.values[natt];
7833 
7834  if (attno < 0)
7835  {
7836  /*
7837  * The OID column can appear in an index definition, but that's
7838  * OK, because we always copy the OID if present (see below).
7839  * Other system columns may not.
7840  */
7841  if (attno == ObjectIdAttributeNumber)
7842  continue;
7843  elog(ERROR, "system column in index");
7844  }
7845  nulls[attno - 1] = false;
7846  }
7847 
7848  key_tuple = heap_form_tuple(desc, values, nulls);
7849  *copy = true;
7850  RelationClose(idx_rel);
7851 
7852  /*
7853  * Always copy oids if the table has them, even if not included in the
7854  * index. The space in the logged tuple is used anyway, so there's little
7855  * point in not including the information.
7856  */
7857  if (relation->rd_rel->relhasoids)
7858  HeapTupleSetOid(key_tuple, HeapTupleGetOid(tp));
7859 
7860  /*
7861  * If the tuple, which by here only contains indexed columns, still has
7862  * toasted columns, force them to be inlined. This is somewhat unlikely
7863  * since there's limits on the size of indexed columns, so we don't
7864  * duplicate toast_flatten_tuple()s functionality in the above loop over
7865  * the indexed columns, even if it would be more efficient.
7866  */
7867  if (HeapTupleHasExternal(key_tuple))
7868  {
7869  HeapTuple oldtup = key_tuple;
7870 
7871  key_tuple = toast_flatten_tuple(oldtup, RelationGetDescr(relation));
7872  heap_freetuple(oldtup);
7873  }
7874 
7875  return key_tuple;
7876 }
HeapTuple toast_flatten_tuple(HeapTuple tup, TupleDesc tupleDesc)
Definition: tuptoaster.c:1084
Oid RelationGetReplicaIndex(Relation relation)
Definition: relcache.c:4676
#define RelationGetDescr(relation)
Definition: rel.h:429
#define ObjectIdAttributeNumber
Definition: sysattr.h:22
#define REPLICA_IDENTITY_NOTHING
Definition: pg_class.h:177
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:692
#define RelationIsLogicallyLogged(relation)
Definition: rel.h:576
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1372
unsigned int Oid
Definition: postgres_ext.h:31
#define DEBUG4
Definition: elog.h:22
#define OidIsValid(objectId)
Definition: c.h:538
int natts
Definition: tupdesc.h:73
#define HeapTupleSetOid(tuple, oid)
Definition: htup_details.h:698
Form_pg_index rd_index
Definition: rel.h:159
#define REPLICA_IDENTITY_FULL
Definition: pg_class.h:179
#define ERROR
Definition: elog.h:43
#define RelationGetRelationName(relation)
Definition: rel.h:437
void RelationClose(Relation relation)
Definition: relcache.c:2156
uintptr_t Datum
Definition: postgres.h:372
#define MaxHeapAttributeNumber
Definition: htup_details.h:47
#define NULL
Definition: c.h:229
void heap_deform_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *values, bool *isnull)
Definition: heaptuple.c:933
static Datum values[MAXATTR]
Definition: bootstrap.c:163
#define HeapTupleHasExternal(tuple)
Definition: htup_details.h:674
#define elog
Definition: elog.h:219
#define HeapTupleGetOid(tuple)
Definition: htup_details.h:695
Relation RelationIdGetRelation(Oid relationId)
Definition: relcache.c:2067
static void fix_infomask_from_infobits ( uint8  infobits,
uint16 infomask,
uint16 infomask2 
)
static

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

8167 {
8168  *infomask &= ~(HEAP_XMAX_IS_MULTI | HEAP_XMAX_LOCK_ONLY |
8170  *infomask2 &= ~HEAP_KEYS_UPDATED;
8171 
8172  if (infobits & XLHL_XMAX_IS_MULTI)
8173  *infomask |= HEAP_XMAX_IS_MULTI;
8174  if (infobits & XLHL_XMAX_LOCK_ONLY)
8175  *infomask |= HEAP_XMAX_LOCK_ONLY;
8176  if (infobits & XLHL_XMAX_EXCL_LOCK)
8177  *infomask |= HEAP_XMAX_EXCL_LOCK;
8178  /* note HEAP_XMAX_SHR_LOCK isn't considered here */
8179  if (infobits & XLHL_XMAX_KEYSHR_LOCK)
8180  *infomask |= HEAP_XMAX_KEYSHR_LOCK;
8181 
8182  if (infobits & XLHL_KEYS_UPDATED)
8183  *infomask2 |= HEAP_KEYS_UPDATED;
8184 }
#define HEAP_XMAX_KEYSHR_LOCK
Definition: htup_details.h:179
#define HEAP_XMAX_LOCK_ONLY
Definition: htup_details.h:182
#define XLHL_XMAX_LOCK_ONLY
Definition: heapam_xlog.h:241
#define XLHL_XMAX_IS_MULTI
Definition: heapam_xlog.h:240
#define HEAP_XMAX_EXCL_LOCK
Definition: htup_details.h:181
#define XLHL_XMAX_EXCL_LOCK
Definition: heapam_xlog.h:242
#define XLHL_KEYS_UPDATED
Definition: heapam_xlog.h:244
#define HEAP_KEYS_UPDATED
Definition: htup_details.h:264
#define HEAP_XMAX_IS_MULTI
Definition: htup_details.h:194
#define XLHL_XMAX_KEYSHR_LOCK
Definition: heapam_xlog.h:243
void FreeBulkInsertState ( BulkInsertState  bistate)

Definition at line 2333 of file heapam.c.

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

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

2334 {
2335  if (bistate->current_buf != InvalidBuffer)
2336  ReleaseBuffer(bistate->current_buf);
2337  FreeAccessStrategy(bistate->strategy);
2338  pfree(bistate);
2339 }
#define InvalidBuffer
Definition: buf.h:25
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3309
void pfree(void *pointer)
Definition: mcxt.c:950
void FreeAccessStrategy(BufferAccessStrategy strategy)
Definition: freelist.c:580
BufferAccessStrategy strategy
Definition: hio.h:33
Buffer current_buf
Definition: hio.h:34
static TransactionId FreezeMultiXactId ( MultiXactId  multi,
uint16  t_infomask,
TransactionId  cutoff_xid,
MultiXactId  cutoff_multi,
uint16 flags 
)
static

Definition at line 6306 of file heapam.c.

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

6309 {
6311  int i;
6312  MultiXactMember *members;
6313  int nmembers;
6314  bool need_replace;
6315  int nnewmembers;
6316  MultiXactMember *newmembers;
6317  bool has_lockers;
6318  TransactionId update_xid;
6319  bool update_committed;
6320 
6321  *flags = 0;
6322 
6323  /* We should only be called in Multis */
6324  Assert(t_infomask & HEAP_XMAX_IS_MULTI);
6325 
6326  if (!MultiXactIdIsValid(multi) ||
6327  HEAP_LOCKED_UPGRADED(t_infomask))
6328  {
6329  /* Ensure infomask bits are appropriately set/reset */
6330  *flags |= FRM_INVALIDATE_XMAX;
6331  return InvalidTransactionId;
6332  }
6333  else if (MultiXactIdPrecedes(multi, cutoff_multi))
6334  {
6335  /*
6336  * This old multi cannot possibly have members still running. If it
6337  * was a locker only, it can be removed without any further
6338  * consideration; but if it contained an update, we might need to
6339  * preserve it.
6340  */
6342  HEAP_XMAX_IS_LOCKED_ONLY(t_infomask)));
6343  if (HEAP_XMAX_IS_LOCKED_ONLY(t_infomask))
6344  {
6345  *flags |= FRM_INVALIDATE_XMAX;
6346  xid = InvalidTransactionId; /* not strictly necessary */
6347  }
6348  else
6349  {
6350  /* replace multi by update xid */
6351  xid = MultiXactIdGetUpdateXid(multi, t_infomask);
6352 
6353  /* wasn't only a lock, xid needs to be valid */
6355 
6356  /*
6357  * If the xid is older than the cutoff, it has to have aborted,
6358  * otherwise the tuple would have gotten pruned away.
6359  */
6360  if (TransactionIdPrecedes(xid, cutoff_xid))
6361  {
6363  *flags |= FRM_INVALIDATE_XMAX;
6364  xid = InvalidTransactionId; /* not strictly necessary */
6365  }
6366  else
6367  {
6368  *flags |= FRM_RETURN_IS_XID;
6369  }
6370  }
6371 
6372  return xid;
6373  }
6374 
6375  /*
6376  * This multixact might have or might not have members still running, but
6377  * we know it's valid and is newer than the cutoff point for multis.
6378  * However, some member(s) of it may be below the cutoff for Xids, so we
6379  * need to walk the whole members array to figure out what to do, if
6380  * anything.
6381  */
6382 
6383  nmembers =
6384  GetMultiXactIdMembers(multi, &members, false,
6385  HEAP_XMAX_IS_LOCKED_ONLY(t_infomask));
6386  if (nmembers <= 0)
6387  {
6388  /* Nothing worth keeping */
6389  *flags |= FRM_INVALIDATE_XMAX;
6390  return InvalidTransactionId;
6391  }
6392 
6393  /* is there anything older than the cutoff? */
6394  need_replace = false;
6395  for (i = 0; i < nmembers; i++)
6396  {
6397  if (TransactionIdPrecedes(members[i].xid, cutoff_xid))
6398  {
6399  need_replace = true;
6400  break;
6401  }
6402  }
6403 
6404  /*
6405  * In the simplest case, there is no member older than the cutoff; we can
6406  * keep the existing MultiXactId as is.
6407  */
6408  if (!need_replace)
6409  {
6410  *flags |= FRM_NOOP;
6411  pfree(members);
6412  return InvalidTransactionId;
6413  }
6414 
6415  /*
6416  * If the multi needs to be updated, figure out which members do we need
6417  * to keep.
6418  */
6419  nnewmembers = 0;
6420  newmembers = palloc(sizeof(MultiXactMember) * nmembers);
6421  has_lockers = false;
6422  update_xid = InvalidTransactionId;
6423  update_committed = false;
6424 
6425  for (i = 0; i < nmembers; i++)
6426  {
6427  /*
6428  * Determine whether to keep this member or ignore it.
6429  */
6430  if (ISUPDATE_from_mxstatus(members[i].status))
6431  {
6432  TransactionId xid = members[i].xid;
6433 
6434  /*
6435  * It's an update; should we keep it? If the transaction is known
6436  * aborted or crashed then it's okay to ignore it, otherwise not.
6437  * Note that an updater older than cutoff_xid cannot possibly be
6438  * committed, because HeapTupleSatisfiesVacuum would have returned
6439  * HEAPTUPLE_DEAD and we would not be trying to freeze the tuple.
6440  *
6441  * As with all tuple visibility routines, it's critical to test
6442  * TransactionIdIsInProgress before TransactionIdDidCommit,
6443  * because of race conditions explained in detail in tqual.c.
6444  */
6447  {
6448  Assert(!TransactionIdIsValid(update_xid));
6449  update_xid = xid;
6450  }
6451  else if (TransactionIdDidCommit(xid))
6452  {
6453  /*
6454  * The transaction committed, so we can tell caller to set
6455  * HEAP_XMAX_COMMITTED. (We can only do this because we know
6456  * the transaction is not running.)
6457  */
6458  Assert(!TransactionIdIsValid(update_xid));
6459  update_committed = true;
6460  update_xid = xid;
6461  }
6462 
6463  /*
6464  * Not in progress, not committed -- must be aborted or crashed;
6465  * we can ignore it.
6466  */
6467 
6468  /*
6469  * Since the tuple wasn't marked HEAPTUPLE_DEAD by vacuum, the
6470  * update Xid cannot possibly be older than the xid cutoff.
6471  */
6472  Assert(!TransactionIdIsValid(update_xid) ||
6473  !TransactionIdPrecedes(update_xid, cutoff_xid));
6474 
6475  /*
6476  * If we determined that it's an Xid corresponding to an update
6477  * that must be retained, additionally add it to the list of
6478  * members of the new Multi, in case we end up using that. (We
6479  * might still decide to use only an update Xid and not a multi,
6480  * but it's easier to maintain the list as we walk the old members
6481  * list.)
6482  */
6483  if (TransactionIdIsValid(update_xid))
6484  newmembers[nnewmembers++] = members[i];
6485  }
6486  else
6487  {
6488  /* We only keep lockers if they are still running */
6489  if (TransactionIdIsCurrentTransactionId(members[i].xid) ||
6490  TransactionIdIsInProgress(members[i].xid))
6491  {
6492  /* running locker cannot possibly be older than the cutoff */
6493  Assert(!TransactionIdPrecedes(members[i].xid, cutoff_xid));
6494  newmembers[nnewmembers++] = members[i];
6495  has_lockers = true;
6496  }
6497  }
6498  }
6499 
6500  pfree(members);
6501 
6502  if (nnewmembers == 0)
6503  {
6504  /* nothing worth keeping!? Tell caller to remove the whole thing */
6505  *flags |= FRM_INVALIDATE_XMAX;
6506  xid = InvalidTransactionId;
6507  }
6508  else if (TransactionIdIsValid(update_xid) && !has_lockers)
6509  {
6510  /*
6511  * If there's a single member and it's an update, pass it back alone
6512  * without creating a new Multi. (XXX we could do this when there's a
6513  * single remaining locker, too, but that would complicate the API too
6514  * much; moreover, the case with the single updater is more
6515  * interesting, because those are longer-lived.)
6516  */
6517  Assert(nnewmembers == 1);
6518  *flags |= FRM_RETURN_IS_XID;
6519  if (update_committed)
6520  *flags |= FRM_MARK_COMMITTED;
6521  xid = update_xid;
6522  }
6523  else
6524  {
6525  /*
6526  * Create a new multixact with the surviving members of the previous
6527  * one, to set as new Xmax in the tuple.
6528  */
6529  xid = MultiXactIdCreateFromMembers(nnewmembers, newmembers);
6530  *flags |= FRM_RETURN_IS_MULTI;
6531  }
6532 
6533  pfree(newmembers);
6534 
6535  return xid;
6536 }
#define FRM_RETURN_IS_XID
Definition: heapam.c:6280
#define FRM_MARK_COMMITTED
Definition: heapam.c:6282
uint32 TransactionId
Definition: c.h:397
bool TransactionIdIsCurrentTransactionId(TransactionId xid)
Definition: xact.c:773
bool TransactionIdIsInProgress(TransactionId xid)
Definition: procarray.c:998
MultiXactId MultiXactIdCreateFromMembers(int nmembers, MultiXactMember *members)
Definition: multixact.c:746
#define HEAP_LOCKED_UPGRADED(infomask)
Definition: htup_details.h:238
bool TransactionIdDidCommit(TransactionId transactionId)
Definition: transam.c:125
static TransactionId MultiXactIdGetUpdateXid(TransactionId xmax, uint16 t_infomask)
Definition: heapam.c:6878
void pfree(void *pointer)
Definition: mcxt.c:950
TransactionId xid
Definition: multixact.h:61
#define FRM_INVALIDATE_XMAX
Definition: heapam.c:6279
#define InvalidTransactionId
Definition: transam.h:31
#define ISUPDATE_from_mxstatus(status)
Definition: multixact.h:55
#define MultiXactIdIsValid(multi)
Definition: multixact.h:27
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition: transam.c:300
#define FRM_RETURN_IS_MULTI
Definition: heapam.c:6281
#define HEAP_XMAX_IS_LOCKED_ONLY(infomask)
Definition: htup_details.h:216
#define HEAP_XMAX_IS_MULTI
Definition: htup_details.h:194
#define Assert(condition)
Definition: c.h:675
#define FRM_NOOP
Definition: heapam.c:6278
bool MultiXactIdPrecedes(MultiXactId multi1, MultiXactId multi2)
Definition: multixact.c:3140
void * palloc(Size size)
Definition: mcxt.c:849
int i
int GetMultiXactIdMembers(MultiXactId multi, MultiXactMember **members, bool from_pgupgrade, bool onlyLock)
Definition: multixact.c:1202
#define TransactionIdIsValid(xid)
Definition: transam.h:41
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:224
bool MultiXactIdIsRunning(MultiXactId multi, bool isLockOnly)
Definition: multixact.c:549
static MultiXactStatus get_mxact_status_for_lock ( LockTupleMode  mode,
bool  is_update 
)
static

Definition at line 4487 of file heapam.c.

References elog, ERROR, and tupleLockExtraInfo.

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

4488 {
4489  int retval;
4490 
4491  if (is_update)
4492  retval = tupleLockExtraInfo[mode].updstatus;
4493  else
4494  retval = tupleLockExtraInfo[mode].lockstatus;
4495 
4496  if (retval == -1)
4497  elog(ERROR, "invalid lock tuple mode %d/%s", mode,
4498  is_update ? "true" : "false");
4499 
4500  return (MultiXactStatus) retval;
4501 }
MultiXactStatus
Definition: multixact.h:40
#define ERROR
Definition: elog.h:43
static const struct @20 tupleLockExtraInfo[MaxLockTupleMode+1]
#define elog
Definition: elog.h:219
BulkInsertState GetBulkInsertState ( void  )

Definition at line 2319 of file heapam.c.

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

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

2320 {
2321  BulkInsertState bistate;
2322 
2323  bistate = (BulkInsertState) palloc(sizeof(BulkInsertStateData));
2325  bistate->current_buf = InvalidBuffer;
2326  return bistate;
2327 }
BufferAccessStrategy GetAccessStrategy(BufferAccessStrategyType btype)
Definition: freelist.c:525
#define InvalidBuffer
Definition: buf.h:25
struct BulkInsertStateData * BulkInsertState
Definition: heapam.h:33
BufferAccessStrategy strategy
Definition: hio.h:33
void * palloc(Size size)
Definition: mcxt.c:849
Buffer current_buf
Definition: hio.h:34
static void GetMultiXactIdHintBits ( MultiXactId  multi,
uint16 new_infomask,
uint16 new_infomask2 
)
static

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

6799 {
6800  int nmembers;
6801  MultiXactMember *members;
6802  int i;
6803  uint16 bits = HEAP_XMAX_IS_MULTI;
6804  uint16 bits2 = 0;
6805  bool has_update = false;
6806  LockTupleMode strongest = LockTupleKeyShare;
6807 
6808  /*
6809  * We only use this in multis we just created, so they cannot be values
6810  * pre-pg_upgrade.
6811  */
6812  nmembers = GetMultiXactIdMembers(multi, &members, false, false);
6813 
6814  for (i = 0; i < nmembers; i++)
6815  {
6816  LockTupleMode mode;
6817 
6818  /*
6819  * Remember the strongest lock mode held by any member of the
6820  * multixact.
6821  */
6822  mode = TUPLOCK_from_mxstatus(members[i].status);
6823  if (mode > strongest)
6824  strongest = mode;
6825 
6826  /* See what other bits we need */
6827  switch (members[i].status)
6828  {
6832  break;
6833 
6835  bits2 |= HEAP_KEYS_UPDATED;
6836  break;
6837 
6839  has_update = true;
6840  break;
6841 
6842  case MultiXactStatusUpdate:
6843  bits2 |= HEAP_KEYS_UPDATED;
6844  has_update = true;
6845  break;
6846  }
6847  }
6848 
6849  if (strongest == LockTupleExclusive ||
6850  strongest == LockTupleNoKeyExclusive)
6851  bits |= HEAP_XMAX_EXCL_LOCK;
6852  else if (strongest == LockTupleShare)
6853  bits |= HEAP_XMAX_SHR_LOCK;
6854  else if (strongest == LockTupleKeyShare)
6855  bits |= HEAP_XMAX_KEYSHR_LOCK;
6856 
6857  if (!has_update)
6858  bits |= HEAP_XMAX_LOCK_ONLY;
6859 
6860  if (nmembers > 0)
6861  pfree(members);
6862 
6863  *new_infomask = bits;
6864  *new_infomask2 = bits2;
6865 }
#define HEAP_XMAX_KEYSHR_LOCK
Definition: htup_details.h:179
#define HEAP_XMAX_LOCK_ONLY
Definition: htup_details.h:182
#define HEAP_XMAX_SHR_LOCK
Definition: htup_details.h:185
LockTupleMode
Definition: heapam.h:38
unsigned short uint16
Definition: c.h:267
void pfree(void *pointer)
Definition: mcxt.c:950
#define HEAP_XMAX_EXCL_LOCK
Definition: htup_details.h:181
#define HEAP_KEYS_UPDATED
Definition: htup_details.h:264
#define HEAP_XMAX_IS_MULTI
Definition: htup_details.h:194
#define TUPLOCK_from_mxstatus(status)
Definition: heapam.c:201
int i
int GetMultiXactIdMembers(MultiXactId multi, MultiXactMember **members, bool from_pgupgrade, bool onlyLock)
Definition: multixact.c:1202
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:224
void heap2_redo ( XLogReaderState record)

Definition at line 9030 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.

9031 {
9032  uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
9033 
9034  switch (info & XLOG_HEAP_OPMASK)
9035  {
9036  case XLOG_HEAP2_CLEAN:
9037  heap_xlog_clean(record);
9038  break;
9040  heap_xlog_freeze_page(record);
9041  break;
9043  heap_xlog_cleanup_info(record);
9044  break;
9045  case XLOG_HEAP2_VISIBLE:
9046  heap_xlog_visible(record);
9047  break;
9049  heap_xlog_multi_insert(record);
9050  break;
9052  heap_xlog_lock_updated(record);
9053  break;
9054  case XLOG_HEAP2_NEW_CID:
9055 
9056  /*
9057  * Nothing to do on a real replay, only used during logical
9058  * decoding.
9059  */
9060  break;
9061  case XLOG_HEAP2_REWRITE:
9062  heap_xlog_logical_rewrite(record);
9063  break;
9064  default:
9065  elog(PANIC, "heap2_redo: unknown op code %u", info);
9066  }
9067 }
void heap_xlog_logical_rewrite(XLogReaderState *r)
Definition: rewriteheap.c:1118
#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:266
#define XLOG_HEAP_OPMASK
Definition: heapam_xlog.h:41
#define PANIC
Definition: elog.h:53
#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:8891
static void heap_xlog_freeze_page(XLogReaderState *record)
Definition: heapam.c:8108
#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:8373
#define XLOG_HEAP2_NEW_CID
Definition: heapam_xlog.h:60
#define XLogRecGetInfo(decoder)
Definition: xlogreader.h:216
#define XLR_INFO_MASK
Definition: xlogrecord.h:62
static void heap_xlog_cleanup_info(XLogReaderState *record)
Definition: heapam.c:7882
#define XLOG_HEAP2_FREEZE_PAGE
Definition: heapam_xlog.h:55
static void heap_xlog_visible(XLogReaderState *record)
Definition: heapam.c:7993
#define elog
Definition: elog.h:219
static void heap_xlog_clean(XLogReaderState *record)
Definition: heapam.c:7903
void heap_abort_speculative ( Relation  relation,
HeapTuple  tuple 
)

Definition at line 6054 of file heapam.c.

References Assert, buffer, 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_XMAX_BITS, HeapTupleHasExternal, HeapTupleHeaderIsHeapOnly, HeapTupleHeaderIsSpeculative, HeapTupleHeaderSetXmin, xl_heap_delete::infobits_set, InvalidTransactionId, IsToastRelation(), ItemIdGetLength, ItemIdIsNormal, ItemPointerGetBlockNumber, ItemPointerGetOffsetNumber, ItemPointerIsValid, LockBuffer(), MarkBufferDirty(), xl_heap_delete::offnum, PageGetItem, PageGetItemId, PageIsAllVisible, PageSetLSN, PageSetPrunable, pgstat_count_heap_delete(), ReadBuffer(), RecentGlobalXmin, REGBUF_STANDARD, RelationGetRelid, RelationNeedsWAL, ReleaseBuffer(), SizeOfHeapDelete, START_CRIT_SECTION, HeapTupleHeaderData::t_choice, HeapTupleHeaderData::t_ctid, HeapTupleData::t_data, HeapTupleHeaderData::t_heap, HeapTupleHeaderData::t_infomask, HeapTupleHeaderData::t_infomask2, HeapTupleData::t_len, HeapTupleData::t_self, HeapTupleData::t_tableOid, HeapTupleFields::t_xmin, toast_delete(), TransactionIdIsValid, XLH_DELETE_IS_SUPER, XLOG_HEAP_DELETE, XLogBeginInsert(), XLogInsert(), XLogRegisterBuffer(), XLogRegisterData(), and xl_heap_delete::xmax.

Referenced by ExecInsert(), and toast_delete_datum().

6055 {
6057  ItemPointer tid = &(tuple->t_self);
6058  ItemId lp;
6059  HeapTupleData tp;
6060  Page page;
6061  BlockNumber block;
6062  Buffer buffer;
6063 
6064  Assert(ItemPointerIsValid(tid));
6065 
6066  block = ItemPointerGetBlockNumber(tid);
6067  buffer = ReadBuffer(relation, block);
6068  page = BufferGetPage(buffer);
6069 
6071 
6072  /*
6073  * Page can't be all visible, we just inserted into it, and are still
6074  * running.
6075  */
6076  Assert(!PageIsAllVisible(page));
6077 
6078  lp = PageGetItemId(page, ItemPointerGetOffsetNumber(tid));
6079  Assert(ItemIdIsNormal(lp));
6080 
6081  tp.t_tableOid = RelationGetRelid(relation);
6082  tp.t_data = (HeapTupleHeader) PageGetItem(page, lp);
6083  tp.t_len = ItemIdGetLength(lp);
6084  tp.t_self = *tid;
6085 
6086  /*
6087  * Sanity check that the tuple really is a speculatively inserted tuple,
6088  * inserted by us.
6089  */
6090  if (tp.t_data->t_choice.t_heap.t_xmin != xid)
6091  elog(ERROR, "attempted to kill a tuple inserted by another transaction");
6092  if (!(IsToastRelation(relation) || HeapTupleHeaderIsSpeculative(tp.t_data)))
6093  elog(ERROR, "attempted to kill a non-speculative tuple");
6095 
6096  /*
6097  * No need to check for serializable conflicts here. There is never a
6098  * need for a combocid, either. No need to extract replica identity, or
6099  * do anything special with infomask bits.
6100  */
6101 
6103 
6104  /*
6105  * The tuple will become DEAD immediately. Flag that this page
6106  * immediately is a candidate for pruning by setting xmin to
6107  * RecentGlobalXmin. That's not pretty, but it doesn't seem worth
6108  * inventing a nicer API for this.
6109  */
6112 
6113  /* store transaction information of xact deleting the tuple */
6116 
6117  /*
6118  * Set the tuple header xmin to InvalidTransactionId. This makes the
6119  * tuple immediately invisible everyone. (In particular, to any
6120  * transactions waiting on the speculative token, woken up later.)
6121  */
6123 
6124  /* Clear the speculative insertion token too */
6125  tp.t_data->t_ctid = tp.t_self;
6126 
6127  MarkBufferDirty(buffer);
6128 
6129  /*
6130  * XLOG stuff
6131  *
6132  * The WAL records generated here match heap_delete(). The same recovery
6133  * routines are used.
6134  */
6135  if (RelationNeedsWAL(relation))
6136  {
6137  xl_heap_delete xlrec;
6138  XLogRecPtr recptr;
6139 
6140  xlrec.flags = XLH_DELETE_IS_SUPER;
6142  tp.t_data->t_infomask2);
6144  xlrec.xmax = xid;
6145 
6146  XLogBeginInsert();
6147  XLogRegisterData((char *) &xlrec, SizeOfHeapDelete);
6148  XLogRegisterBuffer(0, buffer, REGBUF_STANDARD);
6149 
6150  /* No replica identity & replication origin logged */
6151 
6152  recptr = XLogInsert(RM_HEAP_ID, XLOG_HEAP_DELETE);
6153 
6154  PageSetLSN(page, recptr);
6155  }
6156 
6157  END_CRIT_SECTION();
6158 
6159  LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
6160 
6161  if (HeapTupleHasExternal(&tp))
6162  {
6163  Assert(!IsToastRelation(relation));
6164  toast_delete(relation, &tp, true);
6165  }
6166 
6167  /*
6168  * Never need to mark tuple for invalidation, since catalogs don't support
6169  * speculative insertion
6170  */
6171 
6172  /* Now we can release the buffer */
6173  ReleaseBuffer(buffer);
6174 
6175  /* count deletion, as we counted the insertion too */
6176  pgstat_count_heap_delete(relation);
6177 }
#define ItemPointerIsValid(pointer)
Definition: itemptr.h:59
#define BUFFER_LOCK_UNLOCK
Definition: bufmgr.h:87
bool IsToastRelation(Relation relation)
Definition: catalog.c:135
#define HEAP_XMAX_BITS
Definition: htup_details.h:256
union HeapTupleHeaderData::@45 t_choice
#define XLH_DELETE_IS_SUPER
Definition: heapam_xlog.h:95
static uint8 compute_infobits(uint16 infomask, uint16 infomask2)
Definition: heapam.c:2952
HeapTupleFields t_heap
Definition: htup_details.h:146
#define PageIsAllVisible(page)
Definition: bufpage.h:382
uint32 TransactionId
Definition: c.h:397
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:1450
void XLogRegisterBuffer(uint8 block_id, Buffer buffer, uint8 flags)
Definition: xloginsert.c:213
HeapTupleHeaderData * HeapTupleHeader
Definition: htup.h:23
#define END_CRIT_SECTION()
Definition: miscadmin.h:132
#define HeapTupleHeaderIsSpeculative(tup)
Definition: htup_details.h:423
#define PageSetPrunable(page, xid)
Definition: bufpage.h:395
#define START_CRIT_SECTION()
Definition: miscadmin.h:130
uint32 BlockNumber
Definition: block.h:31
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3309
#define BUFFER_LOCK_EXCLUSIVE
Definition: bufmgr.h:89
OffsetNumber offnum
Definition: heapam_xlog.h:105
HeapTupleHeader t_data
Definition: htup.h:67
#define HeapTupleHeaderIsHeapOnly(tup)
Definition: htup_details.h:502
#define ItemIdGetLength(itemId)
Definition: itemid.h:58
#define ERROR
Definition: elog.h:43
ItemPointerData t_ctid
Definition: htup_details.h:150
ItemPointerData t_self
Definition: htup.h:65
TransactionId xmax
Definition: heapam_xlog.h:104
TransactionId GetCurrentTransactionId(void)
Definition: xact.c:417
uint32 t_len
Definition: htup.h:64
#define SizeOfHeapDelete
Definition: heapam_xlog.h:110
TransactionId RecentGlobalXmin
Definition: snapmgr.c:166
#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:160
TransactionId t_xmin
Definition: htup_details.h:118
#define PageGetItemId(page, offsetNumber)
Definition: bufpage.h:232
void XLogRegisterData(char *data, int len)
Definition: xloginsert.c:323
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:415
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3546
#define HEAP_KEYS_UPDATED
Definition: htup_details.h:264
#define HEAP_MOVED
Definition: htup_details.h:202
uint64 XLogRecPtr
Definition: xlogdefs.h:21
#define Assert(condition)
Definition: c.h:675
uint8 infobits_set
Definition: heapam_xlog.h:106
#define ItemIdIsNormal(itemId)
Definition: itemid.h:98
WalTimeSample buffer[LAG_TRACKER_BUFFER_SIZE]
Definition: walsender.c:211
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition: bufmgr.c:594
#define ItemPointerGetOffsetNumber(pointer)
Definition: itemptr.h:94
#define RelationNeedsWAL(relation)
Definition: rel.h:506
void pgstat_count_heap_delete(Relation rel)
Definition: pgstat.c:1953
#define HeapTupleHasExternal(tuple)
Definition: htup_details.h:674
void toast_delete(Relation rel, HeapTuple oldtup, bool is_speculative)
Definition: tuptoaster.c:464
#define elog
Definition: elog.h:219
#define ItemPointerGetBlockNumber(pointer)
Definition: itemptr.h:75
#define TransactionIdIsValid(xid)
Definition: transam.h:41
void XLogBeginInsert(void)
Definition: xloginsert.c:120
#define PageSetLSN(page, lsn)
Definition: bufpage.h:365
int Buffer
Definition: buf.h:23
#define XLOG_HEAP_DELETE
Definition: heapam_xlog.h:33
#define RelationGetRelid(relation)
Definition: rel.h:417
#define PageGetItem(page, itemId)
Definition: bufpage.h:337
Pointer Page
Definition: bufpage.h:74
#define HeapTupleHeaderSetXmin(tup, xid)
Definition: htup_details.h:313
static bool heap_acquire_tuplock ( Relation  relation,
ItemPointer  tid,
LockTupleMode  mode,
LockWaitPolicy  wait_policy,
bool have_tuple_lock 
)
static

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

5208 {
5209  if (*have_tuple_lock)
5210  return true;
5211 
5212  switch (wait_policy)
5213  {
5214  case LockWaitBlock:
5215  LockTupleTuplock(relation, tid, mode);
5216  break;
5217 
5218  case LockWaitSkip:
5219  if (!ConditionalLockTupleTuplock(relation, tid, mode))
5220  return false;
5221  break;
5222 
5223  case LockWaitError:
5224  if (!ConditionalLockTupleTuplock(relation, tid, mode))
5225  ereport(ERROR,
5226  (errcode(ERRCODE_LOCK_NOT_AVAILABLE),
5227  errmsg("could not obtain lock on row in relation \"%s\"",
5228  RelationGetRelationName(relation))));
5229  break;
5230  }
5231  *have_tuple_lock = true;
5232 
5233  return true;
5234 }
#define LockTupleTuplock(rel, tup, mode)
Definition: heapam.c:179
#define ConditionalLockTupleTuplock(rel, tup, mode)
Definition: heapam.c:183
int errcode(int sqlerrcode)
Definition: elog.c:575
#define ERROR
Definition: elog.h:43
#define RelationGetRelationName(relation)
Definition: rel.h:437
#define ereport(elevel, rest)
Definition: elog.h:122
int errmsg(const char *fmt,...)
Definition: elog.c:797
HeapScanDesc heap_beginscan ( Relation  relation,
Snapshot  snapshot,
int  nkeys,
ScanKey  key 
)

Definition at line 1391 of file heapam.c.

References heap_beginscan_internal().

Referenced by AlterDomainNotNull(), ATRewriteTable(), copy_heap_data(), CopyTo(), DefineQueryRewrite(), pgrowlocks(), pgstat_collect_oids(), RelationFindReplTupleSeq(), SeqNext(), validateCheckConstraint(), validateDomainConstraint(), and validateForeignKeyConstraint().

1393 {
1394  return heap_beginscan_internal(relation, snapshot, nkeys, key, NULL,
1395  true, true, true, false, false, false);
1396 }
static HeapScanDesc heap_beginscan_internal(Relation relation, Snapshot snapshot, int nkeys, ScanKey key, ParallelHeapScanDesc parallel_scan, bool allow_strat, bool allow_sync, bool allow_pagemode, bool is_bitmapscan, bool is_samplescan, bool temp_snap)
Definition: heapam.c:1437
#define NULL
Definition: c.h:229
HeapScanDesc heap_beginscan_bm ( Relation  relation,
Snapshot  snapshot,
int  nkeys,
ScanKey  key 
)

Definition at line 1419 of file heapam.c.

References heap_beginscan_internal().

Referenced by ExecInitBitmapHeapScan().

1421 {
1422  return heap_beginscan_internal(relation, snapshot, nkeys, key, NULL,
1423  false, false, true, true, false, false);
1424 }
static HeapScanDesc heap_beginscan_internal(Relation relation, Snapshot snapshot, int nkeys, ScanKey key, ParallelHeapScanDesc parallel_scan, bool allow_strat, bool allow_sync, bool allow_pagemode, bool is_bitmapscan, bool is_samplescan, bool temp_snap)
Definition: heapam.c:1437
#define NULL
Definition: c.h:229
HeapScanDesc heap_beginscan_catalog ( Relation  relation,
int  nkeys,
ScanKey  key 
)

Definition at line 1399 of file heapam.c.

References GetCatalogSnapshot(), heap_beginscan_internal(), RegisterSnapshot(), and RelationGetRelid.

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

1400 {
1401  Oid relid = RelationGetRelid(relation);
1402  Snapshot snapshot = RegisterSnapshot(GetCatalogSnapshot(relid));
1403 
1404  return heap_beginscan_internal(relation, snapshot, nkeys, key, NULL,
1405  true, true, true, false, false, true);
1406 }
Snapshot RegisterSnapshot(Snapshot snapshot)
Definition: snapmgr.c:858
Snapshot GetCatalogSnapshot(Oid relid)
Definition: snapmgr.c:436
unsigned int Oid
Definition: postgres_ext.h:31
static HeapScanDesc heap_beginscan_internal(Relation relation, Snapshot snapshot, int nkeys, ScanKey key, ParallelHeapScanDesc parallel_scan, bool allow_strat, bool allow_sync, bool allow_pagemode, bool is_bitmapscan, bool is_samplescan, bool temp_snap)
Definition: heapam.c:1437
#define NULL
Definition: c.h:229
#define RelationGetRelid(relation)
Definition: rel.h:417
static HeapScanDesc heap_beginscan_internal ( Relation  relation,
Snapshot  snapshot,
int  nkeys,
ScanKey  key,
ParallelHeapScanDesc  parallel_scan,
bool  allow_strat,
bool  allow_sync,
bool  allow_pagemode,
bool  is_bitmapscan,
bool  is_samplescan,
bool  temp_snap 
)
static

Definition at line 1437 of file heapam.c.

References initscan(), IsMVCCSnapshot, NULL, palloc(), PredicateLockRelation(), RelationGetRelid, RelationIncrementReferenceCount(), HeapScanDescData::rs_allow_strat, HeapScanDescData::rs_allow_sync, HeapScanDescData::rs_bitmapscan, HeapScanDescData::rs_ctup, HeapScanDescData::rs_key, HeapScanDescData::rs_nkeys, HeapScanDescData::rs_pageatatime, HeapScanDescData::rs_parallel, HeapScanDescData::rs_rd, HeapScanDescData::rs_samplescan, HeapScanDescData::rs_snapshot, HeapScanDescData::rs_strategy, HeapScanDescData::rs_temp_snap, and HeapTupleData::t_tableOid.

Referenced by heap_beginscan(), heap_beginscan_bm(), heap_beginscan_catalog(), heap_beginscan_parallel(), heap_beginscan_sampling(), and heap_beginscan_strat().

1446 {
1447  HeapScanDesc scan;
1448 
1449  /*
1450  * increment relation ref count while scanning relation
1451  *
1452  * This is just to make really sure the relcache entry won't go away while
1453  * the scan has a pointer to it. Caller should be holding the rel open
1454  * anyway, so this is redundant in all normal scenarios...
1455  */
1457 
1458  /*
1459  * allocate and initialize scan descriptor
1460  */
1461  scan = (HeapScanDesc) palloc(sizeof(HeapScanDescData));
1462 
1463  scan->rs_rd = relation;
1464  scan->rs_snapshot = snapshot;
1465  scan->rs_nkeys = nkeys;
1466  scan->rs_bitmapscan = is_bitmapscan;
1467  scan->rs_samplescan = is_samplescan;
1468  scan->rs_strategy = NULL; /* set in initscan */
1469  scan->rs_allow_strat = allow_strat;
1470  scan->rs_allow_sync = allow_sync;
1471  scan->rs_temp_snap = temp_snap;
1472  scan->rs_parallel = parallel_scan;
1473 
1474  /*
1475  * we can use page-at-a-time mode if it's an MVCC-safe snapshot
1476  */
1477  scan->rs_pageatatime = allow_pagemode && IsMVCCSnapshot(snapshot);
1478 
1479  /*
1480  * For a seqscan in a serializable transaction, acquire a predicate lock
1481  * on the entire relation. This is required not only to lock all the
1482  * matching tuples, but also to conflict with new insertions into the
1483  * table. In an indexscan, we take page locks on the index pages covering
1484  * the range specified in the scan qual, but in a heap scan there is
1485  * nothing more fine-grained to lock. A bitmap scan is a different story,
1486  * there we have already scanned the index and locked the index pages
1487  * covering the predicate. But in that case we still have to lock any
1488  * matching heap tuples.
1489  */
1490  if (!is_bitmapscan)
1491  PredicateLockRelation(relation, snapshot);
1492 
1493  /* we only need to set this up once */
1494  scan->rs_ctup.t_tableOid = RelationGetRelid(relation);
1495 
1496  /*
1497  * we do this here instead of in initscan() because heap_rescan also calls
1498  * initscan() and we don't want to allocate memory again
1499  */
1500  if (nkeys > 0)
1501  scan->rs_key = (ScanKey) palloc(sizeof(ScanKeyData) * nkeys);
1502  else
1503  scan->rs_key = NULL;
1504 
1505  initscan(scan, key, false);
1506 
1507  return scan;
1508 }
bool rs_allow_sync
Definition: relscan.h:55
void PredicateLockRelation(Relation relation, Snapshot snapshot)
Definition: predicate.c:2479
struct HeapScanDescData * HeapScanDesc
Definition: heapam.h:100
HeapTupleData rs_ctup
Definition: relscan.h:68
bool rs_bitmapscan
Definition: relscan.h:51
bool rs_pageatatime
Definition: relscan.h:53
ParallelHeapScanDesc rs_parallel
Definition: relscan.h:72
ScanKeyData * ScanKey
Definition: skey.h:75
Snapshot rs_snapshot
Definition: relscan.h:48
Oid t_tableOid
Definition: htup.h:66
bool rs_temp_snap
Definition: relscan.h:56
void RelationIncrementReferenceCount(Relation rel)
Definition: relcache.c:2123
BufferAccessStrategy rs_strategy
Definition: relscan.h:63
Relation rs_rd
Definition: relscan.h:47
#define NULL
Definition: c.h:229
#define IsMVCCSnapshot(snapshot)
Definition: tqual.h:31
void * palloc(Size size)
Definition: mcxt.c:849
bool rs_allow_strat
Definition: relscan.h:54
static void initscan(HeapScanDesc scan, ScanKey key, bool keep_startblock)
Definition: heapam.c:214
bool rs_samplescan
Definition: relscan.h:52
#define RelationGetRelid(relation)
Definition: rel.h:417
ScanKey rs_key
Definition: relscan.h:50
HeapScanDesc heap_beginscan_parallel ( Relation  relation,
ParallelHeapScanDesc  parallel_scan 
)

Definition at line 1650 of file heapam.c.

References Assert, heap_beginscan_internal(), ParallelHeapScanDescData::phs_relid, ParallelHeapScanDescData::phs_snapshot_data, RegisterSnapshot(), RelationGetRelid, and RestoreSnapshot().

Referenced by ExecSeqScanInitializeDSM(), and ExecSeqScanInitializeWorker().

1651 {
1652  Snapshot snapshot;
1653 
1654  Assert(RelationGetRelid(relation) == parallel_scan->phs_relid);
1655  snapshot = RestoreSnapshot(parallel_scan->phs_snapshot_data);
1656  RegisterSnapshot(snapshot);
1657 
1658  return heap_beginscan_internal(relation, snapshot, 0, NULL, parallel_scan,
1659  true, true, true, false, false, true);
1660 }
char phs_snapshot_data[FLEXIBLE_ARRAY_MEMBER]
Definition: relscan.h:41
Snapshot RestoreSnapshot(char *start_address)
Definition: snapmgr.c:2078
Snapshot RegisterSnapshot(Snapshot snapshot)
Definition: snapmgr.c:858
static HeapScanDesc heap_beginscan_internal(Relation relation, Snapshot snapshot, int nkeys, ScanKey key, ParallelHeapScanDesc parallel_scan, bool allow_strat, bool allow_sync, bool allow_pagemode, bool is_bitmapscan, bool is_samplescan, bool temp_snap)
Definition: heapam.c:1437
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
#define RelationGetRelid(relation)
Definition: rel.h:417
HeapScanDesc heap_beginscan_sampling ( Relation  relation,
Snapshot  snapshot,
int  nkeys,
ScanKey  key,
bool  allow_strat,
bool  allow_sync,
bool  allow_pagemode 
)

Definition at line 1427 of file heapam.c.

References heap_beginscan_internal().

Referenced by tablesample_init().

1430 {
1431  return heap_beginscan_internal(relation, snapshot, nkeys, key, NULL,
1432  allow_strat, allow_sync, allow_pagemode,
1433  false, true, false);
1434 }
static HeapScanDesc heap_beginscan_internal(Relation relation, Snapshot snapshot, int nkeys, ScanKey key, ParallelHeapScanDesc parallel_scan, bool allow_strat, bool allow_sync, bool allow_pagemode, bool is_bitmapscan, bool is_samplescan, bool temp_snap)
Definition: heapam.c:1437
#define NULL
Definition: c.h:229
HeapScanDesc heap_beginscan_strat ( Relation  relation,
Snapshot  snapshot,
int  nkeys,
ScanKey  key,
bool  allow_strat,
bool  allow_sync 
)

Definition at line 1409 of file heapam.c.

References heap_beginscan_internal().

Referenced by IndexBuildHeapRangeScan(), IndexCheckExclusion(), pgstat_heap(), systable_beginscan(), and validate_index_heapscan().

1412 {
1413  return heap_beginscan_internal(relation, snapshot, nkeys, key, NULL,
1414  allow_strat, allow_sync, true,
1415  false, false, false);
1416 }
static HeapScanDesc heap_beginscan_internal(Relation relation, Snapshot snapshot, int nkeys, ScanKey key, ParallelHeapScanDesc parallel_scan, bool allow_strat, bool allow_sync, bool allow_pagemode, bool is_bitmapscan, bool is_samplescan, bool temp_snap)
Definition: heapam.c:1437
#define NULL
Definition: c.h:229
HTSU_Result heap_delete ( Relation  relation,
ItemPointer  tid,
CommandId  cid,
Snapshot  crosscheck,
bool  wait,
HeapUpdateFailureData hufd 
)

Definition at line 3011 of file heapam.c.

References Assert, buffer, BUFFER_LOCK_EXCLUSIVE, BUFFER_LOCK_UNLOCK, BufferGetBlockNumber(), BufferGetPage, CacheInvalidateHeapTuple(), CheckForSerializableConflictIn(), HeapUpdateFailureData::cmax, compute_infobits(), compute_new_xmax_infomask(), HeapUpdateFailureData::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_XMAX_BITS, HEAP_XMAX_INVALID, HEAP_XMAX_IS_LOCKED_ONLY, HEAP_XMAX_IS_MULTI, HeapTupleBeingUpdated, HeapTupleHasExternal, HeapTupleHeaderAdjustCmax(), HeapTupleHeaderClearHotUpdated, HeapTupleHeaderGetCmax(), HeapTupleHeaderGetRawXmax, HeapTupleHeaderGetUpdateXid, HeapTupleHeaderIsOnlyLocked(), HeapTupleHeaderSetCmax, HeapTupleHeaderSetXmax, HeapTupleInvisible, HeapTupleMayBeUpdated, HeapTupleSatisfiesUpdate(), HeapTupleSatisfiesVisibility, HeapTupleSelfUpdated, HeapTupleUpdated, xl_heap_delete::infobits_set, InvalidBuffer, InvalidCommandId, InvalidSnapshot, IsInParallelMode(), ItemIdGetLength, ItemIdIsNormal, ItemPointerGetBlockNumber, ItemPointerGetOffsetNumber, ItemPointerIsValid, LockBuffer(), LockTupleExclusive, LockWaitBlock, log_heap_new_cid(), MarkBufferDirty(), MultiXactIdSetOldestMember(), MultiXactIdWait(), MultiXactStatusUpdate, NULL, xl_heap_delete::offnum, PageClearAllVisible, PageGetItem, PageGetItemId, PageIsAllVisible, PageSetLSN, PageSetPrunable, pgstat_count_heap_delete(), RelationData::rd_rel, ReadBuffer(), REGBUF_STANDARD, RelationGetRelid, RelationIsAccessibleInLogicalDecoding, RelationNeedsWAL, ReleaseBuffer(), RELKIND_MATVIEW, RELKIND_RELATION, REPLICA_IDENTITY_FULL, result, 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, toast_delete(), 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, XLOG_HEAP_DELETE, XLOG_INCLUDE_ORIGIN, XLogBeginInsert(), XLogInsert(), XLogRegisterBuffer(), XLogRegisterData(), XLogSetRecordFlags(), XLTW_Delete, HeapUpdateFailureData::xmax, xl_heap_delete::xmax, and xmax_infomask_changed().

Referenced by ExecDelete(), and simple_heap_delete().

3014 {
3017  ItemId lp;
3018  HeapTupleData tp;
3019  Page page;
3020  BlockNumber block;
3021  Buffer buffer;
3022  Buffer vmbuffer = InvalidBuffer;
3023  TransactionId new_xmax;
3024  uint16 new_infomask,
3025  new_infomask2;
3026  bool have_tuple_lock = false;
3027  bool iscombo;
3028  bool all_visible_cleared = false;
3029  HeapTuple old_key_tuple = NULL; /* replica identity of the tuple */
3030  bool old_key_copied = false;
3031 
3032  Assert(ItemPointerIsValid(tid));
3033 
3034  /*
3035  * Forbid this during a parallel operation, lest it allocate a combocid.
3036  * Other workers might need that combocid for visibility checks, and we
3037  * have no provision for broadcasting it to them.
3038  */
3039  if (IsInParallelMode())
3040  ereport(ERROR,
3041  (errcode(ERRCODE_INVALID_TRANSACTION_STATE),
3042  errmsg("cannot delete tuples during a parallel operation")));
3043 
3044  block = ItemPointerGetBlockNumber(tid);
3045  buffer = ReadBuffer(relation, block);
3046  page = BufferGetPage(buffer);
3047 
3048  /*
3049  * Before locking the buffer, pin the visibility map page if it appears to
3050  * be necessary. Since we haven't got the lock yet, someone else might be
3051  * in the middle of changing this, so we'll need to recheck after we have
3052  * the lock.
3053  */
3054  if (PageIsAllVisible(page))
3055  visibilitymap_pin(relation, block, &vmbuffer);
3056 
3058 
3059  /*
3060  * If we didn't pin the visibility map page and the page has become all
3061  * visible while we were busy locking the buffer, we'll have to unlock and
3062  * re-lock, to avoid holding the buffer lock across an I/O. That's a bit
3063  * unfortunate, but hopefully shouldn't happen often.
3064  */
3065  if (vmbuffer == InvalidBuffer && PageIsAllVisible(page))
3066  {
3067  LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
3068  visibilitymap_pin(relation, block, &vmbuffer);
3070  }
3071 
3072  lp = PageGetItemId(page, ItemPointerGetOffsetNumber(tid));
3073  Assert(ItemIdIsNormal(lp));
3074 
3075  tp.t_tableOid = RelationGetRelid(relation);
3076  tp.t_data = (HeapTupleHeader) PageGetItem(page, lp);
3077  tp.t_len = ItemIdGetLength(lp);
3078  tp.t_self = *tid;
3079 
3080 l1:
3081  result = HeapTupleSatisfiesUpdate(&tp, cid, buffer);
3082 
3083  if (result == HeapTupleInvisible)
3084  {
3085  UnlockReleaseBuffer(buffer);
3086  ereport(ERROR,
3087  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
3088  errmsg("attempted to delete invisible tuple")));
3089  }
3090  else if (result == HeapTupleBeingUpdated && wait)
3091  {
3092  TransactionId xwait;
3093  uint16 infomask;
3094 
3095  /* must copy state data before unlocking buffer */
3096  xwait = HeapTupleHeaderGetRawXmax(tp.t_data);
3097  infomask = tp.t_data->t_infomask;
3098 
3099  /*
3100  * Sleep until concurrent transaction ends -- except when there's a
3101  * single locker and it's our own transaction. Note we don't care
3102  * which lock mode the locker has, because we need the strongest one.
3103  *
3104  * Before sleeping, we need to acquire tuple lock to establish our
3105  * priority for the tuple (see heap_lock_tuple). LockTuple will
3106  * release us when we are next-in-line for the tuple.
3107  *
3108  * If we are forced to "start over" below, we keep the tuple lock;
3109  * this arranges that we stay at the head of the line while rechecking
3110  * tuple state.
3111  */
3112  if (infomask & HEAP_XMAX_IS_MULTI)
3113  {
3114  /* wait for multixact */
3115  if (DoesMultiXactIdConflict((MultiXactId) xwait, infomask,
3117  {
3118  LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
3119 
3120  /* acquire tuple lock, if necessary */
3122  LockWaitBlock, &have_tuple_lock);
3123 
3124  /* wait for multixact */
3126  relation, &(tp.t_self), XLTW_Delete,
3127  NULL);
3129 
3130  /*
3131  * If xwait had just locked the tuple then some other xact
3132  * could update this tuple before we get to this point. Check
3133  * for xmax change, and start over if so.
3134  */
3135  if (xmax_infomask_changed(tp.t_data->t_infomask, infomask) ||
3137  xwait))
3138  goto l1;
3139  }
3140 
3141  /*
3142  * You might think the multixact is necessarily done here, but not
3143  * so: it could have surviving members, namely our own xact or
3144  * other subxacts of this backend. It is legal for us to delete
3145  * the tuple in either case, however (the latter case is
3146  * essentially a situation of upgrading our former shared lock to
3147  * exclusive). We don't bother changing the on-disk hint bits
3148  * since we are about to overwrite the xmax altogether.
3149  */
3150  }
3151  else if (!TransactionIdIsCurrentTransactionId(xwait))
3152  {
3153  /*
3154  * Wait for regular transaction to end; but first, acquire tuple
3155  * lock.
3156  */
3157  LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
3159  LockWaitBlock, &have_tuple_lock);
3160  XactLockTableWait(xwait, relation, &(tp.t_self), XLTW_Delete);
3162 
3163  /*
3164  * xwait is done, but if xwait had just locked the tuple then some
3165  * other xact could update this tuple before we get to this point.
3166  * Check for xmax change, and start over if so.
3167  */
3168  if (xmax_infomask_changed(tp.t_data->t_infomask, infomask) ||
3170  xwait))
3171  goto l1;
3172 
3173  /* Otherwise check if it committed or aborted */
3174  UpdateXmaxHintBits(tp.t_data, buffer, xwait);
3175  }
3176 
3177  /*
3178  * We may overwrite if previous xmax aborted, or if it committed but
3179  * only locked the tuple without updating it.
3180  */
3181  if ((tp.t_data->t_infomask & HEAP_XMAX_INVALID) ||
3184  result = HeapTupleMayBeUpdated;
3185  else
3186  result = HeapTupleUpdated;
3187  }
3188 
3189  if (crosscheck != InvalidSnapshot && result == HeapTupleMayBeUpdated)
3190  {
3191  /* Perform additional check for transaction-snapshot mode RI updates */
3192  if (!HeapTupleSatisfiesVisibility(&tp, crosscheck, buffer))
3193  result = HeapTupleUpdated;
3194  }
3195 
3196  if (result != HeapTupleMayBeUpdated)
3197  {
3198  Assert(result == HeapTupleSelfUpdated ||
3199  result == HeapTupleUpdated ||
3200  result == HeapTupleBeingUpdated);
3202  hufd->ctid = tp.t_data->t_ctid;
3204  if (result == HeapTupleSelfUpdated)
3205  hufd->cmax = HeapTupleHeaderGetCmax(tp.t_data);
3206  else
3207  hufd->cmax = InvalidCommandId;
3208  UnlockReleaseBuffer(buffer);
3209  if (have_tuple_lock)
3210  UnlockTupleTuplock(relation, &(tp.t_self), LockTupleExclusive);
3211  if (vmbuffer != InvalidBuffer)
3212  ReleaseBuffer(vmbuffer);
3213  return result;
3214  }
3215 
3216  /*
3217  * We're about to do the actual delete -- check for conflict first, to
3218  * avoid possibly having to roll back work we've just done.
3219  *
3220  * This is safe without a recheck as long as there is no possibility of
3221  * another process scanning the page between this check and the delete
3222  * being visible to the scan (i.e., an exclusive buffer content lock is
3223  * continuously held from this point until the tuple delete is visible).
3224  */
3225  CheckForSerializableConflictIn(relation, &tp, buffer);
3226 
3227  /* replace cid with a combo cid if necessary */
3228  HeapTupleHeaderAdjustCmax(tp.t_data, &cid, &iscombo);
3229 
3230  /*
3231  * Compute replica identity tuple before entering the critical section so
3232  * we don't PANIC upon a memory allocation failure.
3233  */
3234  old_key_tuple = ExtractReplicaIdentity(relation, &tp, true, &old_key_copied);
3235 
3236  /*
3237  * If this is the first possibly-multixact-able operation in the current
3238  * transaction, set my per-backend OldestMemberMXactId setting. We can be
3239  * certain that the transaction will never become a member of any older
3240  * MultiXactIds than that. (We have to do this even if we end up just
3241  * using our own TransactionId below, since some other backend could
3242  * incorporate our XID into a MultiXact immediately afterwards.)
3243  */
3245 
3248  xid, LockTupleExclusive, true,
3249  &new_xmax, &new_infomask, &new_infomask2);
3250 
3252 
3253  /*
3254  * If this transaction commits, the tuple will become DEAD sooner or
3255  * later. Set flag that this page is a candidate for pruning once our xid
3256  * falls below the OldestXmin horizon. If the transaction finally aborts,
3257  * the subsequent page pruning will be a no-op and the hint will be
3258  * cleared.
3259  */
3260  PageSetPrunable(page, xid);
3261 
3262  if (PageIsAllVisible(page))
3263  {
3264  all_visible_cleared = true;
3265  PageClearAllVisible(page);
3266  visibilitymap_clear(relation, BufferGetBlockNumber(buffer),
3267  vmbuffer, VISIBILITYMAP_VALID_BITS);
3268  }
3269 
3270  /* store transaction information of xact deleting the tuple */
3273  tp.t_data->t_infomask |= new_infomask;
3274  tp.t_data->t_infomask2 |= new_infomask2;
3276  HeapTupleHeaderSetXmax(tp.t_data, new_xmax);
3277  HeapTupleHeaderSetCmax(tp.t_data, cid, iscombo);
3278  /* Make sure there is no forward chain link in t_ctid */
3279  tp.t_data->t_ctid = tp.t_self;
3280 
3281  MarkBufferDirty(buffer);
3282 
3283  /*
3284  * XLOG stuff
3285  *
3286  * NB: heap_abort_speculative() uses the same xlog record and replay
3287  * routines.
3288  */
3289  if (RelationNeedsWAL(relation))
3290  {
3291  xl_heap_delete xlrec;
3292  XLogRecPtr recptr;
3293 
3294  /* For logical decode we need combocids to properly decode the catalog */
3296  log_heap_new_cid(relation, &tp);
3297 
3298  xlrec.flags = all_visible_cleared ? XLH_DELETE_ALL_VISIBLE_CLEARED : 0;
3300  tp.t_data->t_infomask2);
3302  xlrec.xmax = new_xmax;
3303 
3304  if (old_key_tuple != NULL)
3305  {
3306  if (relation->rd_rel->relreplident == REPLICA_IDENTITY_FULL)
3308  else
3310  }
3311 
3312  XLogBeginInsert();
3313  XLogRegisterData((char *) &xlrec, SizeOfHeapDelete);
3314 
3315  XLogRegisterBuffer(0, buffer, REGBUF_STANDARD);
3316 
3317  /*
3318  * Log replica identity of the deleted tuple if there is one
3319  */
3320  if (old_key_tuple != NULL)
3321  {
3322  xl_heap_header xlhdr;
3323 
3324  xlhdr.t_infomask2 = old_key_tuple->t_data->t_infomask2;
3325  xlhdr.t_infomask = old_key_tuple->t_data->t_infomask;
3326  xlhdr.t_hoff = old_key_tuple->t_data->t_hoff;
3327 
3328  XLogRegisterData((char *) &xlhdr, SizeOfHeapHeader);
3329  XLogRegisterData((char *) old_key_tuple->t_data
3331  old_key_tuple->t_len
3333  }
3334 
3335  /* filtering by origin on a row level is much more efficient */
3337 
3338  recptr = XLogInsert(RM_HEAP_ID, XLOG_HEAP_DELETE);
3339 
3340  PageSetLSN(page, recptr);
3341  }
3342 
3343  END_CRIT_SECTION();
3344 
3345  LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
3346 
3347  if (vmbuffer != InvalidBuffer)
3348  ReleaseBuffer(vmbuffer);
3349 
3350  /*
3351  * If the tuple has toasted out-of-line attributes, we need to delete
3352  * those items too. We have to do this before releasing the buffer
3353  * because we need to look at the contents of the tuple, but it's OK to
3354  * release the content lock on the buffer first.
3355  */
3356  if (relation->rd_rel->relkind != RELKIND_RELATION &&
3357  relation->rd_rel->relkind != RELKIND_MATVIEW)
3358  {
3359  /* toast table entries should never be recursively toasted */
3361  }
3362  else if (HeapTupleHasExternal(&tp))
3363  toast_delete(relation, &tp, false);
3364 
3365  /*
3366  * Mark tuple for invalidation from system caches at next command
3367  * boundary. We have to do this before releasing the buffer because we
3368  * need to look at the contents of the tuple.
3369  */
3370  CacheInvalidateHeapTuple(relation, &tp, NULL);
3371 
3372  /* Now we can release the buffer */
3373  ReleaseBuffer(buffer);
3374 
3375  /*
3376  * Release the lmgr tuple lock, if we had it.
3377  */
3378  if (have_tuple_lock)
3379  UnlockTupleTuplock(relation, &(tp.t_self), LockTupleExclusive);
3380 
3381  pgstat_count_heap_delete(relation);
3382 
3383  if (old_key_tuple != NULL && old_key_copied)
3384  heap_freetuple(old_key_tuple);
3385 
3386  return HeapTupleMayBeUpdated;
3387 }
#define HeapTupleHeaderGetUpdateXid(tup)
Definition: htup_details.h:359
bool HeapTupleHeaderIsOnlyLocked(HeapTupleHeader tuple)
Definition: tqual.c:1585
#define ItemPointerIsValid(pointer)
Definition: itemptr.h:59
#define BUFFER_LOCK_UNLOCK
Definition: bufmgr.h:87
#define SizeofHeapTupleHeader
Definition: htup_details.h:170
static XLogRecPtr log_heap_new_cid(Relation relation, HeapTuple tup)
Definition: heapam.c:7694
#define HEAP_XMAX_BITS
Definition: htup_details.h:256
static uint8 compute_infobits(uint16 infomask, uint16 infomask2)
Definition: heapam.c:2952
void CacheInvalidateHeapTuple(Relation relation, HeapTuple tuple, HeapTuple newtuple)
Definition: inval.c:1094
#define TransactionIdEquals(id1, id2)
Definition: transam.h:43
#define PageIsAllVisible(page)
Definition: bufpage.h:382
uint32 TransactionId
Definition: c.h:397
HTSU_Result HeapTupleSatisfiesUpdate(HeapTuple htup, CommandId curcid, Buffer buffer)
Definition: tqual.c:460
bool TransactionIdIsCurrentTransactionId(TransactionId xid)
Definition: xact.c:773
void visibilitymap_pin(Relation rel, BlockNumber heapBlk, Buffer *buf)
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:1450
void XLogRegisterBuffer(uint8 block_id, Buffer buffer, uint8 flags)
Definition: xloginsert.c:213
HeapTupleHeaderData * HeapTupleHeader
Definition: htup.h:23
static bool xmax_infomask_changed(uint16 new_infomask, uint16 old_infomask)
Definition: heapam.c:2974
#define HeapTupleHeaderClearHotUpdated(tup)
Definition: htup_details.h:497
#define END_CRIT_SECTION()
Definition: miscadmin.h:132
#define RELKIND_MATVIEW
Definition: pg_class.h:165
#define InvalidBuffer
Definition: buf.h:25
uint16 t_infomask2
Definition: heapam_xlog.h:122
#define PageSetPrunable(page, xid)
Definition: bufpage.h:395
#define START_CRIT_SECTION()
Definition: miscadmin.h:130
int errcode(int sqlerrcode)
Definition: elog.c:575
#define XLOG_INCLUDE_ORIGIN
Definition: xlog.h:192
return result
Definition: formatting.c:1632
uint32 BlockNumber
Definition: block.h:31
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3309
#define BUFFER_LOCK_EXCLUSIVE
Definition: bufmgr.h:89
Form_pg_class rd_rel
Definition: rel.h:114
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1372
void CheckForSerializableConflictIn(Relation relation, HeapTuple tuple, Buffer buffer)
Definition: predicate.c:4307
#define UnlockTupleTuplock(rel, tup, mode)
Definition: heapam.c:181
#define HeapTupleSatisfiesVisibility(tuple, snapshot, buffer)
Definition: tqual.h:45
OffsetNumber offnum
Definition: heapam_xlog.h:105
void MultiXactIdSetOldestMember(void)
Definition: multixact.c:623
#define VISIBILITYMAP_VALID_BITS
Definition: visibilitymap.h:28
HeapTupleHeader t_data
Definition: htup.h:67
#define HeapTupleHeaderGetRawXmax(tup)
Definition: htup_details.h:369
unsigned short uint16
Definition: c.h:267
#define ItemIdGetLength(itemId)
Definition: itemid.h:58
bool IsInParallelMode(void)
Definition: xact.c:913
bool visibilitymap_clear(Relation rel, BlockNumber heapBlk, Buffer buf, uint8 flags)
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3332
#define REPLICA_IDENTITY_FULL
Definition: pg_class.h:179
#define ERROR
Definition: elog.h:43
#define HEAP_XMAX_INVALID
Definition: htup_details.h:193
ItemPointerData t_ctid
Definition: htup_details.h:150
ItemPointerData t_self
Definition: htup.h:65
TransactionId xmax
Definition: heapam_xlog.h:104
static void MultiXactIdWait(MultiXactId multi, MultiXactStatus status, uint16 infomask, Relation rel, ItemPointer ctid, XLTW_Oper oper, int *remaining)
Definition: heapam.c:7110
TransactionId GetCurrentTransactionId(void)
Definition: xact.c:417
uint32 t_len
Definition: htup.h:64
#define SizeOfHeapDelete
Definition: heapam_xlog.h:110
#define REGBUF_STANDARD
Definition: xloginsert.h:35
#define XLH_DELETE_CONTAINS_OLD_KEY
Definition: heapam_xlog.h:94
CommandId cmax
Definition: heapam.h:72
#define HeapTupleHeaderSetXmax(tup, xid)
Definition: htup_details.h:374
HTSU_Result
Definition: snapshot.h:119
Oid t_tableOid
Definition: htup.h:66
void XLogSetRecordFlags(uint8 flags)
Definition: xloginsert.c:397
#define HeapTupleHeaderSetCmax(tup, cid, iscombo)
Definition: htup_details.h:399
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
#define ereport(elevel, rest)
Definition: elog.h:122
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:5255
TransactionId xmax
Definition: heapam.h:71
#define PageGetItemId(page, offsetNumber)
Definition: bufpage.h:232
#define InvalidSnapshot
Definition: snapshot.h:25
void XLogRegisterData(char *data, int len)
Definition: xloginsert.c:323
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:415
#define RelationIsAccessibleInLogicalDecoding(relation)
Definition: rel.h:560
#define InvalidCommandId
Definition: c.h:414
#define HEAP_XMAX_IS_LOCKED_ONLY(infomask)
Definition: htup_details.h:216
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3546
#define HEAP_KEYS_UPDATED
Definition: htup_details.h:264
#define HEAP_XMAX_IS_MULTI
Definition: htup_details.h:194
static void UpdateXmaxHintBits(HeapTupleHeader tuple, Buffer buffer, TransactionId xid)
Definition: heapam.c:2297
#define HEAP_MOVED
Definition: htup_details.h:202
static bool heap_acquire_tuplock(Relation relation, ItemPointer tid, LockTupleMode mode, LockWaitPolicy wait_policy, bool *have_tuple_lock)
Definition: heapam.c:5206
TransactionId MultiXactId
Definition: c.h:407
#define PageClearAllVisible(page)
Definition: bufpage.h:386
void XactLockTableWait(TransactionId xid, Relation rel, ItemPointer ctid, XLTW_Oper oper)
Definition: lmgr.c:554
#define NULL
Definition: c.h:229
uint64 XLogRecPtr
Definition: xlogdefs.h:21
#define Assert(condition)
Definition: c.h:675
uint8 infobits_set
Definition: heapam_xlog.h:106
static HeapTuple ExtractReplicaIdentity(Relation rel, HeapTuple tup, bool key_modified, bool *copy)
Definition: heapam.c:7770
CommandId HeapTupleHeaderGetCmax(HeapTupleHeader tup)
Definition: combocid.c:119
static bool DoesMultiXactIdConflict(MultiXactId multi, uint16 infomask, LockTupleMode lockmode)
Definition: heapam.c:6943
#define ItemIdIsNormal(itemId)
Definition: itemid.h:98
WalTimeSample buffer[LAG_TRACKER_BUFFER_SIZE]
Definition: walsender.c:211
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition: bufmgr.c:594
uint16 t_infomask
Definition: heapam_xlog.h:123
#define ItemPointerGetOffsetNumber(pointer)
Definition: itemptr.h:94
#define RelationNeedsWAL(relation)
Definition: rel.h:506
void pgstat_count_heap_delete(Relation rel)
Definition: pgstat.c:1953
void HeapTupleHeaderAdjustCmax(HeapTupleHeader tup, CommandId *cmax, bool *iscombo)
Definition: combocid.c:154
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:2605
#define HeapTupleHasExternal(tuple)
Definition: htup_details.h:674
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define XLH_DELETE_ALL_VISIBLE_CLEARED
Definition: heapam_xlog.h:92
void toast_delete(Relation rel, HeapTuple oldtup, bool is_speculative)
Definition: tuptoaster.c:464
ItemPointerData ctid
Definition: heapam.h:70
#define ItemPointerGetBlockNumber(pointer)
Definition: itemptr.h:75
#define RELKIND_RELATION
Definition: pg_class.h:160
void XLogBeginInsert(void)
Definition: xloginsert.c:120
#define PageSetLSN(page, lsn)
Definition: bufpage.h:365
int Buffer
Definition: buf.h:23
#define XLOG_HEAP_DELETE
Definition: heapam_xlog.h:33
#define RelationGetRelid(relation)
Definition: rel.h:417
#define PageGetItem(page, itemId)
Definition: bufpage.h:337
#define SizeOfHeapHeader
Definition: heapam_xlog.h:127
Pointer Page
Definition: bufpage.h:74
#define XLH_DELETE_CONTAINS_OLD_TUPLE
Definition: heapam_xlog.h:93
void heap_endscan ( HeapScanDesc  scan)

Definition at line 1578 of file heapam.c.

References BufferIsValid, FreeAccessStrategy(), pfree(), RelationDecrementReferenceCount(), ReleaseBuffer(), HeapScanDescData::rs_cbuf, HeapScanDescData::rs_key, HeapScanDescData::rs_rd, HeapScanDescData::rs_snapshot, HeapScanDescData::rs_strategy, HeapScanDescData::rs_temp_snap, and UnregisterSnapshot().

Referenced by AlterDomainNotNull(), AlterTableMoveAll(), AlterTableSpaceOptions(), ATRewriteTable(), boot_openrel(), check_db_file_conflict(), copy_heap_data(), CopyTo(), createdb(), DefineQueryRewrite(), do_autovacuum(), DropSetting(), DropTableSpace(), ExecEndBitmapHeapScan(), ExecEndSampleScan(), ExecEndSeqScan(), find_typed_table_dependencies(), get_database_list(), get_rel_oids(), get_subscription_list(), get_tables_to_cluster(), get_tablespace_name(), get_tablespace_oid(), GetAllTablesPublicationRelations(), getRelationsInNamespace(), gettype(), index_update_stats(), IndexBuildHeapRangeScan(), IndexCheckExclusion(), objectsInSchemaToOids(), pgrowlocks(), pgstat_collect_oids(), pgstat_heap(), ReindexMultipleTables(), RelationFindReplTupleSeq(), remove_dbtablespaces(), RemoveConversionById(), RemoveSubscriptionRel(), RenameTableSpace(), systable_endscan(), ThereIsAtLeastOneRole(), vac_truncate_clog(), validate_index_heapscan(), validateCheckConstraint(), validateDomainConstraint(), and validateForeignKeyConstraint().

1579 {
1580  /* Note: no locking manipulations needed */
1581 
1582  /*
1583  * unpin scan buffers
1584  */
1585  if (BufferIsValid(scan->rs_cbuf))
1586  ReleaseBuffer(scan->rs_cbuf);
1587 
1588  /*
1589  * decrement relation reference count and free scan descriptor storage
1590  */
1592 
1593  if (scan->rs_key)
1594  pfree(scan->rs_key);
1595 
1596  if (scan->rs_strategy != NULL)
1598 
1599  if (scan->rs_temp_snap)
1601 
1602  pfree(scan);
1603 }
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3309
void pfree(void *pointer)
Definition: mcxt.c:950
void RelationDecrementReferenceCount(Relation rel)
Definition: relcache.c:2136
Snapshot rs_snapshot
Definition: relscan.h:48
void UnregisterSnapshot(Snapshot snapshot)
Definition: snapmgr.c:900
bool rs_temp_snap
Definition: relscan.h:56
BufferAccessStrategy rs_strategy
Definition: relscan.h:63
Relation rs_rd
Definition: relscan.h:47
Buffer rs_cbuf
Definition: relscan.h:70
void FreeAccessStrategy(BufferAccessStrategy strategy)
Definition: freelist.c:580
#define NULL
Definition: c.h:229
#define BufferIsValid(bufnum)
Definition: bufmgr.h:114
ScanKey rs_key
Definition: relscan.h:50
void heap_execute_freeze_tuple ( HeapTupleHeader  tuple,
xl_heap_freeze_tuple frz 
)

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

6749 {
6750  HeapTupleHeaderSetXmax(tuple, frz->xmax);
6751 
6752  if (frz->frzflags & XLH_FREEZE_XVAC)
6754 
6755  if (frz->frzflags & XLH_INVALID_XVAC)
6757 
6758  tuple->t_infomask = frz->t_infomask;
6759  tuple->t_infomask2 = frz->t_infomask2;
6760 }
#define HeapTupleHeaderSetXvac(tup, xid)
Definition: htup_details.h:417
#define HeapTupleHeaderSetXmax(tup, xid)
Definition: htup_details.h:374
#define InvalidTransactionId
Definition: transam.h:31
#define FrozenTransactionId
Definition: transam.h:33
TransactionId xmax
Definition: heapam_xlog.h:298
#define XLH_INVALID_XVAC
Definition: heapam_xlog.h:294
#define XLH_FREEZE_XVAC
Definition: heapam_xlog.h:293
bool heap_fetch ( Relation  relation,
Snapshot  snapshot,
HeapTuple  tuple,
Buffer userbuf,
bool  keep_buf,
Relation  stats_relation 
)

Definition at line 1862 of file heapam.c.

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

Referenced by AfterTriggerExecute(), EvalPlanQualFetch(), EvalPlanQualFetchRowMarks(), ExecCheckTIDVisible(), ExecDelete(), ExecLockRows(), heap_lock_updated_tuple_rec(), and TidNext().

1868 {
1869  ItemPointer tid = &(tuple->t_self);
1870  ItemId lp;
1871  Buffer buffer;
1872  Page page;
1873  OffsetNumber offnum;
1874  bool valid;
1875 
1876  /*
1877  * Fetch and pin the appropriate page of the relation.
1878  */
1879  buffer = ReadBuffer(relation, ItemPointerGetBlockNumber(tid));
1880 
1881  /*
1882  * Need share lock on buffer to examine tuple commit status.
1883  */
1884  LockBuffer(buffer, BUFFER_LOCK_SHARE);
1885  page = BufferGetPage(buffer);
1886  TestForOldSnapshot(snapshot, relation, page);
1887 
1888  /*
1889  * We'd better check for out-of-range offnum in case of VACUUM since the
1890  * TID was obtained.
1891  */
1892  offnum = ItemPointerGetOffsetNumber(tid);
1893  if (offnum < FirstOffsetNumber || offnum > PageGetMaxOffsetNumber(page))
1894  {
1895  LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
1896  if (keep_buf)
1897  *userbuf = buffer;
1898  else
1899  {
1900  ReleaseBuffer(buffer);
1901  *userbuf = InvalidBuffer;
1902  }
1903  tuple->t_data = NULL;
1904  return false;
1905  }
1906 
1907  /*
1908  * get the item line pointer corresponding to the requested tid
1909  */
1910  lp = PageGetItemId(page, offnum);
1911 
1912  /*
1913  * Must check for deleted tuple.
1914  */
1915  if (!ItemIdIsNormal(lp))
1916  {
1917  LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
1918  if (keep_buf)
1919  *userbuf = buffer;
1920  else
1921  {
1922  ReleaseBuffer(buffer);
1923  *userbuf = InvalidBuffer;
1924  }
1925  tuple->t_data = NULL;
1926  return false;
1927  }
1928 
1929  /*
1930  * fill in *tuple fields
1931  */
1932  tuple->t_data = (HeapTupleHeader) PageGetItem(page, lp);
1933  tuple->t_len = ItemIdGetLength(lp);
1934  tuple->t_tableOid = RelationGetRelid(relation);
1935 
1936  /*
1937  * check time qualification of tuple, then release lock
1938  */
1939  valid = HeapTupleSatisfiesVisibility(tuple, snapshot, buffer);
1940 
1941  if (valid)
1942  PredicateLockTuple(relation, tuple, snapshot);
1943 
1944  CheckForSerializableConflictOut(valid, relation, tuple, buffer, snapshot);
1945 
1946  LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
1947 
1948  if (valid)
1949  {
1950  /*
1951  * All checks passed, so return the tuple as valid. Caller is now
1952  * responsible for releasing the buffer.
1953  */
1954  *userbuf = buffer;
1955 
1956  /* Count the successful fetch against appropriate rel, if any */
1957  if (stats_relation != NULL)
1958  pgstat_count_heap_fetch(stats_relation);
1959 
1960  return true;
1961  }
1962 
1963  /* Tuple failed time qual, but maybe caller wants to see it anyway. */
1964  if (keep_buf)
1965  *userbuf = buffer;
1966  else
1967  {
1968  ReleaseBuffer(buffer);
1969  *userbuf = InvalidBuffer;
1970  }
1971 
1972  return false;
1973 }
#define BUFFER_LOCK_UNLOCK
Definition: bufmgr.h:87
static void TestForOldSnapshot(Snapshot snapshot, Relation relation, Page page)
Definition: bufmgr.h:265
HeapTupleHeaderData * HeapTupleHeader
Definition: htup.h:23
#define InvalidBuffer
Definition: buf.h:25
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3309
#define PageGetMaxOffsetNumber(page)
Definition: bufpage.h:354
void CheckForSerializableConflictOut(bool visible, Relation relation, HeapTuple tuple, Buffer buffer, Snapshot snapshot)
Definition: predicate.c:3926
#define HeapTupleSatisfiesVisibility(tuple, snapshot, buffer)
Definition: tqual.h:45
uint16 OffsetNumber
Definition: off.h:24
HeapTupleHeader t_data
Definition: htup.h:67
#define ItemIdGetLength(itemId)
Definition: itemid.h:58
ItemPointerData t_self
Definition: htup.h:65
#define pgstat_count_heap_fetch(rel)
Definition: pgstat.h:1258
uint32 t_len
Definition: htup.h:64
Oid t_tableOid
Definition: htup.h:66
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
#define PageGetItemId(page, offsetNumber)
Definition: bufpage.h:232
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3546
#define NULL
Definition: c.h:229
#define ItemIdIsNormal(itemId)
Definition: itemid.h:98
WalTimeSample buffer[LAG_TRACKER_BUFFER_SIZE]
Definition: walsender.c:211
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition: bufmgr.c:594
#define ItemPointerGetOffsetNumber(pointer)
Definition: itemptr.h:94
void PredicateLockTuple(Relation relation, HeapTuple tuple, Snapshot snapshot)
Definition: predicate.c:2524
#define BUFFER_LOCK_SHARE
Definition: bufmgr.h:88
#define ItemPointerGetBlockNumber(pointer)
Definition: itemptr.h:75
int Buffer
Definition: buf.h:23
#define RelationGetRelid(relation)
Definition: rel.h:417
#define PageGetItem(page, itemId)
Definition: bufpage.h:337
Pointer Page
Definition: bufpage.h:74
void heap_finish_speculative ( Relation  relation,
HeapTuple  tuple 
)

Definition at line 5963 of file heapam.c.

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

Referenced by ExecInsert().

5964 {
5965  Buffer buffer;
5966  Page page;
5967  OffsetNumber offnum;
5968  ItemId lp = NULL;
5969  HeapTupleHeader htup;
5970 
5971  buffer = ReadBuffer(relation, ItemPointerGetBlockNumber(&(tuple->t_self)));
5973  page = (Page) BufferGetPage(buffer);
5974 
5975  offnum = ItemPointerGetOffsetNumber(&(tuple->t_self));
5976  if (PageGetMaxOffsetNumber(page) >= offnum)
5977  lp = PageGetItemId(page, offnum);
5978 
5979  if (PageGetMaxOffsetNumber(page) < offnum || !ItemIdIsNormal(lp))
5980  elog(ERROR, "invalid lp");
5981 
5982  htup = (HeapTupleHeader) PageGetItem(page, lp);
5983 
5984  /* SpecTokenOffsetNumber should be distinguishable from any real offset */
5986  "invalid speculative token constant");
5987 
5988  /* NO EREPORT(ERROR) from here till changes are logged */
5990 
5992 
5993  MarkBufferDirty(buffer);
5994 
5995  /*
5996  * Replace the speculative insertion token with a real t_ctid, pointing to
5997  * itself like it does on regular tuples.
5998  */
5999  htup->t_ctid = tuple->t_self;
6000 
6001  /* XLOG stuff */
6002  if (RelationNeedsWAL(relation))
6003  {
6004  xl_heap_confirm xlrec;
6005  XLogRecPtr recptr;
6006 
6007  xlrec.offnum = ItemPointerGetOffsetNumber(&tuple->t_self);
6008 
6009  XLogBeginInsert();
6010 
6011  /* We want the same filtering on this as on a plain insert */
6013 
6014  XLogRegisterData((char *) &xlrec, SizeOfHeapConfirm);
6015  XLogRegisterBuffer(0, buffer, REGBUF_STANDARD);
6016 
6017  recptr = XLogInsert(RM_HEAP_ID, XLOG_HEAP_CONFIRM);
6018 
6019  PageSetLSN(page, recptr);
6020  }
6021 
6022  END_CRIT_SECTION();
6023 
6024  UnlockReleaseBuffer(buffer);
6025 }
OffsetNumber offnum
Definition: heapam_xlog.h:274
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:1450
void XLogRegisterBuffer(uint8 block_id, Buffer buffer, uint8 flags)
Definition: xloginsert.c:213
HeapTupleHeaderData * HeapTupleHeader
Definition: htup.h:23
#define MaxOffsetNumber
Definition: off.h:28
#define END_CRIT_SECTION()
Definition: miscadmin.h:132
#define HeapTupleHeaderIsSpeculative(tup)
Definition: htup_details.h:423
#define START_CRIT_SECTION()
Definition: miscadmin.h:130
#define XLOG_INCLUDE_ORIGIN
Definition: xlog.h:192
#define BUFFER_LOCK_EXCLUSIVE
Definition: bufmgr.h:89
#define PageGetMaxOffsetNumber(page)
Definition: bufpage.h:354
uint16 OffsetNumber
Definition: off.h:24
HeapTupleHeader t_data
Definition: htup.h:67
#define StaticAssertStmt(condition, errmessage)
Definition: c.h:757
#define SpecTokenOffsetNumber
Definition: htup_details.h:285
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3332
#define ERROR
Definition: elog.h:43
ItemPointerData t_ctid
Definition: htup_details.h:150
ItemPointerData t_self
Definition: htup.h:65
#define REGBUF_STANDARD
Definition: xloginsert.h:35
void XLogSetRecordFlags(uint8 flags)
Definition: xloginsert.c:397
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
#define SizeOfHeapConfirm
Definition: heapam_xlog.h:277
#define PageGetItemId(page, offsetNumber)
Definition: bufpage.h:232
void XLogRegisterData(char *data, int len)
Definition: xloginsert.c:323
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:415
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3546
#define NULL
Definition: c.h:229
uint64 XLogRecPtr
Definition: xlogdefs.h:21
#define Assert(condition)
Definition: c.h:675
#define ItemIdIsNormal(itemId)
Definition: itemid.h:98
WalTimeSample buffer[LAG_TRACKER_BUFFER_SIZE]
Definition: walsender.c:211
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition: bufmgr.c:594
#define ItemPointerGetOffsetNumber(pointer)
Definition: itemptr.h:94
#define RelationNeedsWAL(relation)
Definition: rel.h:506
#define elog
Definition: elog.h:219
#define ItemPointerGetBlockNumber(pointer)
Definition: itemptr.h:75
void XLogBeginInsert(void)
Definition: xloginsert.c:120
#define PageSetLSN(page, lsn)
Definition: bufpage.h:365
int Buffer
Definition: buf.h:23
#define PageGetItem(page, itemId)
Definition: bufpage.h:337
Pointer Page
Definition: bufpage.h:74
#define XLOG_HEAP_CONFIRM
Definition: heapam_xlog.h:37
bool heap_freeze_tuple ( HeapTupleHeader  tuple,
TransactionId  cutoff_xid,
TransactionId  cutoff_multi 
)

Definition at line 6769 of file heapam.c.

References heap_execute_freeze_tuple(), and heap_prepare_freeze_tuple().

Referenced by rewrite_heap_tuple().

6771 {
6773  bool do_freeze;
6774  bool tuple_totally_frozen;
6775 
6776  do_freeze = heap_prepare_freeze_tuple(tuple, cutoff_xid, cutoff_multi,
6777  &frz, &tuple_totally_frozen);
6778 
6779  /*
6780  * Note that because this is not a WAL-logged operation, we don't need to
6781  * fill in the offset in the freeze record.
6782  */
6783 
6784  if (do_freeze)
6785  heap_execute_freeze_tuple(tuple, &frz);
6786  return do_freeze;
6787 }
void heap_execute_freeze_tuple(HeapTupleHeader tuple, xl_heap_freeze_tuple *frz)
Definition: heapam.c:6748
bool heap_prepare_freeze_tuple(HeapTupleHeader tuple, TransactionId cutoff_xid, TransactionId cutoff_multi, xl_heap_freeze_tuple *frz, bool *totally_frozen_p)
Definition: heapam.c:6570
void heap_get_latest_tid ( Relation  relation,
Snapshot  snapshot,
ItemPointer  tid 
)

Definition at line 2167 of file heapam.c.

References buffer, BUFFER_LOCK_SHARE, BufferGetPage, CheckForSerializableConflictOut(), elog, ERROR, HEAP_XMAX_INVALID, HeapTupleHeaderGetUpdateXid, HeapTupleHeaderGetXmin, HeapTupleHeaderIsOnlyLocked(), HeapTupleSatisfiesVisibility, InvalidTransactionId, ItemIdGetLength, ItemIdIsNormal, ItemPointerEquals(), ItemPointerGetBlockNumber, ItemPointerGetOffsetNumber, ItemPointerIsValid, LockBuffer(), PageGetItem, PageGetItemId, PageGetMaxOffsetNumber, ReadBuffer(), RelationGetNumberOfBlocks, RelationGetRelationName, RelationGetRelid, 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 currtid_byrelname(), currtid_byreloid(), and TidNext().

2170 {
2171  BlockNumber blk;
2172  ItemPointerData ctid;
2173  TransactionId priorXmax;
2174 
2175  /* this is to avoid Assert failures on bad input */
2176  if (!ItemPointerIsValid(tid))
2177  return;
2178 
2179  /*
2180  * Since this can be called with user-supplied TID, don't trust the input
2181  * too much. (RelationGetNumberOfBlocks is an expensive check, so we
2182  * don't check t_ctid links again this way. Note that it would not do to
2183  * call it just once and save the result, either.)
2184  */
2185  blk = ItemPointerGetBlockNumber(tid);
2186  if (blk >= RelationGetNumberOfBlocks(relation))
2187  elog(ERROR, "block number %u is out of range for relation \"%s\"",
2188  blk, RelationGetRelationName(relation));
2189 
2190  /*
2191  * Loop to chase down t_ctid links. At top of loop, ctid is the tuple we
2192  * need to examine, and *tid is the TID we will return if ctid turns out
2193  * to be bogus.
2194  *
2195  * Note that we will loop until we reach the end of the t_ctid chain.
2196  * Depending on the snapshot passed, there might be at most one visible
2197  * version of the row, but we don't try to optimize for that.
2198  */
2199  ctid = *tid;
2200  priorXmax = InvalidTransactionId; /* cannot check first XMIN */
2201  for (;;)
2202  {
2203  Buffer buffer;
2204  Page page;
2205  OffsetNumber offnum;
2206  ItemId lp;
2207  HeapTupleData tp;
2208  bool valid;
2209 
2210  /*
2211  * Read, pin, and lock the page.
2212  */
2213  buffer = ReadBuffer(relation, ItemPointerGetBlockNumber(&ctid));
2214  LockBuffer(buffer, BUFFER_LOCK_SHARE);
2215  page = BufferGetPage(buffer);
2216  TestForOldSnapshot(snapshot, relation, page);
2217 
2218  /*
2219  * Check for bogus item number. This is not treated as an error
2220  * condition because it can happen while following a t_ctid link. We
2221  * just assume that the prior tid is OK and return it unchanged.
2222  */
2223  offnum = ItemPointerGetOffsetNumber(&ctid);
2224  if (offnum < FirstOffsetNumber || offnum > PageGetMaxOffsetNumber(page))
2225  {
2226  UnlockReleaseBuffer(buffer);
2227  break;
2228  }
2229  lp = PageGetItemId(page, offnum);
2230  if (!ItemIdIsNormal(lp))
2231  {
2232  UnlockReleaseBuffer(buffer);
2233  break;
2234  }
2235 
2236  /* OK to access the tuple */
2237  tp.t_self = ctid;
2238  tp.t_data = (HeapTupleHeader) PageGetItem(page, lp);
2239  tp.t_len = ItemIdGetLength(lp);
2240  tp.t_tableOid = RelationGetRelid(relation);
2241 
2242  /*
2243  * After following a t_ctid link, we might arrive at an unrelated
2244  * tuple. Check for XMIN match.
2245  */
2246  if (TransactionIdIsValid(priorXmax) &&
2248  {
2249  UnlockReleaseBuffer(buffer);
2250  break;
2251  }
2252 
2253  /*
2254  * Check time qualification of tuple; if visible, set it as the new
2255  * result candidate.
2256  */
2257  valid = HeapTupleSatisfiesVisibility(&tp, snapshot, buffer);
2258  CheckForSerializableConflictOut(valid, relation, &tp, buffer, snapshot);
2259  if (valid)
2260  *tid = ctid;
2261 
2262  /*
2263  * If there's a valid t_ctid link, follow it, else we're done.
2264  */
2265  if ((tp.t_data->t_infomask & HEAP_XMAX_INVALID) ||
2268  {
2269  UnlockReleaseBuffer(buffer);
2270  break;
2271  }
2272 
2273  ctid = tp.t_data->t_ctid;
2274  priorXmax = HeapTupleHeaderGetUpdateXid(tp.t_data);
2275  UnlockReleaseBuffer(buffer);
2276  } /* end of loop */
2277 }
#define HeapTupleHeaderGetUpdateXid(tup)
Definition: htup_details.h:359
bool HeapTupleHeaderIsOnlyLocked(HeapTupleHeader tuple)
Definition: tqual.c:1585
#define ItemPointerIsValid(pointer)
Definition: itemptr.h:59
static void TestForOldSnapshot(Snapshot snapshot, Relation relation, Page page)
Definition: bufmgr.h:265
#define TransactionIdEquals(id1, id2)
Definition: transam.h:43
uint32 TransactionId
Definition: c.h:397
HeapTupleHeaderData * HeapTupleHeader
Definition: htup.h:23
uint32 BlockNumber
Definition: block.h:31
#define PageGetMaxOffsetNumber(page)
Definition: bufpage.h:354
void CheckForSerializableConflictOut(bool visible, Relation relation, HeapTuple tuple, Buffer buffer, Snapshot snapshot)
Definition: predicate.c:3926
#define HeapTupleSatisfiesVisibility(tuple, snapshot, buffer)
Definition: tqual.h:45
uint16 OffsetNumber
Definition: off.h:24
HeapTupleHeader t_data
Definition: htup.h:67
#define ItemIdGetLength(itemId)
Definition: itemid.h:58
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3332
#define ERROR
Definition: elog.h:43
#define HEAP_XMAX_INVALID
Definition: htup_details.h:193
ItemPointerData t_ctid
Definition: htup_details.h:150
ItemPointerData t_self
Definition: htup.h:65
uint32 t_len
Definition: htup.h:64
#define InvalidTransactionId
Definition: transam.h:31
#define RelationGetRelationName(relation)
Definition: rel.h:437
Oid t_tableOid
Definition: htup.h:66
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
#define PageGetItemId(page, offsetNumber)
Definition: bufpage.h:232
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3546
#define RelationGetNumberOfBlocks(reln)
Definition: bufmgr.h:199
#define ItemIdIsNormal(itemId)
Definition: itemid.h:98
WalTimeSample buffer[LAG_TRACKER_BUFFER_SIZE]
Definition: walsender.c:211
#define HeapTupleHeaderGetXmin(tup)
Definition: htup_details.h:307
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition: bufmgr.c:594
#define ItemPointerGetOffsetNumber(pointer)
Definition: itemptr.h:94
bool ItemPointerEquals(ItemPointer pointer1, ItemPointer pointer2)
Definition: itemptr.c:29
#define BUFFER_LOCK_SHARE
Definition: bufmgr.h:88
#define elog
Definition: elog.h:219
#define ItemPointerGetBlockNumber(pointer)
Definition: itemptr.h:75
#define TransactionIdIsValid(xid)
Definition: transam.h:41
int Buffer
Definition: buf.h:23
#define RelationGetRelid(relation)
Definition: rel.h:417
#define PageGetItem(page, itemId)
Definition: bufpage.h:337
Pointer Page
Definition: bufpage.h:74
HeapTuple heap_getnext ( HeapScanDesc  scan,
ScanDirection  direction 
)

Definition at line 1794 of file heapam.c.

References HEAPDEBUG_1, HEAPDEBUG_2, HEAPDEBUG_3, heapgettup(), heapgettup_pagemode(), NULL, pgstat_count_heap_getnext, HeapScanDescData::rs_ctup, HeapScanDescData::rs_key, HeapScanDescData::rs_nkeys, HeapScanDescData::rs_pageatatime, HeapScanDescData::rs_rd, and HeapTupleData::t_data.

Referenced by AlterDomainNotNull(), AlterTableMoveAll(), AlterTableSpaceOptions(), ATRewriteTable(), boot_openrel(), check_db_file_conflict(), copy_heap_data(), CopyTo(), createdb(), DefineQueryRewrite(), do_autovacuum(), DropSetting(), DropTableSpace(), find_typed_table_dependencies(), get_database_list(), get_rel_oids(), get_subscription_list(), get_tables_to_cluster(), get_tablespace_name(), get_tablespace_oid(), GetAllTablesPublicationRelations(), getRelationsInNamespace(), gettype(), index_update_stats(), IndexBuildHeapRangeScan(), IndexCheckExclusion(), objectsInSchemaToOids(), pgrowlocks(), pgstat_collect_oids(), pgstat_heap(), ReindexMultipleTables(), RelationFindReplTupleSeq(), remove_dbtablespaces(), RemoveConversionById(), RemoveSubscriptionRel(), RenameTableSpace(), SeqNext(), systable_getnext(), ThereIsAtLeastOneRole(), vac_truncate_clog(), validate_index_heapscan(), validateCheckConstraint(), validateDomainConstraint(), and validateForeignKeyConstraint().

1795 {
1796  /* Note: no locking manipulations needed */
1797 
1798  HEAPDEBUG_1; /* heap_getnext( info ) */
1799 
1800  if (scan->rs_pageatatime)
1801  heapgettup_pagemode(scan, direction,
1802  scan->rs_nkeys, scan->rs_key);
1803  else
1804  heapgettup(scan, direction, scan->rs_nkeys, scan->rs_key);
1805 
1806  if (scan->rs_ctup.t_data == NULL)
1807  {
1808  HEAPDEBUG_2; /* heap_getnext returning EOS */
1809  return NULL;
1810  }
1811 
1812  /*
1813  * if we get here it means we have a new current scan tuple, so point to
1814  * the proper return buffer and return the tuple.
1815  */
1816  HEAPDEBUG_3; /* heap_getnext returning tuple */
1817 
1819 
1820  return &(scan->rs_ctup);
1821 }
#define HEAPDEBUG_2
Definition: heapam.c:1788
HeapTupleData rs_ctup
Definition: relscan.h:68
HeapTupleHeader t_data
Definition: htup.h:67
bool rs_pageatatime
Definition: relscan.h:53
#define HEAPDEBUG_1
Definition: heapam.c:1787
static void heapgettup(HeapScanDesc scan, ScanDirection dir, int nkeys, ScanKey key)
Definition: heapam.c:479
Relation rs_rd
Definition: relscan.h:47
#define NULL
Definition: c.h:229
#define HEAPDEBUG_3
Definition: heapam.c:1789
#define pgstat_count_heap_getnext(rel)
Definition: pgstat.h:1253
static void heapgettup_pagemode(HeapScanDesc scan, ScanDirection dir, int nkeys, ScanKey key)
Definition: heapam.c:781
ScanKey rs_key
Definition: relscan.h:50
bool heap_hot_search ( ItemPointer  tid,
Relation  relation,
Snapshot  snapshot,
bool all_dead 
)

Definition at line 2139 of file heapam.c.

References buffer, BUFFER_LOCK_SHARE, BUFFER_LOCK_UNLOCK, heap_hot_search_buffer(), ItemPointerGetBlockNumber, LockBuffer(), ReadBuffer(), ReleaseBuffer(), and result.

Referenced by _bt_check_unique(), and unique_key_recheck().

2141 {
2142  bool result;
2143  Buffer buffer;
2144  HeapTupleData heapTuple;
2145 
2146  buffer = ReadBuffer(relation, ItemPointerGetBlockNumber(tid));
2147  LockBuffer(buffer, BUFFER_LOCK_SHARE);
2148  result = heap_hot_search_buffer(tid, relation, buffer, snapshot,
2149  &heapTuple, all_dead, true);
2150  LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
2151  ReleaseBuffer(buffer);
2152  return result;
2153 }
#define BUFFER_LOCK_UNLOCK
Definition: bufmgr.h:87
return result
Definition: formatting.c:1632
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3309
bool heap_hot_search_buffer(ItemPointer tid, Relation relation, Buffer buffer, Snapshot snapshot, HeapTuple heapTuple, bool *all_dead, bool first_call)
Definition: heapam.c:1997
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3546
WalTimeSample buffer[LAG_TRACKER_BUFFER_SIZE]
Definition: walsender.c:211
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition: bufmgr.c:594
#define BUFFER_LOCK_SHARE
Definition: bufmgr.h:88
#define ItemPointerGetBlockNumber(pointer)
Definition: itemptr.h:75
int Buffer
Definition: buf.h:23
bool heap_hot_search_buffer ( ItemPointer  tid,
Relation  relation,
Buffer  buffer,
Snapshot  snapshot,
HeapTuple  heapTuple,
bool all_dead,
bool  first_call 
)

Definition at line 1997 of file heapam.c.

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

Referenced by bitgetpage(), heap_hot_search(), and index_fetch_heap().

2000 {
2001  Page dp = (Page) BufferGetPage(buffer);
2002  TransactionId prev_xmax = InvalidTransactionId;
2003  OffsetNumber offnum;
2004  bool at_chain_start;
2005  bool valid;
2006  bool skip;
2007 
2008  /* If this is not the first call, previous call returned a (live!) tuple */
2009  if (all_dead)
2010  *all_dead = first_call;
2011 
2013 
2015  offnum = ItemPointerGetOffsetNumber(tid);
2016  at_chain_start = first_call;
2017  skip = !first_call;
2018 
2019  heapTuple->t_self = *tid;
2020 
2021  /* Scan through possible multiple members of HOT-chain */
2022  for (;;)
2023  {
2024  ItemId lp;
2025 
2026  /* check for bogus TID */
2027  if (offnum < FirstOffsetNumber || offnum > PageGetMaxOffsetNumber(dp))
2028  break;
2029 
2030  lp = PageGetItemId(dp, offnum);
2031 
2032  /* check for unused, dead, or redirected items */
2033  if (!ItemIdIsNormal(lp))
2034  {
2035  /* We should only see a redirect at start of chain */
2036  if (ItemIdIsRedirected(lp) && at_chain_start)
2037  {
2038  /* Follow the redirect */
2039  offnum = ItemIdGetRedirect(lp);
2040  at_chain_start = false;
2041  continue;
2042  }
2043  /* else must be end of chain */
2044  break;
2045  }
2046 
2047  heapTuple->t_data = (HeapTupleHeader) PageGetItem(dp, lp);
2048  heapTuple->t_len = ItemIdGetLength(lp);
2049  heapTuple->t_tableOid = RelationGetRelid(relation);
2050  ItemPointerSetOffsetNumber(&heapTuple->t_self, offnum);
2051 
2052  /*
2053  * Shouldn't see a HEAP_ONLY tuple at chain start.
2054  */
2055  if (at_chain_start && HeapTupleIsHeapOnly(heapTuple))
2056  break;
2057 
2058  /*
2059  * The xmin should match the previous xmax value, else chain is
2060  * broken.
2061  */
2062  if (TransactionIdIsValid(prev_xmax) &&
2063  !TransactionIdEquals(prev_xmax,
2064  HeapTupleHeaderGetXmin(heapTuple->t_data)))
2065  break;
2066 
2067  /*
2068  * When first_call is true (and thus, skip is initially false) we'll
2069  * return the first tuple we find. But on later passes, heapTuple
2070  * will initially be pointing to the tuple we returned last time.
2071  * Returning it again would be incorrect (and would loop forever), so
2072  * we skip it and return the next match we find.
2073  */
2074  if (!skip)
2075  {
2076  /*
2077  * For the benefit of logical decoding, have t_self point at the
2078  * element of the HOT chain we're currently investigating instead
2079  * of the root tuple of the HOT chain. This is important because
2080  * the *Satisfies routine for historical mvcc snapshots needs the
2081  * correct tid to decide about the visibility in some cases.
2082  */
2083  ItemPointerSet(&(heapTuple->t_self), BufferGetBlockNumber(buffer), offnum);
2084 
2085  /* If it's visible per the snapshot, we must return it */
2086  valid = HeapTupleSatisfiesVisibility(heapTuple, snapshot, buffer);
2087  CheckForSerializableConflictOut(valid, relation, heapTuple,
2088  buffer, snapshot);
2089  /* reset to original, non-redirected, tid */
2090  heapTuple->t_self = *tid;
2091 
2092  if (valid)
2093  {
2094  ItemPointerSetOffsetNumber(tid, offnum);
2095  PredicateLockTuple(relation, heapTuple, snapshot);
2096  if (all_dead)
2097  *all_dead = false;
2098  return true;
2099  }
2100  }
2101  skip = false;
2102 
2103  /*
2104  * If we can't see it, maybe no one else can either. At caller
2105  * request, check whether all chain members are dead to all
2106  * transactions.
2107  */
2108  if (all_dead && *all_dead &&
2110  *all_dead = false;
2111 
2112  /*
2113  * Check to see if HOT chain continues past this tuple; if so fetch
2114  * the next offnum and loop around.
2115  */
2116  if (HeapTupleIsHotUpdated(heapTuple))
2117  {
2120  offnum = ItemPointerGetOffsetNumber(&heapTuple->t_data->t_ctid);
2121  at_chain_start = false;
2122  prev_xmax = HeapTupleHeaderGetUpdateXid(heapTuple->t_data);
2123  }
2124  else
2125  break; /* end of chain */
2126  }
2127 
2128  return false;
2129 }
#define HeapTupleHeaderGetUpdateXid(tup)
Definition: htup_details.h:359
static void skip(struct vars *v)
Definition: regc_lex.c:1109
#define ItemIdIsRedirected(itemId)
Definition: itemid.h:105
#define TransactionIdEquals(id1, id2)
Definition: transam.h:43
uint32 TransactionId
Definition: c.h:397
HeapTupleHeaderData * HeapTupleHeader
Definition: htup.h:23
#define ItemIdGetRedirect(itemId)
Definition: itemid.h:77
#define PageGetMaxOffsetNumber(page)
Definition: bufpage.h:354
void CheckForSerializableConflictOut(bool visible, Relation relation, HeapTuple tuple, Buffer buffer, Snapshot snapshot)
Definition: predicate.c:3926
bool HeapTupleIsSurelyDead(HeapTuple htup, TransactionId OldestXmin)
Definition: tqual.c:1409
#define HeapTupleSatisfiesVisibility(tuple, snapshot, buffer)
Definition: tqual.h:45
uint16 OffsetNumber
Definition: off.h:24
HeapTupleHeader t_data
Definition: htup.h:67
#define HeapTupleIsHotUpdated(tuple)
Definition: htup_details.h:677
#define ItemIdGetLength(itemId)
Definition: itemid.h:58
ItemPointerData t_ctid
Definition: htup_details.h:150
ItemPointerData t_self
Definition: htup.h:65
uint32 t_len
Definition: htup.h:64
TransactionId RecentGlobalXmin
Definition: snapmgr.c:166
#define InvalidTransactionId
Definition: transam.h:31
Oid t_tableOid
Definition: htup.h:66
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
#define PageGetItemId(page, offsetNumber)
Definition: bufpage.h:232
#define HeapTupleIsHeapOnly(tuple)
Definition: htup_details.h:686
#define Assert(condition)
Definition: c.h:675
#define ItemIdIsNormal(itemId)
Definition: itemid.h:98
WalTimeSample buffer[LAG_TRACKER_BUFFER_SIZE]
Definition: walsender.c:211
#define HeapTupleHeaderGetXmin(tup)
Definition: htup_details.h:307
#define ItemPointerGetOffsetNumber(pointer)
Definition: itemptr.h:94
void PredicateLockTuple(Relation relation, HeapTuple tuple, Snapshot snapshot)
Definition: predicate.c:2524
#define ItemPointerSetOffsetNumber(pointer, offsetNumber)
Definition: itemptr.h:125
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:2605
#define ItemPointerGetBlockNumber(pointer)
Definition: itemptr.h:75
#define TransactionIdIsValid(xid)
Definition: transam.h:41
#define RelationGetRelid(relation)
Definition: rel.h:417
#define PageGetItem(page, itemId)
Definition: bufpage.h:337
Pointer Page
Definition: bufpage.h:74
#define ItemPointerSet(pointer, blockNumber, offNum)
Definition: itemptr.h:104
void heap_inplace_update ( Relation  relation,
HeapTuple  tuple 
)

Definition at line 6195 of file heapam.c.

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

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

6196 {
6197  Buffer buffer;
6198  Page page;
6199  OffsetNumber offnum;
6200  ItemId lp = NULL;
6201  HeapTupleHeader htup;
6202  uint32 oldlen;
6203  uint32 newlen;
6204 
6205  /*
6206  * For now, parallel operations are required to be strictly read-only.
6207  * Unlike a regular update, this should never create a combo CID, so it
6208  * might be possible to relax this restriction, but not without more
6209  * thought and testing. It's not clear that it would be useful, anyway.
6210  */
6211  if (IsInParallelMode())
6212  ereport(ERROR,
6213  (errcode(ERRCODE_INVALID_TRANSACTION_STATE),
6214  errmsg("cannot update tuples during a parallel operation")));
6215 
6216  buffer = ReadBuffer(relation, ItemPointerGetBlockNumber(&(tuple->t_self)));
6218  page = (Page) BufferGetPage(buffer);
6219 
6220  offnum = ItemPointerGetOffsetNumber(&(tuple->t_self));
6221  if (PageGetMaxOffsetNumber(page) >= offnum)
6222  lp = PageGetItemId(page, offnum);
6223 
6224  if (PageGetMaxOffsetNumber(page) < offnum || !ItemIdIsNormal(lp))
6225  elog(ERROR, "invalid lp");
6226 
6227  htup = (HeapTupleHeader) PageGetItem(page, lp);
6228 
6229  oldlen = ItemIdGetLength(lp) - htup->t_hoff;
6230  newlen = tuple->t_len - tuple->t_data->t_hoff;
6231  if (oldlen != newlen || htup->t_hoff != tuple->t_data->t_hoff)
6232  elog(ERROR, "wrong tuple length");
6233 
6234  /* NO EREPORT(ERROR) from here till changes are logged */
6236 
6237  memcpy((char *) htup + htup->t_hoff,
6238  (char *) tuple->t_data + tuple->t_data->t_hoff,
6239  newlen);
6240 
6241  MarkBufferDirty(buffer);
6242 
6243  /* XLOG stuff */
6244  if (RelationNeedsWAL(relation))
6245  {
6246  xl_heap_inplace xlrec;
6247  XLogRecPtr recptr;
6248 
6249  xlrec.offnum = ItemPointerGetOffsetNumber(&tuple->t_self);
6250 
6251  XLogBeginInsert();
6252  XLogRegisterData((char *) &xlrec, SizeOfHeapInplace);
6253 
6254  XLogRegisterBuffer(0, buffer, REGBUF_STANDARD);
6255  XLogRegisterBufData(0, (char *) htup + htup->t_hoff, newlen);
6256 
6257  /* inplace updates aren't decoded atm, don't log the origin */
6258 
6259  recptr = XLogInsert(RM_HEAP_ID, XLOG_HEAP_INPLACE);
6260 
6261  PageSetLSN(page, recptr);
6262  }
6263 
6264  END_CRIT_SECTION();
6265 
6266  UnlockReleaseBuffer(buffer);
6267 
6268  /*
6269  * Send out shared cache inval if necessary. Note that because we only
6270  * pass the new version of the tuple, this mustn't be used for any
6271  * operations that could change catcache lookup keys. But we aren't
6272  * bothering with index updates either, so that's true a fortiori.
6273  */
6275  CacheInvalidateHeapTuple(relation, tuple, NULL);
6276 }
void XLogRegisterBufData(uint8 block_id, char *data, int len)
Definition: xloginsert.c:361
void CacheInvalidateHeapTuple(Relation relation, HeapTuple tuple, HeapTuple newtuple)
Definition: inval.c:1094
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:1450
void XLogRegisterBuffer(uint8 block_id, Buffer buffer, uint8 flags)
Definition: xloginsert.c:213
HeapTupleHeaderData * HeapTupleHeader
Definition: htup.h:23
#define END_CRIT_SECTION()
Definition: miscadmin.h:132
#define SizeOfHeapInplace
Definition: heapam_xlog.h:286
#define START_CRIT_SECTION()
Definition: miscadmin.h:130
int errcode(int sqlerrcode)
Definition: elog.c:575
#define BUFFER_LOCK_EXCLUSIVE
Definition: bufmgr.h:89
#define PageGetMaxOffsetNumber(page)
Definition: bufpage.h:354
uint16 OffsetNumber
Definition: off.h:24
HeapTupleHeader t_data
Definition: htup.h:67
#define ItemIdGetLength(itemId)
Definition: itemid.h:58
bool IsInParallelMode(void)
Definition: xact.c:913
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3332
#define ERROR
Definition: elog.h:43
ItemPointerData t_self
Definition: htup.h:65
uint32 t_len
Definition: htup.h:64
#define REGBUF_STANDARD
Definition: xloginsert.h:35
unsigned int uint32
Definition: c.h:268
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
#define ereport(elevel, rest)
Definition: elog.h:122
#define PageGetItemId(page, offsetNumber)
Definition: bufpage.h:232
void XLogRegisterData(char *data, int len)
Definition: xloginsert.c:323
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:415
OffsetNumber offnum
Definition: heapam_xlog.h:282
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3546
#define NULL
Definition: c.h:229
uint64 XLogRecPtr
Definition: xlogdefs.h:21
#define ItemIdIsNormal(itemId)
Definition: itemid.h:98
WalTimeSample buffer[LAG_TRACKER_BUFFER_SIZE]
Definition: walsender.c:211
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition: bufmgr.c:594
#define ItemPointerGetOffsetNumber(pointer)
Definition: itemptr.h:94
#define XLOG_HEAP_INPLACE
Definition: heapam_xlog.h:39
#define RelationNeedsWAL(relation)
Definition: rel.h:506
#define IsBootstrapProcessingMode()
Definition: miscadmin.h:365
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define elog
Definition: elog.h:219
#define ItemPointerGetBlockNumber(pointer)
Definition: itemptr.h:75
void XLogBeginInsert(void)
Definition: xloginsert.c:120
#define PageSetLSN(page, lsn)
Definition: bufpage.h:365
int Buffer
Definition: buf.h:23
#define PageGetItem(page, itemId)
Definition: bufpage.h:337
Pointer Page
Definition: bufpage.h:74
Oid heap_insert ( Relation  relation,
HeapTuple  tup,
CommandId  cid,
int  options,
BulkInsertState  bistate 
)

Definition at line 2396 of file heapam.c.

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

Referenced by ATRewriteTable(), CopyFrom(), ExecInsert(), intorel_receive(), simple_heap_insert(), toast_save_datum(), and transientrel_receive().

2398 {
2400  HeapTuple heaptup;
2401  Buffer buffer;
2402  Buffer vmbuffer = InvalidBuffer;
2403  bool all_visible_cleared = false;
2404 
2405  /*
2406  * Fill in tuple header fields, assign an OID, and toast the tuple if
2407  * necessary.
2408  *
2409  * Note: below this point, heaptup is the data we actually intend to store
2410  * into the relation; tup is the caller's original untoasted data.
2411  */
2412  heaptup = heap_prepare_insert(relation, tup, xid, cid, options);
2413 
2414  /*
2415  * Find buffer to insert this tuple into. If the page is all visible,
2416  * this will also pin the requisite visibility map page.
2417  */
2418  buffer = RelationGetBufferForTuple(relation, heaptup->t_len,
2419  InvalidBuffer, options, bistate,
2420  &vmbuffer, NULL);
2421 
2422  /*
2423  * We're about to do the actual insert -- but check for conflict first, to
2424  * avoid possibly having to roll back work we've just done.
2425  *
2426  * This is safe without a recheck as long as there is no possibility of
2427  * another process scanning the page between this check and the insert
2428  * being visible to the scan (i.e., an exclusive buffer content lock is
2429  * continuously held from this point until the tuple insert is visible).
2430  *
2431  * For a heap insert, we only need to check for table-level SSI locks. Our
2432  * new tuple can't possibly conflict with existing tuple locks, and heap
2433  * page locks are only consolidated versions of tuple locks; they do not
2434  * lock "gaps" as index page locks do. So we don't need to specify a
2435  * buffer when making the call, which makes for a faster check.
2436  */
2438 
2439  /* NO EREPORT(ERROR) from here till changes are logged */
2441 
2442  RelationPutHeapTuple(relation, buffer, heaptup,
2443  (options & HEAP_INSERT_SPECULATIVE) != 0);
2444 
2445  if (PageIsAllVisible(BufferGetPage(buffer)))
2446  {
2447  all_visible_cleared = true;
2449  visibilitymap_clear(relation,
2450  ItemPointerGetBlockNumber(&(heaptup->t_self)),
2451  vmbuffer, VISIBILITYMAP_VALID_BITS);
2452  }
2453 
2454  /*
2455  * XXX Should we set PageSetPrunable on this page ?
2456  *
2457  * The inserting transaction may eventually abort thus making this tuple
2458  * DEAD and hence available for pruning. Though we don't want to optimize
2459  * for aborts, if no other tuple in this page is UPDATEd/DELETEd, the
2460  * aborted tuple will never be pruned until next vacuum is triggered.
2461  *
2462  * If you do add PageSetPrunable here, add it in heap_xlog_insert too.
2463  */
2464 
2465  MarkBufferDirty(buffer);
2466 
2467  /* XLOG stuff */
2468  if (!(options & HEAP_INSERT_SKIP_WAL) && RelationNeedsWAL(relation))
2469  {
2470  xl_heap_insert xlrec;
2471  xl_heap_header xlhdr;
2472  XLogRecPtr recptr;
2473  Page page = BufferGetPage(buffer);
2474  uint8 info = XLOG_HEAP_INSERT;
2475  int bufflags = 0;
2476 
2477  /*
2478  * If this is a catalog, we need to transmit combocids to properly
2479  * decode, so log that as well.
2480  */
2482  log_heap_new_cid(relation, heaptup);
2483 
2484  /*
2485  * If this is the single and first tuple on page, we can reinit the
2486  * page instead of restoring the whole thing. Set flag, and hide
2487  * buffer references from XLogInsert.
2488  */
2489  if (ItemPointerGetOffsetNumber(&(heaptup->t_self)) == FirstOffsetNumber &&
2491  {
2492  info |= XLOG_HEAP_INIT_PAGE;
2493  bufflags |= REGBUF_WILL_INIT;
2494  }
2495 
2496  xlrec.offnum = ItemPointerGetOffsetNumber(&heaptup->t_self);
2497  xlrec.flags = 0;
2498  if (all_visible_cleared)
2503 
2504  /*
2505  * For logical decoding, we need the tuple even if we're doing a full
2506  * page write, so make sure it's included even if we take a full-page
2507  * image. (XXX We could alternatively store a pointer into the FPW).
2508  */
2509  if (RelationIsLogicallyLogged(relation))
2510  {
2512  bufflags |= REGBUF_KEEP_DATA;
2513  }
2514 
2515  XLogBeginInsert();
2516  XLogRegisterData((char *) &xlrec, SizeOfHeapInsert);
2517 
2518  xlhdr.t_infomask2 = heaptup->t_data->t_infomask2;
2519  xlhdr.t_infomask = heaptup->t_data->t_infomask;
2520  xlhdr.t_hoff = heaptup->t_data->t_hoff;
2521 
2522  /*
2523  * note we mark xlhdr as belonging to buffer; if XLogInsert decides to
2524  * write the whole page to the xlog, we don't need to store
2525  * xl_heap_header in the xlog.
2526  */
2527  XLogRegisterBuffer(0, buffer, REGBUF_STANDARD | bufflags);
2528  XLogRegisterBufData(0, (char *) &xlhdr, SizeOfHeapHeader);
2529  /* PG73FORMAT: write bitmap [+ padding] [+ oid] + data */
2531  (char *) heaptup->t_data + SizeofHeapTupleHeader,
2532  heaptup->t_len - SizeofHeapTupleHeader);
2533 
2534  /* filtering by origin on a row level is much more efficient */
2536 
2537  recptr = XLogInsert(RM_HEAP_ID, info);
2538 
2539  PageSetLSN(page, recptr);
2540  }
2541 
2542  END_CRIT_SECTION();
2543 
2544  UnlockReleaseBuffer(buffer);
2545  if (vmbuffer != InvalidBuffer)
2546  ReleaseBuffer(vmbuffer);
2547 
2548  /*
2549  * If tuple is cachable, mark it for invalidation from the caches in case
2550  * we abort. Note it is OK to do this after releasing the buffer, because
2551  * the heaptup data structure is all in local memory, not in the shared
2552  * buffer.
2553  */
2554  CacheInvalidateHeapTuple(relation, heaptup, NULL);
2555 
2556  /* Note: speculative insertions are counted too, even if aborted later */
2557  pgstat_count_heap_insert(relation, 1);
2558 
2559  /*
2560  * If heaptup is a private copy, release it. Don't forget to copy t_self
2561  * back to the caller's image, too.
2562  */
2563  if (heaptup != tup)
2564  {
2565  tup->t_self = heaptup->t_self;
2566  heap_freetuple(heaptup);
2567  }
2568 
2569  return HeapTupleGetOid(tup);
2570 }
void XLogRegisterBufData(uint8 block_id, char *data, int len)
Definition: xloginsert.c:361
#define SizeofHeapTupleHeader
Definition: htup_details.h:170
#define XLOG_HEAP_INSERT
Definition: heapam_xlog.h:32
static XLogRecPtr log_heap_new_cid(Relation relation, HeapTuple tup)
Definition: heapam.c:7694
void CacheInvalidateHeapTuple(Relation relation, HeapTuple tuple, HeapTuple newtuple)
Definition: inval.c:1094
static HeapTuple heap_prepare_insert(Relation relation, HeapTuple tup, TransactionId xid, CommandId cid, int options)
Definition: heapam.c:2580
#define PageIsAllVisible(page)
Definition: bufpage.h:382
uint32 TransactionId
Definition: c.h:397
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:1450
void XLogRegisterBuffer(uint8 block_id, Buffer buffer, uint8 flags)
Definition: xloginsert.c:213
#define END_CRIT_SECTION()
Definition: miscadmin.h:132
unsigned char uint8
Definition: c.h:266
#define XLH_INSERT_IS_SPECULATIVE
Definition: heapam_xlog.h:68
#define InvalidBuffer
Definition: buf.h:25
#define REGBUF_WILL_INIT
Definition: xloginsert.h:32
uint16 t_infomask2
Definition: heapam_xlog.h:122
#define START_CRIT_SECTION()
Definition: miscadmin.h:130
#define XLOG_INCLUDE_ORIGIN
Definition: xlog.h:192
#define HEAP_INSERT_SKIP_WAL
Definition: heapam.h:28
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3309
#define RelationIsLogicallyLogged(relation)
Definition: rel.h:576
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1372
#define PageGetMaxOffsetNumber(page)
Definition: bufpage.h:354
void RelationPutHeapTuple(Relation relation, Buffer buffer, HeapTuple tuple, bool token)
Definition: hio.c:36
void CheckForSerializableConflictIn(Relation relation, HeapTuple tuple, Buffer buffer)
Definition: predicate.c:4307
#define XLOG_HEAP_INIT_PAGE
Definition: heapam_xlog.h:46
#define HEAP_INSERT_SPECULATIVE
Definition: heapam.h:31
#define VISIBILITYMAP_VALID_BITS
Definition: visibilitymap.h:28
HeapTupleHeader t_data
Definition: htup.h:67
bool visibilitymap_clear(Relation rel, BlockNumber heapBlk, Buffer buf, uint8 flags)
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3332
#define XLH_INSERT_CONTAINS_NEW_TUPLE
Definition: heapam_xlog.h:69
ItemPointerData t_self
Definition: htup.h:65
TransactionId GetCurrentTransactionId(void)
Definition: xact.c:417
uint32 t_len
Definition: htup.h:64
#define FirstOffsetNumber
Definition: off.h:27
#define REGBUF_STANDARD
Definition: xloginsert.h:35
Buffer RelationGetBufferForTuple(Relation relation, Size len, Buffer otherBuffer, int options, BulkInsertState bistate, Buffer *vmbuffer, Buffer *vmbuffer_other)
Definition: hio.c:297
void XLogSetRecordFlags(uint8 flags)
Definition: xloginsert.c:397
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
void XLogRegisterData(char *data, int len)
Definition: xloginsert.c:323
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:415
#define RelationIsAccessibleInLogicalDecoding(relation)
Definition: rel.h:560
#define REGBUF_KEEP_DATA
Definition: xloginsert.h:38
#define PageClearAllVisible(page)
Definition: bufpage.h:386
#define NULL
Definition: c.h:229
uint64 XLogRecPtr
Definition: xlogdefs.h:21
#define Assert(condition)
Definition: c.h:675
WalTimeSample buffer[LAG_TRACKER_BUFFER_SIZE]
Definition: walsender.c:211
uint16 t_infomask
Definition: heapam_xlog.h:123
#define ItemPointerGetOffsetNumber(pointer)
Definition: itemptr.h:94
#define RelationNeedsWAL(relation)
Definition: rel.h:506
#define SizeOfHeapInsert
Definition: heapam_xlog.h:138
#define XLH_INSERT_ALL_VISIBLE_CLEARED
Definition: heapam_xlog.h:66
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:2605
void pgstat_count_heap_insert(Relation rel, PgStat_Counter n)
Definition: pgstat.c:1907
#define ItemPointerGetBlockNumber(pointer)
Definition: itemptr.h:75
#define HeapTupleGetOid(tuple)
Definition: htup_details.h:695
void XLogBeginInsert(void)
Definition: xloginsert.c:120
#define PageSetLSN(page, lsn)
Definition: bufpage.h:365
int Buffer
Definition: buf.h:23
OffsetNumber offnum
Definition: heapam_xlog.h:132
#define SizeOfHeapHeader
Definition: heapam_xlog.h:127
Pointer Page
Definition: bufpage.h:74
HTSU_Result heap_lock_tuple ( Relation  relation,
HeapTuple  tuple,
CommandId  cid,
LockTupleMode  mode,
LockWaitPolicy  wait_policy,
bool  follow_updates,
Buffer buffer,
HeapUpdateFailureData hufd 
)

Definition at line 4540 of file heapam.c.

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

Referenced by EvalPlanQualFetch(), ExecLockRows(), ExecOnConflictUpdate(), GetTupleForTrigger(), RelationFindReplTupleByIndex(), and RelationFindReplTupleSeq().

4544 {
4546  ItemPointer tid = &(tuple->t_self);
4547  ItemId lp;
4548  Page page;
4549  Buffer vmbuffer = InvalidBuffer;
4550  BlockNumber block;
4551  TransactionId xid,
4552  xmax;
4553  uint16 old_infomask,
4554  new_infomask,
4555  new_infomask2;
4556  bool first_time = true;
4557  bool have_tuple_lock = false;
4558  bool cleared_all_frozen = false;
4559 
4560  *buffer = ReadBuffer(relation, ItemPointerGetBlockNumber(tid));
4561  block = ItemPointerGetBlockNumber(tid);
4562 
4563  /*
4564  * Before locking the buffer, pin the visibility map page if it appears to
4565  * be necessary. Since we haven't got the lock yet, someone else might be
4566  * in the middle of changing this, so we'll need to recheck after we have
4567  * the lock.
4568  */
4570  visibilitymap_pin(relation, block, &vmbuffer);
4571 
4573 
4574  page = BufferGetPage(*buffer);
4575  lp = PageGetItemId(page, ItemPointerGetOffsetNumber(tid));
4576  Assert(ItemIdIsNormal(lp));
4577 
4578  tuple->t_data = (HeapTupleHeader) PageGetItem(page, lp);
4579  tuple->t_len = ItemIdGetLength(lp);
4580  tuple->t_tableOid = RelationGetRelid(relation);
4581 
4582 l3:
4583  result = HeapTupleSatisfiesUpdate(tuple, cid, *buffer);
4584 
4585  if (result == HeapTupleInvisible)
4586  {
4587  /*
4588  * This is possible, but only when locking a tuple for ON CONFLICT
4589  * UPDATE. We return this value here rather than throwing an error in
4590  * order to give that case the opportunity to throw a more specific
4591  * error.
4592  */
4593  result = HeapTupleInvisible;
4594  goto out_locked;
4595  }
4596  else if (result == HeapTupleBeingUpdated || result == HeapTupleUpdated)
4597  {
4598  TransactionId xwait;
4599  uint16 infomask;
4600  uint16 infomask2;
4601  bool require_sleep;
4602  ItemPointerData t_ctid;
4603 
4604  /* must copy state data before unlocking buffer */
4605  xwait = HeapTupleHeaderGetRawXmax(tuple->t_data);
4606  infomask = tuple->t_data->t_infomask;
4607  infomask2 = tuple->t_data->t_infomask2;
4608  ItemPointerCopy(&tuple->t_data->t_ctid, &t_ctid);
4609 
4611 
4612  /*
4613  * If any subtransaction of the current top transaction already holds
4614  * a lock as strong as or stronger than what we're requesting, we
4615  * effectively hold the desired lock already. We *must* succeed
4616  * without trying to take the tuple lock, else we will deadlock
4617  * against anyone wanting to acquire a stronger lock.
4618  *
4619  * Note we only do this the first time we loop on the HTSU result;
4620  * there is no point in testing in subsequent passes, because
4621  * evidently our own transaction cannot have acquired a new lock after
4622  * the first time we checked.
4623  */
4624  if (first_time)
4625  {
4626  first_time = false;
4627 
4628  if (infomask & HEAP_XMAX_IS_MULTI)
4629  {
4630  int i;
4631  int nmembers;
4632  MultiXactMember *members;
4633 
4634  /*
4635  * We don't need to allow old multixacts here; if that had
4636  * been the case, HeapTupleSatisfiesUpdate would have returned
4637  * MayBeUpdated and we wouldn't be here.
4638  */
4639  nmembers =
4640  GetMultiXactIdMembers(xwait, &members, false,
4641  HEAP_XMAX_IS_LOCKED_ONLY(infomask));
4642 
4643  for (i = 0; i < nmembers; i++)
4644  {
4645  /* only consider members of our own transaction */
4646  if (!TransactionIdIsCurrentTransactionId(members[i].xid))
4647  continue;
4648 
4649  if (TUPLOCK_from_mxstatus(members[i].status) >= mode)
4650  {
4651  pfree(members);
4652  result = HeapTupleMayBeUpdated;
4653  goto out_unlocked;
4654  }
4655  }
4656 
4657  if (members)
4658  pfree(members);
4659  }
4660  else if (TransactionIdIsCurrentTransactionId(xwait))
4661  {
4662  switch (mode)
4663  {
4664  case LockTupleKeyShare:
4665  Assert(HEAP_XMAX_IS_KEYSHR_LOCKED(infomask) ||
4666  HEAP_XMAX_IS_SHR_LOCKED(infomask) ||
4667  HEAP_XMAX_IS_EXCL_LOCKED(infomask));
4668  result = HeapTupleMayBeUpdated;
4669  goto out_unlocked;
4670  case LockTupleShare:
4671  if (HEAP_XMAX_IS_SHR_LOCKED(infomask) ||
4672  HEAP_XMAX_IS_EXCL_LOCKED(infomask))
4673  {
4674  result = HeapTupleMayBeUpdated;
4675  goto out_unlocked;
4676  }
4677  break;
4679  if (HEAP_XMAX_IS_EXCL_LOCKED(infomask))
4680  {
4681  result = HeapTupleMayBeUpdated;
4682  goto out_unlocked;
4683  }
4684  break;
4685  case LockTupleExclusive:
4686  if (HEAP_XMAX_IS_EXCL_LOCKED(infomask) &&
4687  infomask2 & HEAP_KEYS_UPDATED)
4688  {
4689  result = HeapTupleMayBeUpdated;
4690  goto out_unlocked;
4691  }
4692  break;
4693  }
4694  }
4695  }
4696 
4697  /*
4698  * Initially assume that we will have to wait for the locking
4699  * transaction(s) to finish. We check various cases below in which
4700  * this can be turned off.
4701  */
4702  require_sleep = true;
4703  if (mode == LockTupleKeyShare)
4704  {
4705  /*
4706  * If we're requesting KeyShare, and there's no update present, we
4707  * don't need to wait. Even if there is an update, we can still
4708  * continue if the key hasn't been modified.
4709  *
4710  * However, if there are updates, we need to walk the update chain
4711  * to mark future versions of the row as locked, too. That way,
4712  * if somebody deletes that future version, we're protected
4713  * against the key going away. This locking of future versions
4714  * could block momentarily, if a concurrent transaction is
4715  * deleting a key; or it could return a value to the effect that
4716  * the transaction deleting the key has already committed. So we
4717  * do this before re-locking the buffer; otherwise this would be
4718  * prone to deadlocks.
4719  *
4720  * Note that the TID we're locking was grabbed before we unlocked
4721  * the buffer. For it to change while we're not looking, the
4722  * other properties we're testing for below after re-locking the
4723  * buffer would also change, in which case we would restart this
4724  * loop above.
4725  */
4726  if (!(infomask2 & HEAP_KEYS_UPDATED))
4727  {
4728  bool updated;
4729 
4730  updated = !HEAP_XMAX_IS_LOCKED_ONLY(infomask);
4731 
4732  /*
4733  * If there are updates, follow the update chain; bail out if
4734  * that cannot be done.
4735  */
4736  if (follow_updates && updated)
4737  {
4738  HTSU_Result res;
4739 
4740  res = heap_lock_updated_tuple(relation, tuple, &t_ctid,
4742  mode);
4743  if (res != HeapTupleMayBeUpdated)
4744  {
4745  result = res;
4746  /* recovery code expects to have buffer lock held */
4748  goto failed;
4749  }
4750  }
4751 
4753 
4754  /*
4755  * Make sure it's still an appropriate lock, else start over.
4756  * Also, if it wasn't updated before we released the lock, but
4757  * is updated now, we start over too; the reason is that we
4758  * now need to follow the update chain to lock the new
4759  * versions.
4760  */
4761  if (!HeapTupleHeaderIsOnlyLocked(tuple->t_data) &&
4762  ((tuple->t_data->t_infomask2 & HEAP_KEYS_UPDATED) ||
4763  !updated))
4764  goto l3;
4765 
4766  /* Things look okay, so we can skip sleeping */
4767  require_sleep = false;
4768 
4769  /*
4770  * Note we allow Xmax to change here; other updaters/lockers
4771  * could have modified it before we grabbed the buffer lock.
4772  * However, this is not a problem, because with the recheck we
4773  * just did we ensure that they still don't conflict with the
4774  * lock we want.
4775  */
4776  }
4777  }
4778  else if (mode == LockTupleShare)
4779  {
4780  /*
4781  * If we're requesting Share, we can similarly avoid sleeping if
4782  * there's no update and no exclusive lock present.
4783  */
4784  if (HEAP_XMAX_IS_LOCKED_ONLY(infomask) &&
4785  !HEAP_XMAX_IS_EXCL_LOCKED(infomask))
4786  {
4788 
4789  /*
4790  * Make sure it's still an appropriate lock, else start over.
4791  * See above about allowing xmax to change.
4792  */
4793  if (!HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_data->t_infomask) ||
4795  goto l3;
4796  require_sleep = false;
4797  }
4798  }
4799  else if (mode == LockTupleNoKeyExclusive)
4800  {
4801  /*
4802  * If we're requesting NoKeyExclusive, we might also be able to
4803  * avoid sleeping; just ensure that there no conflicting lock
4804  * already acquired.
4805  */
4806  if (infomask & HEAP_XMAX_IS_MULTI)
4807  {
4808  if (!DoesMultiXactIdConflict((MultiXactId) xwait, infomask,
4809  mode))
4810  {
4811  /*
4812  * No conflict, but if the xmax changed under us in the
4813  * meantime, start over.
4814  */
4816  if (xmax_infomask_changed(tuple->t_data->t_infomask, infomask) ||
4818  xwait))
4819  goto l3;
4820 
4821  /* otherwise, we're good */
4822  require_sleep = false;
4823  }
4824  }
4825  else if (HEAP_XMAX_IS_KEYSHR_LOCKED(infomask))
4826  {
4828 
4829  /* if the xmax changed in the meantime, start over */
4830  if (xmax_infomask_changed(tuple->t_data->t_infomask, infomask) ||
4833  xwait))
4834  goto l3;
4835  /* otherwise, we're good */
4836  require_sleep = false;
4837  }
4838  }
4839 
4840  /*
4841  * As a check independent from those above, we can also avoid sleeping
4842  * if the current transaction is the sole locker of the tuple. Note
4843  * that the strength of the lock already held is irrelevant; this is
4844  * not about recording the lock in Xmax (which will be done regardless
4845  * of this optimization, below). Also, note that the cases where we
4846  * hold a lock stronger than we are requesting are already handled
4847  * above by not doing anything.
4848  *
4849  * Note we only deal with the non-multixact case here; MultiXactIdWait
4850  * is well equipped to deal with this situation on its own.
4851  */
4852  if (require_sleep && !(infomask & HEAP_XMAX_IS_MULTI) &&
4854  {
4855  /* ... but if the xmax changed in the meantime, start over */
4857  if (xmax_infomask_changed(tuple->t_data->t_infomask, infomask) ||
4859  xwait))
4860  goto l3;
4862  require_sleep = false;
4863  }
4864 
4865  /*
4866  * Time to sleep on the other transaction/multixact, if necessary.
4867  *
4868  * If the other transaction is an update that's already committed,
4869  * then sleeping cannot possibly do any good: if we're required to
4870  * sleep, get out to raise an error instead.
4871  *
4872  * By here, we either have already acquired the buffer exclusive lock,
4873  * or we must wait for the locking transaction or multixact; so below
4874  * we ensure that we grab buffer lock after the sleep.
4875  */
4876  if (require_sleep && result == HeapTupleUpdated)
4877  {
4879  goto failed;
4880  }
4881  else if (require_sleep)
4882  {
4883  /*
4884  * Acquire tuple lock to establish our priority for the tuple, or
4885  * die trying. LockTuple will release us when we are next-in-line
4886  * for the tuple. We must do this even if we are share-locking.
4887  *
4888  * If we are forced to "start over" below, we keep the tuple lock;
4889  * this arranges that we stay at the head of the line while
4890  * rechecking tuple state.
4891  */
4892  if (!heap_acquire_tuplock(relation, tid, mode, wait_policy,
4893  &have_tuple_lock))
4894  {
4895  /*
4896  * This can only happen if wait_policy is Skip and the lock
4897  * couldn't be obtained.
4898  */
4899  result = HeapTupleWouldBlock;
4900  /* recovery code expects to have buffer lock held */
4902  goto failed;
4903  }
4904 
4905  if (infomask & HEAP_XMAX_IS_MULTI)
4906  {
4908 
4909  /* We only ever lock tuples, never update them */
4910  if (status >= MultiXactStatusNoKeyUpdate)
4911  elog(ERROR, "invalid lock mode in heap_lock_tuple");
4912 
4913  /* wait for multixact to end, or die trying */
4914  switch (wait_policy)
4915  {
4916  case LockWaitBlock:
4917  MultiXactIdWait((MultiXactId) xwait, status, infomask,
4918  relation, &tuple->t_self, XLTW_Lock, NULL);
4919  break;
4920  case LockWaitSkip:
4922  status, infomask, relation,
4923  NULL))
4924  {
4925  result = HeapTupleWouldBlock;
4926  /* recovery code expects to have buffer lock held */
4928  goto failed;
4929  }
4930  break;
4931  case LockWaitError:
4933  status, infomask, relation,
4934  NULL))
4935  ereport(ERROR,
4936  (errcode(ERRCODE_LOCK_NOT_AVAILABLE),
4937  errmsg("could not obtain lock on row in relation \"%s\"",
4938  RelationGetRelationName(relation))));
4939 
4940  break;
4941  }
4942 
4943  /*
4944  * Of course, the multixact might not be done here: if we're
4945  * requesting a light lock mode, other transactions with light
4946  * locks could still be alive, as well as locks owned by our
4947  * own xact or other subxacts of this backend. We need to
4948  * preserve the surviving MultiXact members. Note that it
4949  * isn't absolutely necessary in the latter case, but doing so
4950  * is simpler.
4951  */
4952  }
4953  else
4954  {
4955  /* wait for regular transaction to end, or die trying */
4956  switch (wait_policy)
4957  {
4958  case LockWaitBlock:
4959  XactLockTableWait(xwait, relation, &tuple->t_self,
4960  XLTW_Lock);
4961  break;
4962  case LockWaitSkip:
4963  if (!ConditionalXactLockTableWait(xwait))
4964  {
4965  result = HeapTupleWouldBlock;
4966  /* recovery code expects to have buffer lock held */
4968  goto failed;
4969  }
4970  break;
4971  case LockWaitError:
4972  if (!ConditionalXactLockTableWait(xwait))
4973  ereport(ERROR,
4974  (errcode(ERRCODE_LOCK_NOT_AVAILABLE),
4975  errmsg("could not obtain lock on row in relation \"%s\"",
4976  RelationGetRelationName(relation))));
4977  break;
4978  }
4979  }
4980 
4981  /* if there are updates, follow the update chain */
4982  if (follow_updates && !HEAP_XMAX_IS_LOCKED_ONLY(infomask))
4983  {
4984  HTSU_Result res;
4985 
4986  res = heap_lock_updated_tuple(relation, tuple, &t_ctid,
4988  mode);
4989  if (res != HeapTupleMayBeUpdated)
4990  {
4991  result = res;
4992  /* recovery code expects to have buffer lock held */
4994  goto failed;
4995  }
4996  }
4997 
4999 
5000  /*
5001  * xwait is done, but if xwait had just locked the tuple then some
5002  * other xact could update this tuple before we get to this point.
5003  * Check for xmax change, and start over if so.
5004  */
5005  if (xmax_infomask_changed(tuple->t_data->t_infomask, infomask) ||
5007  xwait))
5008  goto l3;
5009 
5010  if (!(infomask & HEAP_XMAX_IS_MULTI))
5011  {
5012  /*
5013  * Otherwise check if it committed or aborted. Note we cannot
5014  * be here if the tuple was only locked by somebody who didn't
5015  * conflict with us; that would have been handled above. So
5016  * that transaction must necessarily be gone by now. But
5017  * don't check for this in the multixact case, because some
5018  * locker transactions might still be running.
5019  */
5020  UpdateXmaxHintBits(tuple->t_data, *buffer, xwait);
5021  }
5022  }
5023 
5024  /* By here, we're certain that we hold buffer exclusive lock again */
5025 
5026  /*
5027  * We may lock if previous xmax aborted, or if it committed but only
5028  * locked the tuple without updating it; or if we didn't have to wait
5029  * at all for whatever reason.
5030  */
5031  if (!require_sleep ||
5032  (tuple->t_data->t_infomask & HEAP_XMAX_INVALID) ||
5035  result = HeapTupleMayBeUpdated;
5036  else
5037  result = HeapTupleUpdated;
5038  }
5039 
5040 failed:
5041  if (result != HeapTupleMayBeUpdated)
5042  {
5043  Assert(result == HeapTupleSelfUpdated || result == HeapTupleUpdated ||
5044  result == HeapTupleWouldBlock);
5045  Assert(!(tuple->t_data->t_infomask & HEAP_XMAX_INVALID));
5046  hufd->ctid = tuple->t_data->t_ctid;
5047  hufd->xmax = HeapTupleHeaderGetUpdateXid(tuple->t_data);
5048  if (result == HeapTupleSelfUpdated)
5049  hufd->cmax = HeapTupleHeaderGetCmax(tuple->t_data);
5050  else
5051  hufd->cmax = InvalidCommandId;
5052  goto out_locked;
5053  }
5054 
5055  /*
5056  * If we didn't pin the visibility map page and the page has become all
5057  * visible while we were busy locking the buffer, or during some
5058  * subsequent window during which we had it unlocked, we'll have to unlock
5059  * and re-lock, to avoid holding the buffer lock across I/O. That's a bit
5060  * unfortunate, especially since we'll now have to recheck whether the
5061  * tuple has been locked or updated under us, but hopefully it won't
5062  * happen very often.
5063  */
5064  if (vmbuffer == InvalidBuffer && PageIsAllVisible(page))
5065  {
5067  visibilitymap_pin(relation, block, &vmbuffer);
5069  goto l3;
5070  }
5071 
5072  xmax = HeapTupleHeaderGetRawXmax(tuple->t_data);
5073  old_infomask = tuple->t_data->t_infomask;
5074 
5075  /*
5076  * If this is the first possibly-multixact-able operation in the current
5077  * transaction, set my per-backend OldestMemberMXactId setting. We can be
5078  * certain that the transaction will never become a member of any older
5079  * MultiXactIds than that. (We have to do this even if we end up just
5080  * using our own TransactionId below, since some other backend could
5081  * incorporate our XID into a MultiXact immediately afterwards.)
5082  */
5084 
5085  /*
5086  * Compute the new xmax and infomask to store into the tuple. Note we do
5087  * not modify the tuple just yet, because that would leave it in the wrong
5088  * state if multixact.c elogs.
5089  */
5090  compute_new_xmax_infomask(xmax, old_infomask, tuple->t_data->t_infomask2,
5091  GetCurrentTransactionId(), mode, false,
5092  &xid, &new_infomask, &new_infomask2);
5093 
5095 
5096  /*
5097  * Store transaction information of xact locking the tuple.
5098  *
5099  * Note: Cmax is meaningless in this context, so don't set it; this avoids
5100  * possibly generating a useless combo CID. Moreover, if we're locking a
5101  * previously updated tuple, it's important to preserve the Cmax.
5102  *
5103  * Also reset the HOT UPDATE bit, but only if there's no update; otherwise
5104  * we would break the HOT chain.
5105  */
5106  tuple->t_data->t_infomask &= ~HEAP_XMAX_BITS;
5107  tuple->t_data->t_infomask2 &= ~HEAP_KEYS_UPDATED;
5108  tuple->t_data->t_infomask |= new_infomask;