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 "catalog/pg_type.h"
#include "catalog/storage_xlog.h"
#include "funcapi.h"
#include "miscadmin.h"
#include "storage/bufmgr.h"
#include "storage/procarray.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
 

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)
 

Variables

 PG_MODULE_MAGIC
 

Typedef Documentation

◆ corrupt_items

◆ vbits

Function Documentation

◆ check_relation_relkind()

static void check_relation_relkind ( Relation  rel)
static

Definition at line 772 of file pg_visibility.c.

References ereport, errcode(), errmsg(), ERROR, RelationData::rd_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().

773 {
774  if (rel->rd_rel->relkind != RELKIND_RELATION &&
775  rel->rd_rel->relkind != RELKIND_MATVIEW &&
776  rel->rd_rel->relkind != RELKIND_TOASTVALUE)
777  ereport(ERROR,
778  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
779  errmsg("\"%s\" is not a table, materialized view, or TOAST table",
780  RelationGetRelationName(rel))));
781 }
int errcode(int sqlerrcode)
Definition: elog.c:570
Form_pg_class rd_rel
Definition: rel.h:83
#define ERROR
Definition: elog.h:43
#define RelationGetRelationName(relation)
Definition: rel.h:450
#define ereport(elevel, rest)
Definition: elog.h:141
int errmsg(const char *fmt,...)
Definition: elog.c:784

◆ collect_corrupt_items()

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

Definition at line 549 of file pg_visibility.c.

References AccessShareLock, BAS_BULKREAD, BUFFER_LOCK_SHARE, BufferGetPage, CHECK_FOR_INTERRUPTS, check_relation_relkind(), corrupt_items::count, FirstOffsetNumber, GetAccessStrategy(), GetOldestXmin(), heap_tuple_needs_eventual_freeze(), InvalidBuffer, InvalidTransactionId, ItemIdGetLength, ItemIdIsDead, ItemIdIsRedirected, ItemIdIsUsed, ItemPointerSet, LockBuffer(), MAIN_FORKNUM, corrupt_items::next, OffsetNumberNext, OldestXmin, PageGetItem, PageGetItemId, PageGetMaxOffsetNumber, palloc(), palloc0(), PROCARRAY_FLAGS_VACUUM, RBM_NORMAL, ReadBufferExtended(), record_corrupt_item(), relation_close(), relation_open(), RelationGetNumberOfBlocks, ReleaseBuffer(), HeapTupleData::t_data, HeapTupleData::t_len, HeapTupleData::t_self, HeapTupleData::t_tableOid, corrupt_items::tids, TransactionIdPrecedes(), tuple_all_visible(), UnlockReleaseBuffer(), VM_ALL_FROZEN, and VM_ALL_VISIBLE.

Referenced by pg_check_frozen(), and pg_check_visible().

550 {
551  Relation rel;
552  BlockNumber nblocks;
553  corrupt_items *items;
554  BlockNumber blkno;
555  Buffer vmbuffer = InvalidBuffer;
558 
559  if (all_visible)
560  {
561  /* Don't pass rel; that will fail in recovery. */
562  OldestXmin = GetOldestXmin(NULL, PROCARRAY_FLAGS_VACUUM);
563  }
564 
565  rel = relation_open(relid, AccessShareLock);
566 
567  /* Only some relkinds have a visibility map */
569 
570  nblocks = RelationGetNumberOfBlocks(rel);
571 
572  /*
573  * Guess an initial array size. We don't expect many corrupted tuples, so
574  * start with a small array. This function uses the "next" field to track
575  * the next offset where we can store an item (which is the same thing as
576  * the number of items found so far) and the "count" field to track the
577  * number of entries allocated. We'll repurpose these fields before
578  * returning.
579  */
580  items = palloc0(sizeof(corrupt_items));
581  items->next = 0;
582  items->count = 64;
583  items->tids = palloc(items->count * sizeof(ItemPointerData));
584 
585  /* Loop over every block in the relation. */
586  for (blkno = 0; blkno < nblocks; ++blkno)
587  {
588  bool check_frozen = false;
589  bool check_visible = false;
590  Buffer buffer;
591  Page page;
592  OffsetNumber offnum,
593  maxoff;
594 
595  /* Make sure we are interruptible. */
597 
598  /* Use the visibility map to decide whether to check this page. */
599  if (all_frozen && VM_ALL_FROZEN(rel, blkno, &vmbuffer))
600  check_frozen = true;
601  if (all_visible && VM_ALL_VISIBLE(rel, blkno, &vmbuffer))
602  check_visible = true;
603  if (!check_visible && !check_frozen)
604  continue;
605 
606  /* Read and lock the page. */
607  buffer = ReadBufferExtended(rel, MAIN_FORKNUM, blkno, RBM_NORMAL,
608  bstrategy);
609  LockBuffer(buffer, BUFFER_LOCK_SHARE);
610 
611  page = BufferGetPage(buffer);
612  maxoff = PageGetMaxOffsetNumber(page);
613 
614  /*
615  * The visibility map bits might have changed while we were acquiring
616  * the page lock. Recheck to avoid returning spurious results.
617  */
618  if (check_frozen && !VM_ALL_FROZEN(rel, blkno, &vmbuffer))
619  check_frozen = false;
620  if (check_visible && !VM_ALL_VISIBLE(rel, blkno, &vmbuffer))
621  check_visible = false;
622  if (!check_visible && !check_frozen)
623  {
624  UnlockReleaseBuffer(buffer);
625  continue;
626  }
627 
628  /* Iterate over each tuple on the page. */
629  for (offnum = FirstOffsetNumber;
630  offnum <= maxoff;
631  offnum = OffsetNumberNext(offnum))
632  {
633  HeapTupleData tuple;
634  ItemId itemid;
635 
636  itemid = PageGetItemId(page, offnum);
637 
638  /* Unused or redirect line pointers are of no interest. */
639  if (!ItemIdIsUsed(itemid) || ItemIdIsRedirected(itemid))
640  continue;
641 
642  /* Dead line pointers are neither all-visible nor frozen. */
643  if (ItemIdIsDead(itemid))
644  {
645  ItemPointerSet(&(tuple.t_self), blkno, offnum);
646  record_corrupt_item(items, &tuple.t_self);
647  continue;
648  }
649 
650  /* Initialize a HeapTupleData structure for checks below. */
651  ItemPointerSet(&(tuple.t_self), blkno, offnum);
652  tuple.t_data = (HeapTupleHeader) PageGetItem(page, itemid);
653  tuple.t_len = ItemIdGetLength(itemid);
654  tuple.t_tableOid = relid;
655 
656  /*
657  * If we're checking whether the page is all-visible, we expect
658  * the tuple to be all-visible.
659  */
660  if (check_visible &&
661  !tuple_all_visible(&tuple, OldestXmin, buffer))
662  {
663  TransactionId RecomputedOldestXmin;
664 
665  /*
666  * Time has passed since we computed OldestXmin, so it's
667  * possible that this tuple is all-visible in reality even
668  * though it doesn't appear so based on our
669  * previously-computed value. Let's compute a new value so we
670  * can be certain whether there is a problem.
671  *
672  * From a concurrency point of view, it sort of sucks to
673  * retake ProcArrayLock here while we're holding the buffer
674  * exclusively locked, but it should be safe against
675  * deadlocks, because surely GetOldestXmin() should never take
676  * a buffer lock. And this shouldn't happen often, so it's
677  * worth being careful so as to avoid false positives.
678  */
679  RecomputedOldestXmin = GetOldestXmin(NULL, PROCARRAY_FLAGS_VACUUM);
680 
681  if (!TransactionIdPrecedes(OldestXmin, RecomputedOldestXmin))
682  record_corrupt_item(items, &tuple.t_self);
683  else
684  {
685  OldestXmin = RecomputedOldestXmin;
686  if (!tuple_all_visible(&tuple, OldestXmin, buffer))
687  record_corrupt_item(items, &tuple.t_self);
688  }
689  }
690 
691  /*
692  * If we're checking whether the page is all-frozen, we expect the
693  * tuple to be in a state where it will never need freezing.
694  */
695  if (check_frozen)
696  {
698  record_corrupt_item(items, &tuple.t_self);
699  }
700  }
701 
702  UnlockReleaseBuffer(buffer);
703  }
704 
705  /* Clean up. */
706  if (vmbuffer != InvalidBuffer)
707  ReleaseBuffer(vmbuffer);
709 
710  /*
711  * Before returning, repurpose the fields to match caller's expectations.
712  * next is now the next item that should be read (rather than written) and
713  * count is now the number of items we wrote (rather than the number we
714  * allocated).
715  */
716  items->count = items->next;
717  items->next = 0;
718 
719  return items;
720 }
BufferAccessStrategy GetAccessStrategy(BufferAccessStrategyType btype)
Definition: freelist.c:542
#define ItemIdIsRedirected(itemId)
Definition: itemid.h:106
uint32 TransactionId
Definition: c.h:507
static void record_corrupt_item(corrupt_items *items, ItemPointer tid)
HeapTupleHeaderData * HeapTupleHeader
Definition: htup.h:23
Buffer ReadBufferExtended(Relation reln, ForkNumber forkNum, BlockNumber blockNum, ReadBufferMode mode, BufferAccessStrategy strategy)
Definition: bufmgr.c:642
#define ItemIdIsUsed(itemId)
Definition: itemid.h:92
#define VM_ALL_FROZEN(r, b, v)
Definition: visibilitymap.h:34
#define AccessShareLock
Definition: lockdefs.h:36
#define InvalidBuffer
Definition: buf.h:25
uint32 BlockNumber
Definition: block.h:31
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3353
#define PROCARRAY_FLAGS_VACUUM
Definition: procarray.h:52
#define ItemIdIsDead(itemId)
Definition: itemid.h:113
#define PageGetMaxOffsetNumber(page)
Definition: bufpage.h:357
BlockNumber count
Definition: pg_visibility.c:38
uint16 OffsetNumber
Definition: off.h:24
HeapTupleHeader t_data
Definition: htup.h:68
bool heap_tuple_needs_eventual_freeze(HeapTupleHeader tuple)
Definition: heapam.c:6762
#define ItemIdGetLength(itemId)
Definition: itemid.h:59
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3376
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:48
ItemPointerData t_self
Definition: htup.h:65
uint32 t_len
Definition: htup.h:64
#define FirstOffsetNumber
Definition: off.h:27
#define InvalidTransactionId
Definition: transam.h:31
static TransactionId OldestXmin
Definition: vacuumlazy.c:145
static void check_relation_relkind(Relation rel)
Oid t_tableOid
Definition: htup.h:66
#define BufferGetPage(buffer)
Definition: bufmgr.h:159
static bool tuple_all_visible(HeapTuple tup, TransactionId OldestXmin, Buffer buffer)
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition: transam.c:300
#define PageGetItemId(page, offsetNumber)
Definition: bufpage.h:235
void * palloc0(Size size)
Definition: mcxt.c:955
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3590
#define RelationGetNumberOfBlocks(reln)
Definition: bufmgr.h:198
TransactionId GetOldestXmin(Relation rel, int flags)
Definition: procarray.c:1304
ItemPointer tids
Definition: pg_visibility.c:39
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: relation.c:206
#define VM_ALL_VISIBLE(r, b, v)
Definition: visibilitymap.h:32
#define OffsetNumberNext(offsetNumber)
Definition: off.h:52
BlockNumber next
Definition: pg_visibility.c:37
void * palloc(Size size)
Definition: mcxt.c:924
#define BUFFER_LOCK_SHARE
Definition: bufmgr.h:87
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:99
int Buffer
Definition: buf.h:23
#define PageGetItem(page, itemId)
Definition: bufpage.h:340
Pointer Page
Definition: bufpage.h:78
#define ItemPointerSet(pointer, blockNumber, offNum)
Definition: itemptr.h:127

◆ collect_visibility_data()

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

Definition at line 471 of file pg_visibility.c.

References AccessShareLock, BAS_BULKREAD, vbits::bits, BUFFER_LOCK_SHARE, BufferGetPage, CHECK_FOR_INTERRUPTS, check_relation_relkind(), vbits::count, GetAccessStrategy(), InvalidBuffer, LockBuffer(), MAIN_FORKNUM, vbits::next, offsetof, PageIsAllVisible, palloc0(), RBM_NORMAL, ReadBufferExtended(), 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().

472 {
473  Relation rel;
474  BlockNumber nblocks;
475  vbits *info;
476  BlockNumber blkno;
477  Buffer vmbuffer = InvalidBuffer;
479 
480  rel = relation_open(relid, AccessShareLock);
481 
482  /* Only some relkinds have a visibility map */
484 
485  nblocks = RelationGetNumberOfBlocks(rel);
486  info = palloc0(offsetof(vbits, bits) + nblocks);
487  info->next = 0;
488  info->count = nblocks;
489 
490  for (blkno = 0; blkno < nblocks; ++blkno)
491  {
492  int32 mapbits;
493 
494  /* Make sure we are interruptible. */
496 
497  /* Get map info. */
498  mapbits = (int32) visibilitymap_get_status(rel, blkno, &vmbuffer);
499  if ((mapbits & VISIBILITYMAP_ALL_VISIBLE) != 0)
500  info->bits[blkno] |= (1 << 0);
501  if ((mapbits & VISIBILITYMAP_ALL_FROZEN) != 0)
502  info->bits[blkno] |= (1 << 1);
503 
504  /*
505  * Page-level data requires reading every block, so only get it if the
506  * caller needs it. Use a buffer access strategy, too, to prevent
507  * cache-trashing.
508  */
509  if (include_pd)
510  {
511  Buffer buffer;
512  Page page;
513 
514  buffer = ReadBufferExtended(rel, MAIN_FORKNUM, blkno, RBM_NORMAL,
515  bstrategy);
516  LockBuffer(buffer, BUFFER_LOCK_SHARE);
517 
518  page = BufferGetPage(buffer);
519  if (PageIsAllVisible(page))
520  info->bits[blkno] |= (1 << 2);
521 
522  UnlockReleaseBuffer(buffer);
523  }
524  }
525 
526  /* Clean up. */
527  if (vmbuffer != InvalidBuffer)
528  ReleaseBuffer(vmbuffer);
530 
531  return info;
532 }
BufferAccessStrategy GetAccessStrategy(BufferAccessStrategyType btype)
Definition: freelist.c:542
#define PageIsAllVisible(page)
Definition: bufpage.h:385
#define VISIBILITYMAP_ALL_FROZEN
Definition: visibilitymap.h:27
Buffer ReadBufferExtended(Relation reln, ForkNumber forkNum, BlockNumber blockNum, ReadBufferMode mode, BufferAccessStrategy strategy)
Definition: bufmgr.c:642
#define AccessShareLock
Definition: lockdefs.h:36
#define InvalidBuffer
Definition: buf.h:25
uint32 BlockNumber
Definition: block.h:31
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3353
signed int int32
Definition: c.h:346
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3376
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:48
uint8 bits[FLEXIBLE_ARRAY_MEMBER]
Definition: pg_visibility.c:32
static void check_relation_relkind(Relation rel)
#define BufferGetPage(buffer)
Definition: bufmgr.h:159
void * palloc0(Size size)
Definition: mcxt.c:955
BlockNumber count
Definition: pg_visibility.c:31
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3590
#define RelationGetNumberOfBlocks(reln)
Definition: bufmgr.h:198
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: relation.c:206
#define VISIBILITYMAP_ALL_VISIBLE
Definition: visibilitymap.h:26
uint8 visibilitymap_get_status(Relation rel, BlockNumber heapBlk, Buffer *buf)
#define BUFFER_LOCK_SHARE
Definition: bufmgr.h:87
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:99
int Buffer
Definition: buf.h:23
BlockNumber next
Definition: pg_visibility.c:30
#define offsetof(type, field)
Definition: c.h:655
Pointer Page
Definition: bufpage.h:78

◆ pg_check_frozen()

Datum pg_check_frozen ( PG_FUNCTION_ARGS  )

Definition at line 315 of file pg_visibility.c.

References collect_corrupt_items(), corrupt_items::count, MemoryContextSwitchTo(), FuncCallContext::multi_call_memory_ctx, corrupt_items::next, PG_GETARG_OID, PointerGetDatum, SRF_FIRSTCALL_INIT, SRF_IS_FIRSTCALL, SRF_PERCALL_SETUP, SRF_RETURN_DONE, SRF_RETURN_NEXT, corrupt_items::tids, and FuncCallContext::user_fctx.

316 {
317  FuncCallContext *funcctx;
318  corrupt_items *items;
319 
320  if (SRF_IS_FIRSTCALL())
321  {
322  Oid relid = PG_GETARG_OID(0);
323  MemoryContext oldcontext;
324 
325  funcctx = SRF_FIRSTCALL_INIT();
326  oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
327  /* collect_corrupt_items will verify the relkind */
328  funcctx->user_fctx = collect_corrupt_items(relid, false, true);
329  MemoryContextSwitchTo(oldcontext);
330  }
331 
332  funcctx = SRF_PERCALL_SETUP();
333  items = (corrupt_items *) funcctx->user_fctx;
334 
335  if (items->next < items->count)
336  SRF_RETURN_NEXT(funcctx, PointerGetDatum(&items->tids[items->next++]));
337 
338  SRF_RETURN_DONE(funcctx);
339 }
static corrupt_items * collect_corrupt_items(Oid relid, bool all_visible, bool all_frozen)
#define SRF_IS_FIRSTCALL()
Definition: funcapi.h:283
#define PointerGetDatum(X)
Definition: postgres.h:556
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
unsigned int Oid
Definition: postgres_ext.h:31
BlockNumber count
Definition: pg_visibility.c:38
#define SRF_PERCALL_SETUP()
Definition: funcapi.h:287
#define SRF_RETURN_NEXT(_funcctx, _result)
Definition: funcapi.h:289
#define PG_GETARG_OID(n)
Definition: fmgr.h:270
ItemPointer tids
Definition: pg_visibility.c:39
MemoryContext multi_call_memory_ctx
Definition: funcapi.h:102
BlockNumber next
Definition: pg_visibility.c:37
void * user_fctx
Definition: funcapi.h:83
#define SRF_RETURN_DONE(_funcctx)
Definition: funcapi.h:307
#define SRF_FIRSTCALL_INIT()
Definition: funcapi.h:285

◆ pg_check_visible()

Datum pg_check_visible ( PG_FUNCTION_ARGS  )

Definition at line 347 of file pg_visibility.c.

References collect_corrupt_items(), corrupt_items::count, MemoryContextSwitchTo(), FuncCallContext::multi_call_memory_ctx, corrupt_items::next, PG_GETARG_OID, PointerGetDatum, SRF_FIRSTCALL_INIT, SRF_IS_FIRSTCALL, SRF_PERCALL_SETUP, SRF_RETURN_DONE, SRF_RETURN_NEXT, corrupt_items::tids, and FuncCallContext::user_fctx.

348 {
349  FuncCallContext *funcctx;
350  corrupt_items *items;
351 
352  if (SRF_IS_FIRSTCALL())
353  {
354  Oid relid = PG_GETARG_OID(0);
355  MemoryContext oldcontext;
356 
357  funcctx = SRF_FIRSTCALL_INIT();
358  oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
359  /* collect_corrupt_items will verify the relkind */
360  funcctx->user_fctx = collect_corrupt_items(relid, true, false);
361  MemoryContextSwitchTo(oldcontext);
362  }
363 
364  funcctx = SRF_PERCALL_SETUP();
365  items = (corrupt_items *) funcctx->user_fctx;
366 
367  if (items->next < items->count)
368  SRF_RETURN_NEXT(funcctx, PointerGetDatum(&items->tids[items->next++]));
369 
370  SRF_RETURN_DONE(funcctx);
371 }
static corrupt_items * collect_corrupt_items(Oid relid, bool all_visible, bool all_frozen)
#define SRF_IS_FIRSTCALL()
Definition: funcapi.h:283
#define PointerGetDatum(X)
Definition: postgres.h:556
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
unsigned int Oid
Definition: postgres_ext.h:31
BlockNumber count
Definition: pg_visibility.c:38
#define SRF_PERCALL_SETUP()
Definition: funcapi.h:287
#define SRF_RETURN_NEXT(_funcctx, _result)
Definition: funcapi.h:289
#define PG_GETARG_OID(n)
Definition: fmgr.h:270
ItemPointer tids
Definition: pg_visibility.c:39
MemoryContext multi_call_memory_ctx
Definition: funcapi.h:102
BlockNumber next
Definition: pg_visibility.c:37
void * user_fctx
Definition: funcapi.h:83
#define SRF_RETURN_DONE(_funcctx)
Definition: funcapi.h:307
#define SRF_FIRSTCALL_INIT()
Definition: funcapi.h:285

◆ PG_FUNCTION_INFO_V1() [1/8]

PG_FUNCTION_INFO_V1 ( pg_visibility_map  )

◆ PG_FUNCTION_INFO_V1() [2/8]

PG_FUNCTION_INFO_V1 ( pg_visibility_map_rel  )

◆ PG_FUNCTION_INFO_V1() [3/8]

PG_FUNCTION_INFO_V1 ( pg_visibility  )

◆ PG_FUNCTION_INFO_V1() [4/8]

PG_FUNCTION_INFO_V1 ( pg_visibility_rel  )

◆ PG_FUNCTION_INFO_V1() [5/8]

PG_FUNCTION_INFO_V1 ( pg_visibility_map_summary  )

◆ PG_FUNCTION_INFO_V1() [6/8]

PG_FUNCTION_INFO_V1 ( pg_check_frozen  )

◆ PG_FUNCTION_INFO_V1() [7/8]

PG_FUNCTION_INFO_V1 ( pg_check_visible  )

◆ PG_FUNCTION_INFO_V1() [8/8]

PG_FUNCTION_INFO_V1 ( pg_truncate_visibility_map  )

◆ pg_truncate_visibility_map()

Datum pg_truncate_visibility_map ( PG_FUNCTION_ARGS  )

Definition at line 382 of file pg_visibility.c.

References AccessExclusiveLock, xl_smgr_truncate::blkno, check_relation_relkind(), xl_smgr_truncate::flags, InvalidBlockNumber, PG_GETARG_OID, PG_RETURN_VOID, RelationData::rd_node, RelationData::rd_smgr, relation_close(), relation_open(), RelationNeedsWAL, RelationOpenSmgr, xl_smgr_truncate::rnode, SMGR_TRUNCATE_VM, SMgrRelationData::smgr_vm_nblocks, visibilitymap_truncate(), XLOG_SMGR_TRUNCATE, XLogBeginInsert(), XLogInsert(), XLogRegisterData(), and XLR_SPECIAL_REL_UPDATE.

383 {
384  Oid relid = PG_GETARG_OID(0);
385  Relation rel;
386 
387  rel = relation_open(relid, AccessExclusiveLock);
388 
389  /* Only some relkinds have a visibility map */
391 
392  RelationOpenSmgr(rel);
394 
395  visibilitymap_truncate(rel, 0);
396 
397  if (RelationNeedsWAL(rel))
398  {
399  xl_smgr_truncate xlrec;
400 
401  xlrec.blkno = 0;
402  xlrec.rnode = rel->rd_node;
403  xlrec.flags = SMGR_TRUNCATE_VM;
404 
405  XLogBeginInsert();
406  XLogRegisterData((char *) &xlrec, sizeof(xlrec));
407 
409  }
410 
411  /*
412  * Release the lock right away, not at commit time.
413  *
414  * It would be a problem to release the lock prior to commit if this
415  * truncate operation sends any transactional invalidation messages. Other
416  * backends would potentially be able to lock the relation without
417  * processing them in the window of time between when we release the lock
418  * here and when we sent the messages at our eventual commit. However,
419  * we're currently only sending a non-transactional smgr invalidation,
420  * which will have been posted to shared memory immediately from within
421  * visibilitymap_truncate. Therefore, there should be no race here.
422  *
423  * The reason why it's desirable to release the lock early here is because
424  * of the possibility that someone will need to use this to blow away many
425  * visibility map forks at once. If we can't release the lock until
426  * commit time, the transaction doing this will accumulate
427  * AccessExclusiveLocks on all of those relations at the same time, which
428  * is undesirable. However, if this turns out to be unsafe we may have no
429  * choice...
430  */
432 
433  /* Nothing to return. */
434  PG_RETURN_VOID();
435 }
BlockNumber smgr_vm_nblocks
Definition: smgr.h:56
#define XLR_SPECIAL_REL_UPDATE
Definition: xlogrecord.h:71
struct SMgrRelationData * rd_smgr
Definition: rel.h:56
RelFileNode rnode
Definition: storage_xlog.h:49
unsigned int Oid
Definition: postgres_ext.h:31
#define RelationOpenSmgr(relation)
Definition: rel.h:473
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:48
#define PG_GETARG_OID(n)
Definition: fmgr.h:270
static void check_relation_relkind(Relation rel)
#define XLOG_SMGR_TRUNCATE
Definition: storage_xlog.h:31
void XLogRegisterData(char *data, int len)
Definition: xloginsert.c:323
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:415
#define PG_RETURN_VOID()
Definition: fmgr.h:339
RelFileNode rd_node
Definition: rel.h:54
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: relation.c:206
void visibilitymap_truncate(Relation rel, BlockNumber nheapblocks)
#define InvalidBlockNumber
Definition: block.h:33
#define SMGR_TRUNCATE_VM
Definition: storage_xlog.h:41
#define RelationNeedsWAL(relation)
Definition: rel.h:518
#define AccessExclusiveLock
Definition: lockdefs.h:45
BlockNumber blkno
Definition: storage_xlog.h:48
void XLogBeginInsert(void)
Definition: xloginsert.c:120

◆ pg_visibility()

Datum pg_visibility ( PG_FUNCTION_ARGS  )

Definition at line 108 of file pg_visibility.c.

References AccessShareLock, BoolGetDatum, BUFFER_LOCK_SHARE, BufferGetPage, check_relation_relkind(), ereport, errcode(), errmsg(), ERROR, heap_form_tuple(), HeapTupleGetDatum, InvalidBuffer, LockBuffer(), MaxBlockNumber, MemSet, 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().

109 {
110  Oid relid = PG_GETARG_OID(0);
111  int64 blkno = PG_GETARG_INT64(1);
112  int32 mapbits;
113  Relation rel;
114  Buffer vmbuffer = InvalidBuffer;
115  Buffer buffer;
116  Page page;
117  TupleDesc tupdesc;
118  Datum values[3];
119  bool nulls[3];
120 
121  rel = relation_open(relid, AccessShareLock);
122 
123  /* Only some relkinds have a visibility map */
125 
126  if (blkno < 0 || blkno > MaxBlockNumber)
127  ereport(ERROR,
128  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
129  errmsg("invalid block number")));
130 
131  tupdesc = pg_visibility_tupdesc(false, true);
132  MemSet(nulls, 0, sizeof(nulls));
133 
134  mapbits = (int32) visibilitymap_get_status(rel, blkno, &vmbuffer);
135  if (vmbuffer != InvalidBuffer)
136  ReleaseBuffer(vmbuffer);
137  values[0] = BoolGetDatum((mapbits & VISIBILITYMAP_ALL_VISIBLE) != 0);
138  values[1] = BoolGetDatum((mapbits & VISIBILITYMAP_ALL_FROZEN) != 0);
139 
140  /* Here we have to explicitly check rel size ... */
141  if (blkno < RelationGetNumberOfBlocks(rel))
142  {
143  buffer = ReadBuffer(rel, blkno);
144  LockBuffer(buffer, BUFFER_LOCK_SHARE);
145 
146  page = BufferGetPage(buffer);
147  values[2] = BoolGetDatum(PageIsAllVisible(page));
148 
149  UnlockReleaseBuffer(buffer);
150  }
151  else
152  {
153  /* As with the vismap, silently return 0 for pages past EOF */
154  values[2] = BoolGetDatum(false);
155  }
156 
158 
159  PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
160 }
#define PageIsAllVisible(page)
Definition: bufpage.h:385
#define VISIBILITYMAP_ALL_FROZEN
Definition: visibilitymap.h:27
#define AccessShareLock
Definition: lockdefs.h:36
#define InvalidBuffer
Definition: buf.h:25
int errcode(int sqlerrcode)
Definition: elog.c:570
#define MemSet(start, val, len)
Definition: c.h:955
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3353
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:1020
unsigned int Oid
Definition: postgres_ext.h:31
static TupleDesc pg_visibility_tupdesc(bool include_blkno, bool include_pd)
signed int int32
Definition: c.h:346
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3376
#define ERROR
Definition: elog.h:43
#define MaxBlockNumber
Definition: block.h:35
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:48
#define PG_GETARG_OID(n)
Definition: fmgr.h:270
static void check_relation_relkind(Relation rel)
#define BufferGetPage(buffer)
Definition: bufmgr.h:159
#define ereport(elevel, rest)
Definition: elog.h:141
uintptr_t Datum
Definition: postgres.h:367
#define PG_RETURN_DATUM(x)
Definition: fmgr.h:343
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3590
#define RelationGetNumberOfBlocks(reln)
Definition: bufmgr.h:198
#define BoolGetDatum(X)
Definition: postgres.h:402
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: relation.c:206
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition: bufmgr.c:596
#define HeapTupleGetDatum(tuple)
Definition: funcapi.h:221
#define VISIBILITYMAP_ALL_VISIBLE
Definition: visibilitymap.h:26
static Datum values[MAXATTR]
Definition: bootstrap.c:167
int errmsg(const char *fmt,...)
Definition: elog.c:784
uint8 visibilitymap_get_status(Relation rel, BlockNumber heapBlk, Buffer *buf)
#define BUFFER_LOCK_SHARE
Definition: bufmgr.h:87
#define PG_GETARG_INT64(n)
Definition: fmgr.h:277
int Buffer
Definition: buf.h:23
Pointer Page
Definition: bufpage.h:78

◆ pg_visibility_map()

Datum pg_visibility_map ( PG_FUNCTION_ARGS  )

Definition at line 68 of file pg_visibility.c.

References AccessShareLock, BoolGetDatum, check_relation_relkind(), ereport, errcode(), errmsg(), ERROR, heap_form_tuple(), HeapTupleGetDatum, InvalidBuffer, MaxBlockNumber, MemSet, 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().

69 {
70  Oid relid = PG_GETARG_OID(0);
71  int64 blkno = PG_GETARG_INT64(1);
72  int32 mapbits;
73  Relation rel;
74  Buffer vmbuffer = InvalidBuffer;
75  TupleDesc tupdesc;
76  Datum values[2];
77  bool nulls[2];
78 
79  rel = relation_open(relid, AccessShareLock);
80 
81  /* Only some relkinds have a visibility map */
83 
84  if (blkno < 0 || blkno > MaxBlockNumber)
85  ereport(ERROR,
86  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
87  errmsg("invalid block number")));
88 
89  tupdesc = pg_visibility_tupdesc(false, false);
90  MemSet(nulls, 0, sizeof(nulls));
91 
92  mapbits = (int32) visibilitymap_get_status(rel, blkno, &vmbuffer);
93  if (vmbuffer != InvalidBuffer)
94  ReleaseBuffer(vmbuffer);
95  values[0] = BoolGetDatum((mapbits & VISIBILITYMAP_ALL_VISIBLE) != 0);
96  values[1] = BoolGetDatum((mapbits & VISIBILITYMAP_ALL_FROZEN) != 0);
97 
99 
100  PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
101 }
#define VISIBILITYMAP_ALL_FROZEN
Definition: visibilitymap.h:27
#define AccessShareLock
Definition: lockdefs.h:36
#define InvalidBuffer
Definition: buf.h:25
int errcode(int sqlerrcode)
Definition: elog.c:570
#define MemSet(start, val, len)
Definition: c.h:955
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3353
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:1020
unsigned int Oid
Definition: postgres_ext.h:31
static TupleDesc pg_visibility_tupdesc(bool include_blkno, bool include_pd)
signed int int32
Definition: c.h:346
#define ERROR
Definition: elog.h:43
#define MaxBlockNumber
Definition: block.h:35
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:48
#define PG_GETARG_OID(n)
Definition: fmgr.h:270
static void check_relation_relkind(Relation rel)
#define ereport(elevel, rest)
Definition: elog.h:141
uintptr_t Datum
Definition: postgres.h:367
#define PG_RETURN_DATUM(x)
Definition: fmgr.h:343
#define BoolGetDatum(X)
Definition: postgres.h:402
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: relation.c:206
#define HeapTupleGetDatum(tuple)
Definition: funcapi.h:221
#define VISIBILITYMAP_ALL_VISIBLE
Definition: visibilitymap.h:26
static Datum values[MAXATTR]
Definition: bootstrap.c:167
int errmsg(const char *fmt,...)
Definition: elog.c:784
uint8 visibilitymap_get_status(Relation rel, BlockNumber heapBlk, Buffer *buf)
#define PG_GETARG_INT64(n)
Definition: fmgr.h:277
int Buffer
Definition: buf.h:23

◆ pg_visibility_map_rel()

Datum pg_visibility_map_rel ( PG_FUNCTION_ARGS  )

Definition at line 166 of file pg_visibility.c.

References vbits::bits, BoolGetDatum, collect_visibility_data(), vbits::count, heap_form_tuple(), HeapTupleGetDatum, Int64GetDatum(), MemoryContextSwitchTo(), MemSet, 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.

167 {
168  FuncCallContext *funcctx;
169  vbits *info;
170 
171  if (SRF_IS_FIRSTCALL())
172  {
173  Oid relid = PG_GETARG_OID(0);
174  MemoryContext oldcontext;
175 
176  funcctx = SRF_FIRSTCALL_INIT();
177  oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
178  funcctx->tuple_desc = pg_visibility_tupdesc(true, false);
179  /* collect_visibility_data will verify the relkind */
180  funcctx->user_fctx = collect_visibility_data(relid, false);
181  MemoryContextSwitchTo(oldcontext);
182  }
183 
184  funcctx = SRF_PERCALL_SETUP();
185  info = (vbits *) funcctx->user_fctx;
186 
187  if (info->next < info->count)
188  {
189  Datum values[3];
190  bool nulls[3];
191  HeapTuple tuple;
192 
193  MemSet(nulls, 0, sizeof(nulls));
194  values[0] = Int64GetDatum(info->next);
195  values[1] = BoolGetDatum((info->bits[info->next] & (1 << 0)) != 0);
196  values[2] = BoolGetDatum((info->bits[info->next] & (1 << 1)) != 0);
197  info->next++;
198 
199  tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
200  SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
201  }
202 
203  SRF_RETURN_DONE(funcctx);
204 }
#define SRF_IS_FIRSTCALL()
Definition: funcapi.h:283
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
#define MemSet(start, val, len)
Definition: c.h:955
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:1020
unsigned int Oid
Definition: postgres_ext.h:31
#define SRF_PERCALL_SETUP()
Definition: funcapi.h:287
static TupleDesc pg_visibility_tupdesc(bool include_blkno, bool include_pd)
TupleDesc tuple_desc
Definition: funcapi.h:113
#define SRF_RETURN_NEXT(_funcctx, _result)
Definition: funcapi.h:289
#define PG_GETARG_OID(n)
Definition: fmgr.h:270
uint8 bits[FLEXIBLE_ARRAY_MEMBER]
Definition: pg_visibility.c:32
Datum Int64GetDatum(int64 X)
Definition: fmgr.c:1699
BlockNumber count
Definition: pg_visibility.c:31
uintptr_t Datum
Definition: postgres.h:367
#define BoolGetDatum(X)
Definition: postgres.h:402
MemoryContext multi_call_memory_ctx
Definition: funcapi.h:102
#define HeapTupleGetDatum(tuple)
Definition: funcapi.h:221
static Datum values[MAXATTR]
Definition: bootstrap.c:167
void * user_fctx
Definition: funcapi.h:83
BlockNumber next
Definition: pg_visibility.c:30
static vbits * collect_visibility_data(Oid relid, bool include_pd)
#define SRF_RETURN_DONE(_funcctx)
Definition: funcapi.h:307
#define SRF_FIRSTCALL_INIT()
Definition: funcapi.h:285

◆ pg_visibility_map_summary()

Datum pg_visibility_map_summary ( PG_FUNCTION_ARGS  )

Definition at line 257 of file pg_visibility.c.

References AccessShareLock, BlessTupleDesc(), CHECK_FOR_INTERRUPTS, check_relation_relkind(), CreateTemplateTupleDesc(), heap_form_tuple(), HeapTupleGetDatum, Int64GetDatum(), InvalidBuffer, MemSet, PG_GETARG_OID, PG_RETURN_DATUM, relation_close(), relation_open(), RelationGetNumberOfBlocks, ReleaseBuffer(), TupleDescInitEntry(), values, VISIBILITYMAP_ALL_FROZEN, VISIBILITYMAP_ALL_VISIBLE, and visibilitymap_get_status().

258 {
259  Oid relid = PG_GETARG_OID(0);
260  Relation rel;
261  BlockNumber nblocks;
262  BlockNumber blkno;
263  Buffer vmbuffer = InvalidBuffer;
264  int64 all_visible = 0;
265  int64 all_frozen = 0;
266  TupleDesc tupdesc;
267  Datum values[2];
268  bool nulls[2];
269 
270  rel = relation_open(relid, AccessShareLock);
271 
272  /* Only some relkinds have a visibility map */
274 
275  nblocks = RelationGetNumberOfBlocks(rel);
276 
277  for (blkno = 0; blkno < nblocks; ++blkno)
278  {
279  int32 mapbits;
280 
281  /* Make sure we are interruptible. */
283 
284  /* Get map info. */
285  mapbits = (int32) visibilitymap_get_status(rel, blkno, &vmbuffer);
286  if ((mapbits & VISIBILITYMAP_ALL_VISIBLE) != 0)
287  ++all_visible;
288  if ((mapbits & VISIBILITYMAP_ALL_FROZEN) != 0)
289  ++all_frozen;
290  }
291 
292  /* Clean up. */
293  if (vmbuffer != InvalidBuffer)
294  ReleaseBuffer(vmbuffer);
296 
297  tupdesc = CreateTemplateTupleDesc(2);
298  TupleDescInitEntry(tupdesc, (AttrNumber) 1, "all_visible", INT8OID, -1, 0);
299  TupleDescInitEntry(tupdesc, (AttrNumber) 2, "all_frozen", INT8OID, -1, 0);
300  tupdesc = BlessTupleDesc(tupdesc);
301 
302  MemSet(nulls, 0, sizeof(nulls));
303  values[0] = Int64GetDatum(all_visible);
304  values[1] = Int64GetDatum(all_frozen);
305 
306  PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
307 }
TupleDesc CreateTemplateTupleDesc(int natts)
Definition: tupdesc.c:44
#define VISIBILITYMAP_ALL_FROZEN
Definition: visibilitymap.h:27
#define AccessShareLock
Definition: lockdefs.h:36
#define InvalidBuffer
Definition: buf.h:25
#define MemSet(start, val, len)
Definition: c.h:955
uint32 BlockNumber
Definition: block.h:31
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3353
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:1020
unsigned int Oid
Definition: postgres_ext.h:31
signed int int32
Definition: c.h:346
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: relation.c:48
TupleDesc BlessTupleDesc(TupleDesc tupdesc)
Definition: execTuples.c:2048
#define PG_GETARG_OID(n)
Definition: fmgr.h:270
static void check_relation_relkind(Relation rel)
Datum Int64GetDatum(int64 X)
Definition: fmgr.c:1699
void TupleDescInitEntry(TupleDesc desc, AttrNumber attributeNumber, const char *attributeName, Oid oidtypeid, int32 typmod, int attdim)
Definition: tupdesc.c:603
uintptr_t Datum
Definition: postgres.h:367
#define PG_RETURN_DATUM(x)
Definition: fmgr.h:343
#define RelationGetNumberOfBlocks(reln)
Definition: bufmgr.h:198
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: relation.c:206
#define HeapTupleGetDatum(tuple)
Definition: funcapi.h:221
#define VISIBILITYMAP_ALL_VISIBLE
Definition: visibilitymap.h:26
static Datum values[MAXATTR]
Definition: bootstrap.c:167
uint8 visibilitymap_get_status(Relation rel, BlockNumber heapBlk, Buffer *buf)
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:99
int Buffer
Definition: buf.h:23
int16 AttrNumber
Definition: attnum.h:21

◆ pg_visibility_rel()

Datum pg_visibility_rel ( PG_FUNCTION_ARGS  )

Definition at line 211 of file pg_visibility.c.

References vbits::bits, BoolGetDatum, collect_visibility_data(), vbits::count, heap_form_tuple(), HeapTupleGetDatum, Int64GetDatum(), MemoryContextSwitchTo(), MemSet, 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.

212 {
213  FuncCallContext *funcctx;
214  vbits *info;
215 
216  if (SRF_IS_FIRSTCALL())
217  {
218  Oid relid = PG_GETARG_OID(0);
219  MemoryContext oldcontext;
220 
221  funcctx = SRF_FIRSTCALL_INIT();
222  oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
223  funcctx->tuple_desc = pg_visibility_tupdesc(true, true);
224  /* collect_visibility_data will verify the relkind */
225  funcctx->user_fctx = collect_visibility_data(relid, true);
226  MemoryContextSwitchTo(oldcontext);
227  }
228 
229  funcctx = SRF_PERCALL_SETUP();
230  info = (vbits *) funcctx->user_fctx;
231 
232  if (info->next < info->count)
233  {
234  Datum values[4];
235  bool nulls[4];
236  HeapTuple tuple;
237 
238  MemSet(nulls, 0, sizeof(nulls));
239  values[0] = Int64GetDatum(info->next);
240  values[1] = BoolGetDatum((info->bits[info->next] & (1 << 0)) != 0);
241  values[2] = BoolGetDatum((info->bits[info->next] & (1 << 1)) != 0);
242  values[3] = BoolGetDatum((info->bits[info->next] & (1 << 2)) != 0);
243  info->next++;
244 
245  tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
246  SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
247  }
248 
249  SRF_RETURN_DONE(funcctx);
250 }
#define SRF_IS_FIRSTCALL()
Definition: funcapi.h:283
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
#define MemSet(start, val, len)
Definition: c.h:955
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:1020
unsigned int Oid
Definition: postgres_ext.h:31
#define SRF_PERCALL_SETUP()
Definition: funcapi.h:287
static TupleDesc pg_visibility_tupdesc(bool include_blkno, bool include_pd)
TupleDesc tuple_desc
Definition: funcapi.h:113
#define SRF_RETURN_NEXT(_funcctx, _result)
Definition: funcapi.h:289
#define PG_GETARG_OID(n)
Definition: fmgr.h:270
uint8 bits[FLEXIBLE_ARRAY_MEMBER]
Definition: pg_visibility.c:32
Datum Int64GetDatum(int64 X)
Definition: fmgr.c:1699
BlockNumber count
Definition: pg_visibility.c:31
uintptr_t Datum
Definition: postgres.h:367
#define BoolGetDatum(X)
Definition: postgres.h:402
MemoryContext multi_call_memory_ctx
Definition: funcapi.h:102
#define HeapTupleGetDatum(tuple)
Definition: funcapi.h:221
static Datum values[MAXATTR]
Definition: bootstrap.c:167
void * user_fctx
Definition: funcapi.h:83
BlockNumber next
Definition: pg_visibility.c:30
static vbits * collect_visibility_data(Oid relid, bool include_pd)
#define SRF_RETURN_DONE(_funcctx)
Definition: funcapi.h:307
#define SRF_FIRSTCALL_INIT()
Definition: funcapi.h:285

◆ pg_visibility_tupdesc()

static TupleDesc pg_visibility_tupdesc ( bool  include_blkno,
bool  include_pd 
)
static

Definition at line 442 of file pg_visibility.c.

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

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

443 {
444  TupleDesc tupdesc;
445  AttrNumber maxattr = 2;
446  AttrNumber a = 0;
447 
448  if (include_blkno)
449  ++maxattr;
450  if (include_pd)
451  ++maxattr;
452  tupdesc = CreateTemplateTupleDesc(maxattr);
453  if (include_blkno)
454  TupleDescInitEntry(tupdesc, ++a, "blkno", INT8OID, -1, 0);
455  TupleDescInitEntry(tupdesc, ++a, "all_visible", BOOLOID, -1, 0);
456  TupleDescInitEntry(tupdesc, ++a, "all_frozen", BOOLOID, -1, 0);
457  if (include_pd)
458  TupleDescInitEntry(tupdesc, ++a, "pd_all_visible", BOOLOID, -1, 0);
459  Assert(a == maxattr);
460 
461  return BlessTupleDesc(tupdesc);
462 }
TupleDesc CreateTemplateTupleDesc(int natts)
Definition: tupdesc.c:44
TupleDesc BlessTupleDesc(TupleDesc tupdesc)
Definition: execTuples.c:2048
void TupleDescInitEntry(TupleDesc desc, AttrNumber attributeNumber, const char *attributeName, Oid oidtypeid, int32 typmod, int attdim)
Definition: tupdesc.c:603
#define Assert(condition)
Definition: c.h:732
int16 AttrNumber
Definition: attnum.h:21

◆ record_corrupt_item()

static void record_corrupt_item ( corrupt_items items,
ItemPointer  tid 
)
static

Definition at line 726 of file pg_visibility.c.

References corrupt_items::count, corrupt_items::next, repalloc(), and corrupt_items::tids.

Referenced by collect_corrupt_items().

727 {
728  /* enlarge output array if needed. */
729  if (items->next >= items->count)
730  {
731  items->count *= 2;
732  items->tids = repalloc(items->tids,
733  items->count * sizeof(ItemPointerData));
734  }
735  /* and add the new item */
736  items->tids[items->next++] = *tid;
737 }
BlockNumber count
Definition: pg_visibility.c:38
ItemPointer tids
Definition: pg_visibility.c:39
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1044
BlockNumber next
Definition: pg_visibility.c:37

◆ tuple_all_visible()

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

Definition at line 744 of file pg_visibility.c.

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

Referenced by collect_corrupt_items().

745 {
747  TransactionId xmin;
748 
749  state = HeapTupleSatisfiesVacuum(tup, OldestXmin, buffer);
750  if (state != HEAPTUPLE_LIVE)
751  return false; /* all-visible implies live */
752 
753  /*
754  * Neither lazy_scan_heap nor heap_page_is_all_visible will mark a page
755  * all-visible unless every tuple is hinted committed. However, those hint
756  * bits could be lost after a crash, so we can't be certain that they'll
757  * be set here. So just check the xmin.
758  */
759 
760  xmin = HeapTupleHeaderGetXmin(tup->t_data);
761  if (!TransactionIdPrecedes(xmin, OldestXmin))
762  return false; /* xmin not old enough for all to see */
763 
764  return true;
765 }
uint32 TransactionId
Definition: c.h:507
HeapTupleHeader t_data
Definition: htup.h:68
static TransactionId OldestXmin
Definition: vacuumlazy.c:145
HTSV_Result HeapTupleSatisfiesVacuum(HeapTuple htup, TransactionId OldestXmin, Buffer buffer)
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition: transam.c:300
Definition: regguts.h:298
#define HeapTupleHeaderGetXmin(tup)
Definition: htup_details.h:313
HTSV_Result
Definition: heapam.h:86

Variable Documentation

◆ PG_MODULE_MAGIC

PG_MODULE_MAGIC

Definition at line 26 of file pg_visibility.c.