PostgreSQL Source Code  git master
gistvacuum.c File Reference
#include "postgres.h"
#include "access/genam.h"
#include "access/gist_private.h"
#include "commands/vacuum.h"
#include "miscadmin.h"
#include "storage/indexfsm.h"
#include "storage/lmgr.h"
Include dependency graph for gistvacuum.c:

Go to the source code of this file.

Data Structures

struct  GistBDItem
 

Typedefs

typedef struct GistBDItem GistBDItem
 

Functions

IndexBulkDeleteResultgistvacuumcleanup (IndexVacuumInfo *info, IndexBulkDeleteResult *stats)
 
static void pushStackIfSplited (Page page, GistBDItem *stack)
 
IndexBulkDeleteResultgistbulkdelete (IndexVacuumInfo *info, IndexBulkDeleteResult *stats, IndexBulkDeleteCallback callback, void *callback_state)
 

Typedef Documentation

◆ GistBDItem

Function Documentation

◆ gistbulkdelete()

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

Definition at line 139 of file gistvacuum.c.

References GistBDItem::blkno, buffer, BufferGetPage, callback(), END_CRIT_SECTION, ereport, errdetail(), errhint(), errmsg(), IndexBulkDeleteResult::estimated_count, FirstOffsetNumber, GIST_EXCLUSIVE, GIST_ROOT_BLKNO, GIST_SHARE, GIST_UNLOCK, gistcheckpage(), gistGetFakeLSN(), GistMarkTuplesDeleted, GistPageIsLeaf, GistTupleIsInvalid, gistXLogUpdate(), i, IndexVacuumInfo::index, InvalidBuffer, ItemPointerGetBlockNumber, LockBuffer(), LOG, MAIN_FORKNUM, MarkBufferDirty(), MaxOffsetNumber, GistBDItem::next, IndexBulkDeleteResult::num_index_tuples, OffsetNumberNext, PageGetItem, PageGetItemId, PageGetLSN, PageGetMaxOffsetNumber, PageIndexMultiDelete(), PageSetLSN, palloc(), palloc0(), GistBDItem::parentlsn, pfree(), pushStackIfSplited(), RBM_NORMAL, ReadBufferExtended(), RelationGetRelationName, RelationNeedsWAL, START_CRIT_SECTION, IndexVacuumInfo::strategy, IndexTupleData::t_tid, IndexBulkDeleteResult::tuples_removed, UnlockReleaseBuffer(), and vacuum_delay_point().

Referenced by gisthandler().

141 {
142  Relation rel = info->index;
143  GistBDItem *stack,
144  *ptr;
145 
146  /* first time through? */
147  if (stats == NULL)
149  /* we'll re-count the tuples each time */
150  stats->estimated_count = false;
151  stats->num_index_tuples = 0;
152 
153  stack = (GistBDItem *) palloc0(sizeof(GistBDItem));
154  stack->blkno = GIST_ROOT_BLKNO;
155 
156  while (stack)
157  {
158  Buffer buffer;
159  Page page;
160  OffsetNumber i,
161  maxoff;
162  IndexTuple idxtuple;
163  ItemId iid;
164 
165  buffer = ReadBufferExtended(rel, MAIN_FORKNUM, stack->blkno,
166  RBM_NORMAL, info->strategy);
167  LockBuffer(buffer, GIST_SHARE);
168  gistcheckpage(rel, buffer);
169  page = (Page) BufferGetPage(buffer);
170 
171  if (GistPageIsLeaf(page))
172  {
173  OffsetNumber todelete[MaxOffsetNumber];
174  int ntodelete = 0;
175 
176  LockBuffer(buffer, GIST_UNLOCK);
177  LockBuffer(buffer, GIST_EXCLUSIVE);
178 
179  page = (Page) BufferGetPage(buffer);
180  if (stack->blkno == GIST_ROOT_BLKNO && !GistPageIsLeaf(page))
181  {
182  /* only the root can become non-leaf during relock */
183  UnlockReleaseBuffer(buffer);
184  /* one more check */
185  continue;
186  }
187 
188  /*
189  * check for split proceeded after look at parent, we should check
190  * it after relock
191  */
192  pushStackIfSplited(page, stack);
193 
194  /*
195  * Remove deletable tuples from page
196  */
197 
198  maxoff = PageGetMaxOffsetNumber(page);
199 
200  for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
201  {
202  iid = PageGetItemId(page, i);
203  idxtuple = (IndexTuple) PageGetItem(page, iid);
204 
205  if (callback(&(idxtuple->t_tid), callback_state))
206  todelete[ntodelete++] = i;
207  else
208  stats->num_index_tuples += 1;
209  }
210 
211  stats->tuples_removed += ntodelete;
212 
213  if (ntodelete)
214  {
216 
217  MarkBufferDirty(buffer);
218 
219  PageIndexMultiDelete(page, todelete, ntodelete);
220  GistMarkTuplesDeleted(page);
221 
222  if (RelationNeedsWAL(rel))
223  {
224  XLogRecPtr recptr;
225 
226  recptr = gistXLogUpdate(buffer,
227  todelete, ntodelete,
228  NULL, 0, InvalidBuffer);
229  PageSetLSN(page, recptr);
230  }
231  else
232  PageSetLSN(page, gistGetFakeLSN(rel));
233 
235  }
236 
237  }
238  else
239  {
240  /* check for split proceeded after look at parent */
241  pushStackIfSplited(page, stack);
242 
243  maxoff = PageGetMaxOffsetNumber(page);
244 
245  for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
246  {
247  iid = PageGetItemId(page, i);
248  idxtuple = (IndexTuple) PageGetItem(page, iid);
249 
250  ptr = (GistBDItem *) palloc(sizeof(GistBDItem));
251  ptr->blkno = ItemPointerGetBlockNumber(&(idxtuple->t_tid));
252  ptr->parentlsn = PageGetLSN(page);
253  ptr->next = stack->next;
254  stack->next = ptr;
255 
256  if (GistTupleIsInvalid(idxtuple))
257  ereport(LOG,
258  (errmsg("index \"%s\" contains an inner tuple marked as invalid",
260  errdetail("This is caused by an incomplete page split at crash recovery before upgrading to PostgreSQL 9.1."),
261  errhint("Please REINDEX it.")));
262  }
263  }
264 
265  UnlockReleaseBuffer(buffer);
266 
267  ptr = stack->next;
268  pfree(stack);
269  stack = ptr;
270 
272  }
273 
274  return stats;
275 }
int errhint(const char *fmt,...)
Definition: elog.c:987
double tuples_removed
Definition: genam.h:77
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:1450
#define MaxOffsetNumber
Definition: off.h:28
#define GistMarkTuplesDeleted(page)
Definition: gist.h:140
Buffer ReadBufferExtended(Relation reln, ForkNumber forkNum, BlockNumber blockNum, ReadBufferMode mode, BufferAccessStrategy strategy)
Definition: bufmgr.c:640
ItemPointerData t_tid
Definition: itup.h:37
#define END_CRIT_SECTION()
Definition: miscadmin.h:133
BufferAccessStrategy strategy
Definition: genam.h:51
#define InvalidBuffer
Definition: buf.h:25
#define START_CRIT_SECTION()
Definition: miscadmin.h:131
Relation index
Definition: genam.h:46
#define GistTupleIsInvalid(itup)
Definition: gist_private.h:275
#define GIST_UNLOCK
Definition: gist_private.h:45
#define LOG
Definition: elog.h:26
#define PageGetMaxOffsetNumber(page)
Definition: bufpage.h:353
GistNSN parentlsn
Definition: gistvacuum.c:104
XLogRecPtr gistGetFakeLSN(Relation rel)
Definition: gistutil.c:980
uint16 OffsetNumber
Definition: off.h:24
void pfree(void *pointer)
Definition: mcxt.c:936
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3332
static void callback(struct sockaddr *addr, struct sockaddr *mask, void *unused)
Definition: test_ifaddrs.c:48
#define FirstOffsetNumber
Definition: off.h:27
IndexTupleData * IndexTuple
Definition: itup.h:53
int errdetail(const char *fmt,...)
Definition: elog.c:873
#define RelationGetRelationName(relation)
Definition: rel.h:445
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
#define ereport(elevel, rest)
Definition: elog.h:122
#define GistPageIsLeaf(page)
Definition: gist.h:132
#define PageGetItemId(page, offsetNumber)
Definition: bufpage.h:231
void * palloc0(Size size)
Definition: mcxt.c:864
BlockNumber blkno
Definition: gistvacuum.c:105
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3546
XLogRecPtr gistXLogUpdate(Buffer buffer, OffsetNumber *todelete, int ntodelete, IndexTuple *itup, int ituplen, Buffer leftchildbuf)
Definition: gistxlog.c:457
uint64 XLogRecPtr
Definition: xlogdefs.h:21
WalTimeSample buffer[LAG_TRACKER_BUFFER_SIZE]
Definition: walsender.c:214
void PageIndexMultiDelete(Page page, OffsetNumber *itemnos, int nitems)
Definition: bufpage.c:832
void gistcheckpage(Relation rel, Buffer buf)
Definition: gistutil.c:743
#define OffsetNumberNext(offsetNumber)
Definition: off.h:53
#define GIST_SHARE
Definition: gist_private.h:43
#define RelationNeedsWAL(relation)
Definition: rel.h:514
#define PageGetLSN(page)
Definition: bufpage.h:362
void * palloc(Size size)
Definition: mcxt.c:835
int errmsg(const char *fmt,...)
Definition: elog.c:797
int i
struct GistBDItem * next
Definition: gistvacuum.c:106
#define GIST_ROOT_BLKNO
Definition: gist_private.h:249
#define ItemPointerGetBlockNumber(pointer)
Definition: itemptr.h:76
void vacuum_delay_point(void)
Definition: vacuum.c:1695
#define GIST_EXCLUSIVE
Definition: gist_private.h:44
#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
Pointer Page
Definition: bufpage.h:74
static void pushStackIfSplited(Page page, GistBDItem *stack)
Definition: gistvacuum.c:110

◆ gistvacuumcleanup()

IndexBulkDeleteResult* gistvacuumcleanup ( IndexVacuumInfo info,
IndexBulkDeleteResult stats 
)

Definition at line 29 of file gistvacuum.c.

References IndexVacuumInfo::analyze_only, DataPageDeleteStack::blkno, buffer, BufferGetPage, IndexVacuumInfo::estimated_count, IndexBulkDeleteResult::estimated_count, ExclusiveLock, GIST_ROOT_BLKNO, GIST_SHARE, GistPageIsDeleted, IndexVacuumInfo::index, IndexFreeSpaceMapVacuum(), LockBuffer(), LockRelationForExtension(), MAIN_FORKNUM, IndexVacuumInfo::num_heap_tuples, IndexBulkDeleteResult::num_index_tuples, IndexBulkDeleteResult::num_pages, PageIsNew, IndexBulkDeleteResult::pages_free, palloc0(), RBM_NORMAL, ReadBufferExtended(), RecordFreeIndexPage(), RELATION_IS_LOCAL, RelationGetNumberOfBlocks, IndexVacuumInfo::strategy, UnlockRelationForExtension(), UnlockReleaseBuffer(), and vacuum_delay_point().

Referenced by gisthandler().

30 {
31  Relation rel = info->index;
32  BlockNumber npages,
33  blkno;
34  BlockNumber totFreePages;
35  bool needLock;
36 
37  /* No-op in ANALYZE ONLY mode */
38  if (info->analyze_only)
39  return stats;
40 
41  /* Set up all-zero stats if gistbulkdelete wasn't called */
42  if (stats == NULL)
43  {
45  /* use heap's tuple count */
46  stats->num_index_tuples = info->num_heap_tuples;
47  stats->estimated_count = info->estimated_count;
48 
49  /*
50  * XXX the above is wrong if index is partial. Would it be OK to just
51  * return NULL, or is there work we must do below?
52  */
53  }
54 
55  /*
56  * Need lock unless it's local to this backend.
57  */
58  needLock = !RELATION_IS_LOCAL(rel);
59 
60  /* try to find deleted pages */
61  if (needLock)
63  npages = RelationGetNumberOfBlocks(rel);
64  if (needLock)
66 
67  totFreePages = 0;
68  for (blkno = GIST_ROOT_BLKNO + 1; blkno < npages; blkno++)
69  {
70  Buffer buffer;
71  Page page;
72 
74 
75  buffer = ReadBufferExtended(rel, MAIN_FORKNUM, blkno, RBM_NORMAL,
76  info->strategy);
77  LockBuffer(buffer, GIST_SHARE);
78  page = (Page) BufferGetPage(buffer);
79 
80  if (PageIsNew(page) || GistPageIsDeleted(page))
81  {
82  totFreePages++;
83  RecordFreeIndexPage(rel, blkno);
84  }
85  UnlockReleaseBuffer(buffer);
86  }
87 
88  /* Finally, vacuum the FSM */
90 
91  /* return statistics */
92  stats->pages_free = totFreePages;
93  if (needLock)
96  if (needLock)
98 
99  return stats;
100 }
#define GistPageIsDeleted(page)
Definition: gist.h:135
#define ExclusiveLock
Definition: lockdefs.h:44
#define RELATION_IS_LOCAL(relation)
Definition: rel.h:532
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
uint32 BlockNumber
Definition: block.h:31
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3332
BlockNumber num_pages
Definition: genam.h:73
BlockNumber pages_free
Definition: genam.h:79
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
void LockRelationForExtension(Relation relation, LOCKMODE lockmode)
Definition: lmgr.c:332
void * palloc0(Size size)
Definition: mcxt.c:864
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
double num_heap_tuples
Definition: genam.h:50
void IndexFreeSpaceMapVacuum(Relation rel)
Definition: indexfsm.c:71
WalTimeSample buffer[LAG_TRACKER_BUFFER_SIZE]
Definition: walsender.c:214
#define GIST_SHARE
Definition: gist_private.h:43
#define PageIsNew(page)
Definition: bufpage.h:225
#define GIST_ROOT_BLKNO
Definition: gist_private.h:249
void vacuum_delay_point(void)
Definition: vacuum.c:1695
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
Pointer Page
Definition: bufpage.h:74
bool estimated_count
Definition: genam.h:48

◆ pushStackIfSplited()

static void pushStackIfSplited ( Page  page,
GistBDItem stack 
)
static

Definition at line 110 of file gistvacuum.c.

References GistBDItem::blkno, GIST_ROOT_BLKNO, GistFollowRight, GistPageGetNSN, GistPageGetOpaque, InvalidBlockNumber, GistBDItem::next, palloc(), GistBDItem::parentlsn, GISTPageOpaqueData::rightlink, and XLogRecPtrIsInvalid.

Referenced by gistbulkdelete().

111 {
112  GISTPageOpaque opaque = GistPageGetOpaque(page);
113 
114  if (stack->blkno != GIST_ROOT_BLKNO && !XLogRecPtrIsInvalid(stack->parentlsn) &&
115  (GistFollowRight(page) || stack->parentlsn < GistPageGetNSN(page)) &&
116  opaque->rightlink != InvalidBlockNumber /* sanity check */ )
117  {
118  /* split page detected, install right link to the stack */
119 
120  GistBDItem *ptr = (GistBDItem *) palloc(sizeof(GistBDItem));
121 
122  ptr->blkno = opaque->rightlink;
123  ptr->parentlsn = stack->parentlsn;
124  ptr->next = stack->next;
125  stack->next = ptr;
126  }
127 }
#define GistFollowRight(page)
Definition: gist.h:147
#define GistPageGetNSN(page)
Definition: gist.h:151
GistNSN parentlsn
Definition: gistvacuum.c:104
#define XLogRecPtrIsInvalid(r)
Definition: xlogdefs.h:29
BlockNumber blkno
Definition: gistvacuum.c:105
#define GistPageGetOpaque(page)
Definition: gist.h:130
#define InvalidBlockNumber
Definition: block.h:33
void * palloc(Size size)
Definition: mcxt.c:835
struct GistBDItem * next
Definition: gistvacuum.c:106
#define GIST_ROOT_BLKNO
Definition: gist_private.h:249
BlockNumber rightlink
Definition: gist.h:61