PostgreSQL Source Code git master
Loading...
Searching...
No Matches
ginvacuum.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * ginvacuum.c
4 * delete & vacuum routines for the postgres GIN
5 *
6 *
7 * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
8 * Portions Copyright (c) 1994, Regents of the University of California
9 *
10 * IDENTIFICATION
11 * src/backend/access/gin/ginvacuum.c
12 *-------------------------------------------------------------------------
13 */
14
15#include "postgres.h"
16
17#include "access/gin_private.h"
18#include "access/ginxlog.h"
19#include "access/xloginsert.h"
20#include "commands/vacuum.h"
21#include "miscadmin.h"
22#include "storage/indexfsm.h"
23#include "storage/lmgr.h"
24#include "storage/predicate.h"
25#include "storage/read_stream.h"
26#include "utils/memutils.h"
27
38
39/*
40 * Vacuums an uncompressed posting list. The size of the must can be specified
41 * in number of items (nitems).
42 *
43 * If none of the items need to be removed, returns NULL. Otherwise returns
44 * a new palloc'd array with the remaining items. The number of remaining
45 * items is returned in *nremaining.
46 */
49 int nitem, int *nremaining)
50{
51 int i,
52 remaining = 0;
54
55 /*
56 * Iterate over TIDs array
57 */
58 for (i = 0; i < nitem; i++)
59 {
60 if (gvs->callback(items + i, gvs->callback_state))
61 {
62 gvs->result->tuples_removed += 1;
63 if (!tmpitems)
64 {
65 /*
66 * First TID to be deleted: allocate memory to hold the
67 * remaining items.
68 */
71 }
72 }
73 else
74 {
75 gvs->result->num_index_tuples += 1;
76 if (tmpitems)
78 remaining++;
79 }
80 }
81
83 return tmpitems;
84}
85
86/*
87 * Create a WAL record for vacuuming entry tree leaf page.
88 */
89static void
91{
92 Page page = BufferGetPage(buffer);
94
95 /* This is only used for entry tree leaf pages. */
96 Assert(!GinPageIsData(page));
97 Assert(GinPageIsLeaf(page));
98
100 return;
101
102 /*
103 * Always create a full image, we don't track the changes on the page at
104 * any more fine-grained level. This could obviously be improved...
105 */
108
110 PageSetLSN(page, recptr);
111}
112
113
114/*
115 * Stack entry used during posting tree empty-page deletion scan.
116 *
117 * One DataPageDeleteStack entry is allocated per tree level. As
118 * ginScanPostingTreeToDelete() recurses down the tree, each entry tracks
119 * the buffer of the page currently being visited at that level ('buffer'),
120 * and the buffer of its left sibling ('leftBuffer'). The left page is kept
121 * pinned and exclusively locked because ginDeletePostingPage() needs it to
122 * update the sibling chain; acquiring it later could deadlock with
123 * ginStepRight(), which locks pages left-to-right.
124 */
126{
129
130 Buffer buffer; /* buffer for the page being visited at this
131 * tree level */
132 Buffer leftBuffer; /* pinned and locked rightmost non-deleted
133 * sibling to the left of the current page */
134 OffsetNumber myoff; /* offset of this page's downlink in the
135 * parent */
136 bool isRoot;
138
139
140/*
141 * Delete a posting tree page.
142 *
143 * Removes the page identified by dBuffer from the posting tree by updating
144 * the left sibling's rightlink (in lBuffer) to skip over the deleted page,
145 * and removing the downlink from the parent page (in pBuffer). All three
146 * buffers must already have been pinned and exclusively locked by the caller.
147 *
148 * The buffers are NOT released nor unlocked here; the caller is responsible
149 * for this.
150 */
151static void
154{
155 Page page,
157 BlockNumber rightlink;
159
160 /*
161 * This function MUST be called only if someone of parent pages hold
162 * exclusive cleanup lock. This guarantees that no insertions currently
163 * happen in this subtree. Caller also acquires Exclusive locks on
164 * deletable, parent and left pages.
165 */
166
167 page = BufferGetPage(dBuffer);
168 rightlink = GinPageGetOpaque(page)->rightlink;
169
170 /*
171 * Any insert which would have gone on the leaf block will now go to its
172 * right sibling.
173 */
174 PredicateLockPageCombine(gvs->index, deleteBlkno, rightlink);
175
177
178 /* Unlink the page by changing left sibling's rightlink */
179 page = BufferGetPage(lBuffer);
180 GinPageGetOpaque(page)->rightlink = rightlink;
181
182 /* Delete downlink from parent */
184#ifdef USE_ASSERT_CHECKING
185 do
186 {
188
190 } while (0);
191#endif
193
194 page = BufferGetPage(dBuffer);
195
196 /*
197 * we shouldn't change rightlink field to save workability of running
198 * search scan
199 */
200
201 /*
202 * Mark page as deleted, and remember last xid which could know its
203 * address.
204 */
205 GinPageSetDeleted(page);
207
211
212 if (RelationNeedsWAL(gvs->index))
213 {
216
217 /*
218 * We can't pass REGBUF_STANDARD for the deleted page, because we
219 * didn't set pd_lower on pre-9.4 versions. The page might've been
220 * binary-upgraded from an older version, and hence not have pd_lower
221 * set correctly. Ditto for the left page, but removing the item from
222 * the parent updated its pd_lower, so we know that's OK at this
223 * point.
224 */
229
230 data.parentOffset = myoff;
231 data.rightLink = GinPageGetOpaque(page)->rightlink;
232 data.deleteXid = GinPageGetDeleteXid(page);
233
235
237 PageSetLSN(page, recptr);
240 }
241
243
244 gvs->result->pages_newly_deleted++;
245 gvs->result->pages_deleted++;
246}
247
248
249/*
250 * Scans a posting tree and deletes empty pages.
251 *
252 * The caller must hold a cleanup lock on the root page to prevent concurrent
253 * inserts. The entire path from the root down to the current page is kept
254 * exclusively locked throughout the scan. The left sibling at each level is
255 * also kept locked, because ginDeletePostingPage() needs it to update the
256 * rightlink of the left sibling; re-acquiring the left sibling lock later
257 * could deadlock with ginStepRight(), which acquires page locks
258 * left-to-right.
259 *
260 * All per-level state is carried in 'myStackItem': the buffer to process
261 * (must already be pinned and exclusively locked), the left sibling buffer,
262 * and this page's offset in the parent's downlink array. The root entry is
263 * set up by ginVacuumPostingTree(); child entries are populated here before
264 * recursing.
265 *
266 * Returns true if the page was deleted, false otherwise.
267 */
268static bool
270{
271 Buffer buffer = myStackItem->buffer;
272 Page page;
273 bool pageWasDeleted = false;
274 bool isempty;
275
276 page = BufferGetPage(buffer);
277
278 Assert(GinPageIsData(page));
279
280 if (!GinPageIsLeaf(page))
281 {
283
284 for (i = FirstOffsetNumber; i <= GinPageGetOpaque(page)->maxoff;)
285 {
288
292 RBM_NORMAL, gvs->strategy);
294
295 /* Allocate a child stack entry on first use; reuse thereafter */
296 if (!myStackItem->child)
297 {
299 myStackItem->child->parent = myStackItem;
300 myStackItem->child->leftBuffer = InvalidBuffer;
301 }
302
303 myStackItem->child->buffer = childBuffer;
304 myStackItem->child->isRoot = false;
305 myStackItem->child->myoff = i;
306
307 /*
308 * Recurse into child. If the child page was deleted, its
309 * downlink was removed from our page, so re-examine the same
310 * offset; otherwise advance to the next downlink.
311 */
313 i++;
314 }
315 myStackItem->buffer = InvalidBuffer;
316
317 /*
318 * After processing all children at this level, release the child
319 * level's leftBuffer if we're at the rightmost page. There is no
320 * right sibling that could need it for deletion.
321 */
322 if (GinPageRightMost(page) && BufferIsValid(myStackItem->child->leftBuffer))
323 {
324 UnlockReleaseBuffer(myStackItem->child->leftBuffer);
325 myStackItem->child->leftBuffer = InvalidBuffer;
326 }
327 }
328
329 if (GinPageIsLeaf(page))
331 else
333
334 if (isempty)
335 {
336 /*
337 * Proceed to the ginDeletePostingPage() if that's not the leftmost or
338 * the rightmost page.
339 */
340 if (BufferIsValid(myStackItem->leftBuffer) && !GinPageRightMost(page))
341 {
342 Assert(!myStackItem->isRoot);
344 myStackItem->parent->buffer,
345 myStackItem->myoff,
346 myStackItem->parent->isRoot);
347 pageWasDeleted = true;
348 }
349 }
350
351 if (!pageWasDeleted)
352 {
353 /*
354 * Keep this page as the new leftBuffer for this level: the next
355 * sibling to the right might need it for deletion. Release any
356 * previously held left page first.
357 */
358 if (BufferIsValid(myStackItem->leftBuffer))
359 UnlockReleaseBuffer(myStackItem->leftBuffer);
360 myStackItem->leftBuffer = buffer;
361 }
362 else
363 {
364 /*
365 * Page was deleted; release the buffer. leftBuffer remains the same.
366 */
368 }
369
370 return pageWasDeleted;
371}
372
373
374/*
375 * Scan through posting tree leafs, delete empty tuples. Returns true if there
376 * is at least one empty page.
377 */
378static bool
380{
382 Page page;
383 bool hasVoidPage = false;
385
386 /* Find leftmost leaf page of posting tree and lock it in exclusive mode */
387 while (true)
388 {
390
391 buffer = ReadBufferExtended(gvs->index, MAIN_FORKNUM, blkno,
392 RBM_NORMAL, gvs->strategy);
394 page = BufferGetPage(buffer);
395
396 Assert(GinPageIsData(page));
397
398 if (GinPageIsLeaf(page))
399 {
402 break;
403 }
404
406
409 Assert(blkno != InvalidBlockNumber);
410
412 }
413
414 /* Iterate all posting tree leaves using rightlinks and vacuum them */
415 while (true)
416 {
420 MemoryContextReset(gvs->tmpCxt);
421
422 if (GinDataLeafPageIsEmpty(page))
423 hasVoidPage = true;
424
425 blkno = GinPageGetOpaque(page)->rightlink;
426
428
429 if (blkno == InvalidBlockNumber)
430 break;
431
432 buffer = ReadBufferExtended(gvs->index, MAIN_FORKNUM, blkno,
433 RBM_NORMAL, gvs->strategy);
435 page = BufferGetPage(buffer);
436 }
437
438 return hasVoidPage;
439}
440
441static void
443{
444 if (ginVacuumPostingTreeLeaves(gvs, rootBlkno))
445 {
446 /*
447 * There is at least one empty page. So we have to rescan the tree
448 * deleting empty pages.
449 */
452 *ptr,
453 *tmp;
455
456 buffer = ReadBufferExtended(gvs->index, MAIN_FORKNUM, rootBlkno,
457 RBM_NORMAL, gvs->strategy);
458
459 /*
460 * Lock posting tree root for cleanup to ensure there are no
461 * concurrent inserts.
462 */
464
465 memset(&root, 0, sizeof(DataPageDeleteStack));
466 root.buffer = buffer;
467 root.leftBuffer = InvalidBuffer;
469 root.isRoot = true;
470
472 Assert(!deleted);
473
474 ptr = root.child;
475
476 while (ptr)
477 {
478 tmp = ptr->child;
479 pfree(ptr);
480 ptr = tmp;
481 }
482
484 }
485}
486
487/*
488 * returns modified page or NULL if page isn't modified.
489 * Function works with original page until first change is occurred,
490 * then page is copied into temporary one.
491 */
492static Page
494{
495 Page origpage = BufferGetPage(buffer),
496 tmppage;
498 maxoff = PageGetMaxOffsetNumber(origpage);
499
500 tmppage = origpage;
501
502 *nroot = 0;
503
504 for (i = FirstOffsetNumber; i <= maxoff; i++)
505 {
507
508 if (GinIsPostingTree(itup))
509 {
510 /*
511 * store posting tree's roots for further processing, we can't
512 * vacuum it just now due to risk of deadlocks with scans/inserts
513 */
514 roots[*nroot] = GinGetDownlink(itup);
515 (*nroot)++;
516 }
517 else if (GinGetNPosting(itup) > 0)
518 {
519 int nitems;
521 bool free_items_orig;
523
524 /* Get list of item pointers from the tuple. */
525 if (GinItupIsCompressed(itup))
526 {
528 free_items_orig = true;
529 }
530 else
531 {
533 nitems = GinGetNPosting(itup);
534 free_items_orig = false;
535 }
536
537 /* Remove any items from the list that need to be vacuumed. */
539
540 if (free_items_orig)
542
543 /* If any item pointers were removed, recreate the tuple. */
544 if (items)
545 {
547 Datum key;
548 GinNullCategory category;
550 int plistsize;
551
552 if (nitems > 0)
553 {
556 }
557 else
558 {
559 plist = NULL;
560 plistsize = 0;
561 }
562
563 /*
564 * if we already created a temporary page, make changes in
565 * place
566 */
567 if (tmppage == origpage)
568 {
569 /*
570 * On first difference, create a temporary copy of the
571 * page and copy the tuple's posting list to it.
572 */
573 tmppage = PageGetTempPageCopy(origpage);
574
575 /* set itup pointer to new page */
577 }
578
579 attnum = gintuple_get_attrnum(&gvs->ginstate, itup);
580 key = gintuple_get_key(&gvs->ginstate, itup, &category);
581 itup = GinFormTuple(&gvs->ginstate, attnum, key, category,
582 (char *) plist, plistsize,
583 nitems, true);
584 if (plist)
585 pfree(plist);
587
588 if (PageAddItem(tmppage, itup, IndexTupleSize(itup), i, false, false) != i)
589 elog(ERROR, "failed to add item to index page in \"%s\"",
591
592 pfree(itup);
593 pfree(items);
594 }
595 }
596 }
597
598 return (tmppage == origpage) ? NULL : tmppage;
599}
600
603 IndexBulkDeleteCallback callback, void *callback_state)
604{
605 Relation index = info->index;
611
613 "Gin vacuum temporary context",
615 gvs.index = index;
616 gvs.callback = callback;
617 gvs.callback_state = callback_state;
618 gvs.strategy = info->strategy;
619 initGinState(&gvs.ginstate, index);
620
621 /* first time through? */
622 if (stats == NULL)
623 {
624 /* Yes, so initialize stats to zeroes */
626
627 /*
628 * and cleanup any pending inserts
629 */
631 false, true, stats);
632 }
633
634 /* we'll re-count the tuples each time */
635 stats->num_index_tuples = 0;
636 gvs.result = stats;
637
639 RBM_NORMAL, info->strategy);
640
641 /* find leaf page */
642 for (;;)
643 {
644 Page page = BufferGetPage(buffer);
645 IndexTuple itup;
646
648
649 Assert(!GinPageIsData(page));
650
651 if (GinPageIsLeaf(page))
652 {
655
656 if (blkno == GIN_ROOT_BLKNO && !GinPageIsLeaf(page))
657 {
659 continue; /* check it one more */
660 }
661 break;
662 }
663
665
667 blkno = GinGetDownlink(itup);
668 Assert(blkno != InvalidBlockNumber);
669
672 RBM_NORMAL, info->strategy);
673 }
674
675 /* right now we found leftmost page in entry's BTree */
676
677 for (;;)
678 {
679 Page page = BufferGetPage(buffer);
681 uint32 i;
682
683 Assert(!GinPageIsData(page));
684
686
687 blkno = GinPageGetOpaque(page)->rightlink;
688
689 if (resPage)
690 {
694 xlogVacuumPage(gvs.index, buffer);
697 }
698 else
699 {
701 }
702
703 vacuum_delay_point(false);
704
705 for (i = 0; i < nRoot; i++)
706 {
708 vacuum_delay_point(false);
709 }
710
711 if (blkno == InvalidBlockNumber) /* rightmost page */
712 break;
713
715 RBM_NORMAL, info->strategy);
717 }
718
719 MemoryContextDelete(gvs.tmpCxt);
720
721 return gvs.result;
722}
723
726{
727 Relation index = info->index;
728 bool needLock;
729 BlockNumber npages,
730 blkno;
732 GinState ginstate;
735 ReadStream *stream;
736
737 /*
738 * In an autovacuum analyze, we want to clean up pending insertions.
739 * Otherwise, an ANALYZE-only call is a no-op.
740 */
741 if (info->analyze_only)
742 {
744 {
745 initGinState(&ginstate, index);
746 ginInsertCleanup(&ginstate, false, true, true, stats);
747 }
748 return stats;
749 }
750
751 /*
752 * Set up all-zero stats and cleanup pending inserts if ginbulkdelete
753 * wasn't called
754 */
755 if (stats == NULL)
756 {
758 initGinState(&ginstate, index);
760 false, true, stats);
761 }
762
763 memset(&idxStat, 0, sizeof(idxStat));
764
765 /*
766 * XXX we always report the heap tuple count as the number of index
767 * entries. This is bogus if the index is partial, but it's real hard to
768 * tell how many distinct heap entries are referenced by a GIN index.
769 */
770 stats->num_index_tuples = Max(info->num_heap_tuples, 0);
771 stats->estimated_count = info->estimated_count;
772
773 /*
774 * Need lock unless it's local to this backend.
775 */
777
778 if (needLock)
781 if (needLock)
783
784 totFreePages = 0;
785
786 /* Scan all blocks starting from the root using streaming reads */
788 p.last_exclusive = npages;
789
790 /*
791 * It is safe to use batchmode as block_range_read_stream_cb takes no
792 * locks.
793 */
797 info->strategy,
798 index,
801 &p,
802 0);
803
804 for (blkno = GIN_ROOT_BLKNO; blkno < npages; blkno++)
805 {
807 Page page;
808
809 vacuum_delay_point(false);
810
812
814 page = BufferGetPage(buffer);
815
816 if (GinPageIsRecyclable(page))
817 {
818 Assert(blkno != GIN_ROOT_BLKNO);
820 totFreePages++;
821 }
822 else if (GinPageIsData(page))
823 {
824 idxStat.nDataPages++;
825 }
826 else if (!GinPageIsList(page))
827 {
828 idxStat.nEntryPages++;
829
830 if (GinPageIsLeaf(page))
831 idxStat.nEntries += PageGetMaxOffsetNumber(page);
832 }
833
835 }
836
838 read_stream_end(stream);
839
840 /* Update the metapage with accurate page and entry counts */
841 idxStat.nTotalPages = npages;
842 ginUpdateStats(info->index, &idxStat, false);
843
844 /* Finally, vacuum the FSM */
846
847 stats->pages_free = totFreePages;
848
849 if (needLock)
852 if (needLock)
854
855 return stats;
856}
857
858/*
859 * Return whether Page can safely be recycled.
860 */
861bool
863{
865
866 if (PageIsNew(page))
867 return true;
868
869 if (!GinPageIsDeleted(page))
870 return false;
871
873
875 return true;
876
877 /*
878 * If no backend still could view delete_xid as in running, all scans
879 * concurrent with ginDeletePostingPage() must have finished.
880 */
882}
uint32 BlockNumber
Definition block.h:31
#define InvalidBlockNumber
Definition block.h:33
int Buffer
Definition buf.h:23
#define InvalidBuffer
Definition buf.h:25
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition bufmgr.c:4357
void UnlockReleaseBuffer(Buffer buffer)
Definition bufmgr.c:5522
void MarkBufferDirty(Buffer buffer)
Definition bufmgr.c:3063
void LockBufferForCleanup(Buffer buffer)
Definition bufmgr.c:6537
Buffer ReadBufferExtended(Relation reln, ForkNumber forkNum, BlockNumber blockNum, ReadBufferMode mode, BufferAccessStrategy strategy)
Definition bufmgr.c:921
#define RelationGetNumberOfBlocks(reln)
Definition bufmgr.h:307
static Page BufferGetPage(Buffer buffer)
Definition bufmgr.h:470
static void LockBuffer(Buffer buffer, BufferLockMode mode)
Definition bufmgr.h:332
@ RBM_NORMAL
Definition bufmgr.h:46
static bool BufferIsValid(Buffer bufnum)
Definition bufmgr.h:421
void PageRestoreTempPage(Page tempPage, Page oldPage)
Definition bufpage.c:423
Page PageGetTempPageCopy(const PageData *page)
Definition bufpage.c:381
void PageIndexTupleDelete(Page page, OffsetNumber offnum)
Definition bufpage.c:1051
static bool PageIsNew(const PageData *page)
Definition bufpage.h:259
static ItemId PageGetItemId(Page page, OffsetNumber offsetNumber)
Definition bufpage.h:269
static void * PageGetItem(PageData *page, const ItemIdData *itemId)
Definition bufpage.h:379
static void PageSetLSN(Page page, XLogRecPtr lsn)
Definition bufpage.h:417
PageData * Page
Definition bufpage.h:81
#define PageAddItem(page, item, size, offsetNumber, overwrite, is_heap)
Definition bufpage.h:504
static OffsetNumber PageGetMaxOffsetNumber(const PageData *page)
Definition bufpage.h:397
#define PG_USED_FOR_ASSERTS_ONLY
Definition c.h:243
#define Max(x, y)
Definition c.h:1087
#define Assert(condition)
Definition c.h:945
uint32_t uint32
Definition c.h:618
uint32 TransactionId
Definition c.h:738
#define ERROR
Definition elog.h:39
#define elog(elevel,...)
Definition elog.h:226
#define palloc_array(type, count)
Definition fe_memutils.h:76
#define palloc0_object(type)
Definition fe_memutils.h:75
bool(* IndexBulkDeleteCallback)(ItemPointer itemptr, void *state)
Definition genam.h:95
#define GIN_UNLOCK
Definition gin_private.h:51
#define GIN_EXCLUSIVE
Definition gin_private.h:53
#define GIN_SHARE
Definition gin_private.h:52
#define GinPageGetDeleteXid(page)
Definition ginblock.h:135
#define GinIsPostingTree(itup)
Definition ginblock.h:231
#define GinPageGetOpaque(page)
Definition ginblock.h:110
#define GinGetPosting(itup)
Definition ginblock.h:238
#define SizeOfGinPostingList(plist)
Definition ginblock.h:342
#define GinPageSetDeleteXid(page, xid)
Definition ginblock.h:136
#define GinPageIsList(page)
Definition ginblock.h:117
#define GIN_ROOT_BLKNO
Definition ginblock.h:52
#define GinGetDownlink(itup)
Definition ginblock.h:257
#define GinItupIsCompressed(itup)
Definition ginblock.h:239
#define GinGetNPosting(itup)
Definition ginblock.h:228
#define GinPageIsData(page)
Definition ginblock.h:115
signed char GinNullCategory
Definition ginblock.h:206
#define GinPageRightMost(page)
Definition ginblock.h:129
#define GinDataPageGetPostingItem(page, i)
Definition ginblock.h:298
#define PostingItemGetBlockNumber(pointer)
Definition ginblock.h:189
#define GinDataLeafPageIsEmpty(page)
Definition ginblock.h:283
#define GinPageIsDeleted(page)
Definition ginblock.h:124
#define GinPageSetDeleted(page)
Definition ginblock.h:125
#define GinMaxItemSize
Definition ginblock.h:248
#define GinPageIsLeaf(page)
Definition ginblock.h:112
void GinPageDeletePostingItem(Page page, OffsetNumber offset)
void ginVacuumPostingTreeLeaf(Relation indexrel, Buffer buffer, GinVacuumState *gvs)
IndexTuple GinFormTuple(GinState *ginstate, OffsetNumber attnum, Datum key, GinNullCategory category, Pointer data, Size dataSize, int nipd, bool errorTooBig)
void ginInsertCleanup(GinState *ginstate, bool full_clean, bool fill_fsm, bool forceCleanup, IndexBulkDeleteResult *stats)
Definition ginfast.c:780
GinPostingList * ginCompressPostingList(const ItemPointerData *ipd, int nipd, int maxsize, int *nwritten)
ItemPointer ginPostingListDecode(GinPostingList *plist, int *ndecoded_out)
OffsetNumber gintuple_get_attrnum(GinState *ginstate, IndexTuple tuple)
Definition ginutil.c:233
Datum gintuple_get_key(GinState *ginstate, IndexTuple tuple, GinNullCategory *category)
Definition ginutil.c:266
void initGinState(GinState *state, Relation index)
Definition ginutil.c:103
void ginUpdateStats(Relation index, const GinStatsData *stats, bool is_build)
Definition ginutil.c:619
static bool ginVacuumPostingTreeLeaves(GinVacuumState *gvs, BlockNumber blkno)
Definition ginvacuum.c:379
static void xlogVacuumPage(Relation index, Buffer buffer)
Definition ginvacuum.c:90
ItemPointer ginVacuumItemPointers(GinVacuumState *gvs, ItemPointerData *items, int nitem, int *nremaining)
Definition ginvacuum.c:48
static void ginDeletePostingPage(GinVacuumState *gvs, Buffer dBuffer, Buffer lBuffer, Buffer pBuffer, OffsetNumber myoff, bool isParentRoot)
Definition ginvacuum.c:152
bool GinPageIsRecyclable(Page page)
Definition ginvacuum.c:862
static bool ginScanPostingTreeToDelete(GinVacuumState *gvs, DataPageDeleteStack *myStackItem)
Definition ginvacuum.c:269
static void ginVacuumPostingTree(GinVacuumState *gvs, BlockNumber rootBlkno)
Definition ginvacuum.c:442
IndexBulkDeleteResult * ginbulkdelete(IndexVacuumInfo *info, IndexBulkDeleteResult *stats, IndexBulkDeleteCallback callback, void *callback_state)
Definition ginvacuum.c:602
static Page ginVacuumEntryPage(GinVacuumState *gvs, Buffer buffer, BlockNumber *roots, uint32 *nroot)
Definition ginvacuum.c:493
IndexBulkDeleteResult * ginvacuumcleanup(IndexVacuumInfo *info, IndexBulkDeleteResult *stats)
Definition ginvacuum.c:725
#define XLOG_GIN_VACUUM_PAGE
Definition ginxlog.h:135
#define XLOG_GIN_DELETE_PAGE
Definition ginxlog.h:153
#define nitems(x)
Definition indent.h:31
void IndexFreeSpaceMapVacuum(Relation rel)
Definition indexfsm.c:71
void RecordFreeIndexPage(Relation rel, BlockNumber freeBlock)
Definition indexfsm.c:52
int remaining
Definition informix.c:692
int i
Definition isn.c:77
ItemPointerData * ItemPointer
Definition itemptr.h:49
IndexTupleData * IndexTuple
Definition itup.h:53
static Size IndexTupleSize(const IndexTupleData *itup)
Definition itup.h:71
void LockRelationForExtension(Relation relation, LOCKMODE lockmode)
Definition lmgr.c:424
void UnlockRelationForExtension(Relation relation, LOCKMODE lockmode)
Definition lmgr.c:474
#define ExclusiveLock
Definition lockdefs.h:42
void MemoryContextReset(MemoryContext context)
Definition mcxt.c:403
void pfree(void *pointer)
Definition mcxt.c:1616
MemoryContext CurrentMemoryContext
Definition mcxt.c:160
void MemoryContextDelete(MemoryContext context)
Definition mcxt.c:472
#define AllocSetContextCreate
Definition memutils.h:129
#define ALLOCSET_DEFAULT_SIZES
Definition memutils.h:160
#define AmAutoVacuumWorkerProcess()
Definition miscadmin.h:383
#define START_CRIT_SECTION()
Definition miscadmin.h:150
#define END_CRIT_SECTION()
Definition miscadmin.h:152
#define InvalidOffsetNumber
Definition off.h:26
uint16 OffsetNumber
Definition off.h:24
#define FirstOffsetNumber
Definition off.h:27
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition palloc.h:124
int16 attnum
const void * data
uint64_t Datum
Definition postgres.h:70
void PredicateLockPageCombine(Relation relation, BlockNumber oldblkno, BlockNumber newblkno)
Definition predicate.c:3238
static int fb(int x)
bool GlobalVisCheckRemovableXid(Relation rel, TransactionId xid)
Definition procarray.c:4340
tree ctl root
Definition radixtree.h:1857
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_MAINTENANCE
Definition read_stream.h:28
#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
#define RelationGetRelationName(relation)
Definition rel.h:548
#define RelationNeedsWAL(relation)
Definition rel.h:637
@ MAIN_FORKNUM
Definition relpath.h:58
struct DataPageDeleteStack * parent
Definition ginvacuum.c:128
OffsetNumber myoff
Definition ginvacuum.c:134
struct DataPageDeleteStack * child
Definition ginvacuum.c:127
MemoryContext tmpCxt
Definition ginvacuum.c:36
BufferAccessStrategy strategy
Definition ginvacuum.c:35
IndexBulkDeleteCallback callback
Definition ginvacuum.c:32
IndexBulkDeleteResult * result
Definition ginvacuum.c:31
void * callback_state
Definition ginvacuum.c:33
GinState ginstate
Definition ginvacuum.c:34
Relation index
Definition ginvacuum.c:30
BlockNumber pages_free
Definition genam.h:91
BlockNumber num_pages
Definition genam.h:85
double num_index_tuples
Definition genam.h:87
Relation index
Definition genam.h:54
double num_heap_tuples
Definition genam.h:60
bool analyze_only
Definition genam.h:56
BufferAccessStrategy strategy
Definition genam.h:61
bool estimated_count
Definition genam.h:58
Definition type.h:96
static void callback(struct sockaddr *addr, struct sockaddr *mask, void *unused)
static ItemArray items
static TransactionId ReadNextTransactionId(void)
Definition transam.h:377
#define TransactionIdIsValid(xid)
Definition transam.h:41
void vacuum_delay_point(bool is_analyze)
Definition vacuum.c:2431
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 XLogRegisterBuffer(uint8 block_id, Buffer buffer, uint8 flags)
Definition xloginsert.c:246
void XLogBeginInsert(void)
Definition xloginsert.c:153
#define REGBUF_STANDARD
Definition xloginsert.h:35
#define REGBUF_FORCE_IMAGE
Definition xloginsert.h:32