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 "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 ginDeletePage (GinVacuumState *gvs, BlockNumber deleteBlkno, BlockNumber leftBlkno, BlockNumber parentBlkno, OffsetNumber myoff, bool isParentRoot)
 
static bool ginScanToDelete (GinVacuumState *gvs, BlockNumber blkno, bool isRoot, DataPageDeleteStack *parent, OffsetNumber myoff)
 
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 564 of file ginvacuum.c.

566{
567 Relation index = info->index;
570 Buffer buffer;
573
575 "Gin vacuum temporary context",
577 gvs.index = index;
578 gvs.callback = callback;
579 gvs.callback_state = callback_state;
580 gvs.strategy = info->strategy;
581 initGinState(&gvs.ginstate, index);
582
583 /* first time through? */
584 if (stats == NULL)
585 {
586 /* Yes, so initialize stats to zeroes */
588
589 /*
590 * and cleanup any pending inserts
591 */
593 false, true, stats);
594 }
595
596 /* we'll re-count the tuples each time */
597 stats->num_index_tuples = 0;
598 gvs.result = stats;
599
600 buffer = ReadBufferExtended(index, MAIN_FORKNUM, blkno,
601 RBM_NORMAL, info->strategy);
602
603 /* find leaf page */
604 for (;;)
605 {
606 Page page = BufferGetPage(buffer);
607 IndexTuple itup;
608
609 LockBuffer(buffer, GIN_SHARE);
610
611 Assert(!GinPageIsData(page));
612
613 if (GinPageIsLeaf(page))
614 {
615 LockBuffer(buffer, GIN_UNLOCK);
616 LockBuffer(buffer, GIN_EXCLUSIVE);
617
618 if (blkno == GIN_ROOT_BLKNO && !GinPageIsLeaf(page))
619 {
620 LockBuffer(buffer, GIN_UNLOCK);
621 continue; /* check it one more */
622 }
623 break;
624 }
625
627
629 blkno = GinGetDownlink(itup);
630 Assert(blkno != InvalidBlockNumber);
631
632 UnlockReleaseBuffer(buffer);
633 buffer = ReadBufferExtended(index, MAIN_FORKNUM, blkno,
634 RBM_NORMAL, info->strategy);
635 }
636
637 /* right now we found leftmost page in entry's BTree */
638
639 for (;;)
640 {
641 Page page = BufferGetPage(buffer);
643 uint32 i;
644
645 Assert(!GinPageIsData(page));
646
648
649 blkno = GinPageGetOpaque(page)->rightlink;
650
651 if (resPage)
652 {
655 MarkBufferDirty(buffer);
656 xlogVacuumPage(gvs.index, buffer);
657 UnlockReleaseBuffer(buffer);
659 }
660 else
661 {
662 UnlockReleaseBuffer(buffer);
663 }
664
665 vacuum_delay_point(false);
666
667 for (i = 0; i < nRoot; i++)
668 {
670 vacuum_delay_point(false);
671 }
672
673 if (blkno == InvalidBlockNumber) /* rightmost page */
674 break;
675
676 buffer = ReadBufferExtended(index, MAIN_FORKNUM, blkno,
677 RBM_NORMAL, info->strategy);
678 LockBuffer(buffer, GIN_EXCLUSIVE);
679 }
680
681 MemoryContextDelete(gvs.tmpCxt);
682
683 return gvs.result;
684}
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:5518
void MarkBufferDirty(Buffer buffer)
Definition bufmgr.c:3056
Buffer ReadBufferExtended(Relation reln, ForkNumber forkNum, BlockNumber blockNum, ReadBufferMode mode, BufferAccessStrategy strategy)
Definition bufmgr.c:911
static Page BufferGetPage(Buffer buffer)
Definition bufmgr.h:466
static void LockBuffer(Buffer buffer, BufferLockMode mode)
Definition bufmgr.h:328
@ 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:243
static void * PageGetItem(PageData *page, const ItemIdData *itemId)
Definition bufpage.h:353
PageData * Page
Definition bufpage.h:81
static OffsetNumber PageGetMaxOffsetNumber(const PageData *page)
Definition bufpage.h:371
#define Assert(condition)
Definition c.h:873
uint32_t uint32
Definition c.h:546
#define palloc0_object(type)
Definition fe_memutils.h:75
#define GIN_UNLOCK
Definition gin_private.h:50
#define GIN_EXCLUSIVE
Definition gin_private.h:52
#define GIN_SHARE
Definition gin_private.h:51
#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:89
static void ginVacuumPostingTree(GinVacuumState *gvs, BlockNumber rootBlkno)
Definition ginvacuum.c:408
static Page ginVacuumEntryPage(GinVacuumState *gvs, Buffer buffer, BlockNumber *roots, uint32 *nroot)
Definition ginvacuum.c:455
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:35
double num_index_tuples
Definition genam.h:85
Relation index
Definition genam.h:52
BufferAccessStrategy strategy
Definition genam.h:59
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:2426

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, AmAutoVacuumWorkerProcess, Assert, DataPageDeleteStack::blkno, 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().

◆ ginDeletePage()

static void ginDeletePage ( GinVacuumState gvs,
BlockNumber  deleteBlkno,
BlockNumber  leftBlkno,
BlockNumber  parentBlkno,
OffsetNumber  myoff,
bool  isParentRoot 
)
static

Definition at line 129 of file ginvacuum.c.

131{
135 Page page,
137 BlockNumber rightlink;
138
139 /*
140 * This function MUST be called only if someone of parent pages hold
141 * exclusive cleanup lock. This guarantees that no insertions currently
142 * happen in this subtree. Caller also acquires Exclusive locks on
143 * deletable, parent and left pages.
144 */
146 RBM_NORMAL, gvs->strategy);
148 RBM_NORMAL, gvs->strategy);
150 RBM_NORMAL, gvs->strategy);
151
152 page = BufferGetPage(dBuffer);
153 rightlink = GinPageGetOpaque(page)->rightlink;
154
155 /*
156 * Any insert which would have gone on the leaf block will now go to its
157 * right sibling.
158 */
159 PredicateLockPageCombine(gvs->index, deleteBlkno, rightlink);
160
162
163 /* Unlink the page by changing left sibling's rightlink */
164 page = BufferGetPage(lBuffer);
165 GinPageGetOpaque(page)->rightlink = rightlink;
166
167 /* Delete downlink from parent */
169#ifdef USE_ASSERT_CHECKING
170 do
171 {
173
175 } while (0);
176#endif
178
179 page = BufferGetPage(dBuffer);
180
181 /*
182 * we shouldn't change rightlink field to save workability of running
183 * search scan
184 */
185
186 /*
187 * Mark page as deleted, and remember last xid which could know its
188 * address.
189 */
190 GinPageSetDeleted(page);
192
196
197 if (RelationNeedsWAL(gvs->index))
198 {
201
202 /*
203 * We can't pass REGBUF_STANDARD for the deleted page, because we
204 * didn't set pd_lower on pre-9.4 versions. The page might've been
205 * binary-upgraded from an older version, and hence not have pd_lower
206 * set correctly. Ditto for the left page, but removing the item from
207 * the parent updated its pd_lower, so we know that's OK at this
208 * point.
209 */
214
215 data.parentOffset = myoff;
216 data.rightLink = GinPageGetOpaque(page)->rightlink;
217 data.deleteXid = GinPageGetDeleteXid(page);
218
220
222 PageSetLSN(page, recptr);
225 }
226
230
232
233 gvs->result->pages_newly_deleted++;
234 gvs->result->pages_deleted++;
235}
void ReleaseBuffer(Buffer buffer)
Definition bufmgr.c:5501
static void PageSetLSN(Page page, XLogRecPtr lsn)
Definition bufpage.h:390
#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:3227
#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:478
void XLogRegisterData(const void *data, uint32 len)
Definition xloginsert.c:368
void XLogRegisterBuffer(uint8 block_id, Buffer buffer, uint8 flags)
Definition xloginsert.c:245
void XLogBeginInsert(void)
Definition xloginsert.c:152
#define REGBUF_STANDARD
Definition xloginsert.h:35

References Assert, BufferGetPage(), data, END_CRIT_SECTION, fb(), GinDataPageGetPostingItem, GinPageDeletePostingItem(), GinPageGetDeleteXid, GinPageGetOpaque, GinPageSetDeleted, GinPageSetDeleteXid, MAIN_FORKNUM, MarkBufferDirty(), PageSetLSN(), PostingItemGetBlockNumber, PredicateLockPageCombine(), RBM_NORMAL, ReadBufferExtended(), ReadNextTransactionId(), REGBUF_STANDARD, RelationNeedsWAL, ReleaseBuffer(), START_CRIT_SECTION, XLOG_GIN_DELETE_PAGE, XLogBeginInsert(), XLogInsert(), XLogRegisterBuffer(), and XLogRegisterData().

Referenced by ginScanToDelete().

◆ GinPageIsRecyclable()

bool GinPageIsRecyclable ( Page  page)

Definition at line 801 of file ginvacuum.c.

802{
804
805 if (PageIsNew(page))
806 return true;
807
808 if (!GinPageIsDeleted(page))
809 return false;
810
812
814 return true;
815
816 /*
817 * If no backend still could view delete_xid as in running, all scans
818 * concurrent with ginDeletePage() must have finished.
819 */
821}
static bool PageIsNew(const PageData *page)
Definition bufpage.h:233
uint32 TransactionId
Definition c.h:666
#define GinPageIsDeleted(page)
Definition ginblock.h:124
bool GlobalVisCheckRemovableXid(Relation rel, TransactionId xid)
Definition procarray.c:4279
#define TransactionIdIsValid(xid)
Definition transam.h:41

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

Referenced by GinNewBuffer(), and ginvacuumcleanup().

◆ ginScanToDelete()

static bool ginScanToDelete ( GinVacuumState gvs,
BlockNumber  blkno,
bool  isRoot,
DataPageDeleteStack parent,
OffsetNumber  myoff 
)
static

Definition at line 246 of file ginvacuum.c.

248{
250 Buffer buffer;
251 Page page;
252 bool meDelete = false;
253 bool isempty;
254
255 if (isRoot)
256 {
257 me = parent;
258 }
259 else
260 {
261 if (!parent->child)
262 {
264 me->parent = parent;
265 parent->child = me;
267 }
268 else
269 me = parent->child;
270 }
271
272 buffer = ReadBufferExtended(gvs->index, MAIN_FORKNUM, blkno,
273 RBM_NORMAL, gvs->strategy);
274
275 if (!isRoot)
276 LockBuffer(buffer, GIN_EXCLUSIVE);
277
278 page = BufferGetPage(buffer);
279
280 Assert(GinPageIsData(page));
281
282 if (!GinPageIsLeaf(page))
283 {
285
286 me->blkno = blkno;
287 for (i = FirstOffsetNumber; i <= GinPageGetOpaque(page)->maxoff; i++)
288 {
290
292 i--;
293 }
294
295 if (GinPageRightMost(page) && BufferIsValid(me->child->leftBuffer))
296 {
297 UnlockReleaseBuffer(me->child->leftBuffer);
298 me->child->leftBuffer = InvalidBuffer;
299 }
300 }
301
302 if (GinPageIsLeaf(page))
304 else
306
307 if (isempty)
308 {
309 /* we never delete the left- or rightmost branch */
310 if (BufferIsValid(me->leftBuffer) && !GinPageRightMost(page))
311 {
312 Assert(!isRoot);
313 ginDeletePage(gvs, blkno, BufferGetBlockNumber(me->leftBuffer),
314 me->parent->blkno, myoff, me->parent->isRoot);
315 meDelete = true;
316 }
317 }
318
319 if (!meDelete)
320 {
321 if (BufferIsValid(me->leftBuffer))
322 UnlockReleaseBuffer(me->leftBuffer);
323 me->leftBuffer = buffer;
324 }
325 else
326 {
327 if (!isRoot)
328 LockBuffer(buffer, GIN_UNLOCK);
329
330 ReleaseBuffer(buffer);
331 }
332
333 if (isRoot)
334 ReleaseBuffer(buffer);
335
336 return meDelete;
337}
#define InvalidBuffer
Definition buf.h:25
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition bufmgr.c:4356
static bool BufferIsValid(Buffer bufnum)
Definition bufmgr.h:417
#define GinPageRightMost(page)
Definition ginblock.h:129
#define GinDataLeafPageIsEmpty(page)
Definition ginblock.h:283
static void ginDeletePage(GinVacuumState *gvs, BlockNumber deleteBlkno, BlockNumber leftBlkno, BlockNumber parentBlkno, OffsetNumber myoff, bool isParentRoot)
Definition ginvacuum.c:129
static bool ginScanToDelete(GinVacuumState *gvs, BlockNumber blkno, bool isRoot, DataPageDeleteStack *parent, OffsetNumber myoff)
Definition ginvacuum.c:246
uint16 OffsetNumber
Definition off.h:24
struct DataPageDeleteStack * child
Definition ginvacuum.c:115

References Assert, DataPageDeleteStack::blkno, BufferGetBlockNumber(), BufferGetPage(), BufferIsValid(), DataPageDeleteStack::child, fb(), FirstOffsetNumber, GIN_EXCLUSIVE, GIN_UNLOCK, GinDataLeafPageIsEmpty, GinDataPageGetPostingItem, ginDeletePage(), GinPageGetOpaque, GinPageIsData, GinPageIsLeaf, GinPageRightMost, ginScanToDelete(), i, InvalidBuffer, DataPageDeleteStack::isRoot, DataPageDeleteStack::leftBuffer, LockBuffer(), MAIN_FORKNUM, palloc0_object, DataPageDeleteStack::parent, PostingItemGetBlockNumber, RBM_NORMAL, ReadBufferExtended(), ReleaseBuffer(), and UnlockReleaseBuffer().

Referenced by ginScanToDelete(), and ginVacuumPostingTree().

◆ ginvacuumcleanup()

IndexBulkDeleteResult * ginvacuumcleanup ( IndexVacuumInfo info,
IndexBulkDeleteResult stats 
)

Definition at line 687 of file ginvacuum.c.

688{
689 Relation index = info->index;
690 bool needLock;
691 BlockNumber npages,
692 blkno;
694 GinState ginstate;
696
697 /*
698 * In an autovacuum analyze, we want to clean up pending insertions.
699 * Otherwise, an ANALYZE-only call is a no-op.
700 */
701 if (info->analyze_only)
702 {
704 {
705 initGinState(&ginstate, index);
706 ginInsertCleanup(&ginstate, false, true, true, stats);
707 }
708 return stats;
709 }
710
711 /*
712 * Set up all-zero stats and cleanup pending inserts if ginbulkdelete
713 * wasn't called
714 */
715 if (stats == NULL)
716 {
718 initGinState(&ginstate, index);
720 false, true, stats);
721 }
722
723 memset(&idxStat, 0, sizeof(idxStat));
724
725 /*
726 * XXX we always report the heap tuple count as the number of index
727 * entries. This is bogus if the index is partial, but it's real hard to
728 * tell how many distinct heap entries are referenced by a GIN index.
729 */
730 stats->num_index_tuples = Max(info->num_heap_tuples, 0);
731 stats->estimated_count = info->estimated_count;
732
733 /*
734 * Need lock unless it's local to this backend.
735 */
737
738 if (needLock)
741 if (needLock)
743
744 totFreePages = 0;
745
746 for (blkno = GIN_ROOT_BLKNO; blkno < npages; blkno++)
747 {
748 Buffer buffer;
749 Page page;
750
751 vacuum_delay_point(false);
752
753 buffer = ReadBufferExtended(index, MAIN_FORKNUM, blkno,
754 RBM_NORMAL, info->strategy);
755 LockBuffer(buffer, GIN_SHARE);
756 page = BufferGetPage(buffer);
757
758 if (GinPageIsRecyclable(page))
759 {
760 Assert(blkno != GIN_ROOT_BLKNO);
762 totFreePages++;
763 }
764 else if (GinPageIsData(page))
765 {
766 idxStat.nDataPages++;
767 }
768 else if (!GinPageIsList(page))
769 {
770 idxStat.nEntryPages++;
771
772 if (GinPageIsLeaf(page))
773 idxStat.nEntries += PageGetMaxOffsetNumber(page);
774 }
775
776 UnlockReleaseBuffer(buffer);
777 }
778
779 /* Update the metapage with accurate page and entry counts */
780 idxStat.nTotalPages = npages;
781 ginUpdateStats(info->index, &idxStat, false);
782
783 /* Finally, vacuum the FSM */
785
786 stats->pages_free = totFreePages;
787
788 if (needLock)
791 if (needLock)
793
794 return stats;
795}
#define RelationGetNumberOfBlocks(reln)
Definition bufmgr.h:307
#define Max(x, y)
Definition c.h:991
#define GinPageIsList(page)
Definition ginblock.h:117
void ginUpdateStats(Relation index, const GinStatsData *stats, bool is_build)
Definition ginutil.c:618
bool GinPageIsRecyclable(Page page)
Definition ginvacuum.c:801
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
#define RELATION_IS_LOCAL(relation)
Definition rel.h:657
BlockNumber pages_free
Definition genam.h:89
BlockNumber num_pages
Definition genam.h:83
double num_heap_tuples
Definition genam.h:58
bool analyze_only
Definition genam.h:54
bool estimated_count
Definition genam.h:56

References AmAutoVacuumWorkerProcess, IndexVacuumInfo::analyze_only, Assert, DataPageDeleteStack::blkno, BufferGetPage(), IndexVacuumInfo::estimated_count, IndexBulkDeleteResult::estimated_count, ExclusiveLock, fb(), GIN_ROOT_BLKNO, GIN_SHARE, ginInsertCleanup(), GinPageIsData, GinPageIsLeaf, GinPageIsList, GinPageIsRecyclable(), ginUpdateStats(), IndexVacuumInfo::index, IndexFreeSpaceMapVacuum(), initGinState(), LockBuffer(), LockRelationForExtension(), MAIN_FORKNUM, Max, IndexVacuumInfo::num_heap_tuples, IndexBulkDeleteResult::num_index_tuples, IndexBulkDeleteResult::num_pages, PageGetMaxOffsetNumber(), IndexBulkDeleteResult::pages_free, palloc0_object, RBM_NORMAL, ReadBufferExtended(), 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 455 of file ginvacuum.c.

456{
457 Page origpage = BufferGetPage(buffer),
458 tmppage;
460 maxoff = PageGetMaxOffsetNumber(origpage);
461
462 tmppage = origpage;
463
464 *nroot = 0;
465
466 for (i = FirstOffsetNumber; i <= maxoff; i++)
467 {
469
470 if (GinIsPostingTree(itup))
471 {
472 /*
473 * store posting tree's roots for further processing, we can't
474 * vacuum it just now due to risk of deadlocks with scans/inserts
475 */
476 roots[*nroot] = GinGetDownlink(itup);
477 (*nroot)++;
478 }
479 else if (GinGetNPosting(itup) > 0)
480 {
481 int nitems;
483 bool free_items_orig;
485
486 /* Get list of item pointers from the tuple. */
487 if (GinItupIsCompressed(itup))
488 {
490 free_items_orig = true;
491 }
492 else
493 {
495 nitems = GinGetNPosting(itup);
496 free_items_orig = false;
497 }
498
499 /* Remove any items from the list that need to be vacuumed. */
501
502 if (free_items_orig)
504
505 /* If any item pointers were removed, recreate the tuple. */
506 if (items)
507 {
509 Datum key;
510 GinNullCategory category;
512 int plistsize;
513
514 if (nitems > 0)
515 {
518 }
519 else
520 {
521 plist = NULL;
522 plistsize = 0;
523 }
524
525 /*
526 * if we already created a temporary page, make changes in
527 * place
528 */
529 if (tmppage == origpage)
530 {
531 /*
532 * On first difference, create a temporary copy of the
533 * page and copy the tuple's posting list to it.
534 */
535 tmppage = PageGetTempPageCopy(origpage);
536
537 /* set itup pointer to new page */
539 }
540
541 attnum = gintuple_get_attrnum(&gvs->ginstate, itup);
542 key = gintuple_get_key(&gvs->ginstate, itup, &category);
543 itup = GinFormTuple(&gvs->ginstate, attnum, key, category,
544 (char *) plist, plistsize,
545 nitems, true);
546 if (plist)
547 pfree(plist);
549
550 if (PageAddItem(tmppage, itup, IndexTupleSize(itup), i, false, false) != i)
551 elog(ERROR, "failed to add item to index page in \"%s\"",
553
554 pfree(itup);
555 pfree(items);
556 }
557 }
558 }
559
560 return (tmppage == origpage) ? NULL : tmppage;
561}
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:471
#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:232
Datum gintuple_get_key(GinState *ginstate, IndexTuple tuple, GinNullCategory *category)
Definition ginutil.c:265
ItemPointer ginVacuumItemPointers(GinVacuumState *gvs, ItemPointerData *items, int nitem, int *nremaining)
Definition ginvacuum.c:47
#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, 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 47 of file ginvacuum.c.

49{
50 int i,
51 remaining = 0;
53
54 /*
55 * Iterate over TIDs array
56 */
57 for (i = 0; i < nitem; i++)
58 {
59 if (gvs->callback(items + i, gvs->callback_state))
60 {
61 gvs->result->tuples_removed += 1;
62 if (!tmpitems)
63 {
64 /*
65 * First TID to be deleted: allocate memory to hold the
66 * remaining items.
67 */
70 }
71 }
72 else
73 {
74 gvs->result->num_index_tuples += 1;
75 if (tmpitems)
77 remaining++;
78 }
79 }
80
82 return tmpitems;
83}
#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 408 of file ginvacuum.c.

409{
410 if (ginVacuumPostingTreeLeaves(gvs, rootBlkno))
411 {
412 /*
413 * There is at least one empty page. So we have to rescan the tree
414 * deleting empty pages.
415 */
416 Buffer buffer;
418 *ptr,
419 *tmp;
420
421 buffer = ReadBufferExtended(gvs->index, MAIN_FORKNUM, rootBlkno,
422 RBM_NORMAL, gvs->strategy);
423
424 /*
425 * Lock posting tree root for cleanup to ensure there are no
426 * concurrent inserts.
427 */
428 LockBufferForCleanup(buffer);
429
430 memset(&root, 0, sizeof(DataPageDeleteStack));
431 root.leftBuffer = InvalidBuffer;
432 root.isRoot = true;
433
434 ginScanToDelete(gvs, rootBlkno, true, &root, InvalidOffsetNumber);
435
436 ptr = root.child;
437
438 while (ptr)
439 {
440 tmp = ptr->child;
441 pfree(ptr);
442 ptr = tmp;
443 }
444
445 UnlockReleaseBuffer(buffer);
446 }
447}
void LockBufferForCleanup(Buffer buffer)
Definition bufmgr.c:6527
static bool ginVacuumPostingTreeLeaves(GinVacuumState *gvs, BlockNumber blkno)
Definition ginvacuum.c:345
#define InvalidOffsetNumber
Definition off.h:26
tree ctl root
Definition radixtree.h:1857

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

Referenced by ginbulkdelete().

◆ ginVacuumPostingTreeLeaves()

static bool ginVacuumPostingTreeLeaves ( GinVacuumState gvs,
BlockNumber  blkno 
)
static

Definition at line 345 of file ginvacuum.c.

346{
347 Buffer buffer;
348 Page page;
349 bool hasVoidPage = false;
351
352 /* Find leftmost leaf page of posting tree and lock it in exclusive mode */
353 while (true)
354 {
356
357 buffer = ReadBufferExtended(gvs->index, MAIN_FORKNUM, blkno,
358 RBM_NORMAL, gvs->strategy);
359 LockBuffer(buffer, GIN_SHARE);
360 page = BufferGetPage(buffer);
361
362 Assert(GinPageIsData(page));
363
364 if (GinPageIsLeaf(page))
365 {
366 LockBuffer(buffer, GIN_UNLOCK);
367 LockBuffer(buffer, GIN_EXCLUSIVE);
368 break;
369 }
370
372
375 Assert(blkno != InvalidBlockNumber);
376
377 UnlockReleaseBuffer(buffer);
378 }
379
380 /* Iterate all posting tree leaves using rightlinks and vacuum them */
381 while (true)
382 {
384 ginVacuumPostingTreeLeaf(gvs->index, buffer, gvs);
386 MemoryContextReset(gvs->tmpCxt);
387
388 if (GinDataLeafPageIsEmpty(page))
389 hasVoidPage = true;
390
391 blkno = GinPageGetOpaque(page)->rightlink;
392
393 UnlockReleaseBuffer(buffer);
394
395 if (blkno == InvalidBlockNumber)
396 break;
397
398 buffer = ReadBufferExtended(gvs->index, MAIN_FORKNUM, blkno,
399 RBM_NORMAL, gvs->strategy);
400 LockBuffer(buffer, GIN_EXCLUSIVE);
401 page = BufferGetPage(buffer);
402 }
403
404 return hasVoidPage;
405}
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::blkno, 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 89 of file ginvacuum.c.

90{
91 Page page = BufferGetPage(buffer);
93
94 /* This is only used for entry tree leaf pages. */
95 Assert(!GinPageIsData(page));
96 Assert(GinPageIsLeaf(page));
97
99 return;
100
101 /*
102 * Always create a full image, we don't track the changes on the page at
103 * any more fine-grained level. This could obviously be improved...
104 */
107
109 PageSetLSN(page, recptr);
110}
#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().