PostgreSQL Source Code  git master
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 "postmaster/autovacuum.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)
 

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.

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

Referenced by ginhandler().

566 {
567  Relation index = info->index;
568  BlockNumber blkno = GIN_ROOT_BLKNO;
569  GinVacuumState gvs;
570  Buffer buffer;
571  BlockNumber rootOfPostingTree[BLCKSZ / (sizeof(IndexTupleData) + sizeof(ItemId))];
572  uint32 nRoot;
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 
628  itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, FirstOffsetNumber));
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);
642  Page resPage;
643  uint32 i;
644 
645  Assert(!GinPageIsData(page));
646 
647  resPage = ginVacuumEntryPage(&gvs, buffer, rootOfPostingTree, &nRoot);
648 
649  blkno = GinPageGetOpaque(page)->rightlink;
650 
651  if (resPage)
652  {
654  PageRestoreTempPage(resPage, page);
655  MarkBufferDirty(buffer);
656  xlogVacuumPage(gvs.index, buffer);
657  UnlockReleaseBuffer(buffer);
659  }
660  else
661  {
662  UnlockReleaseBuffer(buffer);
663  }
664 
666 
667  for (i = 0; i < nRoot; i++)
668  {
669  ginVacuumPostingTree(&gvs, rootOfPostingTree[i]);
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 
682 
683  return gvs.result;
684 }
#define GIN_UNLOCK
Definition: gin_private.h:48
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:211
#define AllocSetContextCreate
Definition: memutils.h:170
void PageRestoreTempPage(Page tempPage, Page oldPage)
Definition: bufpage.c:403
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:1468
Relation index
Definition: ginvacuum.c:30
Buffer ReadBufferExtended(Relation reln, ForkNumber forkNum, BlockNumber blockNum, ReadBufferMode mode, BufferAccessStrategy strategy)
Definition: bufmgr.c:652
BufferAccessStrategy strategy
Definition: ginvacuum.c:35
#define END_CRIT_SECTION()
Definition: miscadmin.h:134
BufferAccessStrategy strategy
Definition: genam.h:52
#define START_CRIT_SECTION()
Definition: miscadmin.h:132
Relation index
Definition: genam.h:46
uint32 BlockNumber
Definition: block.h:31
#define GinPageGetOpaque(page)
Definition: ginblock.h:110
#define PageGetMaxOffsetNumber(page)
Definition: bufpage.h:357
IndexBulkDeleteResult * result
Definition: ginvacuum.c:31
Definition: type.h:89
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3506
static void xlogVacuumPage(Relation index, Buffer buffer)
Definition: ginvacuum.c:90
static void callback(struct sockaddr *addr, struct sockaddr *mask, void *unused)
Definition: test_ifaddrs.c:48
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:192
static Page ginVacuumEntryPage(GinVacuumState *gvs, Buffer buffer, BlockNumber *roots, uint32 *nroot)
Definition: ginvacuum.c:455
IndexBulkDeleteCallback callback
Definition: ginvacuum.c:32
#define FirstOffsetNumber
Definition: off.h:27
IndexTupleData * IndexTuple
Definition: itup.h:53
void initGinState(GinState *state, Relation index)
Definition: ginutil.c:94
unsigned int uint32
Definition: c.h:367
MemoryContext CurrentMemoryContext
Definition: mcxt.c:38
#define GinPageIsLeaf(page)
Definition: ginblock.h:112
void * callback_state
Definition: ginvacuum.c:33
#define BufferGetPage(buffer)
Definition: bufmgr.h:169
bool IsAutoVacuumWorkerProcess(void)
Definition: autovacuum.c:3301
#define GIN_SHARE
Definition: gin_private.h:49
#define PageGetItemId(page, offsetNumber)
Definition: bufpage.h:235
void * palloc0(Size size)
Definition: mcxt.c:980
struct IndexTupleData IndexTupleData
#define GIN_EXCLUSIVE
Definition: gin_private.h:50
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3722
#define GinGetDownlink(itup)
Definition: ginblock.h:258
void ginInsertCleanup(GinState *ginstate, bool full_clean, bool fill_fsm, bool forceCleanup, IndexBulkDeleteResult *stats)
Definition: ginfast.c:774
#define GinPageIsData(page)
Definition: ginblock.h:115
#define Assert(condition)
Definition: c.h:738
#define InvalidBlockNumber
Definition: block.h:33
int i
static void ginVacuumPostingTree(GinVacuumState *gvs, BlockNumber rootBlkno)
Definition: ginvacuum.c:408
void vacuum_delay_point(void)
Definition: vacuum.c:1995
MemoryContext tmpCxt
Definition: ginvacuum.c:36
double num_index_tuples
Definition: genam.h:77
int Buffer
Definition: buf.h:23
#define PageGetItem(page, itemId)
Definition: bufpage.h:340
#define GIN_ROOT_BLKNO
Definition: ginblock.h:52
Pointer Page
Definition: bufpage.h:78
GinState ginstate
Definition: ginvacuum.c:34

◆ ginDeletePage()

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

Definition at line 130 of file ginvacuum.c.

References Assert, BufferGetPage, ginxlogDeletePage::deleteXid, END_CRIT_SECTION, GinDataPageGetPostingItem, GinPageDeletePostingItem(), GinPageGetDeleteXid, GinPageGetOpaque, GinPageSetDeleted, GinPageSetDeleteXid, GinVacuumState::index, MAIN_FORKNUM, MarkBufferDirty(), IndexBulkDeleteResult::pages_deleted, PageSetLSN, ginxlogDeletePage::parentOffset, PostingItemGetBlockNumber, PredicateLockPageCombine(), RBM_NORMAL, ReadBufferExtended(), ReadNewTransactionId(), REGBUF_STANDARD, RelationNeedsWAL, ReleaseBuffer(), GinVacuumState::result, ginxlogDeletePage::rightLink, START_CRIT_SECTION, GinVacuumState::strategy, XLOG_GIN_DELETE_PAGE, XLogBeginInsert(), XLogInsert(), XLogRegisterBuffer(), and XLogRegisterData().

Referenced by ginScanToDelete().

132 {
133  Buffer dBuffer;
134  Buffer lBuffer;
135  Buffer pBuffer;
136  Page page,
137  parentPage;
138  BlockNumber rightlink;
139 
140  /*
141  * This function MUST be called only if someone of parent pages hold
142  * exclusive cleanup lock. This guarantees that no insertions currently
143  * happen in this subtree. Caller also acquires Exclusive locks on
144  * deletable, parent and left pages.
145  */
146  lBuffer = ReadBufferExtended(gvs->index, MAIN_FORKNUM, leftBlkno,
147  RBM_NORMAL, gvs->strategy);
148  dBuffer = ReadBufferExtended(gvs->index, MAIN_FORKNUM, deleteBlkno,
149  RBM_NORMAL, gvs->strategy);
150  pBuffer = ReadBufferExtended(gvs->index, MAIN_FORKNUM, parentBlkno,
151  RBM_NORMAL, gvs->strategy);
152 
153  page = BufferGetPage(dBuffer);
154  rightlink = GinPageGetOpaque(page)->rightlink;
155 
156  /*
157  * Any insert which would have gone on the leaf block will now go to its
158  * right sibling.
159  */
160  PredicateLockPageCombine(gvs->index, deleteBlkno, rightlink);
161 
163 
164  /* Unlink the page by changing left sibling's rightlink */
165  page = BufferGetPage(lBuffer);
166  GinPageGetOpaque(page)->rightlink = rightlink;
167 
168  /* Delete downlink from parent */
169  parentPage = BufferGetPage(pBuffer);
170 #ifdef USE_ASSERT_CHECKING
171  do
172  {
173  PostingItem *tod = GinDataPageGetPostingItem(parentPage, myoff);
174 
175  Assert(PostingItemGetBlockNumber(tod) == deleteBlkno);
176  } while (0);
177 #endif
178  GinPageDeletePostingItem(parentPage, myoff);
179 
180  page = BufferGetPage(dBuffer);
181 
182  /*
183  * we shouldn't change rightlink field to save workability of running
184  * search scan
185  */
186 
187  /*
188  * Mark page as deleted, and remember last xid which could know its
189  * address.
190  */
191  GinPageSetDeleted(page);
193 
194  MarkBufferDirty(pBuffer);
195  MarkBufferDirty(lBuffer);
196  MarkBufferDirty(dBuffer);
197 
198  if (RelationNeedsWAL(gvs->index))
199  {
200  XLogRecPtr recptr;
201  ginxlogDeletePage data;
202 
203  /*
204  * We can't pass REGBUF_STANDARD for the deleted page, because we
205  * didn't set pd_lower on pre-9.4 versions. The page might've been
206  * binary-upgraded from an older version, and hence not have pd_lower
207  * set correctly. Ditto for the left page, but removing the item from
208  * the parent updated its pd_lower, so we know that's OK at this
209  * point.
210  */
211  XLogBeginInsert();
212  XLogRegisterBuffer(0, dBuffer, 0);
213  XLogRegisterBuffer(1, pBuffer, REGBUF_STANDARD);
214  XLogRegisterBuffer(2, lBuffer, 0);
215 
216  data.parentOffset = myoff;
217  data.rightLink = GinPageGetOpaque(page)->rightlink;
218  data.deleteXid = GinPageGetDeleteXid(page);
219 
220  XLogRegisterData((char *) &data, sizeof(ginxlogDeletePage));
221 
222  recptr = XLogInsert(RM_GIN_ID, XLOG_GIN_DELETE_PAGE);
223  PageSetLSN(page, recptr);
224  PageSetLSN(parentPage, recptr);
225  PageSetLSN(BufferGetPage(lBuffer), recptr);
226  }
227 
228  ReleaseBuffer(pBuffer);
229  ReleaseBuffer(lBuffer);
230  ReleaseBuffer(dBuffer);
231 
233 
234  gvs->result->pages_deleted++;
235 }
TransactionId deleteXid
Definition: ginxlog.h:159
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:1468
void XLogRegisterBuffer(uint8 block_id, Buffer buffer, uint8 flags)
Definition: xloginsert.c:214
Relation index
Definition: ginvacuum.c:30
Buffer ReadBufferExtended(Relation reln, ForkNumber forkNum, BlockNumber blockNum, ReadBufferMode mode, BufferAccessStrategy strategy)
Definition: bufmgr.c:652
BlockNumber rightLink
Definition: ginxlog.h:158
BufferAccessStrategy strategy
Definition: ginvacuum.c:35
#define END_CRIT_SECTION()
Definition: miscadmin.h:134
#define START_CRIT_SECTION()
Definition: miscadmin.h:132
#define GinPageGetDeleteXid(page)
Definition: ginblock.h:135
uint32 BlockNumber
Definition: block.h:31
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3483
#define GinPageGetOpaque(page)
Definition: ginblock.h:110
OffsetNumber parentOffset
Definition: ginxlog.h:157
IndexBulkDeleteResult * result
Definition: ginvacuum.c:31
#define GinDataPageGetPostingItem(page, i)
Definition: ginblock.h:299
#define REGBUF_STANDARD
Definition: xloginsert.h:35
BlockNumber pages_deleted
Definition: genam.h:79
#define BufferGetPage(buffer)
Definition: bufmgr.h:169
void XLogRegisterData(char *data, int len)
Definition: xloginsert.c:324
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:416
void GinPageDeletePostingItem(Page page, OffsetNumber offset)
Definition: gindatapage.c:417
#define PostingItemGetBlockNumber(pointer)
Definition: ginblock.h:190
uint64 XLogRecPtr
Definition: xlogdefs.h:21
#define Assert(condition)
Definition: c.h:738
#define GinPageSetDeleteXid(page, xid)
Definition: ginblock.h:136
#define RelationNeedsWAL(relation)
Definition: rel.h:562
static TransactionId ReadNewTransactionId(void)
Definition: transam.h:258
#define GinPageSetDeleted(page)
Definition: ginblock.h:125
void PredicateLockPageCombine(Relation relation, BlockNumber oldblkno, BlockNumber newblkno)
Definition: predicate.c:3183
void XLogBeginInsert(void)
Definition: xloginsert.c:121
#define XLOG_GIN_DELETE_PAGE
Definition: ginxlog.h:153
#define PageSetLSN(page, lsn)
Definition: bufpage.h:368
int Buffer
Definition: buf.h:23
Pointer Page
Definition: bufpage.h:78

◆ ginScanToDelete()

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

Definition at line 246 of file ginvacuum.c.

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

Referenced by ginVacuumPostingTree().

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  {
284  OffsetNumber i;
285 
286  me->blkno = blkno;
287  for (i = FirstOffsetNumber; i <= GinPageGetOpaque(page)->maxoff; i++)
288  {
289  PostingItem *pitem = GinDataPageGetPostingItem(page, i);
290 
291  if (ginScanToDelete(gvs, PostingItemGetBlockNumber(pitem), false, me, i))
292  i--;
293  }
294 
295  if (GinPageRightMost(page) && BufferIsValid(me->child->leftBuffer))
296  {
299  }
300  }
301 
302  if (GinPageIsLeaf(page))
303  isempty = GinDataLeafPageIsEmpty(page);
304  else
305  isempty = GinPageGetOpaque(page)->maxoff < FirstOffsetNumber;
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);
314  me->parent->blkno, myoff, me->parent->isRoot);
315  meDelete = true;
316  }
317  }
318 
319  if (!meDelete)
320  {
321  if (BufferIsValid(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 GIN_UNLOCK
Definition: gin_private.h:48
Relation index
Definition: ginvacuum.c:30
Buffer ReadBufferExtended(Relation reln, ForkNumber forkNum, BlockNumber blockNum, ReadBufferMode mode, BufferAccessStrategy strategy)
Definition: bufmgr.c:652
BufferAccessStrategy strategy
Definition: ginvacuum.c:35
#define InvalidBuffer
Definition: buf.h:25
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3483
#define GinPageGetOpaque(page)
Definition: ginblock.h:110
static void ginDeletePage(GinVacuumState *gvs, BlockNumber deleteBlkno, BlockNumber leftBlkno, BlockNumber parentBlkno, OffsetNumber myoff, bool isParentRoot)
Definition: ginvacuum.c:130
#define GinDataLeafPageIsEmpty(page)
Definition: ginblock.h:284
uint16 OffsetNumber
Definition: off.h:24
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3506
#define GinPageRightMost(page)
Definition: ginblock.h:129
#define GinDataPageGetPostingItem(page, i)
Definition: ginblock.h:299
BlockNumber blkno
Definition: ginvacuum.c:119
#define FirstOffsetNumber
Definition: off.h:27
#define GinPageIsLeaf(page)
Definition: ginblock.h:112
#define BufferGetPage(buffer)
Definition: bufmgr.h:169
void * palloc0(Size size)
Definition: mcxt.c:980
#define GIN_EXCLUSIVE
Definition: gin_private.h:50
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3722
struct DataPageDeleteStack * child
Definition: ginvacuum.c:116
#define GinPageIsData(page)
Definition: ginblock.h:115
#define PostingItemGetBlockNumber(pointer)
Definition: ginblock.h:190
#define Assert(condition)
Definition: c.h:738
struct DataPageDeleteStack * parent
Definition: ginvacuum.c:117
#define BufferIsValid(bufnum)
Definition: bufmgr.h:123
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:2633
int i
int Buffer
Definition: buf.h:23
Pointer Page
Definition: bufpage.h:78
static bool ginScanToDelete(GinVacuumState *gvs, BlockNumber blkno, bool isRoot, DataPageDeleteStack *parent, OffsetNumber myoff)
Definition: ginvacuum.c:246

◆ ginvacuumcleanup()

IndexBulkDeleteResult* ginvacuumcleanup ( IndexVacuumInfo info,
IndexBulkDeleteResult stats 
)

Definition at line 687 of file ginvacuum.c.

References IndexVacuumInfo::analyze_only, Assert, DataPageDeleteStack::blkno, BufferGetPage, IndexVacuumInfo::estimated_count, IndexBulkDeleteResult::estimated_count, ExclusiveLock, GIN_ROOT_BLKNO, GIN_SHARE, ginInsertCleanup(), GinPageIsData, GinPageIsLeaf, GinPageIsList, GinPageIsRecyclable, GinVacuumState::ginstate, ginUpdateStats(), IndexVacuumInfo::index, IndexFreeSpaceMapVacuum(), initGinState(), IsAutoVacuumWorkerProcess(), LockBuffer(), LockRelationForExtension(), MAIN_FORKNUM, GinStatsData::nDataPages, GinStatsData::nEntries, GinStatsData::nEntryPages, GinStatsData::nTotalPages, IndexVacuumInfo::num_heap_tuples, IndexBulkDeleteResult::num_index_tuples, IndexBulkDeleteResult::num_pages, PageGetMaxOffsetNumber, IndexBulkDeleteResult::pages_free, palloc0(), RBM_NORMAL, ReadBufferExtended(), RecordFreeIndexPage(), RELATION_IS_LOCAL, RelationGetNumberOfBlocks, IndexVacuumInfo::strategy, UnlockRelationForExtension(), UnlockReleaseBuffer(), and vacuum_delay_point().

Referenced by ginhandler().

688 {
689  Relation index = info->index;
690  bool needLock;
691  BlockNumber npages,
692  blkno;
693  BlockNumber totFreePages;
694  GinState ginstate;
695  GinStatsData idxStat;
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 = info->num_heap_tuples;
731  stats->estimated_count = info->estimated_count;
732 
733  /*
734  * Need lock unless it's local to this backend.
735  */
736  needLock = !RELATION_IS_LOCAL(index);
737 
738  if (needLock)
740  npages = RelationGetNumberOfBlocks(index);
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 
752 
753  buffer = ReadBufferExtended(index, MAIN_FORKNUM, blkno,
754  RBM_NORMAL, info->strategy);
755  LockBuffer(buffer, GIN_SHARE);
756  page = (Page) BufferGetPage(buffer);
757 
758  if (GinPageIsRecyclable(page))
759  {
760  Assert(blkno != GIN_ROOT_BLKNO);
761  RecordFreeIndexPage(index, 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)
790  stats->num_pages = RelationGetNumberOfBlocks(index);
791  if (needLock)
793 
794  return stats;
795 }
BlockNumber nEntryPages
Definition: gin.h:46
#define GinPageIsRecyclable(page)
Definition: ginblock.h:137
#define ExclusiveLock
Definition: lockdefs.h:44
#define RELATION_IS_LOCAL(relation)
Definition: rel.h:583
bool analyze_only
Definition: genam.h:47
Buffer ReadBufferExtended(Relation reln, ForkNumber forkNum, BlockNumber blockNum, ReadBufferMode mode, BufferAccessStrategy strategy)
Definition: bufmgr.c:652
BufferAccessStrategy strategy
Definition: genam.h:52
Relation index
Definition: genam.h:46
int64 nEntries
Definition: gin.h:48
uint32 BlockNumber
Definition: block.h:31
#define PageGetMaxOffsetNumber(page)
Definition: bufpage.h:357
Definition: type.h:89
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3506
BlockNumber num_pages
Definition: genam.h:74
BlockNumber pages_free
Definition: genam.h:80
void initGinState(GinState *state, Relation index)
Definition: ginutil.c:94
#define GinPageIsLeaf(page)
Definition: ginblock.h:112
#define BufferGetPage(buffer)
Definition: bufmgr.h:169
bool IsAutoVacuumWorkerProcess(void)
Definition: autovacuum.c:3301
#define GIN_SHARE
Definition: gin_private.h:49
void LockRelationForExtension(Relation relation, LOCKMODE lockmode)
Definition: lmgr.c:402
void * palloc0(Size size)
Definition: mcxt.c:980
void UnlockRelationForExtension(Relation relation, LOCKMODE lockmode)
Definition: lmgr.c:452
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3722
#define RelationGetNumberOfBlocks(reln)
Definition: bufmgr.h:211
BlockNumber nDataPages
Definition: gin.h:47
void ginInsertCleanup(GinState *ginstate, bool full_clean, bool fill_fsm, bool forceCleanup, IndexBulkDeleteResult *stats)
Definition: ginfast.c:774
#define GinPageIsData(page)
Definition: ginblock.h:115
double num_heap_tuples
Definition: genam.h:51
#define Assert(condition)
Definition: c.h:738
void IndexFreeSpaceMapVacuum(Relation rel)
Definition: indexfsm.c:71
#define GinPageIsList(page)
Definition: ginblock.h:117
BlockNumber nTotalPages
Definition: gin.h:45
void ginUpdateStats(Relation index, const GinStatsData *stats, bool is_build)
Definition: ginutil.c:656
void vacuum_delay_point(void)
Definition: vacuum.c:1995
void RecordFreeIndexPage(Relation rel, BlockNumber freeBlock)
Definition: indexfsm.c:52
double num_index_tuples
Definition: genam.h:77
int Buffer
Definition: buf.h:23
bool estimated_count
Definition: genam.h:76
#define GIN_ROOT_BLKNO
Definition: ginblock.h:52
Pointer Page
Definition: bufpage.h:78
bool estimated_count
Definition: genam.h:49

◆ ginVacuumEntryPage()

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

Definition at line 455 of file ginvacuum.c.

References attnum, BufferGetPage, elog, ERROR, FirstOffsetNumber, ginCompressPostingList(), GinFormTuple(), GinGetDownlink, GinGetNPosting, GinGetPosting, GinIsPostingTree, GinItupIsCompressed, GinMaxItemSize, ginPostingListDecode(), GinVacuumState::ginstate, gintuple_get_attrnum(), gintuple_get_key(), ginVacuumItemPointers(), i, GinVacuumState::index, IndexTupleSize, sort-test::key, PageAddItem, PageGetItem, PageGetItemId, PageGetMaxOffsetNumber, PageGetTempPageCopy(), PageIndexTupleDelete(), pfree(), RelationGetRelationName, and SizeOfGinPostingList.

Referenced by ginbulkdelete().

456 {
457  Page origpage = BufferGetPage(buffer),
458  tmppage;
459  OffsetNumber i,
460  maxoff = PageGetMaxOffsetNumber(origpage);
461 
462  tmppage = origpage;
463 
464  *nroot = 0;
465 
466  for (i = FirstOffsetNumber; i <= maxoff; i++)
467  {
468  IndexTuple itup = (IndexTuple) PageGetItem(tmppage, PageGetItemId(tmppage, i));
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;
482  ItemPointer items_orig;
483  bool free_items_orig;
484  ItemPointer items;
485 
486  /* Get list of item pointers from the tuple. */
487  if (GinItupIsCompressed(itup))
488  {
489  items_orig = ginPostingListDecode((GinPostingList *) GinGetPosting(itup), &nitems);
490  free_items_orig = true;
491  }
492  else
493  {
494  items_orig = (ItemPointer) GinGetPosting(itup);
495  nitems = GinGetNPosting(itup);
496  free_items_orig = false;
497  }
498 
499  /* Remove any items from the list that need to be vacuumed. */
500  items = ginVacuumItemPointers(gvs, items_orig, nitems, &nitems);
501 
502  if (free_items_orig)
503  pfree(items_orig);
504 
505  /* If any item pointers were removed, recreate the tuple. */
506  if (items)
507  {
509  Datum key;
510  GinNullCategory category;
511  GinPostingList *plist;
512  int plistsize;
513 
514  if (nitems > 0)
515  {
516  plist = ginCompressPostingList(items, nitems, GinMaxItemSize, NULL);
517  plistsize = SizeOfGinPostingList(plist);
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 */
538  itup = (IndexTuple) PageGetItem(tmppage, PageGetItemId(tmppage, i));
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);
548  PageIndexTupleDelete(tmppage, i);
549 
550  if (PageAddItem(tmppage, (Item) 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 }
GinPostingList * ginCompressPostingList(const ItemPointer ipd, int nipd, int maxsize, int *nwritten)
ItemPointer ginPostingListDecode(GinPostingList *plist, int *ndecoded)
void PageIndexTupleDelete(Page page, OffsetNumber offnum)
Definition: bufpage.c:719
Relation index
Definition: ginvacuum.c:30
Pointer Item
Definition: item.h:17
ItemPointer ginVacuumItemPointers(GinVacuumState *gvs, ItemPointerData *items, int nitem, int *nremaining)
Definition: ginvacuum.c:48
#define PageAddItem(page, item, size, offsetNumber, overwrite, is_heap)
Definition: bufpage.h:416
#define GinGetNPosting(itup)
Definition: ginblock.h:229
#define PageGetMaxOffsetNumber(page)
Definition: bufpage.h:357
#define GinGetPosting(itup)
Definition: ginblock.h:239
#define GinItupIsCompressed(itup)
Definition: ginblock.h:240
uint16 OffsetNumber
Definition: off.h:24
ItemPointerData * ItemPointer
Definition: itemptr.h:49
void pfree(void *pointer)
Definition: mcxt.c:1056
#define ERROR
Definition: elog.h:43
signed char GinNullCategory
Definition: ginblock.h:207
OffsetNumber gintuple_get_attrnum(GinState *ginstate, IndexTuple tuple)
Definition: ginutil.c:223
#define FirstOffsetNumber
Definition: off.h:27
IndexTupleData * IndexTuple
Definition: itup.h:53
#define RelationGetRelationName(relation)
Definition: rel.h:490
Datum gintuple_get_key(GinState *ginstate, IndexTuple tuple, GinNullCategory *category)
Definition: ginutil.c:256
#define BufferGetPage(buffer)
Definition: bufmgr.h:169
#define PageGetItemId(page, offsetNumber)
Definition: bufpage.h:235
uintptr_t Datum
Definition: postgres.h:367
#define GinGetDownlink(itup)
Definition: ginblock.h:258
int16 attnum
Definition: pg_attribute.h:79
IndexTuple GinFormTuple(GinState *ginstate, OffsetNumber attnum, Datum key, GinNullCategory category, Pointer data, Size dataSize, int nipd, bool errorTooBig)
Definition: ginentrypage.c:45
#define GinIsPostingTree(itup)
Definition: ginblock.h:232
Page PageGetTempPageCopy(Page page)
Definition: bufpage.c:361
#define SizeOfGinPostingList(plist)
Definition: ginblock.h:343
#define GinMaxItemSize
Definition: ginblock.h:249
#define elog(elevel,...)
Definition: elog.h:214
int i
#define PageGetItem(page, itemId)
Definition: bufpage.h:340
Pointer Page
Definition: bufpage.h:78
#define IndexTupleSize(itup)
Definition: itup.h:71
GinState ginstate
Definition: ginvacuum.c:34

◆ ginVacuumItemPointers()

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

Definition at line 48 of file ginvacuum.c.

References GinVacuumState::callback, GinVacuumState::callback_state, i, IndexBulkDeleteResult::num_index_tuples, palloc(), remaining, GinVacuumState::result, and IndexBulkDeleteResult::tuples_removed.

Referenced by ginVacuumEntryPage(), and ginVacuumPostingTreeLeaf().

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 }
int remaining
Definition: informix.c:667
double tuples_removed
Definition: genam.h:78
IndexBulkDeleteResult * result
Definition: ginvacuum.c:31
IndexBulkDeleteCallback callback
Definition: ginvacuum.c:32
void * callback_state
Definition: ginvacuum.c:33
void * palloc(Size size)
Definition: mcxt.c:949
int i
double num_index_tuples
Definition: genam.h:77

◆ ginVacuumPostingTree()

static void ginVacuumPostingTree ( GinVacuumState gvs,
BlockNumber  rootBlkno 
)
static

Definition at line 408 of file ginvacuum.c.

References DataPageDeleteStack::child, ginScanToDelete(), ginVacuumPostingTreeLeaves(), GinVacuumState::index, InvalidBuffer, InvalidOffsetNumber, DataPageDeleteStack::isRoot, DataPageDeleteStack::leftBuffer, LockBufferForCleanup(), MAIN_FORKNUM, pfree(), RBM_NORMAL, ReadBufferExtended(), GinVacuumState::strategy, and UnlockReleaseBuffer().

Referenced by ginbulkdelete().

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;
417  DataPageDeleteStack root,
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:3779
Relation index
Definition: ginvacuum.c:30
Buffer ReadBufferExtended(Relation reln, ForkNumber forkNum, BlockNumber blockNum, ReadBufferMode mode, BufferAccessStrategy strategy)
Definition: bufmgr.c:652
BufferAccessStrategy strategy
Definition: ginvacuum.c:35
#define InvalidBuffer
Definition: buf.h:25
void pfree(void *pointer)
Definition: mcxt.c:1056
static bool ginVacuumPostingTreeLeaves(GinVacuumState *gvs, BlockNumber blkno)
Definition: ginvacuum.c:345
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3506
struct DataPageDeleteStack * child
Definition: ginvacuum.c:116
#define InvalidOffsetNumber
Definition: off.h:26
int Buffer
Definition: buf.h:23
static bool ginScanToDelete(GinVacuumState *gvs, BlockNumber blkno, bool isRoot, DataPageDeleteStack *parent, OffsetNumber myoff)
Definition: ginvacuum.c:246

◆ ginVacuumPostingTreeLeaves()

static bool ginVacuumPostingTreeLeaves ( GinVacuumState gvs,
BlockNumber  blkno 
)
static

Definition at line 345 of file ginvacuum.c.

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

Referenced by ginVacuumPostingTree().

346 {
347  Buffer buffer;
348  Page page;
349  bool hasVoidPage = false;
350  MemoryContext oldCxt;
351 
352  /* Find leftmost leaf page of posting tree and lock it in exclusive mode */
353  while (true)
354  {
355  PostingItem *pitem;
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 
374  blkno = PostingItemGetBlockNumber(pitem);
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  {
383  oldCxt = MemoryContextSwitchTo(gvs->tmpCxt);
384  ginVacuumPostingTreeLeaf(gvs->index, buffer, gvs);
385  MemoryContextSwitchTo(oldCxt);
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 }
#define GIN_UNLOCK
Definition: gin_private.h:48
Relation index
Definition: ginvacuum.c:30
Buffer ReadBufferExtended(Relation reln, ForkNumber forkNum, BlockNumber blockNum, ReadBufferMode mode, BufferAccessStrategy strategy)
Definition: bufmgr.c:652
BufferAccessStrategy strategy
Definition: ginvacuum.c:35
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:136
#define GinPageGetOpaque(page)
Definition: ginblock.h:110
#define PageGetMaxOffsetNumber(page)
Definition: bufpage.h:357
#define GinDataLeafPageIsEmpty(page)
Definition: ginblock.h:284
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3506
#define GinDataPageGetPostingItem(page, i)
Definition: ginblock.h:299
void ginVacuumPostingTreeLeaf(Relation indexrel, Buffer buffer, GinVacuumState *gvs)
Definition: gindatapage.c:735
#define FirstOffsetNumber
Definition: off.h:27
#define GinPageIsLeaf(page)
Definition: ginblock.h:112
#define BufferGetPage(buffer)
Definition: bufmgr.h:169
#define GIN_SHARE
Definition: gin_private.h:49
#define GIN_EXCLUSIVE
Definition: gin_private.h:50
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3722
#define GinPageIsData(page)
Definition: ginblock.h:115
#define PostingItemGetBlockNumber(pointer)
Definition: ginblock.h:190
#define Assert(condition)
Definition: c.h:738
#define InvalidBlockNumber
Definition: block.h:33
MemoryContext tmpCxt
Definition: ginvacuum.c:36
int Buffer
Definition: buf.h:23
Pointer Page
Definition: bufpage.h:78

◆ xlogVacuumPage()

static void xlogVacuumPage ( Relation  index,
Buffer  buffer 
)
static

Definition at line 90 of file ginvacuum.c.

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

Referenced by ginbulkdelete().

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 }
void XLogRegisterBuffer(uint8 block_id, Buffer buffer, uint8 flags)
Definition: xloginsert.c:214
#define REGBUF_STANDARD
Definition: xloginsert.h:35
#define GinPageIsLeaf(page)
Definition: ginblock.h:112
#define BufferGetPage(buffer)
Definition: bufmgr.h:169
#define REGBUF_FORCE_IMAGE
Definition: xloginsert.h:31
#define XLOG_GIN_VACUUM_PAGE
Definition: ginxlog.h:135
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:416
#define GinPageIsData(page)
Definition: ginblock.h:115
uint64 XLogRecPtr
Definition: xlogdefs.h:21
#define Assert(condition)
Definition: c.h:738
#define RelationNeedsWAL(relation)
Definition: rel.h:562
void XLogBeginInsert(void)
Definition: xloginsert.c:121
#define PageSetLSN(page, lsn)
Definition: bufpage.h:368
Pointer Page
Definition: bufpage.h:78