PostgreSQL Source Code  git master
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-2018, 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 "postmaster/autovacuum.h"
23 #include "storage/indexfsm.h"
24 #include "storage/lmgr.h"
25 #include "storage/predicate.h"
26 #include "utils/memutils.h"
27 
29 {
37 };
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;
53  ItemPointer tmpitems = NULL;
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  */
69  tmpitems = palloc(sizeof(ItemPointerData) * nitem);
70  memcpy(tmpitems, items, sizeof(ItemPointerData) * i);
71  }
72  }
73  else
74  {
75  gvs->result->num_index_tuples += 1;
76  if (tmpitems)
77  tmpitems[remaining] = items[i];
78  remaining++;
79  }
80  }
81 
82  *nremaining = remaining;
83  return tmpitems;
84 }
85 
86 /*
87  * Create a WAL record for vacuuming entry tree leaf page.
88  */
89 static void
91 {
92  Page page = BufferGetPage(buffer);
93  XLogRecPtr recptr;
94 
95  /* This is only used for entry tree leaf pages. */
96  Assert(!GinPageIsData(page));
97  Assert(GinPageIsLeaf(page));
98 
99  if (!RelationNeedsWAL(index))
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  */
106  XLogBeginInsert();
108 
109  recptr = XLogInsert(RM_GIN_ID, XLOG_GIN_VACUUM_PAGE);
110  PageSetLSN(page, recptr);
111 }
112 
113 
114 typedef struct DataPageDeleteStack
115 {
118 
119  BlockNumber blkno; /* current block number */
120  BlockNumber leftBlkno; /* rightest non-deleted page on left */
121  bool isRoot;
123 
124 
125 /*
126  * Delete a posting tree page.
127  */
128 static void
130  BlockNumber parentBlkno, OffsetNumber myoff, bool isParentRoot)
131 {
132  Buffer dBuffer;
133  Buffer lBuffer;
134  Buffer pBuffer;
135  Page page,
136  parentPage;
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 acquire Exclusive lock on deletable
143  * page and is acquiring and releasing exclusive lock on left page before.
144  * Left page was locked and released. Then parent and this page are
145  * locked. We acquire left page lock here only to mark page dirty after
146  * changing right pointer.
147  */
148  lBuffer = ReadBufferExtended(gvs->index, MAIN_FORKNUM, leftBlkno,
149  RBM_NORMAL, gvs->strategy);
150  dBuffer = ReadBufferExtended(gvs->index, MAIN_FORKNUM, deleteBlkno,
151  RBM_NORMAL, gvs->strategy);
152  pBuffer = ReadBufferExtended(gvs->index, MAIN_FORKNUM, parentBlkno,
153  RBM_NORMAL, gvs->strategy);
154 
155  LockBuffer(lBuffer, GIN_EXCLUSIVE);
156 
157  page = BufferGetPage(dBuffer);
158  rightlink = GinPageGetOpaque(page)->rightlink;
159 
160  /*
161  * Any insert which would have gone on the leaf block will now go to its
162  * right sibling.
163  */
164  PredicateLockPageCombine(gvs->index, deleteBlkno, rightlink);
165 
167 
168  /* Unlink the page by changing left sibling's rightlink */
169  page = BufferGetPage(lBuffer);
170  GinPageGetOpaque(page)->rightlink = rightlink;
171 
172  /* Delete downlink from parent */
173  parentPage = BufferGetPage(pBuffer);
174 #ifdef USE_ASSERT_CHECKING
175  do
176  {
177  PostingItem *tod = GinDataPageGetPostingItem(parentPage, myoff);
178 
179  Assert(PostingItemGetBlockNumber(tod) == deleteBlkno);
180  } while (0);
181 #endif
182  GinPageDeletePostingItem(parentPage, myoff);
183 
184  page = BufferGetPage(dBuffer);
185 
186  /*
187  * we shouldn't change rightlink field to save workability of running
188  * search scan
189  */
190  GinPageGetOpaque(page)->flags = GIN_DELETED;
191 
192  MarkBufferDirty(pBuffer);
193  MarkBufferDirty(lBuffer);
194  MarkBufferDirty(dBuffer);
195 
196  if (RelationNeedsWAL(gvs->index))
197  {
198  XLogRecPtr recptr;
199  ginxlogDeletePage data;
200 
201  /*
202  * We can't pass REGBUF_STANDARD for the deleted page, because we
203  * didn't set pd_lower on pre-9.4 versions. The page might've been
204  * binary-upgraded from an older version, and hence not have pd_lower
205  * set correctly. Ditto for the left page, but removing the item from
206  * the parent updated its pd_lower, so we know that's OK at this
207  * point.
208  */
209  XLogBeginInsert();
210  XLogRegisterBuffer(0, dBuffer, 0);
211  XLogRegisterBuffer(1, pBuffer, REGBUF_STANDARD);
212  XLogRegisterBuffer(2, lBuffer, 0);
213 
214  data.parentOffset = myoff;
215  data.rightLink = GinPageGetOpaque(page)->rightlink;
216 
217  XLogRegisterData((char *) &data, sizeof(ginxlogDeletePage));
218 
219  recptr = XLogInsert(RM_GIN_ID, XLOG_GIN_DELETE_PAGE);
220  PageSetLSN(page, recptr);
221  PageSetLSN(parentPage, recptr);
222  PageSetLSN(BufferGetPage(lBuffer), recptr);
223  }
224 
225  ReleaseBuffer(pBuffer);
226  UnlockReleaseBuffer(lBuffer);
227  ReleaseBuffer(dBuffer);
228 
230 
231  gvs->result->pages_deleted++;
232 }
233 
234 
235 /*
236  * scans posting tree and deletes empty pages
237  */
238 static bool
241 {
243  Buffer buffer;
244  Page page;
245  bool meDelete = false;
246  bool isempty;
247 
248  if (isRoot)
249  {
250  me = parent;
251  }
252  else
253  {
254  if (!parent->child)
255  {
257  me->parent = parent;
258  parent->child = me;
260  }
261  else
262  me = parent->child;
263  }
264 
265  buffer = ReadBufferExtended(gvs->index, MAIN_FORKNUM, blkno,
266  RBM_NORMAL, gvs->strategy);
267 
268  if (!isRoot)
269  LockBuffer(buffer, GIN_EXCLUSIVE);
270 
271  page = BufferGetPage(buffer);
272 
273  Assert(GinPageIsData(page));
274 
275  if (!GinPageIsLeaf(page))
276  {
277  OffsetNumber i;
278 
279  me->blkno = blkno;
280  for (i = FirstOffsetNumber; i <= GinPageGetOpaque(page)->maxoff; i++)
281  {
282  PostingItem *pitem = GinDataPageGetPostingItem(page, i);
283 
284  if (ginScanToDelete(gvs, PostingItemGetBlockNumber(pitem), false, me, i))
285  i--;
286  }
287  }
288 
289  if (GinPageIsLeaf(page))
290  isempty = GinDataLeafPageIsEmpty(page);
291  else
292  isempty = GinPageGetOpaque(page)->maxoff < FirstOffsetNumber;
293 
294  if (isempty)
295  {
296  /* we never delete the left- or rightmost branch */
297  if (me->leftBlkno != InvalidBlockNumber && !GinPageRightMost(page))
298  {
299  Assert(!isRoot);
300  ginDeletePage(gvs, blkno, me->leftBlkno, me->parent->blkno, myoff, me->parent->isRoot);
301  meDelete = true;
302  }
303  }
304 
305  if (!isRoot)
306  LockBuffer(buffer, GIN_UNLOCK);
307 
308  ReleaseBuffer(buffer);
309 
310  if (!meDelete)
311  me->leftBlkno = blkno;
312 
313  return meDelete;
314 }
315 
316 
317 /*
318  * Scan through posting tree, delete empty tuples from leaf pages.
319  * Also, this function collects empty subtrees (with all empty leafs).
320  * For parents of these subtrees CleanUp lock is taken, then we call
321  * ScanToDelete. This is done for every inner page, which points to
322  * empty subtree.
323  */
324 static bool
326 {
327  Buffer buffer;
328  Page page;
329  bool hasVoidPage = false;
330  MemoryContext oldCxt;
331 
332  buffer = ReadBufferExtended(gvs->index, MAIN_FORKNUM, blkno,
333  RBM_NORMAL, gvs->strategy);
334  page = BufferGetPage(buffer);
335 
336  ginTraverseLock(buffer, false);
337 
338  Assert(GinPageIsData(page));
339 
340  if (GinPageIsLeaf(page))
341  {
342  oldCxt = MemoryContextSwitchTo(gvs->tmpCxt);
343  ginVacuumPostingTreeLeaf(gvs->index, buffer, gvs);
344  MemoryContextSwitchTo(oldCxt);
346 
347  /* if root is a leaf page, we don't desire further processing */
348  if (GinDataLeafPageIsEmpty(page))
349  hasVoidPage = true;
350 
351  UnlockReleaseBuffer(buffer);
352 
353  return hasVoidPage;
354  }
355  else
356  {
357  OffsetNumber i;
358  bool hasEmptyChild = false;
359  bool hasNonEmptyChild = false;
360  OffsetNumber maxoff = GinPageGetOpaque(page)->maxoff;
361  BlockNumber *children = palloc(sizeof(BlockNumber) * (maxoff + 1));
362 
363  /*
364  * Read all children BlockNumbers. Not sure it is safe if there are
365  * many concurrent vacuums.
366  */
367 
368  for (i = FirstOffsetNumber; i <= maxoff; i++)
369  {
370  PostingItem *pitem = GinDataPageGetPostingItem(page, i);
371 
372  children[i] = PostingItemGetBlockNumber(pitem);
373  }
374 
375  UnlockReleaseBuffer(buffer);
376 
377  for (i = FirstOffsetNumber; i <= maxoff; i++)
378  {
379  if (ginVacuumPostingTreeLeaves(gvs, children[i], false))
380  hasEmptyChild = true;
381  else
382  hasNonEmptyChild = true;
383  }
384 
385  pfree(children);
386 
388 
389  /*
390  * All subtree is empty - just return true to indicate that parent
391  * must do a cleanup, unless we are ROOT and there is way to go upper.
392  */
393 
394  if (hasEmptyChild && !hasNonEmptyChild && !isRoot)
395  return true;
396 
397  if (hasEmptyChild)
398  {
399  DataPageDeleteStack root,
400  *ptr,
401  *tmp;
402 
403  buffer = ReadBufferExtended(gvs->index, MAIN_FORKNUM, blkno,
404  RBM_NORMAL, gvs->strategy);
405  LockBufferForCleanup(buffer);
406 
407  memset(&root, 0, sizeof(DataPageDeleteStack));
409  root.isRoot = true;
410 
411  ginScanToDelete(gvs, blkno, true, &root, InvalidOffsetNumber);
412 
413  ptr = root.child;
414 
415  while (ptr)
416  {
417  tmp = ptr->child;
418  pfree(ptr);
419  ptr = tmp;
420  }
421 
422  UnlockReleaseBuffer(buffer);
423  }
424 
425  /* Here we have deleted all empty subtrees */
426  return false;
427  }
428 }
429 
430 static void
432 {
433  ginVacuumPostingTreeLeaves(gvs, rootBlkno, true);
434 }
435 
436 /*
437  * returns modified page or NULL if page isn't modified.
438  * Function works with original page until first change is occurred,
439  * then page is copied into temporary one.
440  */
441 static Page
443 {
444  Page origpage = BufferGetPage(buffer),
445  tmppage;
446  OffsetNumber i,
447  maxoff = PageGetMaxOffsetNumber(origpage);
448 
449  tmppage = origpage;
450 
451  *nroot = 0;
452 
453  for (i = FirstOffsetNumber; i <= maxoff; i++)
454  {
455  IndexTuple itup = (IndexTuple) PageGetItem(tmppage, PageGetItemId(tmppage, i));
456 
457  if (GinIsPostingTree(itup))
458  {
459  /*
460  * store posting tree's roots for further processing, we can't
461  * vacuum it just now due to risk of deadlocks with scans/inserts
462  */
463  roots[*nroot] = GinGetDownlink(itup);
464  (*nroot)++;
465  }
466  else if (GinGetNPosting(itup) > 0)
467  {
468  int nitems;
469  ItemPointer items_orig;
470  bool free_items_orig;
471  ItemPointer items;
472 
473  /* Get list of item pointers from the tuple. */
474  if (GinItupIsCompressed(itup))
475  {
476  items_orig = ginPostingListDecode((GinPostingList *) GinGetPosting(itup), &nitems);
477  free_items_orig = true;
478  }
479  else
480  {
481  items_orig = (ItemPointer) GinGetPosting(itup);
482  nitems = GinGetNPosting(itup);
483  free_items_orig = false;
484  }
485 
486  /* Remove any items from the list that need to be vacuumed. */
487  items = ginVacuumItemPointers(gvs, items_orig, nitems, &nitems);
488 
489  if (free_items_orig)
490  pfree(items_orig);
491 
492  /* If any item pointers were removed, recreate the tuple. */
493  if (items)
494  {
496  Datum key;
497  GinNullCategory category;
498  GinPostingList *plist;
499  int plistsize;
500 
501  if (nitems > 0)
502  {
503  plist = ginCompressPostingList(items, nitems, GinMaxItemSize, NULL);
504  plistsize = SizeOfGinPostingList(plist);
505  }
506  else
507  {
508  plist = NULL;
509  plistsize = 0;
510  }
511 
512  /*
513  * if we already created a temporary page, make changes in
514  * place
515  */
516  if (tmppage == origpage)
517  {
518  /*
519  * On first difference, create a temporary copy of the
520  * page and copy the tuple's posting list to it.
521  */
522  tmppage = PageGetTempPageCopy(origpage);
523 
524  /* set itup pointer to new page */
525  itup = (IndexTuple) PageGetItem(tmppage, PageGetItemId(tmppage, i));
526  }
527 
528  attnum = gintuple_get_attrnum(&gvs->ginstate, itup);
529  key = gintuple_get_key(&gvs->ginstate, itup, &category);
530  itup = GinFormTuple(&gvs->ginstate, attnum, key, category,
531  (char *) plist, plistsize,
532  nitems, true);
533  if (plist)
534  pfree(plist);
535  PageIndexTupleDelete(tmppage, i);
536 
537  if (PageAddItem(tmppage, (Item) itup, IndexTupleSize(itup), i, false, false) != i)
538  elog(ERROR, "failed to add item to index page in \"%s\"",
540 
541  pfree(itup);
542  pfree(items);
543  }
544  }
545  }
546 
547  return (tmppage == origpage) ? NULL : tmppage;
548 }
549 
553 {
554  Relation index = info->index;
556  GinVacuumState gvs;
557  Buffer buffer;
558  BlockNumber rootOfPostingTree[BLCKSZ / (sizeof(IndexTupleData) + sizeof(ItemId))];
559  uint32 nRoot;
560 
562  "Gin vacuum temporary context",
564  gvs.index = index;
565  gvs.callback = callback;
567  gvs.strategy = info->strategy;
568  initGinState(&gvs.ginstate, index);
569 
570  /* first time through? */
571  if (stats == NULL)
572  {
573  /* Yes, so initialize stats to zeroes */
575 
576  /*
577  * and cleanup any pending inserts
578  */
580  false, true, stats);
581  }
582 
583  /* we'll re-count the tuples each time */
584  stats->num_index_tuples = 0;
585  gvs.result = stats;
586 
587  buffer = ReadBufferExtended(index, MAIN_FORKNUM, blkno,
588  RBM_NORMAL, info->strategy);
589 
590  /* find leaf page */
591  for (;;)
592  {
593  Page page = BufferGetPage(buffer);
594  IndexTuple itup;
595 
596  LockBuffer(buffer, GIN_SHARE);
597 
598  Assert(!GinPageIsData(page));
599 
600  if (GinPageIsLeaf(page))
601  {
602  LockBuffer(buffer, GIN_UNLOCK);
603  LockBuffer(buffer, GIN_EXCLUSIVE);
604 
605  if (blkno == GIN_ROOT_BLKNO && !GinPageIsLeaf(page))
606  {
607  LockBuffer(buffer, GIN_UNLOCK);
608  continue; /* check it one more */
609  }
610  break;
611  }
612 
614 
615  itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, FirstOffsetNumber));
616  blkno = GinGetDownlink(itup);
617  Assert(blkno != InvalidBlockNumber);
618 
619  UnlockReleaseBuffer(buffer);
620  buffer = ReadBufferExtended(index, MAIN_FORKNUM, blkno,
621  RBM_NORMAL, info->strategy);
622  }
623 
624  /* right now we found leftmost page in entry's BTree */
625 
626  for (;;)
627  {
628  Page page = BufferGetPage(buffer);
629  Page resPage;
630  uint32 i;
631 
632  Assert(!GinPageIsData(page));
633 
634  resPage = ginVacuumEntryPage(&gvs, buffer, rootOfPostingTree, &nRoot);
635 
636  blkno = GinPageGetOpaque(page)->rightlink;
637 
638  if (resPage)
639  {
641  PageRestoreTempPage(resPage, page);
642  MarkBufferDirty(buffer);
643  xlogVacuumPage(gvs.index, buffer);
644  UnlockReleaseBuffer(buffer);
646  }
647  else
648  {
649  UnlockReleaseBuffer(buffer);
650  }
651 
653 
654  for (i = 0; i < nRoot; i++)
655  {
656  ginVacuumPostingTree(&gvs, rootOfPostingTree[i]);
658  }
659 
660  if (blkno == InvalidBlockNumber) /* rightmost page */
661  break;
662 
663  buffer = ReadBufferExtended(index, MAIN_FORKNUM, blkno,
664  RBM_NORMAL, info->strategy);
665  LockBuffer(buffer, GIN_EXCLUSIVE);
666  }
667 
669 
670  return gvs.result;
671 }
672 
675 {
676  Relation index = info->index;
677  bool needLock;
678  BlockNumber npages,
679  blkno;
680  BlockNumber totFreePages;
682  GinStatsData idxStat;
683 
684  /*
685  * In an autovacuum analyze, we want to clean up pending insertions.
686  * Otherwise, an ANALYZE-only call is a no-op.
687  */
688  if (info->analyze_only)
689  {
691  {
692  initGinState(&ginstate, index);
693  ginInsertCleanup(&ginstate, false, true, true, stats);
694  }
695  return stats;
696  }
697 
698  /*
699  * Set up all-zero stats and cleanup pending inserts if ginbulkdelete
700  * wasn't called
701  */
702  if (stats == NULL)
703  {
705  initGinState(&ginstate, index);
707  false, true, stats);
708  }
709 
710  memset(&idxStat, 0, sizeof(idxStat));
711 
712  /*
713  * XXX we always report the heap tuple count as the number of index
714  * entries. This is bogus if the index is partial, but it's real hard to
715  * tell how many distinct heap entries are referenced by a GIN index.
716  */
717  stats->num_index_tuples = info->num_heap_tuples;
718  stats->estimated_count = info->estimated_count;
719 
720  /*
721  * Need lock unless it's local to this backend.
722  */
723  needLock = !RELATION_IS_LOCAL(index);
724 
725  if (needLock)
727  npages = RelationGetNumberOfBlocks(index);
728  if (needLock)
730 
731  totFreePages = 0;
732 
733  for (blkno = GIN_ROOT_BLKNO; blkno < npages; blkno++)
734  {
735  Buffer buffer;
736  Page page;
737 
739 
740  buffer = ReadBufferExtended(index, MAIN_FORKNUM, blkno,
741  RBM_NORMAL, info->strategy);
742  LockBuffer(buffer, GIN_SHARE);
743  page = (Page) BufferGetPage(buffer);
744 
745  if (PageIsNew(page) || GinPageIsDeleted(page))
746  {
747  Assert(blkno != GIN_ROOT_BLKNO);
748  RecordFreeIndexPage(index, blkno);
749  totFreePages++;
750  }
751  else if (GinPageIsData(page))
752  {
753  idxStat.nDataPages++;
754  }
755  else if (!GinPageIsList(page))
756  {
757  idxStat.nEntryPages++;
758 
759  if (GinPageIsLeaf(page))
760  idxStat.nEntries += PageGetMaxOffsetNumber(page);
761  }
762 
763  UnlockReleaseBuffer(buffer);
764  }
765 
766  /* Update the metapage with accurate page and entry counts */
767  idxStat.nTotalPages = npages;
768  ginUpdateStats(info->index, &idxStat);
769 
770  /* Finally, vacuum the FSM */
772 
773  stats->pages_free = totFreePages;
774 
775  if (needLock)
777  stats->num_pages = RelationGetNumberOfBlocks(index);
778  if (needLock)
780 
781  return stats;
782 }
int remaining
Definition: informix.c:692
#define GIN_UNLOCK
Definition: gin_private.h:43
#define GIN_DELETED
Definition: ginblock.h:41
BlockNumber nEntryPages
Definition: gin.h:45
GinPostingList * ginCompressPostingList(const ItemPointer ipd, int nipd, int maxsize, int *nwritten)
IndexBulkDeleteResult * ginvacuumcleanup(IndexVacuumInfo *info, IndexBulkDeleteResult *stats)
Definition: ginvacuum.c:674
void LockBufferForCleanup(Buffer buffer)
Definition: bufmgr.c:3603
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:211
static bool ginVacuumPostingTreeLeaves(GinVacuumState *gvs, BlockNumber blkno, bool isRoot)
Definition: ginvacuum.c:325
double tuples_removed
Definition: genam.h:77
void PageRestoreTempPage(Page tempPage, Page oldPage)
Definition: bufpage.c:407
ItemPointer ginPostingListDecode(GinPostingList *plist, int *ndecoded)
void PageIndexTupleDelete(Page page, OffsetNumber offnum)
Definition: bufpage.c:723
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:1450
#define ExclusiveLock
Definition: lockdefs.h:44
void XLogRegisterBuffer(uint8 block_id, Buffer buffer, uint8 flags)
Definition: xloginsert.c:213
Relation index
Definition: ginvacuum.c:30
#define RELATION_IS_LOCAL(relation)
Definition: rel.h:528
bool analyze_only
Definition: genam.h:47
Buffer ReadBufferExtended(Relation reln, ForkNumber forkNum, BlockNumber blockNum, ReadBufferMode mode, BufferAccessStrategy strategy)
Definition: bufmgr.c:640
BlockNumber rightLink
Definition: ginxlog.h:160
BufferAccessStrategy strategy
Definition: ginvacuum.c:35
#define END_CRIT_SECTION()
Definition: miscadmin.h:133
BufferAccessStrategy strategy
Definition: genam.h:51
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
Pointer Item
Definition: item.h:17
ItemPointer ginVacuumItemPointers(GinVacuumState *gvs, ItemPointerData *items, int nitem, int *nremaining)
Definition: ginvacuum.c:48
#define START_CRIT_SECTION()
Definition: miscadmin.h:131
Relation index
Definition: genam.h:46
int64 nEntries
Definition: gin.h:47
#define PageAddItem(page, item, size, offsetNumber, overwrite, is_heap)
Definition: bufpage.h:412
#define GinGetNPosting(itup)
Definition: ginblock.h:222
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:136
uint32 BlockNumber
Definition: block.h:31
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3309
#define GinPageGetOpaque(page)
Definition: ginblock.h:109
OffsetNumber parentOffset
Definition: ginxlog.h:159
#define PageGetMaxOffsetNumber(page)
Definition: bufpage.h:353
static void ginDeletePage(GinVacuumState *gvs, BlockNumber deleteBlkno, BlockNumber leftBlkno, BlockNumber parentBlkno, OffsetNumber myoff, bool isParentRoot)
Definition: ginvacuum.c:129
#define GinGetPosting(itup)
Definition: ginblock.h:232
IndexBulkDeleteResult * result
Definition: ginvacuum.c:31
#define GinItupIsCompressed(itup)
Definition: ginblock.h:233
#define GinDataLeafPageIsEmpty(page)
Definition: ginblock.h:277
uint16 OffsetNumber
Definition: off.h:24
ItemPointerData * ItemPointer
Definition: itemptr.h:49
Definition: type.h:89
BlockNumber leftBlkno
Definition: ginvacuum.c:120
void pfree(void *pointer)
Definition: mcxt.c:1031
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3332
#define ERROR
Definition: elog.h:43
#define GinPageRightMost(page)
Definition: ginblock.h:128
signed char GinNullCategory
Definition: ginblock.h:200
static void xlogVacuumPage(Relation index, Buffer buffer)
Definition: ginvacuum.c:90
#define GinDataPageGetPostingItem(page, i)
Definition: ginblock.h:292
BlockNumber num_pages
Definition: genam.h:73
BlockNumber pages_free
Definition: genam.h:79
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:192
void ginUpdateStats(Relation index, const GinStatsData *stats)
Definition: ginutil.c:669
BlockNumber blkno
Definition: ginvacuum.c:119
OffsetNumber gintuple_get_attrnum(GinState *ginstate, IndexTuple tuple)
Definition: ginutil.c:217
void ginVacuumPostingTreeLeaf(Relation indexrel, Buffer buffer, GinVacuumState *gvs)
Definition: gindatapage.c:732
static Page ginVacuumEntryPage(GinVacuumState *gvs, Buffer buffer, BlockNumber *roots, uint32 *nroot)
Definition: ginvacuum.c:442
IndexBulkDeleteCallback callback
Definition: ginvacuum.c:32
#define FirstOffsetNumber
Definition: off.h:27
IndexTupleData * IndexTuple
Definition: itup.h:53
#define REGBUF_STANDARD
Definition: xloginsert.h:34
void initGinState(GinState *state, Relation index)
Definition: ginutil.c:88
#define RelationGetRelationName(relation)
Definition: rel.h:441
unsigned int uint32
Definition: c.h:325
MemoryContext CurrentMemoryContext
Definition: mcxt.c:38
#define GinPageIsLeaf(page)
Definition: ginblock.h:111
Datum gintuple_get_key(GinState *ginstate, IndexTuple tuple, GinNullCategory *category)
Definition: ginutil.c:250
BlockNumber pages_deleted
Definition: genam.h:78
void * callback_state
Definition: ginvacuum.c:33
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
struct DataPageDeleteStack DataPageDeleteStack
bool IsAutoVacuumWorkerProcess(void)
Definition: autovacuum.c:3295
#define GIN_SHARE
Definition: gin_private.h:44
#define AllocSetContextCreate(parent, name, allocparams)
Definition: memutils.h:170
#define REGBUF_FORCE_IMAGE
Definition: xloginsert.h:30
#define PageGetItemId(page, offsetNumber)
Definition: bufpage.h:231
void LockRelationForExtension(Relation relation, LOCKMODE lockmode)
Definition: lmgr.c:332
#define XLOG_GIN_VACUUM_PAGE
Definition: ginxlog.h:137
void XLogRegisterData(char *data, int len)
Definition: xloginsert.c:323
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:415
void * palloc0(Size size)
Definition: mcxt.c:955
#define GinPageIsDeleted(page)
Definition: ginblock.h:123
void UnlockRelationForExtension(Relation relation, LOCKMODE lockmode)
Definition: lmgr.c:382
uintptr_t Datum
Definition: postgres.h:367
struct IndexTupleData IndexTupleData
#define GIN_EXCLUSIVE
Definition: gin_private.h:45
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3546
#define GinGetDownlink(itup)
Definition: ginblock.h:251
void GinPageDeletePostingItem(Page page, OffsetNumber offset)
Definition: gindatapage.c:414
#define RelationGetNumberOfBlocks(reln)
Definition: bufmgr.h:199
struct DataPageDeleteStack * child
Definition: ginvacuum.c:116
#define InvalidOffsetNumber
Definition: off.h:26
BlockNumber nDataPages
Definition: gin.h:46
int16 attnum
Definition: pg_attribute.h:79
void ginInsertCleanup(GinState *ginstate, bool full_clean, bool fill_fsm, bool forceCleanup, IndexBulkDeleteResult *stats)
Definition: ginfast.c:762
#define GinPageIsData(page)
Definition: ginblock.h:114
double num_heap_tuples
Definition: genam.h:50
#define PostingItemGetBlockNumber(pointer)
Definition: ginblock.h:183
uint64 XLogRecPtr
Definition: xlogdefs.h:21
#define Assert(condition)
Definition: c.h:699
IndexTuple GinFormTuple(GinState *ginstate, OffsetNumber attnum, Datum key, GinNullCategory category, Pointer data, Size dataSize, int nipd, bool errorTooBig)
Definition: ginentrypage.c:45
void IndexFreeSpaceMapVacuum(Relation rel)
Definition: indexfsm.c:71
struct DataPageDeleteStack * parent
Definition: ginvacuum.c:117
IndexBulkDeleteResult * ginbulkdelete(IndexVacuumInfo *info, IndexBulkDeleteResult *stats, IndexBulkDeleteCallback callback, void *callback_state)
Definition: ginvacuum.c:551
WalTimeSample buffer[LAG_TRACKER_BUFFER_SIZE]
Definition: walsender.c:215
#define GinPageIsList(page)
Definition: ginblock.h:116
#define InvalidBlockNumber
Definition: block.h:33
BlockNumber nTotalPages
Definition: gin.h:44
#define RelationNeedsWAL(relation)
Definition: rel.h:510
#define PageIsNew(page)
Definition: bufpage.h:225
#define GinIsPostingTree(itup)
Definition: ginblock.h:225
void * palloc(Size size)
Definition: mcxt.c:924
Page PageGetTempPageCopy(Page page)
Definition: bufpage.c:365
#define SizeOfGinPostingList(plist)
Definition: ginblock.h:336
#define GinMaxItemSize
Definition: ginblock.h:242
int i
void PredicateLockPageCombine(Relation relation, BlockNumber oldblkno, BlockNumber newblkno)
Definition: predicate.c:3150
#define elog
Definition: elog.h:219
static void ginVacuumPostingTree(GinVacuumState *gvs, BlockNumber rootBlkno)
Definition: ginvacuum.c:431
void vacuum_delay_point(void)
Definition: vacuum.c:1672
void XLogBeginInsert(void)
Definition: xloginsert.c:120
#define XLOG_GIN_DELETE_PAGE
Definition: ginxlog.h:155
void RecordFreeIndexPage(Relation rel, BlockNumber freeBlock)
Definition: indexfsm.c:52
MemoryContext tmpCxt
Definition: ginvacuum.c:36
#define PageSetLSN(page, lsn)
Definition: bufpage.h:364
double num_index_tuples
Definition: genam.h:76
int Buffer
Definition: buf.h:23
bool estimated_count
Definition: genam.h:75
#define PageGetItem(page, itemId)
Definition: bufpage.h:336
#define GIN_ROOT_BLKNO
Definition: ginblock.h:51
Pointer Page
Definition: bufpage.h:74
#define IndexTupleSize(itup)
Definition: itup.h:71
bool(* IndexBulkDeleteCallback)(ItemPointer itemptr, void *state)
Definition: genam.h:83
static bool ginScanToDelete(GinVacuumState *gvs, BlockNumber blkno, bool isRoot, DataPageDeleteStack *parent, OffsetNumber myoff)
Definition: ginvacuum.c:239
int ginTraverseLock(Buffer buffer, bool searchMode)
Definition: ginbtree.c:36
bool estimated_count
Definition: genam.h:48
GinState ginstate
Definition: ginvacuum.c:34