PostgreSQL Source Code git master
Loading...
Searching...
No Matches
pg_visibility.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * pg_visibility.c
4 * display visibility map information and page-level visibility bits
5 *
6 * Copyright (c) 2016-2026, PostgreSQL Global Development Group
7 *
8 * contrib/pg_visibility/pg_visibility.c
9 *-------------------------------------------------------------------------
10 */
11#include "postgres.h"
12
13#include "access/heapam.h"
14#include "access/htup_details.h"
16#include "access/xloginsert.h"
17#include "catalog/pg_type.h"
19#include "funcapi.h"
20#include "miscadmin.h"
21#include "storage/bufmgr.h"
22#include "storage/proc.h"
23#include "storage/procarray.h"
24#include "storage/read_stream.h"
25#include "storage/smgr.h"
26#include "utils/rel.h"
27
29 .name = "pg_visibility",
30 .version = PG_VERSION
31);
32
39
46
47/* for collect_corrupt_items_read_stream_next_block */
57
66
68static vbits *collect_visibility_data(Oid relid, bool include_pd);
69static corrupt_items *collect_corrupt_items(Oid relid, bool all_visible,
70 bool all_frozen);
72static bool tuple_all_visible(HeapTuple tup, TransactionId OldestXmin,
73 Buffer buffer);
74static void check_relation_relkind(Relation rel);
75
76/*
77 * Visibility map information for a single block of a relation.
78 *
79 * Note: the VM code will silently return zeroes for pages past the end
80 * of the map, so we allow probes up to MaxBlockNumber regardless of the
81 * actual relation size.
82 */
85{
86 Oid relid = PG_GETARG_OID(0);
87 int64 blkno = PG_GETARG_INT64(1);
89 Relation rel;
90 Buffer vmbuffer = InvalidBuffer;
91 TupleDesc tupdesc;
92 Datum values[2];
93 bool nulls[2] = {0};
94
95 rel = relation_open(relid, AccessShareLock);
96
97 /* Only some relkinds have a visibility map */
99
103 errmsg("invalid block number")));
104
105 tupdesc = pg_visibility_tupdesc(false, false);
106
107 mapbits = (int32) visibilitymap_get_status(rel, blkno, &vmbuffer);
108 if (vmbuffer != InvalidBuffer)
109 ReleaseBuffer(vmbuffer);
112
114
116}
117
118/*
119 * Visibility map information for a single block of a relation, plus the
120 * page-level information for the same block.
121 */
122Datum
124{
125 Oid relid = PG_GETARG_OID(0);
126 int64 blkno = PG_GETARG_INT64(1);
128 Relation rel;
129 Buffer vmbuffer = InvalidBuffer;
130 Buffer buffer;
131 Page page;
132 TupleDesc tupdesc;
133 Datum values[3];
134 bool nulls[3] = {0};
135
136 rel = relation_open(relid, AccessShareLock);
137
138 /* Only some relkinds have a visibility map */
140
144 errmsg("invalid block number")));
145
146 tupdesc = pg_visibility_tupdesc(false, true);
147
148 mapbits = (int32) visibilitymap_get_status(rel, blkno, &vmbuffer);
149 if (vmbuffer != InvalidBuffer)
150 ReleaseBuffer(vmbuffer);
153
154 /* Here we have to explicitly check rel size ... */
155 if (blkno < RelationGetNumberOfBlocks(rel))
156 {
157 buffer = ReadBuffer(rel, blkno);
159
160 page = BufferGetPage(buffer);
162
163 UnlockReleaseBuffer(buffer);
164 }
165 else
166 {
167 /* As with the vismap, silently return 0 for pages past EOF */
168 values[2] = BoolGetDatum(false);
169 }
170
172
174}
175
176/*
177 * Visibility map information for every block in a relation.
178 */
179Datum
181{
183 vbits *info;
184
185 if (SRF_IS_FIRSTCALL())
186 {
187 Oid relid = PG_GETARG_OID(0);
188 MemoryContext oldcontext;
189
191 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
192 funcctx->tuple_desc = pg_visibility_tupdesc(true, false);
193 /* collect_visibility_data will verify the relkind */
194 funcctx->user_fctx = collect_visibility_data(relid, false);
195 MemoryContextSwitchTo(oldcontext);
196 }
197
199 info = (vbits *) funcctx->user_fctx;
200
201 if (info->next < info->count)
202 {
203 Datum values[3];
204 bool nulls[3] = {0};
205 HeapTuple tuple;
206
207 values[0] = Int64GetDatum(info->next);
208 values[1] = BoolGetDatum((info->bits[info->next] & (1 << 0)) != 0);
209 values[2] = BoolGetDatum((info->bits[info->next] & (1 << 1)) != 0);
210 info->next++;
211
212 tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
214 }
215
217}
218
219/*
220 * Visibility map information for every block in a relation, plus the page
221 * level information for each block.
222 */
223Datum
225{
227 vbits *info;
228
229 if (SRF_IS_FIRSTCALL())
230 {
231 Oid relid = PG_GETARG_OID(0);
232 MemoryContext oldcontext;
233
235 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
236 funcctx->tuple_desc = pg_visibility_tupdesc(true, true);
237 /* collect_visibility_data will verify the relkind */
238 funcctx->user_fctx = collect_visibility_data(relid, true);
239 MemoryContextSwitchTo(oldcontext);
240 }
241
243 info = (vbits *) funcctx->user_fctx;
244
245 if (info->next < info->count)
246 {
247 Datum values[4];
248 bool nulls[4] = {0};
249 HeapTuple tuple;
250
251 values[0] = Int64GetDatum(info->next);
252 values[1] = BoolGetDatum((info->bits[info->next] & (1 << 0)) != 0);
253 values[2] = BoolGetDatum((info->bits[info->next] & (1 << 1)) != 0);
254 values[3] = BoolGetDatum((info->bits[info->next] & (1 << 2)) != 0);
255 info->next++;
256
257 tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
259 }
260
262}
263
264/*
265 * Count the number of all-visible and all-frozen pages in the visibility
266 * map for a particular relation.
267 */
268Datum
270{
271 Oid relid = PG_GETARG_OID(0);
272 Relation rel;
273 BlockNumber all_visible = 0;
274 BlockNumber all_frozen = 0;
275 TupleDesc tupdesc;
276 Datum values[2];
277 bool nulls[2] = {0};
278
279 rel = relation_open(relid, AccessShareLock);
280
281 /* Only some relkinds have a visibility map */
283
284 visibilitymap_count(rel, &all_visible, &all_frozen);
285
287
288 if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
289 elog(ERROR, "return type must be a row type");
290
291 values[0] = Int64GetDatum((int64) all_visible);
292 values[1] = Int64GetDatum((int64) all_frozen);
293
295}
296
297/*
298 * Return the TIDs of non-frozen tuples present in pages marked all-frozen
299 * in the visibility map. We hope no one will ever find any, but there could
300 * be bugs, database corruption, etc.
301 */
302Datum
304{
307
308 if (SRF_IS_FIRSTCALL())
309 {
310 Oid relid = PG_GETARG_OID(0);
311 MemoryContext oldcontext;
312
314 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
315 /* collect_corrupt_items will verify the relkind */
316 funcctx->user_fctx = collect_corrupt_items(relid, false, true);
317 MemoryContextSwitchTo(oldcontext);
318 }
319
321 items = (corrupt_items *) funcctx->user_fctx;
322
323 if (items->next < items->count)
325
327}
328
329/*
330 * Return the TIDs of not-all-visible tuples in pages marked all-visible
331 * in the visibility map. We hope no one will ever find any, but there could
332 * be bugs, database corruption, etc.
333 */
334Datum
336{
339
340 if (SRF_IS_FIRSTCALL())
341 {
342 Oid relid = PG_GETARG_OID(0);
343 MemoryContext oldcontext;
344
346 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
347 /* collect_corrupt_items will verify the relkind */
348 funcctx->user_fctx = collect_corrupt_items(relid, true, false);
349 MemoryContextSwitchTo(oldcontext);
350 }
351
353 items = (corrupt_items *) funcctx->user_fctx;
354
355 if (items->next < items->count)
357
359}
360
361/*
362 * Remove the visibility map fork for a relation. If there turn out to be
363 * any bugs in the visibility map code that require rebuilding the VM, this
364 * provides users with a way to do it that is cleaner than shutting down the
365 * server and removing files by hand.
366 *
367 * This is a cut-down version of RelationTruncate.
368 */
369Datum
371{
372 Oid relid = PG_GETARG_OID(0);
373 Relation rel;
375 BlockNumber block;
377
379
380 /* Only some relkinds have a visibility map */
382
383 /* Forcibly reset cached file size */
385
386 /* Compute new and old size before entering critical section. */
388 block = visibilitymap_prepare_truncate(rel, 0);
390
391 /*
392 * WAL-logging, buffer dropping, file truncation must be atomic and all on
393 * one side of a checkpoint. See RelationTruncate() for discussion.
394 */
398
399 if (RelationNeedsWAL(rel))
400 {
401 XLogRecPtr lsn;
403
404 xlrec.blkno = 0;
405 xlrec.rlocator = rel->rd_locator;
406 xlrec.flags = SMGR_TRUNCATE_VM;
407
409 XLogRegisterData(&xlrec, sizeof(xlrec));
410
413 XLogFlush(lsn);
414 }
415
416 if (BlockNumberIsValid(block))
417 smgrtruncate(RelationGetSmgr(rel), &fork, 1, &old_block, &block);
418
421
422 /*
423 * Release the lock right away, not at commit time.
424 *
425 * It would be a problem to release the lock prior to commit if this
426 * truncate operation sends any transactional invalidation messages. Other
427 * backends would potentially be able to lock the relation without
428 * processing them in the window of time between when we release the lock
429 * here and when we sent the messages at our eventual commit. However,
430 * we're currently only sending a non-transactional smgr invalidation,
431 * which will have been posted to shared memory immediately from within
432 * smgr_truncate. Therefore, there should be no race here.
433 *
434 * The reason why it's desirable to release the lock early here is because
435 * of the possibility that someone will need to use this to blow away many
436 * visibility map forks at once. If we can't release the lock until
437 * commit time, the transaction doing this will accumulate
438 * AccessExclusiveLocks on all of those relations at the same time, which
439 * is undesirable. However, if this turns out to be unsafe we may have no
440 * choice...
441 */
443
444 /* Nothing to return. */
446}
447
448/*
449 * Helper function to construct whichever TupleDesc we need for a particular
450 * call.
451 */
452static TupleDesc
454{
455 TupleDesc tupdesc;
457 AttrNumber a = 0;
458
459 if (include_blkno)
460 ++maxattr;
461 if (include_pd)
462 ++maxattr;
464 if (include_blkno)
465 TupleDescInitEntry(tupdesc, ++a, "blkno", INT8OID, -1, 0);
466 TupleDescInitEntry(tupdesc, ++a, "all_visible", BOOLOID, -1, 0);
467 TupleDescInitEntry(tupdesc, ++a, "all_frozen", BOOLOID, -1, 0);
468 if (include_pd)
469 TupleDescInitEntry(tupdesc, ++a, "pd_all_visible", BOOLOID, -1, 0);
470 Assert(a == maxattr);
471
472 TupleDescFinalize(tupdesc);
473
474 return BlessTupleDesc(tupdesc);
475}
476
477/*
478 * Collect visibility data about a relation.
479 *
480 * Checks relkind of relid and will throw an error if the relation does not
481 * have a VM.
482 */
483static vbits *
485{
486 Relation rel;
487 BlockNumber nblocks;
488 vbits *info;
489 BlockNumber blkno;
490 Buffer vmbuffer = InvalidBuffer;
493 ReadStream *stream = NULL;
494
495 rel = relation_open(relid, AccessShareLock);
496
497 /* Only some relkinds have a visibility map */
499
500 nblocks = RelationGetNumberOfBlocks(rel);
501 info = palloc0(offsetof(vbits, bits) + nblocks);
502 info->next = 0;
503 info->count = nblocks;
504
505 /* Create a stream if reading main fork. */
506 if (include_pd)
507 {
508 p.current_blocknum = 0;
509 p.last_exclusive = nblocks;
510
511 /*
512 * It is safe to use batchmode as block_range_read_stream_cb takes no
513 * locks.
514 */
517 bstrategy,
518 rel,
521 &p,
522 0);
523 }
524
525 for (blkno = 0; blkno < nblocks; ++blkno)
526 {
528
529 /* Make sure we are interruptible. */
531
532 /* Get map info. */
533 mapbits = (int32) visibilitymap_get_status(rel, blkno, &vmbuffer);
535 info->bits[blkno] |= (1 << 0);
537 info->bits[blkno] |= (1 << 1);
538
539 /*
540 * Page-level data requires reading every block, so only get it if the
541 * caller needs it. Use a buffer access strategy, too, to prevent
542 * cache-trashing.
543 */
544 if (include_pd)
545 {
546 Buffer buffer;
547 Page page;
548
549 buffer = read_stream_next_buffer(stream, NULL);
551
552 page = BufferGetPage(buffer);
553 if (PageIsAllVisible(page))
554 info->bits[blkno] |= (1 << 2);
555
556 UnlockReleaseBuffer(buffer);
557 }
558 }
559
560 if (include_pd)
561 {
563 read_stream_end(stream);
564 }
565
566 /* Clean up. */
567 if (vmbuffer != InvalidBuffer)
568 ReleaseBuffer(vmbuffer);
570
571 return info;
572}
573
574/*
575 * The "strict" version of GetOldestNonRemovableTransactionId(). The
576 * pg_visibility check can tolerate false positives (don't report some of the
577 * errors), but can't tolerate false negatives (report false errors). Normally,
578 * horizons move forwards, but there are cases when it could move backward
579 * (see comment for ComputeXidHorizons()).
580 *
581 * This is why we have to implement our own function for xid horizon, which
582 * would be guaranteed to be newer or equal to any xid horizon computed before.
583 * We have to do the following to achieve this.
584 *
585 * 1. Ignore processes xmin's, because they consider connection to other
586 * databases that were ignored before.
587 * 2. Ignore KnownAssignedXids, as they are not database-aware. Although we
588 * now perform minimal checking on a standby by always using nextXid, this
589 * approach is better than nothing and will at least catch extremely broken
590 * cases where a xid is in the future.
591 * 3. Ignore walsender xmin, because it could go backward if some replication
592 * connections don't use replication slots.
593 *
594 * While it might seem like we could use KnownAssignedXids for shared
595 * catalogs, since shared catalogs rely on a global horizon rather than a
596 * database-specific one - there are potential edge cases. For example, a
597 * transaction may crash on the primary without writing a commit/abort record.
598 * This would lead to a situation where it appears to still be running on the
599 * standby, even though it has already ended on the primary. For this reason,
600 * it's safer to ignore KnownAssignedXids, even for shared catalogs.
601 *
602 * As a result, we're using only currently running xids to compute the horizon.
603 * Surely these would significantly sacrifice accuracy. But we have to do so
604 * to avoid reporting false errors.
605 */
606static TransactionId
608{
610
611 if (RecoveryInProgress())
612 {
613 TransactionId result;
614
615 /* As we ignore KnownAssignedXids on standby, just pick nextXid */
619 return result;
620 }
621 else if (rel == NULL || rel->rd_rel->relisshared)
622 {
623 /* Shared relation: take into account all running xids */
627 return runningTransactions->oldestRunningXid;
628 }
629 else if (!RELATION_IS_LOCAL(rel))
630 {
631 /*
632 * Normal relation: take into account xids running within the current
633 * database
634 */
638 return runningTransactions->oldestDatabaseRunningXid;
639 }
640 else
641 {
642 /*
643 * For temporary relations, ComputeXidHorizons() uses only
644 * TransamVariables->latestCompletedXid and MyProc->xid. These two
645 * shouldn't go backwards. So we're fine with this horizon.
646 */
648 }
649}
650
651/*
652 * Callback function to get next block for read stream object used in
653 * collect_corrupt_items() function.
654 */
655static BlockNumber
657 void *callback_private_data,
658 void *per_buffer_data)
659{
660 struct collect_corrupt_items_read_stream_private *p = callback_private_data;
661
663 {
664 bool check_frozen = false;
665 bool check_visible = false;
666
667 /* Make sure we are interruptible. */
669
671 check_frozen = true;
673 check_visible = true;
675 continue;
676
677 return p->current_blocknum++;
678 }
679
680 return InvalidBlockNumber;
681}
682
683/*
684 * Returns a list of items whose visibility map information does not match
685 * the status of the tuples on the page.
686 *
687 * If all_visible is passed as true, this will include all items which are
688 * on pages marked as all-visible in the visibility map but which do not
689 * seem to in fact be all-visible.
690 *
691 * If all_frozen is passed as true, this will include all items which are
692 * on pages marked as all-frozen but which do not seem to in fact be frozen.
693 *
694 * Checks relkind of relid and will throw an error if the relation does not
695 * have a VM.
696 */
697static corrupt_items *
699{
706 ReadStream *stream;
707 Buffer buffer;
708
710
711 /* Only some relkinds have a visibility map */
713
714 if (all_visible)
716
717 /*
718 * Guess an initial array size. We don't expect many corrupted tuples, so
719 * start with a small array. This function uses the "next" field to track
720 * the next offset where we can store an item (which is the same thing as
721 * the number of items found so far) and the "count" field to track the
722 * number of entries allocated. We'll repurpose these fields before
723 * returning.
724 */
726 items->next = 0;
727 items->count = 64;
728 items->tids = palloc(items->count * sizeof(ItemPointerData));
729
730 p.current_blocknum = 0;
732 p.rel = rel;
737 bstrategy,
738 rel,
741 &p,
742 0);
743
744 /* Loop over every block in the relation. */
745 while ((buffer = read_stream_next_buffer(stream, NULL)) != InvalidBuffer)
746 {
749 Page page;
750 OffsetNumber offnum,
751 maxoff;
752 BlockNumber blkno;
753
754 /* Make sure we are interruptible. */
756
758
759 page = BufferGetPage(buffer);
760 maxoff = PageGetMaxOffsetNumber(page);
761 blkno = BufferGetBlockNumber(buffer);
762
763 /*
764 * The visibility map bits might have changed while we were acquiring
765 * the page lock. Recheck to avoid returning spurious results.
766 */
767 if (check_frozen && !VM_ALL_FROZEN(rel, blkno, &vmbuffer))
768 check_frozen = false;
769 if (check_visible && !VM_ALL_VISIBLE(rel, blkno, &vmbuffer))
770 check_visible = false;
772 {
773 UnlockReleaseBuffer(buffer);
774 continue;
775 }
776
777 /* Iterate over each tuple on the page. */
778 for (offnum = FirstOffsetNumber;
779 offnum <= maxoff;
780 offnum = OffsetNumberNext(offnum))
781 {
782 HeapTupleData tuple;
783 ItemId itemid;
784
785 itemid = PageGetItemId(page, offnum);
786
787 /* Unused or redirect line pointers are of no interest. */
788 if (!ItemIdIsUsed(itemid) || ItemIdIsRedirected(itemid))
789 continue;
790
791 /* Dead line pointers are neither all-visible nor frozen. */
792 if (ItemIdIsDead(itemid))
793 {
794 ItemPointerSet(&(tuple.t_self), blkno, offnum);
796 continue;
797 }
798
799 /* Initialize a HeapTupleData structure for checks below. */
800 ItemPointerSet(&(tuple.t_self), blkno, offnum);
801 tuple.t_data = (HeapTupleHeader) PageGetItem(page, itemid);
802 tuple.t_len = ItemIdGetLength(itemid);
803 tuple.t_tableOid = relid;
804
805 /*
806 * If we're checking whether the page is all-visible, we expect
807 * the tuple to be all-visible.
808 */
809 if (check_visible &&
810 !tuple_all_visible(&tuple, OldestXmin, buffer))
811 {
813
814 /*
815 * Time has passed since we computed OldestXmin, so it's
816 * possible that this tuple is all-visible in reality even
817 * though it doesn't appear so based on our
818 * previously-computed value. Let's compute a new value so we
819 * can be certain whether there is a problem.
820 *
821 * From a concurrency point of view, it sort of sucks to
822 * retake ProcArrayLock here while we're holding the buffer
823 * locked in shared mode, but it should be safe against
824 * deadlocks, because surely
825 * GetStrictOldestNonRemovableTransactionId() should never
826 * take a buffer lock. And this shouldn't happen often, so
827 * it's worth being careful so as to avoid false positives.
828 */
830
833 else
834 {
835 OldestXmin = RecomputedOldestXmin;
836 if (!tuple_all_visible(&tuple, OldestXmin, buffer))
838 }
839 }
840
841 /*
842 * If we're checking whether the page is all-frozen, we expect the
843 * tuple to be in a state where it will never need freezing.
844 */
845 if (check_frozen)
846 {
849 }
850 }
851
852 UnlockReleaseBuffer(buffer);
853 }
854 read_stream_end(stream);
855
856 /* Clean up. */
857 if (vmbuffer != InvalidBuffer)
859 if (p.vmbuffer != InvalidBuffer)
862
863 /*
864 * Before returning, repurpose the fields to match caller's expectations.
865 * next is now the next item that should be read (rather than written) and
866 * count is now the number of items we wrote (rather than the number we
867 * allocated).
868 */
869 items->count = items->next;
870 items->next = 0;
871
872 return items;
873}
874
875/*
876 * Remember one corrupt item.
877 */
878static void
880{
881 /* enlarge output array if needed. */
882 if (items->next >= items->count)
883 {
884 items->count *= 2;
885 items->tids = repalloc(items->tids,
886 items->count * sizeof(ItemPointerData));
887 }
888 /* and add the new item */
889 items->tids[items->next++] = *tid;
890}
891
892/*
893 * Check whether a tuple is all-visible relative to a given OldestXmin value.
894 * The buffer should contain the tuple and should be locked and pinned.
895 */
896static bool
898{
900 TransactionId xmin;
901
902 state = HeapTupleSatisfiesVacuum(tup, OldestXmin, buffer);
903 if (state != HEAPTUPLE_LIVE)
904 return false; /* all-visible implies live */
905
906 /*
907 * Neither lazy_scan_heap nor heap_page_is_all_visible will mark a page
908 * all-visible unless every tuple is hinted committed. However, those hint
909 * bits could be lost after a crash, so we can't be certain that they'll
910 * be set here. So just check the xmin.
911 */
912
913 xmin = HeapTupleHeaderGetXmin(tup->t_data);
914 if (!TransactionIdPrecedes(xmin, OldestXmin))
915 return false; /* xmin not old enough for all to see */
916
917 return true;
918}
919
920/*
921 * check_relation_relkind - convenience routine to check that relation
922 * is of the relkind supported by the callers
923 */
924static void
926{
927 if (!RELKIND_HAS_TABLE_AM(rel->rd_rel->relkind))
930 errmsg("relation \"%s\" is of wrong relation kind",
933}
int16 AttrNumber
Definition attnum.h:21
uint32 BlockNumber
Definition block.h:31
#define InvalidBlockNumber
Definition block.h:33
static bool BlockNumberIsValid(BlockNumber blockNumber)
Definition block.h:71
#define MaxBlockNumber
Definition block.h:35
static Datum values[MAXATTR]
Definition bootstrap.c:188
int Buffer
Definition buf.h:23
#define InvalidBuffer
Definition buf.h:25
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition bufmgr.c:4357
void ReleaseBuffer(Buffer buffer)
Definition bufmgr.c:5505
void UnlockReleaseBuffer(Buffer buffer)
Definition bufmgr.c:5522
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition bufmgr.c:874
@ BAS_BULKREAD
Definition bufmgr.h:37
#define RelationGetNumberOfBlocks(reln)
Definition bufmgr.h:307
static Page BufferGetPage(Buffer buffer)
Definition bufmgr.h:470
@ BUFFER_LOCK_SHARE
Definition bufmgr.h:210
static void LockBuffer(Buffer buffer, BufferLockMode mode)
Definition bufmgr.h:332
static bool PageIsAllVisible(const PageData *page)
Definition bufpage.h:455
static ItemId PageGetItemId(Page page, OffsetNumber offsetNumber)
Definition bufpage.h:269
static void * PageGetItem(PageData *page, const ItemIdData *itemId)
Definition bufpage.h:379
PageData * Page
Definition bufpage.h:81
static OffsetNumber PageGetMaxOffsetNumber(const PageData *page)
Definition bufpage.h:397
uint8_t uint8
Definition c.h:616
#define Assert(condition)
Definition c.h:945
int64_t int64
Definition c.h:615
#define FLEXIBLE_ARRAY_MEMBER
Definition c.h:552
int32_t int32
Definition c.h:614
uint32 TransactionId
Definition c.h:738
int errcode(int sqlerrcode)
Definition elog.c:874
#define ERROR
Definition elog.h:39
#define elog(elevel,...)
Definition elog.h:226
#define ereport(elevel,...)
Definition elog.h:150
TupleDesc BlessTupleDesc(TupleDesc tupdesc)
#define palloc0_object(type)
Definition fe_memutils.h:75
#define PG_RETURN_VOID()
Definition fmgr.h:350
#define PG_GETARG_OID(n)
Definition fmgr.h:275
#define PG_MODULE_MAGIC_EXT(...)
Definition fmgr.h:540
#define PG_GETARG_INT64(n)
Definition fmgr.h:284
#define PG_FUNCTION_INFO_V1(funcname)
Definition fmgr.h:417
#define PG_RETURN_DATUM(x)
Definition fmgr.h:354
#define PG_FUNCTION_ARGS
Definition fmgr.h:193
BufferAccessStrategy GetAccessStrategy(BufferAccessStrategyType btype)
Definition freelist.c:461
TypeFuncClass get_call_result_type(FunctionCallInfo fcinfo, Oid *resultTypeId, TupleDesc *resultTupleDesc)
Definition funcapi.c:276
#define SRF_IS_FIRSTCALL()
Definition funcapi.h:304
#define SRF_PERCALL_SETUP()
Definition funcapi.h:308
@ TYPEFUNC_COMPOSITE
Definition funcapi.h:149
#define SRF_RETURN_NEXT(_funcctx, _result)
Definition funcapi.h:310
#define SRF_FIRSTCALL_INIT()
Definition funcapi.h:306
static Datum HeapTupleGetDatum(const HeapTupleData *tuple)
Definition funcapi.h:230
#define SRF_RETURN_DONE(_funcctx)
Definition funcapi.h:328
bool heap_tuple_needs_eventual_freeze(HeapTupleHeader tuple)
Definition heapam.c:7910
HTSV_Result
Definition heapam.h:137
@ HEAPTUPLE_LIVE
Definition heapam.h:139
HTSV_Result HeapTupleSatisfiesVacuum(HeapTuple htup, TransactionId OldestXmin, Buffer buffer)
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition heaptuple.c:1037
HeapTupleHeaderData * HeapTupleHeader
Definition htup.h:23
static TransactionId HeapTupleHeaderGetXmin(const HeapTupleHeaderData *tup)
int a
Definition isn.c:73
#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 AccessExclusiveLock
Definition lockdefs.h:43
#define AccessShareLock
Definition lockdefs.h:36
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition lwlock.c:1177
void LWLockRelease(LWLock *lock)
Definition lwlock.c:1794
@ LW_SHARED
Definition lwlock.h:113
void * repalloc(void *pointer, Size size)
Definition mcxt.c:1632
void * palloc0(Size size)
Definition mcxt.c:1417
void * palloc(Size size)
Definition mcxt.c:1387
#define START_CRIT_SECTION()
Definition miscadmin.h:150
#define CHECK_FOR_INTERRUPTS()
Definition miscadmin.h:123
#define END_CRIT_SECTION()
Definition miscadmin.h:152
static char * errmsg
#define OffsetNumberNext(offsetNumber)
Definition off.h:52
uint16 OffsetNumber
Definition off.h:24
#define FirstOffsetNumber
Definition off.h:27
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition palloc.h:124
int errdetail_relkind_not_supported(char relkind)
Definition pg_class.c:24
static BlockNumber collect_corrupt_items_read_stream_next_block(ReadStream *stream, void *callback_private_data, void *per_buffer_data)
static corrupt_items * collect_corrupt_items(Oid relid, bool all_visible, bool all_frozen)
Datum pg_visibility_map_summary(PG_FUNCTION_ARGS)
Datum pg_visibility_rel(PG_FUNCTION_ARGS)
static TupleDesc pg_visibility_tupdesc(bool include_blkno, bool include_pd)
static void check_relation_relkind(Relation rel)
static void record_corrupt_item(corrupt_items *items, ItemPointer tid)
static TransactionId GetStrictOldestNonRemovableTransactionId(Relation rel)
Datum pg_visibility_map(PG_FUNCTION_ARGS)
static vbits * collect_visibility_data(Oid relid, bool include_pd)
Datum pg_visibility_map_rel(PG_FUNCTION_ARGS)
Datum pg_check_visible(PG_FUNCTION_ARGS)
Datum pg_check_frozen(PG_FUNCTION_ARGS)
Datum pg_visibility(PG_FUNCTION_ARGS)
static bool tuple_all_visible(HeapTuple tup, TransactionId OldestXmin, Buffer buffer)
Datum pg_truncate_visibility_map(PG_FUNCTION_ARGS)
static Datum Int64GetDatum(int64 X)
Definition postgres.h:413
static Datum PointerGetDatum(const void *X)
Definition postgres.h:342
static Datum BoolGetDatum(bool X)
Definition postgres.h:112
uint64_t Datum
Definition postgres.h:70
unsigned int Oid
static int fb(int x)
#define DELAY_CHKPT_START
Definition proc.h:136
#define DELAY_CHKPT_COMPLETE
Definition proc.h:137
TransactionId GetOldestNonRemovableTransactionId(Relation rel)
Definition procarray.c:1952
RunningTransactions GetRunningTransactionData(void)
Definition procarray.c:2636
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_end(ReadStream *stream)
BlockNumber block_range_read_stream_cb(ReadStream *stream, void *callback_private_data, void *per_buffer_data)
#define READ_STREAM_USE_BATCHING
Definition read_stream.h:64
#define READ_STREAM_FULL
Definition read_stream.h:43
#define RELATION_IS_LOCAL(relation)
Definition rel.h:657
static SMgrRelation RelationGetSmgr(Relation rel)
Definition rel.h:576
#define RelationGetRelationName(relation)
Definition rel.h:548
#define RelationNeedsWAL(relation)
Definition rel.h:637
ForkNumber
Definition relpath.h:56
@ VISIBILITYMAP_FORKNUM
Definition relpath.h:60
@ MAIN_FORKNUM
Definition relpath.h:58
BlockNumber smgrnblocks(SMgrRelation reln, ForkNumber forknum)
Definition smgr.c:819
void smgrtruncate(SMgrRelation reln, ForkNumber *forknum, int nforks, BlockNumber *old_nblocks, BlockNumber *nblocks)
Definition smgr.c:875
void relation_close(Relation relation, LOCKMODE lockmode)
Definition relation.c:205
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition relation.c:47
PGPROC * MyProc
Definition proc.c:68
#define SMGR_TRUNCATE_VM
#define XLOG_SMGR_TRUNCATE
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
int delayChkptFlags
Definition proc.h:257
RelFileLocator rd_locator
Definition rel.h:57
Form_pg_class rd_rel
Definition rel.h:111
BlockNumber smgr_cached_nblocks[MAX_FORKNUM+1]
Definition smgr.h:47
FullTransactionId nextXid
Definition transam.h:220
ItemPointer tids
BlockNumber count
BlockNumber next
BlockNumber next
uint8 bits[FLEXIBLE_ARRAY_MEMBER]
BlockNumber count
BlockNumber blkno
static ItemArray items
#define InvalidTransactionId
Definition transam.h:31
#define XidFromFullTransactionId(x)
Definition transam.h:48
static bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition transam.h:263
TupleDesc CreateTemplateTupleDesc(int natts)
Definition tupdesc.c:165
void TupleDescFinalize(TupleDesc tupdesc)
Definition tupdesc.c:508
void TupleDescInitEntry(TupleDesc desc, AttrNumber attributeNumber, const char *attributeName, Oid oidtypeid, int32 typmod, int attdim)
Definition tupdesc.c:897
TransamVariablesData * TransamVariables
Definition varsup.c:34
uint8 visibilitymap_get_status(Relation rel, BlockNumber heapBlk, Buffer *vmbuf)
BlockNumber visibilitymap_prepare_truncate(Relation rel, BlockNumber nheapblocks)
void visibilitymap_count(Relation rel, BlockNumber *all_visible, BlockNumber *all_frozen)
#define VM_ALL_VISIBLE(r, b, v)
#define VM_ALL_FROZEN(r, b, v)
#define VISIBILITYMAP_ALL_FROZEN
#define VISIBILITYMAP_ALL_VISIBLE
const char * name
bool RecoveryInProgress(void)
Definition xlog.c:6444
void XLogFlush(XLogRecPtr record)
Definition xlog.c:2767
uint64 XLogRecPtr
Definition xlogdefs.h:21
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition xloginsert.c:479
void XLogRegisterData(const void *data, uint32 len)
Definition xloginsert.c:369
void XLogBeginInsert(void)
Definition xloginsert.c:153
#define XLR_SPECIAL_REL_UPDATE
Definition xlogrecord.h:82