PostgreSQL Source Code  git master
pg_visibility.c File Reference
#include "postgres.h"
#include "access/heapam.h"
#include "access/htup_details.h"
#include "access/visibilitymap.h"
#include "access/xloginsert.h"
#include "catalog/pg_type.h"
#include "catalog/storage_xlog.h"
#include "funcapi.h"
#include "miscadmin.h"
#include "storage/bufmgr.h"
#include "storage/proc.h"
#include "storage/procarray.h"
#include "storage/read_stream.h"
#include "storage/smgr.h"
#include "utils/rel.h"
#include "utils/snapmgr.h"
Include dependency graph for pg_visibility.c:

Go to the source code of this file.

Data Structures

struct  vbits
 
struct  corrupt_items
 
struct  collect_corrupt_items_read_stream_private
 

Typedefs

typedef struct vbits vbits
 
typedef struct corrupt_items corrupt_items
 

Functions

 PG_FUNCTION_INFO_V1 (pg_visibility_map)
 
 PG_FUNCTION_INFO_V1 (pg_visibility_map_rel)
 
 PG_FUNCTION_INFO_V1 (pg_visibility)
 
 PG_FUNCTION_INFO_V1 (pg_visibility_rel)
 
 PG_FUNCTION_INFO_V1 (pg_visibility_map_summary)
 
 PG_FUNCTION_INFO_V1 (pg_check_frozen)
 
 PG_FUNCTION_INFO_V1 (pg_check_visible)
 
 PG_FUNCTION_INFO_V1 (pg_truncate_visibility_map)
 
static TupleDesc pg_visibility_tupdesc (bool include_blkno, bool include_pd)
 
static vbitscollect_visibility_data (Oid relid, bool include_pd)
 
static corrupt_itemscollect_corrupt_items (Oid relid, bool all_visible, bool all_frozen)
 
static void record_corrupt_item (corrupt_items *items, ItemPointer tid)
 
static bool tuple_all_visible (HeapTuple tup, TransactionId OldestXmin, Buffer buffer)
 
static void check_relation_relkind (Relation rel)
 
Datum pg_visibility_map (PG_FUNCTION_ARGS)
 
Datum pg_visibility (PG_FUNCTION_ARGS)
 
Datum pg_visibility_map_rel (PG_FUNCTION_ARGS)
 
Datum pg_visibility_rel (PG_FUNCTION_ARGS)
 
Datum pg_visibility_map_summary (PG_FUNCTION_ARGS)
 
Datum pg_check_frozen (PG_FUNCTION_ARGS)
 
Datum pg_check_visible (PG_FUNCTION_ARGS)
 
Datum pg_truncate_visibility_map (PG_FUNCTION_ARGS)
 
static TransactionId GetStrictOldestNonRemovableTransactionId (Relation rel)
 
static BlockNumber collect_corrupt_items_read_stream_next_block (ReadStream *stream, void *callback_private_data, void *per_buffer_data)
 

Variables

 PG_MODULE_MAGIC
 

Typedef Documentation

◆ corrupt_items

typedef struct corrupt_items corrupt_items

◆ vbits

typedef struct vbits vbits

Function Documentation

◆ check_relation_relkind()

static void check_relation_relkind ( Relation  rel)
static

Definition at line 920 of file pg_visibility.c.

921 {
922  if (!RELKIND_HAS_TABLE_AM(rel->rd_rel->relkind))
923  ereport(ERROR,
924  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
925  errmsg("relation \"%s\" is of wrong relation kind",
927  errdetail_relkind_not_supported(rel->rd_rel->relkind)));
928 }
int errcode(int sqlerrcode)
Definition: elog.c:853
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149
int errdetail_relkind_not_supported(char relkind)
Definition: pg_class.c:24
#define RelationGetRelationName(relation)
Definition: rel.h:539
Form_pg_class rd_rel
Definition: rel.h:111

References ereport, errcode(), errdetail_relkind_not_supported(), errmsg(), ERROR, RelationData::rd_rel, collect_corrupt_items_read_stream_private::rel, and RelationGetRelationName.

Referenced by collect_corrupt_items(), collect_visibility_data(), pg_truncate_visibility_map(), pg_visibility(), pg_visibility_map(), and pg_visibility_map_summary().

◆ collect_corrupt_items()

static corrupt_items * collect_corrupt_items ( Oid  relid,
bool  all_visible,
bool  all_frozen 
)
static

Definition at line 693 of file pg_visibility.c.

694 {
695  Relation rel;
697  Buffer vmbuffer = InvalidBuffer;
699  TransactionId OldestXmin = InvalidTransactionId;
701  ReadStream *stream;
702  Buffer buffer;
703 
705 
706  /* Only some relkinds have a visibility map */
708 
709  if (all_visible)
711 
712  /*
713  * Guess an initial array size. We don't expect many corrupted tuples, so
714  * start with a small array. This function uses the "next" field to track
715  * the next offset where we can store an item (which is the same thing as
716  * the number of items found so far) and the "count" field to track the
717  * number of entries allocated. We'll repurpose these fields before
718  * returning.
719  */
720  items = palloc0(sizeof(corrupt_items));
721  items->next = 0;
722  items->count = 64;
723  items->tids = palloc(items->count * sizeof(ItemPointerData));
724 
725  p.current_blocknum = 0;
726  p.last_exclusive = RelationGetNumberOfBlocks(rel);
727  p.rel = rel;
728  p.vmbuffer = InvalidBuffer;
729  p.all_frozen = all_frozen;
730  p.all_visible = all_visible;
732  bstrategy,
733  rel,
734  MAIN_FORKNUM,
736  &p,
737  0);
738 
739  /* Loop over every block in the relation. */
740  while ((buffer = read_stream_next_buffer(stream, NULL)) != InvalidBuffer)
741  {
742  bool check_frozen = all_frozen;
743  bool check_visible = all_visible;
744  Page page;
745  OffsetNumber offnum,
746  maxoff;
747  BlockNumber blkno;
748 
749  /* Make sure we are interruptible. */
751 
752  LockBuffer(buffer, BUFFER_LOCK_SHARE);
753 
754  page = BufferGetPage(buffer);
755  maxoff = PageGetMaxOffsetNumber(page);
756  blkno = BufferGetBlockNumber(buffer);
757 
758  /*
759  * The visibility map bits might have changed while we were acquiring
760  * the page lock. Recheck to avoid returning spurious results.
761  */
762  if (check_frozen && !VM_ALL_FROZEN(rel, blkno, &vmbuffer))
763  check_frozen = false;
764  if (check_visible && !VM_ALL_VISIBLE(rel, blkno, &vmbuffer))
765  check_visible = false;
766  if (!check_visible && !check_frozen)
767  {
768  UnlockReleaseBuffer(buffer);
769  continue;
770  }
771 
772  /* Iterate over each tuple on the page. */
773  for (offnum = FirstOffsetNumber;
774  offnum <= maxoff;
775  offnum = OffsetNumberNext(offnum))
776  {
777  HeapTupleData tuple;
778  ItemId itemid;
779 
780  itemid = PageGetItemId(page, offnum);
781 
782  /* Unused or redirect line pointers are of no interest. */
783  if (!ItemIdIsUsed(itemid) || ItemIdIsRedirected(itemid))
784  continue;
785 
786  /* Dead line pointers are neither all-visible nor frozen. */
787  if (ItemIdIsDead(itemid))
788  {
789  ItemPointerSet(&(tuple.t_self), blkno, offnum);
791  continue;
792  }
793 
794  /* Initialize a HeapTupleData structure for checks below. */
795  ItemPointerSet(&(tuple.t_self), blkno, offnum);
796  tuple.t_data = (HeapTupleHeader) PageGetItem(page, itemid);
797  tuple.t_len = ItemIdGetLength(itemid);
798  tuple.t_tableOid = relid;
799 
800  /*
801  * If we're checking whether the page is all-visible, we expect
802  * the tuple to be all-visible.
803  */
804  if (check_visible &&
805  !tuple_all_visible(&tuple, OldestXmin, buffer))
806  {
807  TransactionId RecomputedOldestXmin;
808 
809  /*
810  * Time has passed since we computed OldestXmin, so it's
811  * possible that this tuple is all-visible in reality even
812  * though it doesn't appear so based on our
813  * previously-computed value. Let's compute a new value so we
814  * can be certain whether there is a problem.
815  *
816  * From a concurrency point of view, it sort of sucks to
817  * retake ProcArrayLock here while we're holding the buffer
818  * exclusively locked, but it should be safe against
819  * deadlocks, because surely
820  * GetStrictOldestNonRemovableTransactionId() should never
821  * take a buffer lock. And this shouldn't happen often, so
822  * it's worth being careful so as to avoid false positives.
823  */
824  RecomputedOldestXmin = GetStrictOldestNonRemovableTransactionId(rel);
825 
826  if (!TransactionIdPrecedes(OldestXmin, RecomputedOldestXmin))
828  else
829  {
830  OldestXmin = RecomputedOldestXmin;
831  if (!tuple_all_visible(&tuple, OldestXmin, buffer))
833  }
834  }
835 
836  /*
837  * If we're checking whether the page is all-frozen, we expect the
838  * tuple to be in a state where it will never need freezing.
839  */
840  if (check_frozen)
841  {
844  }
845  }
846 
847  UnlockReleaseBuffer(buffer);
848  }
849  read_stream_end(stream);
850 
851  /* Clean up. */
852  if (vmbuffer != InvalidBuffer)
854  if (p.vmbuffer != InvalidBuffer)
855  ReleaseBuffer(p.vmbuffer);
857 
858  /*
859  * Before returning, repurpose the fields to match caller's expectations.
860  * next is now the next item that should be read (rather than written) and
861  * count is now the number of items we wrote (rather than the number we
862  * allocated).
863  */
864  items->count = items->next;
865  items->next = 0;
866 
867  return items;
868 }
uint32 BlockNumber
Definition: block.h:31
int Buffer
Definition: buf.h:23
#define InvalidBuffer
Definition: buf.h:25
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:3706
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:4906
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:4923
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:5140
@ BAS_BULKREAD
Definition: bufmgr.h:36
#define BUFFER_LOCK_SHARE
Definition: bufmgr.h:190
#define RelationGetNumberOfBlocks(reln)
Definition: bufmgr.h:273
static Page BufferGetPage(Buffer buffer)
Definition: bufmgr.h:400
Pointer Page
Definition: bufpage.h:81
static Item PageGetItem(Page page, ItemId itemId)
Definition: bufpage.h:354
static ItemId PageGetItemId(Page page, OffsetNumber offsetNumber)
Definition: bufpage.h:243
static OffsetNumber PageGetMaxOffsetNumber(Page page)
Definition: bufpage.h:372
uint32 TransactionId
Definition: c.h:652
BufferAccessStrategy GetAccessStrategy(BufferAccessStrategyType btype)
Definition: freelist.c:541
bool heap_tuple_needs_eventual_freeze(HeapTupleHeader tuple)
Definition: heapam.c:7286
HeapTupleHeaderData * HeapTupleHeader
Definition: htup.h:23
#define ItemIdGetLength(itemId)
Definition: itemid.h:59
#define ItemIdIsDead(itemId)
Definition: itemid.h:113
#define ItemIdIsUsed(itemId)
Definition: itemid.h:92
#define ItemIdIsRedirected(itemId)
Definition: itemid.h:106
static void ItemPointerSet(ItemPointerData *pointer, BlockNumber blockNumber, OffsetNumber offNum)
Definition: itemptr.h:135
#define AccessShareLock
Definition: lockdefs.h:36
void * palloc0(Size size)
Definition: mcxt.c:1347
void * palloc(Size size)
Definition: mcxt.c:1317
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:122
#define OffsetNumberNext(offsetNumber)
Definition: off.h:52
uint16 OffsetNumber
Definition: off.h:24
#define FirstOffsetNumber
Definition: off.h:27
static BlockNumber collect_corrupt_items_read_stream_next_block(ReadStream *stream, void *callback_private_data, void *per_buffer_data)
static void check_relation_relkind(Relation rel)
static void record_corrupt_item(corrupt_items *items, ItemPointer tid)
static TransactionId GetStrictOldestNonRemovableTransactionId(Relation rel)
static bool tuple_all_visible(HeapTuple tup, TransactionId OldestXmin, Buffer buffer)
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)
Definition: read_stream.c:552
Buffer read_stream_next_buffer(ReadStream *stream, void **per_buffer_data)
Definition: read_stream.c:606
void read_stream_end(ReadStream *stream)
Definition: read_stream.c:847
#define READ_STREAM_FULL
Definition: read_stream.h:43
@ MAIN_FORKNUM
Definition: relpath.h:58
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: relation.c:205
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:47
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
static ItemArray items
Definition: test_tidstore.c:49
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition: transam.c:280
#define InvalidTransactionId
Definition: transam.h:31
#define VM_ALL_VISIBLE(r, b, v)
Definition: visibilitymap.h:24
#define VM_ALL_FROZEN(r, b, v)
Definition: visibilitymap.h:26

References AccessShareLock, collect_corrupt_items_read_stream_private::all_frozen, collect_corrupt_items_read_stream_private::all_visible, BAS_BULKREAD, BUFFER_LOCK_SHARE, BufferGetBlockNumber(), BufferGetPage(), CHECK_FOR_INTERRUPTS, check_relation_relkind(), collect_corrupt_items_read_stream_next_block(), collect_corrupt_items_read_stream_private::current_blocknum, FirstOffsetNumber, GetAccessStrategy(), GetStrictOldestNonRemovableTransactionId(), heap_tuple_needs_eventual_freeze(), InvalidBuffer, InvalidTransactionId, ItemIdGetLength, ItemIdIsDead, ItemIdIsRedirected, ItemIdIsUsed, ItemPointerSet(), items, collect_corrupt_items_read_stream_private::last_exclusive, LockBuffer(), MAIN_FORKNUM, OffsetNumberNext, PageGetItem(), PageGetItemId(), PageGetMaxOffsetNumber(), palloc(), palloc0(), read_stream_begin_relation(), read_stream_end(), READ_STREAM_FULL, read_stream_next_buffer(), record_corrupt_item(), collect_corrupt_items_read_stream_private::rel, relation_close(), relation_open(), RelationGetNumberOfBlocks, ReleaseBuffer(), HeapTupleData::t_data, HeapTupleData::t_len, HeapTupleData::t_self, HeapTupleData::t_tableOid, TransactionIdPrecedes(), tuple_all_visible(), UnlockReleaseBuffer(), VM_ALL_FROZEN, VM_ALL_VISIBLE, and collect_corrupt_items_read_stream_private::vmbuffer.

Referenced by pg_check_frozen(), and pg_check_visible().

◆ collect_corrupt_items_read_stream_next_block()

static BlockNumber collect_corrupt_items_read_stream_next_block ( ReadStream stream,
void *  callback_private_data,
void *  per_buffer_data 
)
static

Definition at line 651 of file pg_visibility.c.

654 {
655  struct collect_corrupt_items_read_stream_private *p = callback_private_data;
656 
657  for (; p->current_blocknum < p->last_exclusive; p->current_blocknum++)
658  {
659  bool check_frozen = false;
660  bool check_visible = false;
661 
662  /* Make sure we are interruptible. */
664 
665  if (p->all_frozen && VM_ALL_FROZEN(p->rel, p->current_blocknum, &p->vmbuffer))
666  check_frozen = true;
667  if (p->all_visible && VM_ALL_VISIBLE(p->rel, p->current_blocknum, &p->vmbuffer))
668  check_visible = true;
669  if (!check_visible && !check_frozen)
670  continue;
671 
672  return p->current_blocknum++;
673  }
674 
675  return InvalidBlockNumber;
676 }
#define InvalidBlockNumber
Definition: block.h:33

References collect_corrupt_items_read_stream_private::all_frozen, collect_corrupt_items_read_stream_private::all_visible, CHECK_FOR_INTERRUPTS, collect_corrupt_items_read_stream_private::current_blocknum, InvalidBlockNumber, collect_corrupt_items_read_stream_private::last_exclusive, collect_corrupt_items_read_stream_private::rel, VM_ALL_FROZEN, VM_ALL_VISIBLE, and collect_corrupt_items_read_stream_private::vmbuffer.

Referenced by collect_corrupt_items().

◆ collect_visibility_data()

static vbits * collect_visibility_data ( Oid  relid,
bool  include_pd 
)
static

Definition at line 485 of file pg_visibility.c.

486 {
487  Relation rel;
488  BlockNumber nblocks;
489  vbits *info;
490  BlockNumber blkno;
491  Buffer vmbuffer = InvalidBuffer;
494  ReadStream *stream = NULL;
495 
496  rel = relation_open(relid, AccessShareLock);
497 
498  /* Only some relkinds have a visibility map */
500 
501  nblocks = RelationGetNumberOfBlocks(rel);
502  info = palloc0(offsetof(vbits, bits) + nblocks);
503  info->next = 0;
504  info->count = nblocks;
505 
506  /* Create a stream if reading main fork. */
507  if (include_pd)
508  {
509  p.current_blocknum = 0;
510  p.last_exclusive = nblocks;
512  bstrategy,
513  rel,
514  MAIN_FORKNUM,
516  &p,
517  0);
518  }
519 
520  for (blkno = 0; blkno < nblocks; ++blkno)
521  {
522  int32 mapbits;
523 
524  /* Make sure we are interruptible. */
526 
527  /* Get map info. */
528  mapbits = (int32) visibilitymap_get_status(rel, blkno, &vmbuffer);
529  if ((mapbits & VISIBILITYMAP_ALL_VISIBLE) != 0)
530  info->bits[blkno] |= (1 << 0);
531  if ((mapbits & VISIBILITYMAP_ALL_FROZEN) != 0)
532  info->bits[blkno] |= (1 << 1);
533 
534  /*
535  * Page-level data requires reading every block, so only get it if the
536  * caller needs it. Use a buffer access strategy, too, to prevent
537  * cache-trashing.
538  */
539  if (include_pd)
540  {
541  Buffer buffer;
542  Page page;
543 
544  buffer = read_stream_next_buffer(stream, NULL);
545  LockBuffer(buffer, BUFFER_LOCK_SHARE);
546 
547  page = BufferGetPage(buffer);
548  if (PageIsAllVisible(page))
549  info->bits[blkno] |= (1 << 2);
550 
551  UnlockReleaseBuffer(buffer);
552  }
553  }
554 
555  if (include_pd)
556  {
557  Assert(read_stream_next_buffer(stream, NULL) == InvalidBuffer);
558  read_stream_end(stream);
559  }
560 
561  /* Clean up. */
562  if (vmbuffer != InvalidBuffer)
563  ReleaseBuffer(vmbuffer);
565 
566  return info;
567 }
static bool PageIsAllVisible(Page page)
Definition: bufpage.h:429
signed int int32
Definition: c.h:494
#define Assert(condition)
Definition: c.h:858
BlockNumber block_range_read_stream_cb(ReadStream *stream, void *callback_private_data, void *per_buffer_data)
Definition: read_stream.c:172
BlockNumber next
Definition: pg_visibility.c:33
uint8 bits[FLEXIBLE_ARRAY_MEMBER]
Definition: pg_visibility.c:35
BlockNumber count
Definition: pg_visibility.c:34
uint8 visibilitymap_get_status(Relation rel, BlockNumber heapBlk, Buffer *vmbuf)
#define VISIBILITYMAP_ALL_FROZEN
#define VISIBILITYMAP_ALL_VISIBLE

References AccessShareLock, Assert, BAS_BULKREAD, vbits::bits, block_range_read_stream_cb(), BUFFER_LOCK_SHARE, BufferGetPage(), CHECK_FOR_INTERRUPTS, check_relation_relkind(), vbits::count, BlockRangeReadStreamPrivate::current_blocknum, GetAccessStrategy(), InvalidBuffer, BlockRangeReadStreamPrivate::last_exclusive, LockBuffer(), MAIN_FORKNUM, vbits::next, PageIsAllVisible(), palloc0(), read_stream_begin_relation(), read_stream_end(), READ_STREAM_FULL, read_stream_next_buffer(), relation_close(), relation_open(), RelationGetNumberOfBlocks, ReleaseBuffer(), UnlockReleaseBuffer(), VISIBILITYMAP_ALL_FROZEN, VISIBILITYMAP_ALL_VISIBLE, and visibilitymap_get_status().

Referenced by pg_visibility_map_rel(), and pg_visibility_rel().

◆ GetStrictOldestNonRemovableTransactionId()

static TransactionId GetStrictOldestNonRemovableTransactionId ( Relation  rel)
static

Definition at line 602 of file pg_visibility.c.

603 {
604  RunningTransactions runningTransactions;
605 
606  if (RecoveryInProgress())
607  {
608  TransactionId result;
609 
610  /* As we ignore KnownAssignedXids on standby, just pick nextXid */
611  LWLockAcquire(XidGenLock, LW_SHARED);
613  LWLockRelease(XidGenLock);
614  return result;
615  }
616  else if (rel == NULL || rel->rd_rel->relisshared)
617  {
618  /* Shared relation: take into account all running xids */
619  runningTransactions = GetRunningTransactionData();
620  LWLockRelease(ProcArrayLock);
621  LWLockRelease(XidGenLock);
622  return runningTransactions->oldestRunningXid;
623  }
624  else if (!RELATION_IS_LOCAL(rel))
625  {
626  /*
627  * Normal relation: take into account xids running within the current
628  * database
629  */
630  runningTransactions = GetRunningTransactionData();
631  LWLockRelease(ProcArrayLock);
632  LWLockRelease(XidGenLock);
633  return runningTransactions->oldestDatabaseRunningXid;
634  }
635  else
636  {
637  /*
638  * For temporary relations, ComputeXidHorizons() uses only
639  * TransamVariables->latestCompletedXid and MyProc->xid. These two
640  * shouldn't go backwards. So we're fine with this horizon.
641  */
643  }
644 }
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1168
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1781
@ LW_SHARED
Definition: lwlock.h:115
TransactionId GetOldestNonRemovableTransactionId(Relation rel)
Definition: procarray.c:2005
RunningTransactions GetRunningTransactionData(void)
Definition: procarray.c:2693
#define RELATION_IS_LOCAL(relation)
Definition: rel.h:648
TransactionId oldestRunningXid
Definition: standby.h:92
TransactionId oldestDatabaseRunningXid
Definition: standby.h:93
FullTransactionId nextXid
Definition: transam.h:220
#define XidFromFullTransactionId(x)
Definition: transam.h:48
TransamVariablesData * TransamVariables
Definition: varsup.c:34
bool RecoveryInProgress(void)
Definition: xlog.c:6333

References GetOldestNonRemovableTransactionId(), GetRunningTransactionData(), LW_SHARED, LWLockAcquire(), LWLockRelease(), TransamVariablesData::nextXid, RunningTransactionsData::oldestDatabaseRunningXid, RunningTransactionsData::oldestRunningXid, RelationData::rd_rel, RecoveryInProgress(), RELATION_IS_LOCAL, TransamVariables, and XidFromFullTransactionId.

Referenced by collect_corrupt_items().

◆ pg_check_frozen()

Datum pg_check_frozen ( PG_FUNCTION_ARGS  )

Definition at line 322 of file pg_visibility.c.

323 {
324  FuncCallContext *funcctx;
326 
327  if (SRF_IS_FIRSTCALL())
328  {
329  Oid relid = PG_GETARG_OID(0);
330  MemoryContext oldcontext;
331 
332  funcctx = SRF_FIRSTCALL_INIT();
333  oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
334  /* collect_corrupt_items will verify the relkind */
335  funcctx->user_fctx = collect_corrupt_items(relid, false, true);
336  MemoryContextSwitchTo(oldcontext);
337  }
338 
339  funcctx = SRF_PERCALL_SETUP();
340  items = (corrupt_items *) funcctx->user_fctx;
341 
342  if (items->next < items->count)
343  SRF_RETURN_NEXT(funcctx, PointerGetDatum(&items->tids[items->next++]));
344 
345  SRF_RETURN_DONE(funcctx);
346 }
#define PG_GETARG_OID(n)
Definition: fmgr.h:275
#define SRF_IS_FIRSTCALL()
Definition: funcapi.h:304
#define SRF_PERCALL_SETUP()
Definition: funcapi.h:308
#define SRF_RETURN_NEXT(_funcctx, _result)
Definition: funcapi.h:310
#define SRF_FIRSTCALL_INIT()
Definition: funcapi.h:306
#define SRF_RETURN_DONE(_funcctx)
Definition: funcapi.h:328
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:77
static corrupt_items * collect_corrupt_items(Oid relid, bool all_visible, bool all_frozen)
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:322
unsigned int Oid
Definition: postgres_ext.h:31
MemoryContextSwitchTo(old_ctx)
void * user_fctx
Definition: funcapi.h:82
MemoryContext multi_call_memory_ctx
Definition: funcapi.h:101

References collect_corrupt_items(), if(), items, MemoryContextSwitchTo(), FuncCallContext::multi_call_memory_ctx, PG_GETARG_OID, PointerGetDatum(), SRF_FIRSTCALL_INIT, SRF_IS_FIRSTCALL, SRF_PERCALL_SETUP, SRF_RETURN_DONE, SRF_RETURN_NEXT, and FuncCallContext::user_fctx.

◆ pg_check_visible()

Datum pg_check_visible ( PG_FUNCTION_ARGS  )

Definition at line 354 of file pg_visibility.c.

355 {
356  FuncCallContext *funcctx;
358 
359  if (SRF_IS_FIRSTCALL())
360  {
361  Oid relid = PG_GETARG_OID(0);
362  MemoryContext oldcontext;
363 
364  funcctx = SRF_FIRSTCALL_INIT();
365  oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
366  /* collect_corrupt_items will verify the relkind */
367  funcctx->user_fctx = collect_corrupt_items(relid, true, false);
368  MemoryContextSwitchTo(oldcontext);
369  }
370 
371  funcctx = SRF_PERCALL_SETUP();
372  items = (corrupt_items *) funcctx->user_fctx;
373 
374  if (items->next < items->count)
375  SRF_RETURN_NEXT(funcctx, PointerGetDatum(&items->tids[items->next++]));
376 
377  SRF_RETURN_DONE(funcctx);
378 }

References collect_corrupt_items(), if(), items, MemoryContextSwitchTo(), FuncCallContext::multi_call_memory_ctx, PG_GETARG_OID, PointerGetDatum(), SRF_FIRSTCALL_INIT, SRF_IS_FIRSTCALL, SRF_PERCALL_SETUP, SRF_RETURN_DONE, SRF_RETURN_NEXT, and FuncCallContext::user_fctx.

◆ PG_FUNCTION_INFO_V1() [1/8]

PG_FUNCTION_INFO_V1 ( pg_check_frozen  )

◆ PG_FUNCTION_INFO_V1() [2/8]

PG_FUNCTION_INFO_V1 ( pg_check_visible  )

◆ PG_FUNCTION_INFO_V1() [3/8]

PG_FUNCTION_INFO_V1 ( pg_truncate_visibility_map  )

◆ PG_FUNCTION_INFO_V1() [4/8]

PG_FUNCTION_INFO_V1 ( pg_visibility  )

◆ PG_FUNCTION_INFO_V1() [5/8]

PG_FUNCTION_INFO_V1 ( pg_visibility_map  )

◆ PG_FUNCTION_INFO_V1() [6/8]

PG_FUNCTION_INFO_V1 ( pg_visibility_map_rel  )

◆ PG_FUNCTION_INFO_V1() [7/8]

PG_FUNCTION_INFO_V1 ( pg_visibility_map_summary  )

◆ PG_FUNCTION_INFO_V1() [8/8]

PG_FUNCTION_INFO_V1 ( pg_visibility_rel  )

◆ pg_truncate_visibility_map()

Datum pg_truncate_visibility_map ( PG_FUNCTION_ARGS  )

Definition at line 389 of file pg_visibility.c.

390 {
391  Oid relid = PG_GETARG_OID(0);
392  Relation rel;
393  ForkNumber fork;
394  BlockNumber block;
395 
396  rel = relation_open(relid, AccessExclusiveLock);
397 
398  /* Only some relkinds have a visibility map */
400 
401  /* Forcibly reset cached file size */
403 
404  block = visibilitymap_prepare_truncate(rel, 0);
405  if (BlockNumberIsValid(block))
406  {
407  fork = VISIBILITYMAP_FORKNUM;
408  smgrtruncate(RelationGetSmgr(rel), &fork, 1, &block);
409  }
410 
411  if (RelationNeedsWAL(rel))
412  {
413  xl_smgr_truncate xlrec;
414 
415  xlrec.blkno = 0;
416  xlrec.rlocator = rel->rd_locator;
417  xlrec.flags = SMGR_TRUNCATE_VM;
418 
419  XLogBeginInsert();
420  XLogRegisterData((char *) &xlrec, sizeof(xlrec));
421 
423  }
424 
425  /*
426  * Release the lock right away, not at commit time.
427  *
428  * It would be a problem to release the lock prior to commit if this
429  * truncate operation sends any transactional invalidation messages. Other
430  * backends would potentially be able to lock the relation without
431  * processing them in the window of time between when we release the lock
432  * here and when we sent the messages at our eventual commit. However,
433  * we're currently only sending a non-transactional smgr invalidation,
434  * which will have been posted to shared memory immediately from within
435  * smgr_truncate. Therefore, there should be no race here.
436  *
437  * The reason why it's desirable to release the lock early here is because
438  * of the possibility that someone will need to use this to blow away many
439  * visibility map forks at once. If we can't release the lock until
440  * commit time, the transaction doing this will accumulate
441  * AccessExclusiveLocks on all of those relations at the same time, which
442  * is undesirable. However, if this turns out to be unsafe we may have no
443  * choice...
444  */
446 
447  /* Nothing to return. */
448  PG_RETURN_VOID();
449 }
static bool BlockNumberIsValid(BlockNumber blockNumber)
Definition: block.h:71
#define PG_RETURN_VOID()
Definition: fmgr.h:349
#define AccessExclusiveLock
Definition: lockdefs.h:43
static SMgrRelation RelationGetSmgr(Relation rel)
Definition: rel.h:567
#define RelationNeedsWAL(relation)
Definition: rel.h:628
ForkNumber
Definition: relpath.h:56
@ VISIBILITYMAP_FORKNUM
Definition: relpath.h:60
void smgrtruncate(SMgrRelation reln, ForkNumber *forknum, int nforks, BlockNumber *nblocks)
Definition: smgr.c:703
#define SMGR_TRUNCATE_VM
Definition: storage_xlog.h:41
#define XLOG_SMGR_TRUNCATE
Definition: storage_xlog.h:31
RelFileLocator rd_locator
Definition: rel.h:57
BlockNumber smgr_cached_nblocks[MAX_FORKNUM+1]
Definition: smgr.h:46
RelFileLocator rlocator
Definition: storage_xlog.h:49
BlockNumber blkno
Definition: storage_xlog.h:48
BlockNumber visibilitymap_prepare_truncate(Relation rel, BlockNumber nheapblocks)
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:474
void XLogRegisterData(const char *data, uint32 len)
Definition: xloginsert.c:364
void XLogBeginInsert(void)
Definition: xloginsert.c:149
#define XLR_SPECIAL_REL_UPDATE
Definition: xlogrecord.h:82

References AccessExclusiveLock, xl_smgr_truncate::blkno, BlockNumberIsValid(), check_relation_relkind(), xl_smgr_truncate::flags, InvalidBlockNumber, PG_GETARG_OID, PG_RETURN_VOID, RelationData::rd_locator, relation_close(), relation_open(), RelationGetSmgr(), RelationNeedsWAL, xl_smgr_truncate::rlocator, SMgrRelationData::smgr_cached_nblocks, SMGR_TRUNCATE_VM, smgrtruncate(), VISIBILITYMAP_FORKNUM, visibilitymap_prepare_truncate(), XLOG_SMGR_TRUNCATE, XLogBeginInsert(), XLogInsert(), XLogRegisterData(), and XLR_SPECIAL_REL_UPDATE.

◆ pg_visibility()

Datum pg_visibility ( PG_FUNCTION_ARGS  )

Definition at line 121 of file pg_visibility.c.

122 {
123  Oid relid = PG_GETARG_OID(0);
124  int64 blkno = PG_GETARG_INT64(1);
125  int32 mapbits;
126  Relation rel;
127  Buffer vmbuffer = InvalidBuffer;
128  Buffer buffer;
129  Page page;
130  TupleDesc tupdesc;
131  Datum values[3];
132  bool nulls[3] = {0};
133 
134  rel = relation_open(relid, AccessShareLock);
135 
136  /* Only some relkinds have a visibility map */
138 
139  if (blkno < 0 || blkno > MaxBlockNumber)
140  ereport(ERROR,
141  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
142  errmsg("invalid block number")));
143 
144  tupdesc = pg_visibility_tupdesc(false, true);
145 
146  mapbits = (int32) visibilitymap_get_status(rel, blkno, &vmbuffer);
147  if (vmbuffer != InvalidBuffer)
148  ReleaseBuffer(vmbuffer);
149  values[0] = BoolGetDatum((mapbits & VISIBILITYMAP_ALL_VISIBLE) != 0);
150  values[1] = BoolGetDatum((mapbits & VISIBILITYMAP_ALL_FROZEN) != 0);
151 
152  /* Here we have to explicitly check rel size ... */
153  if (blkno < RelationGetNumberOfBlocks(rel))
154  {
155  buffer = ReadBuffer(rel, blkno);
156  LockBuffer(buffer, BUFFER_LOCK_SHARE);
157 
158  page = BufferGetPage(buffer);
160 
161  UnlockReleaseBuffer(buffer);
162  }
163  else
164  {
165  /* As with the vismap, silently return 0 for pages past EOF */
166  values[2] = BoolGetDatum(false);
167  }
168 
170 
172 }
#define MaxBlockNumber
Definition: block.h:35
static Datum values[MAXATTR]
Definition: bootstrap.c:150
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition: bufmgr.c:746
#define PG_GETARG_INT64(n)
Definition: fmgr.h:283
#define PG_RETURN_DATUM(x)
Definition: fmgr.h:353
static Datum HeapTupleGetDatum(const HeapTupleData *tuple)
Definition: funcapi.h:230
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition: heaptuple.c:1116
static TupleDesc pg_visibility_tupdesc(bool include_blkno, bool include_pd)
uintptr_t Datum
Definition: postgres.h:64
static Datum BoolGetDatum(bool X)
Definition: postgres.h:102

References AccessShareLock, BoolGetDatum(), BUFFER_LOCK_SHARE, BufferGetPage(), check_relation_relkind(), ereport, errcode(), errmsg(), ERROR, heap_form_tuple(), HeapTupleGetDatum(), InvalidBuffer, LockBuffer(), MaxBlockNumber, PageIsAllVisible(), PG_GETARG_INT64, PG_GETARG_OID, PG_RETURN_DATUM, pg_visibility_tupdesc(), ReadBuffer(), relation_close(), relation_open(), RelationGetNumberOfBlocks, ReleaseBuffer(), UnlockReleaseBuffer(), values, VISIBILITYMAP_ALL_FROZEN, VISIBILITYMAP_ALL_VISIBLE, and visibilitymap_get_status().

◆ pg_visibility_map()

Datum pg_visibility_map ( PG_FUNCTION_ARGS  )

Definition at line 82 of file pg_visibility.c.

83 {
84  Oid relid = PG_GETARG_OID(0);
85  int64 blkno = PG_GETARG_INT64(1);
86  int32 mapbits;
87  Relation rel;
88  Buffer vmbuffer = InvalidBuffer;
89  TupleDesc tupdesc;
90  Datum values[2];
91  bool nulls[2] = {0};
92 
93  rel = relation_open(relid, AccessShareLock);
94 
95  /* Only some relkinds have a visibility map */
97 
98  if (blkno < 0 || blkno > MaxBlockNumber)
99  ereport(ERROR,
100  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
101  errmsg("invalid block number")));
102 
103  tupdesc = pg_visibility_tupdesc(false, false);
104 
105  mapbits = (int32) visibilitymap_get_status(rel, blkno, &vmbuffer);
106  if (vmbuffer != InvalidBuffer)
107  ReleaseBuffer(vmbuffer);
108  values[0] = BoolGetDatum((mapbits & VISIBILITYMAP_ALL_VISIBLE) != 0);
109  values[1] = BoolGetDatum((mapbits & VISIBILITYMAP_ALL_FROZEN) != 0);
110 
112 
114 }

References AccessShareLock, BoolGetDatum(), check_relation_relkind(), ereport, errcode(), errmsg(), ERROR, heap_form_tuple(), HeapTupleGetDatum(), InvalidBuffer, MaxBlockNumber, PG_GETARG_INT64, PG_GETARG_OID, PG_RETURN_DATUM, pg_visibility_tupdesc(), relation_close(), relation_open(), ReleaseBuffer(), values, VISIBILITYMAP_ALL_FROZEN, VISIBILITYMAP_ALL_VISIBLE, and visibilitymap_get_status().

◆ pg_visibility_map_rel()

Datum pg_visibility_map_rel ( PG_FUNCTION_ARGS  )

Definition at line 178 of file pg_visibility.c.

179 {
180  FuncCallContext *funcctx;
181  vbits *info;
182 
183  if (SRF_IS_FIRSTCALL())
184  {
185  Oid relid = PG_GETARG_OID(0);
186  MemoryContext oldcontext;
187 
188  funcctx = SRF_FIRSTCALL_INIT();
189  oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
190  funcctx->tuple_desc = pg_visibility_tupdesc(true, false);
191  /* collect_visibility_data will verify the relkind */
192  funcctx->user_fctx = collect_visibility_data(relid, false);
193  MemoryContextSwitchTo(oldcontext);
194  }
195 
196  funcctx = SRF_PERCALL_SETUP();
197  info = (vbits *) funcctx->user_fctx;
198 
199  if (info->next < info->count)
200  {
201  Datum values[3];
202  bool nulls[3] = {0};
203  HeapTuple tuple;
204 
205  values[0] = Int64GetDatum(info->next);
206  values[1] = BoolGetDatum((info->bits[info->next] & (1 << 0)) != 0);
207  values[2] = BoolGetDatum((info->bits[info->next] & (1 << 1)) != 0);
208  info->next++;
209 
210  tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
211  SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
212  }
213 
214  SRF_RETURN_DONE(funcctx);
215 }
Datum Int64GetDatum(int64 X)
Definition: fmgr.c:1807
static vbits * collect_visibility_data(Oid relid, bool include_pd)
TupleDesc tuple_desc
Definition: funcapi.h:112

References vbits::bits, BoolGetDatum(), collect_visibility_data(), vbits::count, heap_form_tuple(), HeapTupleGetDatum(), if(), Int64GetDatum(), MemoryContextSwitchTo(), FuncCallContext::multi_call_memory_ctx, vbits::next, PG_GETARG_OID, pg_visibility_tupdesc(), SRF_FIRSTCALL_INIT, SRF_IS_FIRSTCALL, SRF_PERCALL_SETUP, SRF_RETURN_DONE, SRF_RETURN_NEXT, FuncCallContext::tuple_desc, FuncCallContext::user_fctx, and values.

◆ pg_visibility_map_summary()

Datum pg_visibility_map_summary ( PG_FUNCTION_ARGS  )

Definition at line 267 of file pg_visibility.c.

268 {
269  Oid relid = PG_GETARG_OID(0);
270  Relation rel;
271  BlockNumber nblocks;
272  BlockNumber blkno;
273  Buffer vmbuffer = InvalidBuffer;
274  int64 all_visible = 0;
275  int64 all_frozen = 0;
276  TupleDesc tupdesc;
277  Datum values[2];
278  bool nulls[2] = {0};
279 
280  rel = relation_open(relid, AccessShareLock);
281 
282  /* Only some relkinds have a visibility map */
284 
285  nblocks = RelationGetNumberOfBlocks(rel);
286 
287  for (blkno = 0; blkno < nblocks; ++blkno)
288  {
289  int32 mapbits;
290 
291  /* Make sure we are interruptible. */
293 
294  /* Get map info. */
295  mapbits = (int32) visibilitymap_get_status(rel, blkno, &vmbuffer);
296  if ((mapbits & VISIBILITYMAP_ALL_VISIBLE) != 0)
297  ++all_visible;
298  if ((mapbits & VISIBILITYMAP_ALL_FROZEN) != 0)
299  ++all_frozen;
300  }
301 
302  /* Clean up. */
303  if (vmbuffer != InvalidBuffer)
304  ReleaseBuffer(vmbuffer);
306 
307  if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
308  elog(ERROR, "return type must be a row type");
309 
310  values[0] = Int64GetDatum(all_visible);
311  values[1] = Int64GetDatum(all_frozen);
312 
314 }
#define elog(elevel,...)
Definition: elog.h:225
TypeFuncClass get_call_result_type(FunctionCallInfo fcinfo, Oid *resultTypeId, TupleDesc *resultTupleDesc)
Definition: funcapi.c:276
@ TYPEFUNC_COMPOSITE
Definition: funcapi.h:149

References AccessShareLock, CHECK_FOR_INTERRUPTS, check_relation_relkind(), elog, ERROR, get_call_result_type(), heap_form_tuple(), HeapTupleGetDatum(), Int64GetDatum(), InvalidBuffer, PG_GETARG_OID, PG_RETURN_DATUM, relation_close(), relation_open(), RelationGetNumberOfBlocks, ReleaseBuffer(), TYPEFUNC_COMPOSITE, values, VISIBILITYMAP_ALL_FROZEN, VISIBILITYMAP_ALL_VISIBLE, and visibilitymap_get_status().

◆ pg_visibility_rel()

Datum pg_visibility_rel ( PG_FUNCTION_ARGS  )

Definition at line 222 of file pg_visibility.c.

223 {
224  FuncCallContext *funcctx;
225  vbits *info;
226 
227  if (SRF_IS_FIRSTCALL())
228  {
229  Oid relid = PG_GETARG_OID(0);
230  MemoryContext oldcontext;
231 
232  funcctx = SRF_FIRSTCALL_INIT();
233  oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
234  funcctx->tuple_desc = pg_visibility_tupdesc(true, true);
235  /* collect_visibility_data will verify the relkind */
236  funcctx->user_fctx = collect_visibility_data(relid, true);
237  MemoryContextSwitchTo(oldcontext);
238  }
239 
240  funcctx = SRF_PERCALL_SETUP();
241  info = (vbits *) funcctx->user_fctx;
242 
243  if (info->next < info->count)
244  {
245  Datum values[4];
246  bool nulls[4] = {0};
247  HeapTuple tuple;
248 
249  values[0] = Int64GetDatum(info->next);
250  values[1] = BoolGetDatum((info->bits[info->next] & (1 << 0)) != 0);
251  values[2] = BoolGetDatum((info->bits[info->next] & (1 << 1)) != 0);
252  values[3] = BoolGetDatum((info->bits[info->next] & (1 << 2)) != 0);
253  info->next++;
254 
255  tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
256  SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
257  }
258 
259  SRF_RETURN_DONE(funcctx);
260 }

References vbits::bits, BoolGetDatum(), collect_visibility_data(), vbits::count, heap_form_tuple(), HeapTupleGetDatum(), if(), Int64GetDatum(), MemoryContextSwitchTo(), FuncCallContext::multi_call_memory_ctx, vbits::next, PG_GETARG_OID, pg_visibility_tupdesc(), SRF_FIRSTCALL_INIT, SRF_IS_FIRSTCALL, SRF_PERCALL_SETUP, SRF_RETURN_DONE, SRF_RETURN_NEXT, FuncCallContext::tuple_desc, FuncCallContext::user_fctx, and values.

◆ pg_visibility_tupdesc()

static TupleDesc pg_visibility_tupdesc ( bool  include_blkno,
bool  include_pd 
)
static

Definition at line 456 of file pg_visibility.c.

457 {
458  TupleDesc tupdesc;
459  AttrNumber maxattr = 2;
460  AttrNumber a = 0;
461 
462  if (include_blkno)
463  ++maxattr;
464  if (include_pd)
465  ++maxattr;
466  tupdesc = CreateTemplateTupleDesc(maxattr);
467  if (include_blkno)
468  TupleDescInitEntry(tupdesc, ++a, "blkno", INT8OID, -1, 0);
469  TupleDescInitEntry(tupdesc, ++a, "all_visible", BOOLOID, -1, 0);
470  TupleDescInitEntry(tupdesc, ++a, "all_frozen", BOOLOID, -1, 0);
471  if (include_pd)
472  TupleDescInitEntry(tupdesc, ++a, "pd_all_visible", BOOLOID, -1, 0);
473  Assert(a == maxattr);
474 
475  return BlessTupleDesc(tupdesc);
476 }
int16 AttrNumber
Definition: attnum.h:21
TupleDesc BlessTupleDesc(TupleDesc tupdesc)
Definition: execTuples.c:2158
int a
Definition: isn.c:69
TupleDesc CreateTemplateTupleDesc(int natts)
Definition: tupdesc.c:67
void TupleDescInitEntry(TupleDesc desc, AttrNumber attributeNumber, const char *attributeName, Oid oidtypeid, int32 typmod, int attdim)
Definition: tupdesc.c:651

References a, Assert, BlessTupleDesc(), CreateTemplateTupleDesc(), and TupleDescInitEntry().

Referenced by pg_visibility(), pg_visibility_map(), pg_visibility_map_rel(), and pg_visibility_rel().

◆ record_corrupt_item()

static void record_corrupt_item ( corrupt_items items,
ItemPointer  tid 
)
static

Definition at line 874 of file pg_visibility.c.

875 {
876  /* enlarge output array if needed. */
877  if (items->next >= items->count)
878  {
879  items->count *= 2;
880  items->tids = repalloc(items->tids,
881  items->count * sizeof(ItemPointerData));
882  }
883  /* and add the new item */
884  items->tids[items->next++] = *tid;
885 }
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1541

References items, and repalloc().

Referenced by collect_corrupt_items().

◆ tuple_all_visible()

static bool tuple_all_visible ( HeapTuple  tup,
TransactionId  OldestXmin,
Buffer  buffer 
)
static

Definition at line 892 of file pg_visibility.c.

893 {
895  TransactionId xmin;
896 
897  state = HeapTupleSatisfiesVacuum(tup, OldestXmin, buffer);
898  if (state != HEAPTUPLE_LIVE)
899  return false; /* all-visible implies live */
900 
901  /*
902  * Neither lazy_scan_heap nor heap_page_is_all_visible will mark a page
903  * all-visible unless every tuple is hinted committed. However, those hint
904  * bits could be lost after a crash, so we can't be certain that they'll
905  * be set here. So just check the xmin.
906  */
907 
908  xmin = HeapTupleHeaderGetXmin(tup->t_data);
909  if (!TransactionIdPrecedes(xmin, OldestXmin))
910  return false; /* xmin not old enough for all to see */
911 
912  return true;
913 }
HTSV_Result
Definition: heapam.h:125
@ HEAPTUPLE_LIVE
Definition: heapam.h:127
HTSV_Result HeapTupleSatisfiesVacuum(HeapTuple htup, TransactionId OldestXmin, Buffer buffer)
#define HeapTupleHeaderGetXmin(tup)
Definition: htup_details.h:309
Definition: regguts.h:323

References HEAPTUPLE_LIVE, HeapTupleHeaderGetXmin, HeapTupleSatisfiesVacuum(), HeapTupleData::t_data, and TransactionIdPrecedes().

Referenced by collect_corrupt_items().

Variable Documentation

◆ PG_MODULE_MAGIC

PG_MODULE_MAGIC

Definition at line 29 of file pg_visibility.c.