PostgreSQL Source Code git master
Loading...
Searching...
No Matches
heapam.c File Reference
#include "postgres.h"
#include "access/heapam.h"
#include "access/heaptoast.h"
#include "access/hio.h"
#include "access/multixact.h"
#include "access/subtrans.h"
#include "access/syncscan.h"
#include "access/valid.h"
#include "access/visibilitymap.h"
#include "access/xloginsert.h"
#include "catalog/pg_database.h"
#include "catalog/pg_database_d.h"
#include "commands/vacuum.h"
#include "executor/instrument_node.h"
#include "pgstat.h"
#include "port/pg_bitutils.h"
#include "storage/lmgr.h"
#include "storage/predicate.h"
#include "storage/proc.h"
#include "storage/procarray.h"
#include "utils/datum.h"
#include "utils/injection_point.h"
#include "utils/inval.h"
#include "utils/spccache.h"
#include "utils/syscache.h"
Include dependency graph for heapam.c:

Go to the source code of this file.

Data Structures

struct  IndexDeleteCounts
 

Macros

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

Typedefs

typedef struct IndexDeleteCounts IndexDeleteCounts
 

Functions

static HeapTuple heap_prepare_insert (Relation relation, HeapTuple tup, TransactionId xid, CommandId cid, uint32 options)
 
static XLogRecPtr log_heap_update (Relation reln, Buffer oldbuf, Buffer vmbuffer_old, Buffer newbuf, Buffer vmbuffer_new, HeapTuple oldtup, HeapTuple newtup, HeapTuple old_key_tuple, bool all_visible_cleared, bool new_all_visible_cleared, bool walLogical)
 
static BitmapsetHeapDetermineColumnsInfo (Relation relation, Bitmapset *interesting_cols, Bitmapset *external_cols, HeapTuple oldtup, HeapTuple newtup, bool *has_external)
 
static bool heap_acquire_tuplock (Relation relation, const ItemPointerData *tid, LockTupleMode mode, LockWaitPolicy wait_policy, bool *have_tuple_lock)
 
static BlockNumber heapgettup_advance_block (HeapScanDesc scan, BlockNumber block, ScanDirection dir)
 
static pg_noinline BlockNumber heapgettup_initial_block (HeapScanDesc scan, ScanDirection dir)
 
static void compute_new_xmax_infomask (TransactionId xmax, uint16 old_infomask, uint16 old_infomask2, TransactionId add_to_xmax, LockTupleMode mode, bool is_update, TransactionId *result_xmax, uint16 *result_infomask, uint16 *result_infomask2)
 
static TM_Result heap_lock_updated_tuple (Relation rel, uint16 prior_infomask, TransactionId prior_raw_xmax, const ItemPointerData *prior_ctid, TransactionId xid, LockTupleMode mode)
 
static void GetMultiXactIdHintBits (MultiXactId multi, uint16 *new_infomask, uint16 *new_infomask2)
 
static TransactionId MultiXactIdGetUpdateXid (TransactionId xmax, uint16 t_infomask)
 
static bool DoesMultiXactIdConflict (MultiXactId multi, uint16 infomask, LockTupleMode lockmode, bool *current_is_member)
 
static void MultiXactIdWait (MultiXactId multi, MultiXactStatus status, uint16 infomask, Relation rel, const ItemPointerData *ctid, XLTW_Oper oper, int *remaining)
 
static bool ConditionalMultiXactIdWait (MultiXactId multi, MultiXactStatus status, uint16 infomask, Relation rel, int *remaining, bool logLockFailure)
 
static void index_delete_sort (TM_IndexDeleteOp *delstate)
 
static int bottomup_sort_and_shrink (TM_IndexDeleteOp *delstate)
 
static XLogRecPtr log_heap_new_cid (Relation relation, HeapTuple tup)
 
static HeapTuple ExtractReplicaIdentity (Relation relation, HeapTuple tp, bool key_required, bool *copy)
 
static void AssertHasSnapshotForToast (Relation rel)
 
static BlockNumber heap_scan_stream_read_next_parallel (ReadStream *stream, void *callback_private_data, void *per_buffer_data)
 
static BlockNumber heap_scan_stream_read_next_serial (ReadStream *stream, void *callback_private_data, void *per_buffer_data)
 
static BlockNumber bitmapheap_stream_read_next (ReadStream *pgsr, void *private_data, void *per_buffer_data)
 
static void initscan (HeapScanDesc scan, ScanKey key, bool keep_startblock)
 
void heap_setscanlimits (TableScanDesc sscan, BlockNumber startBlk, BlockNumber numBlks)
 
static pg_always_inline int page_collect_tuples (HeapScanDesc scan, Snapshot snapshot, Page page, Buffer buffer, BlockNumber block, int lines, bool all_visible, bool check_serializable)
 
void heap_prepare_pagescan (TableScanDesc sscan)
 
static void heap_fetch_next_buffer (HeapScanDesc scan, ScanDirection dir)
 
static Page heapgettup_start_page (HeapScanDesc scan, ScanDirection dir, int *linesleft, OffsetNumber *lineoff)
 
static Page heapgettup_continue_page (HeapScanDesc scan, ScanDirection dir, int *linesleft, OffsetNumber *lineoff)
 
static void heapgettup (HeapScanDesc scan, ScanDirection dir, int nkeys, ScanKey key)
 
static void heapgettup_pagemode (HeapScanDesc scan, ScanDirection dir, int nkeys, ScanKey key)
 
TableScanDesc heap_beginscan (Relation relation, Snapshot snapshot, int nkeys, ScanKey key, ParallelTableScanDesc parallel_scan, uint32 flags)
 
void heap_rescan (TableScanDesc sscan, ScanKey key, bool set_params, bool allow_strat, bool allow_sync, bool allow_pagemode)
 
void heap_endscan (TableScanDesc sscan)
 
HeapTuple heap_getnext (TableScanDesc sscan, ScanDirection direction)
 
bool heap_getnextslot (TableScanDesc sscan, ScanDirection direction, TupleTableSlot *slot)
 
void heap_set_tidrange (TableScanDesc sscan, ItemPointer mintid, ItemPointer maxtid)
 
bool heap_getnextslot_tidrange (TableScanDesc sscan, ScanDirection direction, TupleTableSlot *slot)
 
bool heap_fetch (Relation relation, Snapshot snapshot, HeapTuple tuple, Buffer *userbuf, bool keep_buf)
 
void heap_get_latest_tid (TableScanDesc sscan, ItemPointer tid)
 
static void UpdateXmaxHintBits (HeapTupleHeader tuple, Buffer buffer, TransactionId xid)
 
BulkInsertState GetBulkInsertState (void)
 
void FreeBulkInsertState (BulkInsertState bistate)
 
void ReleaseBulkInsertStatePin (BulkInsertState bistate)
 
void heap_insert (Relation relation, HeapTuple tup, CommandId cid, uint32 options, BulkInsertState bistate)
 
static int heap_multi_insert_pages (HeapTuple *heaptuples, int done, int ntuples, Size saveFreeSpace)
 
void heap_multi_insert (Relation relation, TupleTableSlot **slots, int ntuples, CommandId cid, uint32 options, BulkInsertState bistate)
 
void simple_heap_insert (Relation relation, HeapTuple tup)
 
static uint8 compute_infobits (uint16 infomask, uint16 infomask2)
 
static bool xmax_infomask_changed (uint16 new_infomask, uint16 old_infomask)
 
TM_Result heap_delete (Relation relation, const ItemPointerData *tid, CommandId cid, uint32 options, Snapshot crosscheck, bool wait, TM_FailureData *tmfd)
 
void simple_heap_delete (Relation relation, const ItemPointerData *tid)
 
TM_Result heap_update (Relation relation, const ItemPointerData *otid, HeapTuple newtup, CommandId cid, uint32 options pg_attribute_unused(), Snapshot crosscheck, bool wait, TM_FailureData *tmfd, LockTupleMode *lockmode, TU_UpdateIndexes *update_indexes)
 
static bool heap_attr_equals (TupleDesc tupdesc, int attrnum, Datum value1, Datum value2, bool isnull1, bool isnull2)
 
void simple_heap_update (Relation relation, const ItemPointerData *otid, HeapTuple tup, TU_UpdateIndexes *update_indexes)
 
static MultiXactStatus get_mxact_status_for_lock (LockTupleMode mode, bool is_update)
 
TM_Result heap_lock_tuple (Relation relation, HeapTuple tuple, CommandId cid, LockTupleMode mode, LockWaitPolicy wait_policy, bool follow_updates, Buffer *buffer, TM_FailureData *tmfd)
 
static TM_Result test_lockmode_for_conflict (MultiXactStatus status, TransactionId xid, LockTupleMode mode, HeapTuple tup, bool *needwait)
 
static TM_Result heap_lock_updated_tuple_rec (Relation rel, TransactionId priorXmax, const ItemPointerData *tid, TransactionId xid, LockTupleMode mode)
 
void heap_finish_speculative (Relation relation, const ItemPointerData *tid)
 
void heap_abort_speculative (Relation relation, const ItemPointerData *tid)
 
bool heap_inplace_lock (Relation relation, HeapTuple oldtup_ptr, Buffer buffer, void(*release_callback)(void *), void *arg)
 
void heap_inplace_update_and_unlock (Relation relation, HeapTuple oldtup, HeapTuple tuple, Buffer buffer)
 
void heap_inplace_unlock (Relation relation, HeapTuple oldtup, Buffer buffer)
 
static TransactionId FreezeMultiXactId (MultiXactId multi, uint16 t_infomask, const struct VacuumCutoffs *cutoffs, uint16 *flags, HeapPageFreeze *pagefrz)
 
bool heap_prepare_freeze_tuple (HeapTupleHeader tuple, const struct VacuumCutoffs *cutoffs, HeapPageFreeze *pagefrz, HeapTupleFreeze *frz, bool *totally_frozen)
 
void heap_pre_freeze_checks (Buffer buffer, HeapTupleFreeze *tuples, int ntuples)
 
void heap_freeze_prepared_tuples (Buffer buffer, HeapTupleFreeze *tuples, int ntuples)
 
bool heap_freeze_tuple (HeapTupleHeader tuple, TransactionId relfrozenxid, TransactionId relminmxid, TransactionId FreezeLimit, TransactionId MultiXactCutoff)
 
TransactionId HeapTupleGetUpdateXid (const HeapTupleHeaderData *tup)
 
static bool Do_MultiXactIdWait (MultiXactId multi, MultiXactStatus status, uint16 infomask, bool nowait, Relation rel, const ItemPointerData *ctid, XLTW_Oper oper, int *remaining, bool logLockFailure)
 
bool heap_tuple_needs_eventual_freeze (HeapTupleHeader tuple)
 
bool heap_tuple_should_freeze (HeapTupleHeader tuple, const struct VacuumCutoffs *cutoffs, TransactionId *NoFreezePageRelfrozenXid, MultiXactId *NoFreezePageRelminMxid)
 
void HeapTupleHeaderAdvanceConflictHorizon (HeapTupleHeader tuple, TransactionId *snapshotConflictHorizon)
 
static void index_delete_check_htid (TM_IndexDeleteOp *delstate, Page page, OffsetNumber maxoff, const ItemPointerData *htid, TM_IndexStatus *istatus)
 
TransactionId heap_index_delete_tuples (Relation rel, TM_IndexDeleteOp *delstate)
 
static int index_delete_sort_cmp (TM_IndexDelete *deltid1, TM_IndexDelete *deltid2)
 
static int bottomup_nblocksfavorable (IndexDeleteCounts *blockgroups, int nblockgroups, TM_IndexDelete *deltids)
 
static int bottomup_sort_and_shrink_cmp (const void *arg1, const void *arg2)
 
void HeapCheckForSerializableConflictOut (bool visible, Relation relation, HeapTuple tuple, Buffer buffer, Snapshot snapshot)
 

Variables

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

Macro Definition Documentation

◆ BOTTOMUP_MAX_NBLOCKS

#define BOTTOMUP_MAX_NBLOCKS   6

Definition at line 192 of file heapam.c.

◆ BOTTOMUP_TOLERANCE_NBLOCKS

#define BOTTOMUP_TOLERANCE_NBLOCKS   3

Definition at line 193 of file heapam.c.

◆ ConditionalLockTupleTuplock

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

Definition at line 174 of file heapam.c.

182{
184 int next_item;
185 int ndeltids;
186 TM_IndexDelete *deltids;
188#endif
189
190/* heap_index_delete_tuples bottom-up index deletion costing constants */
191#define BOTTOMUP_MAX_NBLOCKS 6
192#define BOTTOMUP_TOLERANCE_NBLOCKS 3
193
194/*
195 * heap_index_delete_tuples uses this when determining which heap blocks it
196 * must visit to help its bottom-up index deletion caller
197 */
198typedef struct IndexDeleteCounts
199{
200 int16 npromisingtids; /* Number of "promising" TIDs in group */
201 int16 ntids; /* Number of TIDs in group */
202 int16 ifirsttid; /* Offset to group's first deltid */
204
205/*
206 * This table maps tuple lock strength values for each particular
207 * MultiXactStatus value.
208 */
209static const int MultiXactStatusLock[MaxMultiXactStatus + 1] =
210{
211 LockTupleKeyShare, /* ForKeyShare */
212 LockTupleShare, /* ForShare */
213 LockTupleNoKeyExclusive, /* ForNoKeyUpdate */
214 LockTupleExclusive, /* ForUpdate */
215 LockTupleNoKeyExclusive, /* NoKeyUpdate */
216 LockTupleExclusive /* Update */
217};
218
219/* Get the LockTupleMode for a given MultiXactStatus */
220#define TUPLOCK_from_mxstatus(status) \
221 (MultiXactStatusLock[(status)])
222
223/*
224 * Check that we have a valid snapshot if we might need TOAST access.
225 */
226static inline void
228{
229#ifdef USE_ASSERT_CHECKING
230
231 /* bootstrap mode in particular breaks this rule */
233 return;
234
235 /* if the relation doesn't have a TOAST table, we are good */
236 if (!OidIsValid(rel->rd_rel->reltoastrelid))
237 return;
238
240
241#endif /* USE_ASSERT_CHECKING */
242}
243
244/* ----------------------------------------------------------------
245 * heap support routines
246 * ----------------------------------------------------------------
247 */
248
249/*
250 * Streaming read API callback for parallel sequential scans. Returns the next
251 * block the caller wants from the read stream or InvalidBlockNumber when done.
252 */
253static BlockNumber
255 void *callback_private_data,
256 void *per_buffer_data)
257{
258 HeapScanDesc scan = (HeapScanDesc) callback_private_data;
259
262
263 if (unlikely(!scan->rs_inited))
264 {
265 /* parallel scan */
269 scan->rs_startblock,
270 scan->rs_numblocks);
271
272 /* may return InvalidBlockNumber if there are no more blocks */
276 scan->rs_inited = true;
277 }
278 else
279 {
282 scan->rs_base.rs_parallel);
283 }
284
285 return scan->rs_prefetch_block;
286}
287
288/*
289 * Streaming read API callback for serial sequential and TID range scans.
290 * Returns the next block the caller wants from the read stream or
291 * InvalidBlockNumber when done.
292 */
293static BlockNumber
295 void *callback_private_data,
296 void *per_buffer_data)
297{
298 HeapScanDesc scan = (HeapScanDesc) callback_private_data;
299
300 if (unlikely(!scan->rs_inited))
301 {
303 scan->rs_inited = true;
304 }
305 else
307 scan->rs_prefetch_block,
308 scan->rs_dir);
309
310 return scan->rs_prefetch_block;
311}
312
313/*
314 * Read stream API callback for bitmap heap scans.
315 * Returns the next block the caller wants from the read stream or
316 * InvalidBlockNumber when done.
317 */
318static BlockNumber
319bitmapheap_stream_read_next(ReadStream *pgsr, void *private_data,
320 void *per_buffer_data)
321{
322 TBMIterateResult *tbmres = per_buffer_data;
325 TableScanDesc sscan = &hscan->rs_base;
326
327 for (;;)
328 {
330
331 /* no more entries in the bitmap */
332 if (!tbm_iterate(&sscan->st.rs_tbmiterator, tbmres))
333 return InvalidBlockNumber;
334
335 /*
336 * Ignore any claimed entries past what we think is the end of the
337 * relation. It may have been extended after the start of our scan (we
338 * only hold an AccessShareLock, and it could be inserts from this
339 * backend). We don't take this optimization in SERIALIZABLE
340 * isolation though, as we need to examine all invisible tuples
341 * reachable by the index.
342 */
344 tbmres->blockno >= hscan->rs_nblocks)
345 continue;
346
347 return tbmres->blockno;
348 }
349
350 /* not reachable */
351 Assert(false);
352}
353
354/* ----------------
355 * initscan - scan code common to heap_beginscan and heap_rescan
356 * ----------------
357 */
358static void
360{
362 bool allow_strat;
363 bool allow_sync;
364
365 /*
366 * Determine the number of blocks we have to scan.
367 *
368 * It is sufficient to do this once at scan start, since any tuples added
369 * while the scan is in progress will be invisible to my snapshot anyway.
370 * (That is not true when using a non-MVCC snapshot. However, we couldn't
371 * guarantee to return tuples added after scan start anyway, since they
372 * might go into pages we already scanned. To guarantee consistent
373 * results for a non-MVCC snapshot, the caller must hold some higher-level
374 * lock that ensures the interesting tuple(s) won't change.)
375 */
376 if (scan->rs_base.rs_parallel != NULL)
377 {
379 scan->rs_nblocks = bpscan->phs_nblocks;
380 }
381 else
383
384 /*
385 * If the table is large relative to NBuffers, use a bulk-read access
386 * strategy and enable synchronized scanning (see syncscan.c). Although
387 * the thresholds for these features could be different, we make them the
388 * same so that there are only two behaviors to tune rather than four.
389 * (However, some callers need to be able to disable one or both of these
390 * behaviors, independently of the size of the table; also there is a GUC
391 * variable that can disable synchronized scanning.)
392 *
393 * Note that table_block_parallelscan_initialize has a very similar test;
394 * if you change this, consider changing that one, too.
395 */
397 scan->rs_nblocks > NBuffers / 4)
398 {
400 allow_sync = (scan->rs_base.rs_flags & SO_ALLOW_SYNC) != 0;
401 }
402 else
403 allow_strat = allow_sync = false;
404
405 if (allow_strat)
406 {
407 /* During a rescan, keep the previous strategy object. */
408 if (scan->rs_strategy == NULL)
410 }
411 else
412 {
413 if (scan->rs_strategy != NULL)
415 scan->rs_strategy = NULL;
416 }
417
418 if (scan->rs_base.rs_parallel != NULL)
419 {
420 /* For parallel scan, believe whatever ParallelTableScanDesc says. */
423 else
425
426 /*
427 * If not rescanning, initialize the startblock. Finding the actual
428 * start location is done in table_block_parallelscan_startblock_init,
429 * based on whether an alternative start location has been set with
430 * heap_setscanlimits, or using the syncscan location, when syncscan
431 * is enabled.
432 */
433 if (!keep_startblock)
435 }
436 else
437 {
438 if (keep_startblock)
439 {
440 /*
441 * When rescanning, we want to keep the previous startblock
442 * setting, so that rewinding a cursor doesn't generate surprising
443 * results. Reset the active syncscan setting, though.
444 */
447 else
449 }
451 {
454 }
455 else
456 {
458 scan->rs_startblock = 0;
459 }
460 }
461
463 scan->rs_inited = false;
464 scan->rs_ctup.t_data = NULL;
466 scan->rs_cbuf = InvalidBuffer;
468 scan->rs_ntuples = 0;
469 scan->rs_cindex = 0;
470
471 /*
472 * Initialize to ForwardScanDirection because it is most common and
473 * because heap scans go forward before going backward (e.g. CURSORs).
474 */
477
478 /* page-at-a-time fields are always invalid when not rs_inited */
479
480 /*
481 * copy the scan key, if appropriate
482 */
483 if (key != NULL && scan->rs_base.rs_nkeys > 0)
484 memcpy(scan->rs_base.rs_key, key, scan->rs_base.rs_nkeys * sizeof(ScanKeyData));
485
486 /*
487 * Currently, we only have a stats counter for sequential heap scans (but
488 * e.g for bitmap scans the underlying bitmap index scans will be counted,
489 * and for sample scans we update stats for tuple fetches).
490 */
491 if (scan->rs_base.rs_flags & SO_TYPE_SEQSCAN)
493}
494
495/*
496 * heap_setscanlimits - restrict range of a heapscan
497 *
498 * startBlk is the page to start at
499 * numBlks is number of pages to scan (InvalidBlockNumber means "all")
500 */
501void
503{
505
506 Assert(!scan->rs_inited); /* else too late to change */
507 /* else rs_startblock is significant */
509
510 /* Check startBlk is valid (but allow case of zero blocks...) */
511 Assert(startBlk == 0 || startBlk < scan->rs_nblocks);
512
513 scan->rs_startblock = startBlk;
514 scan->rs_numblocks = numBlks;
515}
516
517/*
518 * Per-tuple loop for heap_prepare_pagescan(). Pulled out so it can be called
519 * multiple times, with constant arguments for all_visible,
520 * check_serializable.
521 */
523static int
525 Page page, Buffer buffer,
526 BlockNumber block, int lines,
527 bool all_visible, bool check_serializable)
528{
529 Oid relid = RelationGetRelid(scan->rs_base.rs_rd);
530 int ntup = 0;
531 int nvis = 0;
533
534 /* page at a time should have been disabled otherwise */
535 Assert(IsMVCCSnapshot(snapshot));
536
537 /* first find all tuples on the page */
539 {
542
544 continue;
545
546 /*
547 * If the page is not all-visible or we need to check serializability,
548 * maintain enough state to be able to refind the tuple efficiently,
549 * without again first needing to fetch the item and then via that the
550 * tuple.
551 */
552 if (!all_visible || check_serializable)
553 {
554 tup = &batchmvcc.tuples[ntup];
555
557 tup->t_len = ItemIdGetLength(lpp);
558 tup->t_tableOid = relid;
559 ItemPointerSet(&(tup->t_self), block, lineoff);
560 }
561
562 /*
563 * If the page is all visible, these fields otherwise won't be
564 * populated in loop below.
565 */
566 if (all_visible)
567 {
569 {
570 batchmvcc.visible[ntup] = true;
571 }
572 scan->rs_vistuples[ntup] = lineoff;
573 }
574
575 ntup++;
576 }
577
579
580 /*
581 * Unless the page is all visible, test visibility for all tuples one go.
582 * That is considerably more efficient than calling
583 * HeapTupleSatisfiesMVCC() one-by-one.
584 */
585 if (all_visible)
586 nvis = ntup;
587 else
588 nvis = HeapTupleSatisfiesMVCCBatch(snapshot, buffer,
589 ntup,
590 &batchmvcc,
591 scan->rs_vistuples);
592
593 /*
594 * So far we don't have batch API for testing serializabilty, so do so
595 * one-by-one.
596 */
598 {
599 for (int i = 0; i < ntup; i++)
600 {
602 scan->rs_base.rs_rd,
603 &batchmvcc.tuples[i],
604 buffer, snapshot);
605 }
606 }
607
608 return nvis;
609}
610
611/*
612 * heap_prepare_pagescan - Prepare current scan page to be scanned in pagemode
613 *
614 * Preparation currently consists of 1. prune the scan's rs_cbuf page, and 2.
615 * fill the rs_vistuples[] array with the OffsetNumbers of visible tuples.
616 */
617void
619{
621 Buffer buffer = scan->rs_cbuf;
622 BlockNumber block = scan->rs_cblock;
623 Snapshot snapshot;
624 Page page;
625 int lines;
626 bool all_visible;
628
629 Assert(BufferGetBlockNumber(buffer) == block);
630
631 /* ensure we're not accidentally being used when not in pagemode */
633 snapshot = scan->rs_base.rs_snapshot;
634
635 /*
636 * Prune and repair fragmentation for the whole page, if possible.
637 */
638 heap_page_prune_opt(scan->rs_base.rs_rd, buffer, &scan->rs_vmbuffer,
639 sscan->rs_flags & SO_HINT_REL_READ_ONLY);
640
641 /*
642 * We must hold share lock on the buffer content while examining tuple
643 * visibility. Afterwards, however, the tuples we have found to be
644 * visible are guaranteed good as long as we hold the buffer pin.
645 */
647
648 page = BufferGetPage(buffer);
649 lines = PageGetMaxOffsetNumber(page);
650
651 /*
652 * If the all-visible flag indicates that all tuples on the page are
653 * visible to everyone, we can skip the per-tuple visibility tests.
654 *
655 * Note: In hot standby, a tuple that's already visible to all
656 * transactions on the primary might still be invisible to a read-only
657 * transaction in the standby. We partly handle this problem by tracking
658 * the minimum xmin of visible tuples as the cut-off XID while marking a
659 * page all-visible on the primary and WAL log that along with the
660 * visibility map SET operation. In hot standby, we wait for (or abort)
661 * all transactions that can potentially may not see one or more tuples on
662 * the page. That's how index-only scans work fine in hot standby. A
663 * crucial difference between index-only scans and heap scans is that the
664 * index-only scan completely relies on the visibility map where as heap
665 * scan looks at the page-level PD_ALL_VISIBLE flag. We are not sure if
666 * the page-level flag can be trusted in the same way, because it might
667 * get propagated somehow without being explicitly WAL-logged, e.g. via a
668 * full page write. Until we can prove that beyond doubt, let's check each
669 * tuple for visibility the hard way.
670 */
671 all_visible = PageIsAllVisible(page) && !snapshot->takenDuringRecovery;
674
675 /*
676 * We call page_collect_tuples() with constant arguments, to get the
677 * compiler to constant fold the constant arguments. Separate calls with
678 * constant arguments, rather than variables, are needed on several
679 * compilers to actually perform constant folding.
680 */
681 if (likely(all_visible))
682 {
684 scan->rs_ntuples = page_collect_tuples(scan, snapshot, page, buffer,
685 block, lines, true, false);
686 else
687 scan->rs_ntuples = page_collect_tuples(scan, snapshot, page, buffer,
688 block, lines, true, true);
689 }
690 else
691 {
693 scan->rs_ntuples = page_collect_tuples(scan, snapshot, page, buffer,
694 block, lines, false, false);
695 else
696 scan->rs_ntuples = page_collect_tuples(scan, snapshot, page, buffer,
697 block, lines, false, true);
698 }
699
701}
702
703/*
704 * heap_fetch_next_buffer - read and pin the next block from MAIN_FORKNUM.
705 *
706 * Read the next block of the scan relation from the read stream and save it
707 * in the scan descriptor. It is already pinned.
708 */
709static inline void
711{
712 Assert(scan->rs_read_stream);
713
714 /* release previous scan buffer, if any */
715 if (BufferIsValid(scan->rs_cbuf))
716 {
717 ReleaseBuffer(scan->rs_cbuf);
718 scan->rs_cbuf = InvalidBuffer;
719 }
720
721 /*
722 * Be sure to check for interrupts at least once per page. Checks at
723 * higher code levels won't be able to stop a seqscan that encounters many
724 * pages' worth of consecutive dead tuples.
725 */
727
728 /*
729 * If the scan direction is changing, reset the prefetch block to the
730 * current block. Otherwise, we will incorrectly prefetch the blocks
731 * between the prefetch block and the current block again before
732 * prefetching blocks in the new, correct scan direction.
733 */
734 if (unlikely(scan->rs_dir != dir))
735 {
736 scan->rs_prefetch_block = scan->rs_cblock;
738 }
739
740 scan->rs_dir = dir;
741
743 if (BufferIsValid(scan->rs_cbuf))
745}
746
747/*
748 * heapgettup_initial_block - return the first BlockNumber to scan
749 *
750 * Returns InvalidBlockNumber when there are no blocks to scan. This can
751 * occur with empty tables and in parallel scans when parallel workers get all
752 * of the pages before we can get a chance to get our first page.
753 */
756{
757 Assert(!scan->rs_inited);
758 Assert(scan->rs_base.rs_parallel == NULL);
759
760 /* When there are no pages to scan, return InvalidBlockNumber */
761 if (scan->rs_nblocks == 0 || scan->rs_numblocks == 0)
762 return InvalidBlockNumber;
763
764 if (ScanDirectionIsForward(dir))
765 {
766 return scan->rs_startblock;
767 }
768 else
769 {
770 /*
771 * Disable reporting to syncscan logic in a backwards scan; it's not
772 * very likely anyone else is doing the same thing at the same time,
773 * and much more likely that we'll just bollix things for forward
774 * scanners.
775 */
777
778 /*
779 * Start from last page of the scan. Ensure we take into account
780 * rs_numblocks if it's been adjusted by heap_setscanlimits().
781 */
782 if (scan->rs_numblocks != InvalidBlockNumber)
783 return (scan->rs_startblock + scan->rs_numblocks - 1) % scan->rs_nblocks;
784
785 if (scan->rs_startblock > 0)
786 return scan->rs_startblock - 1;
787
788 return scan->rs_nblocks - 1;
789 }
790}
791
792
793/*
794 * heapgettup_start_page - helper function for heapgettup()
795 *
796 * Return the next page to scan based on the scan->rs_cbuf and set *linesleft
797 * to the number of tuples on this page. Also set *lineoff to the first
798 * offset to scan with forward scans getting the first offset and backward
799 * getting the final offset on the page.
800 */
801static Page
804{
805 Page page;
806
807 Assert(scan->rs_inited);
809
810 /* Caller is responsible for ensuring buffer is locked if needed */
811 page = BufferGetPage(scan->rs_cbuf);
812
814
815 if (ScanDirectionIsForward(dir))
817 else
819
820 /* lineoff now references the physically previous or next tid */
821 return page;
822}
823
824
825/*
826 * heapgettup_continue_page - helper function for heapgettup()
827 *
828 * Return the next page to scan based on the scan->rs_cbuf and set *linesleft
829 * to the number of tuples left to scan on this page. Also set *lineoff to
830 * the next offset to scan according to the ScanDirection in 'dir'.
831 */
832static inline Page
835{
836 Page page;
837
838 Assert(scan->rs_inited);
840
841 /* Caller is responsible for ensuring buffer is locked if needed */
842 page = BufferGetPage(scan->rs_cbuf);
843
844 if (ScanDirectionIsForward(dir))
845 {
847 *linesleft = PageGetMaxOffsetNumber(page) - (*lineoff) + 1;
848 }
849 else
850 {
851 /*
852 * The previous returned tuple may have been vacuumed since the
853 * previous scan when we use a non-MVCC snapshot, so we must
854 * re-establish the lineoff <= PageGetMaxOffsetNumber(page) invariant
855 */
857 *linesleft = *lineoff;
858 }
859
860 /* lineoff now references the physically previous or next tid */
861 return page;
862}
863
864/*
865 * heapgettup_advance_block - helper for heap_fetch_next_buffer()
866 *
867 * Given the current block number, the scan direction, and various information
868 * contained in the scan descriptor, calculate the BlockNumber to scan next
869 * and return it. If there are no further blocks to scan, return
870 * InvalidBlockNumber to indicate this fact to the caller.
871 *
872 * This should not be called to determine the initial block number -- only for
873 * subsequent blocks.
874 *
875 * This also adjusts rs_numblocks when a limit has been imposed by
876 * heap_setscanlimits().
877 */
878static inline BlockNumber
880{
881 Assert(scan->rs_base.rs_parallel == NULL);
882
884 {
885 block++;
886
887 /* wrap back to the start of the heap */
888 if (block >= scan->rs_nblocks)
889 block = 0;
890
891 /*
892 * Report our new scan position for synchronization purposes. We don't
893 * do that when moving backwards, however. That would just mess up any
894 * other forward-moving scanners.
895 *
896 * Note: we do this before checking for end of scan so that the final
897 * state of the position hint is back at the start of the rel. That's
898 * not strictly necessary, but otherwise when you run the same query
899 * multiple times the starting position would shift a little bit
900 * backwards on every invocation, which is confusing. We don't
901 * guarantee any specific ordering in general, though.
902 */
903 if (scan->rs_base.rs_flags & SO_ALLOW_SYNC)
904 ss_report_location(scan->rs_base.rs_rd, block);
905
906 /* we're done if we're back at where we started */
907 if (block == scan->rs_startblock)
908 return InvalidBlockNumber;
909
910 /* check if the limit imposed by heap_setscanlimits() is met */
911 if (scan->rs_numblocks != InvalidBlockNumber)
912 {
913 if (--scan->rs_numblocks == 0)
914 return InvalidBlockNumber;
915 }
916
917 return block;
918 }
919 else
920 {
921 /* we're done if the last block is the start position */
922 if (block == scan->rs_startblock)
923 return InvalidBlockNumber;
924
925 /* check if the limit imposed by heap_setscanlimits() is met */
926 if (scan->rs_numblocks != InvalidBlockNumber)
927 {
928 if (--scan->rs_numblocks == 0)
929 return InvalidBlockNumber;
930 }
931
932 /* wrap to the end of the heap when the last page was page 0 */
933 if (block == 0)
934 block = scan->rs_nblocks;
935
936 block--;
937
938 return block;
939 }
940}
941
942/* ----------------
943 * heapgettup - fetch next heap tuple
944 *
945 * Initialize the scan if not already done; then advance to the next
946 * tuple as indicated by "dir"; return the next tuple in scan->rs_ctup,
947 * or set scan->rs_ctup.t_data = NULL if no more tuples.
948 *
949 * Note: the reason nkeys/key are passed separately, even though they are
950 * kept in the scan descriptor, is that the caller may not want us to check
951 * the scankeys.
952 *
953 * Note: when we fall off the end of the scan in either direction, we
954 * reset rs_inited. This means that a further request with the same
955 * scan direction will restart the scan, which is a bit odd, but a
956 * request with the opposite scan direction will start a fresh scan
957 * in the proper direction. The latter is required behavior for cursors,
958 * while the former case is generally undefined behavior in Postgres
959 * so we don't care too much.
960 * ----------------
961 */
962static void
964 ScanDirection dir,
965 int nkeys,
966 ScanKey key)
967{
968 HeapTuple tuple = &(scan->rs_ctup);
969 Page page;
971 int linesleft;
972
973 if (likely(scan->rs_inited))
974 {
975 /* continue from previously returned page/tuple */
977 page = heapgettup_continue_page(scan, dir, &linesleft, &lineoff);
978 goto continue_page;
979 }
980
981 /*
982 * advance the scan until we find a qualifying tuple or run out of stuff
983 * to scan
984 */
985 while (true)
986 {
987 heap_fetch_next_buffer(scan, dir);
988
989 /* did we run out of blocks to scan? */
990 if (!BufferIsValid(scan->rs_cbuf))
991 break;
992
994
996 page = heapgettup_start_page(scan, dir, &linesleft, &lineoff);
998
999 /*
1000 * Only continue scanning the page while we have lines left.
1001 *
1002 * Note that this protects us from accessing line pointers past
1003 * PageGetMaxOffsetNumber(); both for forward scans when we resume the
1004 * table scan, and for when we start scanning a new page.
1005 */
1006 for (; linesleft > 0; linesleft--, lineoff += dir)
1007 {
1008 bool visible;
1010
1011 if (!ItemIdIsNormal(lpp))
1012 continue;
1013
1014 tuple->t_data = (HeapTupleHeader) PageGetItem(page, lpp);
1015 tuple->t_len = ItemIdGetLength(lpp);
1016 ItemPointerSet(&(tuple->t_self), scan->rs_cblock, lineoff);
1017
1018 visible = HeapTupleSatisfiesVisibility(tuple,
1019 scan->rs_base.rs_snapshot,
1020 scan->rs_cbuf);
1021
1023 tuple, scan->rs_cbuf,
1024 scan->rs_base.rs_snapshot);
1025
1026 /* skip tuples not visible to this snapshot */
1027 if (!visible)
1028 continue;
1029
1030 /* skip any tuples that don't match the scan key */
1031 if (key != NULL &&
1033 nkeys, key))
1034 continue;
1035
1037 scan->rs_coffset = lineoff;
1038 return;
1039 }
1040
1041 /*
1042 * if we get here, it means we've exhausted the items on this page and
1043 * it's time to move to the next.
1044 */
1046 }
1047
1048 /* end of scan */
1049 if (BufferIsValid(scan->rs_cbuf))
1050 ReleaseBuffer(scan->rs_cbuf);
1051
1052 scan->rs_cbuf = InvalidBuffer;
1055 tuple->t_data = NULL;
1056 scan->rs_inited = false;
1057}
1058
1059/* ----------------
1060 * heapgettup_pagemode - fetch next heap tuple in page-at-a-time mode
1061 *
1062 * Same API as heapgettup, but used in page-at-a-time mode
1063 *
1064 * The internal logic is much the same as heapgettup's too, but there are some
1065 * differences: we do not take the buffer content lock (that only needs to
1066 * happen inside heap_prepare_pagescan), and we iterate through just the
1067 * tuples listed in rs_vistuples[] rather than all tuples on the page. Notice
1068 * that lineindex is 0-based, where the corresponding loop variable lineoff in
1069 * heapgettup is 1-based.
1070 * ----------------
1071 */
1072static void
1074 ScanDirection dir,
1075 int nkeys,
1076 ScanKey key)
1077{
1078 HeapTuple tuple = &(scan->rs_ctup);
1079 Page page;
1082
1083 if (likely(scan->rs_inited))
1084 {
1085 /* continue from previously returned page/tuple */
1086 page = BufferGetPage(scan->rs_cbuf);
1087
1088 lineindex = scan->rs_cindex + dir;
1089 if (ScanDirectionIsForward(dir))
1090 linesleft = scan->rs_ntuples - lineindex;
1091 else
1092 linesleft = scan->rs_cindex;
1093 /* lineindex now references the next or previous visible tid */
1094
1095 goto continue_page;
1096 }
1097
1098 /*
1099 * advance the scan until we find a qualifying tuple or run out of stuff
1100 * to scan
1101 */
1102 while (true)
1103 {
1104 heap_fetch_next_buffer(scan, dir);
1105
1106 /* did we run out of blocks to scan? */
1107 if (!BufferIsValid(scan->rs_cbuf))
1108 break;
1109
1111
1112 /* prune the page and determine visible tuple offsets */
1114 page = BufferGetPage(scan->rs_cbuf);
1115 linesleft = scan->rs_ntuples;
1117
1118 /* block is the same for all tuples, set it once outside the loop */
1120
1121 /* lineindex now references the next or previous visible tid */
1123
1124 for (; linesleft > 0; linesleft--, lineindex += dir)
1125 {
1126 ItemId lpp;
1128
1129 Assert(lineindex < scan->rs_ntuples);
1131 lpp = PageGetItemId(page, lineoff);
1133
1134 tuple->t_data = (HeapTupleHeader) PageGetItem(page, lpp);
1135 tuple->t_len = ItemIdGetLength(lpp);
1137
1138 /* skip any tuples that don't match the scan key */
1139 if (key != NULL &&
1141 nkeys, key))
1142 continue;
1143
1144 scan->rs_cindex = lineindex;
1145 return;
1146 }
1147 }
1148
1149 /* end of scan */
1150 if (BufferIsValid(scan->rs_cbuf))
1151 ReleaseBuffer(scan->rs_cbuf);
1152 scan->rs_cbuf = InvalidBuffer;
1155 tuple->t_data = NULL;
1156 scan->rs_inited = false;
1157}
1158
1159
1160/* ----------------------------------------------------------------
1161 * heap access method interface
1162 * ----------------------------------------------------------------
1163 */
1164
1165
1167heap_beginscan(Relation relation, Snapshot snapshot,
1168 int nkeys, ScanKey key,
1169 ParallelTableScanDesc parallel_scan,
1170 uint32 flags)
1171{
1172 HeapScanDesc scan;
1173
1174 /*
1175 * increment relation ref count while scanning relation
1176 *
1177 * This is just to make really sure the relcache entry won't go away while
1178 * the scan has a pointer to it. Caller should be holding the rel open
1179 * anyway, so this is redundant in all normal scenarios...
1180 */
1182
1183 /*
1184 * allocate and initialize scan descriptor
1185 */
1186 if (flags & SO_TYPE_BITMAPSCAN)
1187 {
1189
1190 /*
1191 * Bitmap Heap scans do not have any fields that a normal Heap Scan
1192 * does not have, so no special initializations required here.
1193 */
1194 scan = (HeapScanDesc) bscan;
1195 }
1196 else
1198
1199 scan->rs_base.rs_rd = relation;
1200 scan->rs_base.rs_snapshot = snapshot;
1201 scan->rs_base.rs_nkeys = nkeys;
1202 scan->rs_base.rs_flags = flags;
1203 scan->rs_base.rs_parallel = parallel_scan;
1204 scan->rs_base.rs_instrument = NULL;
1205 scan->rs_strategy = NULL; /* set in initscan */
1206 scan->rs_cbuf = InvalidBuffer;
1207
1208 /*
1209 * Disable page-at-a-time mode if it's not a MVCC-safe snapshot.
1210 */
1211 if (!(snapshot && IsMVCCSnapshot(snapshot)))
1213
1214 /* Check that a historic snapshot is not used for non-catalog tables */
1215 if (snapshot &&
1216 IsHistoricMVCCSnapshot(snapshot) &&
1218 {
1219 ereport(ERROR,
1221 errmsg("cannot query non-catalog table \"%s\" during logical decoding",
1222 RelationGetRelationName(relation))));
1223 }
1224
1225 /*
1226 * For seqscan and sample scans in a serializable transaction, acquire a
1227 * predicate lock on the entire relation. This is required not only to
1228 * lock all the matching tuples, but also to conflict with new insertions
1229 * into the table. In an indexscan, we take page locks on the index pages
1230 * covering the range specified in the scan qual, but in a heap scan there
1231 * is nothing more fine-grained to lock. A bitmap scan is a different
1232 * story, there we have already scanned the index and locked the index
1233 * pages covering the predicate. But in that case we still have to lock
1234 * any matching heap tuples. For sample scan we could optimize the locking
1235 * to be at least page-level granularity, but we'd need to add per-tuple
1236 * locking for that.
1237 */
1239 {
1240 /*
1241 * Ensure a missing snapshot is noticed reliably, even if the
1242 * isolation mode means predicate locking isn't performed (and
1243 * therefore the snapshot isn't used here).
1244 */
1245 Assert(snapshot);
1246 PredicateLockRelation(relation, snapshot);
1247 }
1248
1249 /* we only need to set this up once */
1250 scan->rs_ctup.t_tableOid = RelationGetRelid(relation);
1251
1252 /*
1253 * Allocate memory to keep track of page allocation for parallel workers
1254 * when doing a parallel scan.
1255 */
1256 if (parallel_scan != NULL)
1258 else
1260
1261 /*
1262 * we do this here instead of in initscan() because heap_rescan also calls
1263 * initscan() and we don't want to allocate memory again
1264 */
1265 if (nkeys > 0)
1266 scan->rs_base.rs_key = palloc_array(ScanKeyData, nkeys);
1267 else
1268 scan->rs_base.rs_key = NULL;
1269
1270 initscan(scan, key, false);
1271
1272 scan->rs_read_stream = NULL;
1273
1274 /*
1275 * Set up a read stream for sequential scans and TID range scans. This
1276 * should be done after initscan() because initscan() allocates the
1277 * BufferAccessStrategy object passed to the read stream API.
1278 */
1279 if (scan->rs_base.rs_flags & SO_TYPE_SEQSCAN ||
1281 {
1283
1284 if (scan->rs_base.rs_parallel)
1286 else
1288
1289 /* ---
1290 * It is safe to use batchmode as the only locks taken by `cb`
1291 * are never taken while waiting for IO:
1292 * - SyncScanLock is used in the non-parallel case
1293 * - in the parallel case, only spinlocks and atomics are used
1294 * ---
1295 */
1298 scan->rs_strategy,
1299 scan->rs_base.rs_rd,
1301 cb,
1302 scan,
1303 0);
1304 }
1305 else if (scan->rs_base.rs_flags & SO_TYPE_BITMAPSCAN)
1306 {
1309 scan->rs_strategy,
1310 scan->rs_base.rs_rd,
1313 scan,
1314 sizeof(TBMIterateResult));
1315 }
1316
1317 /* enable read stream instrumentation */
1318 if ((flags & SO_SCAN_INSTRUMENT) && (scan->rs_read_stream != NULL))
1319 {
1322 &scan->rs_base.rs_instrument->io);
1323 }
1324
1325 scan->rs_vmbuffer = InvalidBuffer;
1326
1327 return (TableScanDesc) scan;
1328}
1329
1330void
1332 bool allow_strat, bool allow_sync, bool allow_pagemode)
1333{
1335
1336 if (set_params)
1337 {
1338 if (allow_strat)
1340 else
1342
1343 if (allow_sync)
1345 else
1347
1348 if (allow_pagemode && scan->rs_base.rs_snapshot &&
1351 else
1353 }
1354
1355 /*
1356 * unpin scan buffers
1357 */
1358 if (BufferIsValid(scan->rs_cbuf))
1359 {
1360 ReleaseBuffer(scan->rs_cbuf);
1361 scan->rs_cbuf = InvalidBuffer;
1362 }
1363
1364 if (BufferIsValid(scan->rs_vmbuffer))
1365 {
1367 scan->rs_vmbuffer = InvalidBuffer;
1368 }
1369
1370 /*
1371 * SO_TYPE_BITMAPSCAN would be cleaned up here, but it does not hold any
1372 * additional data vs a normal HeapScan
1373 */
1374
1375 /*
1376 * The read stream is reset on rescan. This must be done before
1377 * initscan(), as some state referred to by read_stream_reset() is reset
1378 * in initscan().
1379 */
1380 if (scan->rs_read_stream)
1382
1383 /*
1384 * reinitialize scan descriptor
1385 */
1386 initscan(scan, key, true);
1387}
1388
1389void
1391{
1393
1394 /* Note: no locking manipulations needed */
1395
1396 /*
1397 * unpin scan buffers
1398 */
1399 if (BufferIsValid(scan->rs_cbuf))
1400 ReleaseBuffer(scan->rs_cbuf);
1401
1402 if (BufferIsValid(scan->rs_vmbuffer))
1404
1405 /*
1406 * Must free the read stream before freeing the BufferAccessStrategy.
1407 */
1408 if (scan->rs_read_stream)
1410
1411 /*
1412 * decrement relation reference count and free scan descriptor storage
1413 */
1415
1416 if (scan->rs_base.rs_key)
1417 pfree(scan->rs_base.rs_key);
1418
1419 if (scan->rs_strategy != NULL)
1421
1422 if (scan->rs_parallelworkerdata != NULL)
1424
1425 if (scan->rs_base.rs_flags & SO_TEMP_SNAPSHOT)
1427
1428 if (scan->rs_base.rs_instrument)
1430
1431 pfree(scan);
1432}
1433
1436{
1438
1439 /*
1440 * This is still widely used directly, without going through table AM, so
1441 * add a safety check. It's possible we should, at a later point,
1442 * downgrade this to an assert. The reason for checking the AM routine,
1443 * rather than the AM oid, is that this allows to write regression tests
1444 * that create another AM reusing the heap handler.
1445 */
1446 if (unlikely(sscan->rs_rd->rd_tableam != GetHeapamTableAmRoutine()))
1447 ereport(ERROR,
1449 errmsg_internal("only heap AM is supported")));
1450
1451 /* Note: no locking manipulations needed */
1452
1454 heapgettup_pagemode(scan, direction,
1455 scan->rs_base.rs_nkeys, scan->rs_base.rs_key);
1456 else
1457 heapgettup(scan, direction,
1458 scan->rs_base.rs_nkeys, scan->rs_base.rs_key);
1459
1460 if (scan->rs_ctup.t_data == NULL)
1461 return NULL;
1462
1463 /*
1464 * if we get here it means we have a new current scan tuple, so point to
1465 * the proper return buffer and return the tuple.
1466 */
1467
1469
1470 return &scan->rs_ctup;
1471}
1472
1473bool
1475{
1477
1478 /* Note: no locking manipulations needed */
1479
1480 if (sscan->rs_flags & SO_ALLOW_PAGEMODE)
1481 heapgettup_pagemode(scan, direction, sscan->rs_nkeys, sscan->rs_key);
1482 else
1483 heapgettup(scan, direction, sscan->rs_nkeys, sscan->rs_key);
1484
1485 if (scan->rs_ctup.t_data == NULL)
1486 {
1487 ExecClearTuple(slot);
1488 return false;
1489 }
1490
1491 /*
1492 * if we get here it means we have a new current scan tuple, so point to
1493 * the proper return buffer and return the tuple.
1494 */
1495
1497
1498 ExecStoreBufferHeapTuple(&scan->rs_ctup, slot,
1499 scan->rs_cbuf);
1500 return true;
1501}
1502
1503void
1506{
1512
1513 /*
1514 * For relations without any pages, we can simply leave the TID range
1515 * unset. There will be no tuples to scan, therefore no tuples outside
1516 * the given TID range.
1517 */
1518 if (scan->rs_nblocks == 0)
1519 return;
1520
1521 /*
1522 * Set up some ItemPointers which point to the first and last possible
1523 * tuples in the heap.
1524 */
1527
1528 /*
1529 * If the given maximum TID is below the highest possible TID in the
1530 * relation, then restrict the range to that, otherwise we scan to the end
1531 * of the relation.
1532 */
1535
1536 /*
1537 * If the given minimum TID is above the lowest possible TID in the
1538 * relation, then restrict the range to only scan for TIDs above that.
1539 */
1542
1543 /*
1544 * Check for an empty range and protect from would be negative results
1545 * from the numBlks calculation below.
1546 */
1548 {
1549 /* Set an empty range of blocks to scan */
1551 return;
1552 }
1553
1554 /*
1555 * Calculate the first block and the number of blocks we must scan. We
1556 * could be more aggressive here and perform some more validation to try
1557 * and further narrow the scope of blocks to scan by checking if the
1558 * lowestItem has an offset above MaxOffsetNumber. In this case, we could
1559 * advance startBlk by one. Likewise, if highestItem has an offset of 0
1560 * we could scan one fewer blocks. However, such an optimization does not
1561 * seem worth troubling over, currently.
1562 */
1564
1567
1568 /* Set the start block and number of blocks to scan */
1570
1571 /* Finally, set the TID range in sscan */
1572 ItemPointerCopy(&lowestItem, &sscan->st.tidrange.rs_mintid);
1573 ItemPointerCopy(&highestItem, &sscan->st.tidrange.rs_maxtid);
1574}
1575
1576bool
1578 TupleTableSlot *slot)
1579{
1581 ItemPointer mintid = &sscan->st.tidrange.rs_mintid;
1582 ItemPointer maxtid = &sscan->st.tidrange.rs_maxtid;
1583
1584 /* Note: no locking manipulations needed */
1585 for (;;)
1586 {
1587 if (sscan->rs_flags & SO_ALLOW_PAGEMODE)
1588 heapgettup_pagemode(scan, direction, sscan->rs_nkeys, sscan->rs_key);
1589 else
1590 heapgettup(scan, direction, sscan->rs_nkeys, sscan->rs_key);
1591
1592 if (scan->rs_ctup.t_data == NULL)
1593 {
1594 ExecClearTuple(slot);
1595 return false;
1596 }
1597
1598 /*
1599 * heap_set_tidrange will have used heap_setscanlimits to limit the
1600 * range of pages we scan to only ones that can contain the TID range
1601 * we're scanning for. Here we must filter out any tuples from these
1602 * pages that are outside of that range.
1603 */
1604 if (ItemPointerCompare(&scan->rs_ctup.t_self, mintid) < 0)
1605 {
1606 ExecClearTuple(slot);
1607
1608 /*
1609 * When scanning backwards, the TIDs will be in descending order.
1610 * Future tuples in this direction will be lower still, so we can
1611 * just return false to indicate there will be no more tuples.
1612 */
1613 if (ScanDirectionIsBackward(direction))
1614 return false;
1615
1616 continue;
1617 }
1618
1619 /*
1620 * Likewise for the final page, we must filter out TIDs greater than
1621 * maxtid.
1622 */
1623 if (ItemPointerCompare(&scan->rs_ctup.t_self, maxtid) > 0)
1624 {
1625 ExecClearTuple(slot);
1626
1627 /*
1628 * When scanning forward, the TIDs will be in ascending order.
1629 * Future tuples in this direction will be higher still, so we can
1630 * just return false to indicate there will be no more tuples.
1631 */
1632 if (ScanDirectionIsForward(direction))
1633 return false;
1634 continue;
1635 }
1636
1637 break;
1638 }
1639
1640 /*
1641 * if we get here it means we have a new current scan tuple, so point to
1642 * the proper return buffer and return the tuple.
1643 */
1645
1646 ExecStoreBufferHeapTuple(&scan->rs_ctup, slot, scan->rs_cbuf);
1647 return true;
1648}
1649
1650/*
1651 * heap_fetch - retrieve tuple with given tid
1652 *
1653 * On entry, tuple->t_self is the TID to fetch. We pin the buffer holding
1654 * the tuple, fill in the remaining fields of *tuple, and check the tuple
1655 * against the specified snapshot.
1656 *
1657 * If successful (tuple found and passes snapshot time qual), then *userbuf
1658 * is set to the buffer holding the tuple and true is returned. The caller
1659 * must unpin the buffer when done with the tuple.
1660 *
1661 * If the tuple is not found (ie, item number references a deleted slot),
1662 * then tuple->t_data is set to NULL, *userbuf is set to InvalidBuffer,
1663 * and false is returned.
1664 *
1665 * If the tuple is found but fails the time qual check, then the behavior
1666 * depends on the keep_buf parameter. If keep_buf is false, the results
1667 * are the same as for the tuple-not-found case. If keep_buf is true,
1668 * then tuple->t_data and *userbuf are returned as for the success case,
1669 * and again the caller must unpin the buffer; but false is returned.
1670 *
1671 * heap_fetch does not follow HOT chains: only the exact TID requested will
1672 * be fetched.
1673 *
1674 * It is somewhat inconsistent that we ereport() on invalid block number but
1675 * return false on invalid item number. There are a couple of reasons though.
1676 * One is that the caller can relatively easily check the block number for
1677 * validity, but cannot check the item number without reading the page
1678 * himself. Another is that when we are following a t_ctid link, we can be
1679 * reasonably confident that the page number is valid (since VACUUM shouldn't
1680 * truncate off the destination page without having killed the referencing
1681 * tuple first), but the item number might well not be good.
1682 */
1683bool
1684heap_fetch(Relation relation,
1685 Snapshot snapshot,
1686 HeapTuple tuple,
1687 Buffer *userbuf,
1688 bool keep_buf)
1689{
1690 ItemPointer tid = &(tuple->t_self);
1691 ItemId lp;
1692 Buffer buffer;
1693 Page page;
1694 OffsetNumber offnum;
1695 bool valid;
1696
1697 /*
1698 * Fetch and pin the appropriate page of the relation.
1699 */
1700 buffer = ReadBuffer(relation, ItemPointerGetBlockNumber(tid));
1701
1702 /*
1703 * Need share lock on buffer to examine tuple commit status.
1704 */
1706 page = BufferGetPage(buffer);
1707
1708 /*
1709 * We'd better check for out-of-range offnum in case of VACUUM since the
1710 * TID was obtained.
1711 */
1712 offnum = ItemPointerGetOffsetNumber(tid);
1714 {
1715 UnlockReleaseBuffer(buffer);
1717 tuple->t_data = NULL;
1718 return false;
1719 }
1720
1721 /*
1722 * get the item line pointer corresponding to the requested tid
1723 */
1724 lp = PageGetItemId(page, offnum);
1725
1726 /*
1727 * Must check for deleted tuple.
1728 */
1729 if (!ItemIdIsNormal(lp))
1730 {
1731 UnlockReleaseBuffer(buffer);
1733 tuple->t_data = NULL;
1734 return false;
1735 }
1736
1737 /*
1738 * fill in *tuple fields
1739 */
1740 tuple->t_data = (HeapTupleHeader) PageGetItem(page, lp);
1741 tuple->t_len = ItemIdGetLength(lp);
1742 tuple->t_tableOid = RelationGetRelid(relation);
1743
1744 /*
1745 * check tuple visibility, then release lock
1746 */
1747 valid = HeapTupleSatisfiesVisibility(tuple, snapshot, buffer);
1748
1749 if (valid)
1750 PredicateLockTID(relation, &(tuple->t_self), snapshot,
1752
1753 HeapCheckForSerializableConflictOut(valid, relation, tuple, buffer, snapshot);
1754
1756
1757 if (valid)
1758 {
1759 /*
1760 * All checks passed, so return the tuple as valid. Caller is now
1761 * responsible for releasing the buffer.
1762 */
1763 *userbuf = buffer;
1764
1765 return true;
1766 }
1767
1768 /* Tuple failed time qual, but maybe caller wants to see it anyway. */
1769 if (keep_buf)
1770 *userbuf = buffer;
1771 else
1772 {
1773 ReleaseBuffer(buffer);
1775 tuple->t_data = NULL;
1776 }
1777
1778 return false;
1779}
1780
1781/*
1782 * heap_get_latest_tid - get the latest tid of a specified tuple
1783 *
1784 * Actually, this gets the latest version that is visible according to the
1785 * scan's snapshot. Create a scan using SnapshotDirty to get the very latest,
1786 * possibly uncommitted version.
1787 *
1788 * *tid is both an input and an output parameter: it is updated to
1789 * show the latest version of the row. Note that it will not be changed
1790 * if no version of the row passes the snapshot test.
1791 */
1792void
1794 ItemPointer tid)
1795{
1796 Relation relation = sscan->rs_rd;
1797 Snapshot snapshot = sscan->rs_snapshot;
1798 ItemPointerData ctid;
1800
1801 /*
1802 * table_tuple_get_latest_tid() verified that the passed in tid is valid.
1803 * Assume that t_ctid links are valid however - there shouldn't be invalid
1804 * ones in the table.
1805 */
1807
1808 /*
1809 * Loop to chase down t_ctid links. At top of loop, ctid is the tuple we
1810 * need to examine, and *tid is the TID we will return if ctid turns out
1811 * to be bogus.
1812 *
1813 * Note that we will loop until we reach the end of the t_ctid chain.
1814 * Depending on the snapshot passed, there might be at most one visible
1815 * version of the row, but we don't try to optimize for that.
1816 */
1817 ctid = *tid;
1818 priorXmax = InvalidTransactionId; /* cannot check first XMIN */
1819 for (;;)
1820 {
1821 Buffer buffer;
1822 Page page;
1823 OffsetNumber offnum;
1824 ItemId lp;
1825 HeapTupleData tp;
1826 bool valid;
1827
1828 /*
1829 * Read, pin, and lock the page.
1830 */
1831 buffer = ReadBuffer(relation, ItemPointerGetBlockNumber(&ctid));
1833 page = BufferGetPage(buffer);
1834
1835 /*
1836 * Check for bogus item number. This is not treated as an error
1837 * condition because it can happen while following a t_ctid link. We
1838 * just assume that the prior tid is OK and return it unchanged.
1839 */
1840 offnum = ItemPointerGetOffsetNumber(&ctid);
1842 {
1843 UnlockReleaseBuffer(buffer);
1844 break;
1845 }
1846 lp = PageGetItemId(page, offnum);
1847 if (!ItemIdIsNormal(lp))
1848 {
1849 UnlockReleaseBuffer(buffer);
1850 break;
1851 }
1852
1853 /* OK to access the tuple */
1854 tp.t_self = ctid;
1855 tp.t_data = (HeapTupleHeader) PageGetItem(page, lp);
1856 tp.t_len = ItemIdGetLength(lp);
1857 tp.t_tableOid = RelationGetRelid(relation);
1858
1859 /*
1860 * After following a t_ctid link, we might arrive at an unrelated
1861 * tuple. Check for XMIN match.
1862 */
1865 {
1866 UnlockReleaseBuffer(buffer);
1867 break;
1868 }
1869
1870 /*
1871 * Check tuple visibility; if visible, set it as the new result
1872 * candidate.
1873 */
1874 valid = HeapTupleSatisfiesVisibility(&tp, snapshot, buffer);
1875 HeapCheckForSerializableConflictOut(valid, relation, &tp, buffer, snapshot);
1876 if (valid)
1877 *tid = ctid;
1878
1879 /*
1880 * If there's a valid t_ctid link, follow it, else we're done.
1881 */
1882 if ((tp.t_data->t_infomask & HEAP_XMAX_INVALID) ||
1886 {
1887 UnlockReleaseBuffer(buffer);
1888 break;
1889 }
1890
1891 ctid = tp.t_data->t_ctid;
1893 UnlockReleaseBuffer(buffer);
1894 } /* end of loop */
1895}
1896
1897
1898/*
1899 * UpdateXmaxHintBits - update tuple hint bits after xmax transaction ends
1900 *
1901 * This is called after we have waited for the XMAX transaction to terminate.
1902 * If the transaction aborted, we guarantee the XMAX_INVALID hint bit will
1903 * be set on exit. If the transaction committed, we set the XMAX_COMMITTED
1904 * hint bit if possible --- but beware that that may not yet be possible,
1905 * if the transaction committed asynchronously.
1906 *
1907 * Note that if the transaction was a locker only, we set HEAP_XMAX_INVALID
1908 * even if it commits.
1909 *
1910 * Hence callers should look only at XMAX_INVALID.
1911 *
1912 * Note this is not allowed for tuples whose xmax is a multixact.
1913 */
1914static void
1916{
1919
1921 {
1922 if (!HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask) &&
1925 xid);
1926 else
1929 }
1930}
1931
1932
1933/*
1934 * GetBulkInsertState - prepare status object for a bulk insert
1935 */
1938{
1939 BulkInsertState bistate;
1940
1943 bistate->current_buf = InvalidBuffer;
1944 bistate->next_free = InvalidBlockNumber;
1945 bistate->last_free = InvalidBlockNumber;
1946 bistate->already_extended_by = 0;
1947 return bistate;
1948}
1949
1950/*
1951 * FreeBulkInsertState - clean up after finishing a bulk insert
1952 */
1953void
1955{
1956 if (bistate->current_buf != InvalidBuffer)
1957 ReleaseBuffer(bistate->current_buf);
1958 FreeAccessStrategy(bistate->strategy);
1959 pfree(bistate);
1960}
1961
1962/*
1963 * ReleaseBulkInsertStatePin - release a buffer currently held in bistate
1964 */
1965void
1967{
1968 if (bistate->current_buf != InvalidBuffer)
1969 ReleaseBuffer(bistate->current_buf);
1970 bistate->current_buf = InvalidBuffer;
1971
1972 /*
1973 * Despite the name, we also reset bulk relation extension state.
1974 * Otherwise we can end up erroring out due to looking for free space in
1975 * ->next_free of one partition, even though ->next_free was set when
1976 * extending another partition. It could obviously also be bad for
1977 * efficiency to look at existing blocks at offsets from another
1978 * partition, even if we don't error out.
1979 */
1980 bistate->next_free = InvalidBlockNumber;
1981 bistate->last_free = InvalidBlockNumber;
1982}
1983
1984
1985/*
1986 * heap_insert - insert tuple into a heap
1987 *
1988 * The new tuple is stamped with current transaction ID and the specified
1989 * command ID.
1990 *
1991 * See table_tuple_insert for comments about most of the input flags, except
1992 * that this routine directly takes a tuple rather than a slot.
1993 *
1994 * There's corresponding HEAP_INSERT_ options to all the TABLE_INSERT_
1995 * options, and there additionally is HEAP_INSERT_SPECULATIVE which is used to
1996 * implement table_tuple_insert_speculative().
1997 *
1998 * On return the header fields of *tup are updated to match the stored tuple;
1999 * in particular tup->t_self receives the actual TID where the tuple was
2000 * stored. But note that any toasting of fields within the tuple data is NOT
2001 * reflected into *tup.
2002 */
2003void
2006{
2009 Buffer buffer;
2010 Page page;
2011 Buffer vmbuffer = InvalidBuffer;
2012 bool clear_all_visible = false;
2013 bool vmbuffer_modified = false;
2014
2015 /* Cheap, simplistic check that the tuple matches the rel's rowtype. */
2018
2019 AssertHasSnapshotForToast(relation);
2020
2021 /*
2022 * Fill in tuple header fields and toast the tuple if necessary.
2023 *
2024 * Note: below this point, heaptup is the data we actually intend to store
2025 * into the relation; tup is the caller's original untoasted data.
2026 */
2027 heaptup = heap_prepare_insert(relation, tup, xid, cid, options);
2028
2029 /*
2030 * Find buffer to insert this tuple into. If the page is all visible,
2031 * this will also pin the requisite visibility map page.
2032 */
2033 buffer = RelationGetBufferForTuple(relation, heaptup->t_len,
2034 InvalidBuffer, options, bistate,
2035 &vmbuffer, NULL,
2036 0);
2037
2038 page = BufferGetPage(buffer);
2039
2040 /*
2041 * We're about to do the actual insert -- but check for conflict first, to
2042 * avoid possibly having to roll back work we've just done.
2043 *
2044 * This is safe without a recheck as long as there is no possibility of
2045 * another process scanning the page between this check and the insert
2046 * being visible to the scan (i.e., an exclusive buffer content lock is
2047 * continuously held from this point until the tuple insert is visible).
2048 *
2049 * For a heap insert, we only need to check for table-level SSI locks. Our
2050 * new tuple can't possibly conflict with existing tuple locks, and heap
2051 * page locks are only consolidated versions of tuple locks; they do not
2052 * lock "gaps" as index page locks do. So we don't need to specify a
2053 * buffer when making the call, which makes for a faster check.
2054 */
2056
2057 /* Lock the vmbuffer before the critical section */
2058 if (PageIsAllVisible(page))
2059 {
2061 clear_all_visible = true;
2062 }
2063
2064 /* NO EREPORT(ERROR) from here till changes are logged */
2066
2067 RelationPutHeapTuple(relation, buffer, heaptup,
2069
2071 {
2072 /* It's possible the VM bits were already clear */
2073 if (visibilitymap_clear(relation->rd_locator,
2075 vmbuffer, VISIBILITYMAP_VALID_BITS))
2076 vmbuffer_modified = true;
2077
2078 PageClearAllVisible(page);
2079 }
2080
2081 /*
2082 * Set pd_prune_xid to trigger heap_page_prune_and_freeze() once the page
2083 * is full so that we can set the page all-visible in the VM on the next
2084 * page access.
2085 *
2086 * Setting pd_prune_xid is also handy if the inserting transaction
2087 * eventually aborts making this tuple DEAD and hence available for
2088 * pruning. If no other tuple in this page is UPDATEd/DELETEd, the aborted
2089 * tuple would never otherwise be pruned until next vacuum is triggered.
2090 *
2091 * Don't set it if we are in bootstrap mode or we are inserting a frozen
2092 * tuple, as there is no further pruning/freezing needed in those cases.
2093 */
2095 PageSetPrunable(page, xid);
2096
2097 MarkBufferDirty(buffer);
2098
2099 /* XLOG stuff */
2100 if (RelationNeedsWAL(relation))
2101 {
2105 uint8 info = XLOG_HEAP_INSERT;
2106 int bufflags = 0;
2107
2108 /*
2109 * If this is a catalog, we need to transmit combo CIDs to properly
2110 * decode, so log that as well.
2111 */
2113 log_heap_new_cid(relation, heaptup);
2114
2115 /*
2116 * If this is the single and first tuple on page, we can reinit the
2117 * page instead of restoring the whole thing. Set flag, and hide
2118 * buffer references from XLogInsert.
2119 */
2122 {
2123 info |= XLOG_HEAP_INIT_PAGE;
2125 }
2126
2127 xlrec.offnum = ItemPointerGetOffsetNumber(&heaptup->t_self);
2128 xlrec.flags = 0;
2134
2135 /*
2136 * For logical decoding, we need the tuple even if we're doing a full
2137 * page write, so make sure it's included even if we take a full-page
2138 * image. (XXX We could alternatively store a pointer into the FPW).
2139 */
2140 if (RelationIsLogicallyLogged(relation) &&
2142 {
2145
2146 if (IsToastRelation(relation))
2148 }
2149
2152
2153 xlhdr.t_infomask2 = heaptup->t_data->t_infomask2;
2154 xlhdr.t_infomask = heaptup->t_data->t_infomask;
2155 xlhdr.t_hoff = heaptup->t_data->t_hoff;
2156
2157 /*
2158 * note we mark xlhdr as belonging to buffer; if XLogInsert decides to
2159 * write the whole page to the xlog, we don't need to store
2160 * xl_heap_header in the xlog.
2161 */
2166 /* PG73FORMAT: write bitmap [+ padding] [+ oid] + data */
2168 (char *) heaptup->t_data + SizeofHeapTupleHeader,
2170
2171 /* filtering by origin on a row level is much more efficient */
2173
2176
2177 recptr = XLogInsert(RM_HEAP_ID, info);
2178
2179 PageSetLSN(page, recptr);
2180
2182 PageSetLSN(BufferGetPage(vmbuffer), recptr);
2183 }
2184
2186
2187 UnlockReleaseBuffer(buffer);
2188
2189 /*
2190 * We locked vmbuffer if clear_all_visible was true regardless of whether
2191 * or not we ended up modifying the vmbuffer.
2192 */
2194 LockBuffer(vmbuffer, BUFFER_LOCK_UNLOCK);
2195 if (BufferIsValid(vmbuffer))
2196 ReleaseBuffer(vmbuffer);
2197
2198 /*
2199 * If tuple is cacheable, mark it for invalidation from the caches in case
2200 * we abort. Note it is OK to do this after releasing the buffer, because
2201 * the heaptup data structure is all in local memory, not in the shared
2202 * buffer.
2203 */
2205
2206 /* Note: speculative insertions are counted too, even if aborted later */
2207 pgstat_count_heap_insert(relation, 1);
2208
2209 /*
2210 * If heaptup is a private copy, release it. Don't forget to copy t_self
2211 * back to the caller's image, too.
2212 */
2213 if (heaptup != tup)
2214 {
2215 tup->t_self = heaptup->t_self;
2217 }
2218}
2219
2220/*
2221 * Subroutine for heap_insert(). Prepares a tuple for insertion. This sets the
2222 * tuple header fields and toasts the tuple if necessary. Returns a toasted
2223 * version of the tuple if it was toasted, or the original tuple if not. Note
2224 * that in any case, the header fields are also set in the original tuple.
2225 */
2226static HeapTuple
2229{
2230 /*
2231 * To allow parallel inserts, we need to ensure that they are safe to be
2232 * performed in workers. We have the infrastructure to allow parallel
2233 * inserts in general except for the cases where inserts generate a new
2234 * CommandId (eg. inserts into a table having a foreign key column).
2235 */
2236 if (IsParallelWorker())
2237 ereport(ERROR,
2239 errmsg("cannot insert tuples in a parallel worker")));
2240
2241 tup->t_data->t_infomask &= ~(HEAP_XACT_MASK);
2242 tup->t_data->t_infomask2 &= ~(HEAP2_XACT_MASK);
2243 tup->t_data->t_infomask |= HEAP_XMAX_INVALID;
2244 HeapTupleHeaderSetXmin(tup->t_data, xid);
2247
2248 HeapTupleHeaderSetCmin(tup->t_data, cid);
2249 HeapTupleHeaderSetXmax(tup->t_data, 0); /* for cleanliness */
2250 tup->t_tableOid = RelationGetRelid(relation);
2251
2252 /*
2253 * If the new tuple is too big for storage or contains already toasted
2254 * out-of-line attributes from some other relation, invoke the toaster.
2255 */
2256 if (relation->rd_rel->relkind != RELKIND_RELATION &&
2257 relation->rd_rel->relkind != RELKIND_MATVIEW)
2258 {
2259 /* toast table entries should never be recursively toasted */
2261 return tup;
2262 }
2263 else if (HeapTupleHasExternal(tup) || tup->t_len > TOAST_TUPLE_THRESHOLD)
2264 return heap_toast_insert_or_update(relation, tup, NULL, options);
2265 else
2266 return tup;
2267}
2268
2269/*
2270 * Helper for heap_multi_insert() that computes the number of entire pages
2271 * that inserting the remaining heaptuples requires. Used to determine how
2272 * much the relation needs to be extended by.
2273 */
2274static int
2276{
2278 int npages = 1;
2279
2280 for (int i = done; i < ntuples; i++)
2281 {
2282 size_t tup_sz = sizeof(ItemIdData) + MAXALIGN(heaptuples[i]->t_len);
2283
2284 if (page_avail < tup_sz)
2285 {
2286 npages++;
2288 }
2289 page_avail -= tup_sz;
2290 }
2291
2292 return npages;
2293}
2294
2295/*
2296 * heap_multi_insert - insert multiple tuples into a heap
2297 *
2298 * This is like heap_insert(), but inserts multiple tuples in one operation.
2299 * That's faster than calling heap_insert() in a loop, because when multiple
2300 * tuples can be inserted on a single page, we can write just a single WAL
2301 * record covering all of them, and only need to lock/unlock the page once.
2302 *
2303 * Note: this leaks memory into the current memory context. You can create a
2304 * temporary context before calling this, if that's a problem.
2305 */
2306void
2307heap_multi_insert(Relation relation, TupleTableSlot **slots, int ntuples,
2309{
2312 int i;
2313 int ndone;
2315 Page page;
2316 Buffer vmbuffer = InvalidBuffer;
2317 bool needwal;
2321 bool starting_with_empty_page = false;
2322 int npages = 0;
2323 int npages_used = 0;
2324
2325 /* currently not needed (thus unsupported) for heap_multi_insert() */
2327
2328 AssertHasSnapshotForToast(relation);
2329
2330 needwal = RelationNeedsWAL(relation);
2333
2334 /* Toast and set header data in all the slots */
2335 heaptuples = palloc(ntuples * sizeof(HeapTuple));
2336 for (i = 0; i < ntuples; i++)
2337 {
2338 HeapTuple tuple;
2339
2340 tuple = ExecFetchSlotHeapTuple(slots[i], true, NULL);
2341 slots[i]->tts_tableOid = RelationGetRelid(relation);
2342 tuple->t_tableOid = slots[i]->tts_tableOid;
2343 heaptuples[i] = heap_prepare_insert(relation, tuple, xid, cid,
2344 options);
2345 }
2346
2347 /*
2348 * We're about to do the actual inserts -- but check for conflict first,
2349 * to minimize the possibility of having to roll back work we've just
2350 * done.
2351 *
2352 * A check here does not definitively prevent a serialization anomaly;
2353 * that check MUST be done at least past the point of acquiring an
2354 * exclusive buffer content lock on every buffer that will be affected,
2355 * and MAY be done after all inserts are reflected in the buffers and
2356 * those locks are released; otherwise there is a race condition. Since
2357 * multiple buffers can be locked and unlocked in the loop below, and it
2358 * would not be feasible to identify and lock all of those buffers before
2359 * the loop, we must do a final check at the end.
2360 *
2361 * The check here could be omitted with no loss of correctness; it is
2362 * present strictly as an optimization.
2363 *
2364 * For heap inserts, we only need to check for table-level SSI locks. Our
2365 * new tuples can't possibly conflict with existing tuple locks, and heap
2366 * page locks are only consolidated versions of tuple locks; they do not
2367 * lock "gaps" as index page locks do. So we don't need to specify a
2368 * buffer when making the call, which makes for a faster check.
2369 */
2371
2372 ndone = 0;
2373 while (ndone < ntuples)
2374 {
2375 Buffer buffer;
2376 bool clear_all_visible = false;
2377 bool all_frozen_set = false;
2378 bool vmbuffer_modified = false;
2379 int nthispage;
2380
2382
2383 /*
2384 * Compute number of pages needed to fit the to-be-inserted tuples in
2385 * the worst case. This will be used to determine how much to extend
2386 * the relation by in RelationGetBufferForTuple(), if needed. If we
2387 * filled a prior page from scratch, we can just update our last
2388 * computation, but if we started with a partially filled page,
2389 * recompute from scratch, the number of potentially required pages
2390 * can vary due to tuples needing to fit onto the page, page headers
2391 * etc.
2392 */
2393 if (ndone == 0 || !starting_with_empty_page)
2394 {
2395 npages = heap_multi_insert_pages(heaptuples, ndone, ntuples,
2397 npages_used = 0;
2398 }
2399 else
2400 npages_used++;
2401
2402 /*
2403 * Find buffer where at least the next tuple will fit. If the page is
2404 * all-visible, this will also pin the requisite visibility map page.
2405 *
2406 * Also pin visibility map page if COPY FREEZE inserts tuples into an
2407 * empty page. See all_frozen_set below.
2408 */
2409 buffer = RelationGetBufferForTuple(relation, heaptuples[ndone]->t_len,
2410 InvalidBuffer, options, bistate,
2411 &vmbuffer, NULL,
2412 npages - npages_used);
2413 page = BufferGetPage(buffer);
2414
2416
2418 {
2419 all_frozen_set = true;
2420 /* Lock the vmbuffer before entering the critical section */
2422 }
2423 else if (PageIsAllVisible(page) && !(options & HEAP_INSERT_FROZEN))
2424 {
2425 clear_all_visible = true;
2426 /* Lock the vmbuffer before entering the critical section */
2428 }
2429
2430 /* NO EREPORT(ERROR) from here till changes are logged */
2432
2433 /*
2434 * RelationGetBufferForTuple has ensured that the first tuple fits.
2435 * Put that on the page, and then as many other tuples as fit.
2436 */
2437 RelationPutHeapTuple(relation, buffer, heaptuples[ndone], false);
2438
2439 /*
2440 * For logical decoding we need combo CIDs to properly decode the
2441 * catalog.
2442 */
2443 if (needwal && need_cids)
2444 log_heap_new_cid(relation, heaptuples[ndone]);
2445
2446 for (nthispage = 1; ndone + nthispage < ntuples; nthispage++)
2447 {
2449
2450 if (PageGetHeapFreeSpace(page) < MAXALIGN(heaptup->t_len) + saveFreeSpace)
2451 break;
2452
2453 RelationPutHeapTuple(relation, buffer, heaptup, false);
2454
2455 /*
2456 * For logical decoding we need combo CIDs to properly decode the
2457 * catalog.
2458 */
2459 if (needwal && need_cids)
2460 log_heap_new_cid(relation, heaptup);
2461 }
2462
2463 /*
2464 * If the page is all visible, need to clear that, unless we're only
2465 * going to add further frozen rows to it.
2466 *
2467 * If we're only adding already frozen rows to a previously empty
2468 * page, mark it as all-frozen and update the visibility map. We're
2469 * already holding a pin on the vmbuffer.
2470 */
2472 {
2474 /* It's possible the VM bits were already clear */
2475 if (visibilitymap_clear(relation->rd_locator,
2476 BufferGetBlockNumber(buffer),
2477 vmbuffer, VISIBILITYMAP_VALID_BITS))
2478 vmbuffer_modified = true;
2479
2480 PageClearAllVisible(page);
2481 }
2482 else if (all_frozen_set)
2483 {
2484 PageSetAllVisible(page);
2485 PageClearPrunable(page);
2487 vmbuffer,
2490 relation->rd_locator);
2491 }
2492
2493 /*
2494 * Set pd_prune_xid. See heap_insert() for more on why we do this when
2495 * inserting tuples. This only makes sense if we aren't already
2496 * setting the page frozen in the VM and we're not in bootstrap mode.
2497 */
2499 PageSetPrunable(page, xid);
2500
2501 MarkBufferDirty(buffer);
2502
2503 /* XLOG stuff */
2504 if (needwal)
2505 {
2509 char *tupledata;
2510 int totaldatalen;
2511 char *scratchptr = scratch.data;
2512 bool init;
2513 int bufflags = 0;
2514
2515 /*
2516 * If the page was previously empty, we can reinit the page
2517 * instead of restoring the whole thing.
2518 */
2520
2521 /* allocate xl_heap_multi_insert struct from the scratch area */
2524
2525 /*
2526 * Allocate offsets array. Unless we're reinitializing the page,
2527 * in that case the tuples are stored in order starting at
2528 * FirstOffsetNumber and we don't need to store the offsets
2529 * explicitly.
2530 */
2531 if (!init)
2532 scratchptr += nthispage * sizeof(OffsetNumber);
2533
2534 /* the rest of the scratch space is used for tuple data */
2535 tupledata = scratchptr;
2536
2537 /* check that the mutually exclusive flags are not both set */
2539
2540 xlrec->flags = 0;
2543
2544 /*
2545 * We don't have to worry about including a conflict xid in the
2546 * WAL record, as HEAP_INSERT_FROZEN intentionally violates
2547 * visibility rules.
2548 */
2549 if (all_frozen_set)
2551
2552 xlrec->ntuples = nthispage;
2553
2554 /*
2555 * Write out an xl_multi_insert_tuple and the tuple data itself
2556 * for each tuple.
2557 */
2558 for (i = 0; i < nthispage; i++)
2559 {
2561 xl_multi_insert_tuple *tuphdr;
2562 int datalen;
2563
2564 if (!init)
2565 xlrec->offsets[i] = ItemPointerGetOffsetNumber(&heaptup->t_self);
2566 /* xl_multi_insert_tuple needs two-byte alignment. */
2568 scratchptr = ((char *) tuphdr) + SizeOfMultiInsertTuple;
2569
2570 tuphdr->t_infomask2 = heaptup->t_data->t_infomask2;
2571 tuphdr->t_infomask = heaptup->t_data->t_infomask;
2572 tuphdr->t_hoff = heaptup->t_data->t_hoff;
2573
2574 /* write bitmap [+ padding] [+ oid] + data */
2575 datalen = heaptup->t_len - SizeofHeapTupleHeader;
2577 (char *) heaptup->t_data + SizeofHeapTupleHeader,
2578 datalen);
2579 tuphdr->datalen = datalen;
2580 scratchptr += datalen;
2581 }
2582 totaldatalen = scratchptr - tupledata;
2583 Assert((scratchptr - scratch.data) < BLCKSZ);
2584
2585 if (need_tuple_data)
2587
2588 /*
2589 * Signal that this is the last xl_heap_multi_insert record
2590 * emitted by this call to heap_multi_insert(). Needed for logical
2591 * decoding so it knows when to cleanup temporary data.
2592 */
2593 if (ndone + nthispage == ntuples)
2595
2596 if (init)
2597 {
2598 info |= XLOG_HEAP_INIT_PAGE;
2600 }
2601
2602 /*
2603 * If we're doing logical decoding, include the new tuple data
2604 * even if we take a full-page image of the page.
2605 */
2606 if (need_tuple_data)
2608
2610 XLogRegisterData(xlrec, tupledata - scratch.data);
2615
2617 totaldatalen);
2618
2619 /* filtering by origin on a row level is much more efficient */
2621
2622 recptr = XLogInsert(RM_HEAP2_ID, info);
2623
2624 PageSetLSN(page, recptr);
2626 {
2627 Assert(BufferIsDirty(vmbuffer));
2628 PageSetLSN(BufferGetPage(vmbuffer), recptr);
2629 }
2630 }
2631
2633
2634 /*
2635 * We locked vmbuffer if clear_all_visible was true regardless of
2636 * whether or not we ended up modifying the vmbuffer.
2637 */
2639 LockBuffer(vmbuffer, BUFFER_LOCK_UNLOCK);
2640
2641 UnlockReleaseBuffer(buffer);
2642 ndone += nthispage;
2643
2644 /*
2645 * NB: Only release vmbuffer after inserting all tuples - it's fairly
2646 * likely that we'll insert into subsequent heap pages that are likely
2647 * to use the same vm page.
2648 */
2649 }
2650
2651 /* We're done with inserting all tuples, so release the last vmbuffer. */
2652 if (vmbuffer != InvalidBuffer)
2653 ReleaseBuffer(vmbuffer);
2654
2655 /*
2656 * We're done with the actual inserts. Check for conflicts again, to
2657 * ensure that all rw-conflicts in to these inserts are detected. Without
2658 * this final check, a sequential scan of the heap may have locked the
2659 * table after the "before" check, missing one opportunity to detect the
2660 * conflict, and then scanned the table before the new tuples were there,
2661 * missing the other chance to detect the conflict.
2662 *
2663 * For heap inserts, we only need to check for table-level SSI locks. Our
2664 * new tuples can't possibly conflict with existing tuple locks, and heap
2665 * page locks are only consolidated versions of tuple locks; they do not
2666 * lock "gaps" as index page locks do. So we don't need to specify a
2667 * buffer when making the call.
2668 */
2670
2671 /*
2672 * If tuples are cacheable, mark them for invalidation from the caches in
2673 * case we abort. Note it is OK to do this after releasing the buffer,
2674 * because the heaptuples data structure is all in local memory, not in
2675 * the shared buffer.
2676 */
2677 if (IsCatalogRelation(relation))
2678 {
2679 for (i = 0; i < ntuples; i++)
2681 }
2682
2683 /* copy t_self fields back to the caller's slots */
2684 for (i = 0; i < ntuples; i++)
2685 slots[i]->tts_tid = heaptuples[i]->t_self;
2686
2687 pgstat_count_heap_insert(relation, ntuples);
2688}
2689
2690/*
2691 * simple_heap_insert - insert a tuple
2692 *
2693 * Currently, this routine differs from heap_insert only in supplying
2694 * a default command ID and not allowing access to the speedup options.
2695 *
2696 * This should be used rather than using heap_insert directly in most places
2697 * where we are modifying system catalogs.
2698 */
2699void
2701{
2702 heap_insert(relation, tup, GetCurrentCommandId(true), 0, NULL);
2703}
2704
2705/*
2706 * Given infomask/infomask2, compute the bits that must be saved in the
2707 * "infobits" field of xl_heap_delete, xl_heap_update, xl_heap_lock,
2708 * xl_heap_lock_updated WAL records.
2709 *
2710 * See fix_infomask_from_infobits.
2711 */
2712static uint8
2714{
2715 return
2719 /* note we ignore HEAP_XMAX_SHR_LOCK here */
2721 ((infomask2 & HEAP_KEYS_UPDATED) != 0 ?
2722 XLHL_KEYS_UPDATED : 0);
2723}
2724
2725/*
2726 * Given two versions of the same t_infomask for a tuple, compare them and
2727 * return whether the relevant status for a tuple Xmax has changed. This is
2728 * used after a buffer lock has been released and reacquired: we want to ensure
2729 * that the tuple state continues to be the same it was when we previously
2730 * examined it.
2731 *
2732 * Note the Xmax field itself must be compared separately.
2733 */
2734static inline bool
2736{
2737 const uint16 interesting =
2739
2740 if ((new_infomask & interesting) != (old_infomask & interesting))
2741 return true;
2742
2743 return false;
2744}
2745
2746/*
2747 * heap_delete - delete a tuple
2748 *
2749 * See table_tuple_delete() for an explanation of the parameters, except that
2750 * this routine directly takes a tuple rather than a slot.
2751 *
2752 * In the failure cases, the routine fills *tmfd with the tuple's t_ctid,
2753 * t_xmax (resolving a possible MultiXact, if necessary), and t_cmax (the last
2754 * only for TM_SelfModified, since we cannot obtain cmax from a combo CID
2755 * generated by another transaction).
2756 */
2758heap_delete(Relation relation, const ItemPointerData *tid,
2760 bool wait, TM_FailureData *tmfd)
2761{
2764 ItemId lp;
2765 HeapTupleData tp;
2766 Page page;
2767 BlockNumber block;
2768 Buffer buffer;
2769 Buffer vmbuffer = InvalidBuffer;
2770 bool vmbuffer_modified = false;
2771 TransactionId new_xmax;
2776 bool have_tuple_lock = false;
2777 bool iscombo;
2778 bool clear_all_visible = false;
2779 HeapTuple old_key_tuple = NULL; /* replica identity of the tuple */
2780 bool old_key_copied = false;
2781
2783
2784 AssertHasSnapshotForToast(relation);
2785
2786 /*
2787 * Forbid this during a parallel operation, lest it allocate a combo CID.
2788 * Other workers might need that combo CID for visibility checks, and we
2789 * have no provision for broadcasting it to them.
2790 */
2791 if (IsInParallelMode())
2792 ereport(ERROR,
2794 errmsg("cannot delete tuples during a parallel operation")));
2795
2796 block = ItemPointerGetBlockNumber(tid);
2797 buffer = ReadBuffer(relation, block);
2798 page = BufferGetPage(buffer);
2799
2800 /*
2801 * Before locking the buffer, pin the visibility map page if it appears to
2802 * be necessary. Since we haven't got the lock yet, someone else might be
2803 * in the middle of changing this, so we'll need to recheck after we have
2804 * the lock.
2805 */
2806 if (PageIsAllVisible(page))
2807 visibilitymap_pin(relation, block, &vmbuffer);
2808
2810
2813
2814 tp.t_tableOid = RelationGetRelid(relation);
2815 tp.t_data = (HeapTupleHeader) PageGetItem(page, lp);
2816 tp.t_len = ItemIdGetLength(lp);
2817 tp.t_self = *tid;
2818
2819l1:
2820
2821 /*
2822 * If we didn't pin the visibility map page and the page has become all
2823 * visible while we were busy locking the buffer, we'll have to unlock and
2824 * re-lock, to avoid holding the buffer lock across an I/O. That's a bit
2825 * unfortunate, but hopefully shouldn't happen often.
2826 */
2827 if (vmbuffer == InvalidBuffer && PageIsAllVisible(page))
2828 {
2830 visibilitymap_pin(relation, block, &vmbuffer);
2832 }
2833
2834 result = HeapTupleSatisfiesUpdate(&tp, cid, buffer);
2835
2836 if (result == TM_Invisible)
2837 {
2838 UnlockReleaseBuffer(buffer);
2839 ereport(ERROR,
2841 errmsg("attempted to delete invisible tuple")));
2842 }
2843 else if (result == TM_BeingModified && wait)
2844 {
2847
2848 /* must copy state data before unlocking buffer */
2851
2852 /*
2853 * Sleep until concurrent transaction ends -- except when there's a
2854 * single locker and it's our own transaction. Note we don't care
2855 * which lock mode the locker has, because we need the strongest one.
2856 *
2857 * Before sleeping, we need to acquire tuple lock to establish our
2858 * priority for the tuple (see heap_lock_tuple). LockTuple will
2859 * release us when we are next-in-line for the tuple.
2860 *
2861 * If we are forced to "start over" below, we keep the tuple lock;
2862 * this arranges that we stay at the head of the line while rechecking
2863 * tuple state.
2864 */
2866 {
2867 bool current_is_member = false;
2868
2871 {
2873
2874 /*
2875 * Acquire the lock, if necessary (but skip it when we're
2876 * requesting a lock and already have one; avoids deadlock).
2877 */
2878 if (!current_is_member)
2881
2882 /* wait for multixact */
2884 relation, &(tp.t_self), XLTW_Delete,
2885 NULL);
2887
2888 /*
2889 * If xwait had just locked the tuple then some other xact
2890 * could update this tuple before we get to this point. Check
2891 * for xmax change, and start over if so.
2892 *
2893 * We also must start over if we didn't pin the VM page, and
2894 * the page has become all visible.
2895 */
2896 if ((vmbuffer == InvalidBuffer && PageIsAllVisible(page)) ||
2899 xwait))
2900 goto l1;
2901 }
2902
2903 /*
2904 * You might think the multixact is necessarily done here, but not
2905 * so: it could have surviving members, namely our own xact or
2906 * other subxacts of this backend. It is legal for us to delete
2907 * the tuple in either case, however (the latter case is
2908 * essentially a situation of upgrading our former shared lock to
2909 * exclusive). We don't bother changing the on-disk hint bits
2910 * since we are about to overwrite the xmax altogether.
2911 */
2912 }
2914 {
2915 /*
2916 * Wait for regular transaction to end; but first, acquire tuple
2917 * lock.
2918 */
2922 XactLockTableWait(xwait, relation, &(tp.t_self), XLTW_Delete);
2924
2925 /*
2926 * xwait is done, but if xwait had just locked the tuple then some
2927 * other xact could update this tuple before we get to this point.
2928 * Check for xmax change, and start over if so.
2929 *
2930 * We also must start over if we didn't pin the VM page, and the
2931 * page has become all visible.
2932 */
2933 if ((vmbuffer == InvalidBuffer && PageIsAllVisible(page)) ||
2936 xwait))
2937 goto l1;
2938
2939 /* Otherwise check if it committed or aborted */
2940 UpdateXmaxHintBits(tp.t_data, buffer, xwait);
2941 }
2942
2943 /*
2944 * We may overwrite if previous xmax aborted, or if it committed but
2945 * only locked the tuple without updating it.
2946 */
2947 if ((tp.t_data->t_infomask & HEAP_XMAX_INVALID) ||
2950 result = TM_Ok;
2951 else if (!ItemPointerEquals(&tp.t_self, &tp.t_data->t_ctid))
2953 else
2955 }
2956
2957 /* sanity check the result HeapTupleSatisfiesUpdate() and the logic above */
2958 if (result != TM_Ok)
2959 {
2961 result == TM_Updated ||
2962 result == TM_Deleted ||
2967 }
2968
2970 {
2971 /* Perform additional check for transaction-snapshot mode RI updates */
2972 if (!HeapTupleSatisfiesVisibility(&tp, crosscheck, buffer))
2974 }
2975
2976 if (result != TM_Ok)
2977 {
2978 tmfd->ctid = tp.t_data->t_ctid;
2980 if (result == TM_SelfModified)
2982 else
2983 tmfd->cmax = InvalidCommandId;
2984 UnlockReleaseBuffer(buffer);
2985 if (have_tuple_lock)
2987 if (vmbuffer != InvalidBuffer)
2988 ReleaseBuffer(vmbuffer);
2989 return result;
2990 }
2991
2992 /*
2993 * We're about to do the actual delete -- check for conflict first, to
2994 * avoid possibly having to roll back work we've just done.
2995 *
2996 * This is safe without a recheck as long as there is no possibility of
2997 * another process scanning the page between this check and the delete
2998 * being visible to the scan (i.e., an exclusive buffer content lock is
2999 * continuously held from this point until the tuple delete is visible).
3000 */
3002
3003 /* replace cid with a combo CID if necessary */
3005
3006 /*
3007 * Compute replica identity tuple before entering the critical section so
3008 * we don't PANIC upon a memory allocation failure.
3009 */
3011 ExtractReplicaIdentity(relation, &tp, true, &old_key_copied) : NULL;
3012
3013 /*
3014 * If this is the first possibly-multixact-able operation in the current
3015 * transaction, set my per-backend OldestMemberMXactId setting. We can be
3016 * certain that the transaction will never become a member of any older
3017 * MultiXactIds than that. (We have to do this even if we end up just
3018 * using our own TransactionId below, since some other backend could
3019 * incorporate our XID into a MultiXact immediately afterwards.)
3020 */
3022
3025 xid, LockTupleExclusive, true,
3026 &new_xmax, &new_infomask, &new_infomask2);
3027
3028 /* Lock the VM before entering the critical section */
3029 if (PageIsAllVisible(page))
3030 {
3031 clear_all_visible = true;
3033 }
3034
3036
3037 /*
3038 * If this transaction commits, the tuple will become DEAD sooner or
3039 * later. Set flag that this page is a candidate for pruning once our xid
3040 * falls below the OldestXmin horizon. If the transaction finally aborts,
3041 * the subsequent page pruning will be a no-op and the hint will be
3042 * cleared.
3043 */
3044 PageSetPrunable(page, xid);
3045
3047 {
3048 /* It's possible the VM bits were already clear */
3050 vmbuffer, VISIBILITYMAP_VALID_BITS))
3051 vmbuffer_modified = true;
3052
3053 PageClearAllVisible(page);
3054 }
3055
3056 /* store transaction information of xact deleting the tuple */
3062 HeapTupleHeaderSetXmax(tp.t_data, new_xmax);
3064 /* Make sure there is no forward chain link in t_ctid */
3065 tp.t_data->t_ctid = tp.t_self;
3066
3067 /* Signal that this is actually a move into another partition */
3068 if (changingPart)
3070
3071 MarkBufferDirty(buffer);
3072
3073 /*
3074 * XLOG stuff
3075 *
3076 * NB: heap_abort_speculative() uses the same xlog record and replay
3077 * routines.
3078 */
3079 if (RelationNeedsWAL(relation))
3080 {
3084
3085 /*
3086 * For logical decode we need combo CIDs to properly decode the
3087 * catalog
3088 */
3090 log_heap_new_cid(relation, &tp);
3091
3092 xlrec.flags = 0;
3095 if (changingPart)
3097 xlrec.infobits_set = compute_infobits(tp.t_data->t_infomask,
3098 tp.t_data->t_infomask2);
3100 xlrec.xmax = new_xmax;
3101
3102 if (old_key_tuple != NULL)
3103 {
3104 if (relation->rd_rel->relreplident == REPLICA_IDENTITY_FULL)
3106 else
3108 }
3109
3110 /*
3111 * Mark the change as not-for-logical-decoding if caller requested so.
3112 *
3113 * (This is used for changes that affect relations not visible to
3114 * other transactions, such as the transient table during concurrent
3115 * repack.)
3116 */
3117 if (!walLogical)
3119
3122
3124
3125 /*
3126 * Log replica identity of the deleted tuple if there is one
3127 */
3128 if (old_key_tuple != NULL)
3129 {
3130 xlhdr.t_infomask2 = old_key_tuple->t_data->t_infomask2;
3131 xlhdr.t_infomask = old_key_tuple->t_data->t_infomask;
3132 xlhdr.t_hoff = old_key_tuple->t_data->t_hoff;
3133
3135 XLogRegisterData((char *) old_key_tuple->t_data
3137 old_key_tuple->t_len
3139 }
3140
3141 /* filtering by origin on a row level is much more efficient */
3143
3146
3148
3149 PageSetLSN(page, recptr);
3150
3152 PageSetLSN(BufferGetPage(vmbuffer), recptr);
3153 }
3154
3156
3157 /*
3158 * Release VM lock first, since it covers many heap blocks. We locked
3159 * vmbuffer if clear_all_visible was true regardless of whether or not we
3160 * ended up modifying the vmbuffer.
3161 */
3163 LockBuffer(vmbuffer, BUFFER_LOCK_UNLOCK);
3164
3166
3167 if (vmbuffer != InvalidBuffer)
3168 ReleaseBuffer(vmbuffer);
3169
3170 /*
3171 * If the tuple has toasted out-of-line attributes, we need to delete
3172 * those items too. We have to do this before releasing the buffer
3173 * because we need to look at the contents of the tuple, but it's OK to
3174 * release the content lock on the buffer first.
3175 */
3176 if (relation->rd_rel->relkind != RELKIND_RELATION &&
3177 relation->rd_rel->relkind != RELKIND_MATVIEW)
3178 {
3179 /* toast table entries should never be recursively toasted */
3181 }
3182 else if (HeapTupleHasExternal(&tp))
3183 heap_toast_delete(relation, &tp, false);
3184
3185 /*
3186 * Mark tuple for invalidation from system caches at next command
3187 * boundary. We have to do this before releasing the buffer because we
3188 * need to look at the contents of the tuple.
3189 */
3190 CacheInvalidateHeapTuple(relation, &tp, NULL);
3191
3192 /* Now we can release the buffer */
3193 ReleaseBuffer(buffer);
3194
3195 /*
3196 * Release the lmgr tuple lock, if we had it.
3197 */
3198 if (have_tuple_lock)
3200
3201 pgstat_count_heap_delete(relation);
3202
3205
3206 return TM_Ok;
3207}
3208
3209/*
3210 * simple_heap_delete - delete a tuple
3211 *
3212 * This routine may be used to delete a tuple when concurrent updates of
3213 * the target tuple are not expected (for example, because we have a lock
3214 * on the relation associated with the tuple). Any failure is reported
3215 * via ereport().
3216 */
3217void
3218simple_heap_delete(Relation relation, const ItemPointerData *tid)
3219{
3221 TM_FailureData tmfd;
3222
3223 result = heap_delete(relation, tid,
3224 GetCurrentCommandId(true),
3225 0,
3227 true /* wait for commit */ ,
3228 &tmfd);
3229 switch (result)
3230 {
3231 case TM_SelfModified:
3232 /* Tuple was already updated in current command? */
3233 elog(ERROR, "tuple already updated by self");
3234 break;
3235
3236 case TM_Ok:
3237 /* done successfully */
3238 break;
3239
3240 case TM_Updated:
3241 elog(ERROR, "tuple concurrently updated");
3242 break;
3243
3244 case TM_Deleted:
3245 elog(ERROR, "tuple concurrently deleted");
3246 break;
3247
3248 default:
3249 elog(ERROR, "unrecognized heap_delete status: %u", result);
3250 break;
3251 }
3252}
3253
3254/*
3255 * heap_update - replace a tuple
3256 *
3257 * See table_tuple_update() for an explanation of the parameters, except that
3258 * this routine directly takes a tuple rather than a slot.
3259 *
3260 * In the failure cases, the routine fills *tmfd with the tuple's t_ctid,
3261 * t_xmax (resolving a possible MultiXact, if necessary), and t_cmax (the last
3262 * only for TM_SelfModified, since we cannot obtain cmax from a combo CID
3263 * generated by another transaction).
3264 */
3268 TM_FailureData *tmfd, LockTupleMode *lockmode,
3270{
3279 ItemId lp;
3283 bool old_key_copied = false;
3285 Page page,
3286 newpage;
3287 BlockNumber block;
3289 Buffer buffer,
3290 newbuf,
3291 vmbuffer = InvalidBuffer,
3293 bool unlock_vmbuffer = false;
3294 bool unlock_vmbuffer_new = false;
3295 bool need_toast;
3297 pagefree;
3298 bool have_tuple_lock = false;
3299 bool iscombo;
3300 bool use_hot_update = false;
3301 bool summarized_update = false;
3302 bool key_intact;
3303 bool clear_all_visible = false;
3304 bool clear_all_visible_new = false;
3305 bool vmbuffer_modified = false;
3306 bool vmbuffer_new_modified = false;
3307 bool checked_lockers;
3308 bool locker_remains;
3309 bool id_has_external = false;
3316
3318
3319 /* Cheap, simplistic check that the tuple matches the rel's rowtype. */
3322
3323 AssertHasSnapshotForToast(relation);
3324
3325 /*
3326 * Forbid this during a parallel operation, lest it allocate a combo CID.
3327 * Other workers might need that combo CID for visibility checks, and we
3328 * have no provision for broadcasting it to them.
3329 */
3330 if (IsInParallelMode())
3331 ereport(ERROR,
3333 errmsg("cannot update tuples during a parallel operation")));
3334
3335#ifdef USE_ASSERT_CHECKING
3337#endif
3338
3339 /*
3340 * Fetch the list of attributes to be checked for various operations.
3341 *
3342 * For HOT considerations, this is wasted effort if we fail to update or
3343 * have to put the new tuple on a different page. But we must compute the
3344 * list before obtaining buffer lock --- in the worst case, if we are
3345 * doing an update on one of the relevant system catalogs, we could
3346 * deadlock if we try to fetch the list later. In any case, the relcache
3347 * caches the data so this is usually pretty cheap.
3348 *
3349 * We also need columns used by the replica identity and columns that are
3350 * considered the "key" of rows in the table.
3351 *
3352 * Note that we get copies of each bitmap, so we need not worry about
3353 * relcache flush happening midway through.
3354 */
3367
3369 INJECTION_POINT("heap_update-before-pin", NULL);
3370 buffer = ReadBuffer(relation, block);
3371 page = BufferGetPage(buffer);
3372
3373 /*
3374 * Before locking the buffer, pin the visibility map page if it appears to
3375 * be necessary. Since we haven't got the lock yet, someone else might be
3376 * in the middle of changing this, so we'll need to recheck after we have
3377 * the lock.
3378 */
3379 if (PageIsAllVisible(page))
3380 visibilitymap_pin(relation, block, &vmbuffer);
3381
3383
3385
3386 /*
3387 * Usually, a buffer pin and/or snapshot blocks pruning of otid, ensuring
3388 * we see LP_NORMAL here. When the otid origin is a syscache, we may have
3389 * neither a pin nor a snapshot. Hence, we may see other LP_ states, each
3390 * of which indicates concurrent pruning.
3391 *
3392 * Failing with TM_Updated would be most accurate. However, unlike other
3393 * TM_Updated scenarios, we don't know the successor ctid in LP_UNUSED and
3394 * LP_DEAD cases. While the distinction between TM_Updated and TM_Deleted
3395 * does matter to SQL statements UPDATE and MERGE, those SQL statements
3396 * hold a snapshot that ensures LP_NORMAL. Hence, the choice between
3397 * TM_Updated and TM_Deleted affects only the wording of error messages.
3398 * Settle on TM_Deleted, for two reasons. First, it avoids complicating
3399 * the specification of when tmfd->ctid is valid. Second, it creates
3400 * error log evidence that we took this branch.
3401 *
3402 * Since it's possible to see LP_UNUSED at otid, it's also possible to see
3403 * LP_NORMAL for a tuple that replaced LP_UNUSED. If it's a tuple for an
3404 * unrelated row, we'll fail with "duplicate key value violates unique".
3405 * XXX if otid is the live, newer version of the newtup row, we'll discard
3406 * changes originating in versions of this catalog row after the version
3407 * the caller got from syscache. See syscache-update-pruned.spec.
3408 */
3409 if (!ItemIdIsNormal(lp))
3410 {
3412
3413 UnlockReleaseBuffer(buffer);
3415 if (vmbuffer != InvalidBuffer)
3416 ReleaseBuffer(vmbuffer);
3417 tmfd->ctid = *otid;
3418 tmfd->xmax = InvalidTransactionId;
3419 tmfd->cmax = InvalidCommandId;
3421
3426 /* modified_attrs not yet initialized */
3428 return TM_Deleted;
3429 }
3430
3431 /*
3432 * Fill in enough data in oldtup for HeapDetermineColumnsInfo to work
3433 * properly.
3434 */
3435 oldtup.t_tableOid = RelationGetRelid(relation);
3436 oldtup.t_data = (HeapTupleHeader) PageGetItem(page, lp);
3437 oldtup.t_len = ItemIdGetLength(lp);
3438 oldtup.t_self = *otid;
3439
3440 /* the new tuple is ready, except for this: */
3441 newtup->t_tableOid = RelationGetRelid(relation);
3442
3443 /*
3444 * Determine columns modified by the update. Additionally, identify
3445 * whether any of the unmodified replica identity key attributes in the
3446 * old tuple is externally stored or not. This is required because for
3447 * such attributes the flattened value won't be WAL logged as part of the
3448 * new tuple so we must include it as part of the old_key_tuple. See
3449 * ExtractReplicaIdentity.
3450 */
3452 id_attrs, &oldtup,
3454
3455 /*
3456 * If we're not updating any "key" column, we can grab a weaker lock type.
3457 * This allows for more concurrency when we are running simultaneously
3458 * with foreign key checks.
3459 *
3460 * Note that if a column gets detoasted while executing the update, but
3461 * the value ends up being the same, this test will fail and we will use
3462 * the stronger lock. This is acceptable; the important case to optimize
3463 * is updates that don't manipulate key columns, not those that
3464 * serendipitously arrive at the same key values.
3465 */
3467 {
3468 *lockmode = LockTupleNoKeyExclusive;
3470 key_intact = true;
3471
3472 /*
3473 * If this is the first possibly-multixact-able operation in the
3474 * current transaction, set my per-backend OldestMemberMXactId
3475 * setting. We can be certain that the transaction will never become a
3476 * member of any older MultiXactIds than that. (We have to do this
3477 * even if we end up just using our own TransactionId below, since
3478 * some other backend could incorporate our XID into a MultiXact
3479 * immediately afterwards.)
3480 */
3482 }
3483 else
3484 {
3485 *lockmode = LockTupleExclusive;
3487 key_intact = false;
3488 }
3489
3490 /*
3491 * Note: beyond this point, use oldtup not otid to refer to old tuple.
3492 * otid may very well point at newtup->t_self, which we will overwrite
3493 * with the new tuple's location, so there's great risk of confusion if we
3494 * use otid anymore.
3495 */
3496
3497l2:
3498 checked_lockers = false;
3499 locker_remains = false;
3501
3502 /* see below about the "no wait" case */
3503 Assert(result != TM_BeingModified || wait);
3504
3505 if (result == TM_Invisible)
3506 {
3507 UnlockReleaseBuffer(buffer);
3508 ereport(ERROR,
3510 errmsg("attempted to update invisible tuple")));
3511 }
3512 else if (result == TM_BeingModified && wait)
3513 {
3516 bool can_continue = false;
3517
3518 /*
3519 * XXX note that we don't consider the "no wait" case here. This
3520 * isn't a problem currently because no caller uses that case, but it
3521 * should be fixed if such a caller is introduced. It wasn't a
3522 * problem previously because this code would always wait, but now
3523 * that some tuple locks do not conflict with one of the lock modes we
3524 * use, it is possible that this case is interesting to handle
3525 * specially.
3526 *
3527 * This may cause failures with third-party code that calls
3528 * heap_update directly.
3529 */
3530
3531 /* must copy state data before unlocking buffer */
3533 infomask = oldtup.t_data->t_infomask;
3534
3535 /*
3536 * Now we have to do something about the existing locker. If it's a
3537 * multi, sleep on it; we might be awakened before it is completely
3538 * gone (or even not sleep at all in some cases); we need to preserve
3539 * it as locker, unless it is gone completely.
3540 *
3541 * If it's not a multi, we need to check for sleeping conditions
3542 * before actually going to sleep. If the update doesn't conflict
3543 * with the locks, we just continue without sleeping (but making sure
3544 * it is preserved).
3545 *
3546 * Before sleeping, we need to acquire tuple lock to establish our
3547 * priority for the tuple (see heap_lock_tuple). LockTuple will
3548 * release us when we are next-in-line for the tuple. Note we must
3549 * not acquire the tuple lock until we're sure we're going to sleep;
3550 * otherwise we're open for race conditions with other transactions
3551 * holding the tuple lock which sleep on us.
3552 *
3553 * If we are forced to "start over" below, we keep the tuple lock;
3554 * this arranges that we stay at the head of the line while rechecking
3555 * tuple state.
3556 */
3558 {
3560 int remain;
3561 bool current_is_member = false;
3562
3564 *lockmode, &current_is_member))
3565 {
3567
3568 /*
3569 * Acquire the lock, if necessary (but skip it when we're
3570 * requesting a lock and already have one; avoids deadlock).
3571 */
3572 if (!current_is_member)
3573 heap_acquire_tuplock(relation, &(oldtup.t_self), *lockmode,
3575
3576 /* wait for multixact */
3578 relation, &oldtup.t_self, XLTW_Update,
3579 &remain);
3580 checked_lockers = true;
3581 locker_remains = remain != 0;
3583
3584 /*
3585 * If xwait had just locked the tuple then some other xact
3586 * could update this tuple before we get to this point. Check
3587 * for xmax change, and start over if so.
3588 */
3589 if (xmax_infomask_changed(oldtup.t_data->t_infomask,
3590 infomask) ||
3592 xwait))
3593 goto l2;
3594 }
3595
3596 /*
3597 * Note that the multixact may not be done by now. It could have
3598 * surviving members; our own xact or other subxacts of this
3599 * backend, and also any other concurrent transaction that locked
3600 * the tuple with LockTupleKeyShare if we only got
3601 * LockTupleNoKeyExclusive. If this is the case, we have to be
3602 * careful to mark the updated tuple with the surviving members in
3603 * Xmax.
3604 *
3605 * Note that there could have been another update in the
3606 * MultiXact. In that case, we need to check whether it committed
3607 * or aborted. If it aborted we are safe to update it again;
3608 * otherwise there is an update conflict, and we have to return
3609 * TableTuple{Deleted, Updated} below.
3610 *
3611 * In the LockTupleExclusive case, we still need to preserve the
3612 * surviving members: those would include the tuple locks we had
3613 * before this one, which are important to keep in case this
3614 * subxact aborts.
3615 */
3616 if (!HEAP_XMAX_IS_LOCKED_ONLY(oldtup.t_data->t_infomask))
3618 else
3620
3621 /*
3622 * There was no UPDATE in the MultiXact; or it aborted. No
3623 * TransactionIdIsInProgress() call needed here, since we called
3624 * MultiXactIdWait() above.
3625 */
3628 can_continue = true;
3629 }
3631 {
3632 /*
3633 * The only locker is ourselves; we can avoid grabbing the tuple
3634 * lock here, but must preserve our locking information.
3635 */
3636 checked_lockers = true;
3637 locker_remains = true;
3638 can_continue = true;
3639 }
3641 {
3642 /*
3643 * If it's just a key-share locker, and we're not changing the key
3644 * columns, we don't need to wait for it to end; but we need to
3645 * preserve it as locker.
3646 */
3647 checked_lockers = true;
3648 locker_remains = true;
3649 can_continue = true;
3650 }
3651 else
3652 {
3653 /*
3654 * Wait for regular transaction to end; but first, acquire tuple
3655 * lock.
3656 */
3658 heap_acquire_tuplock(relation, &(oldtup.t_self), *lockmode,
3660 XactLockTableWait(xwait, relation, &oldtup.t_self,
3661 XLTW_Update);
3662 checked_lockers = true;
3664
3665 /*
3666 * xwait is done, but if xwait had just locked the tuple then some
3667 * other xact could update this tuple before we get to this point.
3668 * Check for xmax change, and start over if so.
3669 */
3670 if (xmax_infomask_changed(oldtup.t_data->t_infomask, infomask) ||
3673 goto l2;
3674
3675 /* Otherwise check if it committed or aborted */
3676 UpdateXmaxHintBits(oldtup.t_data, buffer, xwait);
3677 if (oldtup.t_data->t_infomask & HEAP_XMAX_INVALID)
3678 can_continue = true;
3679 }
3680
3681 if (can_continue)
3682 result = TM_Ok;
3683 else if (!ItemPointerEquals(&oldtup.t_self, &oldtup.t_data->t_ctid))
3685 else
3687 }
3688
3689 /* Sanity check the result HeapTupleSatisfiesUpdate() and the logic above */
3690 if (result != TM_Ok)
3691 {
3693 result == TM_Updated ||
3694 result == TM_Deleted ||
3696 Assert(!(oldtup.t_data->t_infomask & HEAP_XMAX_INVALID));
3698 !ItemPointerEquals(&oldtup.t_self, &oldtup.t_data->t_ctid));
3699 }
3700
3702 {
3703 /* Perform additional check for transaction-snapshot mode RI updates */
3706 }
3707
3708 if (result != TM_Ok)
3709 {
3710 tmfd->ctid = oldtup.t_data->t_ctid;
3711 tmfd->xmax = HeapTupleHeaderGetUpdateXid(oldtup.t_data);
3712 if (result == TM_SelfModified)
3713 tmfd->cmax = HeapTupleHeaderGetCmax(oldtup.t_data);
3714 else
3715 tmfd->cmax = InvalidCommandId;
3716 UnlockReleaseBuffer(buffer);
3717 if (have_tuple_lock)
3718 UnlockTupleTuplock(relation, &(oldtup.t_self), *lockmode);
3719 if (vmbuffer != InvalidBuffer)
3720 ReleaseBuffer(vmbuffer);
3722
3729 return result;
3730 }
3731
3732 /*
3733 * If we didn't pin the visibility map page and the page has become all
3734 * visible while we were busy locking the buffer, or during some
3735 * subsequent window during which we had it unlocked, we'll have to unlock
3736 * and re-lock, to avoid holding the buffer lock across an I/O. That's a
3737 * bit unfortunate, especially since we'll now have to recheck whether the
3738 * tuple has been locked or updated under us, but hopefully it won't
3739 * happen very often.
3740 */
3741 if (vmbuffer == InvalidBuffer && PageIsAllVisible(page))
3742 {
3744 visibilitymap_pin(relation, block, &vmbuffer);
3746 goto l2;
3747 }
3748
3749 /* Fill in transaction status data */
3750
3751 /*
3752 * If the tuple we're updating is locked, we need to preserve the locking
3753 * info in the old tuple's Xmax. Prepare a new Xmax value for this.
3754 */
3756 oldtup.t_data->t_infomask,
3757 oldtup.t_data->t_infomask2,
3758 xid, *lockmode, true,
3761
3762 /*
3763 * And also prepare an Xmax value for the new copy of the tuple. If there
3764 * was no xmax previously, or there was one but all lockers are now gone,
3765 * then use InvalidTransactionId; otherwise, get the xmax from the old
3766 * tuple. (In rare cases that might also be InvalidTransactionId and yet
3767 * not have the HEAP_XMAX_INVALID bit set; that's fine.)
3768 */
3769 if ((oldtup.t_data->t_infomask & HEAP_XMAX_INVALID) ||
3770 HEAP_LOCKED_UPGRADED(oldtup.t_data->t_infomask) ||
3773 else
3775
3777 {
3780 }
3781 else
3782 {
3783 /*
3784 * If we found a valid Xmax for the new tuple, then the infomask bits
3785 * to use on the new tuple depend on what was there on the old one.
3786 * Note that since we're doing an update, the only possibility is that
3787 * the lockers had FOR KEY SHARE lock.
3788 */
3789 if (oldtup.t_data->t_infomask & HEAP_XMAX_IS_MULTI)
3790 {
3793 }
3794 else
3795 {
3798 }
3799 }
3800
3801 /*
3802 * Prepare the new tuple with the appropriate initial values of Xmin and
3803 * Xmax, as well as initial infomask bits as computed above.
3804 */
3805 newtup->t_data->t_infomask &= ~(HEAP_XACT_MASK);
3806 newtup->t_data->t_infomask2 &= ~(HEAP2_XACT_MASK);
3807 HeapTupleHeaderSetXmin(newtup->t_data, xid);
3809 newtup->t_data->t_infomask |= HEAP_UPDATED | infomask_new_tuple;
3810 newtup->t_data->t_infomask2 |= infomask2_new_tuple;
3812
3813 /*
3814 * Replace cid with a combo CID if necessary. Note that we already put
3815 * the plain cid into the new tuple.
3816 */
3818
3819 /*
3820 * If the toaster needs to be activated, OR if the new tuple will not fit
3821 * on the same page as the old, then we need to release the content lock
3822 * (but not the pin!) on the old tuple's buffer while we are off doing
3823 * TOAST and/or table-file-extension work. We must mark the old tuple to
3824 * show that it's locked, else other processes may try to update it
3825 * themselves.
3826 *
3827 * We need to invoke the toaster if there are already any out-of-line
3828 * toasted values present, or if the new tuple is over-threshold.
3829 */
3830 if (relation->rd_rel->relkind != RELKIND_RELATION &&
3831 relation->rd_rel->relkind != RELKIND_MATVIEW)
3832 {
3833 /* toast table entries should never be recursively toasted */
3836 need_toast = false;
3837 }
3838 else
3841 newtup->t_len > TOAST_TUPLE_THRESHOLD);
3842
3844
3845 newtupsize = MAXALIGN(newtup->t_len);
3846
3848 {
3852 bool cleared_all_frozen = false;
3853
3854 /*
3855 * To prevent concurrent sessions from updating the tuple, we have to
3856 * temporarily mark it locked, while we release the page-level lock.
3857 *
3858 * To satisfy the rule that any xid potentially appearing in a buffer
3859 * written out to disk, we unfortunately have to WAL log this
3860 * temporary modification. We can reuse xl_heap_lock for this
3861 * purpose. If we crash/error before following through with the
3862 * actual update, xmax will be of an aborted transaction, allowing
3863 * other sessions to proceed.
3864 */
3865
3866 /*
3867 * Compute xmax / infomask appropriate for locking the tuple. This has
3868 * to be done separately from the combo that's going to be used for
3869 * updating, because the potentially created multixact would otherwise
3870 * be wrong.
3871 */
3873 oldtup.t_data->t_infomask,
3874 oldtup.t_data->t_infomask2,
3875 xid, *lockmode, false,
3878
3880
3881 if (PageIsAllVisible(page))
3882 {
3884 unlock_vmbuffer = true;
3885 }
3886
3888
3889 /* Clear obsolete visibility flags ... */
3890 oldtup.t_data->t_infomask &= ~(HEAP_XMAX_BITS | HEAP_MOVED);
3891 oldtup.t_data->t_infomask2 &= ~HEAP_KEYS_UPDATED;
3893 /* ... and store info about transaction updating this tuple */
3896 oldtup.t_data->t_infomask |= infomask_lock_old_tuple;
3897 oldtup.t_data->t_infomask2 |= infomask2_lock_old_tuple;
3899
3900 /* temporarily make it look not-updated, but locked */
3901 oldtup.t_data->t_ctid = oldtup.t_self;
3902
3903 /*
3904 * Clear all-frozen bit on visibility map if needed. We could
3905 * immediately reset ALL_VISIBLE, but given that the WAL logging
3906 * overhead would be unchanged, that doesn't seem necessarily
3907 * worthwhile.
3908 */
3909 if (PageIsAllVisible(page))
3910 {
3911 /* It's possible all-frozen was already clear */
3912 if (visibilitymap_clear(relation->rd_locator, block, vmbuffer,
3914 cleared_all_frozen = true;
3915 }
3916
3917 MarkBufferDirty(buffer);
3918
3919 if (RelationNeedsWAL(relation))
3920 {
3923
3926
3927 xlrec.offnum = ItemPointerGetOffsetNumber(&oldtup.t_self);
3929 xlrec.infobits_set = compute_infobits(oldtup.t_data->t_infomask,
3930 oldtup.t_data->t_infomask2);
3931 xlrec.flags =
3934
3937
3939 PageSetLSN(page, recptr);
3940
3942 PageSetLSN(BufferGetPage(vmbuffer), recptr);
3943 }
3944
3946
3947 /* release VM lock first, since it covers many heap blocks */
3948 if (unlock_vmbuffer)
3949 LockBuffer(vmbuffer, BUFFER_LOCK_UNLOCK);
3950 unlock_vmbuffer = false;
3951
3953
3954 /*
3955 * Let the toaster do its thing, if needed.
3956 *
3957 * Note: below this point, heaptup is the data we actually intend to
3958 * store into the relation; newtup is the caller's original untoasted
3959 * data.
3960 */
3961 if (need_toast)
3962 {
3963 /* Note we always use WAL and FSM during updates */
3965 newtupsize = MAXALIGN(heaptup->t_len);
3966 }
3967 else
3968 heaptup = newtup;
3969
3970 /*
3971 * Now, do we need a new page for the tuple, or not? This is a bit
3972 * tricky since someone else could have added tuples to the page while
3973 * we weren't looking. We have to recheck the available space after
3974 * reacquiring the buffer lock. But don't bother to do that if the
3975 * former amount of free space is still not enough; it's unlikely
3976 * there's more free now than before.
3977 *
3978 * What's more, if we need to get a new page, we will need to acquire
3979 * buffer locks on both old and new pages. To avoid deadlock against
3980 * some other backend trying to get the same two locks in the other
3981 * order, we must be consistent about the order we get the locks in.
3982 * We use the rule "lock the lower-numbered page of the relation
3983 * first". To implement this, we must do RelationGetBufferForTuple
3984 * while not holding the lock on the old page, and we must rely on it
3985 * to get the locks on both pages in the correct order.
3986 *
3987 * Another consideration is that we need visibility map page pin(s) if
3988 * we will have to clear the all-visible flag on either page. If we
3989 * call RelationGetBufferForTuple, we rely on it to acquire any such
3990 * pins; but if we don't, we have to handle that here. Hence we need
3991 * a loop.
3992 */
3993 for (;;)
3994 {
3995 if (newtupsize > pagefree)
3996 {
3997 /* It doesn't fit, must use RelationGetBufferForTuple. */
3998 newbuf = RelationGetBufferForTuple(relation, heaptup->t_len,
3999 buffer, 0, NULL,
4000 &vmbuffer_new, &vmbuffer,
4001 0);
4002 /* We're all done. */
4003 break;
4004 }
4005 /* Acquire VM page pin if needed and we don't have it. */
4006 if (vmbuffer == InvalidBuffer && PageIsAllVisible(page))
4007 visibilitymap_pin(relation, block, &vmbuffer);
4008 /* Re-acquire the lock on the old tuple's page. */
4010 /* Re-check using the up-to-date free space */
4012 if (newtupsize > pagefree ||
4013 (vmbuffer == InvalidBuffer && PageIsAllVisible(page)))
4014 {
4015 /*
4016 * Rats, it doesn't fit anymore, or somebody just now set the
4017 * all-visible flag. We must now unlock and loop to avoid
4018 * deadlock. Fortunately, this path should seldom be taken.
4019 */
4021 }
4022 else
4023 {
4024 /* We're all done. */
4025 newbuf = buffer;
4026 break;
4027 }
4028 }
4029 }
4030 else
4031 {
4032 /* No TOAST work needed, and it'll fit on same page */
4033 newbuf = buffer;
4034 heaptup = newtup;
4035 }
4036
4038
4039 /*
4040 * We're about to do the actual update -- check for conflict first, to
4041 * avoid possibly having to roll back work we've just done.
4042 *
4043 * This is safe without a recheck as long as there is no possibility of
4044 * another process scanning the pages between this check and the update
4045 * being visible to the scan (i.e., exclusive buffer content lock(s) are
4046 * continuously held from this point until the tuple update is visible).
4047 *
4048 * For the new tuple the only check needed is at the relation level, but
4049 * since both tuples are in the same relation and the check for oldtup
4050 * will include checking the relation level, there is no benefit to a
4051 * separate check for the new tuple.
4052 */
4053 CheckForSerializableConflictIn(relation, &oldtup.t_self,
4054 BufferGetBlockNumber(buffer));
4055
4056 /*
4057 * At this point newbuf and buffer are both pinned and locked, and newbuf
4058 * has enough space for the new tuple. If they are the same buffer, only
4059 * one pin is held.
4060 */
4061
4062 if (newbuf == buffer)
4063 {
4064 /*
4065 * Since the new tuple is going into the same page, we might be able
4066 * to do a HOT update. Check if any of the index columns have been
4067 * changed.
4068 */
4070 {
4071 use_hot_update = true;
4072
4073 /*
4074 * If none of the columns that are used in hot-blocking indexes
4075 * were updated, we can apply HOT, but we do still need to check
4076 * if we need to update the summarizing indexes, and update those
4077 * indexes if the columns were updated, or we may fail to detect
4078 * e.g. value bound changes in BRIN minmax indexes.
4079 */
4081 summarized_update = true;
4082 }
4083 }
4084 else
4085 {
4086 /* Set a hint that the old page could use prune/defrag */
4087 PageSetFull(page);
4088 }
4089
4090 /*
4091 * Compute replica identity tuple before entering the critical section so
4092 * we don't PANIC upon a memory allocation failure.
4093 * ExtractReplicaIdentity() will return NULL if nothing needs to be
4094 * logged. Pass old key required as true only if the replica identity key
4095 * columns are modified or it has external data.
4096 */
4101
4104
4105 /*
4106 * Clear PD_ALL_VISIBLE flags and reset visibility map bits for any heap
4107 * pages that were all-visible. If there are two heap pages, we may need
4108 * to clear VM bits for both.
4109 */
4111 vmbuffer_new == vmbuffer)
4112 {
4113 /*
4114 * This is the more complicated case: both the new and old heap pages
4115 * are all-visible and both their VM bits are on the same page of the
4116 * VM, so we register a single VM buffer as HEAP_UPDATE_BLKREF_VM_NEW
4117 * in the WAL record. We must be careful to only lock and register one
4118 * buffer, even though we modify it twice -- once for each heap
4119 * block's VM bits.
4120 */
4122 unlock_vmbuffer_new = true;
4123
4124 /* We will not lock or attempt to modify old VM buffer */
4125 }
4126 else
4127 {
4128 /*
4129 * In all the remaining cases, we will clear at most one heap block's
4130 * VM bits per VM page.
4131 */
4132 Buffer vmbuffers[2] = {
4133 clear_all_visible ? vmbuffer : InvalidBuffer,
4135 };
4136
4137 /*
4138 * When both pages need different VM pages cleared, acquire the VM
4139 * buffer locks in VM block order to avoid deadlocks between backends
4140 * updating tuples in opposite directions across VM pages.
4141 */
4144 {
4145 Buffer swap = vmbuffers[0];
4146
4147 vmbuffers[0] = vmbuffers[1];
4148 vmbuffers[1] = swap;
4149 }
4150
4152 vmbuffers[0] != vmbuffers[1]);
4153
4154 if (BufferIsValid(vmbuffers[0]))
4156 if (BufferIsValid(vmbuffers[1]))
4158
4160 unlock_vmbuffer = true;
4162 unlock_vmbuffer_new = true;
4163 }
4164
4165 /* NO EREPORT(ERROR) from here till changes are logged */
4167
4168 /*
4169 * If this transaction commits, the old tuple will become DEAD sooner or
4170 * later. Set flag that this page is a candidate for pruning once our xid
4171 * falls below the OldestXmin horizon. If the transaction finally aborts,
4172 * the subsequent page pruning will be a no-op and the hint will be
4173 * cleared.
4174 *
4175 * We set the new page prunable as well. See heap_insert() for more on why
4176 * we do this when inserting tuples.
4177 */
4178 PageSetPrunable(page, xid);
4179 if (newbuf != buffer)
4181
4182 if (use_hot_update)
4183 {
4184 /* Mark the old tuple as HOT-updated */
4186 /* And mark the new tuple as heap-only */
4188 /* Mark the caller's copy too, in case different from heaptup */
4190 }
4191 else
4192 {
4193 /* Make sure tuples are correctly marked as not-HOT */
4197 }
4198
4199 RelationPutHeapTuple(relation, newbuf, heaptup, false); /* insert new tuple */
4200
4201
4202 /* Clear obsolete visibility flags, possibly set by ourselves above... */
4203 oldtup.t_data->t_infomask &= ~(HEAP_XMAX_BITS | HEAP_MOVED);
4204 oldtup.t_data->t_infomask2 &= ~HEAP_KEYS_UPDATED;
4205 /* ... and store info about transaction updating this tuple */
4208 oldtup.t_data->t_infomask |= infomask_old_tuple;
4209 oldtup.t_data->t_infomask2 |= infomask2_old_tuple;
4211
4212 /* record address of new tuple in t_ctid of old one */
4213 oldtup.t_data->t_ctid = heaptup->t_self;
4214
4215 /*
4216 * Clear PD_ALL_VISIBLE flags and reset all visibilitymap bits. In all
4217 * cases, it's possible that PD_ALL_VISIBLE was set but the corresponding
4218 * visibility map bits were already clear.
4219 */
4221 {
4222 if (visibilitymap_clear(relation->rd_locator, block,
4223 vmbuffer, VISIBILITYMAP_VALID_BITS))
4224 {
4225 /*
4226 * When old and new heap blocks' VM bits are on the same VM page,
4227 * that page is registered in the WAL record only once. If both
4228 * heap pages were PD_ALL_VISIBLE and either VM bit needs
4229 * clearing, we register the VM buffer as
4230 * HEAP_UPDATE_BLKREF_VM_NEW.
4231 */
4232 if (clear_all_visible_new && vmbuffer == vmbuffer_new)
4233 vmbuffer_new_modified = true;
4234 else
4235 vmbuffer_modified = true;
4236 }
4237
4238 PageClearAllVisible(page);
4239 }
4241 {
4242 /*
4243 * If both heap blocks' VM bits are on the same VM buffer, this will
4244 * clear the new heap block's VM bits from the shared vmbuffer.
4245 */
4248 vmbuffer_new_modified = true;
4249
4251 }
4252
4253 if (newbuf != buffer)
4255 MarkBufferDirty(buffer);
4256
4257 /* XLOG stuff */
4258 if (RelationNeedsWAL(relation))
4259 {
4261
4262 /*
4263 * For logical decoding we need combo CIDs to properly decode the
4264 * catalog.
4265 */
4267 {
4268 log_heap_new_cid(relation, &oldtup);
4269 log_heap_new_cid(relation, heaptup);
4270 }
4271
4272 recptr = log_heap_update(relation, buffer,
4273 vmbuffer_modified ? vmbuffer : InvalidBuffer,
4274 newbuf,
4276 &oldtup, heaptup,
4280 walLogical);
4281 if (newbuf != buffer)
4282 {
4284 }
4285 PageSetLSN(page, recptr);
4286
4288 PageSetLSN(BufferGetPage(vmbuffer), recptr);
4291 }
4292
4294
4295 if (unlock_vmbuffer)
4296 LockBuffer(vmbuffer, BUFFER_LOCK_UNLOCK);
4299
4300 if (newbuf != buffer)
4303
4304 /*
4305 * Mark old tuple for invalidation from system caches at next command
4306 * boundary, and mark the new tuple for invalidation in case we abort. We
4307 * have to do this before releasing the buffer because oldtup is in the
4308 * buffer. (heaptup is all in local memory, but it's necessary to process
4309 * both tuple versions in one call to inval.c so we can avoid redundant
4310 * sinval messages.)
4311 */
4313
4314 /* Now we can release the buffer(s) */
4315 if (newbuf != buffer)
4317 ReleaseBuffer(buffer);
4320 if (BufferIsValid(vmbuffer))
4321 ReleaseBuffer(vmbuffer);
4322
4323 /*
4324 * Release the lmgr tuple lock, if we had it.
4325 */
4326 if (have_tuple_lock)
4327 UnlockTupleTuplock(relation, &(oldtup.t_self), *lockmode);
4328
4329 pgstat_count_heap_update(relation, use_hot_update, newbuf != buffer);
4330
4331 /*
4332 * If heaptup is a private copy, release it. Don't forget to copy t_self
4333 * back to the caller's image, too.
4334 */
4335 if (heaptup != newtup)
4336 {
4337 newtup->t_self = heaptup->t_self;
4339 }
4340
4341 /*
4342 * If it is a HOT update, the update may still need to update summarized
4343 * indexes, lest we fail to update those summaries and get incorrect
4344 * results (for example, minmax bounds of the block may change with this
4345 * update).
4346 */
4347 if (use_hot_update)
4348 {
4351 else
4353 }
4354 else
4356
4359
4366
4367 return TM_Ok;
4368}
4369
4370#ifdef USE_ASSERT_CHECKING
4371/*
4372 * Confirm adequate lock held during heap_update(), per rules from
4373 * README.tuplock section "Locking to write inplace-updated tables".
4374 */
4375static void
4377 const ItemPointerData *otid,
4379{
4380 /* LOCKTAG_TUPLE acceptable for any catalog */
4381 switch (RelationGetRelid(relation))
4382 {
4383 case RelationRelationId:
4384 case DatabaseRelationId:
4385 {
4387
4389 relation->rd_lockInfo.lockRelId.dbId,
4390 relation->rd_lockInfo.lockRelId.relId,
4394 return;
4395 }
4396 break;
4397 default:
4398 Assert(!IsInplaceUpdateRelation(relation));
4399 return;
4400 }
4401
4402 switch (RelationGetRelid(relation))
4403 {
4404 case RelationRelationId:
4405 {
4406 /* LOCKTAG_TUPLE or LOCKTAG_RELATION ok */
4408 Oid relid = classForm->oid;
4409 Oid dbid;
4410 LOCKTAG tag;
4411
4412 if (IsSharedRelation(relid))
4413 dbid = InvalidOid;
4414 else
4415 dbid = MyDatabaseId;
4416
4417 if (classForm->relkind == RELKIND_INDEX)
4418 {
4419 Relation irel = index_open(relid, AccessShareLock);
4420
4421 SET_LOCKTAG_RELATION(tag, dbid, irel->rd_index->indrelid);
4423 }
4424 else
4425 SET_LOCKTAG_RELATION(tag, dbid, relid);
4426
4427 if (!LockHeldByMe(&tag, ShareUpdateExclusiveLock, false) &&
4428 !LockHeldByMe(&tag, ShareRowExclusiveLock, true))
4429 elog(WARNING,
4430 "missing lock for relation \"%s\" (OID %u, relkind %c) @ TID (%u,%u)",
4431 NameStr(classForm->relname),
4432 relid,
4433 classForm->relkind,
4436 }
4437 break;
4438 case DatabaseRelationId:
4439 {
4440 /* LOCKTAG_TUPLE required */
4442
4443 elog(WARNING,
4444 "missing lock on database \"%s\" (OID %u) @ TID (%u,%u)",
4445 NameStr(dbForm->datname),
4446 dbForm->oid,
4449 }
4450 break;
4451 }
4452}
4453
4454/*
4455 * Confirm adequate relation lock held, per rules from README.tuplock section
4456 * "Locking to write inplace-updated tables".
4457 */
4458static void
4460{
4462 Oid relid = classForm->oid;
4463 Oid dbid;
4464 LOCKTAG tag;
4465
4466 if (IsSharedRelation(relid))
4467 dbid = InvalidOid;
4468 else
4469 dbid = MyDatabaseId;
4470
4471 if (classForm->relkind == RELKIND_INDEX)
4472 {
4473 Relation irel = index_open(relid, AccessShareLock);
4474
4475 SET_LOCKTAG_RELATION(tag, dbid, irel->rd_index->indrelid);
4477 }
4478 else
4479 SET_LOCKTAG_RELATION(tag, dbid, relid);
4480
4481 if (!LockHeldByMe(&tag, ShareUpdateExclusiveLock, true))
4482 elog(WARNING,
4483 "missing lock for relation \"%s\" (OID %u, relkind %c) @ TID (%u,%u)",
4484 NameStr(classForm->relname),
4485 relid,
4486 classForm->relkind,
4489}
4490#endif
4491
4492/*
4493 * Check if the specified attribute's values are the same. Subroutine for
4494 * HeapDetermineColumnsInfo.
4495 */
4496static bool
4497heap_attr_equals(TupleDesc tupdesc, int attrnum, Datum value1, Datum value2,
4498 bool isnull1, bool isnull2)
4499{
4500 /*
4501 * If one value is NULL and other is not, then they are certainly not
4502 * equal
4503 */
4504 if (isnull1 != isnull2)
4505 return false;
4506
4507 /*
4508 * If both are NULL, they can be considered equal.
4509 */
4510 if (isnull1)
4511 return true;
4512
4513 /*
4514 * We do simple binary comparison of the two datums. This may be overly
4515 * strict because there can be multiple binary representations for the
4516 * same logical value. But we should be OK as long as there are no false
4517 * positives. Using a type-specific equality operator is messy because
4518 * there could be multiple notions of equality in different operator
4519 * classes; furthermore, we cannot safely invoke user-defined functions
4520 * while holding exclusive buffer lock.
4521 */
4522 if (attrnum <= 0)
4523 {
4524 /* The only allowed system columns are OIDs, so do this */
4526 }
4527 else
4528 {
4529 CompactAttribute *att;
4530
4532 att = TupleDescCompactAttr(tupdesc, attrnum - 1);
4533 return datumIsEqual(value1, value2, att->attbyval, att->attlen);
4534 }
4535}
4536
4537/*
4538 * Check which columns are being updated.
4539 *
4540 * Given an updated tuple, determine (and return into the output bitmapset),
4541 * from those listed as interesting, the set of columns that changed.
4542 *
4543 * has_external indicates if any of the unmodified attributes (from those
4544 * listed as interesting) of the old tuple is a member of external_cols and is
4545 * stored externally.
4546 */
4547static Bitmapset *
4552 bool *has_external)
4553{
4554 int attidx;
4556 TupleDesc tupdesc = RelationGetDescr(relation);
4557
4558 attidx = -1;
4559 while ((attidx = bms_next_member(interesting_cols, attidx)) >= 0)
4560 {
4561 /* attidx is zero-based, attrnum is the normal attribute number */
4563 Datum value1,
4564 value2;
4565 bool isnull1,
4566 isnull2;
4567
4568 /*
4569 * If it's a whole-tuple reference, say "not equal". It's not really
4570 * worth supporting this case, since it could only succeed after a
4571 * no-op update, which is hardly a case worth optimizing for.
4572 */
4573 if (attrnum == 0)
4574 {
4575 modified = bms_add_member(modified, attidx);
4576 continue;
4577 }
4578
4579 /*
4580 * Likewise, automatically say "not equal" for any system attribute
4581 * other than tableOID; we cannot expect these to be consistent in a
4582 * HOT chain, or even to be set correctly yet in the new tuple.
4583 */
4584 if (attrnum < 0)
4585 {
4586 if (attrnum != TableOidAttributeNumber)
4587 {
4588 modified = bms_add_member(modified, attidx);
4589 continue;
4590 }
4591 }
4592
4593 /*
4594 * Extract the corresponding values. XXX this is pretty inefficient
4595 * if there are many indexed columns. Should we do a single
4596 * heap_deform_tuple call on each tuple, instead? But that doesn't
4597 * work for system columns ...
4598 */
4599 value1 = heap_getattr(oldtup, attrnum, tupdesc, &isnull1);
4600 value2 = heap_getattr(newtup, attrnum, tupdesc, &isnull2);
4601
4602 if (!heap_attr_equals(tupdesc, attrnum, value1,
4603 value2, isnull1, isnull2))
4604 {
4605 modified = bms_add_member(modified, attidx);
4606 continue;
4607 }
4608
4609 /*
4610 * No need to check attributes that can't be stored externally. Note
4611 * that system attributes can't be stored externally.
4612 */
4613 if (attrnum < 0 || isnull1 ||
4614 TupleDescCompactAttr(tupdesc, attrnum - 1)->attlen != -1)
4615 continue;
4616
4617 /*
4618 * Check if the old tuple's attribute is stored externally and is a
4619 * member of external_cols.
4620 */
4623 *has_external = true;
4624 }
4625
4626 return modified;
4627}
4628
4629/*
4630 * simple_heap_update - replace a tuple
4631 *
4632 * This routine may be used to update a tuple when concurrent updates of
4633 * the target tuple are not expected (for example, because we have a lock
4634 * on the relation associated with the tuple). Any failure is reported
4635 * via ereport().
4636 */
4637void
4640{
4642 TM_FailureData tmfd;
4643 LockTupleMode lockmode;
4644
4645 result = heap_update(relation, otid, tup,
4646 GetCurrentCommandId(true), 0,
4648 true /* wait for commit */ ,
4649 &tmfd, &lockmode, update_indexes);
4650 switch (result)
4651 {
4652 case TM_SelfModified:
4653 /* Tuple was already updated in current command? */
4654 elog(ERROR, "tuple already updated by self");
4655 break;
4656
4657 case TM_Ok:
4658 /* done successfully */
4659 break;
4660
4661 case TM_Updated:
4662 elog(ERROR, "tuple concurrently updated");
4663 break;
4664
4665 case TM_Deleted:
4666 elog(ERROR, "tuple concurrently deleted");
4667 break;
4668
4669 default:
4670 elog(ERROR, "unrecognized heap_update status: %u", result);
4671 break;
4672 }
4673}
4674
4675
4676/*
4677 * Return the MultiXactStatus corresponding to the given tuple lock mode.
4678 */
4679static MultiXactStatus
4681{
4682 int retval;
4683
4684 if (is_update)
4685 retval = tupleLockExtraInfo[mode].updstatus;
4686 else
4687 retval = tupleLockExtraInfo[mode].lockstatus;
4688
4689 if (retval == -1)
4690 elog(ERROR, "invalid lock tuple mode %d/%s", mode,
4691 is_update ? "true" : "false");
4692
4693 return (MultiXactStatus) retval;
4694}
4695
4696/*
4697 * heap_lock_tuple - lock a tuple in shared or exclusive mode
4698 *
4699 * Note that this acquires a buffer pin, which the caller must release.
4700 *
4701 * Input parameters:
4702 * relation: relation containing tuple (caller must hold suitable lock)
4703 * cid: current command ID (used for visibility test, and stored into
4704 * tuple's cmax if lock is successful)
4705 * mode: indicates if shared or exclusive tuple lock is desired
4706 * wait_policy: what to do if tuple lock is not available
4707 * follow_updates: if true, follow the update chain to also lock descendant
4708 * tuples.
4709 *
4710 * Output parameters:
4711 * *tuple: all fields filled in
4712 * *buffer: set to buffer holding tuple (pinned but not locked at exit)
4713 * *tmfd: filled in failure cases (see below)
4714 *
4715 * Function results are the same as the ones for table_tuple_lock().
4716 *
4717 * In the failure cases other than TM_Invisible, the routine fills
4718 * *tmfd with the tuple's t_ctid, t_xmax (resolving a possible MultiXact,
4719 * if necessary), and t_cmax (the last only for TM_SelfModified,
4720 * since we cannot obtain cmax from a combo CID generated by another
4721 * transaction).
4722 * See comments for struct TM_FailureData for additional info.
4723 *
4724 * See README.tuplock for a thorough explanation of this mechanism.
4725 */
4727heap_lock_tuple(Relation relation, HeapTuple tuple,
4729 bool follow_updates,
4730 Buffer *buffer, TM_FailureData *tmfd)
4731{
4733 ItemPointer tid = &(tuple->t_self);
4734 ItemId lp;
4735 Page page;
4736 Buffer vmbuffer = InvalidBuffer;
4737 bool unlock_vmbuffer = false;
4738 BlockNumber block;
4739 TransactionId xid,
4740 xmax;
4744 bool first_time = true;
4745 bool skip_tuple_lock = false;
4746 bool have_tuple_lock = false;
4747 bool cleared_all_frozen = false;
4748
4749 *buffer = ReadBuffer(relation, ItemPointerGetBlockNumber(tid));
4750 block = ItemPointerGetBlockNumber(tid);
4751 page = BufferGetPage(*buffer);
4752
4753 /*
4754 * Before locking the buffer, pin the visibility map page if it appears to
4755 * be necessary. Since we haven't got the lock yet, someone else might be
4756 * in the middle of changing this, so we'll need to recheck after we have
4757 * the lock.
4758 */
4759 if (PageIsAllVisible(page))
4760 visibilitymap_pin(relation, block, &vmbuffer);
4761
4763
4766
4767 tuple->t_data = (HeapTupleHeader) PageGetItem(page, lp);
4768 tuple->t_len = ItemIdGetLength(lp);
4769 tuple->t_tableOid = RelationGetRelid(relation);
4770
4771l3:
4772 result = HeapTupleSatisfiesUpdate(tuple, cid, *buffer);
4773
4774 if (result == TM_Invisible)
4775 {
4776 /*
4777 * This is possible, but only when locking a tuple for ON CONFLICT DO
4778 * SELECT/UPDATE. We return this value here rather than throwing an
4779 * error in order to give that case the opportunity to throw a more
4780 * specific error.
4781 */
4783 goto out_locked;
4784 }
4785 else if (result == TM_BeingModified ||
4786 result == TM_Updated ||
4787 result == TM_Deleted)
4788 {
4792 bool require_sleep;
4793 ItemPointerData t_ctid;
4794
4795 /* must copy state data before unlocking buffer */
4797 infomask = tuple->t_data->t_infomask;
4798 infomask2 = tuple->t_data->t_infomask2;
4799 ItemPointerCopy(&tuple->t_data->t_ctid, &t_ctid);
4800
4802
4803 /*
4804 * If any subtransaction of the current top transaction already holds
4805 * a lock as strong as or stronger than what we're requesting, we
4806 * effectively hold the desired lock already. We *must* succeed
4807 * without trying to take the tuple lock, else we will deadlock
4808 * against anyone wanting to acquire a stronger lock.
4809 *
4810 * Note we only do this the first time we loop on the HTSU result;
4811 * there is no point in testing in subsequent passes, because
4812 * evidently our own transaction cannot have acquired a new lock after
4813 * the first time we checked.
4814 */
4815 if (first_time)
4816 {
4817 first_time = false;
4818
4820 {
4821 int i;
4822 int nmembers;
4823 MultiXactMember *members;
4824
4825 /*
4826 * We don't need to allow old multixacts here; if that had
4827 * been the case, HeapTupleSatisfiesUpdate would have returned
4828 * MayBeUpdated and we wouldn't be here.
4829 */
4830 nmembers =
4831 GetMultiXactIdMembers(xwait, &members, false,
4833
4834 for (i = 0; i < nmembers; i++)
4835 {
4836 /* only consider members of our own transaction */
4837 if (!TransactionIdIsCurrentTransactionId(members[i].xid))
4838 continue;
4839
4840 if (TUPLOCK_from_mxstatus(members[i].status) >= mode)
4841 {
4842 pfree(members);
4843 result = TM_Ok;
4844 goto out_unlocked;
4845 }
4846 else
4847 {
4848 /*
4849 * Disable acquisition of the heavyweight tuple lock.
4850 * Otherwise, when promoting a weaker lock, we might
4851 * deadlock with another locker that has acquired the
4852 * heavyweight tuple lock and is waiting for our
4853 * transaction to finish.
4854 *
4855 * Note that in this case we still need to wait for
4856 * the multixact if required, to avoid acquiring
4857 * conflicting locks.
4858 */
4859 skip_tuple_lock = true;
4860 }
4861 }
4862
4863 if (members)
4864 pfree(members);
4865 }
4867 {
4868 switch (mode)
4869 {
4870 case LockTupleKeyShare:
4874 result = TM_Ok;
4875 goto out_unlocked;
4876 case LockTupleShare:
4879 {
4880 result = TM_Ok;
4881 goto out_unlocked;
4882 }
4883 break;
4886 {
4887 result = TM_Ok;
4888 goto out_unlocked;
4889 }
4890 break;
4891 case LockTupleExclusive:
4894 {
4895 result = TM_Ok;
4896 goto out_unlocked;
4897 }
4898 break;
4899 }
4900 }
4901 }
4902
4903 /*
4904 * Initially assume that we will have to wait for the locking
4905 * transaction(s) to finish. We check various cases below in which
4906 * this can be turned off.
4907 */
4908 require_sleep = true;
4909 if (mode == LockTupleKeyShare)
4910 {
4911 /*
4912 * If we're requesting KeyShare, and there's no update present, we
4913 * don't need to wait. Even if there is an update, we can still
4914 * continue if the key hasn't been modified.
4915 *
4916 * However, if there are updates, we need to walk the update chain
4917 * to mark future versions of the row as locked, too. That way,
4918 * if somebody deletes that future version, we're protected
4919 * against the key going away. This locking of future versions
4920 * could block momentarily, if a concurrent transaction is
4921 * deleting a key; or it could return a value to the effect that
4922 * the transaction deleting the key has already committed. So we
4923 * do this before re-locking the buffer; otherwise this would be
4924 * prone to deadlocks.
4925 *
4926 * Note that the TID we're locking was grabbed before we unlocked
4927 * the buffer. For it to change while we're not looking, the
4928 * other properties we're testing for below after re-locking the
4929 * buffer would also change, in which case we would restart this
4930 * loop above.
4931 */
4933 {
4934 bool updated;
4935
4937
4938 /*
4939 * If there are updates, follow the update chain; bail out if
4940 * that cannot be done.
4941 */
4942 if (follow_updates && updated &&
4943 !ItemPointerEquals(&tuple->t_self, &t_ctid))
4944 {
4945 TM_Result res;
4946
4947 res = heap_lock_updated_tuple(relation,
4948 infomask, xwait, &t_ctid,
4950 mode);
4951 if (res != TM_Ok)
4952 {
4953 result = res;
4954 /* recovery code expects to have buffer lock held */
4956 goto failed;
4957 }
4958 }
4959
4961
4962 /*
4963 * Make sure it's still an appropriate lock, else start over.
4964 * Also, if it wasn't updated before we released the lock, but
4965 * is updated now, we start over too; the reason is that we
4966 * now need to follow the update chain to lock the new
4967 * versions.
4968 */
4969 if (!HeapTupleHeaderIsOnlyLocked(tuple->t_data) &&
4970 ((tuple->t_data->t_infomask2 & HEAP_KEYS_UPDATED) ||
4971 !updated))
4972 goto l3;
4973
4974 /* Things look okay, so we can skip sleeping */
4975 require_sleep = false;
4976
4977 /*
4978 * Note we allow Xmax to change here; other updaters/lockers
4979 * could have modified it before we grabbed the buffer lock.
4980 * However, this is not a problem, because with the recheck we
4981 * just did we ensure that they still don't conflict with the
4982 * lock we want.
4983 */
4984 }
4985 }
4986 else if (mode == LockTupleShare)
4987 {
4988 /*
4989 * If we're requesting Share, we can similarly avoid sleeping if
4990 * there's no update and no exclusive lock present.
4991 */
4994 {
4996
4997 /*
4998 * Make sure it's still an appropriate lock, else start over.
4999 * See above about allowing xmax to change.
5000 */
5003 goto l3;
5004 require_sleep = false;
5005 }
5006 }
5007 else if (mode == LockTupleNoKeyExclusive)
5008 {
5009 /*
5010 * If we're requesting NoKeyExclusive, we might also be able to
5011 * avoid sleeping; just ensure that there no conflicting lock
5012 * already acquired.
5013 */
5015 {
5017 mode, NULL))
5018 {
5019 /*
5020 * No conflict, but if the xmax changed under us in the
5021 * meantime, start over.
5022 */
5026 xwait))
5027 goto l3;
5028
5029 /* otherwise, we're good */
5030 require_sleep = false;
5031 }
5032 }
5034 {
5036
5037 /* if the xmax changed in the meantime, start over */
5040 xwait))
5041 goto l3;
5042 /* otherwise, we're good */
5043 require_sleep = false;
5044 }
5045 }
5046
5047 /*
5048 * As a check independent from those above, we can also avoid sleeping
5049 * if the current transaction is the sole locker of the tuple. Note
5050 * that the strength of the lock already held is irrelevant; this is
5051 * not about recording the lock in Xmax (which will be done regardless
5052 * of this optimization, below). Also, note that the cases where we
5053 * hold a lock stronger than we are requesting are already handled
5054 * above by not doing anything.
5055 *
5056 * Note we only deal with the non-multixact case here; MultiXactIdWait
5057 * is well equipped to deal with this situation on its own.
5058 */
5061 {
5062 /* ... but if the xmax changed in the meantime, start over */
5066 xwait))
5067 goto l3;
5069 require_sleep = false;
5070 }
5071
5072 /*
5073 * Time to sleep on the other transaction/multixact, if necessary.
5074 *
5075 * If the other transaction is an update/delete that's already
5076 * committed, then sleeping cannot possibly do any good: if we're
5077 * required to sleep, get out to raise an error instead.
5078 *
5079 * By here, we either have already acquired the buffer exclusive lock,
5080 * or we must wait for the locking transaction or multixact; so below
5081 * we ensure that we grab buffer lock after the sleep.
5082 */
5084 {
5086 goto failed;
5087 }
5088 else if (require_sleep)
5089 {
5090 /*
5091 * Acquire tuple lock to establish our priority for the tuple, or
5092 * die trying. LockTuple will release us when we are next-in-line
5093 * for the tuple. We must do this even if we are share-locking,
5094 * but not if we already have a weaker lock on the tuple.
5095 *
5096 * If we are forced to "start over" below, we keep the tuple lock;
5097 * this arranges that we stay at the head of the line while
5098 * rechecking tuple state.
5099 */
5100 if (!skip_tuple_lock &&
5101 !heap_acquire_tuplock(relation, tid, mode, wait_policy,
5103 {
5104 /*
5105 * This can only happen if wait_policy is Skip and the lock
5106 * couldn't be obtained.
5107 */
5109 /* recovery code expects to have buffer lock held */
5111 goto failed;
5112 }
5113
5115 {
5117
5118 /* We only ever lock tuples, never update them */
5119 if (status >= MultiXactStatusNoKeyUpdate)
5120 elog(ERROR, "invalid lock mode in heap_lock_tuple");
5121
5122 /* wait for multixact to end, or die trying */
5123 switch (wait_policy)
5124 {
5125 case LockWaitBlock:
5127 relation, &tuple->t_self, XLTW_Lock, NULL);
5128 break;
5129 case LockWaitSkip:
5131 status, infomask, relation,
5132 NULL, false))
5133 {
5135 /* recovery code expects to have buffer lock held */
5137 goto failed;
5138 }
5139 break;
5140 case LockWaitError:
5142 status, infomask, relation,
5144 ereport(ERROR,
5146 errmsg("could not obtain lock on row in relation \"%s\"",
5147 RelationGetRelationName(relation))));
5148
5149 break;
5150 }
5151
5152 /*
5153 * Of course, the multixact might not be done here: if we're
5154 * requesting a light lock mode, other transactions with light
5155 * locks could still be alive, as well as locks owned by our
5156 * own xact or other subxacts of this backend. We need to
5157 * preserve the surviving MultiXact members. Note that it
5158 * isn't absolutely necessary in the latter case, but doing so
5159 * is simpler.
5160 */
5161 }
5162 else
5163 {
5164 /* wait for regular transaction to end, or die trying */
5165 switch (wait_policy)
5166 {
5167 case LockWaitBlock:
5168 XactLockTableWait(xwait, relation, &tuple->t_self,
5169 XLTW_Lock);
5170 break;
5171 case LockWaitSkip:
5173 {
5175 /* recovery code expects to have buffer lock held */
5177 goto failed;
5178 }
5179 break;
5180 case LockWaitError:
5182 ereport(ERROR,
5184 errmsg("could not obtain lock on row in relation \"%s\"",
5185 RelationGetRelationName(relation))));
5186 break;
5187 }
5188 }
5189
5190 /* if there are updates, follow the update chain */
5192 !ItemPointerEquals(&tuple->t_self, &t_ctid))
5193 {
5194 TM_Result res;
5195
5196 res = heap_lock_updated_tuple(relation,
5197 infomask, xwait, &t_ctid,
5199 mode);
5200 if (res != TM_Ok)
5201 {
5202 result = res;
5203 /* recovery code expects to have buffer lock held */
5205 goto failed;
5206 }
5207 }
5208
5210
5211 /*
5212 * xwait is done, but if xwait had just locked the tuple then some
5213 * other xact could update this tuple before we get to this point.
5214 * Check for xmax change, and start over if so.
5215 */
5218 xwait))
5219 goto l3;
5220
5222 {
5223 /*
5224 * Otherwise check if it committed or aborted. Note we cannot
5225 * be here if the tuple was only locked by somebody who didn't
5226 * conflict with us; that would have been handled above. So
5227 * that transaction must necessarily be gone by now. But
5228 * don't check for this in the multixact case, because some
5229 * locker transactions might still be running.
5230 */
5231 UpdateXmaxHintBits(tuple->t_data, *buffer, xwait);
5232 }
5233 }
5234
5235 /* By here, we're certain that we hold buffer exclusive lock again */
5236
5237 /*
5238 * We may lock if previous xmax aborted, or if it committed but only
5239 * locked the tuple without updating it; or if we didn't have to wait
5240 * at all for whatever reason.
5241 */
5242 if (!require_sleep ||
5243 (tuple->t_data->t_infomask & HEAP_XMAX_INVALID) ||
5246 result = TM_Ok;
5247 else if (!ItemPointerEquals(&tuple->t_self, &tuple->t_data->t_ctid))
5249 else
5251 }
5252
5253failed:
5254 if (result != TM_Ok)
5255 {
5258
5259 /*
5260 * When locking a tuple under LockWaitSkip semantics and we fail with
5261 * TM_WouldBlock above, it's possible for concurrent transactions to
5262 * release the lock and set HEAP_XMAX_INVALID in the meantime. So
5263 * this assert is slightly different from the equivalent one in
5264 * heap_delete and heap_update.
5265 */
5267 !(tuple->t_data->t_infomask & HEAP_XMAX_INVALID));
5269 !ItemPointerEquals(&tuple->t_self, &tuple->t_data->t_ctid));
5270 tmfd->ctid = tuple->t_data->t_ctid;
5271 tmfd->xmax = HeapTupleHeaderGetUpdateXid(tuple->t_data);
5272 if (result == TM_SelfModified)
5273 tmfd->cmax = HeapTupleHeaderGetCmax(tuple->t_data);
5274 else
5275 tmfd->cmax = InvalidCommandId;
5276 goto out_locked;
5277 }
5278
5279 /*
5280 * If we didn't pin the visibility map page and the page has become all
5281 * visible while we were busy locking the buffer, or during some
5282 * subsequent window during which we had it unlocked, we'll have to unlock
5283 * and re-lock, to avoid holding the buffer lock across I/O. That's a bit
5284 * unfortunate, especially since we'll now have to recheck whether the
5285 * tuple has been locked or updated under us, but hopefully it won't
5286 * happen very often.
5287 */
5288 if (vmbuffer == InvalidBuffer && PageIsAllVisible(page))
5289 {
5291 visibilitymap_pin(relation, block, &vmbuffer);
5293 goto l3;
5294 }
5295
5296 xmax = HeapTupleHeaderGetRawXmax(tuple->t_data);
5297 old_infomask = tuple->t_data->t_infomask;
5298
5299 /*
5300 * If this is the first possibly-multixact-able operation in the current
5301 * transaction, set my per-backend OldestMemberMXactId setting. We can be
5302 * certain that the transaction will never become a member of any older
5303 * MultiXactIds than that. (We have to do this even if we end up just
5304 * using our own TransactionId below, since some other backend could
5305 * incorporate our XID into a MultiXact immediately afterwards.)
5306 */
5308
5309 /*
5310 * Compute the new xmax and infomask to store into the tuple. Note we do
5311 * not modify the tuple just yet, because that would leave it in the wrong
5312 * state if multixact.c elogs.
5313 */
5315 GetCurrentTransactionId(), mode, false,
5316 &xid, &new_infomask, &new_infomask2);
5317
5318 /* Lock VM buffer before entering critical section */
5319 if (PageIsAllVisible(page))
5320 {
5322 unlock_vmbuffer = true;
5323 }
5324
5326
5327 /*
5328 * Store transaction information of xact locking the tuple.
5329 *
5330 * Note: Cmax is meaningless in this context, so don't set it; this avoids
5331 * possibly generating a useless combo CID. Moreover, if we're locking a
5332 * previously updated tuple, it's important to preserve the Cmax.
5333 *
5334 * Also reset the HOT UPDATE bit, but only if there's no update; otherwise
5335 * we would break the HOT chain.
5336 */
5339 tuple->t_data->t_infomask |= new_infomask;
5340 tuple->t_data->t_infomask2 |= new_infomask2;
5343 HeapTupleHeaderSetXmax(tuple->t_data, xid);
5344
5345 /*
5346 * Make sure there is no forward chain link in t_ctid. Note that in the
5347 * cases where the tuple has been updated, we must not overwrite t_ctid,
5348 * because it was set by the updater. Moreover, if the tuple has been
5349 * updated, we need to follow the update chain to lock the new versions of
5350 * the tuple as well.
5351 */
5353 tuple->t_data->t_ctid = *tid;
5354
5355 /* Clear only the all-frozen bit on visibility map if needed */
5356 if (PageIsAllVisible(page))
5357 {
5358 if (visibilitymap_clear(relation->rd_locator, block, vmbuffer,
5360 cleared_all_frozen = true;
5361 }
5362
5363
5364 MarkBufferDirty(*buffer);
5365
5366 /*
5367 * XLOG stuff. You might think that we don't need an XLOG record because
5368 * there is no state change worth restoring after a crash. You would be
5369 * wrong however: we have just written either a TransactionId or a
5370 * MultiXactId that may never have been seen on disk before, and we need
5371 * to make sure that there are XLOG entries covering those ID numbers.
5372 * Else the same IDs might be re-used after a crash, which would be
5373 * disastrous if this page made it to disk before the crash. Essentially
5374 * we have to enforce the WAL log-before-data rule even in this case.
5375 * (Also, in a PITR log-shipping or 2PC environment, we have to have XLOG
5376 * entries for everything anyway.)
5377 */
5378 if (RelationNeedsWAL(relation))
5379 {
5382
5385
5386 xlrec.offnum = ItemPointerGetOffsetNumber(&tuple->t_self);
5387 xlrec.xmax = xid;
5388 xlrec.infobits_set = compute_infobits(new_infomask,
5389 tuple->t_data->t_infomask2);
5392
5395
5396 /* we don't decode row locks atm, so no need to log the origin */
5397
5399
5400 PageSetLSN(page, recptr);
5401
5403 PageSetLSN(BufferGetPage(vmbuffer), recptr);
5404 }
5405
5407
5408 /* release VM lock first, since it covers many heap blocks */
5409 if (unlock_vmbuffer)
5410 {
5411 LockBuffer(vmbuffer, BUFFER_LOCK_UNLOCK);
5412 unlock_vmbuffer = false;
5413 }
5414
5415 result = TM_Ok;
5416
5420
5422 if (BufferIsValid(vmbuffer))
5423 ReleaseBuffer(vmbuffer);
5424
5425 /*
5426 * Don't update the visibility map here. Locking a tuple doesn't change
5427 * visibility info.
5428 */
5429
5430 /*
5431 * Now that we have successfully marked the tuple as locked, we can
5432 * release the lmgr tuple lock, if we had it.
5433 */
5434 if (have_tuple_lock)
5435 UnlockTupleTuplock(relation, tid, mode);
5436
5437 return result;
5438}
5439
5440/*
5441 * Acquire heavyweight lock on the given tuple, in preparation for acquiring
5442 * its normal, Xmax-based tuple lock.
5443 *
5444 * have_tuple_lock is an input and output parameter: on input, it indicates
5445 * whether the lock has previously been acquired (and this function does
5446 * nothing in that case). If this function returns success, have_tuple_lock
5447 * has been flipped to true.
5448 *
5449 * Returns false if it was unable to obtain the lock; this can only happen if
5450 * wait_policy is Skip.
5451 */
5452static bool
5455{
5456 if (*have_tuple_lock)
5457 return true;
5458
5459 switch (wait_policy)
5460 {
5461 case LockWaitBlock:
5462 LockTupleTuplock(relation, tid, mode);
5463 break;
5464
5465 case LockWaitSkip:
5466 if (!ConditionalLockTupleTuplock(relation, tid, mode, false))
5467 return false;
5468 break;
5469
5470 case LockWaitError:
5472 ereport(ERROR,
5474 errmsg("could not obtain lock on row in relation \"%s\"",
5475 RelationGetRelationName(relation))));
5476 break;
5477 }
5478 *have_tuple_lock = true;
5479
5480 return true;
5481}
5482
5483/*
5484 * Given an original set of Xmax and infomask, and a transaction (identified by
5485 * add_to_xmax) acquiring a new lock of some mode, compute the new Xmax and
5486 * corresponding infomasks to use on the tuple.
5487 *
5488 * Note that this might have side effects such as creating a new MultiXactId.
5489 *
5490 * Most callers will have called HeapTupleSatisfiesUpdate before this function;
5491 * that will have set the HEAP_XMAX_INVALID bit if the xmax was a MultiXactId
5492 * but it was not running anymore. There is a race condition, which is that the
5493 * MultiXactId may have finished since then, but that uncommon case is handled
5494 * either here, or within MultiXactIdExpand.
5495 *
5496 * There is a similar race condition possible when the old xmax was a regular
5497 * TransactionId. We test TransactionIdIsInProgress again just to narrow the
5498 * window, but it's still possible to end up creating an unnecessary
5499 * MultiXactId. Fortunately this is harmless.
5500 */
5501static void
5507{
5508 TransactionId new_xmax;
5511
5513
5514l5:
5515 new_infomask = 0;
5516 new_infomask2 = 0;
5518 {
5519 /*
5520 * No previous locker; we just insert our own TransactionId.
5521 *
5522 * Note that it's critical that this case be the first one checked,
5523 * because there are several blocks below that come back to this one
5524 * to implement certain optimizations; old_infomask might contain
5525 * other dirty bits in those cases, but we don't really care.
5526 */
5527 if (is_update)
5528 {
5529 new_xmax = add_to_xmax;
5530 if (mode == LockTupleExclusive)
5532 }
5533 else
5534 {
5536 switch (mode)
5537 {
5538 case LockTupleKeyShare:
5539 new_xmax = add_to_xmax;
5541 break;
5542 case LockTupleShare:
5543 new_xmax = add_to_xmax;
5545 break;
5547 new_xmax = add_to_xmax;
5549 break;
5550 case LockTupleExclusive:
5551 new_xmax = add_to_xmax;
5554 break;
5555 default:
5556 new_xmax = InvalidTransactionId; /* silence compiler */
5557 elog(ERROR, "invalid lock mode");
5558 }
5559 }
5560 }
5562 {
5564
5565 /*
5566 * Currently we don't allow XMAX_COMMITTED to be set for multis, so
5567 * cross-check.
5568 */
5570
5571 /*
5572 * A multixact together with LOCK_ONLY set but neither lock bit set
5573 * (i.e. a pg_upgraded share locked tuple) cannot possibly be running
5574 * anymore. This check is critical for databases upgraded by
5575 * pg_upgrade; both MultiXactIdIsRunning and MultiXactIdExpand assume
5576 * that such multis are never passed.
5577 */
5579 {
5582 goto l5;
5583 }
5584
5585 /*
5586 * If the XMAX is already a MultiXactId, then we need to expand it to
5587 * include add_to_xmax; but if all the members were lockers and are
5588 * all gone, we can do away with the IS_MULTI bit and just set
5589 * add_to_xmax as the only locker/updater. If all lockers are gone
5590 * and we have an updater that aborted, we can also do without a
5591 * multi.
5592 *
5593 * The cost of doing GetMultiXactIdMembers would be paid by
5594 * MultiXactIdExpand if we weren't to do this, so this check is not
5595 * incurring extra work anyhow.
5596 */
5598 {
5601 old_infomask)))
5602 {
5603 /*
5604 * Reset these bits and restart; otherwise fall through to
5605 * create a new multi below.
5606 */
5609 goto l5;
5610 }
5611 }
5612
5614
5615 new_xmax = MultiXactIdExpand((MultiXactId) xmax, add_to_xmax,
5616 new_status);
5618 }
5620 {
5621 /*
5622 * It's a committed update, so we need to preserve him as updater of
5623 * the tuple.
5624 */
5625 MultiXactStatus status;
5627
5629 status = MultiXactStatusUpdate;
5630 else
5632
5634
5635 /*
5636 * since it's not running, it's obviously impossible for the old
5637 * updater to be identical to the current one, so we need not check
5638 * for that case as we do in the block above.
5639 */
5640 new_xmax = MultiXactIdCreate(xmax, status, add_to_xmax, new_status);
5642 }
5643 else if (TransactionIdIsInProgress(xmax))
5644 {
5645 /*
5646 * If the XMAX is a valid, in-progress TransactionId, then we need to
5647 * create a new MultiXactId that includes both the old locker or
5648 * updater and our own TransactionId.
5649 */
5653
5655 {
5661 {
5664 else
5666 }
5667 else
5668 {
5669 /*
5670 * LOCK_ONLY can be present alone only when a page has been
5671 * upgraded by pg_upgrade. But in that case,
5672 * TransactionIdIsInProgress() should have returned false. We
5673 * assume it's no longer locked in this case.
5674 */
5675 elog(WARNING, "LOCK_ONLY found for Xid in progress %u", xmax);
5678 goto l5;
5679 }
5680 }
5681 else
5682 {
5683 /* it's an update, but which kind? */
5686 else
5688 }
5689
5691
5692 /*
5693 * If the lock to be acquired is for the same TransactionId as the
5694 * existing lock, there's an optimization possible: consider only the
5695 * strongest of both locks as the only one present, and restart.
5696 */
5697 if (xmax == add_to_xmax)
5698 {
5699 /*
5700 * Note that it's not possible for the original tuple to be
5701 * updated: we wouldn't be here because the tuple would have been
5702 * invisible and we wouldn't try to update it. As a subtlety,
5703 * this code can also run when traversing an update chain to lock
5704 * future versions of a tuple. But we wouldn't be here either,
5705 * because the add_to_xmax would be different from the original
5706 * updater.
5707 */
5709
5710 /* acquire the strongest of both */
5711 if (mode < old_mode)
5712 mode = old_mode;
5713 /* mustn't touch is_update */
5714
5716 goto l5;
5717 }
5718
5719 /* otherwise, just fall back to creating a new multixact */
5721 new_xmax = MultiXactIdCreate(xmax, old_status,
5724 }
5727 {
5728 /*
5729 * It's a committed update, so we gotta preserve him as updater of the
5730 * tuple.
5731 */
5732 MultiXactStatus status;
5734
5736 status = MultiXactStatusUpdate;
5737 else
5739
5741
5742 /*
5743 * since it's not running, it's obviously impossible for the old
5744 * updater to be identical to the current one, so we need not check
5745 * for that case as we do in the block above.
5746 */
5747 new_xmax = MultiXactIdCreate(xmax, status, add_to_xmax, new_status);
5749 }
5750 else
5751 {
5752 /*
5753 * Can get here iff the locking/updating transaction was running when
5754 * the infomask was extracted from the tuple, but finished before
5755 * TransactionIdIsInProgress got to run. Deal with it as if there was
5756 * no locker at all in the first place.
5757 */
5759 goto l5;
5760 }
5761
5764 *result_xmax = new_xmax;
5765}
5766
5767/*
5768 * Subroutine for heap_lock_updated_tuple_rec.
5769 *
5770 * Given a hypothetical multixact status held by the transaction identified
5771 * with the given xid, does the current transaction need to wait, fail, or can
5772 * it continue if it wanted to acquire a lock of the given mode? "needwait"
5773 * is set to true if waiting is necessary; if it can continue, then TM_Ok is
5774 * returned. If the lock is already held by the current transaction, return
5775 * TM_SelfModified. In case of a conflict with another transaction, a
5776 * different HeapTupleSatisfiesUpdate return code is returned.
5777 *
5778 * The held status is said to be hypothetical because it might correspond to a
5779 * lock held by a single Xid, i.e. not a real MultiXactId; we express it this
5780 * way for simplicity of API.
5781 */
5782static TM_Result
5785 bool *needwait)
5786{
5788
5789 *needwait = false;
5791
5792 /*
5793 * Note: we *must* check TransactionIdIsInProgress before
5794 * TransactionIdDidAbort/Commit; see comment at top of heapam_visibility.c
5795 * for an explanation.
5796 */
5798 {
5799 /*
5800 * The tuple has already been locked by our own transaction. This is
5801 * very rare but can happen if multiple transactions are trying to
5802 * lock an ancient version of the same tuple.
5803 */
5804 return TM_SelfModified;
5805 }
5806 else if (TransactionIdIsInProgress(xid))
5807 {
5808 /*
5809 * If the locking transaction is running, what we do depends on
5810 * whether the lock modes conflict: if they do, then we must wait for
5811 * it to finish; otherwise we can fall through to lock this tuple
5812 * version without waiting.
5813 */
5816 {
5817 *needwait = true;
5818 }
5819
5820 /*
5821 * If we set needwait above, then this value doesn't matter;
5822 * otherwise, this value signals to caller that it's okay to proceed.
5823 */
5824 return TM_Ok;
5825 }
5826 else if (TransactionIdDidAbort(xid))
5827 return TM_Ok;
5828 else if (TransactionIdDidCommit(xid))
5829 {
5830 /*
5831 * The other transaction committed. If it was only a locker, then the
5832 * lock is completely gone now and we can return success; but if it
5833 * was an update, then what we do depends on whether the two lock
5834 * modes conflict. If they conflict, then we must report error to
5835 * caller. But if they don't, we can fall through to allow the current
5836 * transaction to lock the tuple.
5837 *
5838 * Note: the reason we worry about ISUPDATE here is because as soon as
5839 * a transaction ends, all its locks are gone and meaningless, and
5840 * thus we can ignore them; whereas its updates persist. In the
5841 * TransactionIdIsInProgress case, above, we don't need to check
5842 * because we know the lock is still "alive" and thus a conflict needs
5843 * always be checked.
5844 */
5845 if (!ISUPDATE_from_mxstatus(status))
5846 return TM_Ok;
5847
5850 {
5851 /* bummer */
5852 if (!ItemPointerEquals(&tup->t_self, &tup->t_data->t_ctid))
5853 return TM_Updated;
5854 else
5855 return TM_Deleted;
5856 }
5857
5858 return TM_Ok;
5859 }
5860
5861 /* Not in progress, not aborted, not committed -- must have crashed */
5862 return TM_Ok;
5863}
5864
5865
5866/*
5867 * Recursive part of heap_lock_updated_tuple
5868 *
5869 * Fetch the tuple pointed to by tid in rel, and mark it as locked by the given
5870 * xid with the given mode; if this tuple is updated, recurse to lock the new
5871 * version as well.
5872 */
5873static TM_Result
5875 const ItemPointerData *tid, TransactionId xid,
5877{
5881 Buffer buf;
5882 Page page;
5887 TransactionId xmax,
5888 new_xmax;
5889 bool cleared_all_frozen = false;
5891 Buffer vmbuffer = InvalidBuffer;
5892 bool unlock_vmbuffer = false;
5893 BlockNumber block;
5894
5895 ItemPointerCopy(tid, &tupid);
5896
5897 for (;;)
5898 {
5899 new_infomask = 0;
5900 new_xmax = InvalidTransactionId;
5901 cleared_all_frozen = false;
5903 ItemPointerCopy(&tupid, &(mytup.t_self));
5904
5905 if (!heap_fetch(rel, SnapshotAny, &mytup, &buf, false))
5906 {
5907 /*
5908 * if we fail to find the updated version of the tuple, it's
5909 * because it was vacuumed/pruned away after its creator
5910 * transaction aborted. So behave as if we got to the end of the
5911 * chain, and there's no further tuple to lock: return success to
5912 * caller.
5913 */
5914 result = TM_Ok;
5915 goto out_unlocked;
5916 }
5917
5918l4:
5920
5921 page = BufferGetPage(buf);
5922
5923 /*
5924 * Before locking the buffer, pin the visibility map page if it
5925 * appears to be necessary. Since we haven't got the lock yet,
5926 * someone else might be in the middle of changing this, so we'll need
5927 * to recheck after we have the lock.
5928 */
5929 if (PageIsAllVisible(page))
5930 {
5931 visibilitymap_pin(rel, block, &vmbuffer);
5932 pinned_desired_page = true;
5933 }
5934 else
5935 pinned_desired_page = false;
5936
5938
5939 /*
5940 * If we didn't pin the visibility map page and the page has become
5941 * all visible while we were busy locking the buffer, we'll have to
5942 * unlock and re-lock, to avoid holding the buffer lock across I/O.
5943 * That's a bit unfortunate, but hopefully shouldn't happen often.
5944 *
5945 * Note: in some paths through this function, we will reach here
5946 * holding a pin on a vm page that may or may not be the one matching
5947 * this page. If this page isn't all-visible, we won't use the vm
5948 * page, but we hold onto such a pin till the end of the function.
5949 */
5951 {
5953 visibilitymap_pin(rel, block, &vmbuffer);
5955 }
5956
5957 /*
5958 * Check the tuple XMIN against prior XMAX, if any. If we reached the
5959 * end of the chain, we're done, so return success.
5960 */
5963 priorXmax))
5964 {
5965 result = TM_Ok;
5966 goto out_locked;
5967 }
5968
5969 /*
5970 * Also check Xmin: if this tuple was created by an aborted
5971 * (sub)transaction, then we already locked the last live one in the
5972 * chain, thus we're done, so return success.
5973 */
5975 {
5976 result = TM_Ok;
5977 goto out_locked;
5978 }
5979
5980 old_infomask = mytup.t_data->t_infomask;
5981 old_infomask2 = mytup.t_data->t_infomask2;
5982 xmax = HeapTupleHeaderGetRawXmax(mytup.t_data);
5983
5984 /*
5985 * If this tuple version has been updated or locked by some concurrent
5986 * transaction(s), what we do depends on whether our lock mode
5987 * conflicts with what those other transactions hold, and also on the
5988 * status of them.
5989 */
5991 {
5993 bool needwait;
5994
5997 {
5998 int nmembers;
5999 int i;
6000 MultiXactMember *members;
6001
6002 /*
6003 * We don't need a test for pg_upgrade'd tuples: this is only
6004 * applied to tuples after the first in an update chain. Said
6005 * first tuple in the chain may well be locked-in-9.2-and-
6006 * pg_upgraded, but that one was already locked by our caller,
6007 * not us; and any subsequent ones cannot be because our
6008 * caller must necessarily have obtained a snapshot later than
6009 * the pg_upgrade itself.
6010 */
6011 Assert(!HEAP_LOCKED_UPGRADED(mytup.t_data->t_infomask));
6012
6013 nmembers = GetMultiXactIdMembers(rawxmax, &members, false,
6015 for (i = 0; i < nmembers; i++)
6016 {
6017 result = test_lockmode_for_conflict(members[i].status,
6018 members[i].xid,
6019 mode,
6020 &mytup,
6021 &needwait);
6022
6023 /*
6024 * If the tuple was already locked by ourselves in a
6025 * previous iteration of this (say heap_lock_tuple was
6026 * forced to restart the locking loop because of a change
6027 * in xmax), then we hold the lock already on this tuple
6028 * version and we don't need to do anything; and this is
6029 * not an error condition either. We just need to skip
6030 * this tuple and continue locking the next version in the
6031 * update chain.
6032 */
6033 if (result == TM_SelfModified)
6034 {
6035 pfree(members);
6036 goto next;
6037 }
6038
6039 if (needwait)
6040 {
6042 XactLockTableWait(members[i].xid, rel,
6043 &mytup.t_self,
6045 pfree(members);
6046 goto l4;
6047 }
6048 if (result != TM_Ok)
6049 {
6050 pfree(members);
6051 goto out_locked;
6052 }
6053 }
6054 if (members)
6055 pfree(members);
6056 }
6057 else
6058 {
6059 MultiXactStatus status;
6060
6061 /*
6062 * For a non-multi Xmax, we first need to compute the
6063 * corresponding MultiXactStatus by using the infomask bits.
6064 */
6066 {
6070 status = MultiXactStatusForShare;
6072 {
6074 status = MultiXactStatusForUpdate;
6075 else
6077 }
6078 else
6079 {
6080 /*
6081 * LOCK_ONLY present alone (a pg_upgraded tuple marked
6082 * as share-locked in the old cluster) shouldn't be
6083 * seen in the middle of an update chain.
6084 */
6085 elog(ERROR, "invalid lock status in tuple");
6086 }
6087 }
6088 else
6089 {
6090 /* it's an update, but which kind? */
6092 status = MultiXactStatusUpdate;
6093 else
6095 }
6096
6098 &mytup, &needwait);
6099
6100 /*
6101 * If the tuple was already locked by ourselves in a previous
6102 * iteration of this (say heap_lock_tuple was forced to
6103 * restart the locking loop because of a change in xmax), then
6104 * we hold the lock already on this tuple version and we don't
6105 * need to do anything; and this is not an error condition
6106 * either. We just need to skip this tuple and continue
6107 * locking the next version in the update chain.
6108 */
6109 if (result == TM_SelfModified)
6110 goto next;
6111
6112 if (needwait)
6113 {
6115 XactLockTableWait(rawxmax, rel, &mytup.t_self,
6117 goto l4;
6118 }
6119 if (result != TM_Ok)
6120 {
6121 goto out_locked;
6122 }
6123 }
6124 }
6125
6126 /* compute the new Xmax and infomask values for the tuple ... */
6127 compute_new_xmax_infomask(xmax, old_infomask, mytup.t_data->t_infomask2,
6128 xid, mode, false,
6129 &new_xmax, &new_infomask, &new_infomask2);
6130
6131 if (PageIsAllVisible(page))
6132 {
6134 unlock_vmbuffer = true;
6135 }
6136
6138
6139 /* ... and set them */
6140 HeapTupleHeaderSetXmax(mytup.t_data, new_xmax);
6141 mytup.t_data->t_infomask &= ~HEAP_XMAX_BITS;
6142 mytup.t_data->t_infomask2 &= ~HEAP_KEYS_UPDATED;
6143 mytup.t_data->t_infomask |= new_infomask;
6144 mytup.t_data->t_infomask2 |= new_infomask2;
6145
6147
6148 if (PageIsAllVisible(page))
6149 {
6150 /* It's possible all-frozen was already clear */
6151 if (visibilitymap_clear(rel->rd_locator, block, vmbuffer,
6153 cleared_all_frozen = true;
6154 }
6155
6156 /* XLOG stuff */
6157 if (RelationNeedsWAL(rel))
6158 {
6161
6164
6165 xlrec.offnum = ItemPointerGetOffsetNumber(&mytup.t_self);
6166 xlrec.xmax = new_xmax;
6168 xlrec.flags =
6170
6172
6175
6177
6178 PageSetLSN(page, recptr);
6179
6181 PageSetLSN(BufferGetPage(vmbuffer), recptr);
6182 }
6183
6185
6186 /* release VM lock first, since it covers many heap blocks */
6187 if (unlock_vmbuffer)
6188 {
6189 LockBuffer(vmbuffer, BUFFER_LOCK_UNLOCK);
6190 unlock_vmbuffer = false;
6191 }
6192
6193next:
6194 /* if we find the end of update chain, we're done. */
6195 if (mytup.t_data->t_infomask & HEAP_XMAX_INVALID ||
6197 ItemPointerEquals(&mytup.t_self, &mytup.t_data->t_ctid) ||
6199 {
6200 result = TM_Ok;
6201 goto out_locked;
6202 }
6203
6204 /* tail recursion */
6206 ItemPointerCopy(&(mytup.t_data->t_ctid), &tupid);
6208 }
6209
6210 result = TM_Ok;
6211
6214
6216 if (vmbuffer != InvalidBuffer)
6217 ReleaseBuffer(vmbuffer);
6219
6220 return result;
6221}
6222
6223/*
6224 * heap_lock_updated_tuple
6225 * Follow update chain when locking an updated tuple, acquiring locks (row
6226 * marks) on the updated versions.
6227 *
6228 * 'prior_infomask', 'prior_raw_xmax' and 'prior_ctid' are the corresponding
6229 * fields from the initial tuple. We will lock the tuples starting from the
6230 * one that 'prior_ctid' points to. Note: This function does not lock the
6231 * initial tuple itself.
6232 *
6233 * This function doesn't check visibility, it just unconditionally marks the
6234 * tuple(s) as locked. If any tuple in the updated chain is being deleted
6235 * concurrently (or updated with the key being modified), sleep until the
6236 * transaction doing it is finished.
6237 *
6238 * Note that we don't acquire heavyweight tuple locks on the tuples we walk
6239 * when we have to wait for other transactions to release them, as opposed to
6240 * what heap_lock_tuple does. The reason is that having more than one
6241 * transaction walking the chain is probably uncommon enough that risk of
6242 * starvation is not likely: one of the preconditions for being here is that
6243 * the snapshot in use predates the update that created this tuple (because we
6244 * started at an earlier version of the tuple), but at the same time such a
6245 * transaction cannot be using repeatable read or serializable isolation
6246 * levels, because that would lead to a serializability failure.
6247 */
6248static TM_Result
6254{
6255 INJECTION_POINT("heap_lock_updated_tuple", NULL);
6256
6257 /*
6258 * If the tuple has moved into another partition (effectively a delete)
6259 * stop here.
6260 */
6262 {
6264
6265 /*
6266 * If this is the first possibly-multixact-able operation in the
6267 * current transaction, set my per-backend OldestMemberMXactId
6268 * setting. We can be certain that the transaction will never become a
6269 * member of any older MultiXactIds than that. (We have to do this
6270 * even if we end up just using our own TransactionId below, since
6271 * some other backend could incorporate our XID into a MultiXact
6272 * immediately afterwards.)
6273 */
6275
6279 }
6280
6281 /* nothing to lock */
6282 return TM_Ok;
6283}
6284
6285/*
6286 * heap_finish_speculative - mark speculative insertion as successful
6287 *
6288 * To successfully finish a speculative insertion we have to clear speculative
6289 * token from tuple. To do so the t_ctid field, which will contain a
6290 * speculative token value, is modified in place to point to the tuple itself,
6291 * which is characteristic of a newly inserted ordinary tuple.
6292 *
6293 * NB: It is not ok to commit without either finishing or aborting a
6294 * speculative insertion. We could treat speculative tuples of committed
6295 * transactions implicitly as completed, but then we would have to be prepared
6296 * to deal with speculative tokens on committed tuples. That wouldn't be
6297 * difficult - no-one looks at the ctid field of a tuple with invalid xmax -
6298 * but clearing the token at completion isn't very expensive either.
6299 * An explicit confirmation WAL record also makes logical decoding simpler.
6300 */
6301void
6303{
6304 Buffer buffer;
6305 Page page;
6306 OffsetNumber offnum;
6307 ItemId lp;
6308 HeapTupleHeader htup;
6309
6310 buffer = ReadBuffer(relation, ItemPointerGetBlockNumber(tid));
6312 page = BufferGetPage(buffer);
6313
6314 offnum = ItemPointerGetOffsetNumber(tid);
6316 elog(ERROR, "offnum out of range");
6317 lp = PageGetItemId(page, offnum);
6318 if (!ItemIdIsNormal(lp))
6319 elog(ERROR, "invalid lp");
6320
6321 htup = (HeapTupleHeader) PageGetItem(page, lp);
6322
6323 /* NO EREPORT(ERROR) from here till changes are logged */
6325
6327
6328 MarkBufferDirty(buffer);
6329
6330 /*
6331 * Replace the speculative insertion token with a real t_ctid, pointing to
6332 * itself like it does on regular tuples.
6333 */
6334 htup->t_ctid = *tid;
6335
6336 /* XLOG stuff */
6337 if (RelationNeedsWAL(relation))
6338 {
6341
6343
6345
6346 /* We want the same filtering on this as on a plain insert */
6348
6351
6353
6354 PageSetLSN(page, recptr);
6355 }
6356
6358
6359 UnlockReleaseBuffer(buffer);
6360}
6361
6362/*
6363 * heap_abort_speculative - kill a speculatively inserted tuple
6364 *
6365 * Marks a tuple that was speculatively inserted in the same command as dead,
6366 * by setting its xmin as invalid. That makes it immediately appear as dead
6367 * to all transactions, including our own. In particular, it makes
6368 * HeapTupleSatisfiesDirty() regard the tuple as dead, so that another backend
6369 * inserting a duplicate key value won't unnecessarily wait for our whole
6370 * transaction to finish (it'll just wait for our speculative insertion to
6371 * finish).
6372 *
6373 * Killing the tuple prevents "unprincipled deadlocks", which are deadlocks
6374 * that arise due to a mutual dependency that is not user visible. By
6375 * definition, unprincipled deadlocks cannot be prevented by the user
6376 * reordering lock acquisition in client code, because the implementation level
6377 * lock acquisitions are not under the user's direct control. If speculative
6378 * inserters did not take this precaution, then under high concurrency they
6379 * could deadlock with each other, which would not be acceptable.
6380 *
6381 * This is somewhat redundant with heap_delete, but we prefer to have a
6382 * dedicated routine with stripped down requirements. Note that this is also
6383 * used to delete the TOAST tuples created during speculative insertion.
6384 *
6385 * This routine does not affect logical decoding as it only looks at
6386 * confirmation records.
6387 */
6388void
6390{
6392 ItemId lp;
6393 HeapTupleData tp;
6394 Page page;
6395 BlockNumber block;
6396 Buffer buffer;
6397
6399
6400 block = ItemPointerGetBlockNumber(tid);
6401 buffer = ReadBuffer(relation, block);
6402 page = BufferGetPage(buffer);
6403
6405
6406 /*
6407 * Page can't be all visible, we just inserted into it, and are still
6408 * running.
6409 */
6410 Assert(!PageIsAllVisible(page));
6411
6414
6415 tp.t_tableOid = RelationGetRelid(relation);
6416 tp.t_data = (HeapTupleHeader) PageGetItem(page, lp);
6417 tp.t_len = ItemIdGetLength(lp);
6418 tp.t_self = *tid;
6419
6420 /*
6421 * Sanity check that the tuple really is a speculatively inserted tuple,
6422 * inserted by us.
6423 */
6424 if (tp.t_data->t_choice.t_heap.t_xmin != xid)
6425 elog(ERROR, "attempted to kill a tuple inserted by another transaction");
6426 if (!(IsToastRelation(relation) || HeapTupleHeaderIsSpeculative(tp.t_data)))
6427 elog(ERROR, "attempted to kill a non-speculative tuple");
6429
6430 /*
6431 * No need to check for serializable conflicts here. There is never a
6432 * need for a combo CID, either. No need to extract replica identity, or
6433 * do anything special with infomask bits.
6434 */
6435
6437
6438 /*
6439 * The tuple will become DEAD immediately. Flag that this page is a
6440 * candidate for pruning by setting xmin to TransactionXmin. While not
6441 * immediately prunable, it is the oldest xid we can cheaply determine
6442 * that's safe against wraparound / being older than the table's
6443 * relfrozenxid. To defend against the unlikely case of a new relation
6444 * having a newer relfrozenxid than our TransactionXmin, use relfrozenxid
6445 * if so (vacuum can't subsequently move relfrozenxid to beyond
6446 * TransactionXmin, so there's no race here).
6447 */
6449 {
6450 TransactionId relfrozenxid = relation->rd_rel->relfrozenxid;
6452
6453 if (TransactionIdPrecedes(TransactionXmin, relfrozenxid))
6454 prune_xid = relfrozenxid;
6455 else
6458 }
6459
6460 /* store transaction information of xact deleting the tuple */
6463
6464 /*
6465 * Set the tuple header xmin to InvalidTransactionId. This makes the
6466 * tuple immediately invisible everyone. (In particular, to any
6467 * transactions waiting on the speculative token, woken up later.)
6468 */
6470
6471 /* Clear the speculative insertion token too */
6472 tp.t_data->t_ctid = tp.t_self;
6473
6474 MarkBufferDirty(buffer);
6475
6476 /*
6477 * XLOG stuff
6478 *
6479 * The WAL records generated here match heap_delete(). The same recovery
6480 * routines are used.
6481 */
6482 if (RelationNeedsWAL(relation))
6483 {
6486
6488 xlrec.infobits_set = compute_infobits(tp.t_data->t_infomask,
6489 tp.t_data->t_infomask2);
6491 xlrec.xmax = xid;
6492
6496
6497 /* No replica identity & replication origin logged */
6498
6500
6501 PageSetLSN(page, recptr);
6502 }
6503
6505
6507
6508 if (HeapTupleHasExternal(&tp))
6509 {
6510 Assert(!IsToastRelation(relation));
6511 heap_toast_delete(relation, &tp, true);
6512 }
6513
6514 /*
6515 * Never need to mark tuple for invalidation, since catalogs don't support
6516 * speculative insertion
6517 */
6518
6519 /* Now we can release the buffer */
6520 ReleaseBuffer(buffer);
6521
6522 /* count deletion, as we counted the insertion too */
6523 pgstat_count_heap_delete(relation);
6524}
6525
6526/*
6527 * heap_inplace_lock - protect inplace update from concurrent heap_update()
6528 *
6529 * Evaluate whether the tuple's state is compatible with a no-key update.
6530 * Current transaction rowmarks are fine, as is KEY SHARE from any
6531 * transaction. If compatible, return true with the buffer exclusive-locked,
6532 * and the caller must release that by calling
6533 * heap_inplace_update_and_unlock(), calling heap_inplace_unlock(), or raising
6534 * an error. Otherwise, call release_callback(arg), wait for blocking
6535 * transactions to end, and return false.
6536 *
6537 * Since this is intended for system catalogs and SERIALIZABLE doesn't cover
6538 * DDL, this doesn't guarantee any particular predicate locking.
6539 *
6540 * heap_delete() is a rarer source of blocking transactions (xwait). We'll
6541 * wait for such a transaction just like for the normal heap_update() case.
6542 * Normal concurrent DROP commands won't cause that, because all inplace
6543 * updaters take some lock that conflicts with DROP. An explicit SQL "DELETE
6544 * FROM pg_class" can cause it. By waiting, if the concurrent transaction
6545 * executed both "DELETE FROM pg_class" and "INSERT INTO pg_class", our caller
6546 * can find the successor tuple.
6547 *
6548 * Readers of inplace-updated fields expect changes to those fields are
6549 * durable. For example, vac_truncate_clog() reads datfrozenxid from
6550 * pg_database tuples via catalog snapshots. A future snapshot must not
6551 * return a lower datfrozenxid for the same database OID (lower in the
6552 * FullTransactionIdPrecedes() sense). We achieve that since no update of a
6553 * tuple can start while we hold a lock on its buffer. In cases like
6554 * BEGIN;GRANT;CREATE INDEX;COMMIT we're inplace-updating a tuple visible only
6555 * to this transaction. ROLLBACK then is one case where it's okay to lose
6556 * inplace updates. (Restoring relhasindex=false on ROLLBACK is fine, since
6557 * any concurrent CREATE INDEX would have blocked, then inplace-updated the
6558 * committed tuple.)
6559 *
6560 * In principle, we could avoid waiting by overwriting every tuple in the
6561 * updated tuple chain. Reader expectations permit updating a tuple only if
6562 * it's aborted, is the tail of the chain, or we already updated the tuple
6563 * referenced in its t_ctid. Hence, we would need to overwrite the tuples in
6564 * order from tail to head. That would imply either (a) mutating all tuples
6565 * in one critical section or (b) accepting a chance of partial completion.
6566 * Partial completion of a relfrozenxid update would have the weird
6567 * consequence that the table's next VACUUM could see the table's relfrozenxid
6568 * move forward between vacuum_get_cutoffs() and finishing.
6569 */
6570bool
6572 HeapTuple oldtup_ptr, Buffer buffer,
6573 void (*release_callback) (void *), void *arg)
6574{
6575 HeapTupleData oldtup = *oldtup_ptr; /* minimize diff vs. heap_update() */
6577 bool ret;
6578
6579#ifdef USE_ASSERT_CHECKING
6580 if (RelationGetRelid(relation) == RelationRelationId)
6582#endif
6583
6584 Assert(BufferIsValid(buffer));
6585
6586 /*
6587 * Register shared cache invals if necessary. Other sessions may finish
6588 * inplace updates of this tuple between this step and LockTuple(). Since
6589 * inplace updates don't change cache keys, that's harmless.
6590 *
6591 * While it's tempting to register invals only after confirming we can
6592 * return true, the following obstacle precludes reordering steps that
6593 * way. Registering invals might reach a CatalogCacheInitializeCache()
6594 * that locks "buffer". That would hang indefinitely if running after our
6595 * own LockBuffer(). Hence, we must register invals before LockBuffer().
6596 */
6598
6599 LockTuple(relation, &oldtup.t_self, InplaceUpdateTupleLock);
6601
6602 /*----------
6603 * Interpret HeapTupleSatisfiesUpdate() like heap_update() does, except:
6604 *
6605 * - wait unconditionally
6606 * - already locked tuple above, since inplace needs that unconditionally
6607 * - don't recheck header after wait: simpler to defer to next iteration
6608 * - don't try to continue even if the updater aborts: likewise
6609 * - no crosscheck
6610 */
6612 buffer);
6613
6614 if (result == TM_Invisible)
6615 {
6616 /* no known way this can happen */
6617 ereport(ERROR,
6619 errmsg_internal("attempted to overwrite invisible tuple")));
6620 }
6621 else if (result == TM_SelfModified)
6622 {
6623 /*
6624 * CREATE INDEX might reach this if an expression is silly enough to
6625 * call e.g. SELECT ... FROM pg_class FOR SHARE. C code of other SQL
6626 * statements might get here after a heap_update() of the same row, in
6627 * the absence of an intervening CommandCounterIncrement().
6628 */
6629 ereport(ERROR,
6631 errmsg("tuple to be updated was already modified by an operation triggered by the current command")));
6632 }
6633 else if (result == TM_BeingModified)
6634 {
6637
6639 infomask = oldtup.t_data->t_infomask;
6640
6642 {
6645 int remain;
6646
6648 lockmode, NULL))
6649 {
6652 ret = false;
6654 relation, &oldtup.t_self, XLTW_Update,
6655 &remain);
6656 }
6657 else
6658 ret = true;
6659 }
6661 ret = true;
6663 ret = true;
6664 else
6665 {
6668 ret = false;
6669 XactLockTableWait(xwait, relation, &oldtup.t_self,
6670 XLTW_Update);
6671 }
6672 }
6673 else
6674 {
6675 ret = (result == TM_Ok);
6676 if (!ret)
6677 {
6680 }
6681 }
6682
6683 /*
6684 * GetCatalogSnapshot() relies on invalidation messages to know when to
6685 * take a new snapshot. COMMIT of xwait is responsible for sending the
6686 * invalidation. We're not acquiring heavyweight locks sufficient to
6687 * block if not yet sent, so we must take a new snapshot to ensure a later
6688 * attempt has a fair chance. While we don't need this if xwait aborted,
6689 * don't bother optimizing that.
6690 */
6691 if (!ret)
6692 {
6693 UnlockTuple(relation, &oldtup.t_self, InplaceUpdateTupleLock);
6696 }
6697 return ret;
6698}
6699
6700/*
6701 * heap_inplace_update_and_unlock - core of systable_inplace_update_finish
6702 *
6703 * The tuple cannot change size, and therefore its header fields and null
6704 * bitmap (if any) don't change either.
6705 *
6706 * Since we hold LOCKTAG_TUPLE, no updater has a local copy of this tuple.
6707 */
6708void
6710 HeapTuple oldtup, HeapTuple tuple,
6711 Buffer buffer)
6712{
6713 HeapTupleHeader htup = oldtup->t_data;
6714 uint32 oldlen;
6715 uint32 newlen;
6716 char *dst;
6717 char *src;
6718 int nmsgs = 0;
6720 bool RelcacheInitFileInval = false;
6721
6722 Assert(ItemPointerEquals(&oldtup->t_self, &tuple->t_self));
6723 oldlen = oldtup->t_len - htup->t_hoff;
6724 newlen = tuple->t_len - tuple->t_data->t_hoff;
6725 if (oldlen != newlen || htup->t_hoff != tuple->t_data->t_hoff)
6726 elog(ERROR, "wrong tuple length");
6727
6728 dst = (char *) htup + htup->t_hoff;
6729 src = (char *) tuple->t_data + tuple->t_data->t_hoff;
6730
6731 /* Like RecordTransactionCommit(), log only if needed */
6734 &RelcacheInitFileInval);
6735
6736 /*
6737 * Unlink relcache init files as needed. If unlinking, acquire
6738 * RelCacheInitLock until after associated invalidations. By doing this
6739 * in advance, if we checkpoint and then crash between inplace
6740 * XLogInsert() and inval, we don't rely on StartupXLOG() ->
6741 * RelationCacheInitFileRemove(). That uses elevel==LOG, so replay would
6742 * neglect to PANIC on EIO.
6743 */
6745
6746 /*----------
6747 * NO EREPORT(ERROR) from here till changes are complete
6748 *
6749 * Our exclusive buffer lock won't stop a reader having already pinned and
6750 * checked visibility for this tuple. With the usual order of changes
6751 * (i.e. updating the buffer contents before WAL logging), a reader could
6752 * observe our not-yet-persistent update to relfrozenxid and update
6753 * datfrozenxid based on that. A crash in that moment could allow
6754 * datfrozenxid to overtake relfrozenxid:
6755 *
6756 * ["D" is a VACUUM (ONLY_DATABASE_STATS)]
6757 * ["R" is a VACUUM tbl]
6758 * D: vac_update_datfrozenxid() -> systable_beginscan(pg_class)
6759 * D: systable_getnext() returns pg_class tuple of tbl
6760 * R: memcpy() into pg_class tuple of tbl
6761 * D: raise pg_database.datfrozenxid, XLogInsert(), finish
6762 * [crash]
6763 * [recovery restores datfrozenxid w/o relfrozenxid]
6764 *
6765 * We avoid that by using a temporary copy of the buffer to hide our
6766 * change from other backends until the change has been WAL-logged. We
6767 * apply our change to the temporary copy and WAL-log it, before modifying
6768 * the real page. That way any action a reader of the in-place-updated
6769 * value takes will be WAL logged after this change.
6770 */
6772
6773 MarkBufferDirty(buffer);
6774
6775 /* XLOG stuff */
6776 if (RelationNeedsWAL(relation))
6777 {
6780 char *origdata = (char *) BufferGetBlock(buffer);
6781 Page page = BufferGetPage(buffer);
6782 uint16 lower = ((PageHeader) page)->pd_lower;
6783 uint16 upper = ((PageHeader) page)->pd_upper;
6785 RelFileLocator rlocator;
6786 ForkNumber forkno;
6787 BlockNumber blkno;
6789
6790 xlrec.offnum = ItemPointerGetOffsetNumber(&tuple->t_self);
6791 xlrec.dbId = MyDatabaseId;
6793 xlrec.relcacheInitFileInval = RelcacheInitFileInval;
6794 xlrec.nmsgs = nmsgs;
6795
6798 if (nmsgs != 0)
6800 nmsgs * sizeof(SharedInvalidationMessage));
6801
6802 /* register block matching what buffer will look like after changes */
6807 BufferGetTag(buffer, &rlocator, &forkno, &blkno);
6808 Assert(forkno == MAIN_FORKNUM);
6809 XLogRegisterBlock(0, &rlocator, forkno, blkno, copied_buffer.data,
6811 XLogRegisterBufData(0, src, newlen);
6812
6813 /* inplace updates aren't decoded atm, don't log the origin */
6814
6816
6817 PageSetLSN(page, recptr);
6818 }
6819
6820 memcpy(dst, src, newlen);
6821
6823
6824 /*
6825 * Send invalidations to shared queue. SearchSysCacheLocked1() assumes we
6826 * do this before UnlockTuple().
6827 */
6829
6831 UnlockTuple(relation, &tuple->t_self, InplaceUpdateTupleLock);
6832
6833 AcceptInvalidationMessages(); /* local processing of just-sent inval */
6834
6835 /*
6836 * Queue a transactional inval, for logical decoding and for third-party
6837 * code that might have been relying on it since long before inplace
6838 * update adopted immediate invalidation. See README.tuplock section
6839 * "Reading inplace-updated columns" for logical decoding details.
6840 */
6842 CacheInvalidateHeapTuple(relation, tuple, NULL);
6843}
6844
6845/*
6846 * heap_inplace_unlock - reverse of heap_inplace_lock
6847 */
6848void
6850 HeapTuple oldtup, Buffer buffer)
6851{
6853 UnlockTuple(relation, &oldtup->t_self, InplaceUpdateTupleLock);
6855}
6856
6857#define FRM_NOOP 0x0001
6858#define FRM_INVALIDATE_XMAX 0x0002
6859#define FRM_RETURN_IS_XID 0x0004
6860#define FRM_RETURN_IS_MULTI 0x0008
6861#define FRM_MARK_COMMITTED 0x0010
6862
6863/*
6864 * FreezeMultiXactId
6865 * Determine what to do during freezing when a tuple is marked by a
6866 * MultiXactId.
6867 *
6868 * "flags" is an output value; it's used to tell caller what to do on return.
6869 * "pagefrz" is an input/output value, used to manage page level freezing.
6870 *
6871 * Possible values that we can set in "flags":
6872 * FRM_NOOP
6873 * don't do anything -- keep existing Xmax
6874 * FRM_INVALIDATE_XMAX
6875 * mark Xmax as InvalidTransactionId and set XMAX_INVALID flag.
6876 * FRM_RETURN_IS_XID
6877 * The Xid return value is a single update Xid to set as xmax.
6878 * FRM_MARK_COMMITTED
6879 * Xmax can be marked as HEAP_XMAX_COMMITTED
6880 * FRM_RETURN_IS_MULTI
6881 * The return value is a new MultiXactId to set as new Xmax.
6882 * (caller must obtain proper infomask bits using GetMultiXactIdHintBits)
6883 *
6884 * Caller delegates control of page freezing to us. In practice we always
6885 * force freezing of caller's page unless FRM_NOOP processing is indicated.
6886 * We help caller ensure that XIDs < FreezeLimit and MXIDs < MultiXactCutoff
6887 * can never be left behind. We freely choose when and how to process each
6888 * Multi, without ever violating the cutoff postconditions for freezing.
6889 *
6890 * It's useful to remove Multis on a proactive timeline (relative to freezing
6891 * XIDs) to keep MultiXact member SLRU buffer misses to a minimum. It can also
6892 * be cheaper in the short run, for us, since we too can avoid SLRU buffer
6893 * misses through eager processing.
6894 *
6895 * NB: Creates a _new_ MultiXactId when FRM_RETURN_IS_MULTI is set, though only
6896 * when FreezeLimit and/or MultiXactCutoff cutoffs leave us with no choice.
6897 * This can usually be put off, which is usually enough to avoid it altogether.
6898 * Allocating new multis during VACUUM should be avoided on general principle;
6899 * only VACUUM can advance relminmxid, so allocating new Multis here comes with
6900 * its own special risks.
6901 *
6902 * NB: Caller must maintain "no freeze" NewRelfrozenXid/NewRelminMxid trackers
6903 * using heap_tuple_should_freeze when we haven't forced page-level freezing.
6904 *
6905 * NB: Caller should avoid needlessly calling heap_tuple_should_freeze when we
6906 * have already forced page-level freezing, since that might incur the same
6907 * SLRU buffer misses that we specifically intended to avoid by freezing.
6908 */
6909static TransactionId
6910FreezeMultiXactId(MultiXactId multi, uint16 t_infomask,
6911 const struct VacuumCutoffs *cutoffs, uint16 *flags,
6912 HeapPageFreeze *pagefrz)
6913{
6915 MultiXactMember *members;
6916 int nmembers;
6917 bool need_replace;
6918 int nnewmembers;
6920 bool has_lockers;
6922 bool update_committed;
6923 TransactionId FreezePageRelfrozenXid;
6924
6925 *flags = 0;
6926
6927 /* We should only be called in Multis */
6928 Assert(t_infomask & HEAP_XMAX_IS_MULTI);
6929
6930 if (!MultiXactIdIsValid(multi) ||
6931 HEAP_LOCKED_UPGRADED(t_infomask))
6932 {
6933 *flags |= FRM_INVALIDATE_XMAX;
6934 pagefrz->freeze_required = true;
6935 return InvalidTransactionId;
6936 }
6937 else if (MultiXactIdPrecedes(multi, cutoffs->relminmxid))
6938 ereport(ERROR,
6940 errmsg_internal("found multixact %u from before relminmxid %u",
6941 multi, cutoffs->relminmxid)));
6942 else if (MultiXactIdPrecedes(multi, cutoffs->OldestMxact))
6943 {
6945
6946 /*
6947 * This old multi cannot possibly have members still running, but
6948 * verify just in case. If it was a locker only, it can be removed
6949 * without any further consideration; but if it contained an update,
6950 * we might need to preserve it.
6951 */
6952 if (MultiXactIdIsRunning(multi,
6953 HEAP_XMAX_IS_LOCKED_ONLY(t_infomask)))
6954 ereport(ERROR,
6956 errmsg_internal("multixact %u from before multi freeze cutoff %u found to be still running",
6957 multi, cutoffs->OldestMxact)));
6958
6959 if (HEAP_XMAX_IS_LOCKED_ONLY(t_infomask))
6960 {
6961 *flags |= FRM_INVALIDATE_XMAX;
6962 pagefrz->freeze_required = true;
6963 return InvalidTransactionId;
6964 }
6965
6966 /* replace multi with single XID for its updater? */
6967 update_xact = MultiXactIdGetUpdateXid(multi, t_infomask);
6969 ereport(ERROR,
6971 errmsg_internal("multixact %u contains update XID %u from before relfrozenxid %u",
6972 multi, update_xact,
6973 cutoffs->relfrozenxid)));
6974 else if (TransactionIdPrecedes(update_xact, cutoffs->OldestXmin))
6975 {
6976 /*
6977 * Updater XID has to have aborted (otherwise the tuple would have
6978 * been pruned away instead, since updater XID is < OldestXmin).
6979 * Just remove xmax.
6980 */
6982 ereport(ERROR,
6984 errmsg_internal("multixact %u contains committed update XID %u from before removable cutoff %u",
6985 multi, update_xact,
6986 cutoffs->OldestXmin)));
6987 *flags |= FRM_INVALIDATE_XMAX;
6988 pagefrz->freeze_required = true;
6989 return InvalidTransactionId;
6990 }
6991
6992 /* Have to keep updater XID as new xmax */
6993 *flags |= FRM_RETURN_IS_XID;
6994 pagefrz->freeze_required = true;
6995 return update_xact;
6996 }
6997
6998 /*
6999 * Some member(s) of this Multi may be below FreezeLimit xid cutoff, so we
7000 * need to walk the whole members array to figure out what to do, if
7001 * anything.
7002 */
7003 nmembers =
7004 GetMultiXactIdMembers(multi, &members, false,
7005 HEAP_XMAX_IS_LOCKED_ONLY(t_infomask));
7006 if (nmembers <= 0)
7007 {
7008 /* Nothing worth keeping */
7009 *flags |= FRM_INVALIDATE_XMAX;
7010 pagefrz->freeze_required = true;
7011 return InvalidTransactionId;
7012 }
7013
7014 /*
7015 * The FRM_NOOP case is the only case where we might need to ratchet back
7016 * FreezePageRelfrozenXid or FreezePageRelminMxid. It is also the only
7017 * case where our caller might ratchet back its NoFreezePageRelfrozenXid
7018 * or NoFreezePageRelminMxid "no freeze" trackers to deal with a multi.
7019 * FRM_NOOP handling should result in the NewRelfrozenXid/NewRelminMxid
7020 * trackers managed by VACUUM being ratcheting back by xmax to the degree
7021 * required to make it safe to leave xmax undisturbed, independent of
7022 * whether or not page freezing is triggered somewhere else.
7023 *
7024 * Our policy is to force freezing in every case other than FRM_NOOP,
7025 * which obviates the need to maintain either set of trackers, anywhere.
7026 * Every other case will reliably execute a freeze plan for xmax that
7027 * either replaces xmax with an XID/MXID >= OldestXmin/OldestMxact, or
7028 * sets xmax to an InvalidTransactionId XID, rendering xmax fully frozen.
7029 * (VACUUM's NewRelfrozenXid/NewRelminMxid trackers are initialized with
7030 * OldestXmin/OldestMxact, so later values never need to be tracked here.)
7031 */
7032 need_replace = false;
7033 FreezePageRelfrozenXid = pagefrz->FreezePageRelfrozenXid;
7034 for (int i = 0; i < nmembers; i++)
7035 {
7036 TransactionId xid = members[i].xid;
7037
7038 Assert(!TransactionIdPrecedes(xid, cutoffs->relfrozenxid));
7039
7040 if (TransactionIdPrecedes(xid, cutoffs->FreezeLimit))
7041 {
7042 /* Can't violate the FreezeLimit postcondition */
7043 need_replace = true;
7044 break;
7045 }
7046 if (TransactionIdPrecedes(xid, FreezePageRelfrozenXid))
7047 FreezePageRelfrozenXid = xid;
7048 }
7049
7050 /* Can't violate the MultiXactCutoff postcondition, either */
7051 if (!need_replace)
7053
7054 if (!need_replace)
7055 {
7056 /*
7057 * vacuumlazy.c might ratchet back NewRelminMxid, NewRelfrozenXid, or
7058 * both together to make it safe to retain this particular multi after
7059 * freezing its page
7060 */
7061 *flags |= FRM_NOOP;
7062 pagefrz->FreezePageRelfrozenXid = FreezePageRelfrozenXid;
7063 if (MultiXactIdPrecedes(multi, pagefrz->FreezePageRelminMxid))
7064 pagefrz->FreezePageRelminMxid = multi;
7065 pfree(members);
7066 return multi;
7067 }
7068
7069 /*
7070 * Do a more thorough second pass over the multi to figure out which
7071 * member XIDs actually need to be kept. Checking the precise status of
7072 * individual members might even show that we don't need to keep anything.
7073 * That is quite possible even though the Multi must be >= OldestMxact,
7074 * since our second pass only keeps member XIDs when it's truly necessary;
7075 * even member XIDs >= OldestXmin often won't be kept by second pass.
7076 */
7077 nnewmembers = 0;
7079 has_lockers = false;
7081 update_committed = false;
7082
7083 /*
7084 * Determine whether to keep each member xid, or to ignore it instead
7085 */
7086 for (int i = 0; i < nmembers; i++)
7087 {
7088 TransactionId xid = members[i].xid;
7089 MultiXactStatus mstatus = members[i].status;
7090
7091 Assert(!TransactionIdPrecedes(xid, cutoffs->relfrozenxid));
7092
7093 if (!ISUPDATE_from_mxstatus(mstatus))
7094 {
7095 /*
7096 * Locker XID (not updater XID). We only keep lockers that are
7097 * still running.
7098 */
7101 {
7102 if (TransactionIdPrecedes(xid, cutoffs->OldestXmin))
7103 ereport(ERROR,
7105 errmsg_internal("multixact %u contains running locker XID %u from before removable cutoff %u",
7106 multi, xid,
7107 cutoffs->OldestXmin)));
7108 newmembers[nnewmembers++] = members[i];
7109 has_lockers = true;
7110 }
7111
7112 continue;
7113 }
7114
7115 /*
7116 * Updater XID (not locker XID). Should we keep it?
7117 *
7118 * Since the tuple wasn't totally removed when vacuum pruned, the
7119 * update Xid cannot possibly be older than OldestXmin cutoff unless
7120 * the updater XID aborted. If the updater transaction is known
7121 * aborted or crashed then it's okay to ignore it, otherwise not.
7122 *
7123 * In any case the Multi should never contain two updaters, whatever
7124 * their individual commit status. Check for that first, in passing.
7125 */
7127 ereport(ERROR,
7129 errmsg_internal("multixact %u has two or more updating members",
7130 multi),
7131 errdetail_internal("First updater XID=%u second updater XID=%u.",
7132 update_xid, xid)));
7133
7134 /*
7135 * As with all tuple visibility routines, it's critical to test
7136 * TransactionIdIsInProgress before TransactionIdDidCommit, because of
7137 * race conditions explained in detail in heapam_visibility.c.
7138 */
7141 update_xid = xid;
7142 else if (TransactionIdDidCommit(xid))
7143 {
7144 /*
7145 * The transaction committed, so we can tell caller to set
7146 * HEAP_XMAX_COMMITTED. (We can only do this because we know the
7147 * transaction is not running.)
7148 */
7149 update_committed = true;
7150 update_xid = xid;
7151 }
7152 else
7153 {
7154 /*
7155 * Not in progress, not committed -- must be aborted or crashed;
7156 * we can ignore it.
7157 */
7158 continue;
7159 }
7160
7161 /*
7162 * We determined that updater must be kept -- add it to pending new
7163 * members list
7164 */
7165 if (TransactionIdPrecedes(xid, cutoffs->OldestXmin))
7166 ereport(ERROR,
7168 errmsg_internal("multixact %u contains committed update XID %u from before removable cutoff %u",
7169 multi, xid, cutoffs->OldestXmin)));
7170 newmembers[nnewmembers++] = members[i];
7171 }
7172
7173 pfree(members);
7174
7175 /*
7176 * Determine what to do with caller's multi based on information gathered
7177 * during our second pass
7178 */
7179 if (nnewmembers == 0)
7180 {
7181 /* Nothing worth keeping */
7182 *flags |= FRM_INVALIDATE_XMAX;
7184 }
7186 {
7187 /*
7188 * If there's a single member and it's an update, pass it back alone
7189 * without creating a new Multi. (XXX we could do this when there's a
7190 * single remaining locker, too, but that would complicate the API too
7191 * much; moreover, the case with the single updater is more
7192 * interesting, because those are longer-lived.)
7193 */
7194 Assert(nnewmembers == 1);
7195 *flags |= FRM_RETURN_IS_XID;
7196 if (update_committed)
7197 *flags |= FRM_MARK_COMMITTED;
7199 }
7200 else
7201 {
7202 /*
7203 * Create a new multixact with the surviving members of the previous
7204 * one, to set as new Xmax in the tuple
7205 */
7207 *flags |= FRM_RETURN_IS_MULTI;
7208 }
7209
7211
7212 pagefrz->freeze_required = true;
7213 return newxmax;
7214}
7215
7216/*
7217 * heap_prepare_freeze_tuple
7218 *
7219 * Check to see whether any of the XID fields of a tuple (xmin, xmax, xvac)
7220 * are older than the OldestXmin and/or OldestMxact freeze cutoffs. If so,
7221 * setup enough state (in the *frz output argument) to enable caller to
7222 * process this tuple as part of freezing its page, and return true. Return
7223 * false if nothing can be changed about the tuple right now.
7224 *
7225 * FreezePageConflictXid is advanced only for xmin/xvac freezing, not for xmax
7226 * changes. We only remove xmax state here when it is lock-only, or when the
7227 * updater XID (including an updater member of a MultiXact) must be aborted;
7228 * otherwise, the tuple would already be removable. Neither case affects
7229 * visibility on a standby.
7230 *
7231 * Also sets *totally_frozen to true if the tuple will be totally frozen once
7232 * caller executes returned freeze plan (or if the tuple was already totally
7233 * frozen by an earlier VACUUM). This indicates that there are no remaining
7234 * XIDs or MultiXactIds that will need to be processed by a future VACUUM.
7235 *
7236 * VACUUM caller must assemble HeapTupleFreeze freeze plan entries for every
7237 * tuple that we returned true for, and then execute freezing. Caller must
7238 * initialize pagefrz fields for page as a whole before first call here for
7239 * each heap page.
7240 *
7241 * VACUUM caller decides on whether or not to freeze the page as a whole.
7242 * We'll often prepare freeze plans for a page that caller just discards.
7243 * However, VACUUM doesn't always get to make a choice; it must freeze when
7244 * pagefrz.freeze_required is set, to ensure that any XIDs < FreezeLimit (and
7245 * MXIDs < MultiXactCutoff) can never be left behind. We help to make sure
7246 * that VACUUM always follows that rule.
7247 *
7248 * We sometimes force freezing of xmax MultiXactId values long before it is
7249 * strictly necessary to do so just to ensure the FreezeLimit postcondition.
7250 * It's worth processing MultiXactIds proactively when it is cheap to do so,
7251 * and it's convenient to make that happen by piggy-backing it on the "force
7252 * freezing" mechanism. Conversely, we sometimes delay freezing MultiXactIds
7253 * because it is expensive right now (though only when it's still possible to
7254 * do so without violating the FreezeLimit/MultiXactCutoff postcondition).
7255 *
7256 * It is assumed that the caller has checked the tuple with
7257 * HeapTupleSatisfiesVacuum() and determined that it is not HEAPTUPLE_DEAD
7258 * (else we should be removing the tuple, not freezing it).
7259 *
7260 * NB: This function has side effects: it might allocate a new MultiXactId.
7261 * It will be set as tuple's new xmax when our *frz output is processed within
7262 * heap_execute_freeze_tuple later on. If the tuple is in a shared buffer
7263 * then caller had better have an exclusive lock on it already.
7264 */
7265bool
7267 const struct VacuumCutoffs *cutoffs,
7268 HeapPageFreeze *pagefrz,
7270{
7271 bool xmin_already_frozen = false,
7272 xmax_already_frozen = false;
7273 bool freeze_xmin = false,
7274 replace_xvac = false,
7275 replace_xmax = false,
7276 freeze_xmax = false;
7277 TransactionId xid;
7278
7279 frz->xmax = HeapTupleHeaderGetRawXmax(tuple);
7280 frz->t_infomask2 = tuple->t_infomask2;
7281 frz->t_infomask = tuple->t_infomask;
7282 frz->frzflags = 0;
7283 frz->checkflags = 0;
7284
7285 /*
7286 * Process xmin, while keeping track of whether it's already frozen, or
7287 * will become frozen iff our freeze plan is executed by caller (could be
7288 * neither).
7289 */
7290 xid = HeapTupleHeaderGetXmin(tuple);
7291 if (!TransactionIdIsNormal(xid))
7292 xmin_already_frozen = true;
7293 else
7294 {
7295 if (TransactionIdPrecedes(xid, cutoffs->relfrozenxid))
7296 ereport(ERROR,
7298 errmsg_internal("found xmin %u from before relfrozenxid %u",
7299 xid, cutoffs->relfrozenxid)));
7300
7301 /* Will set freeze_xmin flags in freeze plan below */
7303
7304 /* Verify that xmin committed if and when freeze plan is executed */
7305 if (freeze_xmin)
7306 {
7309 pagefrz->FreezePageConflictXid = xid;
7310 }
7311 }
7312
7313 /*
7314 * Old-style VACUUM FULL is gone, but we have to process xvac for as long
7315 * as we support having MOVED_OFF/MOVED_IN tuples in the database
7316 */
7317 xid = HeapTupleHeaderGetXvac(tuple);
7318 if (TransactionIdIsNormal(xid))
7319 {
7321 Assert(TransactionIdPrecedes(xid, cutoffs->OldestXmin));
7322
7323 /*
7324 * For Xvac, we always freeze proactively. This allows totally_frozen
7325 * tracking to ignore xvac.
7326 */
7327 replace_xvac = pagefrz->freeze_required = true;
7328
7330 pagefrz->FreezePageConflictXid = xid;
7331
7332 /* Will set replace_xvac flags in freeze plan below */
7333 }
7334
7335 /* Now process xmax */
7336 xid = frz->xmax;
7337 if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
7338 {
7339 /* Raw xmax is a MultiXactId */
7341 uint16 flags;
7342
7343 /*
7344 * We will either remove xmax completely (in the "freeze_xmax" path),
7345 * process xmax by replacing it (in the "replace_xmax" path), or
7346 * perform no-op xmax processing. The only constraint is that the
7347 * FreezeLimit/MultiXactCutoff postcondition must never be violated.
7348 */
7349 newxmax = FreezeMultiXactId(xid, tuple->t_infomask, cutoffs,
7350 &flags, pagefrz);
7351
7352 if (flags & FRM_NOOP)
7353 {
7354 /*
7355 * xmax is a MultiXactId, and nothing about it changes for now.
7356 * This is the only case where 'freeze_required' won't have been
7357 * set for us by FreezeMultiXactId, as well as the only case where
7358 * neither freeze_xmax nor replace_xmax are set (given a multi).
7359 *
7360 * This is a no-op, but the call to FreezeMultiXactId might have
7361 * ratcheted back NewRelfrozenXid and/or NewRelminMxid trackers
7362 * for us (the "freeze page" variants, specifically). That'll
7363 * make it safe for our caller to freeze the page later on, while
7364 * leaving this particular xmax undisturbed.
7365 *
7366 * FreezeMultiXactId is _not_ responsible for the "no freeze"
7367 * NewRelfrozenXid/NewRelminMxid trackers, though -- that's our
7368 * job. A call to heap_tuple_should_freeze for this same tuple
7369 * will take place below if 'freeze_required' isn't set already.
7370 * (This repeats work from FreezeMultiXactId, but allows "no
7371 * freeze" tracker maintenance to happen in only one place.)
7372 */
7375 }
7376 else if (flags & FRM_RETURN_IS_XID)
7377 {
7378 /*
7379 * xmax will become an updater Xid (original MultiXact's updater
7380 * member Xid will be carried forward as a simple Xid in Xmax).
7381 */
7383
7384 /*
7385 * NB -- some of these transformations are only valid because we
7386 * know the return Xid is a tuple updater (i.e. not merely a
7387 * locker.) Also note that the only reason we don't explicitly
7388 * worry about HEAP_KEYS_UPDATED is because it lives in
7389 * t_infomask2 rather than t_infomask.
7390 */
7391 frz->t_infomask &= ~HEAP_XMAX_BITS;
7392 frz->xmax = newxmax;
7393 if (flags & FRM_MARK_COMMITTED)
7394 frz->t_infomask |= HEAP_XMAX_COMMITTED;
7395 replace_xmax = true;
7396 }
7397 else if (flags & FRM_RETURN_IS_MULTI)
7398 {
7401
7402 /*
7403 * xmax is an old MultiXactId that we have to replace with a new
7404 * MultiXactId, to carry forward two or more original member XIDs.
7405 */
7407
7408 /*
7409 * We can't use GetMultiXactIdHintBits directly on the new multi
7410 * here; that routine initializes the masks to all zeroes, which
7411 * would lose other bits we need. Doing it this way ensures all
7412 * unrelated bits remain untouched.
7413 */
7414 frz->t_infomask &= ~HEAP_XMAX_BITS;
7415 frz->t_infomask2 &= ~HEAP_KEYS_UPDATED;
7417 frz->t_infomask |= newbits;
7418 frz->t_infomask2 |= newbits2;
7419 frz->xmax = newxmax;
7420 replace_xmax = true;
7421 }
7422 else
7423 {
7424 /*
7425 * Freeze plan for tuple "freezes xmax" in the strictest sense:
7426 * it'll leave nothing in xmax (neither an Xid nor a MultiXactId).
7427 */
7428 Assert(flags & FRM_INVALIDATE_XMAX);
7430
7431 /* Will set freeze_xmax flags in freeze plan below */
7432 freeze_xmax = true;
7433 }
7434
7435 /* MultiXactId processing forces freezing (barring FRM_NOOP case) */
7436 Assert(pagefrz->freeze_required || (!freeze_xmax && !replace_xmax));
7437 }
7438 else if (TransactionIdIsNormal(xid))
7439 {
7440 /* Raw xmax is normal XID */
7441 if (TransactionIdPrecedes(xid, cutoffs->relfrozenxid))
7442 ereport(ERROR,
7444 errmsg_internal("found xmax %u from before relfrozenxid %u",
7445 xid, cutoffs->relfrozenxid)));
7446
7447 /* Will set freeze_xmax flags in freeze plan below */
7449
7450 /*
7451 * Verify that xmax aborted if and when freeze plan is executed,
7452 * provided it's from an update. (A lock-only xmax can be removed
7453 * independent of this, since the lock is released at xact end.)
7454 */
7456 frz->checkflags |= HEAP_FREEZE_CHECK_XMAX_ABORTED;
7457 }
7458 else if (!TransactionIdIsValid(xid))
7459 {
7460 /* Raw xmax is InvalidTransactionId XID */
7461 Assert((tuple->t_infomask & HEAP_XMAX_IS_MULTI) == 0);
7462 xmax_already_frozen = true;
7463 }
7464 else
7465 ereport(ERROR,
7467 errmsg_internal("found raw xmax %u (infomask 0x%04x) not invalid and not multi",
7468 xid, tuple->t_infomask)));
7469
7470 if (freeze_xmin)
7471 {
7473
7474 frz->t_infomask |= HEAP_XMIN_FROZEN;
7475 }
7476 if (replace_xvac)
7477 {
7478 /*
7479 * If a MOVED_OFF tuple is not dead, the xvac transaction must have
7480 * failed; whereas a non-dead MOVED_IN tuple must mean the xvac
7481 * transaction succeeded.
7482 */
7483 Assert(pagefrz->freeze_required);
7484 if (tuple->t_infomask & HEAP_MOVED_OFF)
7485 frz->frzflags |= XLH_INVALID_XVAC;
7486 else
7487 frz->frzflags |= XLH_FREEZE_XVAC;
7488 }
7489 if (replace_xmax)
7490 {
7492 Assert(pagefrz->freeze_required);
7493
7494 /* Already set replace_xmax flags in freeze plan earlier */
7495 }
7496 if (freeze_xmax)
7497 {
7499
7500 frz->xmax = InvalidTransactionId;
7501
7502 /*
7503 * The tuple might be marked either XMAX_INVALID or XMAX_COMMITTED +
7504 * LOCKED. Normalize to INVALID just to be sure no one gets confused.
7505 * Also get rid of the HEAP_KEYS_UPDATED bit.
7506 */
7507 frz->t_infomask &= ~HEAP_XMAX_BITS;
7508 frz->t_infomask |= HEAP_XMAX_INVALID;
7509 frz->t_infomask2 &= ~HEAP_HOT_UPDATED;
7510 frz->t_infomask2 &= ~HEAP_KEYS_UPDATED;
7511 }
7512
7513 /*
7514 * Determine if this tuple is already totally frozen, or will become
7515 * totally frozen (provided caller executes freeze plans for the page)
7516 */
7519
7520 if (!pagefrz->freeze_required && !(xmin_already_frozen &&
7522 {
7523 /*
7524 * So far no previous tuple from the page made freezing mandatory.
7525 * Does this tuple force caller to freeze the entire page?
7526 */
7527 pagefrz->freeze_required =
7528 heap_tuple_should_freeze(tuple, cutoffs,
7529 &pagefrz->NoFreezePageRelfrozenXid,
7530 &pagefrz->NoFreezePageRelminMxid);
7531 }
7532
7533 /* Tell caller if this tuple has a usable freeze plan set in *frz */
7535}
7536
7537/*
7538 * Perform xmin/xmax XID status sanity checks before actually executing freeze
7539 * plans.
7540 *
7541 * heap_prepare_freeze_tuple doesn't perform these checks directly because
7542 * pg_xact lookups are relatively expensive. They shouldn't be repeated by
7543 * successive VACUUMs that each decide against freezing the same page.
7544 */
7545void
7547 HeapTupleFreeze *tuples, int ntuples)
7548{
7549 Page page = BufferGetPage(buffer);
7550
7551 for (int i = 0; i < ntuples; i++)
7552 {
7553 HeapTupleFreeze *frz = tuples + i;
7554 ItemId itemid = PageGetItemId(page, frz->offset);
7555 HeapTupleHeader htup;
7556
7557 htup = (HeapTupleHeader) PageGetItem(page, itemid);
7558
7559 /* Deliberately avoid relying on tuple hint bits here */
7560 if (frz->checkflags & HEAP_FREEZE_CHECK_XMIN_COMMITTED)
7561 {
7563
7565 if (unlikely(!TransactionIdDidCommit(xmin)))
7566 ereport(ERROR,
7568 errmsg_internal("uncommitted xmin %u needs to be frozen",
7569 xmin)));
7570 }
7571
7572 /*
7573 * TransactionIdDidAbort won't work reliably in the presence of XIDs
7574 * left behind by transactions that were in progress during a crash,
7575 * so we can only check that xmax didn't commit
7576 */
7577 if (frz->checkflags & HEAP_FREEZE_CHECK_XMAX_ABORTED)
7578 {
7580
7583 ereport(ERROR,
7585 errmsg_internal("cannot freeze committed xmax %u",
7586 xmax)));
7587 }
7588 }
7589}
7590
7591/*
7592 * Helper which executes freezing of one or more heap tuples on a page on
7593 * behalf of caller. Caller passes an array of tuple plans from
7594 * heap_prepare_freeze_tuple. Caller must set 'offset' in each plan for us.
7595 * Must be called in a critical section that also marks the buffer dirty and,
7596 * if needed, emits WAL.
7597 */
7598void
7599heap_freeze_prepared_tuples(Buffer buffer, HeapTupleFreeze *tuples, int ntuples)
7600{
7601 Page page = BufferGetPage(buffer);
7602
7603 for (int i = 0; i < ntuples; i++)
7604 {
7605 HeapTupleFreeze *frz = tuples + i;
7606 ItemId itemid = PageGetItemId(page, frz->offset);
7607 HeapTupleHeader htup;
7608
7609 htup = (HeapTupleHeader) PageGetItem(page, itemid);
7611 }
7612}
7613
7614/*
7615 * heap_freeze_tuple
7616 * Freeze tuple in place, without WAL logging.
7617 *
7618 * Useful for callers like CLUSTER that perform their own WAL logging.
7619 */
7620bool
7622 TransactionId relfrozenxid, TransactionId relminmxid,
7623 TransactionId FreezeLimit, TransactionId MultiXactCutoff)
7624{
7626 bool do_freeze;
7627 bool totally_frozen;
7628 struct VacuumCutoffs cutoffs;
7629 HeapPageFreeze pagefrz;
7630
7631 cutoffs.relfrozenxid = relfrozenxid;
7632 cutoffs.relminmxid = relminmxid;
7633 cutoffs.OldestXmin = FreezeLimit;
7634 cutoffs.OldestMxact = MultiXactCutoff;
7635 cutoffs.FreezeLimit = FreezeLimit;
7637
7638 pagefrz.freeze_required = true;
7639 pagefrz.FreezePageRelfrozenXid = FreezeLimit;
7640 pagefrz.FreezePageRelminMxid = MultiXactCutoff;
7641 pagefrz.FreezePageConflictXid = InvalidTransactionId;
7642 pagefrz.NoFreezePageRelfrozenXid = FreezeLimit;
7643 pagefrz.NoFreezePageRelminMxid = MultiXactCutoff;
7644
7645 do_freeze = heap_prepare_freeze_tuple(tuple, &cutoffs,
7646 &pagefrz, &frz, &totally_frozen);
7647
7648 /*
7649 * Note that because this is not a WAL-logged operation, we don't need to
7650 * fill in the offset in the freeze record.
7651 */
7652
7653 if (do_freeze)
7655 return do_freeze;
7656}
7657
7658/*
7659 * For a given MultiXactId, return the hint bits that should be set in the
7660 * tuple's infomask.
7661 *
7662 * Normally this should be called for a multixact that was just created, and
7663 * so is on our local cache, so the GetMembers call is fast.
7664 */
7665static void
7668{
7669 int nmembers;
7670 MultiXactMember *members;
7671 int i;
7673 uint16 bits2 = 0;
7674 bool has_update = false;
7676
7677 /*
7678 * We only use this in multis we just created, so they cannot be values
7679 * pre-pg_upgrade.
7680 */
7681 nmembers = GetMultiXactIdMembers(multi, &members, false, false);
7682
7683 for (i = 0; i < nmembers; i++)
7684 {
7686
7687 /*
7688 * Remember the strongest lock mode held by any member of the
7689 * multixact.
7690 */
7691 mode = TUPLOCK_from_mxstatus(members[i].status);
7692 if (mode > strongest)
7693 strongest = mode;
7694
7695 /* See what other bits we need */
7696 switch (members[i].status)
7697 {
7701 break;
7702
7705 break;
7706
7708 has_update = true;
7709 break;
7710
7713 has_update = true;
7714 break;
7715 }
7716 }
7717
7720 bits |= HEAP_XMAX_EXCL_LOCK;
7721 else if (strongest == LockTupleShare)
7722 bits |= HEAP_XMAX_SHR_LOCK;
7723 else if (strongest == LockTupleKeyShare)
7724 bits |= HEAP_XMAX_KEYSHR_LOCK;
7725
7726 if (!has_update)
7727 bits |= HEAP_XMAX_LOCK_ONLY;
7728
7729 if (nmembers > 0)
7730 pfree(members);
7731
7732 *new_infomask = bits;
7734}
7735
7736/*
7737 * MultiXactIdGetUpdateXid
7738 *
7739 * Given a multixact Xmax and corresponding infomask, which does not have the
7740 * HEAP_XMAX_LOCK_ONLY bit set, obtain and return the Xid of the updating
7741 * transaction.
7742 *
7743 * Caller is expected to check the status of the updating transaction, if
7744 * necessary.
7745 */
7746static TransactionId
7748{
7750 MultiXactMember *members;
7751 int nmembers;
7752
7753 Assert(!(t_infomask & HEAP_XMAX_LOCK_ONLY));
7754 Assert(t_infomask & HEAP_XMAX_IS_MULTI);
7755
7756 /*
7757 * Since we know the LOCK_ONLY bit is not set, this cannot be a multi from
7758 * pre-pg_upgrade.
7759 */
7760 nmembers = GetMultiXactIdMembers(xmax, &members, false, false);
7761
7762 if (nmembers > 0)
7763 {
7764 int i;
7765
7766 for (i = 0; i < nmembers; i++)
7767 {
7768 /* Ignore lockers */
7769 if (!ISUPDATE_from_mxstatus(members[i].status))
7770 continue;
7771
7772 /* there can be at most one updater */
7774 update_xact = members[i].xid;
7775#ifndef USE_ASSERT_CHECKING
7776
7777 /*
7778 * in an assert-enabled build, walk the whole array to ensure
7779 * there's no other updater.
7780 */
7781 break;
7782#endif
7783 }
7784
7785 pfree(members);
7786 }
7787
7788 return update_xact;
7789}
7790
7791/*
7792 * HeapTupleGetUpdateXid
7793 * As above, but use a HeapTupleHeader
7794 *
7795 * See also HeapTupleHeaderGetUpdateXid, which can be used without previously
7796 * checking the hint bits.
7797 */
7800{
7802 tup->t_infomask);
7803}
7804
7805/*
7806 * Does the given multixact conflict with the current transaction grabbing a
7807 * tuple lock of the given strength?
7808 *
7809 * The passed infomask pairs up with the given multixact in the tuple header.
7810 *
7811 * If current_is_member is not NULL, it is set to 'true' if the current
7812 * transaction is a member of the given multixact.
7813 */
7814static bool
7816 LockTupleMode lockmode, bool *current_is_member)
7817{
7818 int nmembers;
7819 MultiXactMember *members;
7820 bool result = false;
7821 LOCKMODE wanted = tupleLockExtraInfo[lockmode].hwlock;
7822
7824 return false;
7825
7826 nmembers = GetMultiXactIdMembers(multi, &members, false,
7828 if (nmembers >= 0)
7829 {
7830 int i;
7831
7832 for (i = 0; i < nmembers; i++)
7833 {
7836
7838 break;
7839
7840 memlockmode = LOCKMODE_from_mxstatus(members[i].status);
7841
7842 /* ignore members from current xact (but track their presence) */
7843 memxid = members[i].xid;
7845 {
7846 if (current_is_member != NULL)
7847 *current_is_member = true;
7848 continue;
7849 }
7850 else if (result)
7851 continue;
7852
7853 /* ignore members that don't conflict with the lock we want */
7855 continue;
7856
7857 if (ISUPDATE_from_mxstatus(members[i].status))
7858 {
7859 /* ignore aborted updaters */
7861 continue;
7862 }
7863 else
7864 {
7865 /* ignore lockers-only that are no longer in progress */
7867 continue;
7868 }
7869
7870 /*
7871 * Whatever remains are either live lockers that conflict with our
7872 * wanted lock, and updaters that are not aborted. Those conflict
7873 * with what we want. Set up to return true, but keep going to
7874 * look for the current transaction among the multixact members,
7875 * if needed.
7876 */
7877 result = true;
7878 }
7879 pfree(members);
7880 }
7881
7882 return result;
7883}
7884
7885/*
7886 * Do_MultiXactIdWait
7887 * Actual implementation for the two functions below.
7888 *
7889 * 'multi', 'status' and 'infomask' indicate what to sleep on (the status is
7890 * needed to ensure we only sleep on conflicting members, and the infomask is
7891 * used to optimize multixact access in case it's a lock-only multi); 'nowait'
7892 * indicates whether to use conditional lock acquisition, to allow callers to
7893 * fail if lock is unavailable. 'rel', 'ctid' and 'oper' are used to set up
7894 * context information for error messages. 'remaining', if not NULL, receives
7895 * the number of members that are still running, including any (non-aborted)
7896 * subtransactions of our own transaction. 'logLockFailure' indicates whether
7897 * to log details when a lock acquisition fails with 'nowait' enabled.
7898 *
7899 * We do this by sleeping on each member using XactLockTableWait. Any
7900 * members that belong to the current backend are *not* waited for, however;
7901 * this would not merely be useless but would lead to Assert failure inside
7902 * XactLockTableWait. By the time this returns, it is certain that all
7903 * transactions *of other backends* that were members of the MultiXactId
7904 * that conflict with the requested status are dead (and no new ones can have
7905 * been added, since it is not legal to add members to an existing
7906 * MultiXactId).
7907 *
7908 * But by the time we finish sleeping, someone else may have changed the Xmax
7909 * of the containing tuple, so the caller needs to iterate on us somehow.
7910 *
7911 * Note that in case we return false, the number of remaining members is
7912 * not to be trusted.
7913 */
7914static bool
7916 uint16 infomask, bool nowait,
7917 Relation rel, const ItemPointerData *ctid, XLTW_Oper oper,
7918 int *remaining, bool logLockFailure)
7919{
7920 bool result = true;
7921 MultiXactMember *members;
7922 int nmembers;
7923 int remain = 0;
7924
7925 /* for pre-pg_upgrade tuples, no need to sleep at all */
7926 nmembers = HEAP_LOCKED_UPGRADED(infomask) ? -1 :
7927 GetMultiXactIdMembers(multi, &members, false,
7929
7930 if (nmembers >= 0)
7931 {
7932 int i;
7933
7934 for (i = 0; i < nmembers; i++)
7935 {
7936 TransactionId memxid = members[i].xid;
7937 MultiXactStatus memstatus = members[i].status;
7938
7940 {
7941 remain++;
7942 continue;
7943 }
7944
7946 LOCKMODE_from_mxstatus(status)))
7947 {
7949 remain++;
7950 continue;
7951 }
7952
7953 /*
7954 * This member conflicts with our multi, so we have to sleep (or
7955 * return failure, if asked to avoid waiting.)
7956 *
7957 * Note that we don't set up an error context callback ourselves,
7958 * but instead we pass the info down to XactLockTableWait. This
7959 * might seem a bit wasteful because the context is set up and
7960 * tore down for each member of the multixact, but in reality it
7961 * should be barely noticeable, and it avoids duplicate code.
7962 */
7963 if (nowait)
7964 {
7966 if (!result)
7967 break;
7968 }
7969 else
7970 XactLockTableWait(memxid, rel, ctid, oper);
7971 }
7972
7973 pfree(members);
7974 }
7975
7976 if (remaining)
7977 *remaining = remain;
7978
7979 return result;
7980}
7981
7982/*
7983 * MultiXactIdWait
7984 * Sleep on a MultiXactId.
7985 *
7986 * By the time we finish sleeping, someone else may have changed the Xmax
7987 * of the containing tuple, so the caller needs to iterate on us somehow.
7988 *
7989 * We return (in *remaining, if not NULL) the number of members that are still
7990 * running, including any (non-aborted) subtransactions of our own transaction.
7991 */
7992static void
7994 Relation rel, const ItemPointerData *ctid, XLTW_Oper oper,
7995 int *remaining)
7996{
7997 (void) Do_MultiXactIdWait(multi, status, infomask, false,
7998 rel, ctid, oper, remaining, false);
7999}
8000
8001/*
8002 * ConditionalMultiXactIdWait
8003 * As above, but only lock if we can get the lock without blocking.
8004 *
8005 * By the time we finish sleeping, someone else may have changed the Xmax
8006 * of the containing tuple, so the caller needs to iterate on us somehow.
8007 *
8008 * If the multixact is now all gone, return true. Returns false if some
8009 * transactions might still be running.
8010 *
8011 * We return (in *remaining, if not NULL) the number of members that are still
8012 * running, including any (non-aborted) subtransactions of our own transaction.
8013 */
8014static bool
8016 uint16 infomask, Relation rel, int *remaining,
8017 bool logLockFailure)
8018{
8019 return Do_MultiXactIdWait(multi, status, infomask, true,
8021}
8022
8023/*
8024 * heap_tuple_needs_eventual_freeze
8025 *
8026 * Check to see whether any of the XID fields of a tuple (xmin, xmax, xvac)
8027 * will eventually require freezing (if tuple isn't removed by pruning first).
8028 */
8029bool
8031{
8032 TransactionId xid;
8033
8034 /*
8035 * If xmin is a normal transaction ID, this tuple is definitely not
8036 * frozen.
8037 */
8038 xid = HeapTupleHeaderGetXmin(tuple);
8039 if (TransactionIdIsNormal(xid))
8040 return true;
8041
8042 /*
8043 * If xmax is a valid xact or multixact, this tuple is also not frozen.
8044 */
8045 if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
8046 {
8047 MultiXactId multi;
8048
8049 multi = HeapTupleHeaderGetRawXmax(tuple);
8050 if (MultiXactIdIsValid(multi))
8051 return true;
8052 }
8053 else
8054 {
8055 xid = HeapTupleHeaderGetRawXmax(tuple);
8056 if (TransactionIdIsNormal(xid))
8057 return true;
8058 }
8059
8060 if (tuple->t_infomask & HEAP_MOVED)
8061 {
8062 xid = HeapTupleHeaderGetXvac(tuple);
8063 if (TransactionIdIsNormal(xid))
8064 return true;
8065 }
8066
8067 return false;
8068}
8069
8070/*
8071 * heap_tuple_should_freeze
8072 *
8073 * Return value indicates if heap_prepare_freeze_tuple sibling function would
8074 * (or should) force freezing of the heap page that contains caller's tuple.
8075 * Tuple header XIDs/MXIDs < FreezeLimit/MultiXactCutoff trigger freezing.
8076 * This includes (xmin, xmax, xvac) fields, as well as MultiXact member XIDs.
8077 *
8078 * The *NoFreezePageRelfrozenXid and *NoFreezePageRelminMxid input/output
8079 * arguments help VACUUM track the oldest extant XID/MXID remaining in rel.
8080 * Our working assumption is that caller won't decide to freeze this tuple.
8081 * It's up to caller to only ratchet back its own top-level trackers after the
8082 * point that it fully commits to not freezing the tuple/page in question.
8083 */
8084bool
8086 const struct VacuumCutoffs *cutoffs,
8087 TransactionId *NoFreezePageRelfrozenXid,
8088 MultiXactId *NoFreezePageRelminMxid)
8089{
8090 TransactionId xid;
8091 MultiXactId multi;
8092 bool freeze = false;
8093
8094 /* First deal with xmin */
8095 xid = HeapTupleHeaderGetXmin(tuple);
8096 if (TransactionIdIsNormal(xid))
8097 {
8099 if (TransactionIdPrecedes(xid, *NoFreezePageRelfrozenXid))
8100 *NoFreezePageRelfrozenXid = xid;
8101 if (TransactionIdPrecedes(xid, cutoffs->FreezeLimit))
8102 freeze = true;
8103 }
8104
8105 /* Now deal with xmax */
8107 multi = InvalidMultiXactId;
8108 if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
8109 multi = HeapTupleHeaderGetRawXmax(tuple);
8110 else
8111 xid = HeapTupleHeaderGetRawXmax(tuple);
8112
8113 if (TransactionIdIsNormal(xid))
8114 {
8116 /* xmax is a non-permanent XID */
8117 if (TransactionIdPrecedes(xid, *NoFreezePageRelfrozenXid))
8118 *NoFreezePageRelfrozenXid = xid;
8119 if (TransactionIdPrecedes(xid, cutoffs->FreezeLimit))
8120 freeze = true;
8121 }
8122 else if (!MultiXactIdIsValid(multi))
8123 {
8124 /* xmax is a permanent XID or invalid MultiXactId/XID */
8125 }
8126 else if (HEAP_LOCKED_UPGRADED(tuple->t_infomask))
8127 {
8128 /* xmax is a pg_upgrade'd MultiXact, which can't have updater XID */
8129 if (MultiXactIdPrecedes(multi, *NoFreezePageRelminMxid))
8130 *NoFreezePageRelminMxid = multi;
8131 /* heap_prepare_freeze_tuple always freezes pg_upgrade'd xmax */
8132 freeze = true;
8133 }
8134 else
8135 {
8136 /* xmax is a MultiXactId that may have an updater XID */
8137 MultiXactMember *members;
8138 int nmembers;
8139
8141 if (MultiXactIdPrecedes(multi, *NoFreezePageRelminMxid))
8142 *NoFreezePageRelminMxid = multi;
8143 if (MultiXactIdPrecedes(multi, cutoffs->MultiXactCutoff))
8144 freeze = true;
8145
8146 /* need to check whether any member of the mxact is old */
8147 nmembers = GetMultiXactIdMembers(multi, &members, false,
8149
8150 for (int i = 0; i < nmembers; i++)
8151 {
8152 xid = members[i].xid;
8154 if (TransactionIdPrecedes(xid, *NoFreezePageRelfrozenXid))
8155 *NoFreezePageRelfrozenXid = xid;
8156 if (TransactionIdPrecedes(xid, cutoffs->FreezeLimit))
8157 freeze = true;
8158 }
8159 if (nmembers > 0)
8160 pfree(members);
8161 }
8162
8163 if (tuple->t_infomask & HEAP_MOVED)
8164 {
8165 xid = HeapTupleHeaderGetXvac(tuple);
8166 if (TransactionIdIsNormal(xid))
8167 {
8169 if (TransactionIdPrecedes(xid, *NoFreezePageRelfrozenXid))
8170 *NoFreezePageRelfrozenXid = xid;
8171 /* heap_prepare_freeze_tuple forces xvac freezing */
8172 freeze = true;
8173 }
8174 }
8175
8176 return freeze;
8177}
8178
8179/*
8180 * Maintain snapshotConflictHorizon for caller by ratcheting forward its value
8181 * using any committed XIDs contained in 'tuple', an obsolescent heap tuple
8182 * that caller is in the process of physically removing, e.g. via HOT pruning
8183 * or index deletion.
8184 *
8185 * Caller must initialize its value to InvalidTransactionId, which is
8186 * generally interpreted as "definitely no need for a recovery conflict".
8187 * Final value must reflect all heap tuples that caller will physically remove
8188 * (or remove TID references to) via its ongoing pruning/deletion operation.
8189 * ResolveRecoveryConflictWithSnapshot() is passed the final value (taken from
8190 * caller's WAL record) by REDO routine when it replays caller's operation.
8191 */
8192void
8194 TransactionId *snapshotConflictHorizon)
8195{
8199
8200 if (tuple->t_infomask & HEAP_MOVED)
8201 {
8202 if (TransactionIdPrecedes(*snapshotConflictHorizon, xvac))
8203 *snapshotConflictHorizon = xvac;
8204 }
8205
8206 /*
8207 * Ignore tuples inserted by an aborted transaction or if the tuple was
8208 * updated/deleted by the inserting transaction.
8209 *
8210 * Look for a committed hint bit, or if no xmin bit is set, check clog.
8211 */
8212 if (HeapTupleHeaderXminCommitted(tuple) ||
8214 {
8215 if (xmax != xmin &&
8216 TransactionIdFollows(xmax, *snapshotConflictHorizon))
8217 *snapshotConflictHorizon = xmax;
8218 }
8219}
8220
8221#ifdef USE_PREFETCH
8222/*
8223 * Helper function for heap_index_delete_tuples. Issues prefetch requests for
8224 * prefetch_count buffers. The prefetch_state keeps track of all the buffers
8225 * we can prefetch, and which have already been prefetched; each call to this
8226 * function picks up where the previous call left off.
8227 *
8228 * Note: we expect the deltids array to be sorted in an order that groups TIDs
8229 * by heap block, with all TIDs for each block appearing together in exactly
8230 * one group.
8231 */
8232static void
8235 int prefetch_count)
8236{
8238 int count = 0;
8239 int i;
8240 int ndeltids = prefetch_state->ndeltids;
8241 TM_IndexDelete *deltids = prefetch_state->deltids;
8242
8243 for (i = prefetch_state->next_item;
8244 i < ndeltids && count < prefetch_count;
8245 i++)
8246 {
8247 ItemPointer htid = &deltids[i].tid;
8248
8251 {
8254 count++;
8255 }
8256 }
8257
8258 /*
8259 * Save the prefetch position so that next time we can continue from that
8260 * position.
8261 */
8262 prefetch_state->next_item = i;
8263 prefetch_state->cur_hblkno = cur_hblkno;
8264}
8265#endif
8266
8267/*
8268 * Helper function for heap_index_delete_tuples. Checks for index corruption
8269 * involving an invalid TID in index AM caller's index page.
8270 *
8271 * This is an ideal place for these checks. The index AM must hold a buffer
8272 * lock on the index page containing the TIDs we examine here, so we don't
8273 * have to worry about concurrent VACUUMs at all. We can be sure that the
8274 * index is corrupt when htid points directly to an LP_UNUSED item or
8275 * heap-only tuple, which is not the case during standard index scans.
8276 */
8277static inline void
8279 Page page, OffsetNumber maxoff,
8281{
8283 ItemId iid;
8284
8285 Assert(OffsetNumberIsValid(istatus->idxoffnum));
8286
8287 if (unlikely(indexpagehoffnum > maxoff))
8288 ereport(ERROR,
8290 errmsg_internal("heap tid from index tuple (%u,%u) points past end of heap page line pointer array at offset %u of block %u in index \"%s\"",
8293 istatus->idxoffnum, delstate->iblknum,
8295
8297 if (unlikely(!ItemIdIsUsed(iid)))
8298 ereport(ERROR,
8300 errmsg_internal("heap tid from index tuple (%u,%u) points to unused heap page item at offset %u of block %u in index \"%s\"",
8303 istatus->idxoffnum, delstate->iblknum,
8305
8306 if (ItemIdHasStorage(iid))
8307 {
8308 HeapTupleHeader htup;
8309
8311 htup = (HeapTupleHeader) PageGetItem(page, iid);
8312
8314 ereport(ERROR,
8316 errmsg_internal("heap tid from index tuple (%u,%u) points to heap-only tuple at offset %u of block %u in index \"%s\"",
8319 istatus->idxoffnum, delstate->iblknum,
8321 }
8322}
8323
8324/*
8325 * heapam implementation of tableam's index_delete_tuples interface.
8326 *
8327 * This helper function is called by index AMs during index tuple deletion.
8328 * See tableam header comments for an explanation of the interface implemented
8329 * here and a general theory of operation. Note that each call here is either
8330 * a simple index deletion call, or a bottom-up index deletion call.
8331 *
8332 * It's possible for this to generate a fair amount of I/O, since we may be
8333 * deleting hundreds of tuples from a single index block. To amortize that
8334 * cost to some degree, this uses prefetching and combines repeat accesses to
8335 * the same heap block.
8336 */
8339{
8340 /* Initial assumption is that earlier pruning took care of conflict */
8341 TransactionId snapshotConflictHorizon = InvalidTransactionId;
8344 Page page = NULL;
8347#ifdef USE_PREFETCH
8350#endif
8352 int finalndeltids = 0,
8353 nblocksaccessed = 0;
8354
8355 /* State that's only used in bottom-up index deletion case */
8356 int nblocksfavorable = 0;
8357 int curtargetfreespace = delstate->bottomupfreespace,
8358 lastfreespace = 0,
8359 actualfreespace = 0;
8360 bool bottomup_final_block = false;
8361
8363
8364 /* Sort caller's deltids array by TID for further processing */
8366
8367 /*
8368 * Bottom-up case: resort deltids array in an order attuned to where the
8369 * greatest number of promising TIDs are to be found, and determine how
8370 * many blocks from the start of sorted array should be considered
8371 * favorable. This will also shrink the deltids array in order to
8372 * eliminate completely unfavorable blocks up front.
8373 */
8374 if (delstate->bottomup)
8376
8377#ifdef USE_PREFETCH
8378 /* Initialize prefetch state. */
8380 prefetch_state.next_item = 0;
8381 prefetch_state.ndeltids = delstate->ndeltids;
8382 prefetch_state.deltids = delstate->deltids;
8383
8384 /*
8385 * Determine the prefetch distance that we will attempt to maintain.
8386 *
8387 * Since the caller holds a buffer lock somewhere in rel, we'd better make
8388 * sure that isn't a catalog relation before we call code that does
8389 * syscache lookups, to avoid risk of deadlock.
8390 */
8391 if (IsCatalogRelation(rel))
8393 else
8396
8397 /* Cap initial prefetch distance for bottom-up deletion caller */
8398 if (delstate->bottomup)
8399 {
8403 }
8404
8405 /* Start prefetching. */
8407#endif
8408
8409 /* Iterate over deltids, determine which to delete, check their horizon */
8410 Assert(delstate->ndeltids > 0);
8411 for (int i = 0; i < delstate->ndeltids; i++)
8412 {
8413 TM_IndexDelete *ideltid = &delstate->deltids[i];
8414 TM_IndexStatus *istatus = delstate->status + ideltid->id;
8415 ItemPointer htid = &ideltid->tid;
8416 OffsetNumber offnum;
8417
8418 /*
8419 * Read buffer, and perform required extra steps each time a new block
8420 * is encountered. Avoid refetching if it's the same block as the one
8421 * from the last htid.
8422 */
8423 if (blkno == InvalidBlockNumber ||
8425 {
8426 /*
8427 * Consider giving up early for bottom-up index deletion caller
8428 * first. (Only prefetch next-next block afterwards, when it
8429 * becomes clear that we're at least going to access the next
8430 * block in line.)
8431 *
8432 * Sometimes the first block frees so much space for bottom-up
8433 * caller that the deletion process can end without accessing any
8434 * more blocks. It is usually necessary to access 2 or 3 blocks
8435 * per bottom-up deletion operation, though.
8436 */
8437 if (delstate->bottomup)
8438 {
8439 /*
8440 * We often allow caller to delete a few additional items
8441 * whose entries we reached after the point that space target
8442 * from caller was satisfied. The cost of accessing the page
8443 * was already paid at that point, so it made sense to finish
8444 * it off. When that happened, we finalize everything here
8445 * (by finishing off the whole bottom-up deletion operation
8446 * without needlessly paying the cost of accessing any more
8447 * blocks).
8448 */
8450 break;
8451
8452 /*
8453 * Give up when we didn't enable our caller to free any
8454 * additional space as a result of processing the page that we
8455 * just finished up with. This rule is the main way in which
8456 * we keep the cost of bottom-up deletion under control.
8457 */
8459 break;
8460 lastfreespace = actualfreespace; /* for next time */
8461
8462 /*
8463 * Deletion operation (which is bottom-up) will definitely
8464 * access the next block in line. Prepare for that now.
8465 *
8466 * Decay target free space so that we don't hang on for too
8467 * long with a marginal case. (Space target is only truly
8468 * helpful when it allows us to recognize that we don't need
8469 * to access more than 1 or 2 blocks to satisfy caller due to
8470 * agreeable workload characteristics.)
8471 *
8472 * We are a bit more patient when we encounter contiguous
8473 * blocks, though: these are treated as favorable blocks. The
8474 * decay process is only applied when the next block in line
8475 * is not a favorable/contiguous block. This is not an
8476 * exception to the general rule; we still insist on finding
8477 * at least one deletable item per block accessed. See
8478 * bottomup_nblocksfavorable() for full details of the theory
8479 * behind favorable blocks and heap block locality in general.
8480 *
8481 * Note: The first block in line is always treated as a
8482 * favorable block, so the earliest possible point that the
8483 * decay can be applied is just before we access the second
8484 * block in line. The Assert() verifies this for us.
8485 */
8487 if (nblocksfavorable > 0)
8489 else
8490 curtargetfreespace /= 2;
8491 }
8492
8493 /* release old buffer */
8494 if (BufferIsValid(buf))
8496
8498 buf = ReadBuffer(rel, blkno);
8500 Assert(!delstate->bottomup ||
8502
8503#ifdef USE_PREFETCH
8504
8505 /*
8506 * To maintain the prefetch distance, prefetch one more page for
8507 * each page we read.
8508 */
8510#endif
8511
8513
8514 page = BufferGetPage(buf);
8515 maxoff = PageGetMaxOffsetNumber(page);
8516 }
8517
8518 /*
8519 * In passing, detect index corruption involving an index page with a
8520 * TID that points to a location in the heap that couldn't possibly be
8521 * correct. We only do this with actual TIDs from caller's index page
8522 * (not items reached by traversing through a HOT chain).
8523 */
8525
8526 if (istatus->knowndeletable)
8527 Assert(!delstate->bottomup && !istatus->promising);
8528 else
8529 {
8530 ItemPointerData tmp = *htid;
8532
8533 /* Are any tuples from this HOT chain non-vacuumable? */
8535 &heapTuple, NULL, true))
8536 continue; /* can't delete entry */
8537
8538 /* Caller will delete, since whole HOT chain is vacuumable */
8539 istatus->knowndeletable = true;
8540
8541 /* Maintain index free space info for bottom-up deletion case */
8542 if (delstate->bottomup)
8543 {
8544 Assert(istatus->freespace > 0);
8545 actualfreespace += istatus->freespace;
8547 bottomup_final_block = true;
8548 }
8549 }
8550
8551 /*
8552 * Maintain snapshotConflictHorizon value for deletion operation as a
8553 * whole by advancing current value using heap tuple headers. This is
8554 * loosely based on the logic for pruning a HOT chain.
8555 */
8557 priorXmax = InvalidTransactionId; /* cannot check first XMIN */
8558 for (;;)
8559 {
8560 ItemId lp;
8561 HeapTupleHeader htup;
8562
8563 /* Sanity check (pure paranoia) */
8564 if (offnum < FirstOffsetNumber)
8565 break;
8566
8567 /*
8568 * An offset past the end of page's line pointer array is possible
8569 * when the array was truncated
8570 */
8571 if (offnum > maxoff)
8572 break;
8573
8574 lp = PageGetItemId(page, offnum);
8576 {
8577 offnum = ItemIdGetRedirect(lp);
8578 continue;
8579 }
8580
8581 /*
8582 * We'll often encounter LP_DEAD line pointers (especially with an
8583 * entry marked knowndeletable by our caller up front). No heap
8584 * tuple headers get examined for an htid that leads us to an
8585 * LP_DEAD item. This is okay because the earlier pruning
8586 * operation that made the line pointer LP_DEAD in the first place
8587 * must have considered the original tuple header as part of
8588 * generating its own snapshotConflictHorizon value.
8589 *
8590 * Relying on XLOG_HEAP2_PRUNE_VACUUM_SCAN records like this is
8591 * the same strategy that index vacuuming uses in all cases. Index
8592 * VACUUM WAL records don't even have a snapshotConflictHorizon
8593 * field of their own for this reason.
8594 */
8595 if (!ItemIdIsNormal(lp))
8596 break;
8597
8598 htup = (HeapTupleHeader) PageGetItem(page, lp);
8599
8600 /*
8601 * Check the tuple XMIN against prior XMAX, if any
8602 */
8605 break;
8606
8608 &snapshotConflictHorizon);
8609
8610 /*
8611 * If the tuple is not HOT-updated, then we are at the end of this
8612 * HOT-chain. No need to visit later tuples from the same update
8613 * chain (they get their own index entries) -- just move on to
8614 * next htid from index AM caller.
8615 */
8616 if (!HeapTupleHeaderIsHotUpdated(htup))
8617 break;
8618
8619 /* Advance to next HOT chain member */
8620 Assert(ItemPointerGetBlockNumber(&htup->t_ctid) == blkno);
8621 offnum = ItemPointerGetOffsetNumber(&htup->t_ctid);
8623 }
8624
8625 /* Enable further/final shrinking of deltids for caller */
8626 finalndeltids = i + 1;
8627 }
8628
8630
8631 /*
8632 * Shrink deltids array to exclude non-deletable entries at the end. This
8633 * is not just a minor optimization. Final deltids array size might be
8634 * zero for a bottom-up caller. Index AM is explicitly allowed to rely on
8635 * ndeltids being zero in all cases with zero total deletable entries.
8636 */
8637 Assert(finalndeltids > 0 || delstate->bottomup);
8638 delstate->ndeltids = finalndeltids;
8639
8640 return snapshotConflictHorizon;
8641}
8642
8643/*
8644 * Specialized inlineable comparison function for index_delete_sort()
8645 */
8646static inline int
8648{
8649 ItemPointer tid1 = &deltid1->tid;
8650 ItemPointer tid2 = &deltid2->tid;
8651
8652 {
8655
8656 if (blk1 != blk2)
8657 return (blk1 < blk2) ? -1 : 1;
8658 }
8659 {
8662
8663 if (pos1 != pos2)
8664 return (pos1 < pos2) ? -1 : 1;
8665 }
8666
8667 Assert(false);
8668
8669 return 0;
8670}
8671
8672/*
8673 * Sort deltids array from delstate by TID. This prepares it for further
8674 * processing by heap_index_delete_tuples().
8675 *
8676 * This operation becomes a noticeable consumer of CPU cycles with some
8677 * workloads, so we go to the trouble of specialization/micro optimization.
8678 * We use shellsort for this because it's easy to specialize, compiles to
8679 * relatively few instructions, and is adaptive to presorted inputs/subsets
8680 * (which are typical here).
8681 */
8682static void
8684{
8685 TM_IndexDelete *deltids = delstate->deltids;
8686 int ndeltids = delstate->ndeltids;
8687
8688 /*
8689 * Shellsort gap sequence (taken from Sedgewick-Incerpi paper).
8690 *
8691 * This implementation is fast with array sizes up to ~4500. This covers
8692 * all supported BLCKSZ values.
8693 */
8694 const int gaps[9] = {1968, 861, 336, 112, 48, 21, 7, 3, 1};
8695
8696 /* Think carefully before changing anything here -- keep swaps cheap */
8697 StaticAssertDecl(sizeof(TM_IndexDelete) <= 8,
8698 "element size exceeds 8 bytes");
8699
8700 for (size_t g = 0; g < lengthof(gaps); g++)
8701 {
8702 for (int hi = gaps[g], i = hi; i < ndeltids; i++)
8703 {
8704 TM_IndexDelete d = deltids[i];
8705 int j = i;
8706
8707 while (j >= hi && index_delete_sort_cmp(&deltids[j - hi], &d) >= 0)
8708 {
8709 deltids[j] = deltids[j - hi];
8710 j -= hi;
8711 }
8712 deltids[j] = d;
8713 }
8714 }
8715}
8716
8717/*
8718 * Returns how many blocks should be considered favorable/contiguous for a
8719 * bottom-up index deletion pass. This is a number of heap blocks that starts
8720 * from and includes the first block in line.
8721 *
8722 * There is always at least one favorable block during bottom-up index
8723 * deletion. In the worst case (i.e. with totally random heap blocks) the
8724 * first block in line (the only favorable block) can be thought of as a
8725 * degenerate array of contiguous blocks that consists of a single block.
8726 * heap_index_delete_tuples() will expect this.
8727 *
8728 * Caller passes blockgroups, a description of the final order that deltids
8729 * will be sorted in for heap_index_delete_tuples() bottom-up index deletion
8730 * processing. Note that deltids need not actually be sorted just yet (caller
8731 * only passes deltids to us so that we can interpret blockgroups).
8732 *
8733 * You might guess that the existence of contiguous blocks cannot matter much,
8734 * since in general the main factor that determines which blocks we visit is
8735 * the number of promising TIDs, which is a fixed hint from the index AM.
8736 * We're not really targeting the general case, though -- the actual goal is
8737 * to adapt our behavior to a wide variety of naturally occurring conditions.
8738 * The effects of most of the heuristics we apply are only noticeable in the
8739 * aggregate, over time and across many _related_ bottom-up index deletion
8740 * passes.
8741 *
8742 * Deeming certain blocks favorable allows heapam to recognize and adapt to
8743 * workloads where heap blocks visited during bottom-up index deletion can be
8744 * accessed contiguously, in the sense that each newly visited block is the
8745 * neighbor of the block that bottom-up deletion just finished processing (or
8746 * close enough to it). It will likely be cheaper to access more favorable
8747 * blocks sooner rather than later (e.g. in this pass, not across a series of
8748 * related bottom-up passes). Either way it is probably only a matter of time
8749 * (or a matter of further correlated version churn) before all blocks that
8750 * appear together as a single large batch of favorable blocks get accessed by
8751 * _some_ bottom-up pass. Large batches of favorable blocks tend to either
8752 * appear almost constantly or not even once (it all depends on per-index
8753 * workload characteristics).
8754 *
8755 * Note that the blockgroups sort order applies a power-of-two bucketing
8756 * scheme that creates opportunities for contiguous groups of blocks to get
8757 * batched together, at least with workloads that are naturally amenable to
8758 * being driven by heap block locality. This doesn't just enhance the spatial
8759 * locality of bottom-up heap block processing in the obvious way. It also
8760 * enables temporal locality of access, since sorting by heap block number
8761 * naturally tends to make the bottom-up processing order deterministic.
8762 *
8763 * Consider the following example to get a sense of how temporal locality
8764 * might matter: There is a heap relation with several indexes, each of which
8765 * is low to medium cardinality. It is subject to constant non-HOT updates.
8766 * The updates are skewed (in one part of the primary key, perhaps). None of
8767 * the indexes are logically modified by the UPDATE statements (if they were
8768 * then bottom-up index deletion would not be triggered in the first place).
8769 * Naturally, each new round of index tuples (for each heap tuple that gets a
8770 * heap_update() call) will have the same heap TID in each and every index.
8771 * Since these indexes are low cardinality and never get logically modified,
8772 * heapam processing during bottom-up deletion passes will access heap blocks
8773 * in approximately sequential order. Temporal locality of access occurs due
8774 * to bottom-up deletion passes behaving very similarly across each of the
8775 * indexes at any given moment. This keeps the number of buffer misses needed
8776 * to visit heap blocks to a minimum.
8777 */
8778static int
8780 TM_IndexDelete *deltids)
8781{
8782 int64 lastblock = -1;
8783 int nblocksfavorable = 0;
8784
8785 Assert(nblockgroups >= 1);
8787
8788 /*
8789 * We tolerate heap blocks that will be accessed only slightly out of
8790 * physical order. Small blips occur when a pair of almost-contiguous
8791 * blocks happen to fall into different buckets (perhaps due only to a
8792 * small difference in npromisingtids that the bucketing scheme didn't
8793 * quite manage to ignore). We effectively ignore these blips by applying
8794 * a small tolerance. The precise tolerance we use is a little arbitrary,
8795 * but it works well enough in practice.
8796 */
8797 for (int b = 0; b < nblockgroups; b++)
8798 {
8799 IndexDeleteCounts *group = blockgroups + b;
8800 TM_IndexDelete *firstdtid = deltids + group->ifirsttid;
8802
8803 if (lastblock != -1 &&
8806 break;
8807
8809 lastblock = block;
8810 }
8811
8812 /* Always indicate that there is at least 1 favorable block */
8814
8815 return nblocksfavorable;
8816}
8817
8818/*
8819 * qsort comparison function for bottomup_sort_and_shrink()
8820 */
8821static int
8822bottomup_sort_and_shrink_cmp(const void *arg1, const void *arg2)
8823{
8826
8827 /*
8828 * Most significant field is npromisingtids (which we invert the order of
8829 * so as to sort in desc order).
8830 *
8831 * Caller should have already normalized npromisingtids fields into
8832 * power-of-two values (buckets).
8833 */
8834 if (group1->npromisingtids > group2->npromisingtids)
8835 return -1;
8836 if (group1->npromisingtids < group2->npromisingtids)
8837 return 1;
8838
8839 /*
8840 * Tiebreak: desc ntids sort order.
8841 *
8842 * We cannot expect power-of-two values for ntids fields. We should
8843 * behave as if they were already rounded up for us instead.
8844 */
8845 if (group1->ntids != group2->ntids)
8846 {
8849
8850 if (ntids1 > ntids2)
8851 return -1;
8852 if (ntids1 < ntids2)
8853 return 1;
8854 }
8855
8856 /*
8857 * Tiebreak: asc offset-into-deltids-for-block (offset to first TID for
8858 * block in deltids array) order.
8859 *
8860 * This is equivalent to sorting in ascending heap block number order
8861 * (among otherwise equal subsets of the array). This approach allows us
8862 * to avoid accessing the out-of-line TID. (We rely on the assumption
8863 * that the deltids array was sorted in ascending heap TID order when
8864 * these offsets to the first TID from each heap block group were formed.)
8865 */
8866 if (group1->ifirsttid > group2->ifirsttid)
8867 return 1;
8868 if (group1->ifirsttid < group2->ifirsttid)
8869 return -1;
8870
8872
8873 return 0;
8874}
8875
8876/*
8877 * heap_index_delete_tuples() helper function for bottom-up deletion callers.
8878 *
8879 * Sorts deltids array in the order needed for useful processing by bottom-up
8880 * deletion. The array should already be sorted in TID order when we're
8881 * called. The sort process groups heap TIDs from deltids into heap block
8882 * groupings. Earlier/more-promising groups/blocks are usually those that are
8883 * known to have the most "promising" TIDs.
8884 *
8885 * Sets new size of deltids array (ndeltids) in state. deltids will only have
8886 * TIDs from the BOTTOMUP_MAX_NBLOCKS most promising heap blocks when we
8887 * return. This often means that deltids will be shrunk to a small fraction
8888 * of its original size (we eliminate many heap blocks from consideration for
8889 * caller up front).
8890 *
8891 * Returns the number of "favorable" blocks. See bottomup_nblocksfavorable()
8892 * for a definition and full details.
8893 */
8894static int
8896{
8900 int nblockgroups = 0;
8901 int ncopied = 0;
8902 int nblocksfavorable = 0;
8903
8904 Assert(delstate->bottomup);
8905 Assert(delstate->ndeltids > 0);
8906
8907 /* Calculate per-heap-block count of TIDs */
8909 for (int i = 0; i < delstate->ndeltids; i++)
8910 {
8911 TM_IndexDelete *ideltid = &delstate->deltids[i];
8912 TM_IndexStatus *istatus = delstate->status + ideltid->id;
8913 ItemPointer htid = &ideltid->tid;
8914 bool promising = istatus->promising;
8915
8916 if (curblock != ItemPointerGetBlockNumber(htid))
8917 {
8918 /* New block group */
8919 nblockgroups++;
8920
8922 !BlockNumberIsValid(curblock));
8923
8924 curblock = ItemPointerGetBlockNumber(htid);
8925 blockgroups[nblockgroups - 1].ifirsttid = i;
8926 blockgroups[nblockgroups - 1].ntids = 1;
8927 blockgroups[nblockgroups - 1].npromisingtids = 0;
8928 }
8929 else
8930 {
8931 blockgroups[nblockgroups - 1].ntids++;
8932 }
8933
8934 if (promising)
8935 blockgroups[nblockgroups - 1].npromisingtids++;
8936 }
8937
8938 /*
8939 * We're about ready to sort block groups to determine the optimal order
8940 * for visiting heap blocks. But before we do, round the number of
8941 * promising tuples for each block group up to the next power-of-two,
8942 * unless it is very low (less than 4), in which case we round up to 4.
8943 * npromisingtids is far too noisy to trust when choosing between a pair
8944 * of block groups that both have very low values.
8945 *
8946 * This scheme divides heap blocks/block groups into buckets. Each bucket
8947 * contains blocks that have _approximately_ the same number of promising
8948 * TIDs as each other. The goal is to ignore relatively small differences
8949 * in the total number of promising entries, so that the whole process can
8950 * give a little weight to heapam factors (like heap block locality)
8951 * instead. This isn't a trade-off, really -- we have nothing to lose. It
8952 * would be foolish to interpret small differences in npromisingtids
8953 * values as anything more than noise.
8954 *
8955 * We tiebreak on nhtids when sorting block group subsets that have the
8956 * same npromisingtids, but this has the same issues as npromisingtids,
8957 * and so nhtids is subject to the same power-of-two bucketing scheme. The
8958 * only reason that we don't fix nhtids in the same way here too is that
8959 * we'll need accurate nhtids values after the sort. We handle nhtids
8960 * bucketization dynamically instead (in the sort comparator).
8961 *
8962 * See bottomup_nblocksfavorable() for a full explanation of when and how
8963 * heap locality/favorable blocks can significantly influence when and how
8964 * heap blocks are accessed.
8965 */
8966 for (int b = 0; b < nblockgroups; b++)
8967 {
8968 IndexDeleteCounts *group = blockgroups + b;
8969
8970 /* Better off falling back on nhtids with low npromisingtids */
8971 if (group->npromisingtids <= 4)
8972 group->npromisingtids = 4;
8973 else
8974 group->npromisingtids =
8976 }
8977
8978 /* Sort groups and rearrange caller's deltids array */
8981 reordereddeltids = palloc(delstate->ndeltids * sizeof(TM_IndexDelete));
8982
8984 /* Determine number of favorable blocks at the start of final deltids */
8986 delstate->deltids);
8987
8988 for (int b = 0; b < nblockgroups; b++)
8989 {
8990 IndexDeleteCounts *group = blockgroups + b;
8991 TM_IndexDelete *firstdtid = delstate->deltids + group->ifirsttid;
8992
8994 sizeof(TM_IndexDelete) * group->ntids);
8995 ncopied += group->ntids;
8996 }
8997
8998 /* Copy final grouped and sorted TIDs back into start of caller's array */
9000 sizeof(TM_IndexDelete) * ncopied);
9001 delstate->ndeltids = ncopied;
9002
9005
9006 return nblocksfavorable;
9007}
9008
9009/*
9010 * Perform XLogInsert for a heap-update operation. Caller must already
9011 * have modified the buffer(s) and marked them dirty.
9012 */
9013static XLogRecPtr
9019 bool walLogical)
9020{
9024 uint8 info;
9026 uint16 prefixlen = 0,
9027 suffixlen = 0;
9029 Page page = BufferGetPage(newbuf);
9031 bool init;
9032 int bufflags;
9033
9034 /* Caller should not call me on a non-WAL-logged relation */
9036
9038
9040 info = XLOG_HEAP_HOT_UPDATE;
9041 else
9042 info = XLOG_HEAP_UPDATE;
9043
9044 /*
9045 * If the old and new tuple are on the same page, we only need to log the
9046 * parts of the new tuple that were changed. That saves on the amount of
9047 * WAL we need to write. Currently, we just count any unchanged bytes in
9048 * the beginning and end of the tuple. That's quick to check, and
9049 * perfectly covers the common case that only one field is updated.
9050 *
9051 * We could do this even if the old and new tuple are on different pages,
9052 * but only if we don't make a full-page image of the old page, which is
9053 * difficult to know in advance. Also, if the old tuple is corrupt for
9054 * some reason, it would allow the corruption to propagate the new page,
9055 * so it seems best to avoid. Under the general assumption that most
9056 * updates tend to create the new tuple version on the same page, there
9057 * isn't much to be gained by doing this across pages anyway.
9058 *
9059 * Skip this if we're taking a full-page image of the new page, as we
9060 * don't include the new tuple in the WAL record in that case. Also
9061 * disable if effective_wal_level='logical', as logical decoding needs to
9062 * be able to read the new tuple in whole from the WAL record alone.
9063 */
9064 if (oldbuf == newbuf && !need_tuple_data &&
9066 {
9067 char *oldp = (char *) oldtup->t_data + oldtup->t_data->t_hoff;
9068 char *newp = (char *) newtup->t_data + newtup->t_data->t_hoff;
9069 int oldlen = oldtup->t_len - oldtup->t_data->t_hoff;
9070 int newlen = newtup->t_len - newtup->t_data->t_hoff;
9071
9072 /* Check for common prefix between old and new tuple */
9073 for (prefixlen = 0; prefixlen < Min(oldlen, newlen); prefixlen++)
9074 {
9075 if (newp[prefixlen] != oldp[prefixlen])
9076 break;
9077 }
9078
9079 /*
9080 * Storing the length of the prefix takes 2 bytes, so we need to save
9081 * at least 3 bytes or there's no point.
9082 */
9083 if (prefixlen < 3)
9084 prefixlen = 0;
9085
9086 /* Same for suffix */
9088 {
9089 if (newp[newlen - suffixlen - 1] != oldp[oldlen - suffixlen - 1])
9090 break;
9091 }
9092 if (suffixlen < 3)
9093 suffixlen = 0;
9094 }
9095
9096 /* Prepare main WAL data chain */
9097 xlrec.flags = 0;
9102 if (prefixlen > 0)
9104 if (suffixlen > 0)
9106 if (need_tuple_data)
9107 {
9109 if (old_key_tuple)
9110 {
9111 if (reln->rd_rel->relreplident == REPLICA_IDENTITY_FULL)
9113 else
9115 }
9116 }
9117
9118 /* If new tuple is the single and first tuple on page... */
9121 {
9122 info |= XLOG_HEAP_INIT_PAGE;
9123 init = true;
9124 }
9125 else
9126 init = false;
9127
9128 /* Prepare WAL data for the old page */
9129 xlrec.old_offnum = ItemPointerGetOffsetNumber(&oldtup->t_self);
9130 xlrec.old_xmax = HeapTupleHeaderGetRawXmax(oldtup->t_data);
9131 xlrec.old_infobits_set = compute_infobits(oldtup->t_data->t_infomask,
9132 oldtup->t_data->t_infomask2);
9133
9134 /* Prepare WAL data for the new page */
9135 xlrec.new_offnum = ItemPointerGetOffsetNumber(&newtup->t_self);
9136 xlrec.new_xmax = HeapTupleHeaderGetRawXmax(newtup->t_data);
9137
9139 if (init)
9141 if (need_tuple_data)
9143
9145 if (oldbuf != newbuf)
9147
9149
9150 /*
9151 * Prepare WAL data for the new tuple.
9152 */
9153 if (prefixlen > 0 || suffixlen > 0)
9154 {
9155 if (prefixlen > 0 && suffixlen > 0)
9156 {
9160 sizeof(uint16) * 2);
9161 }
9162 else if (prefixlen > 0)
9163 {
9165 sizeof(uint16));
9166 }
9167 else
9168 {
9170 sizeof(uint16));
9171 }
9172 }
9173
9174 xlhdr.t_infomask2 = newtup->t_data->t_infomask2;
9175 xlhdr.t_infomask = newtup->t_data->t_infomask;
9176 xlhdr.t_hoff = newtup->t_data->t_hoff;
9178
9179 /*
9180 * PG73FORMAT: write bitmap [+ padding] [+ oid] + data
9181 *
9182 * The 'data' doesn't include the common prefix or suffix.
9183 */
9185 if (prefixlen == 0)
9186 {
9188 (char *) newtup->t_data + SizeofHeapTupleHeader,
9190 }
9191 else
9192 {
9193 /*
9194 * Have to write the null bitmap and data after the common prefix as
9195 * two separate rdata entries.
9196 */
9197 /* bitmap [+ padding] [+ oid] */
9198 if (newtup->t_data->t_hoff - SizeofHeapTupleHeader > 0)
9199 {
9201 (char *) newtup->t_data + SizeofHeapTupleHeader,
9202 newtup->t_data->t_hoff - SizeofHeapTupleHeader);
9203 }
9204
9205 /* data after common prefix */
9207 (char *) newtup->t_data + newtup->t_data->t_hoff + prefixlen,
9208 newtup->t_len - newtup->t_data->t_hoff - prefixlen - suffixlen);
9209 }
9210
9211 /* We need to log a tuple identity */
9213 {
9214 /* don't really need this, but its more comfy to decode */
9215 xlhdr_idx.t_infomask2 = old_key_tuple->t_data->t_infomask2;
9216 xlhdr_idx.t_infomask = old_key_tuple->t_data->t_infomask;
9217 xlhdr_idx.t_hoff = old_key_tuple->t_data->t_hoff;
9218
9220
9221 /* PG73FORMAT: write bitmap [+ padding] [+ oid] + data */
9224 }
9225
9226 /*
9227 * Register VM buffers. If the old and new heap pages' VM bits are on the
9228 * same VM page and both their VM bits were cleared, the caller passes
9229 * only vmbuffer_new (mirroring the heap page convention where block 0 =
9230 * new is always registered).
9231 */
9234
9237
9240
9241 /* filtering by origin on a row level is much more efficient */
9243
9244 recptr = XLogInsert(RM_HEAP_ID, info);
9245
9246 return recptr;
9247}
9248
9249/*
9250 * Perform XLogInsert of an XLOG_HEAP2_NEW_CID record
9251 *
9252 * This is only used when effective_wal_level is logical, and only for
9253 * catalog tuples.
9254 */
9255static XLogRecPtr
9257{
9259
9261 HeapTupleHeader hdr = tup->t_data;
9262
9263 Assert(ItemPointerIsValid(&tup->t_self));
9264 Assert(tup->t_tableOid != InvalidOid);
9265
9266 xlrec.top_xid = GetTopTransactionId();
9267 xlrec.target_locator = relation->rd_locator;
9268 xlrec.target_tid = tup->t_self;
9269
9270 /*
9271 * If the tuple got inserted & deleted in the same TX we definitely have a
9272 * combo CID, set cmin and cmax.
9273 */
9274 if (hdr->t_infomask & HEAP_COMBOCID)
9275 {
9278 xlrec.cmin = HeapTupleHeaderGetCmin(hdr);
9279 xlrec.cmax = HeapTupleHeaderGetCmax(hdr);
9280 xlrec.combocid = HeapTupleHeaderGetRawCommandId(hdr);
9281 }
9282 /* No combo CID, so only cmin or cmax can be set by this TX */
9283 else
9284 {
9285 /*
9286 * Tuple inserted.
9287 *
9288 * We need to check for LOCK ONLY because multixacts might be
9289 * transferred to the new tuple in case of FOR KEY SHARE updates in
9290 * which case there will be an xmax, although the tuple just got
9291 * inserted.
9292 */
9293 if (hdr->t_infomask & HEAP_XMAX_INVALID ||
9295 {
9297 xlrec.cmax = InvalidCommandId;
9298 }
9299 /* Tuple from a different tx updated or deleted. */
9300 else
9301 {
9302 xlrec.cmin = InvalidCommandId;
9304 }
9305 xlrec.combocid = InvalidCommandId;
9306 }
9307
9308 /*
9309 * Note that we don't need to register the buffer here, because this
9310 * operation does not modify the page. The insert/update/delete that
9311 * called us certainly did, but that's WAL-logged separately.
9312 */
9315
9316 /* will be looked at irrespective of origin */
9317
9319
9320 return recptr;
9321}
9322
9323/*
9324 * Build a heap tuple representing the configured REPLICA IDENTITY to represent
9325 * the old tuple in an UPDATE or DELETE.
9326 *
9327 * Returns NULL if there's no need to log an identity or if there's no suitable
9328 * key defined.
9329 *
9330 * Pass key_required true if any replica identity columns changed value, or if
9331 * any of them have any external data. Delete must always pass true.
9332 *
9333 * *copy is set to true if the returned tuple is a modified copy rather than
9334 * the same tuple that was passed in.
9335 */
9336static HeapTuple
9338 bool *copy)
9339{
9340 TupleDesc desc = RelationGetDescr(relation);
9341 char replident = relation->rd_rel->relreplident;
9344 bool nulls[MaxHeapAttributeNumber];
9346
9347 *copy = false;
9348
9349 if (!RelationIsLogicallyLogged(relation))
9350 return NULL;
9351
9352 if (replident == REPLICA_IDENTITY_NOTHING)
9353 return NULL;
9354
9355 if (replident == REPLICA_IDENTITY_FULL)
9356 {
9357 /*
9358 * When logging the entire old tuple, it very well could contain
9359 * toasted columns. If so, force them to be inlined.
9360 */
9361 if (HeapTupleHasExternal(tp))
9362 {
9363 *copy = true;
9364 tp = toast_flatten_tuple(tp, desc);
9365 }
9366 return tp;
9367 }
9368
9369 /* if the key isn't required and we're only logging the key, we're done */
9370 if (!key_required)
9371 return NULL;
9372
9373 /* find out the replica identity columns */
9376
9377 /*
9378 * If there's no defined replica identity columns, treat as !key_required.
9379 * (This case should not be reachable from heap_update, since that should
9380 * calculate key_required accurately. But heap_delete just passes
9381 * constant true for key_required, so we can hit this case in deletes.)
9382 */
9383 if (bms_is_empty(idattrs))
9384 return NULL;
9385
9386 /*
9387 * Construct a new tuple containing only the replica identity columns,
9388 * with nulls elsewhere. While we're at it, assert that the replica
9389 * identity columns aren't null.
9390 */
9391 heap_deform_tuple(tp, desc, values, nulls);
9392
9393 for (int i = 0; i < desc->natts; i++)
9394 {
9396 idattrs))
9397 Assert(!nulls[i]);
9398 else
9399 nulls[i] = true;
9400 }
9401
9402 key_tuple = heap_form_tuple(desc, values, nulls);
9403 *copy = true;
9404
9406
9407 /*
9408 * If the tuple, which by here only contains indexed columns, still has
9409 * toasted columns, force them to be inlined. This is somewhat unlikely
9410 * since there's limits on the size of indexed columns, so we don't
9411 * duplicate toast_flatten_tuple()s functionality in the above loop over
9412 * the indexed columns, even if it would be more efficient.
9413 */
9415 {
9417
9420 }
9421
9422 return key_tuple;
9423}
9424
9425/*
9426 * HeapCheckForSerializableConflictOut
9427 * We are reading a tuple. If it's not visible, there may be a
9428 * rw-conflict out with the inserter. Otherwise, if it is visible to us
9429 * but has been deleted, there may be a rw-conflict out with the deleter.
9430 *
9431 * We will determine the top level xid of the writing transaction with which
9432 * we may be in conflict, and ask CheckForSerializableConflictOut() to check
9433 * for overlap with our own transaction.
9434 *
9435 * This function should be called just about anywhere in heapam.c where a
9436 * tuple has been read. The caller must hold at least a shared lock on the
9437 * buffer, because this function might set hint bits on the tuple. There is
9438 * currently no known reason to call this function from an index AM.
9439 */
9440void
9441HeapCheckForSerializableConflictOut(bool visible, Relation relation,
9442 HeapTuple tuple, Buffer buffer,
9443 Snapshot snapshot)
9444{
9445 TransactionId xid;
9447
9448 if (!CheckForSerializableConflictOutNeeded(relation, snapshot))
9449 return;
9450
9451 /*
9452 * Check to see whether the tuple has been written to by a concurrent
9453 * transaction, either to create it not visible to us, or to delete it
9454 * while it is visible to us. The "visible" bool indicates whether the
9455 * tuple is visible to us, while HeapTupleSatisfiesVacuum checks what else
9456 * is going on with it.
9457 *
9458 * In the event of a concurrently inserted tuple that also happens to have
9459 * been concurrently updated (by a separate transaction), the xmin of the
9460 * tuple will be used -- not the updater's xid.
9461 */
9463 switch (htsvResult)
9464 {
9465 case HEAPTUPLE_LIVE:
9466 if (visible)
9467 return;
9468 xid = HeapTupleHeaderGetXmin(tuple->t_data);
9469 break;
9472 if (visible)
9473 xid = HeapTupleHeaderGetUpdateXid(tuple->t_data);
9474 else
9475 xid = HeapTupleHeaderGetXmin(tuple->t_data);
9476
9478 {
9479 /* This is like the HEAPTUPLE_DEAD case */
9480 Assert(!visible);
9481 return;
9482 }
9483 break;
9485 xid = HeapTupleHeaderGetXmin(tuple->t_data);
9486 break;
9487 case HEAPTUPLE_DEAD:
9488 Assert(!visible);
9489 return;
9490 default:
9491
9492 /*
9493 * The only way to get to this default clause is if a new value is
9494 * added to the enum type without adding it to this switch
9495 * statement. That's a bug, so elog.
9496 */
9497 elog(ERROR, "unrecognized return value from HeapTupleSatisfiesVacuum: %u", htsvResult);
9498
9499 /*
9500 * In spite of having all enum values covered and calling elog on
9501 * this default, some compilers think this is a code path which
9502 * allows xid to be used below without initialization. Silence
9503 * that warning.
9504 */
9506 }
9507
9510
9511 /*
9512 * Find top level xid. Bail out if xid is too early to be a conflict, or
9513 * if it's our own xid.
9514 */
9516 return;
9519 return;
9520
9521 CheckForSerializableConflictOut(relation, xid, snapshot);
9522}
int16 AttrNumber
Definition attnum.h:21
int bms_next_member(const Bitmapset *a, int prevbit)
Definition bitmapset.c:1425
void bms_free(Bitmapset *a)
Definition bitmapset.c:240
bool bms_is_member(int x, const Bitmapset *a)
Definition bitmapset.c:645
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition bitmapset.c:934
Bitmapset * bms_add_members(Bitmapset *a, const Bitmapset *b)
Definition bitmapset.c:1036
bool bms_overlap(const Bitmapset *a, const Bitmapset *b)
Definition bitmapset.c:710
#define bms_is_empty(a)
Definition bitmapset.h:119
uint32 BlockNumber
Definition block.h:31
#define InvalidBlockNumber
Definition block.h:33
static bool BlockNumberIsValid(BlockNumber blockNumber)
Definition block.h:71
static int32 next
Definition blutils.c:225
static Datum values[MAXATTR]
Definition bootstrap.c:190
int Buffer
Definition buf.h:23
#define BufferIsInvalid(buffer)
Definition buf.h:31
#define InvalidBuffer
Definition buf.h:25
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition bufmgr.c:4469
PrefetchBufferResult PrefetchBuffer(Relation reln, ForkNumber forkNum, BlockNumber blockNum)
Definition bufmgr.c:787
void BufferGetTag(Buffer buffer, RelFileLocator *rlocator, ForkNumber *forknum, BlockNumber *blknum)
Definition bufmgr.c:4490
bool BufferIsDirty(Buffer buffer)
Definition bufmgr.c:3137
void ReleaseBuffer(Buffer buffer)
Definition bufmgr.c:5609
void UnlockReleaseBuffer(Buffer buffer)
Definition bufmgr.c:5626
void MarkBufferDirty(Buffer buffer)
Definition bufmgr.c:3170
int maintenance_io_concurrency
Definition bufmgr.c:207
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition bufmgr.c:879
@ BAS_BULKREAD
Definition bufmgr.h:37
@ BAS_BULKWRITE
Definition bufmgr.h:39
#define RelationGetNumberOfBlocks(reln)
Definition bufmgr.h:309
static Page BufferGetPage(Buffer buffer)
Definition bufmgr.h:468
static Block BufferGetBlock(Buffer buffer)
Definition bufmgr.h:435
@ BUFFER_LOCK_SHARE
Definition bufmgr.h:212
@ BUFFER_LOCK_EXCLUSIVE
Definition bufmgr.h:222
@ BUFFER_LOCK_UNLOCK
Definition bufmgr.h:207
static void LockBuffer(Buffer buffer, BufferLockMode mode)
Definition bufmgr.h:334
static bool BufferIsValid(Buffer bufnum)
Definition bufmgr.h:419
Size PageGetHeapFreeSpace(const PageData *page)
Definition bufpage.c:1000
PageHeaderData * PageHeader
Definition bufpage.h:199
static bool PageIsAllVisible(const PageData *page)
Definition bufpage.h:454
static void PageClearAllVisible(Page page)
Definition bufpage.h:464
#define SizeOfPageHeaderData
Definition bufpage.h:241
static void PageSetAllVisible(Page page)
Definition bufpage.h:459
static ItemId PageGetItemId(Page page, OffsetNumber offsetNumber)
Definition bufpage.h:268
static void * PageGetItem(PageData *page, const ItemIdData *itemId)
Definition bufpage.h:378
static void PageSetFull(Page page)
Definition bufpage.h:443
static void PageSetLSN(Page page, XLogRecPtr lsn)
Definition bufpage.h:416
PageData * Page
Definition bufpage.h:81
#define PageClearPrunable(page)
Definition bufpage.h:485
#define PageSetPrunable(page, xid)
Definition bufpage.h:478
static OffsetNumber PageGetMaxOffsetNumber(const PageData *page)
Definition bufpage.h:396
#define NameStr(name)
Definition c.h:894
#define InvalidCommandId
Definition c.h:812
#define pg_always_inline
Definition c.h:364
#define pg_noinline
Definition c.h:380
#define Min(x, y)
Definition c.h:1131
#define pg_attribute_unused()
Definition c.h:208
#define likely(x)
Definition c.h:496
#define MAXALIGN(LEN)
Definition c.h:955
uint8_t uint8
Definition c.h:681
#define Assert(condition)
Definition c.h:1002
int64_t int64
Definition c.h:680
TransactionId MultiXactId
Definition c.h:805
int16_t int16
Definition c.h:678
#define SHORTALIGN(LEN)
Definition c.h:951
uint16_t uint16
Definition c.h:682
#define pg_unreachable()
Definition c.h:426
#define unlikely(x)
Definition c.h:497
uint32_t uint32
Definition c.h:683
#define lengthof(array)
Definition c.h:932
#define StaticAssertDecl(condition, errmessage)
Definition c.h:1067
uint32 CommandId
Definition c.h:809
uint32 TransactionId
Definition c.h:795
#define OidIsValid(objectId)
Definition c.h:917
size_t Size
Definition c.h:748
bool IsToastRelation(Relation relation)
Definition catalog.c:208
bool IsCatalogRelation(Relation relation)
Definition catalog.c:106
bool IsSharedRelation(Oid relationId)
Definition catalog.c:331
bool IsInplaceUpdateRelation(Relation relation)
Definition catalog.c:185
uint32 result
memcpy(sums, checksumBaseOffsets, sizeof(checksumBaseOffsets))
CommandId HeapTupleHeaderGetCmin(const HeapTupleHeaderData *tup)
Definition combocid.c:104
void HeapTupleHeaderAdjustCmax(const HeapTupleHeaderData *tup, CommandId *cmax, bool *iscombo)
Definition combocid.c:153
CommandId HeapTupleHeaderGetCmax(const HeapTupleHeaderData *tup)
Definition combocid.c:118
bool datumIsEqual(Datum value1, Datum value2, bool typByVal, int typLen)
Definition datum.c:223
Datum arg
Definition elog.c:1323
int errcode(int sqlerrcode)
Definition elog.c:875
int int errdetail_internal(const char *fmt,...) pg_attribute_printf(1
int int errmsg_internal(const char *fmt,...) pg_attribute_printf(1
#define WARNING
Definition elog.h:37
#define ERROR
Definition elog.h:40
#define elog(elevel,...)
Definition elog.h:228
#define ereport(elevel,...)
Definition elog.h:152
HeapTuple ExecFetchSlotHeapTuple(TupleTableSlot *slot, bool materialize, bool *shouldFree)
TupleTableSlot * ExecStoreBufferHeapTuple(HeapTuple tuple, TupleTableSlot *slot, Buffer buffer)
#define palloc_object(type)
Definition fe_memutils.h:89
#define palloc_array(type, count)
Definition fe_memutils.h:91
#define palloc0_object(type)
Definition fe_memutils.h:90
BufferAccessStrategy GetAccessStrategy(BufferAccessStrategyType btype)
Definition freelist.c:426
void FreeAccessStrategy(BufferAccessStrategy strategy)
Definition freelist.c:608
int NBuffers
Definition globals.c:144
Oid MyDatabaseTableSpace
Definition globals.c:98
Oid MyDatabaseId
Definition globals.c:96
void simple_heap_update(Relation relation, const ItemPointerData *otid, HeapTuple tup, TU_UpdateIndexes *update_indexes)
Definition heapam.c:4639
static bool DoesMultiXactIdConflict(MultiXactId multi, uint16 infomask, LockTupleMode lockmode, bool *current_is_member)
Definition heapam.c:7816
static XLogRecPtr log_heap_new_cid(Relation relation, HeapTuple tup)
Definition heapam.c:9257
static XLogRecPtr log_heap_update(Relation reln, Buffer oldbuf, Buffer vmbuffer_old, Buffer newbuf, Buffer vmbuffer_new, HeapTuple oldtup, HeapTuple newtup, HeapTuple old_key_tuple, bool all_visible_cleared, bool new_all_visible_cleared, bool walLogical)
Definition heapam.c:9015
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:5503
static HeapTuple heap_prepare_insert(Relation relation, HeapTuple tup, TransactionId xid, CommandId cid, uint32 options)
Definition heapam.c:2228
static TM_Result heap_lock_updated_tuple_rec(Relation rel, TransactionId priorXmax, const ItemPointerData *tid, TransactionId xid, LockTupleMode mode)
Definition heapam.c:5875
static void heap_fetch_next_buffer(HeapScanDesc scan, ScanDirection dir)
Definition heapam.c:711
bool heap_inplace_lock(Relation relation, HeapTuple oldtup_ptr, Buffer buffer, void(*release_callback)(void *), void *arg)
Definition heapam.c:6572
bool heap_fetch(Relation relation, Snapshot snapshot, HeapTuple tuple, Buffer *userbuf, bool keep_buf)
Definition heapam.c:1685
#define BOTTOMUP_TOLERANCE_NBLOCKS
Definition heapam.c:193
static BlockNumber heap_scan_stream_read_next_parallel(ReadStream *stream, void *callback_private_data, void *per_buffer_data)
Definition heapam.c:255
static int bottomup_sort_and_shrink(TM_IndexDeleteOp *delstate)
Definition heapam.c:8896
static bool heap_acquire_tuplock(Relation relation, const ItemPointerData *tid, LockTupleMode mode, LockWaitPolicy wait_policy, bool *have_tuple_lock)
Definition heapam.c:5454
static int heap_multi_insert_pages(HeapTuple *heaptuples, int done, int ntuples, Size saveFreeSpace)
Definition heapam.c:2276
static BlockNumber heap_scan_stream_read_next_serial(ReadStream *stream, void *callback_private_data, void *per_buffer_data)
Definition heapam.c:295
static pg_always_inline int page_collect_tuples(HeapScanDesc scan, Snapshot snapshot, Page page, Buffer buffer, BlockNumber block, int lines, bool all_visible, bool check_serializable)
Definition heapam.c:525
static void GetMultiXactIdHintBits(MultiXactId multi, uint16 *new_infomask, uint16 *new_infomask2)
Definition heapam.c:7667
void heap_insert(Relation relation, HeapTuple tup, CommandId cid, uint32 options, BulkInsertState bistate)
Definition heapam.c:2005
void heap_finish_speculative(Relation relation, const ItemPointerData *tid)
Definition heapam.c:6303
void HeapTupleHeaderAdvanceConflictHorizon(HeapTupleHeader tuple, TransactionId *snapshotConflictHorizon)
Definition heapam.c:8194
bool heap_getnextslot(TableScanDesc sscan, ScanDirection direction, TupleTableSlot *slot)
Definition heapam.c:1475
#define LOCKMODE_from_mxstatus(status)
Definition heapam.c:162
void heap_endscan(TableScanDesc sscan)
Definition heapam.c:1391
#define FRM_RETURN_IS_XID
Definition heapam.c:6860
#define TUPLOCK_from_mxstatus(status)
Definition heapam.c:221
void heap_rescan(TableScanDesc sscan, ScanKey key, bool set_params, bool allow_strat, bool allow_sync, bool allow_pagemode)
Definition heapam.c:1332
void heap_inplace_unlock(Relation relation, HeapTuple oldtup, Buffer buffer)
Definition heapam.c:6850
static int index_delete_sort_cmp(TM_IndexDelete *deltid1, TM_IndexDelete *deltid2)
Definition heapam.c:8648
static bool ConditionalMultiXactIdWait(MultiXactId multi, MultiXactStatus status, uint16 infomask, Relation rel, int *remaining, bool logLockFailure)
Definition heapam.c:8016
bool heap_tuple_needs_eventual_freeze(HeapTupleHeader tuple)
Definition heapam.c:8031
static TransactionId FreezeMultiXactId(MultiXactId multi, uint16 t_infomask, const struct VacuumCutoffs *cutoffs, uint16 *flags, HeapPageFreeze *pagefrz)
Definition heapam.c:6911
static HeapTuple ExtractReplicaIdentity(Relation relation, HeapTuple tp, bool key_required, bool *copy)
Definition heapam.c:9338
static pg_noinline BlockNumber heapgettup_initial_block(HeapScanDesc scan, ScanDirection dir)
Definition heapam.c:756
static TM_Result heap_lock_updated_tuple(Relation rel, uint16 prior_infomask, TransactionId prior_raw_xmax, const ItemPointerData *prior_ctid, TransactionId xid, LockTupleMode mode)
Definition heapam.c:6250
#define LockTupleTuplock(rel, tup, mode)
Definition heapam.c:170
bool heap_tuple_should_freeze(HeapTupleHeader tuple, const struct VacuumCutoffs *cutoffs, TransactionId *NoFreezePageRelfrozenXid, MultiXactId *NoFreezePageRelminMxid)
Definition heapam.c:8086
bool heap_freeze_tuple(HeapTupleHeader tuple, TransactionId relfrozenxid, TransactionId relminmxid, TransactionId FreezeLimit, TransactionId MultiXactCutoff)
Definition heapam.c:7622
void heap_inplace_update_and_unlock(Relation relation, HeapTuple oldtup, HeapTuple tuple, Buffer buffer)
Definition heapam.c:6710
static BlockNumber heapgettup_advance_block(HeapScanDesc scan, BlockNumber block, ScanDirection dir)
Definition heapam.c:880
static TransactionId MultiXactIdGetUpdateXid(TransactionId xmax, uint16 t_infomask)
Definition heapam.c:7748
#define BOTTOMUP_MAX_NBLOCKS
Definition heapam.c:192
void ReleaseBulkInsertStatePin(BulkInsertState bistate)
Definition heapam.c:1967
#define FRM_MARK_COMMITTED
Definition heapam.c:6862
#define FRM_NOOP
Definition heapam.c:6858
static void index_delete_check_htid(TM_IndexDeleteOp *delstate, Page page, OffsetNumber maxoff, const ItemPointerData *htid, TM_IndexStatus *istatus)
Definition heapam.c:8279
HeapTuple heap_getnext(TableScanDesc sscan, ScanDirection direction)
Definition heapam.c:1436
void heap_freeze_prepared_tuples(Buffer buffer, HeapTupleFreeze *tuples, int ntuples)
Definition heapam.c:7600
bool heap_getnextslot_tidrange(TableScanDesc sscan, ScanDirection direction, TupleTableSlot *slot)
Definition heapam.c:1578
static void MultiXactIdWait(MultiXactId multi, MultiXactStatus status, uint16 infomask, Relation rel, const ItemPointerData *ctid, XLTW_Oper oper, int *remaining)
Definition heapam.c:7994
void heap_set_tidrange(TableScanDesc sscan, ItemPointer mintid, ItemPointer maxtid)
Definition heapam.c:1505
void heap_abort_speculative(Relation relation, const ItemPointerData *tid)
Definition heapam.c:6390
void heap_multi_insert(Relation relation, TupleTableSlot **slots, int ntuples, CommandId cid, uint32 options, BulkInsertState bistate)
Definition heapam.c:2308
static BlockNumber bitmapheap_stream_read_next(ReadStream *pgsr, void *private_data, void *per_buffer_data)
Definition heapam.c:320
TableScanDesc heap_beginscan(Relation relation, Snapshot snapshot, int nkeys, ScanKey key, ParallelTableScanDesc parallel_scan, uint32 flags)
Definition heapam.c:1168
static void heapgettup(HeapScanDesc scan, ScanDirection dir, int nkeys, ScanKey key)
Definition heapam.c:964
static Page heapgettup_continue_page(HeapScanDesc scan, ScanDirection dir, int *linesleft, OffsetNumber *lineoff)
Definition heapam.c:834
static uint8 compute_infobits(uint16 infomask, uint16 infomask2)
Definition heapam.c:2714
#define FRM_RETURN_IS_MULTI
Definition heapam.c:6861
#define FRM_INVALIDATE_XMAX
Definition heapam.c:6859
static bool heap_attr_equals(TupleDesc tupdesc, int attrnum, Datum value1, Datum value2, bool isnull1, bool isnull2)
Definition heapam.c:4498
static void index_delete_sort(TM_IndexDeleteOp *delstate)
Definition heapam.c:8684
void heap_prepare_pagescan(TableScanDesc sscan)
Definition heapam.c:619
static Bitmapset * HeapDetermineColumnsInfo(Relation relation, Bitmapset *interesting_cols, Bitmapset *external_cols, HeapTuple oldtup, HeapTuple newtup, bool *has_external)
Definition heapam.c:4549
static const int MultiXactStatusLock[MaxMultiXactStatus+1]
Definition heapam.c:210
void simple_heap_insert(Relation relation, HeapTuple tup)
Definition heapam.c:2701
static bool xmax_infomask_changed(uint16 new_infomask, uint16 old_infomask)
Definition heapam.c:2736
#define UnlockTupleTuplock(rel, tup, mode)
Definition heapam.c:172
TM_Result heap_update(Relation relation, const ItemPointerData *otid, HeapTuple newtup, CommandId cid, uint32 options pg_attribute_unused(), Snapshot crosscheck, bool wait, TM_FailureData *tmfd, LockTupleMode *lockmode, TU_UpdateIndexes *update_indexes)
Definition heapam.c:3267
static TM_Result test_lockmode_for_conflict(MultiXactStatus status, TransactionId xid, LockTupleMode mode, HeapTuple tup, bool *needwait)
Definition heapam.c:5784
bool heap_prepare_freeze_tuple(HeapTupleHeader tuple, const struct VacuumCutoffs *cutoffs, HeapPageFreeze *pagefrz, HeapTupleFreeze *frz, bool *totally_frozen)
Definition heapam.c:7267
static void AssertHasSnapshotForToast(Relation rel)
Definition heapam.c:228
void simple_heap_delete(Relation relation, const ItemPointerData *tid)
Definition heapam.c:3219
static const struct @15 tupleLockExtraInfo[]
TransactionId HeapTupleGetUpdateXid(const HeapTupleHeaderData *tup)
Definition heapam.c:7800
TransactionId heap_index_delete_tuples(Relation rel, TM_IndexDeleteOp *delstate)
Definition heapam.c:8339
#define ConditionalLockTupleTuplock(rel, tup, mode, log)
Definition heapam.c:174
static void initscan(HeapScanDesc scan, ScanKey key, bool keep_startblock)
Definition heapam.c:360
static int bottomup_nblocksfavorable(IndexDeleteCounts *blockgroups, int nblockgroups, TM_IndexDelete *deltids)
Definition heapam.c:8780
static void heapgettup_pagemode(HeapScanDesc scan, ScanDirection dir, int nkeys, ScanKey key)
Definition heapam.c:1074
TM_Result heap_lock_tuple(Relation relation, HeapTuple tuple, CommandId cid, LockTupleMode mode, LockWaitPolicy wait_policy, bool follow_updates, Buffer *buffer, TM_FailureData *tmfd)
Definition heapam.c:4728
static void UpdateXmaxHintBits(HeapTupleHeader tuple, Buffer buffer, TransactionId xid)
Definition heapam.c:1916
static bool Do_MultiXactIdWait(MultiXactId multi, MultiXactStatus status, uint16 infomask, bool nowait, Relation rel, const ItemPointerData *ctid, XLTW_Oper oper, int *remaining, bool logLockFailure)
Definition heapam.c:7916
static int bottomup_sort_and_shrink_cmp(const void *arg1, const void *arg2)
Definition heapam.c:8823
void heap_get_latest_tid(TableScanDesc sscan, ItemPointer tid)
Definition heapam.c:1794
void heap_setscanlimits(TableScanDesc sscan, BlockNumber startBlk, BlockNumber numBlks)
Definition heapam.c:503
void HeapCheckForSerializableConflictOut(bool visible, Relation relation, HeapTuple tuple, Buffer buffer, Snapshot snapshot)
Definition heapam.c:9442
static Page heapgettup_start_page(HeapScanDesc scan, ScanDirection dir, int *linesleft, OffsetNumber *lineoff)
Definition heapam.c:803
static MultiXactStatus get_mxact_status_for_lock(LockTupleMode mode, bool is_update)
Definition heapam.c:4681
void heap_pre_freeze_checks(Buffer buffer, HeapTupleFreeze *tuples, int ntuples)
Definition heapam.c:7547
BulkInsertState GetBulkInsertState(void)
Definition heapam.c:1938
TM_Result heap_delete(Relation relation, const ItemPointerData *tid, CommandId cid, uint32 options, Snapshot crosscheck, bool wait, TM_FailureData *tmfd)
Definition heapam.c:2759
void FreeBulkInsertState(BulkInsertState bistate)
Definition heapam.c:1955
#define HEAP_INSERT_SPECULATIVE
Definition heapam.h:39
#define HEAP_FREEZE_CHECK_XMAX_ABORTED
Definition heapam.h:150
struct HeapScanDescData * HeapScanDesc
Definition heapam.h:107
HTSV_Result
Definition heapam.h:137
@ HEAPTUPLE_RECENTLY_DEAD
Definition heapam.h:140
@ HEAPTUPLE_INSERT_IN_PROGRESS
Definition heapam.h:141
@ HEAPTUPLE_LIVE
Definition heapam.h:139
@ HEAPTUPLE_DELETE_IN_PROGRESS
Definition heapam.h:142
@ HEAPTUPLE_DEAD
Definition heapam.h:138
struct BitmapHeapScanDescData * BitmapHeapScanDesc
Definition heapam.h:115
#define HEAP_INSERT_FROZEN
Definition heapam.h:37
static void heap_execute_freeze_tuple(HeapTupleHeader tuple, HeapTupleFreeze *frz)
Definition heapam.h:533
#define HEAP_FREEZE_CHECK_XMIN_COMMITTED
Definition heapam.h:149
#define HEAP_INSERT_NO_LOGICAL
Definition heapam.h:38
struct BulkInsertStateData * BulkInsertState
Definition heapam.h:47
const TableAmRoutine * GetHeapamTableAmRoutine(void)
bool heap_hot_search_buffer(ItemPointer tid, Relation relation, Buffer buffer, Snapshot snapshot, HeapTuple heapTuple, bool *all_dead, bool first_call)
void HeapTupleSetHintBits(HeapTupleHeader tuple, Buffer buffer, uint16 infomask, TransactionId xid)
bool HeapTupleSatisfiesVisibility(HeapTuple htup, Snapshot snapshot, Buffer buffer)
HTSV_Result HeapTupleSatisfiesVacuum(HeapTuple htup, TransactionId OldestXmin, Buffer buffer)
int HeapTupleSatisfiesMVCCBatch(Snapshot snapshot, Buffer buffer, int ntups, BatchMVCCState *batchmvcc, OffsetNumber *vistuples_dense)
bool HeapTupleHeaderIsOnlyLocked(HeapTupleHeader tuple)
TM_Result HeapTupleSatisfiesUpdate(HeapTuple htup, CommandId curcid, Buffer buffer)
#define XLH_INSERT_ON_TOAST_RELATION
Definition heapam_xlog.h:76
#define HEAP_DELETE_BLKREF_HEAP
#define SizeOfHeapMultiInsert
#define XLOG_HEAP2_MULTI_INSERT
Definition heapam_xlog.h:64
#define SizeOfHeapUpdate
#define XLH_INVALID_XVAC
#define XLH_UPDATE_NEW_ALL_VISIBLE_CLEARED
Definition heapam_xlog.h:87
#define XLOG_HEAP_HOT_UPDATE
Definition heapam_xlog.h:37
#define XLOG_HEAP_DELETE
Definition heapam_xlog.h:34
#define XLH_INSERT_IS_SPECULATIVE
Definition heapam_xlog.h:74
#define XLH_LOCK_ALL_FROZEN_CLEARED
#define XLH_DELETE_CONTAINS_OLD_KEY
#define HEAP_MULTI_INSERT_BLKREF_HEAP
#define XLH_UPDATE_CONTAINS_NEW_TUPLE
Definition heapam_xlog.h:90
#define XLH_INSERT_LAST_IN_MULTI
Definition heapam_xlog.h:73
#define HEAP_LOCK_BLKREF_VM
#define XLH_INSERT_ALL_FROZEN_SET
Definition heapam_xlog.h:79
#define XLH_FREEZE_XVAC
#define XLOG_HEAP_UPDATE
Definition heapam_xlog.h:35
#define XLHL_XMAX_KEYSHR_LOCK
#define XLH_DELETE_ALL_VISIBLE_CLEARED
#define XLH_UPDATE_CONTAINS_OLD_TUPLE
Definition heapam_xlog.h:88
#define HEAP_INSERT_BLKREF_VM
#define HEAP_UPDATE_BLKREF_HEAP_NEW
#define HEAP_LOCK_BLKREF_HEAP
#define HEAP_DELETE_BLKREF_VM
#define SizeOfHeapNewCid
#define SizeOfHeapLockUpdated
#define XLHL_XMAX_IS_MULTI
#define XLH_INSERT_ALL_VISIBLE_CLEARED
Definition heapam_xlog.h:72
#define SizeOfHeapHeader
#define XLH_DELETE_IS_PARTITION_MOVE
#define MinSizeOfHeapInplace
#define XLH_UPDATE_OLD_ALL_VISIBLE_CLEARED
Definition heapam_xlog.h:85
#define XLHL_XMAX_LOCK_ONLY
#define XLOG_HEAP_INPLACE
Definition heapam_xlog.h:40
#define XLOG_HEAP2_LOCK_UPDATED
Definition heapam_xlog.h:65
#define XLH_UPDATE_SUFFIX_FROM_OLD
Definition heapam_xlog.h:92
#define HEAP_UPDATE_BLKREF_HEAP_OLD
#define XLH_UPDATE_PREFIX_FROM_OLD
Definition heapam_xlog.h:91
#define SizeOfMultiInsertTuple
#define XLHL_XMAX_EXCL_LOCK
#define XLOG_HEAP2_NEW_CID
Definition heapam_xlog.h:66
#define XLH_DELETE_CONTAINS_OLD_TUPLE
#define HEAP_INSERT_BLKREF_HEAP
#define HEAP_UPDATE_BLKREF_VM_OLD
#define HEAP_MULTI_INSERT_BLKREF_VM
#define XLOG_HEAP_LOCK
Definition heapam_xlog.h:39
#define XLOG_HEAP_INSERT
Definition heapam_xlog.h:33
#define SizeOfHeapInsert
#define SizeOfHeapDelete
#define HEAP_UPDATE_BLKREF_VM_NEW
#define XLH_DELETE_IS_SUPER
#define XLH_UPDATE_CONTAINS_OLD_KEY
Definition heapam_xlog.h:89
#define XLH_DELETE_NO_LOGICAL
#define XLHL_KEYS_UPDATED
#define XLH_INSERT_CONTAINS_NEW_TUPLE
Definition heapam_xlog.h:75
#define XLOG_HEAP_INIT_PAGE
Definition heapam_xlog.h:47
#define SizeOfHeapConfirm
#define SizeOfHeapLock
#define XLOG_HEAP_CONFIRM
Definition heapam_xlog.h:38
void heap_toast_delete(Relation rel, HeapTuple oldtup, bool is_speculative)
Definition heaptoast.c:43
HeapTuple heap_toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup, uint32 options)
Definition heaptoast.c:96
HeapTuple toast_flatten_tuple(HeapTuple tup, TupleDesc tupleDesc)
Definition heaptoast.c:350
#define TOAST_TUPLE_THRESHOLD
Definition heaptoast.h:48
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition heaptuple.c:1025
void heap_deform_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *values, bool *isnull)
Definition heaptuple.c:1254
void heap_freetuple(HeapTuple htup)
Definition heaptuple.c:1372
void RelationPutHeapTuple(Relation relation, Buffer buffer, HeapTuple tuple, bool token)
Definition hio.c:35
Buffer RelationGetBufferForTuple(Relation relation, Size len, Buffer otherBuffer, uint32 options, BulkInsertState bistate, Buffer *vmbuffer, Buffer *vmbuffer_other, int num_pages)
Definition hio.c:500
HeapTupleHeaderData * HeapTupleHeader
Definition htup.h:23
#define HEAP_MOVED_OFF
#define HEAP_XMAX_SHR_LOCK
#define HEAP_XMIN_FROZEN
static Datum heap_getattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
static bool HeapTupleHeaderXminFrozen(const HeapTupleHeaderData *tup)
#define HeapTupleHeaderGetNatts(tup)
static void HeapTupleHeaderSetXminFrozen(HeapTupleHeaderData *tup)
#define SizeofHeapTupleHeader
#define HEAP_KEYS_UPDATED
static bool HEAP_XMAX_IS_SHR_LOCKED(uint16 infomask)
static bool HEAP_XMAX_IS_LOCKED_ONLY(uint16 infomask)
static bool HeapTupleHeaderXminInvalid(const HeapTupleHeaderData *tup)
static void HeapTupleClearHotUpdated(const HeapTupleData *tuple)
static bool HeapTupleHasExternal(const HeapTupleData *tuple)
static TransactionId HeapTupleHeaderGetXvac(const HeapTupleHeaderData *tup)
#define HEAP2_XACT_MASK
static void HeapTupleHeaderSetCmax(HeapTupleHeaderData *tup, CommandId cid, bool iscombo)
#define HEAP_XMAX_LOCK_ONLY
static void HeapTupleHeaderClearHotUpdated(HeapTupleHeaderData *tup)
static void HeapTupleHeaderSetCmin(HeapTupleHeaderData *tup, CommandId cid)
#define HEAP_XMAX_BITS
#define HEAP_LOCK_MASK
static CommandId HeapTupleHeaderGetRawCommandId(const HeapTupleHeaderData *tup)
static TransactionId HeapTupleHeaderGetRawXmax(const HeapTupleHeaderData *tup)
static bool HeapTupleHeaderIsHeapOnly(const HeapTupleHeaderData *tup)
static bool HeapTupleIsHeapOnly(const HeapTupleData *tuple)
#define HEAP_MOVED
static void HeapTupleSetHeapOnly(const HeapTupleData *tuple)
#define HEAP_XMAX_IS_MULTI
static bool HEAP_XMAX_IS_KEYSHR_LOCKED(uint16 infomask)
#define HEAP_XMAX_COMMITTED
static TransactionId HeapTupleHeaderGetXmin(const HeapTupleHeaderData *tup)
#define HEAP_COMBOCID
#define HEAP_XACT_MASK
static bool HeapTupleHeaderIndicatesMovedPartitions(const HeapTupleHeaderData *tup)
static void HeapTupleSetHotUpdated(const HeapTupleData *tuple)
#define HEAP_XMAX_EXCL_LOCK
static bool HeapTupleHeaderIsHotUpdated(const HeapTupleHeaderData *tup)
#define HEAP_XMAX_INVALID
static TransactionId HeapTupleHeaderGetRawXmin(const HeapTupleHeaderData *tup)
static void * GETSTRUCT(const HeapTupleData *tuple)
static void HeapTupleClearHeapOnly(const HeapTupleData *tuple)
#define MaxHeapAttributeNumber
static bool HeapTupleHeaderIsSpeculative(const HeapTupleHeaderData *tup)
static TransactionId HeapTupleHeaderGetUpdateXid(const HeapTupleHeaderData *tup)
#define MaxHeapTuplesPerPage
static bool HEAP_XMAX_IS_EXCL_LOCKED(uint16 infomask)
static void HeapTupleHeaderSetXmin(HeapTupleHeaderData *tup, TransactionId xid)
static bool HEAP_LOCKED_UPGRADED(uint16 infomask)
#define HEAP_UPDATED
#define HEAP_XMAX_KEYSHR_LOCK
static void HeapTupleHeaderSetMovedPartitions(HeapTupleHeaderData *tup)
static void HeapTupleHeaderSetXmax(HeapTupleHeaderData *tup, TransactionId xid)
static bool HeapTupleHeaderXminCommitted(const HeapTupleHeaderData *tup)
#define IsParallelWorker()
Definition parallel.h:62
void index_close(Relation relation, LOCKMODE lockmode)
Definition indexam.c:178
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition indexam.c:134
int remaining
Definition informix.c:692
#define INJECTION_POINT(name, arg)
void AcceptInvalidationMessages(void)
Definition inval.c:930
int inplaceGetInvalidationMessages(SharedInvalidationMessage **msgs, bool *RelcacheInitFileInval)
Definition inval.c:1088
void PreInplace_Inval(void)
Definition inval.c:1247
void CacheInvalidateHeapTupleInplace(Relation relation, HeapTuple key_equivalent_tuple)
Definition inval.c:1590
void AtInplace_Inval(void)
Definition inval.c:1260
void ForgetInplace_Inval(void)
Definition inval.c:1283
void CacheInvalidateHeapTuple(Relation relation, HeapTuple tuple, HeapTuple newtuple)
Definition inval.c:1568
int b
Definition isn.c:74
int j
Definition isn.c:78
int i
Definition isn.c:77
#define ItemIdGetLength(itemId)
Definition itemid.h:59
#define ItemIdIsNormal(itemId)
Definition itemid.h:99
#define ItemIdGetRedirect(itemId)
Definition itemid.h:78
#define ItemIdIsUsed(itemId)
Definition itemid.h:92
#define ItemIdIsRedirected(itemId)
Definition itemid.h:106
#define ItemIdHasStorage(itemId)
Definition itemid.h:120
int32 ItemPointerCompare(const ItemPointerData *arg1, const ItemPointerData *arg2)
Definition itemptr.c:51
bool ItemPointerEquals(const ItemPointerData *pointer1, const ItemPointerData *pointer2)
Definition itemptr.c:35
static void ItemPointerSet(ItemPointerData *pointer, BlockNumber blockNumber, OffsetNumber offNum)
Definition itemptr.h:135
static void ItemPointerSetInvalid(ItemPointerData *pointer)
Definition itemptr.h:184
static void ItemPointerSetOffsetNumber(ItemPointerData *pointer, OffsetNumber offsetNumber)
Definition itemptr.h:158
static void ItemPointerSetBlockNumber(ItemPointerData *pointer, BlockNumber blockNumber)
Definition itemptr.h:147
static OffsetNumber ItemPointerGetOffsetNumber(const ItemPointerData *pointer)
Definition itemptr.h:124
static bool ItemPointerIndicatesMovedPartitions(const ItemPointerData *pointer)
Definition itemptr.h:197
static BlockNumber ItemPointerGetBlockNumber(const ItemPointerData *pointer)
Definition itemptr.h:103
static BlockNumber ItemPointerGetBlockNumberNoCheck(const ItemPointerData *pointer)
Definition itemptr.h:93
static void ItemPointerCopy(const ItemPointerData *fromPointer, ItemPointerData *toPointer)
Definition itemptr.h:172
static bool ItemPointerIsValid(const ItemPointerData *pointer)
Definition itemptr.h:83
void UnlockTuple(Relation relation, const ItemPointerData *tid, LOCKMODE lockmode)
Definition lmgr.c:601
bool ConditionalXactLockTableWait(TransactionId xid, bool logLockFailure)
Definition lmgr.c:739
void LockTuple(Relation relation, const ItemPointerData *tid, LOCKMODE lockmode)
Definition lmgr.c:562
void XactLockTableWait(TransactionId xid, Relation rel, const ItemPointerData *ctid, XLTW_Oper oper)
Definition lmgr.c:663
XLTW_Oper
Definition lmgr.h:25
@ XLTW_None
Definition lmgr.h:26
@ XLTW_Lock
Definition lmgr.h:29
@ XLTW_Delete
Definition lmgr.h:28
@ XLTW_LockUpdated
Definition lmgr.h:30
@ XLTW_Update
Definition lmgr.h:27
bool LockHeldByMe(const LOCKTAG *locktag, LOCKMODE lockmode, bool orstronger)
Definition lock.c:640
bool DoLockModesConflict(LOCKMODE mode1, LOCKMODE mode2)
Definition lock.c:620
bool log_lock_failures
Definition lock.c:57
int LOCKMODE
Definition lockdefs.h:26
#define ShareRowExclusiveLock
Definition lockdefs.h:41
#define AccessShareLock
Definition lockdefs.h:36
#define InplaceUpdateTupleLock
Definition lockdefs.h:48
#define ShareUpdateExclusiveLock
Definition lockdefs.h:39
LockWaitPolicy
Definition lockoptions.h:38
@ LockWaitSkip
Definition lockoptions.h:42
@ LockWaitBlock
Definition lockoptions.h:40
@ LockWaitError
Definition lockoptions.h:44
LockTupleMode
Definition lockoptions.h:51
@ LockTupleExclusive
Definition lockoptions.h:59
@ LockTupleNoKeyExclusive
Definition lockoptions.h:57
@ LockTupleShare
Definition lockoptions.h:55
@ LockTupleKeyShare
Definition lockoptions.h:53
#define SET_LOCKTAG_RELATION(locktag, dboid, reloid)
Definition locktag.h:81
#define SET_LOCKTAG_TUPLE(locktag, dboid, reloid, blocknum, offnum)
Definition locktag.h:117
void pfree(void *pointer)
Definition mcxt.c:1619
void * palloc(Size size)
Definition mcxt.c:1390
#define IsBootstrapProcessingMode()
Definition miscadmin.h:486
#define START_CRIT_SECTION()
Definition miscadmin.h:152
#define CHECK_FOR_INTERRUPTS()
Definition miscadmin.h:125
#define IsNormalProcessingMode()
Definition miscadmin.h:488
#define END_CRIT_SECTION()
Definition miscadmin.h:154
MultiXactId MultiXactIdExpand(MultiXactId multi, TransactionId xid, MultiXactStatus status)
Definition multixact.c:411
bool MultiXactIdPrecedes(MultiXactId multi1, MultiXactId multi2)
Definition multixact.c:2865
bool MultiXactIdPrecedesOrEquals(MultiXactId multi1, MultiXactId multi2)
Definition multixact.c:2879
bool MultiXactIdIsRunning(MultiXactId multi, bool isLockOnly)
Definition multixact.c:522
void MultiXactIdSetOldestMember(void)
Definition multixact.c:596
MultiXactId MultiXactIdCreateFromMembers(int nmembers, MultiXactMember *members)
Definition multixact.c:715
MultiXactId MultiXactIdCreate(TransactionId xid1, MultiXactStatus status1, TransactionId xid2, MultiXactStatus status2)
Definition multixact.c:358
int GetMultiXactIdMembers(MultiXactId multi, MultiXactMember **members, bool from_pgupgrade, bool isLockOnly)
Definition multixact.c:1172
#define MultiXactIdIsValid(multi)
Definition multixact.h:29
MultiXactStatus
Definition multixact.h:37
@ MultiXactStatusForShare
Definition multixact.h:39
@ MultiXactStatusForNoKeyUpdate
Definition multixact.h:40
@ MultiXactStatusNoKeyUpdate
Definition multixact.h:43
@ MultiXactStatusUpdate
Definition multixact.h:45
@ MultiXactStatusForUpdate
Definition multixact.h:41
@ MultiXactStatusForKeyShare
Definition multixact.h:38
#define ISUPDATE_from_mxstatus(status)
Definition multixact.h:51
#define InvalidMultiXactId
Definition multixact.h:25
#define MaxMultiXactStatus
Definition multixact.h:48
static char * errmsg
#define InvalidOffsetNumber
Definition off.h:26
#define OffsetNumberIsValid(offsetNumber)
Definition off.h:39
#define OffsetNumberNext(offsetNumber)
Definition off.h:52
uint16 OffsetNumber
Definition off.h:24
#define FirstOffsetNumber
Definition off.h:27
#define OffsetNumberPrev(offsetNumber)
Definition off.h:54
#define MaxOffsetNumber
Definition off.h:28
Datum lower(PG_FUNCTION_ARGS)
Datum upper(PG_FUNCTION_ARGS)
Operator oper(ParseState *pstate, List *opname, Oid ltypeId, Oid rtypeId, bool noError, int location)
Definition parse_oper.c:376
int16 attlen
#define ERRCODE_DATA_CORRUPTED
static uint32 pg_nextpower2_32(uint32 num)
static PgChecksumMode mode
FormData_pg_class * Form_pg_class
Definition pg_class.h:160
END_CATALOG_STRUCT typedef FormData_pg_database * Form_pg_database
static char buf[DEFAULT_XLOG_SEG_SIZE]
#define pgstat_count_heap_getnext(rel)
Definition pgstat.h:735
#define pgstat_count_heap_scan(rel)
Definition pgstat.h:730
void pgstat_count_heap_update(Relation rel, bool hot, bool newpage)
void pgstat_count_heap_delete(Relation rel)
void pgstat_count_heap_insert(Relation rel, PgStat_Counter n)
#define qsort(a, b, c, d)
Definition port.h:496
static Oid DatumGetObjectId(Datum X)
Definition postgres.h:242
uint64_t Datum
Definition postgres.h:70
static Pointer DatumGetPointer(Datum X)
Definition postgres.h:332
#define InvalidOid
unsigned int Oid
void CheckForSerializableConflictIn(Relation relation, const ItemPointerData *tid, BlockNumber blkno)
Definition predicate.c:4265
void CheckForSerializableConflictOut(Relation relation, TransactionId xid, Snapshot snapshot)
Definition predicate.c:3952
void PredicateLockRelation(Relation relation, Snapshot snapshot)
Definition predicate.c:2505
void PredicateLockTID(Relation relation, const ItemPointerData *tid, Snapshot snapshot, TransactionId tuple_xid)
Definition predicate.c:2550
bool CheckForSerializableConflictOutNeeded(Relation relation, Snapshot snapshot)
Definition predicate.c:3920
static int fb(int x)
GlobalVisState * GlobalVisTestFor(Relation rel)
Definition procarray.c:4114
bool TransactionIdIsInProgress(TransactionId xid)
Definition procarray.c:1393
void heap_page_prune_opt(Relation relation, Buffer buffer, Buffer *vmbuffer, bool rel_read_only)
Definition pruneheap.c:272
void read_stream_reset(ReadStream *stream)
Buffer read_stream_next_buffer(ReadStream *stream, void **per_buffer_data)
ReadStream * read_stream_begin_relation(int flags, BufferAccessStrategy strategy, Relation rel, ForkNumber forknum, ReadStreamBlockNumberCB callback, void *callback_private_data, size_t per_buffer_data_size)
void read_stream_enable_stats(ReadStream *stream, IOStats *stats)
void read_stream_end(ReadStream *stream)
#define READ_STREAM_USE_BATCHING
Definition read_stream.h:64
BlockNumber(* ReadStreamBlockNumberCB)(ReadStream *stream, void *callback_private_data, void *per_buffer_data)
Definition read_stream.h:78
#define READ_STREAM_DEFAULT
Definition read_stream.h:21
#define READ_STREAM_SEQUENTIAL
Definition read_stream.h:36
#define RelationGetRelid(relation)
Definition rel.h:516
#define RelationIsLogicallyLogged(relation)
Definition rel.h:721
#define RelationGetTargetPageFreeSpace(relation, defaultff)
Definition rel.h:391
#define RelationGetDescr(relation)
Definition rel.h:542
#define RelationGetNumberOfAttributes(relation)
Definition rel.h:522
#define RelationGetRelationName(relation)
Definition rel.h:550
#define RelationIsAccessibleInLogicalDecoding(relation)
Definition rel.h:704
#define RelationNeedsWAL(relation)
Definition rel.h:639
#define RelationUsesLocalBuffers(relation)
Definition rel.h:648
#define HEAP_DEFAULT_FILLFACTOR
Definition rel.h:362
void RelationDecrementReferenceCount(Relation rel)
Definition relcache.c:2204
Bitmapset * RelationGetIndexAttrBitmap(Relation relation, IndexAttrBitmapKind attrKind)
Definition relcache.c:5315
void RelationIncrementReferenceCount(Relation rel)
Definition relcache.c:2191
@ INDEX_ATTR_BITMAP_KEY
Definition relcache.h:70
@ INDEX_ATTR_BITMAP_HOT_BLOCKING
Definition relcache.h:73
@ INDEX_ATTR_BITMAP_SUMMARIZED
Definition relcache.h:74
@ INDEX_ATTR_BITMAP_IDENTITY_KEY
Definition relcache.h:72
ForkNumber
Definition relpath.h:56
@ MAIN_FORKNUM
Definition relpath.h:58
struct ParallelBlockTableScanDescData * ParallelBlockTableScanDesc
Definition relscan.h:109
#define ScanDirectionIsForward(direction)
Definition sdir.h:64
#define ScanDirectionIsBackward(direction)
Definition sdir.h:50
ScanDirection
Definition sdir.h:25
@ ForwardScanDirection
Definition sdir.h:28
void UnregisterSnapshot(Snapshot snapshot)
Definition snapmgr.c:866
TransactionId TransactionXmin
Definition snapmgr.c:159
bool HaveRegisteredOrActiveSnapshot(void)
Definition snapmgr.c:1643
void InvalidateCatalogSnapshot(void)
Definition snapmgr.c:455
#define IsHistoricMVCCSnapshot(snapshot)
Definition snapmgr.h:67
#define SnapshotAny
Definition snapmgr.h:33
#define InitNonVacuumableSnapshot(snapshotdata, vistestp)
Definition snapmgr.h:50
#define IsMVCCSnapshot(snapshot)
Definition snapmgr.h:59
#define InvalidSnapshot
Definition snapshot.h:119
int get_tablespace_maintenance_io_concurrency(Oid spcid)
Definition spccache.c:230
#define init()
BlockNumber last_free
Definition hio.h:49
BufferAccessStrategy strategy
Definition hio.h:31
uint32 already_extended_by
Definition hio.h:50
BlockNumber next_free
Definition hio.h:48
Buffer current_buf
Definition hio.h:32
MultiXactId NoFreezePageRelminMxid
Definition heapam.h:244
TransactionId FreezePageConflictXid
Definition heapam.h:233
TransactionId FreezePageRelfrozenXid
Definition heapam.h:220
bool freeze_required
Definition heapam.h:194
MultiXactId FreezePageRelminMxid
Definition heapam.h:221
TransactionId NoFreezePageRelfrozenXid
Definition heapam.h:243
Buffer rs_vmbuffer
Definition heapam.h:100
BufferAccessStrategy rs_strategy
Definition heapam.h:75
ScanDirection rs_dir
Definition heapam.h:90
uint32 rs_ntuples
Definition heapam.h:104
OffsetNumber rs_coffset
Definition heapam.h:70
Buffer rs_cbuf
Definition heapam.h:72
ParallelBlockTableScanWorkerData * rs_parallelworkerdata
Definition heapam.h:97
BlockNumber rs_startblock
Definition heapam.h:64
HeapTupleData rs_ctup
Definition heapam.h:77
OffsetNumber rs_vistuples[MaxHeapTuplesPerPage]
Definition heapam.h:105
BlockNumber rs_numblocks
Definition heapam.h:65
BlockNumber rs_nblocks
Definition heapam.h:63
ReadStream * rs_read_stream
Definition heapam.h:80
uint32 rs_cindex
Definition heapam.h:103
BlockNumber rs_prefetch_block
Definition heapam.h:91
BlockNumber rs_cblock
Definition heapam.h:71
TableScanDescData rs_base
Definition heapam.h:60
ItemPointerData t_self
Definition htup.h:65
uint32 t_len
Definition htup.h:64
HeapTupleHeader t_data
Definition htup.h:68
Oid t_tableOid
Definition htup.h:66
TransactionId t_xmin
union HeapTupleHeaderData::@52 t_choice
ItemPointerData t_ctid
HeapTupleFields t_heap
int16 npromisingtids
Definition heapam.c:201
LockRelId lockRelId
Definition rel.h:46
Oid relId
Definition rel.h:40
Oid dbId
Definition rel.h:41
TransactionId xid
Definition multixact.h:57
MultiXactStatus status
Definition multixact.h:58
LockInfoData rd_lockInfo
Definition rel.h:114
Form_pg_index rd_index
Definition rel.h:192
RelFileLocator rd_locator
Definition rel.h:57
Form_pg_class rd_rel
Definition rel.h:111
bool takenDuringRecovery
Definition snapshot.h:180
TransactionId xmax
Definition tableam.h:172
CommandId cmax
Definition tableam.h:173
ItemPointerData ctid
Definition tableam.h:171
ItemPointerData tid
Definition tableam.h:234
Relation rs_rd
Definition relscan.h:36
struct TableScanInstrumentation * rs_instrument
Definition relscan.h:72
uint32 rs_flags
Definition relscan.h:64
struct ScanKeyData * rs_key
Definition relscan.h:39
struct SnapshotData * rs_snapshot
Definition relscan.h:37
struct ParallelTableScanDescData * rs_parallel
Definition relscan.h:66
TransactionId FreezeLimit
Definition vacuum.h:288
TransactionId OldestXmin
Definition vacuum.h:278
TransactionId relfrozenxid
Definition vacuum.h:262
MultiXactId relminmxid
Definition vacuum.h:263
MultiXactId MultiXactCutoff
Definition vacuum.h:289
MultiXactId OldestMxact
Definition vacuum.h:279
Definition c.h:835
OffsetNumber offnum
TransactionId SubTransGetTopmostTransaction(TransactionId xid)
Definition subtrans.c:170
void ss_report_location(Relation rel, BlockNumber location)
Definition syncscan.c:287
BlockNumber ss_get_location(Relation rel, BlockNumber relnblocks)
Definition syncscan.c:252
#define FirstLowInvalidHeapAttributeNumber
Definition sysattr.h:27
#define TableOidAttributeNumber
Definition sysattr.h:26
bool RelationSupportsSysCache(Oid relid)
Definition syscache.c:763
void table_block_parallelscan_startblock_init(Relation rel, ParallelBlockTableScanWorker pbscanwork, ParallelBlockTableScanDesc pbscan, BlockNumber startblock, BlockNumber numblocks)
Definition tableam.c:453
BlockNumber table_block_parallelscan_nextpage(Relation rel, ParallelBlockTableScanWorker pbscanwork, ParallelBlockTableScanDesc pbscan)
Definition tableam.c:548
bool synchronize_seqscans
Definition tableam.c:50
@ SO_ALLOW_STRAT
Definition tableam.h:61
@ SO_TYPE_TIDRANGESCAN
Definition tableam.h:56
@ SO_TEMP_SNAPSHOT
Definition tableam.h:68
@ SO_HINT_REL_READ_ONLY
Definition tableam.h:71
@ SO_ALLOW_PAGEMODE
Definition tableam.h:65
@ SO_TYPE_SAMPLESCAN
Definition tableam.h:54
@ SO_ALLOW_SYNC
Definition tableam.h:63
@ SO_TYPE_SEQSCAN
Definition tableam.h:52
@ SO_SCAN_INSTRUMENT
Definition tableam.h:74
@ SO_TYPE_BITMAPSCAN
Definition tableam.h:53
TU_UpdateIndexes
Definition tableam.h:133
@ TU_Summarizing
Definition tableam.h:141
@ TU_All
Definition tableam.h:138
@ TU_None
Definition tableam.h:135
TM_Result
Definition tableam.h:95
@ TM_Ok
Definition tableam.h:100
@ TM_BeingModified
Definition tableam.h:122
@ TM_Deleted
Definition tableam.h:115
@ TM_WouldBlock
Definition tableam.h:125
@ TM_Updated
Definition tableam.h:112
@ TM_SelfModified
Definition tableam.h:106
@ TM_Invisible
Definition tableam.h:103
#define TABLE_DELETE_CHANGING_PARTITION
Definition tableam.h:289
#define TABLE_DELETE_NO_LOGICAL
Definition tableam.h:290
#define TABLE_UPDATE_NO_LOGICAL
Definition tableam.h:293
bool tbm_iterate(TBMIterator *iterator, TBMIterateResult *tbmres)
Definition tidbitmap.c:1614
bool TransactionIdDidCommit(TransactionId transactionId)
Definition transam.c:126
bool TransactionIdDidAbort(TransactionId transactionId)
Definition transam.c:188
static bool TransactionIdFollows(TransactionId id1, TransactionId id2)
Definition transam.h:297
#define InvalidTransactionId
Definition transam.h:31
static bool TransactionIdPrecedesOrEquals(TransactionId id1, TransactionId id2)
Definition transam.h:282
static bool TransactionIdFollowsOrEquals(TransactionId id1, TransactionId id2)
Definition transam.h:312
#define TransactionIdEquals(id1, id2)
Definition transam.h:43
#define TransactionIdIsValid(xid)
Definition transam.h:41
#define TransactionIdIsNormal(xid)
Definition transam.h:42
static bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition transam.h:263
static CompactAttribute * TupleDescCompactAttr(TupleDesc tupdesc, int i)
Definition tupdesc.h:195
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition tuptable.h:476
static bool HeapKeyTest(HeapTuple tuple, TupleDesc tupdesc, int nkeys, ScanKey keys)
Definition valid.h:28
static bool VARATT_IS_EXTERNAL(const void *PTR)
Definition varatt.h:354
bool visibilitymap_clear(RelFileLocator rlocator, BlockNumber heapBlk, Buffer vmbuf, uint8 flags)
void visibilitymap_pin(Relation rel, BlockNumber heapBlk, Buffer *vmbuf)
void visibilitymap_set(BlockNumber heapBlk, Buffer vmBuf, uint8 flags, RelFileLocator rlocator)
#define VISIBILITYMAP_VALID_BITS
#define VISIBILITYMAP_ALL_FROZEN
#define VISIBILITYMAP_ALL_VISIBLE
TransactionId GetTopTransactionId(void)
Definition xact.c:428
TransactionId GetTopTransactionIdIfAny(void)
Definition xact.c:443
bool TransactionIdIsCurrentTransactionId(TransactionId xid)
Definition xact.c:943
bool IsInParallelMode(void)
Definition xact.c:1119
TransactionId GetCurrentTransactionId(void)
Definition xact.c:456
CommandId GetCurrentCommandId(bool used)
Definition xact.c:831
#define IsolationIsSerializable()
Definition xact.h:53
#define XLOG_INCLUDE_ORIGIN
Definition xlog.h:166
#define XLogStandbyInfoActive()
Definition xlog.h:126
uint64 XLogRecPtr
Definition xlogdefs.h:21
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition xloginsert.c:482
void XLogRegisterBufData(uint8 block_id, const void *data, uint32 len)
Definition xloginsert.c:413
bool XLogCheckBufferNeedsBackup(Buffer buffer)
void XLogRegisterData(const void *data, uint32 len)
Definition xloginsert.c:372
void XLogSetRecordFlags(uint8 flags)
Definition xloginsert.c:464
void XLogRegisterBlock(uint8 block_id, RelFileLocator *rlocator, ForkNumber forknum, BlockNumber blknum, const PageData *page, uint8 flags)
Definition xloginsert.c:317
void XLogRegisterBuffer(uint8 block_id, Buffer buffer, uint8 flags)
Definition xloginsert.c:246
void XLogBeginInsert(void)
Definition xloginsert.c:153
#define REGBUF_STANDARD
Definition xloginsert.h:35
#define REGBUF_KEEP_DATA
Definition xloginsert.h:36
#define REGBUF_WILL_INIT
Definition xloginsert.h:34

◆ FRM_INVALIDATE_XMAX

#define FRM_INVALIDATE_XMAX   0x0002

Definition at line 6859 of file heapam.c.

◆ FRM_MARK_COMMITTED

#define FRM_MARK_COMMITTED   0x0010

Definition at line 6862 of file heapam.c.

◆ FRM_NOOP

#define FRM_NOOP   0x0001

Definition at line 6858 of file heapam.c.

◆ FRM_RETURN_IS_MULTI

#define FRM_RETURN_IS_MULTI   0x0008

Definition at line 6861 of file heapam.c.

◆ FRM_RETURN_IS_XID

#define FRM_RETURN_IS_XID   0x0004

Definition at line 6860 of file heapam.c.

◆ LOCKMODE_from_mxstatus

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

Definition at line 162 of file heapam.c.

◆ LockTupleTuplock

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

Definition at line 170 of file heapam.c.

◆ TUPLOCK_from_mxstatus

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

Definition at line 221 of file heapam.c.

◆ UnlockTupleTuplock

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

Definition at line 172 of file heapam.c.

Typedef Documentation

◆ IndexDeleteCounts

Function Documentation

◆ AssertHasSnapshotForToast()

static void AssertHasSnapshotForToast ( Relation  rel)
inlinestatic

Definition at line 228 of file heapam.c.

229{
230#ifdef USE_ASSERT_CHECKING
231
232 /* bootstrap mode in particular breaks this rule */
234 return;
235
236 /* if the relation doesn't have a TOAST table, we are good */
237 if (!OidIsValid(rel->rd_rel->reltoastrelid))
238 return;
239
241
242#endif /* USE_ASSERT_CHECKING */
243}

References Assert, HaveRegisteredOrActiveSnapshot(), IsNormalProcessingMode, OidIsValid, and RelationData::rd_rel.

Referenced by heap_delete(), heap_insert(), heap_multi_insert(), and heap_update().

◆ bitmapheap_stream_read_next()

static BlockNumber bitmapheap_stream_read_next ( ReadStream pgsr,
void private_data,
void per_buffer_data 
)
static

Definition at line 320 of file heapam.c.

322{
323 TBMIterateResult *tbmres = per_buffer_data;
326 TableScanDesc sscan = &hscan->rs_base;
327
328 for (;;)
329 {
331
332 /* no more entries in the bitmap */
333 if (!tbm_iterate(&sscan->st.rs_tbmiterator, tbmres))
334 return InvalidBlockNumber;
335
336 /*
337 * Ignore any claimed entries past what we think is the end of the
338 * relation. It may have been extended after the start of our scan (we
339 * only hold an AccessShareLock, and it could be inserts from this
340 * backend). We don't take this optimization in SERIALIZABLE
341 * isolation though, as we need to examine all invisible tuples
342 * reachable by the index.
343 */
345 tbmres->blockno >= hscan->rs_nblocks)
346 continue;
347
348 return tbmres->blockno;
349 }
350
351 /* not reachable */
352 Assert(false);
353}

References Assert, CHECK_FOR_INTERRUPTS, fb(), InvalidBlockNumber, IsolationIsSerializable, and tbm_iterate().

Referenced by heap_beginscan().

◆ bottomup_nblocksfavorable()

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

Definition at line 8780 of file heapam.c.

8782{
8783 int64 lastblock = -1;
8784 int nblocksfavorable = 0;
8785
8786 Assert(nblockgroups >= 1);
8788
8789 /*
8790 * We tolerate heap blocks that will be accessed only slightly out of
8791 * physical order. Small blips occur when a pair of almost-contiguous
8792 * blocks happen to fall into different buckets (perhaps due only to a
8793 * small difference in npromisingtids that the bucketing scheme didn't
8794 * quite manage to ignore). We effectively ignore these blips by applying
8795 * a small tolerance. The precise tolerance we use is a little arbitrary,
8796 * but it works well enough in practice.
8797 */
8798 for (int b = 0; b < nblockgroups; b++)
8799 {
8800 IndexDeleteCounts *group = blockgroups + b;
8801 TM_IndexDelete *firstdtid = deltids + group->ifirsttid;
8803
8804 if (lastblock != -1 &&
8807 break;
8808
8810 lastblock = block;
8811 }
8812
8813 /* Always indicate that there is at least 1 favorable block */
8815
8816 return nblocksfavorable;
8817}

References Assert, b, BOTTOMUP_MAX_NBLOCKS, BOTTOMUP_TOLERANCE_NBLOCKS, fb(), IndexDeleteCounts::ifirsttid, and ItemPointerGetBlockNumber().

Referenced by bottomup_sort_and_shrink().

◆ bottomup_sort_and_shrink()

static int bottomup_sort_and_shrink ( TM_IndexDeleteOp delstate)
static

Definition at line 8896 of file heapam.c.

8897{
8901 int nblockgroups = 0;
8902 int ncopied = 0;
8903 int nblocksfavorable = 0;
8904
8905 Assert(delstate->bottomup);
8906 Assert(delstate->ndeltids > 0);
8907
8908 /* Calculate per-heap-block count of TIDs */
8910 for (int i = 0; i < delstate->ndeltids; i++)
8911 {
8912 TM_IndexDelete *ideltid = &delstate->deltids[i];
8913 TM_IndexStatus *istatus = delstate->status + ideltid->id;
8914 ItemPointer htid = &ideltid->tid;
8915 bool promising = istatus->promising;
8916
8917 if (curblock != ItemPointerGetBlockNumber(htid))
8918 {
8919 /* New block group */
8920 nblockgroups++;
8921
8923 !BlockNumberIsValid(curblock));
8924
8925 curblock = ItemPointerGetBlockNumber(htid);
8926 blockgroups[nblockgroups - 1].ifirsttid = i;
8927 blockgroups[nblockgroups - 1].ntids = 1;
8928 blockgroups[nblockgroups - 1].npromisingtids = 0;
8929 }
8930 else
8931 {
8932 blockgroups[nblockgroups - 1].ntids++;
8933 }
8934
8935 if (promising)
8936 blockgroups[nblockgroups - 1].npromisingtids++;
8937 }
8938
8939 /*
8940 * We're about ready to sort block groups to determine the optimal order
8941 * for visiting heap blocks. But before we do, round the number of
8942 * promising tuples for each block group up to the next power-of-two,
8943 * unless it is very low (less than 4), in which case we round up to 4.
8944 * npromisingtids is far too noisy to trust when choosing between a pair
8945 * of block groups that both have very low values.
8946 *
8947 * This scheme divides heap blocks/block groups into buckets. Each bucket
8948 * contains blocks that have _approximately_ the same number of promising
8949 * TIDs as each other. The goal is to ignore relatively small differences
8950 * in the total number of promising entries, so that the whole process can
8951 * give a little weight to heapam factors (like heap block locality)
8952 * instead. This isn't a trade-off, really -- we have nothing to lose. It
8953 * would be foolish to interpret small differences in npromisingtids
8954 * values as anything more than noise.
8955 *
8956 * We tiebreak on nhtids when sorting block group subsets that have the
8957 * same npromisingtids, but this has the same issues as npromisingtids,
8958 * and so nhtids is subject to the same power-of-two bucketing scheme. The
8959 * only reason that we don't fix nhtids in the same way here too is that
8960 * we'll need accurate nhtids values after the sort. We handle nhtids
8961 * bucketization dynamically instead (in the sort comparator).
8962 *
8963 * See bottomup_nblocksfavorable() for a full explanation of when and how
8964 * heap locality/favorable blocks can significantly influence when and how
8965 * heap blocks are accessed.
8966 */
8967 for (int b = 0; b < nblockgroups; b++)
8968 {
8969 IndexDeleteCounts *group = blockgroups + b;
8970
8971 /* Better off falling back on nhtids with low npromisingtids */
8972 if (group->npromisingtids <= 4)
8973 group->npromisingtids = 4;
8974 else
8975 group->npromisingtids =
8977 }
8978
8979 /* Sort groups and rearrange caller's deltids array */
8982 reordereddeltids = palloc(delstate->ndeltids * sizeof(TM_IndexDelete));
8983
8985 /* Determine number of favorable blocks at the start of final deltids */
8987 delstate->deltids);
8988
8989 for (int b = 0; b < nblockgroups; b++)
8990 {
8991 IndexDeleteCounts *group = blockgroups + b;
8992 TM_IndexDelete *firstdtid = delstate->deltids + group->ifirsttid;
8993
8995 sizeof(TM_IndexDelete) * group->ntids);
8996 ncopied += group->ntids;
8997 }
8998
8999 /* Copy final grouped and sorted TIDs back into start of caller's array */
9001 sizeof(TM_IndexDelete) * ncopied);
9002 delstate->ndeltids = ncopied;
9003
9006
9007 return nblocksfavorable;
9008}

References Assert, b, BlockNumberIsValid(), BOTTOMUP_MAX_NBLOCKS, bottomup_nblocksfavorable(), bottomup_sort_and_shrink_cmp(), fb(), i, IndexDeleteCounts::ifirsttid, InvalidBlockNumber, ItemPointerGetBlockNumber(), memcpy(), Min, IndexDeleteCounts::npromisingtids, IndexDeleteCounts::ntids, palloc(), palloc_array, pfree(), pg_nextpower2_32(), and qsort.

Referenced by heap_index_delete_tuples().

◆ bottomup_sort_and_shrink_cmp()

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

Definition at line 8823 of file heapam.c.

8824{
8827
8828 /*
8829 * Most significant field is npromisingtids (which we invert the order of
8830 * so as to sort in desc order).
8831 *
8832 * Caller should have already normalized npromisingtids fields into
8833 * power-of-two values (buckets).
8834 */
8835 if (group1->npromisingtids > group2->npromisingtids)
8836 return -1;
8837 if (group1->npromisingtids < group2->npromisingtids)
8838 return 1;
8839
8840 /*
8841 * Tiebreak: desc ntids sort order.
8842 *
8843 * We cannot expect power-of-two values for ntids fields. We should
8844 * behave as if they were already rounded up for us instead.
8845 */
8846 if (group1->ntids != group2->ntids)
8847 {
8850
8851 if (ntids1 > ntids2)
8852 return -1;
8853 if (ntids1 < ntids2)
8854 return 1;
8855 }
8856
8857 /*
8858 * Tiebreak: asc offset-into-deltids-for-block (offset to first TID for
8859 * block in deltids array) order.
8860 *
8861 * This is equivalent to sorting in ascending heap block number order
8862 * (among otherwise equal subsets of the array). This approach allows us
8863 * to avoid accessing the out-of-line TID. (We rely on the assumption
8864 * that the deltids array was sorted in ascending heap TID order when
8865 * these offsets to the first TID from each heap block group were formed.)
8866 */
8867 if (group1->ifirsttid > group2->ifirsttid)
8868 return 1;
8869 if (group1->ifirsttid < group2->ifirsttid)
8870 return -1;
8871
8873
8874 return 0;
8875}

References fb(), pg_nextpower2_32(), and pg_unreachable.

Referenced by bottomup_sort_and_shrink().

◆ compute_infobits()

◆ compute_new_xmax_infomask()

static void compute_new_xmax_infomask ( TransactionId  xmax,
uint16  old_infomask,
uint16  old_infomask2,
TransactionId  add_to_xmax,
LockTupleMode  mode,
bool  is_update,
TransactionId result_xmax,
uint16 result_infomask,
uint16 result_infomask2 
)
static

Definition at line 5503 of file heapam.c.

5508{
5509 TransactionId new_xmax;
5512
5514
5515l5:
5516 new_infomask = 0;
5517 new_infomask2 = 0;
5519 {
5520 /*
5521 * No previous locker; we just insert our own TransactionId.
5522 *
5523 * Note that it's critical that this case be the first one checked,
5524 * because there are several blocks below that come back to this one
5525 * to implement certain optimizations; old_infomask might contain
5526 * other dirty bits in those cases, but we don't really care.
5527 */
5528 if (is_update)
5529 {
5530 new_xmax = add_to_xmax;
5531 if (mode == LockTupleExclusive)
5533 }
5534 else
5535 {
5537 switch (mode)
5538 {
5539 case LockTupleKeyShare:
5540 new_xmax = add_to_xmax;
5542 break;
5543 case LockTupleShare:
5544 new_xmax = add_to_xmax;
5546 break;
5548 new_xmax = add_to_xmax;
5550 break;
5551 case LockTupleExclusive:
5552 new_xmax = add_to_xmax;
5555 break;
5556 default:
5557 new_xmax = InvalidTransactionId; /* silence compiler */
5558 elog(ERROR, "invalid lock mode");
5559 }
5560 }
5561 }
5563 {
5565
5566 /*
5567 * Currently we don't allow XMAX_COMMITTED to be set for multis, so
5568 * cross-check.
5569 */
5571
5572 /*
5573 * A multixact together with LOCK_ONLY set but neither lock bit set
5574 * (i.e. a pg_upgraded share locked tuple) cannot possibly be running
5575 * anymore. This check is critical for databases upgraded by
5576 * pg_upgrade; both MultiXactIdIsRunning and MultiXactIdExpand assume
5577 * that such multis are never passed.
5578 */
5580 {
5583 goto l5;
5584 }
5585
5586 /*
5587 * If the XMAX is already a MultiXactId, then we need to expand it to
5588 * include add_to_xmax; but if all the members were lockers and are
5589 * all gone, we can do away with the IS_MULTI bit and just set
5590 * add_to_xmax as the only locker/updater. If all lockers are gone
5591 * and we have an updater that aborted, we can also do without a
5592 * multi.
5593 *
5594 * The cost of doing GetMultiXactIdMembers would be paid by
5595 * MultiXactIdExpand if we weren't to do this, so this check is not
5596 * incurring extra work anyhow.
5597 */
5599 {
5602 old_infomask)))
5603 {
5604 /*
5605 * Reset these bits and restart; otherwise fall through to
5606 * create a new multi below.
5607 */
5610 goto l5;
5611 }
5612 }
5613
5615
5616 new_xmax = MultiXactIdExpand((MultiXactId) xmax, add_to_xmax,
5617 new_status);
5619 }
5621 {
5622 /*
5623 * It's a committed update, so we need to preserve him as updater of
5624 * the tuple.
5625 */
5626 MultiXactStatus status;
5628
5630 status = MultiXactStatusUpdate;
5631 else
5633
5635
5636 /*
5637 * since it's not running, it's obviously impossible for the old
5638 * updater to be identical to the current one, so we need not check
5639 * for that case as we do in the block above.
5640 */
5641 new_xmax = MultiXactIdCreate(xmax, status, add_to_xmax, new_status);
5643 }
5644 else if (TransactionIdIsInProgress(xmax))
5645 {
5646 /*
5647 * If the XMAX is a valid, in-progress TransactionId, then we need to
5648 * create a new MultiXactId that includes both the old locker or
5649 * updater and our own TransactionId.
5650 */
5654
5656 {
5662 {
5665 else
5667 }
5668 else
5669 {
5670 /*
5671 * LOCK_ONLY can be present alone only when a page has been
5672 * upgraded by pg_upgrade. But in that case,
5673 * TransactionIdIsInProgress() should have returned false. We
5674 * assume it's no longer locked in this case.
5675 */
5676 elog(WARNING, "LOCK_ONLY found for Xid in progress %u", xmax);
5679 goto l5;
5680 }
5681 }
5682 else
5683 {
5684 /* it's an update, but which kind? */
5687 else
5689 }
5690
5692
5693 /*
5694 * If the lock to be acquired is for the same TransactionId as the
5695 * existing lock, there's an optimization possible: consider only the
5696 * strongest of both locks as the only one present, and restart.
5697 */
5698 if (xmax == add_to_xmax)
5699 {
5700 /*
5701 * Note that it's not possible for the original tuple to be
5702 * updated: we wouldn't be here because the tuple would have been
5703 * invisible and we wouldn't try to update it. As a subtlety,
5704 * this code can also run when traversing an update chain to lock
5705 * future versions of a tuple. But we wouldn't be here either,
5706 * because the add_to_xmax would be different from the original
5707 * updater.
5708 */
5710
5711 /* acquire the strongest of both */
5712 if (mode < old_mode)
5713 mode = old_mode;
5714 /* mustn't touch is_update */
5715
5717 goto l5;
5718 }
5719
5720 /* otherwise, just fall back to creating a new multixact */
5722 new_xmax = MultiXactIdCreate(xmax, old_status,
5725 }
5728 {
5729 /*
5730 * It's a committed update, so we gotta preserve him as updater of the
5731 * tuple.
5732 */
5733 MultiXactStatus status;
5735
5737 status = MultiXactStatusUpdate;
5738 else
5740
5742
5743 /*
5744 * since it's not running, it's obviously impossible for the old
5745 * updater to be identical to the current one, so we need not check
5746 * for that case as we do in the block above.
5747 */
5748 new_xmax = MultiXactIdCreate(xmax, status, add_to_xmax, new_status);
5750 }
5751 else
5752 {
5753 /*
5754 * Can get here iff the locking/updating transaction was running when
5755 * the infomask was extracted from the tuple, but finished before
5756 * TransactionIdIsInProgress got to run. Deal with it as if there was
5757 * no locker at all in the first place.
5758 */
5760 goto l5;
5761 }
5762
5765 *result_xmax = new_xmax;
5766}

References Assert, elog, ERROR, fb(), 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, mode, MultiXactIdCreate(), MultiXactIdExpand(), MultiXactIdGetUpdateXid(), MultiXactIdIsRunning(), MultiXactStatusForKeyShare, MultiXactStatusForNoKeyUpdate, MultiXactStatusForShare, MultiXactStatusForUpdate, MultiXactStatusNoKeyUpdate, MultiXactStatusUpdate, TransactionIdDidCommit(), TransactionIdIsCurrentTransactionId(), TransactionIdIsInProgress(), TUPLOCK_from_mxstatus, and WARNING.

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

◆ ConditionalMultiXactIdWait()

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

Definition at line 8016 of file heapam.c.

8019{
8020 return Do_MultiXactIdWait(multi, status, infomask, true,
8022}

References Do_MultiXactIdWait(), fb(), remaining, and XLTW_None.

Referenced by heap_lock_tuple().

◆ Do_MultiXactIdWait()

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

Definition at line 7916 of file heapam.c.

7920{
7921 bool result = true;
7922 MultiXactMember *members;
7923 int nmembers;
7924 int remain = 0;
7925
7926 /* for pre-pg_upgrade tuples, no need to sleep at all */
7927 nmembers = HEAP_LOCKED_UPGRADED(infomask) ? -1 :
7928 GetMultiXactIdMembers(multi, &members, false,
7930
7931 if (nmembers >= 0)
7932 {
7933 int i;
7934
7935 for (i = 0; i < nmembers; i++)
7936 {
7937 TransactionId memxid = members[i].xid;
7938 MultiXactStatus memstatus = members[i].status;
7939
7941 {
7942 remain++;
7943 continue;
7944 }
7945
7947 LOCKMODE_from_mxstatus(status)))
7948 {
7950 remain++;
7951 continue;
7952 }
7953
7954 /*
7955 * This member conflicts with our multi, so we have to sleep (or
7956 * return failure, if asked to avoid waiting.)
7957 *
7958 * Note that we don't set up an error context callback ourselves,
7959 * but instead we pass the info down to XactLockTableWait. This
7960 * might seem a bit wasteful because the context is set up and
7961 * tore down for each member of the multixact, but in reality it
7962 * should be barely noticeable, and it avoids duplicate code.
7963 */
7964 if (nowait)
7965 {
7967 if (!result)
7968 break;
7969 }
7970 else
7971 XactLockTableWait(memxid, rel, ctid, oper);
7972 }
7973
7974 pfree(members);
7975 }
7976
7977 if (remaining)
7978 *remaining = remain;
7979
7980 return result;
7981}

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

Referenced by ConditionalMultiXactIdWait(), and MultiXactIdWait().

◆ DoesMultiXactIdConflict()

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

Definition at line 7816 of file heapam.c.

7818{
7819 int nmembers;
7820 MultiXactMember *members;
7821 bool result = false;
7822 LOCKMODE wanted = tupleLockExtraInfo[lockmode].hwlock;
7823
7825 return false;
7826
7827 nmembers = GetMultiXactIdMembers(multi, &members, false,
7829 if (nmembers >= 0)
7830 {
7831 int i;
7832
7833 for (i = 0; i < nmembers; i++)
7834 {
7837
7839 break;
7840
7841 memlockmode = LOCKMODE_from_mxstatus(members[i].status);
7842
7843 /* ignore members from current xact (but track their presence) */
7844 memxid = members[i].xid;
7846 {
7847 if (current_is_member != NULL)
7848 *current_is_member = true;
7849 continue;
7850 }
7851 else if (result)
7852 continue;
7853
7854 /* ignore members that don't conflict with the lock we want */
7856 continue;
7857
7858 if (ISUPDATE_from_mxstatus(members[i].status))
7859 {
7860 /* ignore aborted updaters */
7862 continue;
7863 }
7864 else
7865 {
7866 /* ignore lockers-only that are no longer in progress */
7868 continue;
7869 }
7870
7871 /*
7872 * Whatever remains are either live lockers that conflict with our
7873 * wanted lock, and updaters that are not aborted. Those conflict
7874 * with what we want. Set up to return true, but keep going to
7875 * look for the current transaction among the multixact members,
7876 * if needed.
7877 */
7878 result = true;
7879 }
7880 pfree(members);
7881 }
7882
7883 return result;
7884}

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

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

◆ ExtractReplicaIdentity()

static HeapTuple ExtractReplicaIdentity ( Relation  relation,
HeapTuple  tp,
bool  key_required,
bool copy 
)
static

Definition at line 9338 of file heapam.c.

9340{
9341 TupleDesc desc = RelationGetDescr(relation);
9342 char replident = relation->rd_rel->relreplident;
9345 bool nulls[MaxHeapAttributeNumber];
9347
9348 *copy = false;
9349
9350 if (!RelationIsLogicallyLogged(relation))
9351 return NULL;
9352
9353 if (replident == REPLICA_IDENTITY_NOTHING)
9354 return NULL;
9355
9356 if (replident == REPLICA_IDENTITY_FULL)
9357 {
9358 /*
9359 * When logging the entire old tuple, it very well could contain
9360 * toasted columns. If so, force them to be inlined.
9361 */
9362 if (HeapTupleHasExternal(tp))
9363 {
9364 *copy = true;
9365 tp = toast_flatten_tuple(tp, desc);
9366 }
9367 return tp;
9368 }
9369
9370 /* if the key isn't required and we're only logging the key, we're done */
9371 if (!key_required)
9372 return NULL;
9373
9374 /* find out the replica identity columns */
9377
9378 /*
9379 * If there's no defined replica identity columns, treat as !key_required.
9380 * (This case should not be reachable from heap_update, since that should
9381 * calculate key_required accurately. But heap_delete just passes
9382 * constant true for key_required, so we can hit this case in deletes.)
9383 */
9384 if (bms_is_empty(idattrs))
9385 return NULL;
9386
9387 /*
9388 * Construct a new tuple containing only the replica identity columns,
9389 * with nulls elsewhere. While we're at it, assert that the replica
9390 * identity columns aren't null.
9391 */
9392 heap_deform_tuple(tp, desc, values, nulls);
9393
9394 for (int i = 0; i < desc->natts; i++)
9395 {
9397 idattrs))
9398 Assert(!nulls[i]);
9399 else
9400 nulls[i] = true;
9401 }
9402
9403 key_tuple = heap_form_tuple(desc, values, nulls);
9404 *copy = true;
9405
9407
9408 /*
9409 * If the tuple, which by here only contains indexed columns, still has
9410 * toasted columns, force them to be inlined. This is somewhat unlikely
9411 * since there's limits on the size of indexed columns, so we don't
9412 * duplicate toast_flatten_tuple()s functionality in the above loop over
9413 * the indexed columns, even if it would be more efficient.
9414 */
9416 {
9418
9421 }
9422
9423 return key_tuple;
9424}

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

Referenced by heap_delete(), and heap_update().

◆ FreeBulkInsertState()

◆ FreezeMultiXactId()

static TransactionId FreezeMultiXactId ( MultiXactId  multi,
uint16  t_infomask,
const struct VacuumCutoffs cutoffs,
uint16 flags,
HeapPageFreeze pagefrz 
)
static

Definition at line 6911 of file heapam.c.

6914{
6916 MultiXactMember *members;
6917 int nmembers;
6918 bool need_replace;
6919 int nnewmembers;
6921 bool has_lockers;
6923 bool update_committed;
6924 TransactionId FreezePageRelfrozenXid;
6925
6926 *flags = 0;
6927
6928 /* We should only be called in Multis */
6929 Assert(t_infomask & HEAP_XMAX_IS_MULTI);
6930
6931 if (!MultiXactIdIsValid(multi) ||
6932 HEAP_LOCKED_UPGRADED(t_infomask))
6933 {
6934 *flags |= FRM_INVALIDATE_XMAX;
6935 pagefrz->freeze_required = true;
6936 return InvalidTransactionId;
6937 }
6938 else if (MultiXactIdPrecedes(multi, cutoffs->relminmxid))
6939 ereport(ERROR,
6941 errmsg_internal("found multixact %u from before relminmxid %u",
6942 multi, cutoffs->relminmxid)));
6943 else if (MultiXactIdPrecedes(multi, cutoffs->OldestMxact))
6944 {
6946
6947 /*
6948 * This old multi cannot possibly have members still running, but
6949 * verify just in case. If it was a locker only, it can be removed
6950 * without any further consideration; but if it contained an update,
6951 * we might need to preserve it.
6952 */
6953 if (MultiXactIdIsRunning(multi,
6954 HEAP_XMAX_IS_LOCKED_ONLY(t_infomask)))
6955 ereport(ERROR,
6957 errmsg_internal("multixact %u from before multi freeze cutoff %u found to be still running",
6958 multi, cutoffs->OldestMxact)));
6959
6960 if (HEAP_XMAX_IS_LOCKED_ONLY(t_infomask))
6961 {
6962 *flags |= FRM_INVALIDATE_XMAX;
6963 pagefrz->freeze_required = true;
6964 return InvalidTransactionId;
6965 }
6966
6967 /* replace multi with single XID for its updater? */
6968 update_xact = MultiXactIdGetUpdateXid(multi, t_infomask);
6970 ereport(ERROR,
6972 errmsg_internal("multixact %u contains update XID %u from before relfrozenxid %u",
6973 multi, update_xact,
6974 cutoffs->relfrozenxid)));
6975 else if (TransactionIdPrecedes(update_xact, cutoffs->OldestXmin))
6976 {
6977 /*
6978 * Updater XID has to have aborted (otherwise the tuple would have
6979 * been pruned away instead, since updater XID is < OldestXmin).
6980 * Just remove xmax.
6981 */
6983 ereport(ERROR,
6985 errmsg_internal("multixact %u contains committed update XID %u from before removable cutoff %u",
6986 multi, update_xact,
6987 cutoffs->OldestXmin)));
6988 *flags |= FRM_INVALIDATE_XMAX;
6989 pagefrz->freeze_required = true;
6990 return InvalidTransactionId;
6991 }
6992
6993 /* Have to keep updater XID as new xmax */
6994 *flags |= FRM_RETURN_IS_XID;
6995 pagefrz->freeze_required = true;
6996 return update_xact;
6997 }
6998
6999 /*
7000 * Some member(s) of this Multi may be below FreezeLimit xid cutoff, so we
7001 * need to walk the whole members array to figure out what to do, if
7002 * anything.
7003 */
7004 nmembers =
7005 GetMultiXactIdMembers(multi, &members, false,
7006 HEAP_XMAX_IS_LOCKED_ONLY(t_infomask));
7007 if (nmembers <= 0)
7008 {
7009 /* Nothing worth keeping */
7010 *flags |= FRM_INVALIDATE_XMAX;
7011 pagefrz->freeze_required = true;
7012 return InvalidTransactionId;
7013 }
7014
7015 /*
7016 * The FRM_NOOP case is the only case where we might need to ratchet back
7017 * FreezePageRelfrozenXid or FreezePageRelminMxid. It is also the only
7018 * case where our caller might ratchet back its NoFreezePageRelfrozenXid
7019 * or NoFreezePageRelminMxid "no freeze" trackers to deal with a multi.
7020 * FRM_NOOP handling should result in the NewRelfrozenXid/NewRelminMxid
7021 * trackers managed by VACUUM being ratcheting back by xmax to the degree
7022 * required to make it safe to leave xmax undisturbed, independent of
7023 * whether or not page freezing is triggered somewhere else.
7024 *
7025 * Our policy is to force freezing in every case other than FRM_NOOP,
7026 * which obviates the need to maintain either set of trackers, anywhere.
7027 * Every other case will reliably execute a freeze plan for xmax that
7028 * either replaces xmax with an XID/MXID >= OldestXmin/OldestMxact, or
7029 * sets xmax to an InvalidTransactionId XID, rendering xmax fully frozen.
7030 * (VACUUM's NewRelfrozenXid/NewRelminMxid trackers are initialized with
7031 * OldestXmin/OldestMxact, so later values never need to be tracked here.)
7032 */
7033 need_replace = false;
7034 FreezePageRelfrozenXid = pagefrz->FreezePageRelfrozenXid;
7035 for (int i = 0; i < nmembers; i++)
7036 {
7037 TransactionId xid = members[i].xid;
7038
7039 Assert(!TransactionIdPrecedes(xid, cutoffs->relfrozenxid));
7040
7041 if (TransactionIdPrecedes(xid, cutoffs->FreezeLimit))
7042 {
7043 /* Can't violate the FreezeLimit postcondition */
7044 need_replace = true;
7045 break;
7046 }
7047 if (TransactionIdPrecedes(xid, FreezePageRelfrozenXid))
7048 FreezePageRelfrozenXid = xid;
7049 }
7050
7051 /* Can't violate the MultiXactCutoff postcondition, either */
7052 if (!need_replace)
7054
7055 if (!need_replace)
7056 {
7057 /*
7058 * vacuumlazy.c might ratchet back NewRelminMxid, NewRelfrozenXid, or
7059 * both together to make it safe to retain this particular multi after
7060 * freezing its page
7061 */
7062 *flags |= FRM_NOOP;
7063 pagefrz->FreezePageRelfrozenXid = FreezePageRelfrozenXid;
7064 if (MultiXactIdPrecedes(multi, pagefrz->FreezePageRelminMxid))
7065 pagefrz->FreezePageRelminMxid = multi;
7066 pfree(members);
7067 return multi;
7068 }
7069
7070 /*
7071 * Do a more thorough second pass over the multi to figure out which
7072 * member XIDs actually need to be kept. Checking the precise status of
7073 * individual members might even show that we don't need to keep anything.
7074 * That is quite possible even though the Multi must be >= OldestMxact,
7075 * since our second pass only keeps member XIDs when it's truly necessary;
7076 * even member XIDs >= OldestXmin often won't be kept by second pass.
7077 */
7078 nnewmembers = 0;
7080 has_lockers = false;
7082 update_committed = false;
7083
7084 /*
7085 * Determine whether to keep each member xid, or to ignore it instead
7086 */
7087 for (int i = 0; i < nmembers; i++)
7088 {
7089 TransactionId xid = members[i].xid;
7090 MultiXactStatus mstatus = members[i].status;
7091
7092 Assert(!TransactionIdPrecedes(xid, cutoffs->relfrozenxid));
7093
7094 if (!ISUPDATE_from_mxstatus(mstatus))
7095 {
7096 /*
7097 * Locker XID (not updater XID). We only keep lockers that are
7098 * still running.
7099 */
7102 {
7103 if (TransactionIdPrecedes(xid, cutoffs->OldestXmin))
7104 ereport(ERROR,
7106 errmsg_internal("multixact %u contains running locker XID %u from before removable cutoff %u",
7107 multi, xid,
7108 cutoffs->OldestXmin)));
7109 newmembers[nnewmembers++] = members[i];
7110 has_lockers = true;
7111 }
7112
7113 continue;
7114 }
7115
7116 /*
7117 * Updater XID (not locker XID). Should we keep it?
7118 *
7119 * Since the tuple wasn't totally removed when vacuum pruned, the
7120 * update Xid cannot possibly be older than OldestXmin cutoff unless
7121 * the updater XID aborted. If the updater transaction is known
7122 * aborted or crashed then it's okay to ignore it, otherwise not.
7123 *
7124 * In any case the Multi should never contain two updaters, whatever
7125 * their individual commit status. Check for that first, in passing.
7126 */
7128 ereport(ERROR,
7130 errmsg_internal("multixact %u has two or more updating members",
7131 multi),
7132 errdetail_internal("First updater XID=%u second updater XID=%u.",
7133 update_xid, xid)));
7134
7135 /*
7136 * As with all tuple visibility routines, it's critical to test
7137 * TransactionIdIsInProgress before TransactionIdDidCommit, because of
7138 * race conditions explained in detail in heapam_visibility.c.
7139 */
7142 update_xid = xid;
7143 else if (TransactionIdDidCommit(xid))
7144 {
7145 /*
7146 * The transaction committed, so we can tell caller to set
7147 * HEAP_XMAX_COMMITTED. (We can only do this because we know the
7148 * transaction is not running.)
7149 */
7150 update_committed = true;
7151 update_xid = xid;
7152 }
7153 else
7154 {
7155 /*
7156 * Not in progress, not committed -- must be aborted or crashed;
7157 * we can ignore it.
7158 */
7159 continue;
7160 }
7161
7162 /*
7163 * We determined that updater must be kept -- add it to pending new
7164 * members list
7165 */
7166 if (TransactionIdPrecedes(xid, cutoffs->OldestXmin))
7167 ereport(ERROR,
7169 errmsg_internal("multixact %u contains committed update XID %u from before removable cutoff %u",
7170 multi, xid, cutoffs->OldestXmin)));
7171 newmembers[nnewmembers++] = members[i];
7172 }
7173
7174 pfree(members);
7175
7176 /*
7177 * Determine what to do with caller's multi based on information gathered
7178 * during our second pass
7179 */
7180 if (nnewmembers == 0)
7181 {
7182 /* Nothing worth keeping */
7183 *flags |= FRM_INVALIDATE_XMAX;
7185 }
7187 {
7188 /*
7189 * If there's a single member and it's an update, pass it back alone
7190 * without creating a new Multi. (XXX we could do this when there's a
7191 * single remaining locker, too, but that would complicate the API too
7192 * much; moreover, the case with the single updater is more
7193 * interesting, because those are longer-lived.)
7194 */
7195 Assert(nnewmembers == 1);
7196 *flags |= FRM_RETURN_IS_XID;
7197 if (update_committed)
7198 *flags |= FRM_MARK_COMMITTED;
7200 }
7201 else
7202 {
7203 /*
7204 * Create a new multixact with the surviving members of the previous
7205 * one, to set as new Xmax in the tuple
7206 */
7208 *flags |= FRM_RETURN_IS_MULTI;
7209 }
7210
7212
7213 pagefrz->freeze_required = true;
7214 return newxmax;
7215}

References Assert, ereport, errcode(), ERRCODE_DATA_CORRUPTED, errdetail_internal(), errmsg_internal(), ERROR, fb(), HeapPageFreeze::freeze_required, VacuumCutoffs::FreezeLimit, HeapPageFreeze::FreezePageRelfrozenXid, HeapPageFreeze::FreezePageRelminMxid, 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, VacuumCutoffs::MultiXactCutoff, MultiXactIdCreateFromMembers(), MultiXactIdGetUpdateXid(), MultiXactIdIsRunning(), MultiXactIdIsValid, MultiXactIdPrecedes(), VacuumCutoffs::OldestMxact, VacuumCutoffs::OldestXmin, palloc_array, pfree(), VacuumCutoffs::relfrozenxid, VacuumCutoffs::relminmxid, MultiXactMember::status, TransactionIdDidCommit(), TransactionIdIsCurrentTransactionId(), TransactionIdIsInProgress(), TransactionIdIsValid, TransactionIdPrecedes(), and MultiXactMember::xid.

Referenced by heap_prepare_freeze_tuple().

◆ get_mxact_status_for_lock()

static MultiXactStatus get_mxact_status_for_lock ( LockTupleMode  mode,
bool  is_update 
)
static

Definition at line 4681 of file heapam.c.

4682{
4683 int retval;
4684
4685 if (is_update)
4686 retval = tupleLockExtraInfo[mode].updstatus;
4687 else
4688 retval = tupleLockExtraInfo[mode].lockstatus;
4689
4690 if (retval == -1)
4691 elog(ERROR, "invalid lock tuple mode %d/%s", mode,
4692 is_update ? "true" : "false");
4693
4694 return (MultiXactStatus) retval;
4695}

References elog, ERROR, fb(), mode, and tupleLockExtraInfo.

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

◆ GetBulkInsertState()

◆ GetMultiXactIdHintBits()

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

Definition at line 7667 of file heapam.c.

7669{
7670 int nmembers;
7671 MultiXactMember *members;
7672 int i;
7674 uint16 bits2 = 0;
7675 bool has_update = false;
7677
7678 /*
7679 * We only use this in multis we just created, so they cannot be values
7680 * pre-pg_upgrade.
7681 */
7682 nmembers = GetMultiXactIdMembers(multi, &members, false, false);
7683
7684 for (i = 0; i < nmembers; i++)
7685 {
7687
7688 /*
7689 * Remember the strongest lock mode held by any member of the
7690 * multixact.
7691 */
7692 mode = TUPLOCK_from_mxstatus(members[i].status);
7693 if (mode > strongest)
7694 strongest = mode;
7695
7696 /* See what other bits we need */
7697 switch (members[i].status)
7698 {
7702 break;
7703
7706 break;
7707
7709 has_update = true;
7710 break;
7711
7714 has_update = true;
7715 break;
7716 }
7717 }
7718
7721 bits |= HEAP_XMAX_EXCL_LOCK;
7722 else if (strongest == LockTupleShare)
7723 bits |= HEAP_XMAX_SHR_LOCK;
7724 else if (strongest == LockTupleKeyShare)
7725 bits |= HEAP_XMAX_KEYSHR_LOCK;
7726
7727 if (!has_update)
7728 bits |= HEAP_XMAX_LOCK_ONLY;
7729
7730 if (nmembers > 0)
7731 pfree(members);
7732
7733 *new_infomask = bits;
7735}

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

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

◆ heap_abort_speculative()

void heap_abort_speculative ( Relation  relation,
const ItemPointerData tid 
)

Definition at line 6390 of file heapam.c.

6391{
6393 ItemId lp;
6394 HeapTupleData tp;
6395 Page page;
6396 BlockNumber block;
6397 Buffer buffer;
6398
6400
6401 block = ItemPointerGetBlockNumber(tid);
6402 buffer = ReadBuffer(relation, block);
6403 page = BufferGetPage(buffer);
6404
6406
6407 /*
6408 * Page can't be all visible, we just inserted into it, and are still
6409 * running.
6410 */
6411 Assert(!PageIsAllVisible(page));
6412
6415
6416 tp.t_tableOid = RelationGetRelid(relation);
6417 tp.t_data = (HeapTupleHeader) PageGetItem(page, lp);
6418 tp.t_len = ItemIdGetLength(lp);
6419 tp.t_self = *tid;
6420
6421 /*
6422 * Sanity check that the tuple really is a speculatively inserted tuple,
6423 * inserted by us.
6424 */
6425 if (tp.t_data->t_choice.t_heap.t_xmin != xid)
6426 elog(ERROR, "attempted to kill a tuple inserted by another transaction");
6427 if (!(IsToastRelation(relation) || HeapTupleHeaderIsSpeculative(tp.t_data)))
6428 elog(ERROR, "attempted to kill a non-speculative tuple");
6430
6431 /*
6432 * No need to check for serializable conflicts here. There is never a
6433 * need for a combo CID, either. No need to extract replica identity, or
6434 * do anything special with infomask bits.
6435 */
6436
6438
6439 /*
6440 * The tuple will become DEAD immediately. Flag that this page is a
6441 * candidate for pruning by setting xmin to TransactionXmin. While not
6442 * immediately prunable, it is the oldest xid we can cheaply determine
6443 * that's safe against wraparound / being older than the table's
6444 * relfrozenxid. To defend against the unlikely case of a new relation
6445 * having a newer relfrozenxid than our TransactionXmin, use relfrozenxid
6446 * if so (vacuum can't subsequently move relfrozenxid to beyond
6447 * TransactionXmin, so there's no race here).
6448 */
6450 {
6451 TransactionId relfrozenxid = relation->rd_rel->relfrozenxid;
6453
6454 if (TransactionIdPrecedes(TransactionXmin, relfrozenxid))
6455 prune_xid = relfrozenxid;
6456 else
6459 }
6460
6461 /* store transaction information of xact deleting the tuple */
6464
6465 /*
6466 * Set the tuple header xmin to InvalidTransactionId. This makes the
6467 * tuple immediately invisible everyone. (In particular, to any
6468 * transactions waiting on the speculative token, woken up later.)
6469 */
6471
6472 /* Clear the speculative insertion token too */
6473 tp.t_data->t_ctid = tp.t_self;
6474
6475 MarkBufferDirty(buffer);
6476
6477 /*
6478 * XLOG stuff
6479 *
6480 * The WAL records generated here match heap_delete(). The same recovery
6481 * routines are used.
6482 */
6483 if (RelationNeedsWAL(relation))
6484 {
6487
6489 xlrec.infobits_set = compute_infobits(tp.t_data->t_infomask,
6490 tp.t_data->t_infomask2);
6492 xlrec.xmax = xid;
6493
6497
6498 /* No replica identity & replication origin logged */
6499
6501
6502 PageSetLSN(page, recptr);
6503 }
6504
6506
6508
6509 if (HeapTupleHasExternal(&tp))
6510 {
6511 Assert(!IsToastRelation(relation));
6512 heap_toast_delete(relation, &tp, true);
6513 }
6514
6515 /*
6516 * Never need to mark tuple for invalidation, since catalogs don't support
6517 * speculative insertion
6518 */
6519
6520 /* Now we can release the buffer */
6521 ReleaseBuffer(buffer);
6522
6523 /* count deletion, as we counted the insertion too */
6524 pgstat_count_heap_delete(relation);
6525}

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

Referenced by heapam_tuple_complete_speculative(), and toast_delete_datum().

◆ heap_acquire_tuplock()

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

Definition at line 5454 of file heapam.c.

5456{
5457 if (*have_tuple_lock)
5458 return true;
5459
5460 switch (wait_policy)
5461 {
5462 case LockWaitBlock:
5463 LockTupleTuplock(relation, tid, mode);
5464 break;
5465
5466 case LockWaitSkip:
5467 if (!ConditionalLockTupleTuplock(relation, tid, mode, false))
5468 return false;
5469 break;
5470
5471 case LockWaitError:
5473 ereport(ERROR,
5475 errmsg("could not obtain lock on row in relation \"%s\"",
5476 RelationGetRelationName(relation))));
5477 break;
5478 }
5479 *have_tuple_lock = true;
5480
5481 return true;
5482}

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

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

◆ heap_attr_equals()

static bool heap_attr_equals ( TupleDesc  tupdesc,
int  attrnum,
Datum  value1,
Datum  value2,
bool  isnull1,
bool  isnull2 
)
static

Definition at line 4498 of file heapam.c.

4500{
4501 /*
4502 * If one value is NULL and other is not, then they are certainly not
4503 * equal
4504 */
4505 if (isnull1 != isnull2)
4506 return false;
4507
4508 /*
4509 * If both are NULL, they can be considered equal.
4510 */
4511 if (isnull1)
4512 return true;
4513
4514 /*
4515 * We do simple binary comparison of the two datums. This may be overly
4516 * strict because there can be multiple binary representations for the
4517 * same logical value. But we should be OK as long as there are no false
4518 * positives. Using a type-specific equality operator is messy because
4519 * there could be multiple notions of equality in different operator
4520 * classes; furthermore, we cannot safely invoke user-defined functions
4521 * while holding exclusive buffer lock.
4522 */
4523 if (attrnum <= 0)
4524 {
4525 /* The only allowed system columns are OIDs, so do this */
4527 }
4528 else
4529 {
4530 CompactAttribute *att;
4531
4533 att = TupleDescCompactAttr(tupdesc, attrnum - 1);
4534 return datumIsEqual(value1, value2, att->attbyval, att->attlen);
4535 }
4536}

References Assert, CompactAttribute::attbyval, CompactAttribute::attlen, DatumGetObjectId(), datumIsEqual(), fb(), and TupleDescCompactAttr().

Referenced by HeapDetermineColumnsInfo().

◆ heap_beginscan()

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

Definition at line 1168 of file heapam.c.

1172{
1173 HeapScanDesc scan;
1174
1175 /*
1176 * increment relation ref count while scanning relation
1177 *
1178 * This is just to make really sure the relcache entry won't go away while
1179 * the scan has a pointer to it. Caller should be holding the rel open
1180 * anyway, so this is redundant in all normal scenarios...
1181 */
1183
1184 /*
1185 * allocate and initialize scan descriptor
1186 */
1187 if (flags & SO_TYPE_BITMAPSCAN)
1188 {
1190
1191 /*
1192 * Bitmap Heap scans do not have any fields that a normal Heap Scan
1193 * does not have, so no special initializations required here.
1194 */
1195 scan = (HeapScanDesc) bscan;
1196 }
1197 else
1199
1200 scan->rs_base.rs_rd = relation;
1201 scan->rs_base.rs_snapshot = snapshot;
1202 scan->rs_base.rs_nkeys = nkeys;
1203 scan->rs_base.rs_flags = flags;
1204 scan->rs_base.rs_parallel = parallel_scan;
1205 scan->rs_base.rs_instrument = NULL;
1206 scan->rs_strategy = NULL; /* set in initscan */
1207 scan->rs_cbuf = InvalidBuffer;
1208
1209 /*
1210 * Disable page-at-a-time mode if it's not a MVCC-safe snapshot.
1211 */
1212 if (!(snapshot && IsMVCCSnapshot(snapshot)))
1214
1215 /* Check that a historic snapshot is not used for non-catalog tables */
1216 if (snapshot &&
1217 IsHistoricMVCCSnapshot(snapshot) &&
1219 {
1220 ereport(ERROR,
1222 errmsg("cannot query non-catalog table \"%s\" during logical decoding",
1223 RelationGetRelationName(relation))));
1224 }
1225
1226 /*
1227 * For seqscan and sample scans in a serializable transaction, acquire a
1228 * predicate lock on the entire relation. This is required not only to
1229 * lock all the matching tuples, but also to conflict with new insertions
1230 * into the table. In an indexscan, we take page locks on the index pages
1231 * covering the range specified in the scan qual, but in a heap scan there
1232 * is nothing more fine-grained to lock. A bitmap scan is a different
1233 * story, there we have already scanned the index and locked the index
1234 * pages covering the predicate. But in that case we still have to lock
1235 * any matching heap tuples. For sample scan we could optimize the locking
1236 * to be at least page-level granularity, but we'd need to add per-tuple
1237 * locking for that.
1238 */
1240 {
1241 /*
1242 * Ensure a missing snapshot is noticed reliably, even if the
1243 * isolation mode means predicate locking isn't performed (and
1244 * therefore the snapshot isn't used here).
1245 */
1246 Assert(snapshot);
1247 PredicateLockRelation(relation, snapshot);
1248 }
1249
1250 /* we only need to set this up once */
1251 scan->rs_ctup.t_tableOid = RelationGetRelid(relation);
1252
1253 /*
1254 * Allocate memory to keep track of page allocation for parallel workers
1255 * when doing a parallel scan.
1256 */
1257 if (parallel_scan != NULL)
1259 else
1261
1262 /*
1263 * we do this here instead of in initscan() because heap_rescan also calls
1264 * initscan() and we don't want to allocate memory again
1265 */
1266 if (nkeys > 0)
1267 scan->rs_base.rs_key = palloc_array(ScanKeyData, nkeys);
1268 else
1269 scan->rs_base.rs_key = NULL;
1270
1271 initscan(scan, key, false);
1272
1273 scan->rs_read_stream = NULL;
1274
1275 /*
1276 * Set up a read stream for sequential scans and TID range scans. This
1277 * should be done after initscan() because initscan() allocates the
1278 * BufferAccessStrategy object passed to the read stream API.
1279 */
1280 if (scan->rs_base.rs_flags & SO_TYPE_SEQSCAN ||
1282 {
1284
1285 if (scan->rs_base.rs_parallel)
1287 else
1289
1290 /* ---
1291 * It is safe to use batchmode as the only locks taken by `cb`
1292 * are never taken while waiting for IO:
1293 * - SyncScanLock is used in the non-parallel case
1294 * - in the parallel case, only spinlocks and atomics are used
1295 * ---
1296 */
1299 scan->rs_strategy,
1300 scan->rs_base.rs_rd,
1302 cb,
1303 scan,
1304 0);
1305 }
1306 else if (scan->rs_base.rs_flags & SO_TYPE_BITMAPSCAN)
1307 {
1310 scan->rs_strategy,
1311 scan->rs_base.rs_rd,
1314 scan,
1315 sizeof(TBMIterateResult));
1316 }
1317
1318 /* enable read stream instrumentation */
1319 if ((flags & SO_SCAN_INSTRUMENT) && (scan->rs_read_stream != NULL))
1320 {
1323 &scan->rs_base.rs_instrument->io);
1324 }
1325
1326 scan->rs_vmbuffer = InvalidBuffer;
1327
1328 return (TableScanDesc) scan;
1329}

References Assert, bitmapheap_stream_read_next(), ereport, errcode(), errmsg, ERROR, fb(), heap_scan_stream_read_next_parallel(), heap_scan_stream_read_next_serial(), initscan(), InvalidBuffer, TableScanInstrumentation::io, IsHistoricMVCCSnapshot, IsMVCCSnapshot, MAIN_FORKNUM, palloc0_object, palloc_array, palloc_object, PredicateLockRelation(), read_stream_begin_relation(), READ_STREAM_DEFAULT, read_stream_enable_stats(), READ_STREAM_SEQUENTIAL, READ_STREAM_USE_BATCHING, RelationGetRelationName, RelationGetRelid, RelationIncrementReferenceCount(), RelationIsAccessibleInLogicalDecoding, HeapScanDescData::rs_base, HeapScanDescData::rs_cbuf, HeapScanDescData::rs_ctup, TableScanDescData::rs_flags, TableScanDescData::rs_instrument, TableScanDescData::rs_key, TableScanDescData::rs_nkeys, TableScanDescData::rs_parallel, HeapScanDescData::rs_parallelworkerdata, TableScanDescData::rs_rd, HeapScanDescData::rs_read_stream, TableScanDescData::rs_snapshot, HeapScanDescData::rs_strategy, HeapScanDescData::rs_vmbuffer, SO_SCAN_INSTRUMENT, SO_TYPE_BITMAPSCAN, SO_TYPE_SAMPLESCAN, SO_TYPE_SEQSCAN, SO_TYPE_TIDRANGESCAN, and HeapTupleData::t_tableOid.

◆ heap_delete()

TM_Result heap_delete ( Relation  relation,
const ItemPointerData tid,
CommandId  cid,
uint32  options,
Snapshot  crosscheck,
bool  wait,
TM_FailureData tmfd 
)

Definition at line 2759 of file heapam.c.

2762{
2765 ItemId lp;
2766 HeapTupleData tp;
2767 Page page;
2768 BlockNumber block;
2769 Buffer buffer;
2770 Buffer vmbuffer = InvalidBuffer;
2771 bool vmbuffer_modified = false;
2772 TransactionId new_xmax;
2777 bool have_tuple_lock = false;
2778 bool iscombo;
2779 bool clear_all_visible = false;
2780 HeapTuple old_key_tuple = NULL; /* replica identity of the tuple */
2781 bool old_key_copied = false;
2782
2784
2785 AssertHasSnapshotForToast(relation);
2786
2787 /*
2788 * Forbid this during a parallel operation, lest it allocate a combo CID.
2789 * Other workers might need that combo CID for visibility checks, and we
2790 * have no provision for broadcasting it to them.
2791 */
2792 if (IsInParallelMode())
2793 ereport(ERROR,
2795 errmsg("cannot delete tuples during a parallel operation")));
2796
2797 block = ItemPointerGetBlockNumber(tid);
2798 buffer = ReadBuffer(relation, block);
2799 page = BufferGetPage(buffer);
2800
2801 /*
2802 * Before locking the buffer, pin the visibility map page if it appears to
2803 * be necessary. Since we haven't got the lock yet, someone else might be
2804 * in the middle of changing this, so we'll need to recheck after we have
2805 * the lock.
2806 */
2807 if (PageIsAllVisible(page))
2808 visibilitymap_pin(relation, block, &vmbuffer);
2809
2811
2814
2815 tp.t_tableOid = RelationGetRelid(relation);
2816 tp.t_data = (HeapTupleHeader) PageGetItem(page, lp);
2817 tp.t_len = ItemIdGetLength(lp);
2818 tp.t_self = *tid;
2819
2820l1:
2821
2822 /*
2823 * If we didn't pin the visibility map page and the page has become all
2824 * visible while we were busy locking the buffer, we'll have to unlock and
2825 * re-lock, to avoid holding the buffer lock across an I/O. That's a bit
2826 * unfortunate, but hopefully shouldn't happen often.
2827 */
2828 if (vmbuffer == InvalidBuffer && PageIsAllVisible(page))
2829 {
2831 visibilitymap_pin(relation, block, &vmbuffer);
2833 }
2834
2835 result = HeapTupleSatisfiesUpdate(&tp, cid, buffer);
2836
2837 if (result == TM_Invisible)
2838 {
2839 UnlockReleaseBuffer(buffer);
2840 ereport(ERROR,
2842 errmsg("attempted to delete invisible tuple")));
2843 }
2844 else if (result == TM_BeingModified && wait)
2845 {
2848
2849 /* must copy state data before unlocking buffer */
2852
2853 /*
2854 * Sleep until concurrent transaction ends -- except when there's a
2855 * single locker and it's our own transaction. Note we don't care
2856 * which lock mode the locker has, because we need the strongest one.
2857 *
2858 * Before sleeping, we need to acquire tuple lock to establish our
2859 * priority for the tuple (see heap_lock_tuple). LockTuple will
2860 * release us when we are next-in-line for the tuple.
2861 *
2862 * If we are forced to "start over" below, we keep the tuple lock;
2863 * this arranges that we stay at the head of the line while rechecking
2864 * tuple state.
2865 */
2867 {
2868 bool current_is_member = false;
2869
2872 {
2874
2875 /*
2876 * Acquire the lock, if necessary (but skip it when we're
2877 * requesting a lock and already have one; avoids deadlock).
2878 */
2879 if (!current_is_member)
2882
2883 /* wait for multixact */
2885 relation, &(tp.t_self), XLTW_Delete,
2886 NULL);
2888
2889 /*
2890 * If xwait had just locked the tuple then some other xact
2891 * could update this tuple before we get to this point. Check
2892 * for xmax change, and start over if so.
2893 *
2894 * We also must start over if we didn't pin the VM page, and
2895 * the page has become all visible.
2896 */
2897 if ((vmbuffer == InvalidBuffer && PageIsAllVisible(page)) ||
2900 xwait))
2901 goto l1;
2902 }
2903
2904 /*
2905 * You might think the multixact is necessarily done here, but not
2906 * so: it could have surviving members, namely our own xact or
2907 * other subxacts of this backend. It is legal for us to delete
2908 * the tuple in either case, however (the latter case is
2909 * essentially a situation of upgrading our former shared lock to
2910 * exclusive). We don't bother changing the on-disk hint bits
2911 * since we are about to overwrite the xmax altogether.
2912 */
2913 }
2915 {
2916 /*
2917 * Wait for regular transaction to end; but first, acquire tuple
2918 * lock.
2919 */
2923 XactLockTableWait(xwait, relation, &(tp.t_self), XLTW_Delete);
2925
2926 /*
2927 * xwait is done, but if xwait had just locked the tuple then some
2928 * other xact could update this tuple before we get to this point.
2929 * Check for xmax change, and start over if so.
2930 *
2931 * We also must start over if we didn't pin the VM page, and the
2932 * page has become all visible.
2933 */
2934 if ((vmbuffer == InvalidBuffer && PageIsAllVisible(page)) ||
2937 xwait))
2938 goto l1;
2939
2940 /* Otherwise check if it committed or aborted */
2941 UpdateXmaxHintBits(tp.t_data, buffer, xwait);
2942 }
2943
2944 /*
2945 * We may overwrite if previous xmax aborted, or if it committed but
2946 * only locked the tuple without updating it.
2947 */
2948 if ((tp.t_data->t_infomask & HEAP_XMAX_INVALID) ||
2951 result = TM_Ok;
2952 else if (!ItemPointerEquals(&tp.t_self, &tp.t_data->t_ctid))
2954 else
2956 }
2957
2958 /* sanity check the result HeapTupleSatisfiesUpdate() and the logic above */
2959 if (result != TM_Ok)
2960 {
2962 result == TM_Updated ||
2963 result == TM_Deleted ||
2968 }
2969
2971 {
2972 /* Perform additional check for transaction-snapshot mode RI updates */
2973 if (!HeapTupleSatisfiesVisibility(&tp, crosscheck, buffer))
2975 }
2976
2977 if (result != TM_Ok)
2978 {
2979 tmfd->ctid = tp.t_data->t_ctid;
2981 if (result == TM_SelfModified)
2983 else
2984 tmfd->cmax = InvalidCommandId;
2985 UnlockReleaseBuffer(buffer);
2986 if (have_tuple_lock)
2988 if (vmbuffer != InvalidBuffer)
2989 ReleaseBuffer(vmbuffer);
2990 return result;
2991 }
2992
2993 /*
2994 * We're about to do the actual delete -- check for conflict first, to
2995 * avoid possibly having to roll back work we've just done.
2996 *
2997 * This is safe without a recheck as long as there is no possibility of
2998 * another process scanning the page between this check and the delete
2999 * being visible to the scan (i.e., an exclusive buffer content lock is
3000 * continuously held from this point until the tuple delete is visible).
3001 */
3003
3004 /* replace cid with a combo CID if necessary */
3006
3007 /*
3008 * Compute replica identity tuple before entering the critical section so
3009 * we don't PANIC upon a memory allocation failure.
3010 */
3012 ExtractReplicaIdentity(relation, &tp, true, &old_key_copied) : NULL;
3013
3014 /*
3015 * If this is the first possibly-multixact-able operation in the current
3016 * transaction, set my per-backend OldestMemberMXactId setting. We can be
3017 * certain that the transaction will never become a member of any older
3018 * MultiXactIds than that. (We have to do this even if we end up just
3019 * using our own TransactionId below, since some other backend could
3020 * incorporate our XID into a MultiXact immediately afterwards.)
3021 */
3023
3026 xid, LockTupleExclusive, true,
3027 &new_xmax, &new_infomask, &new_infomask2);
3028
3029 /* Lock the VM before entering the critical section */
3030 if (PageIsAllVisible(page))
3031 {
3032 clear_all_visible = true;
3034 }
3035
3037
3038 /*
3039 * If this transaction commits, the tuple will become DEAD sooner or
3040 * later. Set flag that this page is a candidate for pruning once our xid
3041 * falls below the OldestXmin horizon. If the transaction finally aborts,
3042 * the subsequent page pruning will be a no-op and the hint will be
3043 * cleared.
3044 */
3045 PageSetPrunable(page, xid);
3046
3048 {
3049 /* It's possible the VM bits were already clear */
3051 vmbuffer, VISIBILITYMAP_VALID_BITS))
3052 vmbuffer_modified = true;
3053
3054 PageClearAllVisible(page);
3055 }
3056
3057 /* store transaction information of xact deleting the tuple */
3063 HeapTupleHeaderSetXmax(tp.t_data, new_xmax);
3065 /* Make sure there is no forward chain link in t_ctid */
3066 tp.t_data->t_ctid = tp.t_self;
3067
3068 /* Signal that this is actually a move into another partition */
3069 if (changingPart)
3071
3072 MarkBufferDirty(buffer);
3073
3074 /*
3075 * XLOG stuff
3076 *
3077 * NB: heap_abort_speculative() uses the same xlog record and replay
3078 * routines.
3079 */
3080 if (RelationNeedsWAL(relation))
3081 {
3085
3086 /*
3087 * For logical decode we need combo CIDs to properly decode the
3088 * catalog
3089 */
3091 log_heap_new_cid(relation, &tp);
3092
3093 xlrec.flags = 0;
3096 if (changingPart)
3098 xlrec.infobits_set = compute_infobits(tp.t_data->t_infomask,
3099 tp.t_data->t_infomask2);
3101 xlrec.xmax = new_xmax;
3102
3103 if (old_key_tuple != NULL)
3104 {
3105 if (relation->rd_rel->relreplident == REPLICA_IDENTITY_FULL)
3107 else
3109 }
3110
3111 /*
3112 * Mark the change as not-for-logical-decoding if caller requested so.
3113 *
3114 * (This is used for changes that affect relations not visible to
3115 * other transactions, such as the transient table during concurrent
3116 * repack.)
3117 */
3118 if (!walLogical)
3120
3123
3125
3126 /*
3127 * Log replica identity of the deleted tuple if there is one
3128 */
3129 if (old_key_tuple != NULL)
3130 {
3131 xlhdr.t_infomask2 = old_key_tuple->t_data->t_infomask2;
3132 xlhdr.t_infomask = old_key_tuple->t_data->t_infomask;
3133 xlhdr.t_hoff = old_key_tuple->t_data->t_hoff;
3134
3136 XLogRegisterData((char *) old_key_tuple->t_data
3138 old_key_tuple->t_len
3140 }
3141
3142 /* filtering by origin on a row level is much more efficient */
3144
3147
3149
3150 PageSetLSN(page, recptr);
3151
3153 PageSetLSN(BufferGetPage(vmbuffer), recptr);
3154 }
3155
3157
3158 /*
3159 * Release VM lock first, since it covers many heap blocks. We locked
3160 * vmbuffer if clear_all_visible was true regardless of whether or not we
3161 * ended up modifying the vmbuffer.
3162 */
3164 LockBuffer(vmbuffer, BUFFER_LOCK_UNLOCK);
3165
3167
3168 if (vmbuffer != InvalidBuffer)
3169 ReleaseBuffer(vmbuffer);
3170
3171 /*
3172 * If the tuple has toasted out-of-line attributes, we need to delete
3173 * those items too. We have to do this before releasing the buffer
3174 * because we need to look at the contents of the tuple, but it's OK to
3175 * release the content lock on the buffer first.
3176 */
3177 if (relation->rd_rel->relkind != RELKIND_RELATION &&
3178 relation->rd_rel->relkind != RELKIND_MATVIEW)
3179 {
3180 /* toast table entries should never be recursively toasted */
3182 }
3183 else if (HeapTupleHasExternal(&tp))
3184 heap_toast_delete(relation, &tp, false);
3185
3186 /*
3187 * Mark tuple for invalidation from system caches at next command
3188 * boundary. We have to do this before releasing the buffer because we
3189 * need to look at the contents of the tuple.
3190 */
3191 CacheInvalidateHeapTuple(relation, &tp, NULL);
3192
3193 /* Now we can release the buffer */
3194 ReleaseBuffer(buffer);
3195
3196 /*
3197 * Release the lmgr tuple lock, if we had it.
3198 */
3199 if (have_tuple_lock)
3201
3202 pgstat_count_heap_delete(relation);
3203
3206
3207 return TM_Ok;
3208}

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

Referenced by heapam_tuple_delete(), and simple_heap_delete().

◆ heap_endscan()

void heap_endscan ( TableScanDesc  sscan)

Definition at line 1391 of file heapam.c.

1392{
1394
1395 /* Note: no locking manipulations needed */
1396
1397 /*
1398 * unpin scan buffers
1399 */
1400 if (BufferIsValid(scan->rs_cbuf))
1401 ReleaseBuffer(scan->rs_cbuf);
1402
1403 if (BufferIsValid(scan->rs_vmbuffer))
1405
1406 /*
1407 * Must free the read stream before freeing the BufferAccessStrategy.
1408 */
1409 if (scan->rs_read_stream)
1411
1412 /*
1413 * decrement relation reference count and free scan descriptor storage
1414 */
1416
1417 if (scan->rs_base.rs_key)
1418 pfree(scan->rs_base.rs_key);
1419
1420 if (scan->rs_strategy != NULL)
1422
1423 if (scan->rs_parallelworkerdata != NULL)
1425
1426 if (scan->rs_base.rs_flags & SO_TEMP_SNAPSHOT)
1428
1429 if (scan->rs_base.rs_instrument)
1431
1432 pfree(scan);
1433}

References BufferIsValid(), fb(), FreeAccessStrategy(), pfree(), read_stream_end(), RelationDecrementReferenceCount(), ReleaseBuffer(), HeapScanDescData::rs_base, HeapScanDescData::rs_cbuf, TableScanDescData::rs_flags, TableScanDescData::rs_instrument, TableScanDescData::rs_key, HeapScanDescData::rs_parallelworkerdata, TableScanDescData::rs_rd, HeapScanDescData::rs_read_stream, TableScanDescData::rs_snapshot, HeapScanDescData::rs_strategy, HeapScanDescData::rs_vmbuffer, SO_TEMP_SNAPSHOT, and UnregisterSnapshot().

◆ heap_fetch()

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

Definition at line 1685 of file heapam.c.

1690{
1691 ItemPointer tid = &(tuple->t_self);
1692 ItemId lp;
1693 Buffer buffer;
1694 Page page;
1695 OffsetNumber offnum;
1696 bool valid;
1697
1698 /*
1699 * Fetch and pin the appropriate page of the relation.
1700 */
1701 buffer = ReadBuffer(relation, ItemPointerGetBlockNumber(tid));
1702
1703 /*
1704 * Need share lock on buffer to examine tuple commit status.
1705 */
1707 page = BufferGetPage(buffer);
1708
1709 /*
1710 * We'd better check for out-of-range offnum in case of VACUUM since the
1711 * TID was obtained.
1712 */
1713 offnum = ItemPointerGetOffsetNumber(tid);
1715 {
1716 UnlockReleaseBuffer(buffer);
1718 tuple->t_data = NULL;
1719 return false;
1720 }
1721
1722 /*
1723 * get the item line pointer corresponding to the requested tid
1724 */
1725 lp = PageGetItemId(page, offnum);
1726
1727 /*
1728 * Must check for deleted tuple.
1729 */
1730 if (!ItemIdIsNormal(lp))
1731 {
1732 UnlockReleaseBuffer(buffer);
1734 tuple->t_data = NULL;
1735 return false;
1736 }
1737
1738 /*
1739 * fill in *tuple fields
1740 */
1741 tuple->t_data = (HeapTupleHeader) PageGetItem(page, lp);
1742 tuple->t_len = ItemIdGetLength(lp);
1743 tuple->t_tableOid = RelationGetRelid(relation);
1744
1745 /*
1746 * check tuple visibility, then release lock
1747 */
1748 valid = HeapTupleSatisfiesVisibility(tuple, snapshot, buffer);
1749
1750 if (valid)
1751 PredicateLockTID(relation, &(tuple->t_self), snapshot,
1753
1754 HeapCheckForSerializableConflictOut(valid, relation, tuple, buffer, snapshot);
1755
1757
1758 if (valid)
1759 {
1760 /*
1761 * All checks passed, so return the tuple as valid. Caller is now
1762 * responsible for releasing the buffer.
1763 */
1764 *userbuf = buffer;
1765
1766 return true;
1767 }
1768
1769 /* Tuple failed time qual, but maybe caller wants to see it anyway. */
1770 if (keep_buf)
1771 *userbuf = buffer;
1772 else
1773 {
1774 ReleaseBuffer(buffer);
1776 tuple->t_data = NULL;
1777 }
1778
1779 return false;
1780}

References BUFFER_LOCK_SHARE, BUFFER_LOCK_UNLOCK, BufferGetPage(), fb(), HeapCheckForSerializableConflictOut(), HeapTupleHeaderGetXmin(), HeapTupleSatisfiesVisibility(), InvalidBuffer, ItemIdGetLength, ItemIdIsNormal, ItemPointerGetBlockNumber(), ItemPointerGetOffsetNumber(), LockBuffer(), PageGetItem(), PageGetItemId(), PageGetMaxOffsetNumber(), PredicateLockTID(), ReadBuffer(), RelationGetRelid, ReleaseBuffer(), HeapTupleData::t_data, HeapTupleData::t_len, HeapTupleData::t_self, HeapTupleData::t_tableOid, and UnlockReleaseBuffer().

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

◆ heap_fetch_next_buffer()

static void heap_fetch_next_buffer ( HeapScanDesc  scan,
ScanDirection  dir 
)
inlinestatic

Definition at line 711 of file heapam.c.

712{
713 Assert(scan->rs_read_stream);
714
715 /* release previous scan buffer, if any */
716 if (BufferIsValid(scan->rs_cbuf))
717 {
718 ReleaseBuffer(scan->rs_cbuf);
719 scan->rs_cbuf = InvalidBuffer;
720 }
721
722 /*
723 * Be sure to check for interrupts at least once per page. Checks at
724 * higher code levels won't be able to stop a seqscan that encounters many
725 * pages' worth of consecutive dead tuples.
726 */
728
729 /*
730 * If the scan direction is changing, reset the prefetch block to the
731 * current block. Otherwise, we will incorrectly prefetch the blocks
732 * between the prefetch block and the current block again before
733 * prefetching blocks in the new, correct scan direction.
734 */
735 if (unlikely(scan->rs_dir != dir))
736 {
737 scan->rs_prefetch_block = scan->rs_cblock;
739 }
740
741 scan->rs_dir = dir;
742
744 if (BufferIsValid(scan->rs_cbuf))
746}

References Assert, BufferGetBlockNumber(), BufferIsValid(), CHECK_FOR_INTERRUPTS, fb(), InvalidBuffer, read_stream_next_buffer(), read_stream_reset(), ReleaseBuffer(), HeapScanDescData::rs_cblock, HeapScanDescData::rs_cbuf, HeapScanDescData::rs_dir, HeapScanDescData::rs_prefetch_block, HeapScanDescData::rs_read_stream, and unlikely.

Referenced by heapgettup(), and heapgettup_pagemode().

◆ heap_finish_speculative()

void heap_finish_speculative ( Relation  relation,
const ItemPointerData tid 
)

Definition at line 6303 of file heapam.c.

6304{
6305 Buffer buffer;
6306 Page page;
6307 OffsetNumber offnum;
6308 ItemId lp;
6309 HeapTupleHeader htup;
6310
6311 buffer = ReadBuffer(relation, ItemPointerGetBlockNumber(tid));
6313 page = BufferGetPage(buffer);
6314
6315 offnum = ItemPointerGetOffsetNumber(tid);
6317 elog(ERROR, "offnum out of range");
6318 lp = PageGetItemId(page, offnum);
6319 if (!ItemIdIsNormal(lp))
6320 elog(ERROR, "invalid lp");
6321
6322 htup = (HeapTupleHeader) PageGetItem(page, lp);
6323
6324 /* NO EREPORT(ERROR) from here till changes are logged */
6326
6328
6329 MarkBufferDirty(buffer);
6330
6331 /*
6332 * Replace the speculative insertion token with a real t_ctid, pointing to
6333 * itself like it does on regular tuples.
6334 */
6335 htup->t_ctid = *tid;
6336
6337 /* XLOG stuff */
6338 if (RelationNeedsWAL(relation))
6339 {
6342
6344
6346
6347 /* We want the same filtering on this as on a plain insert */
6349
6352
6354
6355 PageSetLSN(page, recptr);
6356 }
6357
6359
6360 UnlockReleaseBuffer(buffer);
6361}

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

Referenced by heapam_tuple_complete_speculative().

◆ heap_freeze_prepared_tuples()

void heap_freeze_prepared_tuples ( Buffer  buffer,
HeapTupleFreeze tuples,
int  ntuples 
)

Definition at line 7600 of file heapam.c.

7601{
7602 Page page = BufferGetPage(buffer);
7603
7604 for (int i = 0; i < ntuples; i++)
7605 {
7606 HeapTupleFreeze *frz = tuples + i;
7607 ItemId itemid = PageGetItemId(page, frz->offset);
7608 HeapTupleHeader htup;
7609
7610 htup = (HeapTupleHeader) PageGetItem(page, itemid);
7612 }
7613}

References BufferGetPage(), fb(), heap_execute_freeze_tuple(), i, PageGetItem(), and PageGetItemId().

Referenced by heap_page_prune_and_freeze().

◆ heap_freeze_tuple()

bool heap_freeze_tuple ( HeapTupleHeader  tuple,
TransactionId  relfrozenxid,
TransactionId  relminmxid,
TransactionId  FreezeLimit,
TransactionId  MultiXactCutoff 
)

Definition at line 7622 of file heapam.c.

7625{
7627 bool do_freeze;
7628 bool totally_frozen;
7629 struct VacuumCutoffs cutoffs;
7630 HeapPageFreeze pagefrz;
7631
7632 cutoffs.relfrozenxid = relfrozenxid;
7633 cutoffs.relminmxid = relminmxid;
7634 cutoffs.OldestXmin = FreezeLimit;
7635 cutoffs.OldestMxact = MultiXactCutoff;
7636 cutoffs.FreezeLimit = FreezeLimit;
7637 cutoffs.MultiXactCutoff = MultiXactCutoff;
7638
7639 pagefrz.freeze_required = true;
7640 pagefrz.FreezePageRelfrozenXid = FreezeLimit;
7641 pagefrz.FreezePageRelminMxid = MultiXactCutoff;
7642 pagefrz.FreezePageConflictXid = InvalidTransactionId;
7643 pagefrz.NoFreezePageRelfrozenXid = FreezeLimit;
7644 pagefrz.NoFreezePageRelminMxid = MultiXactCutoff;
7645
7646 do_freeze = heap_prepare_freeze_tuple(tuple, &cutoffs,
7647 &pagefrz, &frz, &totally_frozen);
7648
7649 /*
7650 * Note that because this is not a WAL-logged operation, we don't need to
7651 * fill in the offset in the freeze record.
7652 */
7653
7654 if (do_freeze)
7656 return do_freeze;
7657}

References fb(), VacuumCutoffs::FreezeLimit, heap_execute_freeze_tuple(), heap_prepare_freeze_tuple(), InvalidTransactionId, VacuumCutoffs::MultiXactCutoff, VacuumCutoffs::OldestMxact, VacuumCutoffs::OldestXmin, VacuumCutoffs::relfrozenxid, and VacuumCutoffs::relminmxid.

Referenced by rewrite_heap_tuple().

◆ heap_get_latest_tid()

void heap_get_latest_tid ( TableScanDesc  sscan,
ItemPointer  tid 
)

Definition at line 1794 of file heapam.c.

1796{
1797 Relation relation = sscan->rs_rd;
1798 Snapshot snapshot = sscan->rs_snapshot;
1799 ItemPointerData ctid;
1801
1802 /*
1803 * table_tuple_get_latest_tid() verified that the passed in tid is valid.
1804 * Assume that t_ctid links are valid however - there shouldn't be invalid
1805 * ones in the table.
1806 */
1808
1809 /*
1810 * Loop to chase down t_ctid links. At top of loop, ctid is the tuple we
1811 * need to examine, and *tid is the TID we will return if ctid turns out
1812 * to be bogus.
1813 *
1814 * Note that we will loop until we reach the end of the t_ctid chain.
1815 * Depending on the snapshot passed, there might be at most one visible
1816 * version of the row, but we don't try to optimize for that.
1817 */
1818 ctid = *tid;
1819 priorXmax = InvalidTransactionId; /* cannot check first XMIN */
1820 for (;;)
1821 {
1822 Buffer buffer;
1823 Page page;
1824 OffsetNumber offnum;
1825 ItemId lp;
1826 HeapTupleData tp;
1827 bool valid;
1828
1829 /*
1830 * Read, pin, and lock the page.
1831 */
1832 buffer = ReadBuffer(relation, ItemPointerGetBlockNumber(&ctid));
1834 page = BufferGetPage(buffer);
1835
1836 /*
1837 * Check for bogus item number. This is not treated as an error
1838 * condition because it can happen while following a t_ctid link. We
1839 * just assume that the prior tid is OK and return it unchanged.
1840 */
1841 offnum = ItemPointerGetOffsetNumber(&ctid);
1843 {
1844 UnlockReleaseBuffer(buffer);
1845 break;
1846 }
1847 lp = PageGetItemId(page, offnum);
1848 if (!ItemIdIsNormal(lp))
1849 {
1850 UnlockReleaseBuffer(buffer);
1851 break;
1852 }
1853
1854 /* OK to access the tuple */
1855 tp.t_self = ctid;
1856 tp.t_data = (HeapTupleHeader) PageGetItem(page, lp);
1857 tp.t_len = ItemIdGetLength(lp);
1858 tp.t_tableOid = RelationGetRelid(relation);
1859
1860 /*
1861 * After following a t_ctid link, we might arrive at an unrelated
1862 * tuple. Check for XMIN match.
1863 */
1866 {
1867 UnlockReleaseBuffer(buffer);
1868 break;
1869 }
1870
1871 /*
1872 * Check tuple visibility; if visible, set it as the new result
1873 * candidate.
1874 */
1875 valid = HeapTupleSatisfiesVisibility(&tp, snapshot, buffer);
1876 HeapCheckForSerializableConflictOut(valid, relation, &tp, buffer, snapshot);
1877 if (valid)
1878 *tid = ctid;
1879
1880 /*
1881 * If there's a valid t_ctid link, follow it, else we're done.
1882 */
1883 if ((tp.t_data->t_infomask & HEAP_XMAX_INVALID) ||
1887 {
1888 UnlockReleaseBuffer(buffer);
1889 break;
1890 }
1891
1892 ctid = tp.t_data->t_ctid;
1894 UnlockReleaseBuffer(buffer);
1895 } /* end of loop */
1896}

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

◆ heap_getnext()

HeapTuple heap_getnext ( TableScanDesc  sscan,
ScanDirection  direction 
)

Definition at line 1436 of file heapam.c.

1437{
1439
1440 /*
1441 * This is still widely used directly, without going through table AM, so
1442 * add a safety check. It's possible we should, at a later point,
1443 * downgrade this to an assert. The reason for checking the AM routine,
1444 * rather than the AM oid, is that this allows to write regression tests
1445 * that create another AM reusing the heap handler.
1446 */
1447 if (unlikely(sscan->rs_rd->rd_tableam != GetHeapamTableAmRoutine()))
1448 ereport(ERROR,
1450 errmsg_internal("only heap AM is supported")));
1451
1452 /* Note: no locking manipulations needed */
1453
1455 heapgettup_pagemode(scan, direction,
1456 scan->rs_base.rs_nkeys, scan->rs_base.rs_key);
1457 else
1458 heapgettup(scan, direction,
1459 scan->rs_base.rs_nkeys, scan->rs_base.rs_key);
1460
1461 if (scan->rs_ctup.t_data == NULL)
1462 return NULL;
1463
1464 /*
1465 * if we get here it means we have a new current scan tuple, so point to
1466 * the proper return buffer and return the tuple.
1467 */
1468
1470
1471 return &scan->rs_ctup;
1472}

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

Referenced by AlterTableMoveAll(), AlterTableSpaceOptions(), BuildDatabaseList(), BuildRelationList(), check_db_file_conflict(), CreateDatabaseUsingFileCopy(), do_autovacuum(), DropSetting(), DropTableSpace(), find_typed_table_dependencies(), get_all_vacuum_rels(), get_database_list(), get_subscription_list(), get_tables_to_repack(), get_tablespace_name(), get_tablespace_oid(), GetAllPublicationRelations(), getRelationsInNamespace(), GetSchemaPublicationRelations(), heapam_index_build_range_scan(), heapam_index_validate_scan(), objectsInSchemaToOids(), pg_stat_get_autovacuum_scores(), pgrowlocks(), pgstat_heap(), populate_typ_list(), ReindexMultipleTables(), remove_dbtablespaces(), RemoveSubscriptionRel(), RenameTableSpace(), ThereIsAtLeastOneRole(), and vac_truncate_clog().

◆ heap_getnextslot()

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

Definition at line 1475 of file heapam.c.

1476{
1478
1479 /* Note: no locking manipulations needed */
1480
1481 if (sscan->rs_flags & SO_ALLOW_PAGEMODE)
1482 heapgettup_pagemode(scan, direction, sscan->rs_nkeys, sscan->rs_key);
1483 else
1484 heapgettup(scan, direction, sscan->rs_nkeys, sscan->rs_key);
1485
1486 if (scan->rs_ctup.t_data == NULL)
1487 {
1488 ExecClearTuple(slot);
1489 return false;
1490 }
1491
1492 /*
1493 * if we get here it means we have a new current scan tuple, so point to
1494 * the proper return buffer and return the tuple.
1495 */
1496
1498
1499 ExecStoreBufferHeapTuple(&scan->rs_ctup, slot,
1500 scan->rs_cbuf);
1501 return true;
1502}

References ExecClearTuple(), ExecStoreBufferHeapTuple(), fb(), heapgettup(), heapgettup_pagemode(), pgstat_count_heap_getnext, HeapScanDescData::rs_base, HeapScanDescData::rs_cbuf, HeapScanDescData::rs_ctup, TableScanDescData::rs_rd, SO_ALLOW_PAGEMODE, and HeapTupleData::t_data.

◆ heap_getnextslot_tidrange()

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

Definition at line 1578 of file heapam.c.

1580{
1582 ItemPointer mintid = &sscan->st.tidrange.rs_mintid;
1583 ItemPointer maxtid = &sscan->st.tidrange.rs_maxtid;
1584
1585 /* Note: no locking manipulations needed */
1586 for (;;)
1587 {
1588 if (sscan->rs_flags & SO_ALLOW_PAGEMODE)
1589 heapgettup_pagemode(scan, direction, sscan->rs_nkeys, sscan->rs_key);
1590 else
1591 heapgettup(scan, direction, sscan->rs_nkeys, sscan->rs_key);
1592
1593 if (scan->rs_ctup.t_data == NULL)
1594 {
1595 ExecClearTuple(slot);
1596 return false;
1597 }
1598
1599 /*
1600 * heap_set_tidrange will have used heap_setscanlimits to limit the
1601 * range of pages we scan to only ones that can contain the TID range
1602 * we're scanning for. Here we must filter out any tuples from these
1603 * pages that are outside of that range.
1604 */
1605 if (ItemPointerCompare(&scan->rs_ctup.t_self, mintid) < 0)
1606 {
1607 ExecClearTuple(slot);
1608
1609 /*
1610 * When scanning backwards, the TIDs will be in descending order.
1611 * Future tuples in this direction will be lower still, so we can
1612 * just return false to indicate there will be no more tuples.
1613 */
1614 if (ScanDirectionIsBackward(direction))
1615 return false;
1616
1617 continue;
1618 }
1619
1620 /*
1621 * Likewise for the final page, we must filter out TIDs greater than
1622 * maxtid.
1623 */
1624 if (ItemPointerCompare(&scan->rs_ctup.t_self, maxtid) > 0)
1625 {
1626 ExecClearTuple(slot);
1627
1628 /*
1629 * When scanning forward, the TIDs will be in ascending order.
1630 * Future tuples in this direction will be higher still, so we can
1631 * just return false to indicate there will be no more tuples.
1632 */
1633 if (ScanDirectionIsForward(direction))
1634 return false;
1635 continue;
1636 }
1637
1638 break;
1639 }
1640
1641 /*
1642 * if we get here it means we have a new current scan tuple, so point to
1643 * the proper return buffer and return the tuple.
1644 */
1646
1647 ExecStoreBufferHeapTuple(&scan->rs_ctup, slot, scan->rs_cbuf);
1648 return true;
1649}

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

◆ heap_index_delete_tuples()

TransactionId heap_index_delete_tuples ( Relation  rel,
TM_IndexDeleteOp delstate 
)

Definition at line 8339 of file heapam.c.

8340{
8341 /* Initial assumption is that earlier pruning took care of conflict */
8342 TransactionId snapshotConflictHorizon = InvalidTransactionId;
8345 Page page = NULL;
8348#ifdef USE_PREFETCH
8351#endif
8353 int finalndeltids = 0,
8354 nblocksaccessed = 0;
8355
8356 /* State that's only used in bottom-up index deletion case */
8357 int nblocksfavorable = 0;
8358 int curtargetfreespace = delstate->bottomupfreespace,
8359 lastfreespace = 0,
8360 actualfreespace = 0;
8361 bool bottomup_final_block = false;
8362
8364
8365 /* Sort caller's deltids array by TID for further processing */
8367
8368 /*
8369 * Bottom-up case: resort deltids array in an order attuned to where the
8370 * greatest number of promising TIDs are to be found, and determine how
8371 * many blocks from the start of sorted array should be considered
8372 * favorable. This will also shrink the deltids array in order to
8373 * eliminate completely unfavorable blocks up front.
8374 */
8375 if (delstate->bottomup)
8377
8378#ifdef USE_PREFETCH
8379 /* Initialize prefetch state. */
8381 prefetch_state.next_item = 0;
8382 prefetch_state.ndeltids = delstate->ndeltids;
8383 prefetch_state.deltids = delstate->deltids;
8384
8385 /*
8386 * Determine the prefetch distance that we will attempt to maintain.
8387 *
8388 * Since the caller holds a buffer lock somewhere in rel, we'd better make
8389 * sure that isn't a catalog relation before we call code that does
8390 * syscache lookups, to avoid risk of deadlock.
8391 */
8392 if (IsCatalogRelation(rel))
8394 else
8397
8398 /* Cap initial prefetch distance for bottom-up deletion caller */
8399 if (delstate->bottomup)
8400 {
8404 }
8405
8406 /* Start prefetching. */
8408#endif
8409
8410 /* Iterate over deltids, determine which to delete, check their horizon */
8411 Assert(delstate->ndeltids > 0);
8412 for (int i = 0; i < delstate->ndeltids; i++)
8413 {
8414 TM_IndexDelete *ideltid = &delstate->deltids[i];
8415 TM_IndexStatus *istatus = delstate->status + ideltid->id;
8416 ItemPointer htid = &ideltid->tid;
8417 OffsetNumber offnum;
8418
8419 /*
8420 * Read buffer, and perform required extra steps each time a new block
8421 * is encountered. Avoid refetching if it's the same block as the one
8422 * from the last htid.
8423 */
8424 if (blkno == InvalidBlockNumber ||
8426 {
8427 /*
8428 * Consider giving up early for bottom-up index deletion caller
8429 * first. (Only prefetch next-next block afterwards, when it
8430 * becomes clear that we're at least going to access the next
8431 * block in line.)
8432 *
8433 * Sometimes the first block frees so much space for bottom-up
8434 * caller that the deletion process can end without accessing any
8435 * more blocks. It is usually necessary to access 2 or 3 blocks
8436 * per bottom-up deletion operation, though.
8437 */
8438 if (delstate->bottomup)
8439 {
8440 /*
8441 * We often allow caller to delete a few additional items
8442 * whose entries we reached after the point that space target
8443 * from caller was satisfied. The cost of accessing the page
8444 * was already paid at that point, so it made sense to finish
8445 * it off. When that happened, we finalize everything here
8446 * (by finishing off the whole bottom-up deletion operation
8447 * without needlessly paying the cost of accessing any more
8448 * blocks).
8449 */
8451 break;
8452
8453 /*
8454 * Give up when we didn't enable our caller to free any
8455 * additional space as a result of processing the page that we
8456 * just finished up with. This rule is the main way in which
8457 * we keep the cost of bottom-up deletion under control.
8458 */
8460 break;
8461 lastfreespace = actualfreespace; /* for next time */
8462
8463 /*
8464 * Deletion operation (which is bottom-up) will definitely
8465 * access the next block in line. Prepare for that now.
8466 *
8467 * Decay target free space so that we don't hang on for too
8468 * long with a marginal case. (Space target is only truly
8469 * helpful when it allows us to recognize that we don't need
8470 * to access more than 1 or 2 blocks to satisfy caller due to
8471 * agreeable workload characteristics.)
8472 *
8473 * We are a bit more patient when we encounter contiguous
8474 * blocks, though: these are treated as favorable blocks. The
8475 * decay process is only applied when the next block in line
8476 * is not a favorable/contiguous block. This is not an
8477 * exception to the general rule; we still insist on finding
8478 * at least one deletable item per block accessed. See
8479 * bottomup_nblocksfavorable() for full details of the theory
8480 * behind favorable blocks and heap block locality in general.
8481 *
8482 * Note: The first block in line is always treated as a
8483 * favorable block, so the earliest possible point that the
8484 * decay can be applied is just before we access the second
8485 * block in line. The Assert() verifies this for us.
8486 */
8488 if (nblocksfavorable > 0)
8490 else
8491 curtargetfreespace /= 2;
8492 }
8493
8494 /* release old buffer */
8495 if (BufferIsValid(buf))
8497
8499 buf = ReadBuffer(rel, blkno);
8501 Assert(!delstate->bottomup ||
8503
8504#ifdef USE_PREFETCH
8505
8506 /*
8507 * To maintain the prefetch distance, prefetch one more page for
8508 * each page we read.
8509 */
8511#endif
8512
8514
8515 page = BufferGetPage(buf);
8516 maxoff = PageGetMaxOffsetNumber(page);
8517 }
8518
8519 /*
8520 * In passing, detect index corruption involving an index page with a
8521 * TID that points to a location in the heap that couldn't possibly be
8522 * correct. We only do this with actual TIDs from caller's index page
8523 * (not items reached by traversing through a HOT chain).
8524 */
8526
8527 if (istatus->knowndeletable)
8528 Assert(!delstate->bottomup && !istatus->promising);
8529 else
8530 {
8531 ItemPointerData tmp = *htid;
8533
8534 /* Are any tuples from this HOT chain non-vacuumable? */
8536 &heapTuple, NULL, true))
8537 continue; /* can't delete entry */
8538
8539 /* Caller will delete, since whole HOT chain is vacuumable */
8540 istatus->knowndeletable = true;
8541
8542 /* Maintain index free space info for bottom-up deletion case */
8543 if (delstate->bottomup)
8544 {
8545 Assert(istatus->freespace > 0);
8546 actualfreespace += istatus->freespace;
8548 bottomup_final_block = true;
8549 }
8550 }
8551
8552 /*
8553 * Maintain snapshotConflictHorizon value for deletion operation as a
8554 * whole by advancing current value using heap tuple headers. This is
8555 * loosely based on the logic for pruning a HOT chain.
8556 */
8558 priorXmax = InvalidTransactionId; /* cannot check first XMIN */
8559 for (;;)
8560 {
8561 ItemId lp;
8562 HeapTupleHeader htup;
8563
8564 /* Sanity check (pure paranoia) */
8565 if (offnum < FirstOffsetNumber)
8566 break;
8567
8568 /*
8569 * An offset past the end of page's line pointer array is possible
8570 * when the array was truncated
8571 */
8572 if (offnum > maxoff)
8573 break;
8574
8575 lp = PageGetItemId(page, offnum);
8577 {
8578 offnum = ItemIdGetRedirect(lp);
8579 continue;
8580 }
8581
8582 /*
8583 * We'll often encounter LP_DEAD line pointers (especially with an
8584 * entry marked knowndeletable by our caller up front). No heap
8585 * tuple headers get examined for an htid that leads us to an
8586 * LP_DEAD item. This is okay because the earlier pruning
8587 * operation that made the line pointer LP_DEAD in the first place
8588 * must have considered the original tuple header as part of
8589 * generating its own snapshotConflictHorizon value.
8590 *
8591 * Relying on XLOG_HEAP2_PRUNE_VACUUM_SCAN records like this is
8592 * the same strategy that index vacuuming uses in all cases. Index
8593 * VACUUM WAL records don't even have a snapshotConflictHorizon
8594 * field of their own for this reason.
8595 */
8596 if (!ItemIdIsNormal(lp))
8597 break;
8598
8599 htup = (HeapTupleHeader) PageGetItem(page, lp);
8600
8601 /*
8602 * Check the tuple XMIN against prior XMAX, if any
8603 */
8606 break;
8607
8609 &snapshotConflictHorizon);
8610
8611 /*
8612 * If the tuple is not HOT-updated, then we are at the end of this
8613 * HOT-chain. No need to visit later tuples from the same update
8614 * chain (they get their own index entries) -- just move on to
8615 * next htid from index AM caller.
8616 */
8617 if (!HeapTupleHeaderIsHotUpdated(htup))
8618 break;
8619
8620 /* Advance to next HOT chain member */
8621 Assert(ItemPointerGetBlockNumber(&htup->t_ctid) == blkno);
8622 offnum = ItemPointerGetOffsetNumber(&htup->t_ctid);
8624 }
8625
8626 /* Enable further/final shrinking of deltids for caller */
8627 finalndeltids = i + 1;
8628 }
8629
8631
8632 /*
8633 * Shrink deltids array to exclude non-deletable entries at the end. This
8634 * is not just a minor optimization. Final deltids array size might be
8635 * zero for a bottom-up caller. Index AM is explicitly allowed to rely on
8636 * ndeltids being zero in all cases with zero total deletable entries.
8637 */
8638 Assert(finalndeltids > 0 || delstate->bottomup);
8639 delstate->ndeltids = finalndeltids;
8640
8641 return snapshotConflictHorizon;
8642}

References Assert, BOTTOMUP_MAX_NBLOCKS, bottomup_sort_and_shrink(), buf, BUFFER_LOCK_SHARE, BufferGetPage(), BufferIsValid(), fb(), FirstOffsetNumber, get_tablespace_maintenance_io_concurrency(), GlobalVisTestFor(), heap_hot_search_buffer(), HeapTupleHeaderAdvanceConflictHorizon(), HeapTupleHeaderGetUpdateXid(), HeapTupleHeaderGetXmin(), HeapTupleHeaderIsHotUpdated(), i, index_delete_check_htid(), index_delete_sort(), InitNonVacuumableSnapshot, InvalidBlockNumber, InvalidBuffer, InvalidOffsetNumber, InvalidTransactionId, IsCatalogRelation(), ItemIdGetRedirect, ItemIdIsNormal, ItemIdIsRedirected, ItemPointerGetBlockNumber(), ItemPointerGetOffsetNumber(), LockBuffer(), maintenance_io_concurrency, Min, PageGetItem(), PageGetItemId(), PageGetMaxOffsetNumber(), RelationData::rd_rel, ReadBuffer(), HeapTupleHeaderData::t_ctid, TransactionIdEquals, TransactionIdIsValid, and UnlockReleaseBuffer().

◆ heap_inplace_lock()

bool heap_inplace_lock ( Relation  relation,
HeapTuple  oldtup_ptr,
Buffer  buffer,
void(*)(void *)  release_callback,
void arg 
)

Definition at line 6572 of file heapam.c.

6575{
6576 HeapTupleData oldtup = *oldtup_ptr; /* minimize diff vs. heap_update() */
6578 bool ret;
6579
6580#ifdef USE_ASSERT_CHECKING
6581 if (RelationGetRelid(relation) == RelationRelationId)
6583#endif
6584
6585 Assert(BufferIsValid(buffer));
6586
6587 /*
6588 * Register shared cache invals if necessary. Other sessions may finish
6589 * inplace updates of this tuple between this step and LockTuple(). Since
6590 * inplace updates don't change cache keys, that's harmless.
6591 *
6592 * While it's tempting to register invals only after confirming we can
6593 * return true, the following obstacle precludes reordering steps that
6594 * way. Registering invals might reach a CatalogCacheInitializeCache()
6595 * that locks "buffer". That would hang indefinitely if running after our
6596 * own LockBuffer(). Hence, we must register invals before LockBuffer().
6597 */
6599
6600 LockTuple(relation, &oldtup.t_self, InplaceUpdateTupleLock);
6602
6603 /*----------
6604 * Interpret HeapTupleSatisfiesUpdate() like heap_update() does, except:
6605 *
6606 * - wait unconditionally
6607 * - already locked tuple above, since inplace needs that unconditionally
6608 * - don't recheck header after wait: simpler to defer to next iteration
6609 * - don't try to continue even if the updater aborts: likewise
6610 * - no crosscheck
6611 */
6613 buffer);
6614
6615 if (result == TM_Invisible)
6616 {
6617 /* no known way this can happen */
6618 ereport(ERROR,
6620 errmsg_internal("attempted to overwrite invisible tuple")));
6621 }
6622 else if (result == TM_SelfModified)
6623 {
6624 /*
6625 * CREATE INDEX might reach this if an expression is silly enough to
6626 * call e.g. SELECT ... FROM pg_class FOR SHARE. C code of other SQL
6627 * statements might get here after a heap_update() of the same row, in
6628 * the absence of an intervening CommandCounterIncrement().
6629 */
6630 ereport(ERROR,
6632 errmsg("tuple to be updated was already modified by an operation triggered by the current command")));
6633 }
6634 else if (result == TM_BeingModified)
6635 {
6638
6640 infomask = oldtup.t_data->t_infomask;
6641
6643 {
6646 int remain;
6647
6649 lockmode, NULL))
6650 {
6653 ret = false;
6655 relation, &oldtup.t_self, XLTW_Update,
6656 &remain);
6657 }
6658 else
6659 ret = true;
6660 }
6662 ret = true;
6664 ret = true;
6665 else
6666 {
6669 ret = false;
6670 XactLockTableWait(xwait, relation, &oldtup.t_self,
6671 XLTW_Update);
6672 }
6673 }
6674 else
6675 {
6676 ret = (result == TM_Ok);
6677 if (!ret)
6678 {
6681 }
6682 }
6683
6684 /*
6685 * GetCatalogSnapshot() relies on invalidation messages to know when to
6686 * take a new snapshot. COMMIT of xwait is responsible for sending the
6687 * invalidation. We're not acquiring heavyweight locks sufficient to
6688 * block if not yet sent, so we must take a new snapshot to ensure a later
6689 * attempt has a fair chance. While we don't need this if xwait aborted,
6690 * don't bother optimizing that.
6691 */
6692 if (!ret)
6693 {
6694 UnlockTuple(relation, &oldtup.t_self, InplaceUpdateTupleLock);
6697 }
6698 return ret;
6699}

References arg, Assert, BUFFER_LOCK_EXCLUSIVE, BUFFER_LOCK_UNLOCK, BufferIsValid(), CacheInvalidateHeapTupleInplace(), DoesMultiXactIdConflict(), ereport, errcode(), errmsg, errmsg_internal(), ERROR, fb(), ForgetInplace_Inval(), GetCurrentCommandId(), HEAP_XMAX_IS_KEYSHR_LOCKED(), HEAP_XMAX_IS_MULTI, HeapTupleHeaderGetRawXmax(), HeapTupleSatisfiesUpdate(), InplaceUpdateTupleLock, InvalidateCatalogSnapshot(), LockBuffer(), LockTuple(), LockTupleNoKeyExclusive, MultiXactIdWait(), MultiXactStatusNoKeyUpdate, RelationGetRelid, result, TM_BeingModified, TM_Invisible, TM_Ok, TM_SelfModified, TransactionIdIsCurrentTransactionId(), UnlockTuple(), XactLockTableWait(), and XLTW_Update.

Referenced by systable_inplace_update_begin().

◆ heap_inplace_unlock()

void heap_inplace_unlock ( Relation  relation,
HeapTuple  oldtup,
Buffer  buffer 
)

◆ heap_inplace_update_and_unlock()

void heap_inplace_update_and_unlock ( Relation  relation,
HeapTuple  oldtup,
HeapTuple  tuple,
Buffer  buffer 
)

Definition at line 6710 of file heapam.c.

6713{
6714 HeapTupleHeader htup = oldtup->t_data;
6715 uint32 oldlen;
6716 uint32 newlen;
6717 char *dst;
6718 char *src;
6719 int nmsgs = 0;
6721 bool RelcacheInitFileInval = false;
6722
6723 Assert(ItemPointerEquals(&oldtup->t_self, &tuple->t_self));
6724 oldlen = oldtup->t_len - htup->t_hoff;
6725 newlen = tuple->t_len - tuple->t_data->t_hoff;
6726 if (oldlen != newlen || htup->t_hoff != tuple->t_data->t_hoff)
6727 elog(ERROR, "wrong tuple length");
6728
6729 dst = (char *) htup + htup->t_hoff;
6730 src = (char *) tuple->t_data + tuple->t_data->t_hoff;
6731
6732 /* Like RecordTransactionCommit(), log only if needed */
6735 &RelcacheInitFileInval);
6736
6737 /*
6738 * Unlink relcache init files as needed. If unlinking, acquire
6739 * RelCacheInitLock until after associated invalidations. By doing this
6740 * in advance, if we checkpoint and then crash between inplace
6741 * XLogInsert() and inval, we don't rely on StartupXLOG() ->
6742 * RelationCacheInitFileRemove(). That uses elevel==LOG, so replay would
6743 * neglect to PANIC on EIO.
6744 */
6746
6747 /*----------
6748 * NO EREPORT(ERROR) from here till changes are complete
6749 *
6750 * Our exclusive buffer lock won't stop a reader having already pinned and
6751 * checked visibility for this tuple. With the usual order of changes
6752 * (i.e. updating the buffer contents before WAL logging), a reader could
6753 * observe our not-yet-persistent update to relfrozenxid and update
6754 * datfrozenxid based on that. A crash in that moment could allow
6755 * datfrozenxid to overtake relfrozenxid:
6756 *
6757 * ["D" is a VACUUM (ONLY_DATABASE_STATS)]
6758 * ["R" is a VACUUM tbl]
6759 * D: vac_update_datfrozenxid() -> systable_beginscan(pg_class)
6760 * D: systable_getnext() returns pg_class tuple of tbl
6761 * R: memcpy() into pg_class tuple of tbl
6762 * D: raise pg_database.datfrozenxid, XLogInsert(), finish
6763 * [crash]
6764 * [recovery restores datfrozenxid w/o relfrozenxid]
6765 *
6766 * We avoid that by using a temporary copy of the buffer to hide our
6767 * change from other backends until the change has been WAL-logged. We
6768 * apply our change to the temporary copy and WAL-log it, before modifying
6769 * the real page. That way any action a reader of the in-place-updated
6770 * value takes will be WAL logged after this change.
6771 */
6773
6774 MarkBufferDirty(buffer);
6775
6776 /* XLOG stuff */
6777 if (RelationNeedsWAL(relation))
6778 {
6781 char *origdata = (char *) BufferGetBlock(buffer);
6782 Page page = BufferGetPage(buffer);
6783 uint16 lower = ((PageHeader) page)->pd_lower;
6784 uint16 upper = ((PageHeader) page)->pd_upper;
6786 RelFileLocator rlocator;
6787 ForkNumber forkno;
6788 BlockNumber blkno;
6790
6791 xlrec.offnum = ItemPointerGetOffsetNumber(&tuple->t_self);
6792 xlrec.dbId = MyDatabaseId;
6794 xlrec.relcacheInitFileInval = RelcacheInitFileInval;
6795 xlrec.nmsgs = nmsgs;
6796
6799 if (nmsgs != 0)
6801 nmsgs * sizeof(SharedInvalidationMessage));
6802
6803 /* register block matching what buffer will look like after changes */
6808 BufferGetTag(buffer, &rlocator, &forkno, &blkno);
6809 Assert(forkno == MAIN_FORKNUM);
6810 XLogRegisterBlock(0, &rlocator, forkno, blkno, copied_buffer.data,
6812 XLogRegisterBufData(0, src, newlen);
6813
6814 /* inplace updates aren't decoded atm, don't log the origin */
6815
6817
6818 PageSetLSN(page, recptr);
6819 }
6820
6821 memcpy(dst, src, newlen);
6822
6824
6825 /*
6826 * Send invalidations to shared queue. SearchSysCacheLocked1() assumes we
6827 * do this before UnlockTuple().
6828 */
6830
6832 UnlockTuple(relation, &tuple->t_self, InplaceUpdateTupleLock);
6833
6834 AcceptInvalidationMessages(); /* local processing of just-sent inval */
6835
6836 /*
6837 * Queue a transactional inval, for logical decoding and for third-party
6838 * code that might have been relying on it since long before inplace
6839 * update adopted immediate invalidation. See README.tuplock section
6840 * "Reading inplace-updated columns" for logical decoding details.
6841 */
6843 CacheInvalidateHeapTuple(relation, tuple, NULL);
6844}

References AcceptInvalidationMessages(), Assert, AtInplace_Inval(), BUFFER_LOCK_UNLOCK, BufferGetBlock(), BufferGetPage(), BufferGetTag(), CacheInvalidateHeapTuple(), elog, END_CRIT_SECTION, ERROR, fb(), inplaceGetInvalidationMessages(), InplaceUpdateTupleLock, IsBootstrapProcessingMode, ItemPointerEquals(), ItemPointerGetOffsetNumber(), LockBuffer(), lower(), MAIN_FORKNUM, MarkBufferDirty(), memcpy(), MinSizeOfHeapInplace, MyDatabaseId, MyDatabaseTableSpace, PageSetLSN(), PreInplace_Inval(), REGBUF_STANDARD, RelationNeedsWAL, START_CRIT_SECTION, HeapTupleData::t_data, HeapTupleHeaderData::t_hoff, HeapTupleData::t_len, HeapTupleData::t_self, UnlockTuple(), upper(), XLOG_HEAP_INPLACE, XLogBeginInsert(), XLogInsert(), XLogRegisterBlock(), XLogRegisterBufData(), XLogRegisterData(), and XLogStandbyInfoActive.

Referenced by systable_inplace_update_finish().

◆ heap_insert()

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

Definition at line 2005 of file heapam.c.

2007{
2010 Buffer buffer;
2011 Page page;
2012 Buffer vmbuffer = InvalidBuffer;
2013 bool clear_all_visible = false;
2014 bool vmbuffer_modified = false;
2015
2016 /* Cheap, simplistic check that the tuple matches the rel's rowtype. */
2019
2020 AssertHasSnapshotForToast(relation);
2021
2022 /*
2023 * Fill in tuple header fields and toast the tuple if necessary.
2024 *
2025 * Note: below this point, heaptup is the data we actually intend to store
2026 * into the relation; tup is the caller's original untoasted data.
2027 */
2028 heaptup = heap_prepare_insert(relation, tup, xid, cid, options);
2029
2030 /*
2031 * Find buffer to insert this tuple into. If the page is all visible,
2032 * this will also pin the requisite visibility map page.
2033 */
2034 buffer = RelationGetBufferForTuple(relation, heaptup->t_len,
2035 InvalidBuffer, options, bistate,
2036 &vmbuffer, NULL,
2037 0);
2038
2039 page = BufferGetPage(buffer);
2040
2041 /*
2042 * We're about to do the actual insert -- but check for conflict first, to
2043 * avoid possibly having to roll back work we've just done.
2044 *
2045 * This is safe without a recheck as long as there is no possibility of
2046 * another process scanning the page between this check and the insert
2047 * being visible to the scan (i.e., an exclusive buffer content lock is
2048 * continuously held from this point until the tuple insert is visible).
2049 *
2050 * For a heap insert, we only need to check for table-level SSI locks. Our
2051 * new tuple can't possibly conflict with existing tuple locks, and heap
2052 * page locks are only consolidated versions of tuple locks; they do not
2053 * lock "gaps" as index page locks do. So we don't need to specify a
2054 * buffer when making the call, which makes for a faster check.
2055 */
2057
2058 /* Lock the vmbuffer before the critical section */
2059 if (PageIsAllVisible(page))
2060 {
2062 clear_all_visible = true;
2063 }
2064
2065 /* NO EREPORT(ERROR) from here till changes are logged */
2067
2068 RelationPutHeapTuple(relation, buffer, heaptup,
2070
2072 {
2073 /* It's possible the VM bits were already clear */
2074 if (visibilitymap_clear(relation->rd_locator,
2076 vmbuffer, VISIBILITYMAP_VALID_BITS))
2077 vmbuffer_modified = true;
2078
2079 PageClearAllVisible(page);
2080 }
2081
2082 /*
2083 * Set pd_prune_xid to trigger heap_page_prune_and_freeze() once the page
2084 * is full so that we can set the page all-visible in the VM on the next
2085 * page access.
2086 *
2087 * Setting pd_prune_xid is also handy if the inserting transaction
2088 * eventually aborts making this tuple DEAD and hence available for
2089 * pruning. If no other tuple in this page is UPDATEd/DELETEd, the aborted
2090 * tuple would never otherwise be pruned until next vacuum is triggered.
2091 *
2092 * Don't set it if we are in bootstrap mode or we are inserting a frozen
2093 * tuple, as there is no further pruning/freezing needed in those cases.
2094 */
2096 PageSetPrunable(page, xid);
2097
2098 MarkBufferDirty(buffer);
2099
2100 /* XLOG stuff */
2101 if (RelationNeedsWAL(relation))
2102 {
2106 uint8 info = XLOG_HEAP_INSERT;
2107 int bufflags = 0;
2108
2109 /*
2110 * If this is a catalog, we need to transmit combo CIDs to properly
2111 * decode, so log that as well.
2112 */
2114 log_heap_new_cid(relation, heaptup);
2115
2116 /*
2117 * If this is the single and first tuple on page, we can reinit the
2118 * page instead of restoring the whole thing. Set flag, and hide
2119 * buffer references from XLogInsert.
2120 */
2123 {
2124 info |= XLOG_HEAP_INIT_PAGE;
2126 }
2127
2128 xlrec.offnum = ItemPointerGetOffsetNumber(&heaptup->t_self);
2129 xlrec.flags = 0;
2135
2136 /*
2137 * For logical decoding, we need the tuple even if we're doing a full
2138 * page write, so make sure it's included even if we take a full-page
2139 * image. (XXX We could alternatively store a pointer into the FPW).
2140 */
2141 if (RelationIsLogicallyLogged(relation) &&
2143 {
2146
2147 if (IsToastRelation(relation))
2149 }
2150
2153
2154 xlhdr.t_infomask2 = heaptup->t_data->t_infomask2;
2155 xlhdr.t_infomask = heaptup->t_data->t_infomask;
2156 xlhdr.t_hoff = heaptup->t_data->t_hoff;
2157
2158 /*
2159 * note we mark xlhdr as belonging to buffer; if XLogInsert decides to
2160 * write the whole page to the xlog, we don't need to store
2161 * xl_heap_header in the xlog.
2162 */
2167 /* PG73FORMAT: write bitmap [+ padding] [+ oid] + data */
2169 (char *) heaptup->t_data + SizeofHeapTupleHeader,
2171
2172 /* filtering by origin on a row level is much more efficient */
2174
2177
2178 recptr = XLogInsert(RM_HEAP_ID, info);
2179
2180 PageSetLSN(page, recptr);
2181
2183 PageSetLSN(BufferGetPage(vmbuffer), recptr);
2184 }
2185
2187
2188 UnlockReleaseBuffer(buffer);
2189
2190 /*
2191 * We locked vmbuffer if clear_all_visible was true regardless of whether
2192 * or not we ended up modifying the vmbuffer.
2193 */
2195 LockBuffer(vmbuffer, BUFFER_LOCK_UNLOCK);
2196 if (BufferIsValid(vmbuffer))
2197 ReleaseBuffer(vmbuffer);
2198
2199 /*
2200 * If tuple is cacheable, mark it for invalidation from the caches in case
2201 * we abort. Note it is OK to do this after releasing the buffer, because
2202 * the heaptup data structure is all in local memory, not in the shared
2203 * buffer.
2204 */
2206
2207 /* Note: speculative insertions are counted too, even if aborted later */
2208 pgstat_count_heap_insert(relation, 1);
2209
2210 /*
2211 * If heaptup is a private copy, release it. Don't forget to copy t_self
2212 * back to the caller's image, too.
2213 */
2214 if (heaptup != tup)
2215 {
2216 tup->t_self = heaptup->t_self;
2218 }
2219}

References Assert, AssertHasSnapshotForToast(), BUFFER_LOCK_EXCLUSIVE, BUFFER_LOCK_UNLOCK, BufferGetBlockNumber(), BufferGetPage(), BufferIsValid(), CacheInvalidateHeapTuple(), CheckForSerializableConflictIn(), END_CRIT_SECTION, fb(), FirstOffsetNumber, GetCurrentTransactionId(), heap_freetuple(), HEAP_INSERT_BLKREF_HEAP, HEAP_INSERT_BLKREF_VM, HEAP_INSERT_FROZEN, HEAP_INSERT_NO_LOGICAL, HEAP_INSERT_SPECULATIVE, heap_prepare_insert(), HeapTupleHeaderGetNatts, InvalidBlockNumber, InvalidBuffer, IsToastRelation(), ItemPointerGetBlockNumber(), ItemPointerGetOffsetNumber(), LockBuffer(), log_heap_new_cid(), MarkBufferDirty(), PageClearAllVisible(), PageGetMaxOffsetNumber(), PageIsAllVisible(), PageSetLSN(), PageSetPrunable, pgstat_count_heap_insert(), RelationData::rd_locator, REGBUF_KEEP_DATA, REGBUF_STANDARD, REGBUF_WILL_INIT, RelationGetBufferForTuple(), RelationGetNumberOfAttributes, RelationIsAccessibleInLogicalDecoding, RelationIsLogicallyLogged, RelationNeedsWAL, RelationPutHeapTuple(), ReleaseBuffer(), SizeOfHeapHeader, SizeOfHeapInsert, SizeofHeapTupleHeader, START_CRIT_SECTION, TransactionIdIsNormal, UnlockReleaseBuffer(), visibilitymap_clear(), VISIBILITYMAP_VALID_BITS, XLH_INSERT_ALL_VISIBLE_CLEARED, XLH_INSERT_CONTAINS_NEW_TUPLE, XLH_INSERT_IS_SPECULATIVE, XLH_INSERT_ON_TOAST_RELATION, XLOG_HEAP_INIT_PAGE, XLOG_HEAP_INSERT, XLOG_INCLUDE_ORIGIN, XLogBeginInsert(), XLogInsert(), XLogRegisterBufData(), XLogRegisterBuffer(), XLogRegisterData(), and XLogSetRecordFlags().

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

◆ heap_lock_tuple()

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

Definition at line 4728 of file heapam.c.

4732{
4734 ItemPointer tid = &(tuple->t_self);
4735 ItemId lp;
4736 Page page;
4737 Buffer vmbuffer = InvalidBuffer;
4738 bool unlock_vmbuffer = false;
4739 BlockNumber block;
4740 TransactionId xid,
4741 xmax;
4745 bool first_time = true;
4746 bool skip_tuple_lock = false;
4747 bool have_tuple_lock = false;
4748 bool cleared_all_frozen = false;
4749
4750 *buffer = ReadBuffer(relation, ItemPointerGetBlockNumber(tid));
4751 block = ItemPointerGetBlockNumber(tid);
4752 page = BufferGetPage(*buffer);
4753
4754 /*
4755 * Before locking the buffer, pin the visibility map page if it appears to
4756 * be necessary. Since we haven't got the lock yet, someone else might be
4757 * in the middle of changing this, so we'll need to recheck after we have
4758 * the lock.
4759 */
4760 if (PageIsAllVisible(page))
4761 visibilitymap_pin(relation, block, &vmbuffer);
4762
4764
4767
4768 tuple->t_data = (HeapTupleHeader) PageGetItem(page, lp);
4769 tuple->t_len = ItemIdGetLength(lp);
4770 tuple->t_tableOid = RelationGetRelid(relation);
4771
4772l3:
4773 result = HeapTupleSatisfiesUpdate(tuple, cid, *buffer);
4774
4775 if (result == TM_Invisible)
4776 {
4777 /*
4778 * This is possible, but only when locking a tuple for ON CONFLICT DO
4779 * SELECT/UPDATE. We return this value here rather than throwing an
4780 * error in order to give that case the opportunity to throw a more
4781 * specific error.
4782 */
4784 goto out_locked;
4785 }
4786 else if (result == TM_BeingModified ||
4787 result == TM_Updated ||
4788 result == TM_Deleted)
4789 {
4793 bool require_sleep;
4794 ItemPointerData t_ctid;
4795
4796 /* must copy state data before unlocking buffer */
4798 infomask = tuple->t_data->t_infomask;
4799 infomask2 = tuple->t_data->t_infomask2;
4800 ItemPointerCopy(&tuple->t_data->t_ctid, &t_ctid);
4801
4803
4804 /*
4805 * If any subtransaction of the current top transaction already holds
4806 * a lock as strong as or stronger than what we're requesting, we
4807 * effectively hold the desired lock already. We *must* succeed
4808 * without trying to take the tuple lock, else we will deadlock
4809 * against anyone wanting to acquire a stronger lock.
4810 *
4811 * Note we only do this the first time we loop on the HTSU result;
4812 * there is no point in testing in subsequent passes, because
4813 * evidently our own transaction cannot have acquired a new lock after
4814 * the first time we checked.
4815 */
4816 if (first_time)
4817 {
4818 first_time = false;
4819
4821 {
4822 int i;
4823 int nmembers;
4824 MultiXactMember *members;
4825
4826 /*
4827 * We don't need to allow old multixacts here; if that had
4828 * been the case, HeapTupleSatisfiesUpdate would have returned
4829 * MayBeUpdated and we wouldn't be here.
4830 */
4831 nmembers =
4832 GetMultiXactIdMembers(xwait, &members, false,
4834
4835 for (i = 0; i < nmembers; i++)
4836 {
4837 /* only consider members of our own transaction */
4838 if (!TransactionIdIsCurrentTransactionId(members[i].xid))
4839 continue;
4840
4841 if (TUPLOCK_from_mxstatus(members[i].status) >= mode)
4842 {
4843 pfree(members);
4844 result = TM_Ok;
4845 goto out_unlocked;
4846 }
4847 else
4848 {
4849 /*
4850 * Disable acquisition of the heavyweight tuple lock.
4851 * Otherwise, when promoting a weaker lock, we might
4852 * deadlock with another locker that has acquired the
4853 * heavyweight tuple lock and is waiting for our
4854 * transaction to finish.
4855 *
4856 * Note that in this case we still need to wait for
4857 * the multixact if required, to avoid acquiring
4858 * conflicting locks.
4859 */
4860 skip_tuple_lock = true;
4861 }
4862 }
4863
4864 if (members)
4865 pfree(members);
4866 }
4868 {
4869 switch (mode)
4870 {
4871 case LockTupleKeyShare:
4875 result = TM_Ok;
4876 goto out_unlocked;
4877 case LockTupleShare:
4880 {
4881 result = TM_Ok;
4882 goto out_unlocked;
4883 }
4884 break;
4887 {
4888 result = TM_Ok;
4889 goto out_unlocked;
4890 }
4891 break;
4892 case LockTupleExclusive:
4895 {
4896 result = TM_Ok;
4897 goto out_unlocked;
4898 }
4899 break;
4900 }
4901 }
4902 }
4903
4904 /*
4905 * Initially assume that we will have to wait for the locking
4906 * transaction(s) to finish. We check various cases below in which
4907 * this can be turned off.
4908 */
4909 require_sleep = true;
4910 if (mode == LockTupleKeyShare)
4911 {
4912 /*
4913 * If we're requesting KeyShare, and there's no update present, we
4914 * don't need to wait. Even if there is an update, we can still
4915 * continue if the key hasn't been modified.
4916 *
4917 * However, if there are updates, we need to walk the update chain
4918 * to mark future versions of the row as locked, too. That way,
4919 * if somebody deletes that future version, we're protected
4920 * against the key going away. This locking of future versions
4921 * could block momentarily, if a concurrent transaction is
4922 * deleting a key; or it could return a value to the effect that
4923 * the transaction deleting the key has already committed. So we
4924 * do this before re-locking the buffer; otherwise this would be
4925 * prone to deadlocks.
4926 *
4927 * Note that the TID we're locking was grabbed before we unlocked
4928 * the buffer. For it to change while we're not looking, the
4929 * other properties we're testing for below after re-locking the
4930 * buffer would also change, in which case we would restart this
4931 * loop above.
4932 */
4934 {
4935 bool updated;
4936
4938
4939 /*
4940 * If there are updates, follow the update chain; bail out if
4941 * that cannot be done.
4942 */
4943 if (follow_updates && updated &&
4944 !ItemPointerEquals(&tuple->t_self, &t_ctid))
4945 {
4946 TM_Result res;
4947
4948 res = heap_lock_updated_tuple(relation,
4949 infomask, xwait, &t_ctid,
4951 mode);
4952 if (res != TM_Ok)
4953 {
4954 result = res;
4955 /* recovery code expects to have buffer lock held */
4957 goto failed;
4958 }
4959 }
4960
4962
4963 /*
4964 * Make sure it's still an appropriate lock, else start over.
4965 * Also, if it wasn't updated before we released the lock, but
4966 * is updated now, we start over too; the reason is that we
4967 * now need to follow the update chain to lock the new
4968 * versions.
4969 */
4970 if (!HeapTupleHeaderIsOnlyLocked(tuple->t_data) &&
4971 ((tuple->t_data->t_infomask2 & HEAP_KEYS_UPDATED) ||
4972 !updated))
4973 goto l3;
4974
4975 /* Things look okay, so we can skip sleeping */
4976 require_sleep = false;
4977
4978 /*
4979 * Note we allow Xmax to change here; other updaters/lockers
4980 * could have modified it before we grabbed the buffer lock.
4981 * However, this is not a problem, because with the recheck we
4982 * just did we ensure that they still don't conflict with the
4983 * lock we want.
4984 */
4985 }
4986 }
4987 else if (mode == LockTupleShare)
4988 {
4989 /*
4990 * If we're requesting Share, we can similarly avoid sleeping if
4991 * there's no update and no exclusive lock present.
4992 */
4995 {
4997
4998 /*
4999 * Make sure it's still an appropriate lock, else start over.
5000 * See above about allowing xmax to change.
5001 */
5004 goto l3;
5005 require_sleep = false;
5006 }
5007 }
5008 else if (mode == LockTupleNoKeyExclusive)
5009 {
5010 /*
5011 * If we're requesting NoKeyExclusive, we might also be able to
5012 * avoid sleeping; just ensure that there no conflicting lock
5013 * already acquired.
5014 */
5016 {
5018 mode, NULL))
5019 {
5020 /*
5021 * No conflict, but if the xmax changed under us in the
5022 * meantime, start over.
5023 */
5027 xwait))
5028 goto l3;
5029
5030 /* otherwise, we're good */
5031 require_sleep = false;
5032 }
5033 }
5035 {
5037
5038 /* if the xmax changed in the meantime, start over */
5041 xwait))
5042 goto l3;
5043 /* otherwise, we're good */
5044 require_sleep = false;
5045 }
5046 }
5047
5048 /*
5049 * As a check independent from those above, we can also avoid sleeping
5050 * if the current transaction is the sole locker of the tuple. Note
5051 * that the strength of the lock already held is irrelevant; this is
5052 * not about recording the lock in Xmax (which will be done regardless
5053 * of this optimization, below). Also, note that the cases where we
5054 * hold a lock stronger than we are requesting are already handled
5055 * above by not doing anything.
5056 *
5057 * Note we only deal with the non-multixact case here; MultiXactIdWait
5058 * is well equipped to deal with this situation on its own.
5059 */
5062 {
5063 /* ... but if the xmax changed in the meantime, start over */
5067 xwait))
5068 goto l3;
5070 require_sleep = false;
5071 }
5072
5073 /*
5074 * Time to sleep on the other transaction/multixact, if necessary.
5075 *
5076 * If the other transaction is an update/delete that's already
5077 * committed, then sleeping cannot possibly do any good: if we're
5078 * required to sleep, get out to raise an error instead.
5079 *
5080 * By here, we either have already acquired the buffer exclusive lock,
5081 * or we must wait for the locking transaction or multixact; so below
5082 * we ensure that we grab buffer lock after the sleep.
5083 */
5085 {
5087 goto failed;
5088 }
5089 else if (require_sleep)
5090 {
5091 /*
5092 * Acquire tuple lock to establish our priority for the tuple, or
5093 * die trying. LockTuple will release us when we are next-in-line
5094 * for the tuple. We must do this even if we are share-locking,
5095 * but not if we already have a weaker lock on the tuple.
5096 *
5097 * If we are forced to "start over" below, we keep the tuple lock;
5098 * this arranges that we stay at the head of the line while
5099 * rechecking tuple state.
5100 */
5101 if (!skip_tuple_lock &&
5102 !heap_acquire_tuplock(relation, tid, mode, wait_policy,
5104 {
5105 /*
5106 * This can only happen if wait_policy is Skip and the lock
5107 * couldn't be obtained.
5108 */
5110 /* recovery code expects to have buffer lock held */
5112 goto failed;
5113 }
5114
5116 {
5118
5119 /* We only ever lock tuples, never update them */
5120 if (status >= MultiXactStatusNoKeyUpdate)
5121 elog(ERROR, "invalid lock mode in heap_lock_tuple");
5122
5123 /* wait for multixact to end, or die trying */
5124 switch (wait_policy)
5125 {
5126 case LockWaitBlock:
5128 relation, &tuple->t_self, XLTW_Lock, NULL);
5129 break;
5130 case LockWaitSkip:
5132 status, infomask, relation,
5133 NULL, false))
5134 {
5136 /* recovery code expects to have buffer lock held */
5138 goto failed;
5139 }
5140 break;
5141 case LockWaitError:
5143 status, infomask, relation,
5145 ereport(ERROR,
5147 errmsg("could not obtain lock on row in relation \"%s\"",
5148 RelationGetRelationName(relation))));
5149
5150 break;
5151 }
5152
5153 /*
5154 * Of course, the multixact might not be done here: if we're
5155 * requesting a light lock mode, other transactions with light
5156 * locks could still be alive, as well as locks owned by our
5157 * own xact or other subxacts of this backend. We need to
5158 * preserve the surviving MultiXact members. Note that it
5159 * isn't absolutely necessary in the latter case, but doing so
5160 * is simpler.
5161 */
5162 }
5163 else
5164 {
5165 /* wait for regular transaction to end, or die trying */
5166 switch (wait_policy)
5167 {
5168 case LockWaitBlock:
5169 XactLockTableWait(xwait, relation, &tuple->t_self,
5170 XLTW_Lock);
5171 break;
5172 case LockWaitSkip:
5174 {
5176 /* recovery code expects to have buffer lock held */
5178 goto failed;
5179 }
5180 break;
5181 case LockWaitError:
5183 ereport(ERROR,
5185 errmsg("could not obtain lock on row in relation \"%s\"",
5186 RelationGetRelationName(relation))));
5187 break;
5188 }
5189 }
5190
5191 /* if there are updates, follow the update chain */
5193 !ItemPointerEquals(&tuple->t_self, &t_ctid))
5194 {
5195 TM_Result res;
5196
5197 res = heap_lock_updated_tuple(relation,
5198 infomask, xwait, &t_ctid,
5200 mode);
5201 if (res != TM_Ok)
5202 {
5203 result = res;
5204 /* recovery code expects to have buffer lock held */
5206 goto failed;
5207 }
5208 }
5209
5211
5212 /*
5213 * xwait is done, but if xwait had just locked the tuple then some
5214 * other xact could update this tuple before we get to this point.
5215 * Check for xmax change, and start over if so.
5216 */
5219 xwait))
5220 goto l3;
5221
5223 {
5224 /*
5225 * Otherwise check if it committed or aborted. Note we cannot
5226 * be here if the tuple was only locked by somebody who didn't
5227 * conflict with us; that would have been handled above. So
5228 * that transaction must necessarily be gone by now. But
5229 * don't check for this in the multixact case, because some
5230 * locker transactions might still be running.
5231 */
5232 UpdateXmaxHintBits(tuple->t_data, *buffer, xwait);
5233 }
5234 }
5235
5236 /* By here, we're certain that we hold buffer exclusive lock again */
5237
5238 /*
5239 * We may lock if previous xmax aborted, or if it committed but only
5240 * locked the tuple without updating it; or if we didn't have to wait
5241 * at all for whatever reason.
5242 */
5243 if (!require_sleep ||
5244 (tuple->t_data->t_infomask & HEAP_XMAX_INVALID) ||
5247 result = TM_Ok;
5248 else if (!ItemPointerEquals(&tuple->t_self, &tuple->t_data->t_ctid))
5250 else
5252 }
5253
5254failed:
5255 if (result != TM_Ok)
5256 {
5259
5260 /*
5261 * When locking a tuple under LockWaitSkip semantics and we fail with
5262 * TM_WouldBlock above, it's possible for concurrent transactions to
5263 * release the lock and set HEAP_XMAX_INVALID in the meantime. So
5264 * this assert is slightly different from the equivalent one in
5265 * heap_delete and heap_update.
5266 */
5268 !(tuple->t_data->t_infomask & HEAP_XMAX_INVALID));
5270 !ItemPointerEquals(&tuple->t_self, &tuple->t_data->t_ctid));
5271 tmfd->ctid = tuple->t_data->t_ctid;
5272 tmfd->xmax = HeapTupleHeaderGetUpdateXid(tuple->t_data);
5273 if (result == TM_SelfModified)
5274 tmfd->cmax = HeapTupleHeaderGetCmax(tuple->t_data);
5275 else
5276 tmfd->cmax = InvalidCommandId;
5277 goto out_locked;
5278 }
5279
5280 /*
5281 * If we didn't pin the visibility map page and the page has become all
5282 * visible while we were busy locking the buffer, or during some
5283 * subsequent window during which we had it unlocked, we'll have to unlock
5284 * and re-lock, to avoid holding the buffer lock across I/O. That's a bit
5285 * unfortunate, especially since we'll now have to recheck whether the
5286 * tuple has been locked or updated under us, but hopefully it won't
5287 * happen very often.
5288 */
5289 if (vmbuffer == InvalidBuffer && PageIsAllVisible(page))
5290 {
5292 visibilitymap_pin(relation, block, &vmbuffer);
5294 goto l3;
5295 }
5296
5297 xmax = HeapTupleHeaderGetRawXmax(tuple->t_data);
5298 old_infomask = tuple->t_data->t_infomask;
5299
5300 /*
5301 * If this is the first possibly-multixact-able operation in the current
5302 * transaction, set my per-backend OldestMemberMXactId setting. We can be
5303 * certain that the transaction will never become a member of any older
5304 * MultiXactIds than that. (We have to do this even if we end up just
5305 * using our own TransactionId below, since some other backend could
5306 * incorporate our XID into a MultiXact immediately afterwards.)
5307 */
5309
5310 /*
5311 * Compute the new xmax and infomask to store into the tuple. Note we do
5312 * not modify the tuple just yet, because that would leave it in the wrong
5313 * state if multixact.c elogs.
5314 */
5316 GetCurrentTransactionId(), mode, false,
5317 &xid, &new_infomask, &new_infomask2);
5318
5319 /* Lock VM buffer before entering critical section */
5320 if (PageIsAllVisible(page))
5321 {
5323 unlock_vmbuffer = true;
5324 }
5325
5327
5328 /*
5329 * Store transaction information of xact locking the tuple.
5330 *
5331 * Note: Cmax is meaningless in this context, so don't set it; this avoids
5332 * possibly generating a useless combo CID. Moreover, if we're locking a
5333 * previously updated tuple, it's important to preserve the Cmax.
5334 *
5335 * Also reset the HOT UPDATE bit, but only if there's no update; otherwise
5336 * we would break the HOT chain.
5337 */
5340 tuple->t_data->t_infomask |= new_infomask;
5341 tuple->t_data->t_infomask2 |= new_infomask2;
5344 HeapTupleHeaderSetXmax(tuple->t_data, xid);
5345
5346 /*
5347 * Make sure there is no forward chain link in t_ctid. Note that in the
5348 * cases where the tuple has been updated, we must not overwrite t_ctid,
5349 * because it was set by the updater. Moreover, if the tuple has been
5350 * updated, we need to follow the update chain to lock the new versions of
5351 * the tuple as well.
5352 */
5354 tuple->t_data->t_ctid = *tid;
5355
5356 /* Clear only the all-frozen bit on visibility map if needed */
5357 if (PageIsAllVisible(page))
5358 {
5359 if (visibilitymap_clear(relation->rd_locator, block, vmbuffer,
5361 cleared_all_frozen = true;
5362 }
5363
5364
5365 MarkBufferDirty(*buffer);
5366
5367 /*
5368 * XLOG stuff. You might think that we don't need an XLOG record because
5369 * there is no state change worth restoring after a crash. You would be
5370 * wrong however: we have just written either a TransactionId or a
5371 * MultiXactId that may never have been seen on disk before, and we need
5372 * to make sure that there are XLOG entries covering those ID numbers.
5373 * Else the same IDs might be re-used after a crash, which would be
5374 * disastrous if this page made it to disk before the crash. Essentially
5375 * we have to enforce the WAL log-before-data rule even in this case.
5376 * (Also, in a PITR log-shipping or 2PC environment, we have to have XLOG
5377 * entries for everything anyway.)
5378 */
5379 if (RelationNeedsWAL(relation))
5380 {
5383
5386
5387 xlrec.offnum = ItemPointerGetOffsetNumber(&tuple->t_self);
5388 xlrec.xmax = xid;
5389 xlrec.infobits_set = compute_infobits(new_infomask,
5390 tuple->t_data->t_infomask2);
5393
5396
5397 /* we don't decode row locks atm, so no need to log the origin */
5398
5400
5401 PageSetLSN(page, recptr);
5402
5404 PageSetLSN(BufferGetPage(vmbuffer), recptr);
5405 }
5406
5408
5409 /* release VM lock first, since it covers many heap blocks */
5410 if (unlock_vmbuffer)
5411 {
5412 LockBuffer(vmbuffer, BUFFER_LOCK_UNLOCK);
5413 unlock_vmbuffer = false;
5414 }
5415
5416 result = TM_Ok;
5417
5421
5423 if (BufferIsValid(vmbuffer))
5424 ReleaseBuffer(vmbuffer);
5425
5426 /*
5427 * Don't update the visibility map here. Locking a tuple doesn't change
5428 * visibility info.
5429 */
5430
5431 /*
5432 * Now that we have successfully marked the tuple as locked, we can
5433 * release the lmgr tuple lock, if we had it.
5434 */
5435 if (have_tuple_lock)
5436 UnlockTupleTuplock(relation, tid, mode);
5437
5438 return result;
5439}

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

Referenced by heapam_tuple_lock().

◆ heap_lock_updated_tuple()

static TM_Result heap_lock_updated_tuple ( Relation  rel,
uint16  prior_infomask,
TransactionId  prior_raw_xmax,
const ItemPointerData prior_ctid,
TransactionId  xid,
LockTupleMode  mode 
)
static

Definition at line 6250 of file heapam.c.

6255{
6256 INJECTION_POINT("heap_lock_updated_tuple", NULL);
6257
6258 /*
6259 * If the tuple has moved into another partition (effectively a delete)
6260 * stop here.
6261 */
6263 {
6265
6266 /*
6267 * If this is the first possibly-multixact-able operation in the
6268 * current transaction, set my per-backend OldestMemberMXactId
6269 * setting. We can be certain that the transaction will never become a
6270 * member of any older MultiXactIds than that. (We have to do this
6271 * even if we end up just using our own TransactionId below, since
6272 * some other backend could incorporate our XID into a MultiXact
6273 * immediately afterwards.)
6274 */
6276
6280 }
6281
6282 /* nothing to lock */
6283 return TM_Ok;
6284}

References fb(), heap_lock_updated_tuple_rec(), HEAP_XMAX_IS_MULTI, INJECTION_POINT, ItemPointerIndicatesMovedPartitions(), mode, MultiXactIdGetUpdateXid(), MultiXactIdSetOldestMember(), and TM_Ok.

Referenced by heap_lock_tuple().

◆ heap_lock_updated_tuple_rec()

static TM_Result heap_lock_updated_tuple_rec ( Relation  rel,
TransactionId  priorXmax,
const ItemPointerData tid,
TransactionId  xid,
LockTupleMode  mode 
)
static

Definition at line 5875 of file heapam.c.

5878{
5882 Buffer buf;
5883 Page page;
5888 TransactionId xmax,
5889 new_xmax;
5890 bool cleared_all_frozen = false;
5892 Buffer vmbuffer = InvalidBuffer;
5893 bool unlock_vmbuffer = false;
5894 BlockNumber block;
5895
5896 ItemPointerCopy(tid, &tupid);
5897
5898 for (;;)
5899 {
5900 new_infomask = 0;
5901 new_xmax = InvalidTransactionId;
5902 cleared_all_frozen = false;
5904 ItemPointerCopy(&tupid, &(mytup.t_self));
5905
5906 if (!heap_fetch(rel, SnapshotAny, &mytup, &buf, false))
5907 {
5908 /*
5909 * if we fail to find the updated version of the tuple, it's
5910 * because it was vacuumed/pruned away after its creator
5911 * transaction aborted. So behave as if we got to the end of the
5912 * chain, and there's no further tuple to lock: return success to
5913 * caller.
5914 */
5915 result = TM_Ok;
5916 goto out_unlocked;
5917 }
5918
5919l4:
5921
5922 page = BufferGetPage(buf);
5923
5924 /*
5925 * Before locking the buffer, pin the visibility map page if it
5926 * appears to be necessary. Since we haven't got the lock yet,
5927 * someone else might be in the middle of changing this, so we'll need
5928 * to recheck after we have the lock.
5929 */
5930 if (PageIsAllVisible(page))
5931 {
5932 visibilitymap_pin(rel, block, &vmbuffer);
5933 pinned_desired_page = true;
5934 }
5935 else
5936 pinned_desired_page = false;
5937
5939
5940 /*
5941 * If we didn't pin the visibility map page and the page has become
5942 * all visible while we were busy locking the buffer, we'll have to
5943 * unlock and re-lock, to avoid holding the buffer lock across I/O.
5944 * That's a bit unfortunate, but hopefully shouldn't happen often.
5945 *
5946 * Note: in some paths through this function, we will reach here
5947 * holding a pin on a vm page that may or may not be the one matching
5948 * this page. If this page isn't all-visible, we won't use the vm
5949 * page, but we hold onto such a pin till the end of the function.
5950 */
5952 {
5954 visibilitymap_pin(rel, block, &vmbuffer);
5956 }
5957
5958 /*
5959 * Check the tuple XMIN against prior XMAX, if any. If we reached the
5960 * end of the chain, we're done, so return success.
5961 */
5964 priorXmax))
5965 {
5966 result = TM_Ok;
5967 goto out_locked;
5968 }
5969
5970 /*
5971 * Also check Xmin: if this tuple was created by an aborted
5972 * (sub)transaction, then we already locked the last live one in the
5973 * chain, thus we're done, so return success.
5974 */
5976 {
5977 result = TM_Ok;
5978 goto out_locked;
5979 }
5980
5981 old_infomask = mytup.t_data->t_infomask;
5982 old_infomask2 = mytup.t_data->t_infomask2;
5983 xmax = HeapTupleHeaderGetRawXmax(mytup.t_data);
5984
5985 /*
5986 * If this tuple version has been updated or locked by some concurrent
5987 * transaction(s), what we do depends on whether our lock mode
5988 * conflicts with what those other transactions hold, and also on the
5989 * status of them.
5990 */
5992 {
5994 bool needwait;
5995
5998 {
5999 int nmembers;
6000 int i;
6001 MultiXactMember *members;
6002
6003 /*
6004 * We don't need a test for pg_upgrade'd tuples: this is only
6005 * applied to tuples after the first in an update chain. Said
6006 * first tuple in the chain may well be locked-in-9.2-and-
6007 * pg_upgraded, but that one was already locked by our caller,
6008 * not us; and any subsequent ones cannot be because our
6009 * caller must necessarily have obtained a snapshot later than
6010 * the pg_upgrade itself.
6011 */
6012 Assert(!HEAP_LOCKED_UPGRADED(mytup.t_data->t_infomask));
6013
6014 nmembers = GetMultiXactIdMembers(rawxmax, &members, false,
6016 for (i = 0; i < nmembers; i++)
6017 {
6018 result = test_lockmode_for_conflict(members[i].status,
6019 members[i].xid,
6020 mode,
6021 &mytup,
6022 &needwait);
6023
6024 /*
6025 * If the tuple was already locked by ourselves in a
6026 * previous iteration of this (say heap_lock_tuple was
6027 * forced to restart the locking loop because of a change
6028 * in xmax), then we hold the lock already on this tuple
6029 * version and we don't need to do anything; and this is
6030 * not an error condition either. We just need to skip
6031 * this tuple and continue locking the next version in the
6032 * update chain.
6033 */
6034 if (result == TM_SelfModified)
6035 {
6036 pfree(members);
6037 goto next;
6038 }
6039
6040 if (needwait)
6041 {
6043 XactLockTableWait(members[i].xid, rel,
6044 &mytup.t_self,
6046 pfree(members);
6047 goto l4;
6048 }
6049 if (result != TM_Ok)
6050 {
6051 pfree(members);
6052 goto out_locked;
6053 }
6054 }
6055 if (members)
6056 pfree(members);
6057 }
6058 else
6059 {
6060 MultiXactStatus status;
6061
6062 /*
6063 * For a non-multi Xmax, we first need to compute the
6064 * corresponding MultiXactStatus by using the infomask bits.
6065 */
6067 {
6071 status = MultiXactStatusForShare;
6073 {
6075 status = MultiXactStatusForUpdate;
6076 else
6078 }
6079 else
6080 {
6081 /*
6082 * LOCK_ONLY present alone (a pg_upgraded tuple marked
6083 * as share-locked in the old cluster) shouldn't be
6084 * seen in the middle of an update chain.
6085 */
6086 elog(ERROR, "invalid lock status in tuple");
6087 }
6088 }
6089 else
6090 {
6091 /* it's an update, but which kind? */
6093 status = MultiXactStatusUpdate;
6094 else
6096 }
6097
6099 &mytup, &needwait);
6100
6101 /*
6102 * If the tuple was already locked by ourselves in a previous
6103 * iteration of this (say heap_lock_tuple was forced to
6104 * restart the locking loop because of a change in xmax), then
6105 * we hold the lock already on this tuple version and we don't
6106 * need to do anything; and this is not an error condition
6107 * either. We just need to skip this tuple and continue
6108 * locking the next version in the update chain.
6109 */
6110 if (result == TM_SelfModified)
6111 goto next;
6112
6113 if (needwait)
6114 {
6116 XactLockTableWait(rawxmax, rel, &mytup.t_self,
6118 goto l4;
6119 }
6120 if (result != TM_Ok)
6121 {
6122 goto out_locked;
6123 }
6124 }
6125 }
6126
6127 /* compute the new Xmax and infomask values for the tuple ... */
6128 compute_new_xmax_infomask(xmax, old_infomask, mytup.t_data->t_infomask2,
6129 xid, mode, false,
6130 &new_xmax, &new_infomask, &new_infomask2);
6131
6132 if (PageIsAllVisible(page))
6133 {
6135 unlock_vmbuffer = true;
6136 }
6137
6139
6140 /* ... and set them */
6141 HeapTupleHeaderSetXmax(mytup.t_data, new_xmax);
6142 mytup.t_data->t_infomask &= ~HEAP_XMAX_BITS;
6143 mytup.t_data->t_infomask2 &= ~HEAP_KEYS_UPDATED;
6144 mytup.t_data->t_infomask |= new_infomask;
6145 mytup.t_data->t_infomask2 |= new_infomask2;
6146
6148
6149 if (PageIsAllVisible(page))
6150 {
6151 /* It's possible all-frozen was already clear */
6152 if (visibilitymap_clear(rel->rd_locator, block, vmbuffer,
6154 cleared_all_frozen = true;
6155 }
6156
6157 /* XLOG stuff */
6158 if (RelationNeedsWAL(rel))
6159 {
6162
6165
6166 xlrec.offnum = ItemPointerGetOffsetNumber(&mytup.t_self);
6167 xlrec.xmax = new_xmax;
6169 xlrec.flags =
6171
6173
6176
6178
6179 PageSetLSN(page, recptr);
6180
6182 PageSetLSN(BufferGetPage(vmbuffer), recptr);
6183 }
6184
6186
6187 /* release VM lock first, since it covers many heap blocks */
6188 if (unlock_vmbuffer)
6189 {
6190 LockBuffer(vmbuffer, BUFFER_LOCK_UNLOCK);
6191 unlock_vmbuffer = false;
6192 }
6193
6194next:
6195 /* if we find the end of update chain, we're done. */
6196 if (mytup.t_data->t_infomask & HEAP_XMAX_INVALID ||
6198 ItemPointerEquals(&mytup.t_self, &mytup.t_data->t_ctid) ||
6200 {
6201 result = TM_Ok;
6202 goto out_locked;
6203 }
6204
6205 /* tail recursion */
6207 ItemPointerCopy(&(mytup.t_data->t_ctid), &tupid);
6209 }
6210
6211 result = TM_Ok;
6212
6215
6217 if (vmbuffer != InvalidBuffer)
6218 ReleaseBuffer(vmbuffer);
6220
6221 return result;
6222}

References Assert, buf, BUFFER_LOCK_EXCLUSIVE, BUFFER_LOCK_UNLOCK, BufferGetPage(), CHECK_FOR_INTERRUPTS, compute_infobits(), compute_new_xmax_infomask(), elog, END_CRIT_SECTION, ERROR, fb(), GetMultiXactIdMembers(), heap_fetch(), HEAP_KEYS_UPDATED, HEAP_LOCK_BLKREF_HEAP, HEAP_LOCK_BLKREF_VM, HEAP_LOCKED_UPGRADED(), 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(), HeapTupleHeaderGetRawXmax(), HeapTupleHeaderGetUpdateXid(), HeapTupleHeaderGetXmin(), HeapTupleHeaderIndicatesMovedPartitions(), HeapTupleHeaderIsOnlyLocked(), HeapTupleHeaderSetXmax(), i, InvalidBuffer, InvalidTransactionId, ItemPointerCopy(), ItemPointerEquals(), ItemPointerGetBlockNumber(), ItemPointerGetOffsetNumber(), LockBuffer(), MarkBufferDirty(), mode, MultiXactStatusForKeyShare, MultiXactStatusForNoKeyUpdate, MultiXactStatusForShare, MultiXactStatusForUpdate, MultiXactStatusNoKeyUpdate, MultiXactStatusUpdate, next, PageIsAllVisible(), PageSetLSN(), pfree(), RelationData::rd_locator, REGBUF_STANDARD, RelationNeedsWAL, ReleaseBuffer(), result, SizeOfHeapLockUpdated, SnapshotAny, START_CRIT_SECTION, test_lockmode_for_conflict(), TM_Ok, TM_SelfModified, TransactionIdDidAbort(), TransactionIdEquals, TransactionIdIsValid, UnlockReleaseBuffer(), VISIBILITYMAP_ALL_FROZEN, visibilitymap_clear(), visibilitymap_pin(), XactLockTableWait(), XLH_LOCK_ALL_FROZEN_CLEARED, XLOG_HEAP2_LOCK_UPDATED, XLogBeginInsert(), XLogInsert(), XLogRegisterBuffer(), XLogRegisterData(), and XLTW_LockUpdated.

Referenced by heap_lock_updated_tuple().

◆ heap_multi_insert()

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

Definition at line 2308 of file heapam.c.

2310{
2313 int i;
2314 int ndone;
2316 Page page;
2317 Buffer vmbuffer = InvalidBuffer;
2318 bool needwal;
2322 bool starting_with_empty_page = false;
2323 int npages = 0;
2324 int npages_used = 0;
2325
2326 /* currently not needed (thus unsupported) for heap_multi_insert() */
2328
2329 AssertHasSnapshotForToast(relation);
2330
2331 needwal = RelationNeedsWAL(relation);
2334
2335 /* Toast and set header data in all the slots */
2336 heaptuples = palloc(ntuples * sizeof(HeapTuple));
2337 for (i = 0; i < ntuples; i++)
2338 {
2339 HeapTuple tuple;
2340
2341 tuple = ExecFetchSlotHeapTuple(slots[i], true, NULL);
2342 slots[i]->tts_tableOid = RelationGetRelid(relation);
2343 tuple->t_tableOid = slots[i]->tts_tableOid;
2344 heaptuples[i] = heap_prepare_insert(relation, tuple, xid, cid,
2345 options);
2346 }
2347
2348 /*
2349 * We're about to do the actual inserts -- but check for conflict first,
2350 * to minimize the possibility of having to roll back work we've just
2351 * done.
2352 *
2353 * A check here does not definitively prevent a serialization anomaly;
2354 * that check MUST be done at least past the point of acquiring an
2355 * exclusive buffer content lock on every buffer that will be affected,
2356 * and MAY be done after all inserts are reflected in the buffers and
2357 * those locks are released; otherwise there is a race condition. Since
2358 * multiple buffers can be locked and unlocked in the loop below, and it
2359 * would not be feasible to identify and lock all of those buffers before
2360 * the loop, we must do a final check at the end.
2361 *
2362 * The check here could be omitted with no loss of correctness; it is
2363 * present strictly as an optimization.
2364 *
2365 * For heap inserts, we only need to check for table-level SSI locks. Our
2366 * new tuples can't possibly conflict with existing tuple locks, and heap
2367 * page locks are only consolidated versions of tuple locks; they do not
2368 * lock "gaps" as index page locks do. So we don't need to specify a
2369 * buffer when making the call, which makes for a faster check.
2370 */
2372
2373 ndone = 0;
2374 while (ndone < ntuples)
2375 {
2376 Buffer buffer;
2377 bool clear_all_visible = false;
2378 bool all_frozen_set = false;
2379 bool vmbuffer_modified = false;
2380 int nthispage;
2381
2383
2384 /*
2385 * Compute number of pages needed to fit the to-be-inserted tuples in
2386 * the worst case. This will be used to determine how much to extend
2387 * the relation by in RelationGetBufferForTuple(), if needed. If we
2388 * filled a prior page from scratch, we can just update our last
2389 * computation, but if we started with a partially filled page,
2390 * recompute from scratch, the number of potentially required pages
2391 * can vary due to tuples needing to fit onto the page, page headers
2392 * etc.
2393 */
2394 if (ndone == 0 || !starting_with_empty_page)
2395 {
2396 npages = heap_multi_insert_pages(heaptuples, ndone, ntuples,
2398 npages_used = 0;
2399 }
2400 else
2401 npages_used++;
2402
2403 /*
2404 * Find buffer where at least the next tuple will fit. If the page is
2405 * all-visible, this will also pin the requisite visibility map page.
2406 *
2407 * Also pin visibility map page if COPY FREEZE inserts tuples into an
2408 * empty page. See all_frozen_set below.
2409 */
2410 buffer = RelationGetBufferForTuple(relation, heaptuples[ndone]->t_len,
2411 InvalidBuffer, options, bistate,
2412 &vmbuffer, NULL,
2413 npages - npages_used);
2414 page = BufferGetPage(buffer);
2415
2417
2419 {
2420 all_frozen_set = true;
2421 /* Lock the vmbuffer before entering the critical section */
2423 }
2424 else if (PageIsAllVisible(page) && !(options & HEAP_INSERT_FROZEN))
2425 {
2426 clear_all_visible = true;
2427 /* Lock the vmbuffer before entering the critical section */
2429 }
2430
2431 /* NO EREPORT(ERROR) from here till changes are logged */
2433
2434 /*
2435 * RelationGetBufferForTuple has ensured that the first tuple fits.
2436 * Put that on the page, and then as many other tuples as fit.
2437 */
2438 RelationPutHeapTuple(relation, buffer, heaptuples[ndone], false);
2439
2440 /*
2441 * For logical decoding we need combo CIDs to properly decode the
2442 * catalog.
2443 */
2444 if (needwal && need_cids)
2445 log_heap_new_cid(relation, heaptuples[ndone]);
2446
2447 for (nthispage = 1; ndone + nthispage < ntuples; nthispage++)
2448 {
2450
2451 if (PageGetHeapFreeSpace(page) < MAXALIGN(heaptup->t_len) + saveFreeSpace)
2452 break;
2453
2454 RelationPutHeapTuple(relation, buffer, heaptup, false);
2455
2456 /*
2457 * For logical decoding we need combo CIDs to properly decode the
2458 * catalog.
2459 */
2460 if (needwal && need_cids)
2461 log_heap_new_cid(relation, heaptup);
2462 }
2463
2464 /*
2465 * If the page is all visible, need to clear that, unless we're only
2466 * going to add further frozen rows to it.
2467 *
2468 * If we're only adding already frozen rows to a previously empty
2469 * page, mark it as all-frozen and update the visibility map. We're
2470 * already holding a pin on the vmbuffer.
2471 */
2473 {
2475 /* It's possible the VM bits were already clear */
2476 if (visibilitymap_clear(relation->rd_locator,
2477 BufferGetBlockNumber(buffer),
2478 vmbuffer, VISIBILITYMAP_VALID_BITS))
2479 vmbuffer_modified = true;
2480
2481 PageClearAllVisible(page);
2482 }
2483 else if (all_frozen_set)
2484 {
2485 PageSetAllVisible(page);
2486 PageClearPrunable(page);
2488 vmbuffer,
2491 relation->rd_locator);
2492 }
2493
2494 /*
2495 * Set pd_prune_xid. See heap_insert() for more on why we do this when
2496 * inserting tuples. This only makes sense if we aren't already
2497 * setting the page frozen in the VM and we're not in bootstrap mode.
2498 */
2500 PageSetPrunable(page, xid);
2501
2502 MarkBufferDirty(buffer);
2503
2504 /* XLOG stuff */
2505 if (needwal)
2506 {
2510 char *tupledata;
2511 int totaldatalen;
2512 char *scratchptr = scratch.data;
2513 bool init;
2514 int bufflags = 0;
2515
2516 /*
2517 * If the page was previously empty, we can reinit the page
2518 * instead of restoring the whole thing.
2519 */
2521
2522 /* allocate xl_heap_multi_insert struct from the scratch area */
2525
2526 /*
2527 * Allocate offsets array. Unless we're reinitializing the page,
2528 * in that case the tuples are stored in order starting at
2529 * FirstOffsetNumber and we don't need to store the offsets
2530 * explicitly.
2531 */
2532 if (!init)
2533 scratchptr += nthispage * sizeof(OffsetNumber);
2534
2535 /* the rest of the scratch space is used for tuple data */
2536 tupledata = scratchptr;
2537
2538 /* check that the mutually exclusive flags are not both set */
2540
2541 xlrec->flags = 0;
2544
2545 /*
2546 * We don't have to worry about including a conflict xid in the
2547 * WAL record, as HEAP_INSERT_FROZEN intentionally violates
2548 * visibility rules.
2549 */
2550 if (all_frozen_set)
2552
2553 xlrec->ntuples = nthispage;
2554
2555 /*
2556 * Write out an xl_multi_insert_tuple and the tuple data itself
2557 * for each tuple.
2558 */
2559 for (i = 0; i < nthispage; i++)
2560 {
2562 xl_multi_insert_tuple *tuphdr;
2563 int datalen;
2564
2565 if (!init)
2566 xlrec->offsets[i] = ItemPointerGetOffsetNumber(&heaptup->t_self);
2567 /* xl_multi_insert_tuple needs two-byte alignment. */
2569 scratchptr = ((char *) tuphdr) + SizeOfMultiInsertTuple;
2570
2571 tuphdr->t_infomask2 = heaptup->t_data->t_infomask2;
2572 tuphdr->t_infomask = heaptup->t_data->t_infomask;
2573 tuphdr->t_hoff = heaptup->t_data->t_hoff;
2574
2575 /* write bitmap [+ padding] [+ oid] + data */
2576 datalen = heaptup->t_len - SizeofHeapTupleHeader;
2578 (char *) heaptup->t_data + SizeofHeapTupleHeader,
2579 datalen);
2580 tuphdr->datalen = datalen;
2581 scratchptr += datalen;
2582 }
2583 totaldatalen = scratchptr - tupledata;
2584 Assert((scratchptr - scratch.data) < BLCKSZ);
2585
2586 if (need_tuple_data)
2588
2589 /*
2590 * Signal that this is the last xl_heap_multi_insert record
2591 * emitted by this call to heap_multi_insert(). Needed for logical
2592 * decoding so it knows when to cleanup temporary data.
2593 */
2594 if (ndone + nthispage == ntuples)
2596
2597 if (init)
2598 {
2599 info |= XLOG_HEAP_INIT_PAGE;
2601 }
2602
2603 /*
2604 * If we're doing logical decoding, include the new tuple data
2605 * even if we take a full-page image of the page.
2606 */
2607 if (need_tuple_data)
2609
2611 XLogRegisterData(xlrec, tupledata - scratch.data);
2616
2618 totaldatalen);
2619
2620 /* filtering by origin on a row level is much more efficient */
2622
2623 recptr = XLogInsert(RM_HEAP2_ID, info);
2624
2625 PageSetLSN(page, recptr);
2627 {
2628 Assert(BufferIsDirty(vmbuffer));
2629 PageSetLSN(BufferGetPage(vmbuffer), recptr);
2630 }
2631 }
2632
2634
2635 /*
2636 * We locked vmbuffer if clear_all_visible was true regardless of
2637 * whether or not we ended up modifying the vmbuffer.
2638 */
2640 LockBuffer(vmbuffer, BUFFER_LOCK_UNLOCK);
2641
2642 UnlockReleaseBuffer(buffer);
2643 ndone += nthispage;
2644
2645 /*
2646 * NB: Only release vmbuffer after inserting all tuples - it's fairly
2647 * likely that we'll insert into subsequent heap pages that are likely
2648 * to use the same vm page.
2649 */
2650 }
2651
2652 /* We're done with inserting all tuples, so release the last vmbuffer. */
2653 if (vmbuffer != InvalidBuffer)
2654 ReleaseBuffer(vmbuffer);
2655
2656 /*
2657 * We're done with the actual inserts. Check for conflicts again, to
2658 * ensure that all rw-conflicts in to these inserts are detected. Without
2659 * this final check, a sequential scan of the heap may have locked the
2660 * table after the "before" check, missing one opportunity to detect the
2661 * conflict, and then scanned the table before the new tuples were there,
2662 * missing the other chance to detect the conflict.
2663 *
2664 * For heap inserts, we only need to check for table-level SSI locks. Our
2665 * new tuples can't possibly conflict with existing tuple locks, and heap
2666 * page locks are only consolidated versions of tuple locks; they do not
2667 * lock "gaps" as index page locks do. So we don't need to specify a
2668 * buffer when making the call.
2669 */
2671
2672 /*
2673 * If tuples are cacheable, mark them for invalidation from the caches in
2674 * case we abort. Note it is OK to do this after releasing the buffer,
2675 * because the heaptuples data structure is all in local memory, not in
2676 * the shared buffer.
2677 */
2678 if (IsCatalogRelation(relation))
2679 {
2680 for (i = 0; i < ntuples; i++)
2682 }
2683
2684 /* copy t_self fields back to the caller's slots */
2685 for (i = 0; i < ntuples; i++)
2686 slots[i]->tts_tid = heaptuples[i]->t_self;
2687
2688 pgstat_count_heap_insert(relation, ntuples);
2689}

References Assert, AssertHasSnapshotForToast(), BUFFER_LOCK_EXCLUSIVE, BUFFER_LOCK_UNLOCK, BufferGetBlockNumber(), BufferGetPage(), BufferIsDirty(), CacheInvalidateHeapTuple(), CHECK_FOR_INTERRUPTS, CheckForSerializableConflictIn(), xl_multi_insert_tuple::datalen, END_CRIT_SECTION, ExecFetchSlotHeapTuple(), fb(), GetCurrentTransactionId(), HEAP_DEFAULT_FILLFACTOR, HEAP_INSERT_FROZEN, HEAP_INSERT_NO_LOGICAL, HEAP_MULTI_INSERT_BLKREF_HEAP, HEAP_MULTI_INSERT_BLKREF_VM, heap_multi_insert_pages(), heap_prepare_insert(), i, init, InvalidBlockNumber, InvalidBuffer, IsCatalogRelation(), ItemPointerGetOffsetNumber(), LockBuffer(), log_heap_new_cid(), MarkBufferDirty(), MAXALIGN, memcpy(), PageClearAllVisible(), PageClearPrunable, PageGetHeapFreeSpace(), PageGetMaxOffsetNumber(), PageIsAllVisible(), PageSetAllVisible(), PageSetLSN(), PageSetPrunable, palloc(), pgstat_count_heap_insert(), RelationData::rd_locator, REGBUF_KEEP_DATA, REGBUF_STANDARD, REGBUF_WILL_INIT, RelationGetBufferForTuple(), RelationGetRelid, RelationGetTargetPageFreeSpace, RelationIsAccessibleInLogicalDecoding, RelationIsLogicallyLogged, RelationNeedsWAL, RelationPutHeapTuple(), ReleaseBuffer(), SHORTALIGN, SizeOfHeapMultiInsert, SizeofHeapTupleHeader, SizeOfMultiInsertTuple, START_CRIT_SECTION, xl_multi_insert_tuple::t_hoff, xl_multi_insert_tuple::t_infomask, xl_multi_insert_tuple::t_infomask2, HeapTupleData::t_tableOid, TransactionIdIsNormal, TupleTableSlot::tts_tableOid, UnlockReleaseBuffer(), VISIBILITYMAP_ALL_FROZEN, VISIBILITYMAP_ALL_VISIBLE, visibilitymap_clear(), visibilitymap_set(), VISIBILITYMAP_VALID_BITS, XLH_INSERT_ALL_FROZEN_SET, XLH_INSERT_ALL_VISIBLE_CLEARED, XLH_INSERT_CONTAINS_NEW_TUPLE, XLH_INSERT_LAST_IN_MULTI, XLOG_HEAP2_MULTI_INSERT, XLOG_HEAP_INIT_PAGE, XLOG_INCLUDE_ORIGIN, XLogBeginInsert(), XLogInsert(), XLogRegisterBufData(), XLogRegisterBuffer(), XLogRegisterData(), and XLogSetRecordFlags().

Referenced by CatalogTuplesMultiInsertWithInfo().

◆ heap_multi_insert_pages()

static int heap_multi_insert_pages ( HeapTuple heaptuples,
int  done,
int  ntuples,
Size  saveFreeSpace 
)
static

Definition at line 2276 of file heapam.c.

2277{
2279 int npages = 1;
2280
2281 for (int i = done; i < ntuples; i++)
2282 {
2283 size_t tup_sz = sizeof(ItemIdData) + MAXALIGN(heaptuples[i]->t_len);
2284
2285 if (page_avail < tup_sz)
2286 {
2287 npages++;
2289 }
2290 page_avail -= tup_sz;
2291 }
2292
2293 return npages;
2294}

References fb(), i, MAXALIGN, and SizeOfPageHeaderData.

Referenced by heap_multi_insert().

◆ heap_pre_freeze_checks()

void heap_pre_freeze_checks ( Buffer  buffer,
HeapTupleFreeze tuples,
int  ntuples 
)

Definition at line 7547 of file heapam.c.

7549{
7550 Page page = BufferGetPage(buffer);
7551
7552 for (int i = 0; i < ntuples; i++)
7553 {
7554 HeapTupleFreeze *frz = tuples + i;
7555 ItemId itemid = PageGetItemId(page, frz->offset);
7556 HeapTupleHeader htup;
7557
7558 htup = (HeapTupleHeader) PageGetItem(page, itemid);
7559
7560 /* Deliberately avoid relying on tuple hint bits here */
7561 if (frz->checkflags & HEAP_FREEZE_CHECK_XMIN_COMMITTED)
7562 {
7564
7566 if (unlikely(!TransactionIdDidCommit(xmin)))
7567 ereport(ERROR,
7569 errmsg_internal("uncommitted xmin %u needs to be frozen",
7570 xmin)));
7571 }
7572
7573 /*
7574 * TransactionIdDidAbort won't work reliably in the presence of XIDs
7575 * left behind by transactions that were in progress during a crash,
7576 * so we can only check that xmax didn't commit
7577 */
7578 if (frz->checkflags & HEAP_FREEZE_CHECK_XMAX_ABORTED)
7579 {
7581
7584 ereport(ERROR,
7586 errmsg_internal("cannot freeze committed xmax %u",
7587 xmax)));
7588 }
7589 }
7590}

References Assert, BufferGetPage(), ereport, errcode(), ERRCODE_DATA_CORRUPTED, errmsg_internal(), ERROR, fb(), HEAP_FREEZE_CHECK_XMAX_ABORTED, HEAP_FREEZE_CHECK_XMIN_COMMITTED, HeapTupleHeaderGetRawXmax(), HeapTupleHeaderGetRawXmin(), HeapTupleHeaderXminFrozen(), i, PageGetItem(), PageGetItemId(), TransactionIdDidCommit(), TransactionIdIsNormal, and unlikely.

Referenced by heap_page_will_freeze().

◆ heap_prepare_freeze_tuple()

bool heap_prepare_freeze_tuple ( HeapTupleHeader  tuple,
const struct VacuumCutoffs cutoffs,
HeapPageFreeze pagefrz,
HeapTupleFreeze frz,
bool totally_frozen 
)

Definition at line 7267 of file heapam.c.

7271{
7272 bool xmin_already_frozen = false,
7273 xmax_already_frozen = false;
7274 bool freeze_xmin = false,
7275 replace_xvac = false,
7276 replace_xmax = false,
7277 freeze_xmax = false;
7278 TransactionId xid;
7279
7280 frz->xmax = HeapTupleHeaderGetRawXmax(tuple);
7281 frz->t_infomask2 = tuple->t_infomask2;
7282 frz->t_infomask = tuple->t_infomask;
7283 frz->frzflags = 0;
7284 frz->checkflags = 0;
7285
7286 /*
7287 * Process xmin, while keeping track of whether it's already frozen, or
7288 * will become frozen iff our freeze plan is executed by caller (could be
7289 * neither).
7290 */
7291 xid = HeapTupleHeaderGetXmin(tuple);
7292 if (!TransactionIdIsNormal(xid))
7293 xmin_already_frozen = true;
7294 else
7295 {
7296 if (TransactionIdPrecedes(xid, cutoffs->relfrozenxid))
7297 ereport(ERROR,
7299 errmsg_internal("found xmin %u from before relfrozenxid %u",
7300 xid, cutoffs->relfrozenxid)));
7301
7302 /* Will set freeze_xmin flags in freeze plan below */
7304
7305 /* Verify that xmin committed if and when freeze plan is executed */
7306 if (freeze_xmin)
7307 {
7310 pagefrz->FreezePageConflictXid = xid;
7311 }
7312 }
7313
7314 /*
7315 * Old-style VACUUM FULL is gone, but we have to process xvac for as long
7316 * as we support having MOVED_OFF/MOVED_IN tuples in the database
7317 */
7318 xid = HeapTupleHeaderGetXvac(tuple);
7319 if (TransactionIdIsNormal(xid))
7320 {
7322 Assert(TransactionIdPrecedes(xid, cutoffs->OldestXmin));
7323
7324 /*
7325 * For Xvac, we always freeze proactively. This allows totally_frozen
7326 * tracking to ignore xvac.
7327 */
7328 replace_xvac = pagefrz->freeze_required = true;
7329
7331 pagefrz->FreezePageConflictXid = xid;
7332
7333 /* Will set replace_xvac flags in freeze plan below */
7334 }
7335
7336 /* Now process xmax */
7337 xid = frz->xmax;
7338 if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
7339 {
7340 /* Raw xmax is a MultiXactId */
7342 uint16 flags;
7343
7344 /*
7345 * We will either remove xmax completely (in the "freeze_xmax" path),
7346 * process xmax by replacing it (in the "replace_xmax" path), or
7347 * perform no-op xmax processing. The only constraint is that the
7348 * FreezeLimit/MultiXactCutoff postcondition must never be violated.
7349 */
7350 newxmax = FreezeMultiXactId(xid, tuple->t_infomask, cutoffs,
7351 &flags, pagefrz);
7352
7353 if (flags & FRM_NOOP)
7354 {
7355 /*
7356 * xmax is a MultiXactId, and nothing about it changes for now.
7357 * This is the only case where 'freeze_required' won't have been
7358 * set for us by FreezeMultiXactId, as well as the only case where
7359 * neither freeze_xmax nor replace_xmax are set (given a multi).
7360 *
7361 * This is a no-op, but the call to FreezeMultiXactId might have
7362 * ratcheted back NewRelfrozenXid and/or NewRelminMxid trackers
7363 * for us (the "freeze page" variants, specifically). That'll
7364 * make it safe for our caller to freeze the page later on, while
7365 * leaving this particular xmax undisturbed.
7366 *
7367 * FreezeMultiXactId is _not_ responsible for the "no freeze"
7368 * NewRelfrozenXid/NewRelminMxid trackers, though -- that's our
7369 * job. A call to heap_tuple_should_freeze for this same tuple
7370 * will take place below if 'freeze_required' isn't set already.
7371 * (This repeats work from FreezeMultiXactId, but allows "no
7372 * freeze" tracker maintenance to happen in only one place.)
7373 */
7376 }
7377 else if (flags & FRM_RETURN_IS_XID)
7378 {
7379 /*
7380 * xmax will become an updater Xid (original MultiXact's updater
7381 * member Xid will be carried forward as a simple Xid in Xmax).
7382 */
7384
7385 /*
7386 * NB -- some of these transformations are only valid because we
7387 * know the return Xid is a tuple updater (i.e. not merely a
7388 * locker.) Also note that the only reason we don't explicitly
7389 * worry about HEAP_KEYS_UPDATED is because it lives in
7390 * t_infomask2 rather than t_infomask.
7391 */
7392 frz->t_infomask &= ~HEAP_XMAX_BITS;
7393 frz->xmax = newxmax;
7394 if (flags & FRM_MARK_COMMITTED)
7395 frz->t_infomask |= HEAP_XMAX_COMMITTED;
7396 replace_xmax = true;
7397 }
7398 else if (flags & FRM_RETURN_IS_MULTI)
7399 {
7402
7403 /*
7404 * xmax is an old MultiXactId that we have to replace with a new
7405 * MultiXactId, to carry forward two or more original member XIDs.
7406 */
7408
7409 /*
7410 * We can't use GetMultiXactIdHintBits directly on the new multi
7411 * here; that routine initializes the masks to all zeroes, which
7412 * would lose other bits we need. Doing it this way ensures all
7413 * unrelated bits remain untouched.
7414 */
7415 frz->t_infomask &= ~HEAP_XMAX_BITS;
7416 frz->t_infomask2 &= ~HEAP_KEYS_UPDATED;
7418 frz->t_infomask |= newbits;
7419 frz->t_infomask2 |= newbits2;
7420 frz->xmax = newxmax;
7421 replace_xmax = true;
7422 }
7423 else
7424 {
7425 /*
7426 * Freeze plan for tuple "freezes xmax" in the strictest sense:
7427 * it'll leave nothing in xmax (neither an Xid nor a MultiXactId).
7428 */
7429 Assert(flags & FRM_INVALIDATE_XMAX);
7431
7432 /* Will set freeze_xmax flags in freeze plan below */
7433 freeze_xmax = true;
7434 }
7435
7436 /* MultiXactId processing forces freezing (barring FRM_NOOP case) */
7437 Assert(pagefrz->freeze_required || (!freeze_xmax && !replace_xmax));
7438 }
7439 else if (TransactionIdIsNormal(xid))
7440 {
7441 /* Raw xmax is normal XID */
7442 if (TransactionIdPrecedes(xid, cutoffs->relfrozenxid))
7443 ereport(ERROR,
7445 errmsg_internal("found xmax %u from before relfrozenxid %u",
7446 xid, cutoffs->relfrozenxid)));
7447
7448 /* Will set freeze_xmax flags in freeze plan below */
7450
7451 /*
7452 * Verify that xmax aborted if and when freeze plan is executed,
7453 * provided it's from an update. (A lock-only xmax can be removed
7454 * independent of this, since the lock is released at xact end.)
7455 */
7457 frz->checkflags |= HEAP_FREEZE_CHECK_XMAX_ABORTED;
7458 }
7459 else if (!TransactionIdIsValid(xid))
7460 {
7461 /* Raw xmax is InvalidTransactionId XID */
7462 Assert((tuple->t_infomask & HEAP_XMAX_IS_MULTI) == 0);
7463 xmax_already_frozen = true;
7464 }
7465 else
7466 ereport(ERROR,
7468 errmsg_internal("found raw xmax %u (infomask 0x%04x) not invalid and not multi",
7469 xid, tuple->t_infomask)));
7470
7471 if (freeze_xmin)
7472 {
7474
7475 frz->t_infomask |= HEAP_XMIN_FROZEN;
7476 }
7477 if (replace_xvac)
7478 {
7479 /*
7480 * If a MOVED_OFF tuple is not dead, the xvac transaction must have
7481 * failed; whereas a non-dead MOVED_IN tuple must mean the xvac
7482 * transaction succeeded.
7483 */
7484 Assert(pagefrz->freeze_required);
7485 if (tuple->t_infomask & HEAP_MOVED_OFF)
7486 frz->frzflags |= XLH_INVALID_XVAC;
7487 else
7488 frz->frzflags |= XLH_FREEZE_XVAC;
7489 }
7490 if (replace_xmax)
7491 {
7493 Assert(pagefrz->freeze_required);
7494
7495 /* Already set replace_xmax flags in freeze plan earlier */
7496 }
7497 if (freeze_xmax)
7498 {
7500
7501 frz->xmax = InvalidTransactionId;
7502
7503 /*
7504 * The tuple might be marked either XMAX_INVALID or XMAX_COMMITTED +
7505 * LOCKED. Normalize to INVALID just to be sure no one gets confused.
7506 * Also get rid of the HEAP_KEYS_UPDATED bit.
7507 */
7508 frz->t_infomask &= ~HEAP_XMAX_BITS;
7509 frz->t_infomask |= HEAP_XMAX_INVALID;
7510 frz->t_infomask2 &= ~HEAP_HOT_UPDATED;
7511 frz->t_infomask2 &= ~HEAP_KEYS_UPDATED;
7512 }
7513
7514 /*
7515 * Determine if this tuple is already totally frozen, or will become
7516 * totally frozen (provided caller executes freeze plans for the page)
7517 */
7520
7521 if (!pagefrz->freeze_required && !(xmin_already_frozen &&
7523 {
7524 /*
7525 * So far no previous tuple from the page made freezing mandatory.
7526 * Does this tuple force caller to freeze the entire page?
7527 */
7528 pagefrz->freeze_required =
7529 heap_tuple_should_freeze(tuple, cutoffs,
7530 &pagefrz->NoFreezePageRelfrozenXid,
7531 &pagefrz->NoFreezePageRelminMxid);
7532 }
7533
7534 /* Tell caller if this tuple has a usable freeze plan set in *frz */
7536}

References Assert, ereport, errcode(), ERRCODE_DATA_CORRUPTED, errmsg_internal(), ERROR, fb(), HeapPageFreeze::freeze_required, FreezeMultiXactId(), HeapPageFreeze::FreezePageConflictXid, FRM_INVALIDATE_XMAX, FRM_MARK_COMMITTED, FRM_NOOP, FRM_RETURN_IS_MULTI, FRM_RETURN_IS_XID, GetMultiXactIdHintBits(), HEAP_FREEZE_CHECK_XMAX_ABORTED, HEAP_FREEZE_CHECK_XMIN_COMMITTED, HEAP_MOVED_OFF, heap_tuple_should_freeze(), HEAP_XMAX_COMMITTED, HEAP_XMAX_INVALID, HEAP_XMAX_IS_LOCKED_ONLY(), HEAP_XMAX_IS_MULTI, HEAP_XMIN_FROZEN, HeapTupleHeaderGetRawXmax(), HeapTupleHeaderGetXmin(), HeapTupleHeaderGetXvac(), InvalidTransactionId, VacuumCutoffs::MultiXactCutoff, MultiXactIdIsValid, MultiXactIdPrecedes(), HeapPageFreeze::NoFreezePageRelfrozenXid, HeapPageFreeze::NoFreezePageRelminMxid, VacuumCutoffs::OldestMxact, VacuumCutoffs::OldestXmin, VacuumCutoffs::relfrozenxid, HeapTupleHeaderData::t_infomask, HeapTupleHeaderData::t_infomask2, TransactionIdFollows(), TransactionIdIsNormal, TransactionIdIsValid, TransactionIdPrecedes(), TransactionIdPrecedesOrEquals(), XLH_FREEZE_XVAC, and XLH_INVALID_XVAC.

Referenced by heap_freeze_tuple(), and heap_prune_record_unchanged_lp_normal().

◆ heap_prepare_insert()

static HeapTuple heap_prepare_insert ( Relation  relation,
HeapTuple  tup,
TransactionId  xid,
CommandId  cid,
uint32  options 
)
static

Definition at line 2228 of file heapam.c.

2230{
2231 /*
2232 * To allow parallel inserts, we need to ensure that they are safe to be
2233 * performed in workers. We have the infrastructure to allow parallel
2234 * inserts in general except for the cases where inserts generate a new
2235 * CommandId (eg. inserts into a table having a foreign key column).
2236 */
2237 if (IsParallelWorker())
2238 ereport(ERROR,
2240 errmsg("cannot insert tuples in a parallel worker")));
2241
2242 tup->t_data->t_infomask &= ~(HEAP_XACT_MASK);
2243 tup->t_data->t_infomask2 &= ~(HEAP2_XACT_MASK);
2244 tup->t_data->t_infomask |= HEAP_XMAX_INVALID;
2245 HeapTupleHeaderSetXmin(tup->t_data, xid);
2248
2249 HeapTupleHeaderSetCmin(tup->t_data, cid);
2250 HeapTupleHeaderSetXmax(tup->t_data, 0); /* for cleanliness */
2251 tup->t_tableOid = RelationGetRelid(relation);
2252
2253 /*
2254 * If the new tuple is too big for storage or contains already toasted
2255 * out-of-line attributes from some other relation, invoke the toaster.
2256 */
2257 if (relation->rd_rel->relkind != RELKIND_RELATION &&
2258 relation->rd_rel->relkind != RELKIND_MATVIEW)
2259 {
2260 /* toast table entries should never be recursively toasted */
2262 return tup;
2263 }
2264 else if (HeapTupleHasExternal(tup) || tup->t_len > TOAST_TUPLE_THRESHOLD)
2265 return heap_toast_insert_or_update(relation, tup, NULL, options);
2266 else
2267 return tup;
2268}

References Assert, ereport, errcode(), errmsg, ERROR, fb(), HEAP2_XACT_MASK, HEAP_INSERT_FROZEN, heap_toast_insert_or_update(), HEAP_XACT_MASK, HEAP_XMAX_INVALID, HeapTupleHasExternal(), HeapTupleHeaderSetCmin(), HeapTupleHeaderSetXmax(), HeapTupleHeaderSetXmin(), HeapTupleHeaderSetXminFrozen(), IsParallelWorker, RelationData::rd_rel, RelationGetRelid, and TOAST_TUPLE_THRESHOLD.

Referenced by heap_insert(), and heap_multi_insert().

◆ heap_prepare_pagescan()

void heap_prepare_pagescan ( TableScanDesc  sscan)

Definition at line 619 of file heapam.c.

620{
622 Buffer buffer = scan->rs_cbuf;
623 BlockNumber block = scan->rs_cblock;
624 Snapshot snapshot;
625 Page page;
626 int lines;
627 bool all_visible;
629
630 Assert(BufferGetBlockNumber(buffer) == block);
631
632 /* ensure we're not accidentally being used when not in pagemode */
634 snapshot = scan->rs_base.rs_snapshot;
635
636 /*
637 * Prune and repair fragmentation for the whole page, if possible.
638 */
639 heap_page_prune_opt(scan->rs_base.rs_rd, buffer, &scan->rs_vmbuffer,
640 sscan->rs_flags & SO_HINT_REL_READ_ONLY);
641
642 /*
643 * We must hold share lock on the buffer content while examining tuple
644 * visibility. Afterwards, however, the tuples we have found to be
645 * visible are guaranteed good as long as we hold the buffer pin.
646 */
648
649 page = BufferGetPage(buffer);
650 lines = PageGetMaxOffsetNumber(page);
651
652 /*
653 * If the all-visible flag indicates that all tuples on the page are
654 * visible to everyone, we can skip the per-tuple visibility tests.
655 *
656 * Note: In hot standby, a tuple that's already visible to all
657 * transactions on the primary might still be invisible to a read-only
658 * transaction in the standby. We partly handle this problem by tracking
659 * the minimum xmin of visible tuples as the cut-off XID while marking a
660 * page all-visible on the primary and WAL log that along with the
661 * visibility map SET operation. In hot standby, we wait for (or abort)
662 * all transactions that can potentially may not see one or more tuples on
663 * the page. That's how index-only scans work fine in hot standby. A
664 * crucial difference between index-only scans and heap scans is that the
665 * index-only scan completely relies on the visibility map where as heap
666 * scan looks at the page-level PD_ALL_VISIBLE flag. We are not sure if
667 * the page-level flag can be trusted in the same way, because it might
668 * get propagated somehow without being explicitly WAL-logged, e.g. via a
669 * full page write. Until we can prove that beyond doubt, let's check each
670 * tuple for visibility the hard way.
671 */
672 all_visible = PageIsAllVisible(page) && !snapshot->takenDuringRecovery;
675
676 /*
677 * We call page_collect_tuples() with constant arguments, to get the
678 * compiler to constant fold the constant arguments. Separate calls with
679 * constant arguments, rather than variables, are needed on several
680 * compilers to actually perform constant folding.
681 */
682 if (likely(all_visible))
683 {
685 scan->rs_ntuples = page_collect_tuples(scan, snapshot, page, buffer,
686 block, lines, true, false);
687 else
688 scan->rs_ntuples = page_collect_tuples(scan, snapshot, page, buffer,
689 block, lines, true, true);
690 }
691 else
692 {
694 scan->rs_ntuples = page_collect_tuples(scan, snapshot, page, buffer,
695 block, lines, false, false);
696 else
697 scan->rs_ntuples = page_collect_tuples(scan, snapshot, page, buffer,
698 block, lines, false, true);
699 }
700
702}

References Assert, BUFFER_LOCK_SHARE, BUFFER_LOCK_UNLOCK, BufferGetBlockNumber(), BufferGetPage(), CheckForSerializableConflictOutNeeded(), fb(), heap_page_prune_opt(), likely, LockBuffer(), page_collect_tuples(), PageGetMaxOffsetNumber(), PageIsAllVisible(), HeapScanDescData::rs_base, HeapScanDescData::rs_cblock, HeapScanDescData::rs_cbuf, TableScanDescData::rs_flags, HeapScanDescData::rs_ntuples, TableScanDescData::rs_rd, TableScanDescData::rs_snapshot, HeapScanDescData::rs_vmbuffer, SO_ALLOW_PAGEMODE, SO_HINT_REL_READ_ONLY, and SnapshotData::takenDuringRecovery.

Referenced by heapam_scan_sample_next_block(), and heapgettup_pagemode().

◆ heap_rescan()

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

Definition at line 1332 of file heapam.c.

1334{
1336
1337 if (set_params)
1338 {
1339 if (allow_strat)
1341 else
1343
1344 if (allow_sync)
1346 else
1348
1349 if (allow_pagemode && scan->rs_base.rs_snapshot &&
1352 else
1354 }
1355
1356 /*
1357 * unpin scan buffers
1358 */
1359 if (BufferIsValid(scan->rs_cbuf))
1360 {
1361 ReleaseBuffer(scan->rs_cbuf);
1362 scan->rs_cbuf = InvalidBuffer;
1363 }
1364
1365 if (BufferIsValid(scan->rs_vmbuffer))
1366 {
1368 scan->rs_vmbuffer = InvalidBuffer;
1369 }
1370
1371 /*
1372 * SO_TYPE_BITMAPSCAN would be cleaned up here, but it does not hold any
1373 * additional data vs a normal HeapScan
1374 */
1375
1376 /*
1377 * The read stream is reset on rescan. This must be done before
1378 * initscan(), as some state referred to by read_stream_reset() is reset
1379 * in initscan().
1380 */
1381 if (scan->rs_read_stream)
1383
1384 /*
1385 * reinitialize scan descriptor
1386 */
1387 initscan(scan, key, true);
1388}

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

◆ heap_scan_stream_read_next_parallel()

static BlockNumber heap_scan_stream_read_next_parallel ( ReadStream stream,
void callback_private_data,
void per_buffer_data 
)
static

◆ heap_scan_stream_read_next_serial()

static BlockNumber heap_scan_stream_read_next_serial ( ReadStream stream,
void callback_private_data,
void per_buffer_data 
)
static

Definition at line 295 of file heapam.c.

298{
299 HeapScanDesc scan = (HeapScanDesc) callback_private_data;
300
301 if (unlikely(!scan->rs_inited))
302 {
304 scan->rs_inited = true;
305 }
306 else
308 scan->rs_prefetch_block,
309 scan->rs_dir);
310
311 return scan->rs_prefetch_block;
312}

References heapgettup_advance_block(), heapgettup_initial_block(), HeapScanDescData::rs_dir, HeapScanDescData::rs_inited, HeapScanDescData::rs_prefetch_block, and unlikely.

Referenced by heap_beginscan().

◆ heap_set_tidrange()

void heap_set_tidrange ( TableScanDesc  sscan,
ItemPointer  mintid,
ItemPointer  maxtid 
)

Definition at line 1505 of file heapam.c.

1507{
1513
1514 /*
1515 * For relations without any pages, we can simply leave the TID range
1516 * unset. There will be no tuples to scan, therefore no tuples outside
1517 * the given TID range.
1518 */
1519 if (scan->rs_nblocks == 0)
1520 return;
1521
1522 /*
1523 * Set up some ItemPointers which point to the first and last possible
1524 * tuples in the heap.
1525 */
1528
1529 /*
1530 * If the given maximum TID is below the highest possible TID in the
1531 * relation, then restrict the range to that, otherwise we scan to the end
1532 * of the relation.
1533 */
1536
1537 /*
1538 * If the given minimum TID is above the lowest possible TID in the
1539 * relation, then restrict the range to only scan for TIDs above that.
1540 */
1543
1544 /*
1545 * Check for an empty range and protect from would be negative results
1546 * from the numBlks calculation below.
1547 */
1549 {
1550 /* Set an empty range of blocks to scan */
1552 return;
1553 }
1554
1555 /*
1556 * Calculate the first block and the number of blocks we must scan. We
1557 * could be more aggressive here and perform some more validation to try
1558 * and further narrow the scope of blocks to scan by checking if the
1559 * lowestItem has an offset above MaxOffsetNumber. In this case, we could
1560 * advance startBlk by one. Likewise, if highestItem has an offset of 0
1561 * we could scan one fewer blocks. However, such an optimization does not
1562 * seem worth troubling over, currently.
1563 */
1565
1568
1569 /* Set the start block and number of blocks to scan */
1571
1572 /* Finally, set the TID range in sscan */
1573 ItemPointerCopy(&lowestItem, &sscan->st.tidrange.rs_mintid);
1574 ItemPointerCopy(&highestItem, &sscan->st.tidrange.rs_maxtid);
1575}

References fb(), FirstOffsetNumber, heap_setscanlimits(), ItemPointerCompare(), ItemPointerCopy(), ItemPointerGetBlockNumberNoCheck(), ItemPointerSet(), MaxOffsetNumber, and HeapScanDescData::rs_nblocks.

◆ heap_setscanlimits()

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

Definition at line 503 of file heapam.c.

504{
506
507 Assert(!scan->rs_inited); /* else too late to change */
508 /* else rs_startblock is significant */
510
511 /* Check startBlk is valid (but allow case of zero blocks...) */
512 Assert(startBlk == 0 || startBlk < scan->rs_nblocks);
513
514 scan->rs_startblock = startBlk;
515 scan->rs_numblocks = numBlks;
516}

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

Referenced by heap_set_tidrange(), and heapam_index_build_range_scan().

◆ heap_tuple_needs_eventual_freeze()

bool heap_tuple_needs_eventual_freeze ( HeapTupleHeader  tuple)

Definition at line 8031 of file heapam.c.

8032{
8033 TransactionId xid;
8034
8035 /*
8036 * If xmin is a normal transaction ID, this tuple is definitely not
8037 * frozen.
8038 */
8039 xid = HeapTupleHeaderGetXmin(tuple);
8040 if (TransactionIdIsNormal(xid))
8041 return true;
8042
8043 /*
8044 * If xmax is a valid xact or multixact, this tuple is also not frozen.
8045 */
8046 if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
8047 {
8048 MultiXactId multi;
8049
8050 multi = HeapTupleHeaderGetRawXmax(tuple);
8051 if (MultiXactIdIsValid(multi))
8052 return true;
8053 }
8054 else
8055 {
8056 xid = HeapTupleHeaderGetRawXmax(tuple);
8057 if (TransactionIdIsNormal(xid))
8058 return true;
8059 }
8060
8061 if (tuple->t_infomask & HEAP_MOVED)
8062 {
8063 xid = HeapTupleHeaderGetXvac(tuple);
8064 if (TransactionIdIsNormal(xid))
8065 return true;
8066 }
8067
8068 return false;
8069}

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

Referenced by collect_corrupt_items(), and heap_page_would_be_all_visible().

◆ heap_tuple_should_freeze()

bool heap_tuple_should_freeze ( HeapTupleHeader  tuple,
const struct VacuumCutoffs cutoffs,
TransactionId NoFreezePageRelfrozenXid,
MultiXactId NoFreezePageRelminMxid 
)

Definition at line 8086 of file heapam.c.

8090{
8091 TransactionId xid;
8092 MultiXactId multi;
8093 bool freeze = false;
8094
8095 /* First deal with xmin */
8096 xid = HeapTupleHeaderGetXmin(tuple);
8097 if (TransactionIdIsNormal(xid))
8098 {
8100 if (TransactionIdPrecedes(xid, *NoFreezePageRelfrozenXid))
8101 *NoFreezePageRelfrozenXid = xid;
8102 if (TransactionIdPrecedes(xid, cutoffs->FreezeLimit))
8103 freeze = true;
8104 }
8105
8106 /* Now deal with xmax */
8108 multi = InvalidMultiXactId;
8109 if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
8110 multi = HeapTupleHeaderGetRawXmax(tuple);
8111 else
8112 xid = HeapTupleHeaderGetRawXmax(tuple);
8113
8114 if (TransactionIdIsNormal(xid))
8115 {
8117 /* xmax is a non-permanent XID */
8118 if (TransactionIdPrecedes(xid, *NoFreezePageRelfrozenXid))
8119 *NoFreezePageRelfrozenXid = xid;
8120 if (TransactionIdPrecedes(xid, cutoffs->FreezeLimit))
8121 freeze = true;
8122 }
8123 else if (!MultiXactIdIsValid(multi))
8124 {
8125 /* xmax is a permanent XID or invalid MultiXactId/XID */
8126 }
8127 else if (HEAP_LOCKED_UPGRADED(tuple->t_infomask))
8128 {
8129 /* xmax is a pg_upgrade'd MultiXact, which can't have updater XID */
8130 if (MultiXactIdPrecedes(multi, *NoFreezePageRelminMxid))
8131 *NoFreezePageRelminMxid = multi;
8132 /* heap_prepare_freeze_tuple always freezes pg_upgrade'd xmax */
8133 freeze = true;
8134 }
8135 else
8136 {
8137 /* xmax is a MultiXactId that may have an updater XID */
8138 MultiXactMember *members;
8139 int nmembers;
8140
8142 if (MultiXactIdPrecedes(multi, *NoFreezePageRelminMxid))
8143 *NoFreezePageRelminMxid = multi;
8144 if (MultiXactIdPrecedes(multi, cutoffs->MultiXactCutoff))
8145 freeze = true;
8146
8147 /* need to check whether any member of the mxact is old */
8148 nmembers = GetMultiXactIdMembers(multi, &members, false,
8150
8151 for (int i = 0; i < nmembers; i++)
8152 {
8153 xid = members[i].xid;
8155 if (TransactionIdPrecedes(xid, *NoFreezePageRelfrozenXid))
8156 *NoFreezePageRelfrozenXid = xid;
8157 if (TransactionIdPrecedes(xid, cutoffs->FreezeLimit))
8158 freeze = true;
8159 }
8160 if (nmembers > 0)
8161 pfree(members);
8162 }
8163
8164 if (tuple->t_infomask & HEAP_MOVED)
8165 {
8166 xid = HeapTupleHeaderGetXvac(tuple);
8167 if (TransactionIdIsNormal(xid))
8168 {
8170 if (TransactionIdPrecedes(xid, *NoFreezePageRelfrozenXid))
8171 *NoFreezePageRelfrozenXid = xid;
8172 /* heap_prepare_freeze_tuple forces xvac freezing */
8173 freeze = true;
8174 }
8175 }
8176
8177 return freeze;
8178}

References Assert, VacuumCutoffs::FreezeLimit, GetMultiXactIdMembers(), HEAP_LOCKED_UPGRADED(), HEAP_MOVED, HEAP_XMAX_IS_LOCKED_ONLY(), HEAP_XMAX_IS_MULTI, HeapTupleHeaderGetRawXmax(), HeapTupleHeaderGetXmin(), HeapTupleHeaderGetXvac(), i, InvalidMultiXactId, InvalidTransactionId, VacuumCutoffs::MultiXactCutoff, MultiXactIdIsValid, MultiXactIdPrecedes(), MultiXactIdPrecedesOrEquals(), pfree(), VacuumCutoffs::relfrozenxid, VacuumCutoffs::relminmxid, HeapTupleHeaderData::t_infomask, TransactionIdIsNormal, TransactionIdPrecedes(), TransactionIdPrecedesOrEquals(), and MultiXactMember::xid.

Referenced by heap_prepare_freeze_tuple(), and lazy_scan_noprune().

◆ heap_update()

TM_Result heap_update ( Relation  relation,
const ItemPointerData otid,
HeapTuple  newtup,
CommandId  cid,
uint32 options   pg_attribute_unused(),
Snapshot  crosscheck,
bool  wait,
TM_FailureData tmfd,
LockTupleMode lockmode,
TU_UpdateIndexes update_indexes 
)

Definition at line 3267 of file heapam.c.

3271{
3280 ItemId lp;
3284 bool old_key_copied = false;
3286 Page page,
3287 newpage;
3288 BlockNumber block;
3290 Buffer buffer,
3291 newbuf,
3292 vmbuffer = InvalidBuffer,
3294 bool unlock_vmbuffer = false;
3295 bool unlock_vmbuffer_new = false;
3296 bool need_toast;
3298 pagefree;
3299 bool have_tuple_lock = false;
3300 bool iscombo;
3301 bool use_hot_update = false;
3302 bool summarized_update = false;
3303 bool key_intact;
3304 bool clear_all_visible = false;
3305 bool clear_all_visible_new = false;
3306 bool vmbuffer_modified = false;
3307 bool vmbuffer_new_modified = false;
3308 bool checked_lockers;
3309 bool locker_remains;
3310 bool id_has_external = false;
3317
3319
3320 /* Cheap, simplistic check that the tuple matches the rel's rowtype. */
3323
3324 AssertHasSnapshotForToast(relation);
3325
3326 /*
3327 * Forbid this during a parallel operation, lest it allocate a combo CID.
3328 * Other workers might need that combo CID for visibility checks, and we
3329 * have no provision for broadcasting it to them.
3330 */
3331 if (IsInParallelMode())
3332 ereport(ERROR,
3334 errmsg("cannot update tuples during a parallel operation")));
3335
3336#ifdef USE_ASSERT_CHECKING
3338#endif
3339
3340 /*
3341 * Fetch the list of attributes to be checked for various operations.
3342 *
3343 * For HOT considerations, this is wasted effort if we fail to update or
3344 * have to put the new tuple on a different page. But we must compute the
3345 * list before obtaining buffer lock --- in the worst case, if we are
3346 * doing an update on one of the relevant system catalogs, we could
3347 * deadlock if we try to fetch the list later. In any case, the relcache
3348 * caches the data so this is usually pretty cheap.
3349 *
3350 * We also need columns used by the replica identity and columns that are
3351 * considered the "key" of rows in the table.
3352 *
3353 * Note that we get copies of each bitmap, so we need not worry about
3354 * relcache flush happening midway through.
3355 */
3368
3370 INJECTION_POINT("heap_update-before-pin", NULL);
3371 buffer = ReadBuffer(relation, block);
3372 page = BufferGetPage(buffer);
3373
3374 /*
3375 * Before locking the buffer, pin the visibility map page if it appears to
3376 * be necessary. Since we haven't got the lock yet, someone else might be
3377 * in the middle of changing this, so we'll need to recheck after we have
3378 * the lock.
3379 */
3380 if (PageIsAllVisible(page))
3381 visibilitymap_pin(relation, block, &vmbuffer);
3382
3384
3386
3387 /*
3388 * Usually, a buffer pin and/or snapshot blocks pruning of otid, ensuring
3389 * we see LP_NORMAL here. When the otid origin is a syscache, we may have
3390 * neither a pin nor a snapshot. Hence, we may see other LP_ states, each
3391 * of which indicates concurrent pruning.
3392 *
3393 * Failing with TM_Updated would be most accurate. However, unlike other
3394 * TM_Updated scenarios, we don't know the successor ctid in LP_UNUSED and
3395 * LP_DEAD cases. While the distinction between TM_Updated and TM_Deleted
3396 * does matter to SQL statements UPDATE and MERGE, those SQL statements
3397 * hold a snapshot that ensures LP_NORMAL. Hence, the choice between
3398 * TM_Updated and TM_Deleted affects only the wording of error messages.
3399 * Settle on TM_Deleted, for two reasons. First, it avoids complicating
3400 * the specification of when tmfd->ctid is valid. Second, it creates
3401 * error log evidence that we took this branch.
3402 *
3403 * Since it's possible to see LP_UNUSED at otid, it's also possible to see
3404 * LP_NORMAL for a tuple that replaced LP_UNUSED. If it's a tuple for an
3405 * unrelated row, we'll fail with "duplicate key value violates unique".
3406 * XXX if otid is the live, newer version of the newtup row, we'll discard
3407 * changes originating in versions of this catalog row after the version
3408 * the caller got from syscache. See syscache-update-pruned.spec.
3409 */
3410 if (!ItemIdIsNormal(lp))
3411 {
3413
3414 UnlockReleaseBuffer(buffer);
3416 if (vmbuffer != InvalidBuffer)
3417 ReleaseBuffer(vmbuffer);
3418 tmfd->ctid = *otid;
3419 tmfd->xmax = InvalidTransactionId;
3420 tmfd->cmax = InvalidCommandId;
3422
3427 /* modified_attrs not yet initialized */
3429 return TM_Deleted;
3430 }
3431
3432 /*
3433 * Fill in enough data in oldtup for HeapDetermineColumnsInfo to work
3434 * properly.
3435 */
3436 oldtup.t_tableOid = RelationGetRelid(relation);
3437 oldtup.t_data = (HeapTupleHeader) PageGetItem(page, lp);
3438 oldtup.t_len = ItemIdGetLength(lp);
3439 oldtup.t_self = *otid;
3440
3441 /* the new tuple is ready, except for this: */
3442 newtup->t_tableOid = RelationGetRelid(relation);
3443
3444 /*
3445 * Determine columns modified by the update. Additionally, identify
3446 * whether any of the unmodified replica identity key attributes in the
3447 * old tuple is externally stored or not. This is required because for
3448 * such attributes the flattened value won't be WAL logged as part of the
3449 * new tuple so we must include it as part of the old_key_tuple. See
3450 * ExtractReplicaIdentity.
3451 */
3453 id_attrs, &oldtup,
3455
3456 /*
3457 * If we're not updating any "key" column, we can grab a weaker lock type.
3458 * This allows for more concurrency when we are running simultaneously
3459 * with foreign key checks.
3460 *
3461 * Note that if a column gets detoasted while executing the update, but
3462 * the value ends up being the same, this test will fail and we will use
3463 * the stronger lock. This is acceptable; the important case to optimize
3464 * is updates that don't manipulate key columns, not those that
3465 * serendipitously arrive at the same key values.
3466 */
3468 {
3469 *lockmode = LockTupleNoKeyExclusive;
3471 key_intact = true;
3472
3473 /*
3474 * If this is the first possibly-multixact-able operation in the
3475 * current transaction, set my per-backend OldestMemberMXactId
3476 * setting. We can be certain that the transaction will never become a
3477 * member of any older MultiXactIds than that. (We have to do this
3478 * even if we end up just using our own TransactionId below, since
3479 * some other backend could incorporate our XID into a MultiXact
3480 * immediately afterwards.)
3481 */
3483 }
3484 else
3485 {
3486 *lockmode = LockTupleExclusive;
3488 key_intact = false;
3489 }
3490
3491 /*
3492 * Note: beyond this point, use oldtup not otid to refer to old tuple.
3493 * otid may very well point at newtup->t_self, which we will overwrite
3494 * with the new tuple's location, so there's great risk of confusion if we
3495 * use otid anymore.
3496 */
3497
3498l2:
3499 checked_lockers = false;
3500 locker_remains = false;
3502
3503 /* see below about the "no wait" case */
3504 Assert(result != TM_BeingModified || wait);
3505
3506 if (result == TM_Invisible)
3507 {
3508 UnlockReleaseBuffer(buffer);
3509 ereport(ERROR,
3511 errmsg("attempted to update invisible tuple")));
3512 }
3513 else if (result == TM_BeingModified && wait)
3514 {
3517 bool can_continue = false;
3518
3519 /*
3520 * XXX note that we don't consider the "no wait" case here. This
3521 * isn't a problem currently because no caller uses that case, but it
3522 * should be fixed if such a caller is introduced. It wasn't a
3523 * problem previously because this code would always wait, but now
3524 * that some tuple locks do not conflict with one of the lock modes we
3525 * use, it is possible that this case is interesting to handle
3526 * specially.
3527 *
3528 * This may cause failures with third-party code that calls
3529 * heap_update directly.
3530 */
3531
3532 /* must copy state data before unlocking buffer */
3534 infomask = oldtup.t_data->t_infomask;
3535
3536 /*
3537 * Now we have to do something about the existing locker. If it's a
3538 * multi, sleep on it; we might be awakened before it is completely
3539 * gone (or even not sleep at all in some cases); we need to preserve
3540 * it as locker, unless it is gone completely.
3541 *
3542 * If it's not a multi, we need to check for sleeping conditions
3543 * before actually going to sleep. If the update doesn't conflict
3544 * with the locks, we just continue without sleeping (but making sure
3545 * it is preserved).
3546 *
3547 * Before sleeping, we need to acquire tuple lock to establish our
3548 * priority for the tuple (see heap_lock_tuple). LockTuple will
3549 * release us when we are next-in-line for the tuple. Note we must
3550 * not acquire the tuple lock until we're sure we're going to sleep;
3551 * otherwise we're open for race conditions with other transactions
3552 * holding the tuple lock which sleep on us.
3553 *
3554 * If we are forced to "start over" below, we keep the tuple lock;
3555 * this arranges that we stay at the head of the line while rechecking
3556 * tuple state.
3557 */
3559 {
3561 int remain;
3562 bool current_is_member = false;
3563
3565 *lockmode, &current_is_member))
3566 {
3568
3569 /*
3570 * Acquire the lock, if necessary (but skip it when we're
3571 * requesting a lock and already have one; avoids deadlock).
3572 */
3573 if (!current_is_member)
3574 heap_acquire_tuplock(relation, &(oldtup.t_self), *lockmode,
3576
3577 /* wait for multixact */
3579 relation, &oldtup.t_self, XLTW_Update,
3580 &remain);
3581 checked_lockers = true;
3582 locker_remains = remain != 0;
3584
3585 /*
3586 * If xwait had just locked the tuple then some other xact
3587 * could update this tuple before we get to this point. Check
3588 * for xmax change, and start over if so.
3589 */
3590 if (xmax_infomask_changed(oldtup.t_data->t_infomask,
3591 infomask) ||
3593 xwait))
3594 goto l2;
3595 }
3596
3597 /*
3598 * Note that the multixact may not be done by now. It could have
3599 * surviving members; our own xact or other subxacts of this
3600 * backend, and also any other concurrent transaction that locked
3601 * the tuple with LockTupleKeyShare if we only got
3602 * LockTupleNoKeyExclusive. If this is the case, we have to be
3603 * careful to mark the updated tuple with the surviving members in
3604 * Xmax.
3605 *
3606 * Note that there could have been another update in the
3607 * MultiXact. In that case, we need to check whether it committed
3608 * or aborted. If it aborted we are safe to update it again;
3609 * otherwise there is an update conflict, and we have to return
3610 * TableTuple{Deleted, Updated} below.
3611 *
3612 * In the LockTupleExclusive case, we still need to preserve the
3613 * surviving members: those would include the tuple locks we had
3614 * before this one, which are important to keep in case this
3615 * subxact aborts.
3616 */
3617 if (!HEAP_XMAX_IS_LOCKED_ONLY(oldtup.t_data->t_infomask))
3619 else
3621
3622 /*
3623 * There was no UPDATE in the MultiXact; or it aborted. No
3624 * TransactionIdIsInProgress() call needed here, since we called
3625 * MultiXactIdWait() above.
3626 */
3629 can_continue = true;
3630 }
3632 {
3633 /*
3634 * The only locker is ourselves; we can avoid grabbing the tuple
3635 * lock here, but must preserve our locking information.
3636 */
3637 checked_lockers = true;
3638 locker_remains = true;
3639 can_continue = true;
3640 }
3642 {
3643 /*
3644 * If it's just a key-share locker, and we're not changing the key
3645 * columns, we don't need to wait for it to end; but we need to
3646 * preserve it as locker.
3647 */
3648 checked_lockers = true;
3649 locker_remains = true;
3650 can_continue = true;
3651 }
3652 else
3653 {
3654 /*
3655 * Wait for regular transaction to end; but first, acquire tuple
3656 * lock.
3657 */
3659 heap_acquire_tuplock(relation, &(oldtup.t_self), *lockmode,
3661 XactLockTableWait(xwait, relation, &oldtup.t_self,
3662 XLTW_Update);
3663 checked_lockers = true;
3665
3666 /*
3667 * xwait is done, but if xwait had just locked the tuple then some
3668 * other xact could update this tuple before we get to this point.
3669 * Check for xmax change, and start over if so.
3670 */
3671 if (xmax_infomask_changed(oldtup.t_data->t_infomask, infomask) ||
3674 goto l2;
3675
3676 /* Otherwise check if it committed or aborted */
3677 UpdateXmaxHintBits(oldtup.t_data, buffer, xwait);
3678 if (oldtup.t_data->t_infomask & HEAP_XMAX_INVALID)
3679 can_continue = true;
3680 }
3681
3682 if (can_continue)
3683 result = TM_Ok;
3684 else if (!ItemPointerEquals(&oldtup.t_self, &oldtup.t_data->t_ctid))
3686 else
3688 }
3689
3690 /* Sanity check the result HeapTupleSatisfiesUpdate() and the logic above */
3691 if (result != TM_Ok)
3692 {
3694 result == TM_Updated ||
3695 result == TM_Deleted ||
3697 Assert(!(oldtup.t_data->t_infomask & HEAP_XMAX_INVALID));
3699 !ItemPointerEquals(&oldtup.t_self, &oldtup.t_data->t_ctid));
3700 }
3701
3703 {
3704 /* Perform additional check for transaction-snapshot mode RI updates */
3707 }
3708
3709 if (result != TM_Ok)
3710 {
3711 tmfd->ctid = oldtup.t_data->t_ctid;
3712 tmfd->xmax = HeapTupleHeaderGetUpdateXid(oldtup.t_data);
3713 if (result == TM_SelfModified)
3714 tmfd->cmax = HeapTupleHeaderGetCmax(oldtup.t_data);
3715 else
3716 tmfd->cmax = InvalidCommandId;
3717 UnlockReleaseBuffer(buffer);
3718 if (have_tuple_lock)
3719 UnlockTupleTuplock(relation, &(oldtup.t_self), *lockmode);
3720 if (vmbuffer != InvalidBuffer)
3721 ReleaseBuffer(vmbuffer);
3723
3730 return result;
3731 }
3732
3733 /*
3734 * If we didn't pin the visibility map page and the page has become all
3735 * visible while we were busy locking the buffer, or during some
3736 * subsequent window during which we had it unlocked, we'll have to unlock
3737 * and re-lock, to avoid holding the buffer lock across an I/O. That's a
3738 * bit unfortunate, especially since we'll now have to recheck whether the
3739 * tuple has been locked or updated under us, but hopefully it won't
3740 * happen very often.
3741 */
3742 if (vmbuffer == InvalidBuffer && PageIsAllVisible(page))
3743 {
3745 visibilitymap_pin(relation, block, &vmbuffer);
3747 goto l2;
3748 }
3749
3750 /* Fill in transaction status data */
3751
3752 /*
3753 * If the tuple we're updating is locked, we need to preserve the locking
3754 * info in the old tuple's Xmax. Prepare a new Xmax value for this.
3755 */
3757 oldtup.t_data->t_infomask,
3758 oldtup.t_data->t_infomask2,
3759 xid, *lockmode, true,
3762
3763 /*
3764 * And also prepare an Xmax value for the new copy of the tuple. If there
3765 * was no xmax previously, or there was one but all lockers are now gone,
3766 * then use InvalidTransactionId; otherwise, get the xmax from the old
3767 * tuple. (In rare cases that might also be InvalidTransactionId and yet
3768 * not have the HEAP_XMAX_INVALID bit set; that's fine.)
3769 */
3770 if ((oldtup.t_data->t_infomask & HEAP_XMAX_INVALID) ||
3771 HEAP_LOCKED_UPGRADED(oldtup.t_data->t_infomask) ||
3774 else
3776
3778 {
3781 }
3782 else
3783 {
3784 /*
3785 * If we found a valid Xmax for the new tuple, then the infomask bits
3786 * to use on the new tuple depend on what was there on the old one.
3787 * Note that since we're doing an update, the only possibility is that
3788 * the lockers had FOR KEY SHARE lock.
3789 */
3790 if (oldtup.t_data->t_infomask & HEAP_XMAX_IS_MULTI)
3791 {
3794 }
3795 else
3796 {
3799 }
3800 }
3801
3802 /*
3803 * Prepare the new tuple with the appropriate initial values of Xmin and
3804 * Xmax, as well as initial infomask bits as computed above.
3805 */
3806 newtup->t_data->t_infomask &= ~(HEAP_XACT_MASK);
3807 newtup->t_data->t_infomask2 &= ~(HEAP2_XACT_MASK);
3808 HeapTupleHeaderSetXmin(newtup->t_data, xid);
3810 newtup->t_data->t_infomask |= HEAP_UPDATED | infomask_new_tuple;
3811 newtup->t_data->t_infomask2 |= infomask2_new_tuple;
3813
3814 /*
3815 * Replace cid with a combo CID if necessary. Note that we already put
3816 * the plain cid into the new tuple.
3817 */
3819
3820 /*
3821 * If the toaster needs to be activated, OR if the new tuple will not fit
3822 * on the same page as the old, then we need to release the content lock
3823 * (but not the pin!) on the old tuple's buffer while we are off doing
3824 * TOAST and/or table-file-extension work. We must mark the old tuple to
3825 * show that it's locked, else other processes may try to update it
3826 * themselves.
3827 *
3828 * We need to invoke the toaster if there are already any out-of-line
3829 * toasted values present, or if the new tuple is over-threshold.
3830 */
3831 if (relation->rd_rel->relkind != RELKIND_RELATION &&
3832 relation->rd_rel->relkind != RELKIND_MATVIEW)
3833 {
3834 /* toast table entries should never be recursively toasted */
3837 need_toast = false;
3838 }
3839 else
3842 newtup->t_len > TOAST_TUPLE_THRESHOLD);
3843
3845
3846 newtupsize = MAXALIGN(newtup->t_len);
3847
3849 {
3853 bool cleared_all_frozen = false;
3854
3855 /*
3856 * To prevent concurrent sessions from updating the tuple, we have to
3857 * temporarily mark it locked, while we release the page-level lock.
3858 *
3859 * To satisfy the rule that any xid potentially appearing in a buffer
3860 * written out to disk, we unfortunately have to WAL log this
3861 * temporary modification. We can reuse xl_heap_lock for this
3862 * purpose. If we crash/error before following through with the
3863 * actual update, xmax will be of an aborted transaction, allowing
3864 * other sessions to proceed.
3865 */
3866
3867 /*
3868 * Compute xmax / infomask appropriate for locking the tuple. This has
3869 * to be done separately from the combo that's going to be used for
3870 * updating, because the potentially created multixact would otherwise
3871 * be wrong.
3872 */
3874 oldtup.t_data->t_infomask,
3875 oldtup.t_data->t_infomask2,
3876 xid, *lockmode, false,
3879
3881
3882 if (PageIsAllVisible(page))
3883 {
3885 unlock_vmbuffer = true;
3886 }
3887
3889
3890 /* Clear obsolete visibility flags ... */
3891 oldtup.t_data->t_infomask &= ~(HEAP_XMAX_BITS | HEAP_MOVED);
3892 oldtup.t_data->t_infomask2 &= ~HEAP_KEYS_UPDATED;
3894 /* ... and store info about transaction updating this tuple */
3897 oldtup.t_data->t_infomask |= infomask_lock_old_tuple;
3898 oldtup.t_data->t_infomask2 |= infomask2_lock_old_tuple;
3900
3901 /* temporarily make it look not-updated, but locked */
3902 oldtup.t_data->t_ctid = oldtup.t_self;
3903
3904 /*
3905 * Clear all-frozen bit on visibility map if needed. We could
3906 * immediately reset ALL_VISIBLE, but given that the WAL logging
3907 * overhead would be unchanged, that doesn't seem necessarily
3908 * worthwhile.
3909 */
3910 if (PageIsAllVisible(page))
3911 {
3912 /* It's possible all-frozen was already clear */
3913 if (visibilitymap_clear(relation->rd_locator, block, vmbuffer,
3915 cleared_all_frozen = true;
3916 }
3917
3918 MarkBufferDirty(buffer);
3919
3920 if (RelationNeedsWAL(relation))
3921 {
3924
3927
3928 xlrec.offnum = ItemPointerGetOffsetNumber(&oldtup.t_self);
3930 xlrec.infobits_set = compute_infobits(oldtup.t_data->t_infomask,
3931 oldtup.t_data->t_infomask2);
3932 xlrec.flags =
3935
3938
3940 PageSetLSN(page, recptr);
3941
3943 PageSetLSN(BufferGetPage(vmbuffer), recptr);
3944 }
3945
3947
3948 /* release VM lock first, since it covers many heap blocks */
3949 if (unlock_vmbuffer)
3950 LockBuffer(vmbuffer, BUFFER_LOCK_UNLOCK);
3951 unlock_vmbuffer = false;
3952
3954
3955 /*
3956 * Let the toaster do its thing, if needed.
3957 *
3958 * Note: below this point, heaptup is the data we actually intend to
3959 * store into the relation; newtup is the caller's original untoasted
3960 * data.
3961 */
3962 if (need_toast)
3963 {
3964 /* Note we always use WAL and FSM during updates */
3966 newtupsize = MAXALIGN(heaptup->t_len);
3967 }
3968 else
3969 heaptup = newtup;
3970
3971 /*
3972 * Now, do we need a new page for the tuple, or not? This is a bit
3973 * tricky since someone else could have added tuples to the page while
3974 * we weren't looking. We have to recheck the available space after
3975 * reacquiring the buffer lock. But don't bother to do that if the
3976 * former amount of free space is still not enough; it's unlikely
3977 * there's more free now than before.
3978 *
3979 * What's more, if we need to get a new page, we will need to acquire
3980 * buffer locks on both old and new pages. To avoid deadlock against
3981 * some other backend trying to get the same two locks in the other
3982 * order, we must be consistent about the order we get the locks in.
3983 * We use the rule "lock the lower-numbered page of the relation
3984 * first". To implement this, we must do RelationGetBufferForTuple
3985 * while not holding the lock on the old page, and we must rely on it
3986 * to get the locks on both pages in the correct order.
3987 *
3988 * Another consideration is that we need visibility map page pin(s) if
3989 * we will have to clear the all-visible flag on either page. If we
3990 * call RelationGetBufferForTuple, we rely on it to acquire any such
3991 * pins; but if we don't, we have to handle that here. Hence we need
3992 * a loop.
3993 */
3994 for (;;)
3995 {
3996 if (newtupsize > pagefree)
3997 {
3998 /* It doesn't fit, must use RelationGetBufferForTuple. */
3999 newbuf = RelationGetBufferForTuple(relation, heaptup->t_len,
4000 buffer, 0, NULL,
4001 &vmbuffer_new, &vmbuffer,
4002 0);
4003 /* We're all done. */
4004 break;
4005 }
4006 /* Acquire VM page pin if needed and we don't have it. */
4007 if (vmbuffer == InvalidBuffer && PageIsAllVisible(page))
4008 visibilitymap_pin(relation, block, &vmbuffer);
4009 /* Re-acquire the lock on the old tuple's page. */
4011 /* Re-check using the up-to-date free space */
4013 if (newtupsize > pagefree ||
4014 (vmbuffer == InvalidBuffer && PageIsAllVisible(page)))
4015 {
4016 /*
4017 * Rats, it doesn't fit anymore, or somebody just now set the
4018 * all-visible flag. We must now unlock and loop to avoid
4019 * deadlock. Fortunately, this path should seldom be taken.
4020 */
4022 }
4023 else
4024 {
4025 /* We're all done. */
4026 newbuf = buffer;
4027 break;
4028 }
4029 }
4030 }
4031 else
4032 {
4033 /* No TOAST work needed, and it'll fit on same page */
4034 newbuf = buffer;
4035 heaptup = newtup;
4036 }
4037
4039
4040 /*
4041 * We're about to do the actual update -- check for conflict first, to
4042 * avoid possibly having to roll back work we've just done.
4043 *
4044 * This is safe without a recheck as long as there is no possibility of
4045 * another process scanning the pages between this check and the update
4046 * being visible to the scan (i.e., exclusive buffer content lock(s) are
4047 * continuously held from this point until the tuple update is visible).
4048 *
4049 * For the new tuple the only check needed is at the relation level, but
4050 * since both tuples are in the same relation and the check for oldtup
4051 * will include checking the relation level, there is no benefit to a
4052 * separate check for the new tuple.
4053 */
4054 CheckForSerializableConflictIn(relation, &oldtup.t_self,
4055 BufferGetBlockNumber(buffer));
4056
4057 /*
4058 * At this point newbuf and buffer are both pinned and locked, and newbuf
4059 * has enough space for the new tuple. If they are the same buffer, only
4060 * one pin is held.
4061 */
4062
4063 if (newbuf == buffer)
4064 {
4065 /*
4066 * Since the new tuple is going into the same page, we might be able
4067 * to do a HOT update. Check if any of the index columns have been
4068 * changed.
4069 */
4071 {
4072 use_hot_update = true;
4073
4074 /*
4075 * If none of the columns that are used in hot-blocking indexes
4076 * were updated, we can apply HOT, but we do still need to check
4077 * if we need to update the summarizing indexes, and update those
4078 * indexes if the columns were updated, or we may fail to detect
4079 * e.g. value bound changes in BRIN minmax indexes.
4080 */
4082 summarized_update = true;
4083 }
4084 }
4085 else
4086 {
4087 /* Set a hint that the old page could use prune/defrag */
4088 PageSetFull(page);
4089 }
4090
4091 /*
4092 * Compute replica identity tuple before entering the critical section so
4093 * we don't PANIC upon a memory allocation failure.
4094 * ExtractReplicaIdentity() will return NULL if nothing needs to be
4095 * logged. Pass old key required as true only if the replica identity key
4096 * columns are modified or it has external data.
4097 */
4102
4105
4106 /*
4107 * Clear PD_ALL_VISIBLE flags and reset visibility map bits for any heap
4108 * pages that were all-visible. If there are two heap pages, we may need
4109 * to clear VM bits for both.
4110 */
4112 vmbuffer_new == vmbuffer)
4113 {
4114 /*
4115 * This is the more complicated case: both the new and old heap pages
4116 * are all-visible and both their VM bits are on the same page of the
4117 * VM, so we register a single VM buffer as HEAP_UPDATE_BLKREF_VM_NEW
4118 * in the WAL record. We must be careful to only lock and register one
4119 * buffer, even though we modify it twice -- once for each heap
4120 * block's VM bits.
4121 */
4123 unlock_vmbuffer_new = true;
4124
4125 /* We will not lock or attempt to modify old VM buffer */
4126 }
4127 else
4128 {
4129 /*
4130 * In all the remaining cases, we will clear at most one heap block's
4131 * VM bits per VM page.
4132 */
4133 Buffer vmbuffers[2] = {
4134 clear_all_visible ? vmbuffer : InvalidBuffer,
4136 };
4137
4138 /*
4139 * When both pages need different VM pages cleared, acquire the VM
4140 * buffer locks in VM block order to avoid deadlocks between backends
4141 * updating tuples in opposite directions across VM pages.
4142 */
4145 {
4146 Buffer swap = vmbuffers[0];
4147
4148 vmbuffers[0] = vmbuffers[1];
4149 vmbuffers[1] = swap;
4150 }
4151
4153 vmbuffers[0] != vmbuffers[1]);
4154
4155 if (BufferIsValid(vmbuffers[0]))
4157 if (BufferIsValid(vmbuffers[1]))
4159
4161 unlock_vmbuffer = true;
4163 unlock_vmbuffer_new = true;
4164 }
4165
4166 /* NO EREPORT(ERROR) from here till changes are logged */
4168
4169 /*
4170 * If this transaction commits, the old tuple will become DEAD sooner or
4171 * later. Set flag that this page is a candidate for pruning once our xid
4172 * falls below the OldestXmin horizon. If the transaction finally aborts,
4173 * the subsequent page pruning will be a no-op and the hint will be
4174 * cleared.
4175 *
4176 * We set the new page prunable as well. See heap_insert() for more on why
4177 * we do this when inserting tuples.
4178 */
4179 PageSetPrunable(page, xid);
4180 if (newbuf != buffer)
4182
4183 if (use_hot_update)
4184 {
4185 /* Mark the old tuple as HOT-updated */
4187 /* And mark the new tuple as heap-only */
4189 /* Mark the caller's copy too, in case different from heaptup */
4191 }
4192 else
4193 {
4194 /* Make sure tuples are correctly marked as not-HOT */
4198 }
4199
4200 RelationPutHeapTuple(relation, newbuf, heaptup, false); /* insert new tuple */
4201
4202
4203 /* Clear obsolete visibility flags, possibly set by ourselves above... */
4204 oldtup.t_data->t_infomask &= ~(HEAP_XMAX_BITS | HEAP_MOVED);
4205 oldtup.t_data->t_infomask2 &= ~HEAP_KEYS_UPDATED;
4206 /* ... and store info about transaction updating this tuple */
4209 oldtup.t_data->t_infomask |= infomask_old_tuple;
4210 oldtup.t_data->t_infomask2 |= infomask2_old_tuple;
4212
4213 /* record address of new tuple in t_ctid of old one */
4214 oldtup.t_data->t_ctid = heaptup->t_self;
4215
4216 /*
4217 * Clear PD_ALL_VISIBLE flags and reset all visibilitymap bits. In all
4218 * cases, it's possible that PD_ALL_VISIBLE was set but the corresponding
4219 * visibility map bits were already clear.
4220 */
4222 {
4223 if (visibilitymap_clear(relation->rd_locator, block,
4224 vmbuffer, VISIBILITYMAP_VALID_BITS))
4225 {
4226 /*
4227 * When old and new heap blocks' VM bits are on the same VM page,
4228 * that page is registered in the WAL record only once. If both
4229 * heap pages were PD_ALL_VISIBLE and either VM bit needs
4230 * clearing, we register the VM buffer as
4231 * HEAP_UPDATE_BLKREF_VM_NEW.
4232 */
4233 if (clear_all_visible_new && vmbuffer == vmbuffer_new)
4234 vmbuffer_new_modified = true;
4235 else
4236 vmbuffer_modified = true;
4237 }
4238
4239 PageClearAllVisible(page);
4240 }
4242 {
4243 /*
4244 * If both heap blocks' VM bits are on the same VM buffer, this will
4245 * clear the new heap block's VM bits from the shared vmbuffer.
4246 */
4249 vmbuffer_new_modified = true;
4250
4252 }
4253
4254 if (newbuf != buffer)
4256 MarkBufferDirty(buffer);
4257
4258 /* XLOG stuff */
4259 if (RelationNeedsWAL(relation))
4260 {
4262
4263 /*
4264 * For logical decoding we need combo CIDs to properly decode the
4265 * catalog.
4266 */
4268 {
4269 log_heap_new_cid(relation, &oldtup);
4270 log_heap_new_cid(relation, heaptup);
4271 }
4272
4273 recptr = log_heap_update(relation, buffer,
4274 vmbuffer_modified ? vmbuffer : InvalidBuffer,
4275 newbuf,
4277 &oldtup, heaptup,
4281 walLogical);
4282 if (newbuf != buffer)
4283 {
4285 }
4286 PageSetLSN(page, recptr);
4287
4289 PageSetLSN(BufferGetPage(vmbuffer), recptr);
4292 }
4293
4295
4296 if (unlock_vmbuffer)
4297 LockBuffer(vmbuffer, BUFFER_LOCK_UNLOCK);
4300
4301 if (newbuf != buffer)
4304
4305 /*
4306 * Mark old tuple for invalidation from system caches at next command
4307 * boundary, and mark the new tuple for invalidation in case we abort. We
4308 * have to do this before releasing the buffer because oldtup is in the
4309 * buffer. (heaptup is all in local memory, but it's necessary to process
4310 * both tuple versions in one call to inval.c so we can avoid redundant
4311 * sinval messages.)
4312 */
4314
4315 /* Now we can release the buffer(s) */
4316 if (newbuf != buffer)
4318 ReleaseBuffer(buffer);
4321 if (BufferIsValid(vmbuffer))
4322 ReleaseBuffer(vmbuffer);
4323
4324 /*
4325 * Release the lmgr tuple lock, if we had it.
4326 */
4327 if (have_tuple_lock)
4328 UnlockTupleTuplock(relation, &(oldtup.t_self), *lockmode);
4329
4330 pgstat_count_heap_update(relation, use_hot_update, newbuf != buffer);
4331
4332 /*
4333 * If heaptup is a private copy, release it. Don't forget to copy t_self
4334 * back to the caller's image, too.
4335 */
4336 if (heaptup != newtup)
4337 {
4338 newtup->t_self = heaptup->t_self;
4340 }
4341
4342 /*
4343 * If it is a HOT update, the update may still need to update summarized
4344 * indexes, lest we fail to update those summaries and get incorrect
4345 * results (for example, minmax bounds of the block may change with this
4346 * update).
4347 */
4348 if (use_hot_update)
4349 {
4352 else
4354 }
4355 else
4357
4360
4367
4368 return TM_Ok;
4369}

References Assert, AssertHasSnapshotForToast(), bms_add_members(), bms_free(), bms_overlap(), BUFFER_LOCK_EXCLUSIVE, BUFFER_LOCK_UNLOCK, BufferGetBlockNumber(), BufferGetPage(), BufferIsValid(), CacheInvalidateHeapTuple(), CheckForSerializableConflictIn(), TM_FailureData::cmax, compute_infobits(), compute_new_xmax_infomask(), TM_FailureData::ctid, DoesMultiXactIdConflict(), END_CRIT_SECTION, ereport, errcode(), errmsg, ERROR, ExtractReplicaIdentity(), fb(), GetCurrentTransactionId(), GetMultiXactIdHintBits(), HEAP2_XACT_MASK, heap_acquire_tuplock(), heap_freetuple(), HEAP_LOCK_BLKREF_HEAP, HEAP_LOCK_BLKREF_VM, HEAP_LOCKED_UPGRADED(), HEAP_MOVED, heap_toast_insert_or_update(), HEAP_UPDATED, HEAP_XACT_MASK, HEAP_XMAX_BITS, HEAP_XMAX_INVALID, HEAP_XMAX_IS_KEYSHR_LOCKED(), HEAP_XMAX_IS_LOCKED_ONLY(), HEAP_XMAX_IS_MULTI, HEAP_XMAX_KEYSHR_LOCK, HEAP_XMAX_LOCK_ONLY, HeapDetermineColumnsInfo(), HeapTupleClearHeapOnly(), HeapTupleClearHotUpdated(), HeapTupleGetUpdateXid(), HeapTupleHasExternal(), HeapTupleHeaderAdjustCmax(), HeapTupleHeaderGetCmax(), HeapTupleHeaderGetNatts, HeapTupleHeaderGetRawXmax(), HeapTupleHeaderGetUpdateXid(), HeapTupleHeaderSetCmax(), HeapTupleHeaderSetCmin(), HeapTupleHeaderSetXmax(), HeapTupleHeaderSetXmin(), HeapTupleSatisfiesUpdate(), HeapTupleSatisfiesVisibility(), HeapTupleSetHeapOnly(), HeapTupleSetHotUpdated(), INDEX_ATTR_BITMAP_HOT_BLOCKING, INDEX_ATTR_BITMAP_IDENTITY_KEY, INDEX_ATTR_BITMAP_KEY, INDEX_ATTR_BITMAP_SUMMARIZED, INJECTION_POINT, InvalidBuffer, InvalidCommandId, InvalidSnapshot, InvalidTransactionId, IsInParallelMode(), ItemIdGetLength, ItemIdIsNormal, ItemPointerEquals(), ItemPointerGetBlockNumber(), ItemPointerGetOffsetNumber(), ItemPointerIsValid(), LockBuffer(), LockTupleExclusive, LockTupleNoKeyExclusive, LockWaitBlock, log_heap_new_cid(), log_heap_update(), MarkBufferDirty(), MAXALIGN, MultiXactIdSetOldestMember(), MultiXactIdWait(), MultiXactStatusNoKeyUpdate, MultiXactStatusUpdate, PageClearAllVisible(), PageGetHeapFreeSpace(), PageGetItem(), PageGetItemId(), PageIsAllVisible(), PageSetFull(), PageSetLSN(), PageSetPrunable, pgstat_count_heap_update(), RelationData::rd_locator, RelationData::rd_rel, ReadBuffer(), REGBUF_STANDARD, RelationGetBufferForTuple(), RelationGetIndexAttrBitmap(), RelationGetNumberOfAttributes, RelationGetRelid, RelationIsAccessibleInLogicalDecoding, RelationNeedsWAL, RelationPutHeapTuple(), RelationSupportsSysCache(), ReleaseBuffer(), result, SizeOfHeapLock, START_CRIT_SECTION, TABLE_UPDATE_NO_LOGICAL, TM_BeingModified, TM_Deleted, TM_Invisible, TM_Ok, TM_SelfModified, TM_Updated, TOAST_TUPLE_THRESHOLD, TransactionIdDidAbort(), TransactionIdEquals, TransactionIdIsCurrentTransactionId(), TransactionIdIsValid, TU_All, TU_None, TU_Summarizing, UnlockReleaseBuffer(), UnlockTupleTuplock, UpdateXmaxHintBits(), VISIBILITYMAP_ALL_FROZEN, visibilitymap_clear(), visibilitymap_pin(), VISIBILITYMAP_VALID_BITS, XactLockTableWait(), XLH_LOCK_ALL_FROZEN_CLEARED, XLOG_HEAP_LOCK, XLogBeginInsert(), XLogInsert(), XLogRegisterBuffer(), XLogRegisterData(), XLTW_Update, TM_FailureData::xmax, and xmax_infomask_changed().

Referenced by heapam_tuple_update(), and simple_heap_update().

◆ HeapCheckForSerializableConflictOut()

void HeapCheckForSerializableConflictOut ( bool  visible,
Relation  relation,
HeapTuple  tuple,
Buffer  buffer,
Snapshot  snapshot 
)

Definition at line 9442 of file heapam.c.

9445{
9446 TransactionId xid;
9448
9449 if (!CheckForSerializableConflictOutNeeded(relation, snapshot))
9450 return;
9451
9452 /*
9453 * Check to see whether the tuple has been written to by a concurrent
9454 * transaction, either to create it not visible to us, or to delete it
9455 * while it is visible to us. The "visible" bool indicates whether the
9456 * tuple is visible to us, while HeapTupleSatisfiesVacuum checks what else
9457 * is going on with it.
9458 *
9459 * In the event of a concurrently inserted tuple that also happens to have
9460 * been concurrently updated (by a separate transaction), the xmin of the
9461 * tuple will be used -- not the updater's xid.
9462 */
9464 switch (htsvResult)
9465 {
9466 case HEAPTUPLE_LIVE:
9467 if (visible)
9468 return;
9469 xid = HeapTupleHeaderGetXmin(tuple->t_data);
9470 break;
9473 if (visible)
9474 xid = HeapTupleHeaderGetUpdateXid(tuple->t_data);
9475 else
9476 xid = HeapTupleHeaderGetXmin(tuple->t_data);
9477
9479 {
9480 /* This is like the HEAPTUPLE_DEAD case */
9481 Assert(!visible);
9482 return;
9483 }
9484 break;
9486 xid = HeapTupleHeaderGetXmin(tuple->t_data);
9487 break;
9488 case HEAPTUPLE_DEAD:
9489 Assert(!visible);
9490 return;
9491 default:
9492
9493 /*
9494 * The only way to get to this default clause is if a new value is
9495 * added to the enum type without adding it to this switch
9496 * statement. That's a bug, so elog.
9497 */
9498 elog(ERROR, "unrecognized return value from HeapTupleSatisfiesVacuum: %u", htsvResult);
9499
9500 /*
9501 * In spite of having all enum values covered and calling elog on
9502 * this default, some compilers think this is a code path which
9503 * allows xid to be used below without initialization. Silence
9504 * that warning.
9505 */
9507 }
9508
9511
9512 /*
9513 * Find top level xid. Bail out if xid is too early to be a conflict, or
9514 * if it's our own xid.
9515 */
9517 return;
9520 return;
9521
9522 CheckForSerializableConflictOut(relation, xid, snapshot);
9523}

References Assert, CheckForSerializableConflictOut(), CheckForSerializableConflictOutNeeded(), elog, ERROR, fb(), GetTopTransactionIdIfAny(), HEAPTUPLE_DEAD, HEAPTUPLE_DELETE_IN_PROGRESS, HEAPTUPLE_INSERT_IN_PROGRESS, HEAPTUPLE_LIVE, HEAPTUPLE_RECENTLY_DEAD, HeapTupleHeaderGetUpdateXid(), HeapTupleHeaderGetXmin(), HeapTupleSatisfiesVacuum(), InvalidTransactionId, SubTransGetTopmostTransaction(), HeapTupleData::t_data, TransactionIdEquals, TransactionIdFollowsOrEquals(), TransactionIdIsValid, TransactionIdPrecedes(), and TransactionXmin.

Referenced by BitmapHeapScanNextBlock(), heap_fetch(), heap_get_latest_tid(), heap_hot_search_buffer(), heapam_scan_sample_next_tuple(), heapgettup(), and page_collect_tuples().

◆ HeapDetermineColumnsInfo()

static Bitmapset * HeapDetermineColumnsInfo ( Relation  relation,
Bitmapset interesting_cols,
Bitmapset external_cols,
HeapTuple  oldtup,
HeapTuple  newtup,
bool has_external 
)
static

Definition at line 4549 of file heapam.c.

4554{
4555 int attidx;
4557 TupleDesc tupdesc = RelationGetDescr(relation);
4558
4559 attidx = -1;
4560 while ((attidx = bms_next_member(interesting_cols, attidx)) >= 0)
4561 {
4562 /* attidx is zero-based, attrnum is the normal attribute number */
4564 Datum value1,
4565 value2;
4566 bool isnull1,
4567 isnull2;
4568
4569 /*
4570 * If it's a whole-tuple reference, say "not equal". It's not really
4571 * worth supporting this case, since it could only succeed after a
4572 * no-op update, which is hardly a case worth optimizing for.
4573 */
4574 if (attrnum == 0)
4575 {
4576 modified = bms_add_member(modified, attidx);
4577 continue;
4578 }
4579
4580 /*
4581 * Likewise, automatically say "not equal" for any system attribute
4582 * other than tableOID; we cannot expect these to be consistent in a
4583 * HOT chain, or even to be set correctly yet in the new tuple.
4584 */
4585 if (attrnum < 0)
4586 {
4587 if (attrnum != TableOidAttributeNumber)
4588 {
4589 modified = bms_add_member(modified, attidx);
4590 continue;
4591 }
4592 }
4593
4594 /*
4595 * Extract the corresponding values. XXX this is pretty inefficient
4596 * if there are many indexed columns. Should we do a single
4597 * heap_deform_tuple call on each tuple, instead? But that doesn't
4598 * work for system columns ...
4599 */
4600 value1 = heap_getattr(oldtup, attrnum, tupdesc, &isnull1);
4601 value2 = heap_getattr(newtup, attrnum, tupdesc, &isnull2);
4602
4603 if (!heap_attr_equals(tupdesc, attrnum, value1,
4604 value2, isnull1, isnull2))
4605 {
4606 modified = bms_add_member(modified, attidx);
4607 continue;
4608 }
4609
4610 /*
4611 * No need to check attributes that can't be stored externally. Note
4612 * that system attributes can't be stored externally.
4613 */
4614 if (attrnum < 0 || isnull1 ||
4615 TupleDescCompactAttr(tupdesc, attrnum - 1)->attlen != -1)
4616 continue;
4617
4618 /*
4619 * Check if the old tuple's attribute is stored externally and is a
4620 * member of external_cols.
4621 */
4624 *has_external = true;
4625 }
4626
4627 return modified;
4628}

References attlen, bms_add_member(), bms_is_member(), bms_next_member(), DatumGetPointer(), fb(), FirstLowInvalidHeapAttributeNumber, heap_attr_equals(), heap_getattr(), RelationGetDescr, TableOidAttributeNumber, TupleDescCompactAttr(), and VARATT_IS_EXTERNAL().

Referenced by heap_update().

◆ heapgettup()

static void heapgettup ( HeapScanDesc  scan,
ScanDirection  dir,
int  nkeys,
ScanKey  key 
)
static

Definition at line 964 of file heapam.c.

968{
969 HeapTuple tuple = &(scan->rs_ctup);
970 Page page;
972 int linesleft;
973
974 if (likely(scan->rs_inited))
975 {
976 /* continue from previously returned page/tuple */
978 page = heapgettup_continue_page(scan, dir, &linesleft, &lineoff);
979 goto continue_page;
980 }
981
982 /*
983 * advance the scan until we find a qualifying tuple or run out of stuff
984 * to scan
985 */
986 while (true)
987 {
988 heap_fetch_next_buffer(scan, dir);
989
990 /* did we run out of blocks to scan? */
991 if (!BufferIsValid(scan->rs_cbuf))
992 break;
993
995
997 page = heapgettup_start_page(scan, dir, &linesleft, &lineoff);
999
1000 /*
1001 * Only continue scanning the page while we have lines left.
1002 *
1003 * Note that this protects us from accessing line pointers past
1004 * PageGetMaxOffsetNumber(); both for forward scans when we resume the
1005 * table scan, and for when we start scanning a new page.
1006 */
1007 for (; linesleft > 0; linesleft--, lineoff += dir)
1008 {
1009 bool visible;
1011
1012 if (!ItemIdIsNormal(lpp))
1013 continue;
1014
1015 tuple->t_data = (HeapTupleHeader) PageGetItem(page, lpp);
1016 tuple->t_len = ItemIdGetLength(lpp);
1017 ItemPointerSet(&(tuple->t_self), scan->rs_cblock, lineoff);
1018
1019 visible = HeapTupleSatisfiesVisibility(tuple,
1020 scan->rs_base.rs_snapshot,
1021 scan->rs_cbuf);
1022
1024 tuple, scan->rs_cbuf,
1025 scan->rs_base.rs_snapshot);
1026
1027 /* skip tuples not visible to this snapshot */
1028 if (!visible)
1029 continue;
1030
1031 /* skip any tuples that don't match the scan key */
1032 if (key != NULL &&
1034 nkeys, key))
1035 continue;
1036
1038 scan->rs_coffset = lineoff;
1039 return;
1040 }
1041
1042 /*
1043 * if we get here, it means we've exhausted the items on this page and
1044 * it's time to move to the next.
1045 */
1047 }
1048
1049 /* end of scan */
1050 if (BufferIsValid(scan->rs_cbuf))
1051 ReleaseBuffer(scan->rs_cbuf);
1052
1053 scan->rs_cbuf = InvalidBuffer;
1056 tuple->t_data = NULL;
1057 scan->rs_inited = false;
1058}

References Assert, BUFFER_LOCK_SHARE, BUFFER_LOCK_UNLOCK, BufferGetBlockNumber(), BufferIsValid(), fb(), heap_fetch_next_buffer(), HeapCheckForSerializableConflictOut(), heapgettup_continue_page(), heapgettup_start_page(), HeapKeyTest(), HeapTupleSatisfiesVisibility(), InvalidBlockNumber, InvalidBuffer, ItemIdGetLength, ItemIdIsNormal, ItemPointerSet(), likely, LockBuffer(), PageGetItem(), PageGetItemId(), RelationGetDescr, ReleaseBuffer(), HeapScanDescData::rs_base, HeapScanDescData::rs_cblock, HeapScanDescData::rs_cbuf, HeapScanDescData::rs_coffset, HeapScanDescData::rs_ctup, HeapScanDescData::rs_inited, HeapScanDescData::rs_prefetch_block, TableScanDescData::rs_rd, TableScanDescData::rs_snapshot, HeapTupleData::t_data, HeapTupleData::t_len, and HeapTupleData::t_self.

Referenced by heap_getnext(), heap_getnextslot(), and heap_getnextslot_tidrange().

◆ heapgettup_advance_block()

static BlockNumber heapgettup_advance_block ( HeapScanDesc  scan,
BlockNumber  block,
ScanDirection  dir 
)
inlinestatic

Definition at line 880 of file heapam.c.

881{
882 Assert(scan->rs_base.rs_parallel == NULL);
883
885 {
886 block++;
887
888 /* wrap back to the start of the heap */
889 if (block >= scan->rs_nblocks)
890 block = 0;
891
892 /*
893 * Report our new scan position for synchronization purposes. We don't
894 * do that when moving backwards, however. That would just mess up any
895 * other forward-moving scanners.
896 *
897 * Note: we do this before checking for end of scan so that the final
898 * state of the position hint is back at the start of the rel. That's
899 * not strictly necessary, but otherwise when you run the same query
900 * multiple times the starting position would shift a little bit
901 * backwards on every invocation, which is confusing. We don't
902 * guarantee any specific ordering in general, though.
903 */
904 if (scan->rs_base.rs_flags & SO_ALLOW_SYNC)
905 ss_report_location(scan->rs_base.rs_rd, block);
906
907 /* we're done if we're back at where we started */
908 if (block == scan->rs_startblock)
909 return InvalidBlockNumber;
910
911 /* check if the limit imposed by heap_setscanlimits() is met */
912 if (scan->rs_numblocks != InvalidBlockNumber)
913 {
914 if (--scan->rs_numblocks == 0)
915 return InvalidBlockNumber;
916 }
917
918 return block;
919 }
920 else
921 {
922 /* we're done if the last block is the start position */
923 if (block == scan->rs_startblock)
924 return InvalidBlockNumber;
925
926 /* check if the limit imposed by heap_setscanlimits() is met */
927 if (scan->rs_numblocks != InvalidBlockNumber)
928 {
929 if (--scan->rs_numblocks == 0)
930 return InvalidBlockNumber;
931 }
932
933 /* wrap to the end of the heap when the last page was page 0 */
934 if (block == 0)
935 block = scan->rs_nblocks;
936
937 block--;
938
939 return block;
940 }
941}

References Assert, fb(), InvalidBlockNumber, likely, HeapScanDescData::rs_base, TableScanDescData::rs_flags, HeapScanDescData::rs_nblocks, HeapScanDescData::rs_numblocks, TableScanDescData::rs_parallel, TableScanDescData::rs_rd, HeapScanDescData::rs_startblock, ScanDirectionIsForward, SO_ALLOW_SYNC, and ss_report_location().

Referenced by heap_scan_stream_read_next_serial().

◆ heapgettup_continue_page()

static Page heapgettup_continue_page ( HeapScanDesc  scan,
ScanDirection  dir,
int linesleft,
OffsetNumber lineoff 
)
inlinestatic

Definition at line 834 of file heapam.c.

836{
837 Page page;
838
839 Assert(scan->rs_inited);
841
842 /* Caller is responsible for ensuring buffer is locked if needed */
843 page = BufferGetPage(scan->rs_cbuf);
844
845 if (ScanDirectionIsForward(dir))
846 {
848 *linesleft = PageGetMaxOffsetNumber(page) - (*lineoff) + 1;
849 }
850 else
851 {
852 /*
853 * The previous returned tuple may have been vacuumed since the
854 * previous scan when we use a non-MVCC snapshot, so we must
855 * re-establish the lineoff <= PageGetMaxOffsetNumber(page) invariant
856 */
858 *linesleft = *lineoff;
859 }
860
861 /* lineoff now references the physically previous or next tid */
862 return page;
863}

References Assert, BufferGetPage(), BufferIsValid(), fb(), Min, OffsetNumberNext, OffsetNumberPrev, PageGetMaxOffsetNumber(), HeapScanDescData::rs_cbuf, HeapScanDescData::rs_coffset, HeapScanDescData::rs_inited, and ScanDirectionIsForward.

Referenced by heapgettup().

◆ heapgettup_initial_block()

static pg_noinline BlockNumber heapgettup_initial_block ( HeapScanDesc  scan,
ScanDirection  dir 
)
static

Definition at line 756 of file heapam.c.

757{
758 Assert(!scan->rs_inited);
759 Assert(scan->rs_base.rs_parallel == NULL);
760
761 /* When there are no pages to scan, return InvalidBlockNumber */
762 if (scan->rs_nblocks == 0 || scan->rs_numblocks == 0)
763 return InvalidBlockNumber;
764
765 if (ScanDirectionIsForward(dir))
766 {
767 return scan->rs_startblock;
768 }
769 else
770 {
771 /*
772 * Disable reporting to syncscan logic in a backwards scan; it's not
773 * very likely anyone else is doing the same thing at the same time,
774 * and much more likely that we'll just bollix things for forward
775 * scanners.
776 */
778
779 /*
780 * Start from last page of the scan. Ensure we take into account
781 * rs_numblocks if it's been adjusted by heap_setscanlimits().
782 */
783 if (scan->rs_numblocks != InvalidBlockNumber)
784 return (scan->rs_startblock + scan->rs_numblocks - 1) % scan->rs_nblocks;
785
786 if (scan->rs_startblock > 0)
787 return scan->rs_startblock - 1;
788
789 return scan->rs_nblocks - 1;
790 }
791}

References Assert, fb(), InvalidBlockNumber, HeapScanDescData::rs_base, TableScanDescData::rs_flags, HeapScanDescData::rs_inited, HeapScanDescData::rs_nblocks, HeapScanDescData::rs_numblocks, TableScanDescData::rs_parallel, HeapScanDescData::rs_startblock, and ScanDirectionIsForward.

Referenced by heap_scan_stream_read_next_serial().

◆ heapgettup_pagemode()

static void heapgettup_pagemode ( HeapScanDesc  scan,
ScanDirection  dir,
int  nkeys,
ScanKey  key 
)
static

Definition at line 1074 of file heapam.c.

1078{
1079 HeapTuple tuple = &(scan->rs_ctup);
1080 Page page;
1083
1084 if (likely(scan->rs_inited))
1085 {
1086 /* continue from previously returned page/tuple */
1087 page = BufferGetPage(scan->rs_cbuf);
1088
1089 lineindex = scan->rs_cindex + dir;
1090 if (ScanDirectionIsForward(dir))
1091 linesleft = scan->rs_ntuples - lineindex;
1092 else
1093 linesleft = scan->rs_cindex;
1094 /* lineindex now references the next or previous visible tid */
1095
1096 goto continue_page;
1097 }
1098
1099 /*
1100 * advance the scan until we find a qualifying tuple or run out of stuff
1101 * to scan
1102 */
1103 while (true)
1104 {
1105 heap_fetch_next_buffer(scan, dir);
1106
1107 /* did we run out of blocks to scan? */
1108 if (!BufferIsValid(scan->rs_cbuf))
1109 break;
1110
1112
1113 /* prune the page and determine visible tuple offsets */
1115 page = BufferGetPage(scan->rs_cbuf);
1116 linesleft = scan->rs_ntuples;
1118
1119 /* block is the same for all tuples, set it once outside the loop */
1121
1122 /* lineindex now references the next or previous visible tid */
1124
1125 for (; linesleft > 0; linesleft--, lineindex += dir)
1126 {
1127 ItemId lpp;
1129
1130 Assert(lineindex < scan->rs_ntuples);
1132 lpp = PageGetItemId(page, lineoff);
1134
1135 tuple->t_data = (HeapTupleHeader) PageGetItem(page, lpp);
1136 tuple->t_len = ItemIdGetLength(lpp);
1138
1139 /* skip any tuples that don't match the scan key */
1140 if (key != NULL &&
1142 nkeys, key))
1143 continue;
1144
1145 scan->rs_cindex = lineindex;
1146 return;
1147 }
1148 }
1149
1150 /* end of scan */
1151 if (BufferIsValid(scan->rs_cbuf))
1152 ReleaseBuffer(scan->rs_cbuf);
1153 scan->rs_cbuf = InvalidBuffer;
1156 tuple->t_data = NULL;
1157 scan->rs_inited = false;
1158}

References Assert, BufferGetBlockNumber(), BufferGetPage(), BufferIsValid(), fb(), heap_fetch_next_buffer(), heap_prepare_pagescan(), HeapKeyTest(), InvalidBlockNumber, InvalidBuffer, ItemIdGetLength, ItemIdIsNormal, ItemPointerSetBlockNumber(), ItemPointerSetOffsetNumber(), likely, PageGetItem(), PageGetItemId(), RelationGetDescr, ReleaseBuffer(), HeapScanDescData::rs_cblock, HeapScanDescData::rs_cbuf, HeapScanDescData::rs_cindex, HeapScanDescData::rs_ctup, HeapScanDescData::rs_inited, HeapScanDescData::rs_ntuples, HeapScanDescData::rs_prefetch_block, TableScanDescData::rs_rd, ScanDirectionIsForward, HeapTupleData::t_data, HeapTupleData::t_len, and HeapTupleData::t_self.

Referenced by heap_getnext(), heap_getnextslot(), and heap_getnextslot_tidrange().

◆ heapgettup_start_page()

static Page heapgettup_start_page ( HeapScanDesc  scan,
ScanDirection  dir,
int linesleft,
OffsetNumber lineoff 
)
static

Definition at line 803 of file heapam.c.

805{
806 Page page;
807
808 Assert(scan->rs_inited);
810
811 /* Caller is responsible for ensuring buffer is locked if needed */
812 page = BufferGetPage(scan->rs_cbuf);
813
815
816 if (ScanDirectionIsForward(dir))
818 else
820
821 /* lineoff now references the physically previous or next tid */
822 return page;
823}

References Assert, BufferGetPage(), BufferIsValid(), fb(), FirstOffsetNumber, PageGetMaxOffsetNumber(), HeapScanDescData::rs_cbuf, HeapScanDescData::rs_inited, and ScanDirectionIsForward.

Referenced by heapgettup().

◆ HeapTupleGetUpdateXid()

◆ HeapTupleHeaderAdvanceConflictHorizon()

void HeapTupleHeaderAdvanceConflictHorizon ( HeapTupleHeader  tuple,
TransactionId snapshotConflictHorizon 
)

Definition at line 8194 of file heapam.c.

8196{
8200
8201 if (tuple->t_infomask & HEAP_MOVED)
8202 {
8203 if (TransactionIdPrecedes(*snapshotConflictHorizon, xvac))
8204 *snapshotConflictHorizon = xvac;
8205 }
8206
8207 /*
8208 * Ignore tuples inserted by an aborted transaction or if the tuple was
8209 * updated/deleted by the inserting transaction.
8210 *
8211 * Look for a committed hint bit, or if no xmin bit is set, check clog.
8212 */
8213 if (HeapTupleHeaderXminCommitted(tuple) ||
8215 {
8216 if (xmax != xmin &&
8217 TransactionIdFollows(xmax, *snapshotConflictHorizon))
8218 *snapshotConflictHorizon = xmax;
8219 }
8220}

References fb(), HEAP_MOVED, HeapTupleHeaderGetUpdateXid(), HeapTupleHeaderGetXmin(), HeapTupleHeaderGetXvac(), HeapTupleHeaderXminCommitted(), HeapTupleHeaderXminInvalid(), HeapTupleHeaderData::t_infomask, TransactionIdDidCommit(), TransactionIdFollows(), and TransactionIdPrecedes().

Referenced by heap_index_delete_tuples(), heap_prune_chain(), and prune_freeze_plan().

◆ index_delete_check_htid()

static void index_delete_check_htid ( TM_IndexDeleteOp delstate,
Page  page,
OffsetNumber  maxoff,
const ItemPointerData htid,
TM_IndexStatus istatus 
)
inlinestatic

Definition at line 8279 of file heapam.c.

8282{
8284 ItemId iid;
8285
8286 Assert(OffsetNumberIsValid(istatus->idxoffnum));
8287
8288 if (unlikely(indexpagehoffnum > maxoff))
8289 ereport(ERROR,
8291 errmsg_internal("heap tid from index tuple (%u,%u) points past end of heap page line pointer array at offset %u of block %u in index \"%s\"",
8294 istatus->idxoffnum, delstate->iblknum,
8296
8298 if (unlikely(!ItemIdIsUsed(iid)))
8299 ereport(ERROR,
8301 errmsg_internal("heap tid from index tuple (%u,%u) points to unused heap page item at offset %u of block %u in index \"%s\"",
8304 istatus->idxoffnum, delstate->iblknum,
8306
8307 if (ItemIdHasStorage(iid))
8308 {
8309 HeapTupleHeader htup;
8310
8312 htup = (HeapTupleHeader) PageGetItem(page, iid);
8313
8315 ereport(ERROR,
8317 errmsg_internal("heap tid from index tuple (%u,%u) points to heap-only tuple at offset %u of block %u in index \"%s\"",
8320 istatus->idxoffnum, delstate->iblknum,
8322 }
8323}

References Assert, ereport, errcode(), errmsg_internal(), ERROR, fb(), HeapTupleHeaderIsHeapOnly(), ItemIdHasStorage, ItemIdIsNormal, ItemIdIsUsed, ItemPointerGetBlockNumber(), ItemPointerGetOffsetNumber(), OffsetNumberIsValid, PageGetItem(), PageGetItemId(), RelationGetRelationName, and unlikely.

Referenced by heap_index_delete_tuples().

◆ index_delete_sort()

static void index_delete_sort ( TM_IndexDeleteOp delstate)
static

Definition at line 8684 of file heapam.c.

8685{
8686 TM_IndexDelete *deltids = delstate->deltids;
8687 int ndeltids = delstate->ndeltids;
8688
8689 /*
8690 * Shellsort gap sequence (taken from Sedgewick-Incerpi paper).
8691 *
8692 * This implementation is fast with array sizes up to ~4500. This covers
8693 * all supported BLCKSZ values.
8694 */
8695 const int gaps[9] = {1968, 861, 336, 112, 48, 21, 7, 3, 1};
8696
8697 /* Think carefully before changing anything here -- keep swaps cheap */
8698 StaticAssertDecl(sizeof(TM_IndexDelete) <= 8,
8699 "element size exceeds 8 bytes");
8700
8701 for (size_t g = 0; g < lengthof(gaps); g++)
8702 {
8703 for (int hi = gaps[g], i = hi; i < ndeltids; i++)
8704 {
8705 TM_IndexDelete d = deltids[i];
8706 int j = i;
8707
8708 while (j >= hi && index_delete_sort_cmp(&deltids[j - hi], &d) >= 0)
8709 {
8710 deltids[j] = deltids[j - hi];
8711 j -= hi;
8712 }
8713 deltids[j] = d;
8714 }
8715 }
8716}

References fb(), i, index_delete_sort_cmp(), j, lengthof, and StaticAssertDecl.

Referenced by heap_index_delete_tuples().

◆ index_delete_sort_cmp()

static int index_delete_sort_cmp ( TM_IndexDelete deltid1,
TM_IndexDelete deltid2 
)
inlinestatic

Definition at line 8648 of file heapam.c.

8649{
8650 ItemPointer tid1 = &deltid1->tid;
8651 ItemPointer tid2 = &deltid2->tid;
8652
8653 {
8656
8657 if (blk1 != blk2)
8658 return (blk1 < blk2) ? -1 : 1;
8659 }
8660 {
8663
8664 if (pos1 != pos2)
8665 return (pos1 < pos2) ? -1 : 1;
8666 }
8667
8668 Assert(false);
8669
8670 return 0;
8671}

References Assert, fb(), ItemPointerGetBlockNumber(), and ItemPointerGetOffsetNumber().

Referenced by index_delete_sort().

◆ initscan()

static void initscan ( HeapScanDesc  scan,
ScanKey  key,
bool  keep_startblock 
)
static

Definition at line 360 of file heapam.c.

361{
363 bool allow_strat;
364 bool allow_sync;
365
366 /*
367 * Determine the number of blocks we have to scan.
368 *
369 * It is sufficient to do this once at scan start, since any tuples added
370 * while the scan is in progress will be invisible to my snapshot anyway.
371 * (That is not true when using a non-MVCC snapshot. However, we couldn't
372 * guarantee to return tuples added after scan start anyway, since they
373 * might go into pages we already scanned. To guarantee consistent
374 * results for a non-MVCC snapshot, the caller must hold some higher-level
375 * lock that ensures the interesting tuple(s) won't change.)
376 */
377 if (scan->rs_base.rs_parallel != NULL)
378 {
380 scan->rs_nblocks = bpscan->phs_nblocks;
381 }
382 else
384
385 /*
386 * If the table is large relative to NBuffers, use a bulk-read access
387 * strategy and enable synchronized scanning (see syncscan.c). Although
388 * the thresholds for these features could be different, we make them the
389 * same so that there are only two behaviors to tune rather than four.
390 * (However, some callers need to be able to disable one or both of these
391 * behaviors, independently of the size of the table; also there is a GUC
392 * variable that can disable synchronized scanning.)
393 *
394 * Note that table_block_parallelscan_initialize has a very similar test;
395 * if you change this, consider changing that one, too.
396 */
398 scan->rs_nblocks > NBuffers / 4)
399 {
401 allow_sync = (scan->rs_base.rs_flags & SO_ALLOW_SYNC) != 0;
402 }
403 else
404 allow_strat = allow_sync = false;
405
406 if (allow_strat)
407 {
408 /* During a rescan, keep the previous strategy object. */
409 if (scan->rs_strategy == NULL)
411 }
412 else
413 {
414 if (scan->rs_strategy != NULL)
416 scan->rs_strategy = NULL;
417 }
418
419 if (scan->rs_base.rs_parallel != NULL)
420 {
421 /* For parallel scan, believe whatever ParallelTableScanDesc says. */
424 else
426
427 /*
428 * If not rescanning, initialize the startblock. Finding the actual
429 * start location is done in table_block_parallelscan_startblock_init,
430 * based on whether an alternative start location has been set with
431 * heap_setscanlimits, or using the syncscan location, when syncscan
432 * is enabled.
433 */
434 if (!keep_startblock)
436 }
437 else
438 {
439 if (keep_startblock)
440 {
441 /*
442 * When rescanning, we want to keep the previous startblock
443 * setting, so that rewinding a cursor doesn't generate surprising
444 * results. Reset the active syncscan setting, though.
445 */
448 else
450 }
452 {
455 }
456 else
457 {
459 scan->rs_startblock = 0;
460 }
461 }
462
464 scan->rs_inited = false;
465 scan->rs_ctup.t_data = NULL;
467 scan->rs_cbuf = InvalidBuffer;
469 scan->rs_ntuples = 0;
470 scan->rs_cindex = 0;
471
472 /*
473 * Initialize to ForwardScanDirection because it is most common and
474 * because heap scans go forward before going backward (e.g. CURSORs).
475 */
478
479 /* page-at-a-time fields are always invalid when not rs_inited */
480
481 /*
482 * copy the scan key, if appropriate
483 */
484 if (key != NULL && scan->rs_base.rs_nkeys > 0)
485 memcpy(scan->rs_base.rs_key, key, scan->rs_base.rs_nkeys * sizeof(ScanKeyData));
486
487 /*
488 * Currently, we only have a stats counter for sequential heap scans (but
489 * e.g for bitmap scans the underlying bitmap index scans will be counted,
490 * and for sample scans we update stats for tuple fetches).
491 */
492 if (scan->rs_base.rs_flags & SO_TYPE_SEQSCAN)
494}

References BAS_BULKREAD, fb(), ForwardScanDirection, FreeAccessStrategy(), GetAccessStrategy(), InvalidBlockNumber, InvalidBuffer, ItemPointerSetInvalid(), memcpy(), NBuffers, pgstat_count_heap_scan, ParallelTableScanDescData::phs_syncscan, RelationGetNumberOfBlocks, RelationUsesLocalBuffers, HeapScanDescData::rs_base, HeapScanDescData::rs_cblock, HeapScanDescData::rs_cbuf, HeapScanDescData::rs_cindex, HeapScanDescData::rs_ctup, HeapScanDescData::rs_dir, TableScanDescData::rs_flags, HeapScanDescData::rs_inited, TableScanDescData::rs_key, HeapScanDescData::rs_nblocks, TableScanDescData::rs_nkeys, HeapScanDescData::rs_ntuples, HeapScanDescData::rs_numblocks, TableScanDescData::rs_parallel, HeapScanDescData::rs_prefetch_block, TableScanDescData::rs_rd, HeapScanDescData::rs_startblock, HeapScanDescData::rs_strategy, SO_ALLOW_STRAT, SO_ALLOW_SYNC, SO_TYPE_SEQSCAN, ss_get_location(), synchronize_seqscans, HeapTupleData::t_data, and HeapTupleData::t_self.

Referenced by heap_beginscan(), and heap_rescan().

◆ log_heap_new_cid()

static XLogRecPtr log_heap_new_cid ( Relation  relation,
HeapTuple  tup 
)
static

Definition at line 9257 of file heapam.c.

9258{
9260
9262 HeapTupleHeader hdr = tup->t_data;
9263
9264 Assert(ItemPointerIsValid(&tup->t_self));
9265 Assert(tup->t_tableOid != InvalidOid);
9266
9267 xlrec.top_xid = GetTopTransactionId();
9268 xlrec.target_locator = relation->rd_locator;
9269 xlrec.target_tid = tup->t_self;
9270
9271 /*
9272 * If the tuple got inserted & deleted in the same TX we definitely have a
9273 * combo CID, set cmin and cmax.
9274 */
9275 if (hdr->t_infomask & HEAP_COMBOCID)
9276 {
9279 xlrec.cmin = HeapTupleHeaderGetCmin(hdr);
9280 xlrec.cmax = HeapTupleHeaderGetCmax(hdr);
9281 xlrec.combocid = HeapTupleHeaderGetRawCommandId(hdr);
9282 }
9283 /* No combo CID, so only cmin or cmax can be set by this TX */
9284 else
9285 {
9286 /*
9287 * Tuple inserted.
9288 *
9289 * We need to check for LOCK ONLY because multixacts might be
9290 * transferred to the new tuple in case of FOR KEY SHARE updates in
9291 * which case there will be an xmax, although the tuple just got
9292 * inserted.
9293 */
9294 if (hdr->t_infomask & HEAP_XMAX_INVALID ||
9296 {
9298 xlrec.cmax = InvalidCommandId;
9299 }
9300 /* Tuple from a different tx updated or deleted. */
9301 else
9302 {
9303 xlrec.cmin = InvalidCommandId;
9305 }
9306 xlrec.combocid = InvalidCommandId;
9307 }
9308
9309 /*
9310 * Note that we don't need to register the buffer here, because this
9311 * operation does not modify the page. The insert/update/delete that
9312 * called us certainly did, but that's WAL-logged separately.
9313 */
9316
9317 /* will be looked at irrespective of origin */
9318
9320
9321 return recptr;
9322}

References Assert, fb(), GetTopTransactionId(), HEAP_COMBOCID, HEAP_XMAX_INVALID, HEAP_XMAX_IS_LOCKED_ONLY(), HeapTupleHeaderGetCmax(), HeapTupleHeaderGetCmin(), HeapTupleHeaderGetRawCommandId(), HeapTupleHeaderXminInvalid(), InvalidCommandId, InvalidOid, ItemPointerIsValid(), RelationData::rd_locator, SizeOfHeapNewCid, HeapTupleHeaderData::t_infomask, XLOG_HEAP2_NEW_CID, XLogBeginInsert(), XLogInsert(), and XLogRegisterData().

Referenced by heap_delete(), heap_insert(), heap_multi_insert(), and heap_update().

◆ log_heap_update()

static XLogRecPtr log_heap_update ( Relation  reln,
Buffer  oldbuf,
Buffer  vmbuffer_old,
Buffer  newbuf,
Buffer  vmbuffer_new,
HeapTuple  oldtup,
HeapTuple  newtup,
HeapTuple  old_key_tuple,
bool  all_visible_cleared,
bool  new_all_visible_cleared,
bool  walLogical 
)
static

Definition at line 9015 of file heapam.c.

9021{
9025 uint8 info;
9027 uint16 prefixlen = 0,
9028 suffixlen = 0;
9030 Page page = BufferGetPage(newbuf);
9032 bool init;
9033 int bufflags;
9034
9035 /* Caller should not call me on a non-WAL-logged relation */
9037
9039
9041 info = XLOG_HEAP_HOT_UPDATE;
9042 else
9043 info = XLOG_HEAP_UPDATE;
9044
9045 /*
9046 * If the old and new tuple are on the same page, we only need to log the
9047 * parts of the new tuple that were changed. That saves on the amount of
9048 * WAL we need to write. Currently, we just count any unchanged bytes in
9049 * the beginning and end of the tuple. That's quick to check, and
9050 * perfectly covers the common case that only one field is updated.
9051 *
9052 * We could do this even if the old and new tuple are on different pages,
9053 * but only if we don't make a full-page image of the old page, which is
9054 * difficult to know in advance. Also, if the old tuple is corrupt for
9055 * some reason, it would allow the corruption to propagate the new page,
9056 * so it seems best to avoid. Under the general assumption that most
9057 * updates tend to create the new tuple version on the same page, there
9058 * isn't much to be gained by doing this across pages anyway.
9059 *
9060 * Skip this if we're taking a full-page image of the new page, as we
9061 * don't include the new tuple in the WAL record in that case. Also
9062 * disable if effective_wal_level='logical', as logical decoding needs to
9063 * be able to read the new tuple in whole from the WAL record alone.
9064 */
9065 if (oldbuf == newbuf && !need_tuple_data &&
9067 {
9068 char *oldp = (char *) oldtup->t_data + oldtup->t_data->t_hoff;
9069 char *newp = (char *) newtup->t_data + newtup->t_data->t_hoff;
9070 int oldlen = oldtup->t_len - oldtup->t_data->t_hoff;
9071 int newlen = newtup->t_len - newtup->t_data->t_hoff;
9072
9073 /* Check for common prefix between old and new tuple */
9074 for (prefixlen = 0; prefixlen < Min(oldlen, newlen); prefixlen++)
9075 {
9076 if (newp[prefixlen] != oldp[prefixlen])
9077 break;
9078 }
9079
9080 /*
9081 * Storing the length of the prefix takes 2 bytes, so we need to save
9082 * at least 3 bytes or there's no point.
9083 */
9084 if (prefixlen < 3)
9085 prefixlen = 0;
9086
9087 /* Same for suffix */
9089 {
9090 if (newp[newlen - suffixlen - 1] != oldp[oldlen - suffixlen - 1])
9091 break;
9092 }
9093 if (suffixlen < 3)
9094 suffixlen = 0;
9095 }
9096
9097 /* Prepare main WAL data chain */
9098 xlrec.flags = 0;
9103 if (prefixlen > 0)
9105 if (suffixlen > 0)
9107 if (need_tuple_data)
9108 {
9110 if (old_key_tuple)
9111 {
9112 if (reln->rd_rel->relreplident == REPLICA_IDENTITY_FULL)
9114 else
9116 }
9117 }
9118
9119 /* If new tuple is the single and first tuple on page... */
9122 {
9123 info |= XLOG_HEAP_INIT_PAGE;
9124 init = true;
9125 }
9126 else
9127 init = false;
9128
9129 /* Prepare WAL data for the old page */
9130 xlrec.old_offnum = ItemPointerGetOffsetNumber(&oldtup->t_self);
9131 xlrec.old_xmax = HeapTupleHeaderGetRawXmax(oldtup->t_data);
9132 xlrec.old_infobits_set = compute_infobits(oldtup->t_data->t_infomask,
9133 oldtup->t_data->t_infomask2);
9134
9135 /* Prepare WAL data for the new page */
9136 xlrec.new_offnum = ItemPointerGetOffsetNumber(&newtup->t_self);
9137 xlrec.new_xmax = HeapTupleHeaderGetRawXmax(newtup->t_data);
9138
9140 if (init)
9142 if (need_tuple_data)
9144
9146 if (oldbuf != newbuf)
9148
9150
9151 /*
9152 * Prepare WAL data for the new tuple.
9153 */
9154 if (prefixlen > 0 || suffixlen > 0)
9155 {
9156 if (prefixlen > 0 && suffixlen > 0)
9157 {
9161 sizeof(uint16) * 2);
9162 }
9163 else if (prefixlen > 0)
9164 {
9166 sizeof(uint16));
9167 }
9168 else
9169 {
9171 sizeof(uint16));
9172 }
9173 }
9174
9175 xlhdr.t_infomask2 = newtup->t_data->t_infomask2;
9176 xlhdr.t_infomask = newtup->t_data->t_infomask;
9177 xlhdr.t_hoff = newtup->t_data->t_hoff;
9179
9180 /*
9181 * PG73FORMAT: write bitmap [+ padding] [+ oid] + data
9182 *
9183 * The 'data' doesn't include the common prefix or suffix.
9184 */
9186 if (prefixlen == 0)
9187 {
9189 (char *) newtup->t_data + SizeofHeapTupleHeader,
9191 }
9192 else
9193 {
9194 /*
9195 * Have to write the null bitmap and data after the common prefix as
9196 * two separate rdata entries.
9197 */
9198 /* bitmap [+ padding] [+ oid] */
9199 if (newtup->t_data->t_hoff - SizeofHeapTupleHeader > 0)
9200 {
9202 (char *) newtup->t_data + SizeofHeapTupleHeader,
9203 newtup->t_data->t_hoff - SizeofHeapTupleHeader);
9204 }
9205
9206 /* data after common prefix */
9208 (char *) newtup->t_data + newtup->t_data->t_hoff + prefixlen,
9209 newtup->t_len - newtup->t_data->t_hoff - prefixlen - suffixlen);
9210 }
9211
9212 /* We need to log a tuple identity */
9214 {
9215 /* don't really need this, but its more comfy to decode */
9216 xlhdr_idx.t_infomask2 = old_key_tuple->t_data->t_infomask2;
9217 xlhdr_idx.t_infomask = old_key_tuple->t_data->t_infomask;
9218 xlhdr_idx.t_hoff = old_key_tuple->t_data->t_hoff;
9219
9221
9222 /* PG73FORMAT: write bitmap [+ padding] [+ oid] + data */
9225 }
9226
9227 /*
9228 * Register VM buffers. If the old and new heap pages' VM bits are on the
9229 * same VM page and both their VM bits were cleared, the caller passes
9230 * only vmbuffer_new (mirroring the heap page convention where block 0 =
9231 * new is always registered).
9232 */
9235
9238
9241
9242 /* filtering by origin on a row level is much more efficient */
9244
9245 recptr = XLogInsert(RM_HEAP_ID, info);
9246
9247 return recptr;
9248}

References Assert, BufferGetPage(), BufferIsInvalid, BufferIsValid(), compute_infobits(), fb(), FirstOffsetNumber, HEAP_UPDATE_BLKREF_HEAP_NEW, HEAP_UPDATE_BLKREF_HEAP_OLD, HEAP_UPDATE_BLKREF_VM_NEW, HEAP_UPDATE_BLKREF_VM_OLD, HeapTupleHeaderGetRawXmax(), HeapTupleIsHeapOnly(), init, ItemPointerGetOffsetNumber(), Min, PageGetMaxOffsetNumber(), REGBUF_KEEP_DATA, REGBUF_STANDARD, REGBUF_WILL_INIT, RelationIsLogicallyLogged, RelationNeedsWAL, SizeOfHeapHeader, SizeofHeapTupleHeader, SizeOfHeapUpdate, XLH_UPDATE_CONTAINS_NEW_TUPLE, XLH_UPDATE_CONTAINS_OLD_KEY, XLH_UPDATE_CONTAINS_OLD_TUPLE, XLH_UPDATE_NEW_ALL_VISIBLE_CLEARED, XLH_UPDATE_OLD_ALL_VISIBLE_CLEARED, XLH_UPDATE_PREFIX_FROM_OLD, XLH_UPDATE_SUFFIX_FROM_OLD, XLOG_HEAP_HOT_UPDATE, XLOG_HEAP_INIT_PAGE, XLOG_HEAP_UPDATE, XLOG_INCLUDE_ORIGIN, XLogBeginInsert(), XLogCheckBufferNeedsBackup(), XLogInsert(), XLogRegisterBufData(), XLogRegisterBuffer(), XLogRegisterData(), and XLogSetRecordFlags().

Referenced by heap_update().

◆ MultiXactIdGetUpdateXid()

static TransactionId MultiXactIdGetUpdateXid ( TransactionId  xmax,
uint16  t_infomask 
)
static

Definition at line 7748 of file heapam.c.

7749{
7751 MultiXactMember *members;
7752 int nmembers;
7753
7754 Assert(!(t_infomask & HEAP_XMAX_LOCK_ONLY));
7755 Assert(t_infomask & HEAP_XMAX_IS_MULTI);
7756
7757 /*
7758 * Since we know the LOCK_ONLY bit is not set, this cannot be a multi from
7759 * pre-pg_upgrade.
7760 */
7761 nmembers = GetMultiXactIdMembers(xmax, &members, false, false);
7762
7763 if (nmembers > 0)
7764 {
7765 int i;
7766
7767 for (i = 0; i < nmembers; i++)
7768 {
7769 /* Ignore lockers */
7770 if (!ISUPDATE_from_mxstatus(members[i].status))
7771 continue;
7772
7773 /* there can be at most one updater */
7775 update_xact = members[i].xid;
7776#ifndef USE_ASSERT_CHECKING
7777
7778 /*
7779 * in an assert-enabled build, walk the whole array to ensure
7780 * there's no other updater.
7781 */
7782 break;
7783#endif
7784 }
7785
7786 pfree(members);
7787 }
7788
7789 return update_xact;
7790}

References Assert, fb(), GetMultiXactIdMembers(), HEAP_XMAX_IS_MULTI, HEAP_XMAX_LOCK_ONLY, i, InvalidTransactionId, ISUPDATE_from_mxstatus, pfree(), and MultiXactMember::xid.

Referenced by compute_new_xmax_infomask(), FreezeMultiXactId(), heap_lock_updated_tuple(), and HeapTupleGetUpdateXid().

◆ MultiXactIdWait()

static void MultiXactIdWait ( MultiXactId  multi,
MultiXactStatus  status,
uint16  infomask,
Relation  rel,
const ItemPointerData ctid,
XLTW_Oper  oper,
int remaining 
)
static

Definition at line 7994 of file heapam.c.

7997{
7998 (void) Do_MultiXactIdWait(multi, status, infomask, false,
7999 rel, ctid, oper, remaining, false);
8000}

References Do_MultiXactIdWait(), fb(), oper(), and remaining.

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

◆ page_collect_tuples()

static pg_always_inline int page_collect_tuples ( HeapScanDesc  scan,
Snapshot  snapshot,
Page  page,
Buffer  buffer,
BlockNumber  block,
int  lines,
bool  all_visible,
bool  check_serializable 
)
static

Definition at line 525 of file heapam.c.

529{
530 Oid relid = RelationGetRelid(scan->rs_base.rs_rd);
531 int ntup = 0;
532 int nvis = 0;
534
535 /* page at a time should have been disabled otherwise */
536 Assert(IsMVCCSnapshot(snapshot));
537
538 /* first find all tuples on the page */
540 {
543
545 continue;
546
547 /*
548 * If the page is not all-visible or we need to check serializability,
549 * maintain enough state to be able to refind the tuple efficiently,
550 * without again first needing to fetch the item and then via that the
551 * tuple.
552 */
553 if (!all_visible || check_serializable)
554 {
555 tup = &batchmvcc.tuples[ntup];
556
558 tup->t_len = ItemIdGetLength(lpp);
559 tup->t_tableOid = relid;
560 ItemPointerSet(&(tup->t_self), block, lineoff);
561 }
562
563 /*
564 * If the page is all visible, these fields otherwise won't be
565 * populated in loop below.
566 */
567 if (all_visible)
568 {
570 {
571 batchmvcc.visible[ntup] = true;
572 }
573 scan->rs_vistuples[ntup] = lineoff;
574 }
575
576 ntup++;
577 }
578
580
581 /*
582 * Unless the page is all visible, test visibility for all tuples one go.
583 * That is considerably more efficient than calling
584 * HeapTupleSatisfiesMVCC() one-by-one.
585 */
586 if (all_visible)
587 nvis = ntup;
588 else
589 nvis = HeapTupleSatisfiesMVCCBatch(snapshot, buffer,
590 ntup,
591 &batchmvcc,
592 scan->rs_vistuples);
593
594 /*
595 * So far we don't have batch API for testing serializabilty, so do so
596 * one-by-one.
597 */
599 {
600 for (int i = 0; i < ntup; i++)
601 {
603 scan->rs_base.rs_rd,
604 &batchmvcc.tuples[i],
605 buffer, snapshot);
606 }
607 }
608
609 return nvis;
610}

References Assert, fb(), FirstOffsetNumber, HeapCheckForSerializableConflictOut(), HeapTupleSatisfiesMVCCBatch(), i, IsMVCCSnapshot, ItemIdGetLength, ItemIdIsNormal, ItemPointerSet(), MaxHeapTuplesPerPage, PageGetItem(), PageGetItemId(), RelationGetRelid, HeapScanDescData::rs_base, TableScanDescData::rs_rd, HeapScanDescData::rs_vistuples, HeapTupleData::t_data, and unlikely.

Referenced by heap_prepare_pagescan().

◆ ReleaseBulkInsertStatePin()

void ReleaseBulkInsertStatePin ( BulkInsertState  bistate)

Definition at line 1967 of file heapam.c.

1968{
1969 if (bistate->current_buf != InvalidBuffer)
1970 ReleaseBuffer(bistate->current_buf);
1971 bistate->current_buf = InvalidBuffer;
1972
1973 /*
1974 * Despite the name, we also reset bulk relation extension state.
1975 * Otherwise we can end up erroring out due to looking for free space in
1976 * ->next_free of one partition, even though ->next_free was set when
1977 * extending another partition. It could obviously also be bad for
1978 * efficiency to look at existing blocks at offsets from another
1979 * partition, even if we don't error out.
1980 */
1981 bistate->next_free = InvalidBlockNumber;
1982 bistate->last_free = InvalidBlockNumber;
1983}

References BulkInsertStateData::current_buf, InvalidBlockNumber, InvalidBuffer, BulkInsertStateData::last_free, BulkInsertStateData::next_free, and ReleaseBuffer().

Referenced by CopyFrom().

◆ simple_heap_delete()

void simple_heap_delete ( Relation  relation,
const ItemPointerData tid 
)

Definition at line 3219 of file heapam.c.

3220{
3222 TM_FailureData tmfd;
3223
3224 result = heap_delete(relation, tid,
3225 GetCurrentCommandId(true),
3226 0,
3228 true /* wait for commit */ ,
3229 &tmfd);
3230 switch (result)
3231 {
3232 case TM_SelfModified:
3233 /* Tuple was already updated in current command? */
3234 elog(ERROR, "tuple already updated by self");
3235 break;
3236
3237 case TM_Ok:
3238 /* done successfully */
3239 break;
3240
3241 case TM_Updated:
3242 elog(ERROR, "tuple concurrently updated");
3243 break;
3244
3245 case TM_Deleted:
3246 elog(ERROR, "tuple concurrently deleted");
3247 break;
3248
3249 default:
3250 elog(ERROR, "unrecognized heap_delete status: %u", result);
3251 break;
3252 }
3253}

References elog, ERROR, GetCurrentCommandId(), heap_delete(), InvalidSnapshot, result, TM_Deleted, TM_Ok, TM_SelfModified, and TM_Updated.

Referenced by CatalogTupleDelete(), and toast_delete_datum().

◆ simple_heap_insert()

void simple_heap_insert ( Relation  relation,
HeapTuple  tup 
)

Definition at line 2701 of file heapam.c.

2702{
2703 heap_insert(relation, tup, GetCurrentCommandId(true), 0, NULL);
2704}

References fb(), GetCurrentCommandId(), and heap_insert().

Referenced by CatalogTupleInsert(), CatalogTupleInsertWithInfo(), and InsertOneTuple().

◆ simple_heap_update()

void simple_heap_update ( Relation  relation,
const ItemPointerData otid,
HeapTuple  tup,
TU_UpdateIndexes update_indexes 
)

Definition at line 4639 of file heapam.c.

4641{
4643 TM_FailureData tmfd;
4644 LockTupleMode lockmode;
4645
4646 result = heap_update(relation, otid, tup,
4647 GetCurrentCommandId(true), 0,
4649 true /* wait for commit */ ,
4650 &tmfd, &lockmode, update_indexes);
4651 switch (result)
4652 {
4653 case TM_SelfModified:
4654 /* Tuple was already updated in current command? */
4655 elog(ERROR, "tuple already updated by self");
4656 break;
4657
4658 case TM_Ok:
4659 /* done successfully */
4660 break;
4661
4662 case TM_Updated:
4663 elog(ERROR, "tuple concurrently updated");
4664 break;
4665
4666 case TM_Deleted:
4667 elog(ERROR, "tuple concurrently deleted");
4668 break;
4669
4670 default:
4671 elog(ERROR, "unrecognized heap_update status: %u", result);
4672 break;
4673 }
4674}

References elog, ERROR, fb(), GetCurrentCommandId(), heap_update(), InvalidSnapshot, result, TM_Deleted, TM_Ok, TM_SelfModified, and TM_Updated.

Referenced by CatalogTupleUpdate(), and CatalogTupleUpdateWithInfo().

◆ test_lockmode_for_conflict()

static TM_Result test_lockmode_for_conflict ( MultiXactStatus  status,
TransactionId  xid,
LockTupleMode  mode,
HeapTuple  tup,
bool needwait 
)
static

Definition at line 5784 of file heapam.c.

5787{
5789
5790 *needwait = false;
5792
5793 /*
5794 * Note: we *must* check TransactionIdIsInProgress before
5795 * TransactionIdDidAbort/Commit; see comment at top of heapam_visibility.c
5796 * for an explanation.
5797 */
5799 {
5800 /*
5801 * The tuple has already been locked by our own transaction. This is
5802 * very rare but can happen if multiple transactions are trying to
5803 * lock an ancient version of the same tuple.
5804 */
5805 return TM_SelfModified;
5806 }
5807 else if (TransactionIdIsInProgress(xid))
5808 {
5809 /*
5810 * If the locking transaction is running, what we do depends on
5811 * whether the lock modes conflict: if they do, then we must wait for
5812 * it to finish; otherwise we can fall through to lock this tuple
5813 * version without waiting.
5814 */
5817 {
5818 *needwait = true;
5819 }
5820
5821 /*
5822 * If we set needwait above, then this value doesn't matter;
5823 * otherwise, this value signals to caller that it's okay to proceed.
5824 */
5825 return TM_Ok;
5826 }
5827 else if (TransactionIdDidAbort(xid))
5828 return TM_Ok;
5829 else if (TransactionIdDidCommit(xid))
5830 {
5831 /*
5832 * The other transaction committed. If it was only a locker, then the
5833 * lock is completely gone now and we can return success; but if it
5834 * was an update, then what we do depends on whether the two lock
5835 * modes conflict. If they conflict, then we must report error to
5836 * caller. But if they don't, we can fall through to allow the current
5837 * transaction to lock the tuple.
5838 *
5839 * Note: the reason we worry about ISUPDATE here is because as soon as
5840 * a transaction ends, all its locks are gone and meaningless, and
5841 * thus we can ignore them; whereas its updates persist. In the
5842 * TransactionIdIsInProgress case, above, we don't need to check
5843 * because we know the lock is still "alive" and thus a conflict needs
5844 * always be checked.
5845 */
5846 if (!ISUPDATE_from_mxstatus(status))
5847 return TM_Ok;
5848
5851 {
5852 /* bummer */
5853 if (!ItemPointerEquals(&tup->t_self, &tup->t_data->t_ctid))
5854 return TM_Updated;
5855 else
5856 return TM_Deleted;
5857 }
5858
5859 return TM_Ok;
5860 }
5861
5862 /* Not in progress, not aborted, not committed -- must have crashed */
5863 return TM_Ok;
5864}

References DoLockModesConflict(), fb(), get_mxact_status_for_lock(), ISUPDATE_from_mxstatus, ItemPointerEquals(), LOCKMODE_from_mxstatus, mode, TM_Deleted, TM_Ok, TM_SelfModified, TM_Updated, TransactionIdDidAbort(), TransactionIdDidCommit(), TransactionIdIsCurrentTransactionId(), and TransactionIdIsInProgress().

Referenced by heap_lock_updated_tuple_rec().

◆ UpdateXmaxHintBits()

◆ xmax_infomask_changed()

static bool xmax_infomask_changed ( uint16  new_infomask,
uint16  old_infomask 
)
inlinestatic

Definition at line 2736 of file heapam.c.

2737{
2738 const uint16 interesting =
2740
2741 if ((new_infomask & interesting) != (old_infomask & interesting))
2742 return true;
2743
2744 return false;
2745}

References fb(), HEAP_LOCK_MASK, HEAP_XMAX_IS_MULTI, and HEAP_XMAX_LOCK_ONLY.

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

Variable Documentation

◆ hwlock

LOCKMODE hwlock

Definition at line 131 of file heapam.c.

◆ lockstatus

int lockstatus

Definition at line 132 of file heapam.c.

◆ MultiXactStatusLock

const int MultiXactStatusLock[MaxMultiXactStatus+1]
static
Initial value:

Definition at line 210 of file heapam.c.

211{
212 LockTupleKeyShare, /* ForKeyShare */
213 LockTupleShare, /* ForShare */
214 LockTupleNoKeyExclusive, /* ForNoKeyUpdate */
215 LockTupleExclusive, /* ForUpdate */
216 LockTupleNoKeyExclusive, /* NoKeyUpdate */
217 LockTupleExclusive /* Update */
218};

◆ [struct]

const struct { ... } tupleLockExtraInfo[]
Initial value:
=
{
.hwlock = AccessShareLock,
.updstatus = -1
},
.hwlock = RowShareLock,
.lockstatus = MultiXactStatusForShare,
.updstatus = -1
},
.hwlock = ExclusiveLock,
},
.lockstatus = MultiXactStatusForUpdate,
.updstatus = MultiXactStatusUpdate
}
}
#define AccessExclusiveLock
Definition lockdefs.h:43
#define ExclusiveLock
Definition lockdefs.h:42
#define RowShareLock
Definition lockdefs.h:37

Referenced by DoesMultiXactIdConflict(), and get_mxact_status_for_lock().

◆ updstatus

int updstatus

Definition at line 133 of file heapam.c.