PostgreSQL Source Code git master
Loading...
Searching...
No Matches
ginvacuum.c File Reference
#include "postgres.h"
#include "access/gin_private.h"
#include "access/ginxlog.h"
#include "access/xloginsert.h"
#include "commands/vacuum.h"
#include "miscadmin.h"
#include "storage/indexfsm.h"
#include "storage/lmgr.h"
#include "storage/predicate.h"
#include "storage/read_stream.h"
#include "utils/memutils.h"
Include dependency graph for ginvacuum.c:

Go to the source code of this file.

Data Structures

struct  GinVacuumState
 
struct  DataPageDeleteStack
 

Typedefs

typedef struct DataPageDeleteStack DataPageDeleteStack
 

Functions

ItemPointer ginVacuumItemPointers (GinVacuumState *gvs, ItemPointerData *items, int nitem, int *nremaining)
 
static void xlogVacuumPage (Relation index, Buffer buffer)
 
static void ginDeletePostingPage (GinVacuumState *gvs, Buffer dBuffer, Buffer lBuffer, Buffer pBuffer, OffsetNumber myoff, bool isParentRoot)
 
static bool ginScanPostingTreeToDelete (GinVacuumState *gvs, DataPageDeleteStack *myStackItem)
 
static bool ginVacuumPostingTreeLeaves (GinVacuumState *gvs, BlockNumber blkno)
 
static void ginVacuumPostingTree (GinVacuumState *gvs, BlockNumber rootBlkno)
 
static Page ginVacuumEntryPage (GinVacuumState *gvs, Buffer buffer, BlockNumber *roots, uint32 *nroot)
 
IndexBulkDeleteResultginbulkdelete (IndexVacuumInfo *info, IndexBulkDeleteResult *stats, IndexBulkDeleteCallback callback, void *callback_state)
 
IndexBulkDeleteResultginvacuumcleanup (IndexVacuumInfo *info, IndexBulkDeleteResult *stats)
 
bool GinPageIsRecyclable (Page page)
 

Typedef Documentation

◆ DataPageDeleteStack

Function Documentation

◆ ginbulkdelete()

IndexBulkDeleteResult * ginbulkdelete ( IndexVacuumInfo info,
IndexBulkDeleteResult stats,
IndexBulkDeleteCallback  callback,
void callback_state 
)

Definition at line 602 of file ginvacuum.c.

604{
605 Relation index = info->index;
608 Buffer buffer;
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
638 buffer = ReadBufferExtended(index, MAIN_FORKNUM, blkno,
639 RBM_NORMAL, info->strategy);
640
641 /* find leaf page */
642 for (;;)
643 {
644 Page page = BufferGetPage(buffer);
645 IndexTuple itup;
646
647 LockBuffer(buffer, GIN_SHARE);
648
649 Assert(!GinPageIsData(page));
650
651 if (GinPageIsLeaf(page))
652 {
653 LockBuffer(buffer, GIN_UNLOCK);
654 LockBuffer(buffer, GIN_EXCLUSIVE);
655
656 if (blkno == GIN_ROOT_BLKNO && !GinPageIsLeaf(page))
657 {
658 LockBuffer(buffer, GIN_UNLOCK);
659 continue; /* check it one more */
660 }
661 break;
662 }
663
665
667 blkno = GinGetDownlink(itup);
668 Assert(blkno != InvalidBlockNumber);
669
670 UnlockReleaseBuffer(buffer);
671 buffer = ReadBufferExtended(index, MAIN_FORKNUM, blkno,
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 {
693 MarkBufferDirty(buffer);
694 xlogVacuumPage(gvs.index, buffer);
696 UnlockReleaseBuffer(buffer);
697 }
698 else
699 {
700 UnlockReleaseBuffer(buffer);
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
714 buffer = ReadBufferExtended(index, MAIN_FORKNUM, blkno,
715 RBM_NORMAL, info->strategy);
716 LockBuffer(buffer, GIN_EXCLUSIVE);
717 }
718
719 MemoryContextDelete(gvs.tmpCxt);
720
721 return gvs.result;
722}
uint32 BlockNumber
Definition block.h:31
#define InvalidBlockNumber
Definition block.h:33
int Buffer
Definition buf.h:23
void UnlockReleaseBuffer(Buffer buffer)
Definition bufmgr.c:5522
void MarkBufferDirty(Buffer buffer)
Definition bufmgr.c:3063
Buffer ReadBufferExtended(Relation reln, ForkNumber forkNum, BlockNumber blockNum, ReadBufferMode mode, BufferAccessStrategy strategy)
Definition bufmgr.c:921
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
void PageRestoreTempPage(Page tempPage, Page oldPage)
Definition bufpage.c:423
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
#define Assert(condition)
Definition c.h:945
uint32_t uint32
Definition c.h:618
#define palloc0_object(type)
Definition fe_memutils.h:75
#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 GinPageGetOpaque(page)
Definition ginblock.h:110
#define GIN_ROOT_BLKNO
Definition ginblock.h:52
#define GinGetDownlink(itup)
Definition ginblock.h:257
#define GinPageIsData(page)
Definition ginblock.h:115
#define GinPageIsLeaf(page)
Definition ginblock.h:112
void ginInsertCleanup(GinState *ginstate, bool full_clean, bool fill_fsm, bool forceCleanup, IndexBulkDeleteResult *stats)
Definition ginfast.c:780
void initGinState(GinState *state, Relation index)
Definition ginutil.c:103
static void xlogVacuumPage(Relation index, Buffer buffer)
Definition ginvacuum.c:90
static void ginVacuumPostingTree(GinVacuumState *gvs, BlockNumber rootBlkno)
Definition ginvacuum.c:442
static Page ginVacuumEntryPage(GinVacuumState *gvs, Buffer buffer, BlockNumber *roots, uint32 *nroot)
Definition ginvacuum.c:493
int i
Definition isn.c:77
IndexTupleData * IndexTuple
Definition itup.h:53
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 FirstOffsetNumber
Definition off.h:27
static int fb(int x)
@ MAIN_FORKNUM
Definition relpath.h:58
MemoryContext tmpCxt
Definition ginvacuum.c:36
double num_index_tuples
Definition genam.h:87
Relation index
Definition genam.h:54
BufferAccessStrategy strategy
Definition genam.h:61
Definition type.h:96
static void callback(struct sockaddr *addr, struct sockaddr *mask, void *unused)
void vacuum_delay_point(bool is_analyze)
Definition vacuum.c:2431

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, AmAutoVacuumWorkerProcess, Assert, DataPageDeleteStack::buffer, BufferGetPage(), callback(), CurrentMemoryContext, END_CRIT_SECTION, fb(), FirstOffsetNumber, GIN_EXCLUSIVE, GIN_ROOT_BLKNO, GIN_SHARE, GIN_UNLOCK, GinGetDownlink, ginInsertCleanup(), GinPageGetOpaque, GinPageIsData, GinPageIsLeaf, ginVacuumEntryPage(), ginVacuumPostingTree(), i, IndexVacuumInfo::index, initGinState(), InvalidBlockNumber, LockBuffer(), MAIN_FORKNUM, MarkBufferDirty(), MemoryContextDelete(), IndexBulkDeleteResult::num_index_tuples, PageGetItem(), PageGetItemId(), PageGetMaxOffsetNumber(), PageRestoreTempPage(), palloc0_object, RBM_NORMAL, ReadBufferExtended(), START_CRIT_SECTION, IndexVacuumInfo::strategy, GinVacuumState::tmpCxt, UnlockReleaseBuffer(), vacuum_delay_point(), and xlogVacuumPage().

Referenced by ginhandler().

◆ ginDeletePostingPage()

static void ginDeletePostingPage ( GinVacuumState gvs,
Buffer  dBuffer,
Buffer  lBuffer,
Buffer  pBuffer,
OffsetNumber  myoff,
bool  isParentRoot 
)
static

Definition at line 152 of file ginvacuum.c.

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}
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition bufmgr.c:4357
static void PageSetLSN(Page page, XLogRecPtr lsn)
Definition bufpage.h:417
#define GinPageGetDeleteXid(page)
Definition ginblock.h:135
#define GinPageSetDeleteXid(page, xid)
Definition ginblock.h:136
#define GinDataPageGetPostingItem(page, i)
Definition ginblock.h:298
#define PostingItemGetBlockNumber(pointer)
Definition ginblock.h:189
#define GinPageSetDeleted(page)
Definition ginblock.h:125
void GinPageDeletePostingItem(Page page, OffsetNumber offset)
#define XLOG_GIN_DELETE_PAGE
Definition ginxlog.h:153
const void * data
void PredicateLockPageCombine(Relation relation, BlockNumber oldblkno, BlockNumber newblkno)
Definition predicate.c:3238
#define RelationNeedsWAL(relation)
Definition rel.h:637
static TransactionId ReadNextTransactionId(void)
Definition transam.h:377
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

References Assert, BufferGetBlockNumber(), BufferGetPage(), data, END_CRIT_SECTION, fb(), GinDataPageGetPostingItem, GinPageDeletePostingItem(), GinPageGetDeleteXid, GinPageGetOpaque, GinPageSetDeleted, GinPageSetDeleteXid, MarkBufferDirty(), DataPageDeleteStack::myoff, PageSetLSN(), PostingItemGetBlockNumber, PredicateLockPageCombine(), ReadNextTransactionId(), REGBUF_STANDARD, RelationNeedsWAL, START_CRIT_SECTION, XLOG_GIN_DELETE_PAGE, XLogBeginInsert(), XLogInsert(), XLogRegisterBuffer(), and XLogRegisterData().

Referenced by ginScanPostingTreeToDelete().

◆ GinPageIsRecyclable()

bool GinPageIsRecyclable ( Page  page)

Definition at line 862 of file ginvacuum.c.

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}
static bool PageIsNew(const PageData *page)
Definition bufpage.h:259
uint32 TransactionId
Definition c.h:738
#define GinPageIsDeleted(page)
Definition ginblock.h:124
bool GlobalVisCheckRemovableXid(Relation rel, TransactionId xid)
Definition procarray.c:4307
#define TransactionIdIsValid(xid)
Definition transam.h:41

References fb(), GinPageGetDeleteXid, GinPageIsDeleted, GlobalVisCheckRemovableXid(), PageIsNew(), and TransactionIdIsValid.

Referenced by GinNewBuffer(), and ginvacuumcleanup().

◆ ginScanPostingTreeToDelete()

static bool ginScanPostingTreeToDelete ( GinVacuumState gvs,
DataPageDeleteStack myStackItem 
)
static

Definition at line 269 of file ginvacuum.c.

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);
343 ginDeletePostingPage(gvs, buffer, myStackItem->leftBuffer,
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 */
367 UnlockReleaseBuffer(buffer);
368 }
369
370 return pageWasDeleted;
371}
#define InvalidBuffer
Definition buf.h:25
static bool BufferIsValid(Buffer bufnum)
Definition bufmgr.h:421
#define GinPageRightMost(page)
Definition ginblock.h:129
#define GinDataLeafPageIsEmpty(page)
Definition ginblock.h:283
static void ginDeletePostingPage(GinVacuumState *gvs, Buffer dBuffer, Buffer lBuffer, Buffer pBuffer, OffsetNumber myoff, bool isParentRoot)
Definition ginvacuum.c:152
static bool ginScanPostingTreeToDelete(GinVacuumState *gvs, DataPageDeleteStack *myStackItem)
Definition ginvacuum.c:269
uint16 OffsetNumber
Definition off.h:24

References Assert, DataPageDeleteStack::buffer, BufferGetPage(), BufferIsValid(), fb(), FirstOffsetNumber, GIN_EXCLUSIVE, GinDataLeafPageIsEmpty, GinDataPageGetPostingItem, ginDeletePostingPage(), GinPageGetOpaque, GinPageIsData, GinPageIsLeaf, GinPageRightMost, ginScanPostingTreeToDelete(), i, InvalidBuffer, LockBuffer(), MAIN_FORKNUM, palloc0_object, PostingItemGetBlockNumber, RBM_NORMAL, ReadBufferExtended(), and UnlockReleaseBuffer().

Referenced by ginScanPostingTreeToDelete(), and ginVacuumPostingTree().

◆ ginvacuumcleanup()

IndexBulkDeleteResult * ginvacuumcleanup ( IndexVacuumInfo info,
IndexBulkDeleteResult stats 
)

Definition at line 725 of file ginvacuum.c.

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 {
806 Buffer buffer;
807 Page page;
808
809 vacuum_delay_point(false);
810
811 buffer = read_stream_next_buffer(stream, NULL);
812
813 LockBuffer(buffer, GIN_SHARE);
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
834 UnlockReleaseBuffer(buffer);
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}
#define RelationGetNumberOfBlocks(reln)
Definition bufmgr.h:307
#define Max(x, y)
Definition c.h:1087
#define GinPageIsList(page)
Definition ginblock.h:117
void ginUpdateStats(Relation index, const GinStatsData *stats, bool is_build)
Definition ginutil.c:619
bool GinPageIsRecyclable(Page page)
Definition ginvacuum.c:862
void IndexFreeSpaceMapVacuum(Relation rel)
Definition indexfsm.c:71
void RecordFreeIndexPage(Relation rel, BlockNumber freeBlock)
Definition indexfsm.c:52
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
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
BlockNumber pages_free
Definition genam.h:91
BlockNumber num_pages
Definition genam.h:85
double num_heap_tuples
Definition genam.h:60
bool analyze_only
Definition genam.h:56
bool estimated_count
Definition genam.h:58

References AmAutoVacuumWorkerProcess, IndexVacuumInfo::analyze_only, Assert, block_range_read_stream_cb(), DataPageDeleteStack::buffer, BufferGetPage(), BlockRangeReadStreamPrivate::current_blocknum, IndexVacuumInfo::estimated_count, IndexBulkDeleteResult::estimated_count, ExclusiveLock, fb(), GIN_ROOT_BLKNO, GIN_SHARE, ginInsertCleanup(), GinPageIsData, GinPageIsLeaf, GinPageIsList, GinPageIsRecyclable(), ginUpdateStats(), IndexVacuumInfo::index, IndexFreeSpaceMapVacuum(), initGinState(), InvalidBuffer, BlockRangeReadStreamPrivate::last_exclusive, LockBuffer(), LockRelationForExtension(), MAIN_FORKNUM, Max, IndexVacuumInfo::num_heap_tuples, IndexBulkDeleteResult::num_index_tuples, IndexBulkDeleteResult::num_pages, PageGetMaxOffsetNumber(), IndexBulkDeleteResult::pages_free, palloc0_object, read_stream_begin_relation(), read_stream_end(), READ_STREAM_FULL, READ_STREAM_MAINTENANCE, read_stream_next_buffer(), READ_STREAM_USE_BATCHING, RecordFreeIndexPage(), RELATION_IS_LOCAL, RelationGetNumberOfBlocks, IndexVacuumInfo::strategy, UnlockRelationForExtension(), UnlockReleaseBuffer(), and vacuum_delay_point().

Referenced by ginhandler().

◆ ginVacuumEntryPage()

static Page ginVacuumEntryPage ( GinVacuumState gvs,
Buffer  buffer,
BlockNumber roots,
uint32 nroot 
)
static

Definition at line 493 of file ginvacuum.c.

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}
Page PageGetTempPageCopy(const PageData *page)
Definition bufpage.c:381
void PageIndexTupleDelete(Page page, OffsetNumber offnum)
Definition bufpage.c:1051
#define PageAddItem(page, item, size, offsetNumber, overwrite, is_heap)
Definition bufpage.h:504
#define ERROR
Definition elog.h:39
#define elog(elevel,...)
Definition elog.h:226
#define GinIsPostingTree(itup)
Definition ginblock.h:231
#define GinGetPosting(itup)
Definition ginblock.h:238
#define SizeOfGinPostingList(plist)
Definition ginblock.h:342
#define GinItupIsCompressed(itup)
Definition ginblock.h:239
#define GinGetNPosting(itup)
Definition ginblock.h:228
signed char GinNullCategory
Definition ginblock.h:206
#define GinMaxItemSize
Definition ginblock.h:248
IndexTuple GinFormTuple(GinState *ginstate, OffsetNumber attnum, Datum key, GinNullCategory category, Pointer data, Size dataSize, int nipd, bool errorTooBig)
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
ItemPointer ginVacuumItemPointers(GinVacuumState *gvs, ItemPointerData *items, int nitem, int *nremaining)
Definition ginvacuum.c:48
#define nitems(x)
Definition indent.h:31
ItemPointerData * ItemPointer
Definition itemptr.h:49
static Size IndexTupleSize(const IndexTupleData *itup)
Definition itup.h:71
void pfree(void *pointer)
Definition mcxt.c:1616
int16 attnum
uint64_t Datum
Definition postgres.h:70
#define RelationGetRelationName(relation)
Definition rel.h:548
static ItemArray items

References attnum, DataPageDeleteStack::buffer, BufferGetPage(), elog, ERROR, fb(), FirstOffsetNumber, ginCompressPostingList(), GinFormTuple(), GinGetDownlink, GinGetNPosting, GinGetPosting, GinIsPostingTree, GinItupIsCompressed, GinMaxItemSize, ginPostingListDecode(), gintuple_get_attrnum(), gintuple_get_key(), ginVacuumItemPointers(), i, IndexTupleSize(), items, nitems, PageAddItem, PageGetItem(), PageGetItemId(), PageGetMaxOffsetNumber(), PageGetTempPageCopy(), PageIndexTupleDelete(), pfree(), RelationGetRelationName, and SizeOfGinPostingList.

Referenced by ginbulkdelete().

◆ ginVacuumItemPointers()

ItemPointer ginVacuumItemPointers ( GinVacuumState gvs,
ItemPointerData items,
int  nitem,
int nremaining 
)

Definition at line 48 of file ginvacuum.c.

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}
#define palloc_array(type, count)
Definition fe_memutils.h:76
int remaining
Definition informix.c:692

References fb(), i, items, palloc_array, and remaining.

Referenced by ginVacuumEntryPage(), and ginVacuumPostingTreeLeaf().

◆ ginVacuumPostingTree()

static void ginVacuumPostingTree ( GinVacuumState gvs,
BlockNumber  rootBlkno 
)
static

Definition at line 442 of file ginvacuum.c.

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 */
450 Buffer buffer;
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 */
463 LockBufferForCleanup(buffer);
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
483 UnlockReleaseBuffer(buffer);
484 }
485}
void LockBufferForCleanup(Buffer buffer)
Definition bufmgr.c:6537
#define PG_USED_FOR_ASSERTS_ONLY
Definition c.h:243
static bool ginVacuumPostingTreeLeaves(GinVacuumState *gvs, BlockNumber blkno)
Definition ginvacuum.c:379
#define InvalidOffsetNumber
Definition off.h:26
tree ctl root
Definition radixtree.h:1857
struct DataPageDeleteStack * child
Definition ginvacuum.c:127

References Assert, DataPageDeleteStack::buffer, DataPageDeleteStack::child, fb(), ginScanPostingTreeToDelete(), ginVacuumPostingTreeLeaves(), InvalidBuffer, InvalidOffsetNumber, LockBufferForCleanup(), MAIN_FORKNUM, pfree(), PG_USED_FOR_ASSERTS_ONLY, RBM_NORMAL, ReadBufferExtended(), root, and UnlockReleaseBuffer().

Referenced by ginbulkdelete().

◆ ginVacuumPostingTreeLeaves()

static bool ginVacuumPostingTreeLeaves ( GinVacuumState gvs,
BlockNumber  blkno 
)
static

Definition at line 379 of file ginvacuum.c.

380{
381 Buffer buffer;
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);
393 LockBuffer(buffer, GIN_SHARE);
394 page = BufferGetPage(buffer);
395
396 Assert(GinPageIsData(page));
397
398 if (GinPageIsLeaf(page))
399 {
400 LockBuffer(buffer, GIN_UNLOCK);
401 LockBuffer(buffer, GIN_EXCLUSIVE);
402 break;
403 }
404
406
409 Assert(blkno != InvalidBlockNumber);
410
411 UnlockReleaseBuffer(buffer);
412 }
413
414 /* Iterate all posting tree leaves using rightlinks and vacuum them */
415 while (true)
416 {
418 ginVacuumPostingTreeLeaf(gvs->index, buffer, gvs);
420 MemoryContextReset(gvs->tmpCxt);
421
422 if (GinDataLeafPageIsEmpty(page))
423 hasVoidPage = true;
424
425 blkno = GinPageGetOpaque(page)->rightlink;
426
427 UnlockReleaseBuffer(buffer);
428
429 if (blkno == InvalidBlockNumber)
430 break;
431
432 buffer = ReadBufferExtended(gvs->index, MAIN_FORKNUM, blkno,
433 RBM_NORMAL, gvs->strategy);
434 LockBuffer(buffer, GIN_EXCLUSIVE);
435 page = BufferGetPage(buffer);
436 }
437
438 return hasVoidPage;
439}
void ginVacuumPostingTreeLeaf(Relation indexrel, Buffer buffer, GinVacuumState *gvs)
void MemoryContextReset(MemoryContext context)
Definition mcxt.c:403
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition palloc.h:124

References Assert, DataPageDeleteStack::buffer, BufferGetPage(), fb(), FirstOffsetNumber, GIN_EXCLUSIVE, GIN_SHARE, GIN_UNLOCK, GinDataLeafPageIsEmpty, GinDataPageGetPostingItem, GinPageGetOpaque, GinPageIsData, GinPageIsLeaf, ginVacuumPostingTreeLeaf(), InvalidBlockNumber, LockBuffer(), MAIN_FORKNUM, MemoryContextReset(), MemoryContextSwitchTo(), PageGetMaxOffsetNumber(), PostingItemGetBlockNumber, RBM_NORMAL, ReadBufferExtended(), and UnlockReleaseBuffer().

Referenced by ginVacuumPostingTree().

◆ xlogVacuumPage()

static void xlogVacuumPage ( Relation  index,
Buffer  buffer 
)
static

Definition at line 90 of file ginvacuum.c.

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}
#define XLOG_GIN_VACUUM_PAGE
Definition ginxlog.h:135
#define REGBUF_FORCE_IMAGE
Definition xloginsert.h:32

References Assert, BufferGetPage(), fb(), GinPageIsData, GinPageIsLeaf, PageSetLSN(), REGBUF_FORCE_IMAGE, REGBUF_STANDARD, RelationNeedsWAL, XLOG_GIN_VACUUM_PAGE, XLogBeginInsert(), XLogInsert(), and XLogRegisterBuffer().

Referenced by ginbulkdelete().