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, bool isRoot)
 
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 552 of file ginvacuum.c.

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

554 {
555  Relation index = info->index;
556  BlockNumber blkno = GIN_ROOT_BLKNO;
557  GinVacuumState gvs;
558  Buffer buffer;
559  BlockNumber rootOfPostingTree[BLCKSZ / (sizeof(IndexTupleData) + sizeof(ItemId))];
560  uint32 nRoot;
561 
563  "Gin vacuum temporary context",
565  gvs.index = index;
566  gvs.callback = callback;
567  gvs.callback_state = callback_state;
568  gvs.strategy = info->strategy;
569  initGinState(&gvs.ginstate, index);
570 
571  /* first time through? */
572  if (stats == NULL)
573  {
574  /* Yes, so initialize stats to zeroes */
576 
577  /*
578  * and cleanup any pending inserts
579  */
581  false, true, stats);
582  }
583 
584  /* we'll re-count the tuples each time */
585  stats->num_index_tuples = 0;
586  gvs.result = stats;
587 
588  buffer = ReadBufferExtended(index, MAIN_FORKNUM, blkno,
589  RBM_NORMAL, info->strategy);
590 
591  /* find leaf page */
592  for (;;)
593  {
594  Page page = BufferGetPage(buffer);
595  IndexTuple itup;
596 
597  LockBuffer(buffer, GIN_SHARE);
598 
599  Assert(!GinPageIsData(page));
600 
601  if (GinPageIsLeaf(page))
602  {
603  LockBuffer(buffer, GIN_UNLOCK);
604  LockBuffer(buffer, GIN_EXCLUSIVE);
605 
606  if (blkno == GIN_ROOT_BLKNO && !GinPageIsLeaf(page))
607  {
608  LockBuffer(buffer, GIN_UNLOCK);
609  continue; /* check it one more */
610  }
611  break;
612  }
613 
615 
616  itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, FirstOffsetNumber));
617  blkno = GinGetDownlink(itup);
618  Assert(blkno != InvalidBlockNumber);
619 
620  UnlockReleaseBuffer(buffer);
621  buffer = ReadBufferExtended(index, MAIN_FORKNUM, blkno,
622  RBM_NORMAL, info->strategy);
623  }
624 
625  /* right now we found leftmost page in entry's BTree */
626 
627  for (;;)
628  {
629  Page page = BufferGetPage(buffer);
630  Page resPage;
631  uint32 i;
632 
633  Assert(!GinPageIsData(page));
634 
635  resPage = ginVacuumEntryPage(&gvs, buffer, rootOfPostingTree, &nRoot);
636 
637  blkno = GinPageGetOpaque(page)->rightlink;
638 
639  if (resPage)
640  {
642  PageRestoreTempPage(resPage, page);
643  MarkBufferDirty(buffer);
644  xlogVacuumPage(gvs.index, buffer);
645  UnlockReleaseBuffer(buffer);
647  }
648  else
649  {
650  UnlockReleaseBuffer(buffer);
651  }
652 
654 
655  for (i = 0; i < nRoot; i++)
656  {
657  ginVacuumPostingTree(&gvs, rootOfPostingTree[i]);
659  }
660 
661  if (blkno == InvalidBlockNumber) /* rightmost page */
662  break;
663 
664  buffer = ReadBufferExtended(index, MAIN_FORKNUM, blkno,
665  RBM_NORMAL, info->strategy);
666  LockBuffer(buffer, GIN_EXCLUSIVE);
667  }
668 
670 
671  return gvs.result;
672 }
#define GIN_UNLOCK
Definition: gin_private.h:43
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:211
void PageRestoreTempPage(Page tempPage, Page oldPage)
Definition: bufpage.c:407
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:1450
Relation index
Definition: ginvacuum.c:30
Buffer ReadBufferExtended(Relation reln, ForkNumber forkNum, BlockNumber blockNum, ReadBufferMode mode, BufferAccessStrategy strategy)
Definition: bufmgr.c:640
BufferAccessStrategy strategy
Definition: ginvacuum.c:35
#define END_CRIT_SECTION()
Definition: miscadmin.h:133
BufferAccessStrategy strategy
Definition: genam.h:51
#define START_CRIT_SECTION()
Definition: miscadmin.h:131
Relation index
Definition: genam.h:46
uint32 BlockNumber
Definition: block.h:31
#define GinPageGetOpaque(page)
Definition: ginblock.h:109
#define PageGetMaxOffsetNumber(page)
Definition: bufpage.h:353
IndexBulkDeleteResult * result
Definition: ginvacuum.c:31
Definition: type.h:89
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3332
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:443
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:88
unsigned int uint32
Definition: c.h:325
MemoryContext CurrentMemoryContext
Definition: mcxt.c:38
#define GinPageIsLeaf(page)
Definition: ginblock.h:111
void * callback_state
Definition: ginvacuum.c:33
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
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 PageGetItemId(page, offsetNumber)
Definition: bufpage.h:231
void * palloc0(Size size)
Definition: mcxt.c:955
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 ginInsertCleanup(GinState *ginstate, bool full_clean, bool fill_fsm, bool forceCleanup, IndexBulkDeleteResult *stats)
Definition: ginfast.c:754
#define GinPageIsData(page)
Definition: ginblock.h:114
#define Assert(condition)
Definition: c.h:699
WalTimeSample buffer[LAG_TRACKER_BUFFER_SIZE]
Definition: walsender.c:215
#define InvalidBlockNumber
Definition: block.h:33
int i
static void ginVacuumPostingTree(GinVacuumState *gvs, BlockNumber rootBlkno)
Definition: ginvacuum.c:432
void vacuum_delay_point(void)
Definition: vacuum.c:1672
MemoryContext tmpCxt
Definition: ginvacuum.c:36
double num_index_tuples
Definition: genam.h:76
int Buffer
Definition: buf.h:23
#define PageGetItem(page, itemId)
Definition: bufpage.h:336
#define GIN_ROOT_BLKNO
Definition: ginblock.h:51
Pointer Page
Definition: bufpage.h:74
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 129 of file ginvacuum.c.

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

Referenced by ginScanToDelete().

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 
170  page = BufferGetPage(lBuffer);
171  GinPageGetOpaque(page)->rightlink = rightlink;
172 
173  /* Delete downlink from parent */
174  parentPage = BufferGetPage(pBuffer);
175 #ifdef USE_ASSERT_CHECKING
176  do
177  {
178  PostingItem *tod = GinDataPageGetPostingItem(parentPage, myoff);
179 
180  Assert(PostingItemGetBlockNumber(tod) == deleteBlkno);
181  } while (0);
182 #endif
183  GinPageDeletePostingItem(parentPage, myoff);
184 
185  page = BufferGetPage(dBuffer);
186 
187  /*
188  * we shouldn't change rightlink field to save workability of running
189  * search scan
190  */
191  GinPageGetOpaque(page)->flags = GIN_DELETED;
192 
193  MarkBufferDirty(pBuffer);
194  MarkBufferDirty(lBuffer);
195  MarkBufferDirty(dBuffer);
196 
197  if (RelationNeedsWAL(gvs->index))
198  {
199  XLogRecPtr recptr;
200  ginxlogDeletePage data;
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  */
210  XLogBeginInsert();
211  XLogRegisterBuffer(0, dBuffer, 0);
212  XLogRegisterBuffer(1, pBuffer, REGBUF_STANDARD);
213  XLogRegisterBuffer(2, lBuffer, 0);
214 
215  data.parentOffset = myoff;
216  data.rightLink = GinPageGetOpaque(page)->rightlink;
217 
218  XLogRegisterData((char *) &data, sizeof(ginxlogDeletePage));
219 
220  recptr = XLogInsert(RM_GIN_ID, XLOG_GIN_DELETE_PAGE);
221  PageSetLSN(page, recptr);
222  PageSetLSN(parentPage, recptr);
223  PageSetLSN(BufferGetPage(lBuffer), recptr);
224  }
225 
226  ReleaseBuffer(pBuffer);
227  UnlockReleaseBuffer(lBuffer);
228  ReleaseBuffer(dBuffer);
229 
231 
232  gvs->result->pages_deleted++;
233 }
#define GIN_DELETED
Definition: ginblock.h:41
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:1450
void XLogRegisterBuffer(uint8 block_id, Buffer buffer, uint8 flags)
Definition: xloginsert.c:213
Relation index
Definition: ginvacuum.c:30
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
#define START_CRIT_SECTION()
Definition: miscadmin.h:131
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
IndexBulkDeleteResult * result
Definition: ginvacuum.c:31
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3332
#define GinDataPageGetPostingItem(page, i)
Definition: ginblock.h:292
#define REGBUF_STANDARD
Definition: xloginsert.h:34
BlockNumber pages_deleted
Definition: genam.h:78
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
void XLogRegisterData(char *data, int len)
Definition: xloginsert.c:323
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:415
#define GIN_EXCLUSIVE
Definition: gin_private.h:45
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3546
void GinPageDeletePostingItem(Page page, OffsetNumber offset)
Definition: gindatapage.c:414
#define PostingItemGetBlockNumber(pointer)
Definition: ginblock.h:183
uint64 XLogRecPtr
Definition: xlogdefs.h:21
#define Assert(condition)
Definition: c.h:699
#define RelationNeedsWAL(relation)
Definition: rel.h:510
void PredicateLockPageCombine(Relation relation, BlockNumber oldblkno, BlockNumber newblkno)
Definition: predicate.c:3150
void XLogBeginInsert(void)
Definition: xloginsert.c:120
#define XLOG_GIN_DELETE_PAGE
Definition: ginxlog.h:155
#define PageSetLSN(page, lsn)
Definition: bufpage.h:364
int Buffer
Definition: buf.h:23
Pointer Page
Definition: bufpage.h:74

◆ ginScanToDelete()

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

Definition at line 240 of file ginvacuum.c.

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

Referenced by ginVacuumPostingTreeLeaves().

242 {
244  Buffer buffer;
245  Page page;
246  bool meDelete = false;
247  bool isempty;
248 
249  if (isRoot)
250  {
251  me = parent;
252  }
253  else
254  {
255  if (!parent->child)
256  {
258  me->parent = parent;
259  parent->child = me;
261  }
262  else
263  me = parent->child;
264  }
265 
266  buffer = ReadBufferExtended(gvs->index, MAIN_FORKNUM, blkno,
267  RBM_NORMAL, gvs->strategy);
268 
269  if (!isRoot)
270  LockBuffer(buffer, GIN_EXCLUSIVE);
271 
272  page = BufferGetPage(buffer);
273 
274  Assert(GinPageIsData(page));
275 
276  if (!GinPageIsLeaf(page))
277  {
278  OffsetNumber i;
279 
280  me->blkno = blkno;
281  for (i = FirstOffsetNumber; i <= GinPageGetOpaque(page)->maxoff; i++)
282  {
283  PostingItem *pitem = GinDataPageGetPostingItem(page, i);
284 
285  if (ginScanToDelete(gvs, PostingItemGetBlockNumber(pitem), false, me, i))
286  i--;
287  }
288  }
289 
290  if (GinPageIsLeaf(page))
291  isempty = GinDataLeafPageIsEmpty(page);
292  else
293  isempty = GinPageGetOpaque(page)->maxoff < FirstOffsetNumber;
294 
295  if (isempty)
296  {
297  /* we never delete the left- or rightmost branch */
298  if (me->leftBlkno != InvalidBlockNumber && !GinPageRightMost(page))
299  {
300  Assert(!isRoot);
301  ginDeletePage(gvs, blkno, me->leftBlkno, me->parent->blkno, myoff, me->parent->isRoot);
302  meDelete = true;
303  }
304  }
305 
306  if (!isRoot)
307  LockBuffer(buffer, GIN_UNLOCK);
308 
309  ReleaseBuffer(buffer);
310 
311  if (!meDelete)
312  me->leftBlkno = blkno;
313 
314  return meDelete;
315 }
#define GIN_UNLOCK
Definition: gin_private.h:43
Relation index
Definition: ginvacuum.c:30
Buffer ReadBufferExtended(Relation reln, ForkNumber forkNum, BlockNumber blockNum, ReadBufferMode mode, BufferAccessStrategy strategy)
Definition: bufmgr.c:640
BufferAccessStrategy strategy
Definition: ginvacuum.c:35
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3309
#define GinPageGetOpaque(page)
Definition: ginblock.h:109
static void ginDeletePage(GinVacuumState *gvs, BlockNumber deleteBlkno, BlockNumber leftBlkno, BlockNumber parentBlkno, OffsetNumber myoff, bool isParentRoot)
Definition: ginvacuum.c:129
#define GinDataLeafPageIsEmpty(page)
Definition: ginblock.h:277
uint16 OffsetNumber
Definition: off.h:24
BlockNumber leftBlkno
Definition: ginvacuum.c:120
#define GinPageRightMost(page)
Definition: ginblock.h:128
#define GinDataPageGetPostingItem(page, i)
Definition: ginblock.h:292
BlockNumber blkno
Definition: ginvacuum.c:119
#define FirstOffsetNumber
Definition: off.h:27
#define GinPageIsLeaf(page)
Definition: ginblock.h:111
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
void * palloc0(Size size)
Definition: mcxt.c:955
#define GIN_EXCLUSIVE
Definition: gin_private.h:45
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3546
struct DataPageDeleteStack * child
Definition: ginvacuum.c:116
#define GinPageIsData(page)
Definition: ginblock.h:114
#define PostingItemGetBlockNumber(pointer)
Definition: ginblock.h:183
#define Assert(condition)
Definition: c.h:699
struct DataPageDeleteStack * parent
Definition: ginvacuum.c:117
WalTimeSample buffer[LAG_TRACKER_BUFFER_SIZE]
Definition: walsender.c:215
#define InvalidBlockNumber
Definition: block.h:33
int i
int Buffer
Definition: buf.h:23
Pointer Page
Definition: bufpage.h:74
static bool ginScanToDelete(GinVacuumState *gvs, BlockNumber blkno, bool isRoot, DataPageDeleteStack *parent, OffsetNumber myoff)
Definition: ginvacuum.c:240

◆ ginvacuumcleanup()

IndexBulkDeleteResult* ginvacuumcleanup ( IndexVacuumInfo info,
IndexBulkDeleteResult stats 
)

Definition at line 675 of file ginvacuum.c.

References IndexVacuumInfo::analyze_only, Assert, DataPageDeleteStack::blkno, buffer, BufferGetPage, IndexVacuumInfo::estimated_count, IndexBulkDeleteResult::estimated_count, ExclusiveLock, GIN_ROOT_BLKNO, GIN_SHARE, ginInsertCleanup(), GinPageIsData, GinPageIsDeleted, GinPageIsLeaf, GinPageIsList, 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, PageIsNew, IndexBulkDeleteResult::pages_free, palloc0(), RBM_NORMAL, ReadBufferExtended(), RecordFreeIndexPage(), RELATION_IS_LOCAL, RelationGetNumberOfBlocks, IndexVacuumInfo::strategy, UnlockRelationForExtension(), UnlockReleaseBuffer(), and vacuum_delay_point().

Referenced by ginhandler().

676 {
677  Relation index = info->index;
678  bool needLock;
679  BlockNumber npages,
680  blkno;
681  BlockNumber totFreePages;
682  GinState ginstate;
683  GinStatsData idxStat;
684 
685  /*
686  * In an autovacuum analyze, we want to clean up pending insertions.
687  * Otherwise, an ANALYZE-only call is a no-op.
688  */
689  if (info->analyze_only)
690  {
692  {
693  initGinState(&ginstate, index);
694  ginInsertCleanup(&ginstate, false, true, true, stats);
695  }
696  return stats;
697  }
698 
699  /*
700  * Set up all-zero stats and cleanup pending inserts if ginbulkdelete
701  * wasn't called
702  */
703  if (stats == NULL)
704  {
706  initGinState(&ginstate, index);
708  false, true, stats);
709  }
710 
711  memset(&idxStat, 0, sizeof(idxStat));
712 
713  /*
714  * XXX we always report the heap tuple count as the number of index
715  * entries. This is bogus if the index is partial, but it's real hard to
716  * tell how many distinct heap entries are referenced by a GIN index.
717  */
718  stats->num_index_tuples = info->num_heap_tuples;
719  stats->estimated_count = info->estimated_count;
720 
721  /*
722  * Need lock unless it's local to this backend.
723  */
724  needLock = !RELATION_IS_LOCAL(index);
725 
726  if (needLock)
728  npages = RelationGetNumberOfBlocks(index);
729  if (needLock)
731 
732  totFreePages = 0;
733 
734  for (blkno = GIN_ROOT_BLKNO; blkno < npages; blkno++)
735  {
736  Buffer buffer;
737  Page page;
738 
740 
741  buffer = ReadBufferExtended(index, MAIN_FORKNUM, blkno,
742  RBM_NORMAL, info->strategy);
743  LockBuffer(buffer, GIN_SHARE);
744  page = (Page) BufferGetPage(buffer);
745 
746  if (PageIsNew(page) || GinPageIsDeleted(page))
747  {
748  Assert(blkno != GIN_ROOT_BLKNO);
749  RecordFreeIndexPage(index, blkno);
750  totFreePages++;
751  }
752  else if (GinPageIsData(page))
753  {
754  idxStat.nDataPages++;
755  }
756  else if (!GinPageIsList(page))
757  {
758  idxStat.nEntryPages++;
759 
760  if (GinPageIsLeaf(page))
761  idxStat.nEntries += PageGetMaxOffsetNumber(page);
762  }
763 
764  UnlockReleaseBuffer(buffer);
765  }
766 
767  /* Update the metapage with accurate page and entry counts */
768  idxStat.nTotalPages = npages;
769  ginUpdateStats(info->index, &idxStat);
770 
771  /* Finally, vacuum the FSM */
773 
774  stats->pages_free = totFreePages;
775 
776  if (needLock)
778  stats->num_pages = RelationGetNumberOfBlocks(index);
779  if (needLock)
781 
782  return stats;
783 }
BlockNumber nEntryPages
Definition: gin.h:45
#define ExclusiveLock
Definition: lockdefs.h:44
#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
BufferAccessStrategy strategy
Definition: genam.h:51
Relation index
Definition: genam.h:46
int64 nEntries
Definition: gin.h:47
uint32 BlockNumber
Definition: block.h:31
#define PageGetMaxOffsetNumber(page)
Definition: bufpage.h:353
Definition: type.h:89
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3332
BlockNumber num_pages
Definition: genam.h:73
BlockNumber pages_free
Definition: genam.h:79
void ginUpdateStats(Relation index, const GinStatsData *stats)
Definition: ginutil.c:669
void initGinState(GinState *state, Relation index)
Definition: ginutil.c:88
#define GinPageIsLeaf(page)
Definition: ginblock.h:111
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
bool IsAutoVacuumWorkerProcess(void)
Definition: autovacuum.c:3295
#define GIN_SHARE
Definition: gin_private.h:44
void LockRelationForExtension(Relation relation, LOCKMODE lockmode)
Definition: lmgr.c:332
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
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3546
#define RelationGetNumberOfBlocks(reln)
Definition: bufmgr.h:199
BlockNumber nDataPages
Definition: gin.h:46
void ginInsertCleanup(GinState *ginstate, bool full_clean, bool fill_fsm, bool forceCleanup, IndexBulkDeleteResult *stats)
Definition: ginfast.c:754
#define GinPageIsData(page)
Definition: ginblock.h:114
double num_heap_tuples
Definition: genam.h:50
#define Assert(condition)
Definition: c.h:699
void IndexFreeSpaceMapVacuum(Relation rel)
Definition: indexfsm.c:71
WalTimeSample buffer[LAG_TRACKER_BUFFER_SIZE]
Definition: walsender.c:215
#define GinPageIsList(page)
Definition: ginblock.h:116
BlockNumber nTotalPages
Definition: gin.h:44
#define PageIsNew(page)
Definition: bufpage.h:225
void vacuum_delay_point(void)
Definition: vacuum.c:1672
void RecordFreeIndexPage(Relation rel, BlockNumber freeBlock)
Definition: indexfsm.c:52
double num_index_tuples
Definition: genam.h:76
int Buffer
Definition: buf.h:23
bool estimated_count
Definition: genam.h:75
#define GIN_ROOT_BLKNO
Definition: ginblock.h:51
Pointer Page
Definition: bufpage.h:74
bool estimated_count
Definition: genam.h:48

◆ ginVacuumEntryPage()

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

Definition at line 443 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, PageAddItem, PageGetItem, PageGetItemId, PageGetMaxOffsetNumber, PageGetTempPageCopy(), PageIndexTupleDelete(), pfree(), RelationGetRelationName, and SizeOfGinPostingList.

Referenced by ginbulkdelete().

444 {
445  Page origpage = BufferGetPage(buffer),
446  tmppage;
447  OffsetNumber i,
448  maxoff = PageGetMaxOffsetNumber(origpage);
449 
450  tmppage = origpage;
451 
452  *nroot = 0;
453 
454  for (i = FirstOffsetNumber; i <= maxoff; i++)
455  {
456  IndexTuple itup = (IndexTuple) PageGetItem(tmppage, PageGetItemId(tmppage, i));
457 
458  if (GinIsPostingTree(itup))
459  {
460  /*
461  * store posting tree's roots for further processing, we can't
462  * vacuum it just now due to risk of deadlocks with scans/inserts
463  */
464  roots[*nroot] = GinGetDownlink(itup);
465  (*nroot)++;
466  }
467  else if (GinGetNPosting(itup) > 0)
468  {
469  int nitems;
470  ItemPointer items_orig;
471  bool free_items_orig;
472  ItemPointer items;
473 
474  /* Get list of item pointers from the tuple. */
475  if (GinItupIsCompressed(itup))
476  {
477  items_orig = ginPostingListDecode((GinPostingList *) GinGetPosting(itup), &nitems);
478  free_items_orig = true;
479  }
480  else
481  {
482  items_orig = (ItemPointer) GinGetPosting(itup);
483  nitems = GinGetNPosting(itup);
484  free_items_orig = false;
485  }
486 
487  /* Remove any items from the list that need to be vacuumed. */
488  items = ginVacuumItemPointers(gvs, items_orig, nitems, &nitems);
489 
490  if (free_items_orig)
491  pfree(items_orig);
492 
493  /* If any item pointers were removed, recreate the tuple. */
494  if (items)
495  {
497  Datum key;
498  GinNullCategory category;
499  GinPostingList *plist;
500  int plistsize;
501 
502  if (nitems > 0)
503  {
504  plist = ginCompressPostingList(items, nitems, GinMaxItemSize, NULL);
505  plistsize = SizeOfGinPostingList(plist);
506  }
507  else
508  {
509  plist = NULL;
510  plistsize = 0;
511  }
512 
513  /*
514  * if we already created a temporary page, make changes in
515  * place
516  */
517  if (tmppage == origpage)
518  {
519  /*
520  * On first difference, create a temporary copy of the
521  * page and copy the tuple's posting list to it.
522  */
523  tmppage = PageGetTempPageCopy(origpage);
524 
525  /* set itup pointer to new page */
526  itup = (IndexTuple) PageGetItem(tmppage, PageGetItemId(tmppage, i));
527  }
528 
529  attnum = gintuple_get_attrnum(&gvs->ginstate, itup);
530  key = gintuple_get_key(&gvs->ginstate, itup, &category);
531  itup = GinFormTuple(&gvs->ginstate, attnum, key, category,
532  (char *) plist, plistsize,
533  nitems, true);
534  if (plist)
535  pfree(plist);
536  PageIndexTupleDelete(tmppage, i);
537 
538  if (PageAddItem(tmppage, (Item) itup, IndexTupleSize(itup), i, false, false) != i)
539  elog(ERROR, "failed to add item to index page in \"%s\"",
541 
542  pfree(itup);
543  pfree(items);
544  }
545  }
546  }
547 
548  return (tmppage == origpage) ? NULL : tmppage;
549 }
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:723
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:412
#define GinGetNPosting(itup)
Definition: ginblock.h:222
#define PageGetMaxOffsetNumber(page)
Definition: bufpage.h:353
#define GinGetPosting(itup)
Definition: ginblock.h:232
#define GinItupIsCompressed(itup)
Definition: ginblock.h:233
uint16 OffsetNumber
Definition: off.h:24
ItemPointerData * ItemPointer
Definition: itemptr.h:49
void pfree(void *pointer)
Definition: mcxt.c:1031
#define ERROR
Definition: elog.h:43
signed char GinNullCategory
Definition: ginblock.h:200
OffsetNumber gintuple_get_attrnum(GinState *ginstate, IndexTuple tuple)
Definition: ginutil.c:217
#define FirstOffsetNumber
Definition: off.h:27
IndexTupleData * IndexTuple
Definition: itup.h:53
#define RelationGetRelationName(relation)
Definition: rel.h:441
Datum gintuple_get_key(GinState *ginstate, IndexTuple tuple, GinNullCategory *category)
Definition: ginutil.c:250
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
#define PageGetItemId(page, offsetNumber)
Definition: bufpage.h:231
uintptr_t Datum
Definition: postgres.h:365
#define GinGetDownlink(itup)
Definition: ginblock.h:251
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
WalTimeSample buffer[LAG_TRACKER_BUFFER_SIZE]
Definition: walsender.c:215
#define GinIsPostingTree(itup)
Definition: ginblock.h:225
Page PageGetTempPageCopy(Page page)
Definition: bufpage.c:365
#define SizeOfGinPostingList(plist)
Definition: ginblock.h:336
#define GinMaxItemSize
Definition: ginblock.h:242
int i
#define elog
Definition: elog.h:219
#define PageGetItem(page, itemId)
Definition: bufpage.h:336
Pointer Page
Definition: bufpage.h:74
#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:692
double tuples_removed
Definition: genam.h:77
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:924
int i
double num_index_tuples
Definition: genam.h:76

◆ ginVacuumPostingTree()

static void ginVacuumPostingTree ( GinVacuumState gvs,
BlockNumber  rootBlkno 
)
static

Definition at line 432 of file ginvacuum.c.

References ginVacuumPostingTreeLeaves().

Referenced by ginbulkdelete().

433 {
434  ginVacuumPostingTreeLeaves(gvs, rootBlkno, true);
435 }
static bool ginVacuumPostingTreeLeaves(GinVacuumState *gvs, BlockNumber blkno, bool isRoot)
Definition: ginvacuum.c:326

◆ ginVacuumPostingTreeLeaves()

static bool ginVacuumPostingTreeLeaves ( GinVacuumState gvs,
BlockNumber  blkno,
bool  isRoot 
)
static

Definition at line 326 of file ginvacuum.c.

References Assert, buffer, BufferGetPage, DataPageDeleteStack::child, FirstOffsetNumber, GinDataLeafPageIsEmpty, GinDataPageGetPostingItem, GinPageGetOpaque, GinPageIsData, GinPageIsLeaf, ginScanToDelete(), ginTraverseLock(), ginVacuumPostingTreeLeaf(), i, GinVacuumState::index, InvalidBlockNumber, InvalidOffsetNumber, DataPageDeleteStack::isRoot, DataPageDeleteStack::leftBlkno, LockBufferForCleanup(), MAIN_FORKNUM, MemoryContextReset(), MemoryContextSwitchTo(), palloc(), pfree(), PostingItemGetBlockNumber, RBM_NORMAL, ReadBufferExtended(), GinVacuumState::strategy, GinVacuumState::tmpCxt, UnlockReleaseBuffer(), and vacuum_delay_point().

Referenced by ginVacuumPostingTree().

327 {
328  Buffer buffer;
329  Page page;
330  bool hasVoidPage = false;
331  MemoryContext oldCxt;
332 
333  buffer = ReadBufferExtended(gvs->index, MAIN_FORKNUM, blkno,
334  RBM_NORMAL, gvs->strategy);
335  page = BufferGetPage(buffer);
336 
337  ginTraverseLock(buffer, false);
338 
339  Assert(GinPageIsData(page));
340 
341  if (GinPageIsLeaf(page))
342  {
343  oldCxt = MemoryContextSwitchTo(gvs->tmpCxt);
344  ginVacuumPostingTreeLeaf(gvs->index, buffer, gvs);
345  MemoryContextSwitchTo(oldCxt);
347 
348  /* if root is a leaf page, we don't desire further processing */
349  if (GinDataLeafPageIsEmpty(page))
350  hasVoidPage = true;
351 
352  UnlockReleaseBuffer(buffer);
353 
354  return hasVoidPage;
355  }
356  else
357  {
358  OffsetNumber i;
359  bool hasEmptyChild = false;
360  bool hasNonEmptyChild = false;
361  OffsetNumber maxoff = GinPageGetOpaque(page)->maxoff;
362  BlockNumber *children = palloc(sizeof(BlockNumber) * (maxoff + 1));
363 
364  /*
365  * Read all children BlockNumbers. Not sure it is safe if there are
366  * many concurrent vacuums.
367  */
368 
369  for (i = FirstOffsetNumber; i <= maxoff; i++)
370  {
371  PostingItem *pitem = GinDataPageGetPostingItem(page, i);
372 
373  children[i] = PostingItemGetBlockNumber(pitem);
374  }
375 
376  UnlockReleaseBuffer(buffer);
377 
378  for (i = FirstOffsetNumber; i <= maxoff; i++)
379  {
380  if (ginVacuumPostingTreeLeaves(gvs, children[i], false))
381  hasEmptyChild = true;
382  else
383  hasNonEmptyChild = true;
384  }
385 
386  pfree(children);
387 
389 
390  /*
391  * All subtree is empty - just return true to indicate that parent
392  * must do a cleanup, unless we are ROOT and there is way to go upper.
393  */
394 
395  if (hasEmptyChild && !hasNonEmptyChild && !isRoot)
396  return true;
397 
398  if (hasEmptyChild)
399  {
400  DataPageDeleteStack root,
401  *ptr,
402  *tmp;
403 
404  buffer = ReadBufferExtended(gvs->index, MAIN_FORKNUM, blkno,
405  RBM_NORMAL, gvs->strategy);
406  LockBufferForCleanup(buffer);
407 
408  memset(&root, 0, sizeof(DataPageDeleteStack));
410  root.isRoot = true;
411 
412  ginScanToDelete(gvs, blkno, true, &root, InvalidOffsetNumber);
413 
414  ptr = root.child;
415 
416  while (ptr)
417  {
418  tmp = ptr->child;
419  pfree(ptr);
420  ptr = tmp;
421  }
422 
423  UnlockReleaseBuffer(buffer);
424  }
425 
426  /* Here we have deleted all empty subtrees */
427  return false;
428  }
429 }
void LockBufferForCleanup(Buffer buffer)
Definition: bufmgr.c:3603
static bool ginVacuumPostingTreeLeaves(GinVacuumState *gvs, BlockNumber blkno, bool isRoot)
Definition: ginvacuum.c:326
Relation index
Definition: ginvacuum.c:30
Buffer ReadBufferExtended(Relation reln, ForkNumber forkNum, BlockNumber blockNum, ReadBufferMode mode, BufferAccessStrategy strategy)
Definition: bufmgr.c:640
BufferAccessStrategy strategy
Definition: ginvacuum.c:35
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:136
uint32 BlockNumber
Definition: block.h:31
#define GinPageGetOpaque(page)
Definition: ginblock.h:109
#define GinDataLeafPageIsEmpty(page)
Definition: ginblock.h:277
uint16 OffsetNumber
Definition: off.h:24
BlockNumber leftBlkno
Definition: ginvacuum.c:120
void pfree(void *pointer)
Definition: mcxt.c:1031
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3332
#define GinDataPageGetPostingItem(page, i)
Definition: ginblock.h:292
void ginVacuumPostingTreeLeaf(Relation indexrel, Buffer buffer, GinVacuumState *gvs)
Definition: gindatapage.c:732
#define FirstOffsetNumber
Definition: off.h:27
#define GinPageIsLeaf(page)
Definition: ginblock.h:111
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
struct DataPageDeleteStack * child
Definition: ginvacuum.c:116
#define InvalidOffsetNumber
Definition: off.h:26
#define GinPageIsData(page)
Definition: ginblock.h:114
#define PostingItemGetBlockNumber(pointer)
Definition: ginblock.h:183
#define Assert(condition)
Definition: c.h:699
WalTimeSample buffer[LAG_TRACKER_BUFFER_SIZE]
Definition: walsender.c:215
#define InvalidBlockNumber
Definition: block.h:33
void * palloc(Size size)
Definition: mcxt.c:924
int i
void vacuum_delay_point(void)
Definition: vacuum.c:1672
MemoryContext tmpCxt
Definition: ginvacuum.c:36
int Buffer
Definition: buf.h:23
Pointer Page
Definition: bufpage.h:74
static bool ginScanToDelete(GinVacuumState *gvs, BlockNumber blkno, bool isRoot, DataPageDeleteStack *parent, OffsetNumber myoff)
Definition: ginvacuum.c:240
int ginTraverseLock(Buffer buffer, bool searchMode)
Definition: ginbtree.c:36

◆ 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:213
#define REGBUF_STANDARD
Definition: xloginsert.h:34
#define GinPageIsLeaf(page)
Definition: ginblock.h:111
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
#define REGBUF_FORCE_IMAGE
Definition: xloginsert.h:30
#define XLOG_GIN_VACUUM_PAGE
Definition: ginxlog.h:137
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:415
#define GinPageIsData(page)
Definition: ginblock.h:114
uint64 XLogRecPtr
Definition: xlogdefs.h:21
#define Assert(condition)
Definition: c.h:699
WalTimeSample buffer[LAG_TRACKER_BUFFER_SIZE]
Definition: walsender.c:215
#define RelationNeedsWAL(relation)
Definition: rel.h:510
void XLogBeginInsert(void)
Definition: xloginsert.c:120
#define PageSetLSN(page, lsn)
Definition: bufpage.h:364
Pointer Page
Definition: bufpage.h:74