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 138 of file gistvacuum.c.

References GistBDItem::blkno, buffer, BufferGetLSNAtomic(), 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, 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().

140 {
141  Relation rel = info->index;
142  GistBDItem *stack,
143  *ptr;
144 
145  /* first time through? */
146  if (stats == NULL)
148  /* we'll re-count the tuples each time */
149  stats->estimated_count = false;
150  stats->num_index_tuples = 0;
151 
152  stack = (GistBDItem *) palloc0(sizeof(GistBDItem));
153  stack->blkno = GIST_ROOT_BLKNO;
154 
155  while (stack)
156  {
157  Buffer buffer;
158  Page page;
159  OffsetNumber i,
160  maxoff;
161  IndexTuple idxtuple;
162  ItemId iid;
163 
164  buffer = ReadBufferExtended(rel, MAIN_FORKNUM, stack->blkno,
165  RBM_NORMAL, info->strategy);
166  LockBuffer(buffer, GIST_SHARE);
167  gistcheckpage(rel, buffer);
168  page = (Page) BufferGetPage(buffer);
169 
170  if (GistPageIsLeaf(page))
171  {
172  OffsetNumber todelete[MaxOffsetNumber];
173  int ntodelete = 0;
174 
175  LockBuffer(buffer, GIST_UNLOCK);
176  LockBuffer(buffer, GIST_EXCLUSIVE);
177 
178  page = (Page) BufferGetPage(buffer);
179  if (stack->blkno == GIST_ROOT_BLKNO && !GistPageIsLeaf(page))
180  {
181  /* only the root can become non-leaf during relock */
182  UnlockReleaseBuffer(buffer);
183  /* one more check */
184  continue;
185  }
186 
187  /*
188  * check for split proceeded after look at parent, we should check
189  * it after relock
190  */
191  pushStackIfSplited(page, stack);
192 
193  /*
194  * Remove deletable tuples from page
195  */
196 
197  maxoff = PageGetMaxOffsetNumber(page);
198 
199  for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
200  {
201  iid = PageGetItemId(page, i);
202  idxtuple = (IndexTuple) PageGetItem(page, iid);
203 
204  if (callback(&(idxtuple->t_tid), callback_state))
205  todelete[ntodelete++] = i;
206  else
207  stats->num_index_tuples += 1;
208  }
209 
210  stats->tuples_removed += ntodelete;
211 
212  if (ntodelete)
213  {
215 
216  MarkBufferDirty(buffer);
217 
218  PageIndexMultiDelete(page, todelete, ntodelete);
219  GistMarkTuplesDeleted(page);
220 
221  if (RelationNeedsWAL(rel))
222  {
223  XLogRecPtr recptr;
224 
225  recptr = gistXLogUpdate(buffer,
226  todelete, ntodelete,
227  NULL, 0, InvalidBuffer);
228  PageSetLSN(page, recptr);
229  }
230  else
231  PageSetLSN(page, gistGetFakeLSN(rel));
232 
234  }
235 
236  }
237  else
238  {
239  /* check for split proceeded after look at parent */
240  pushStackIfSplited(page, stack);
241 
242  maxoff = PageGetMaxOffsetNumber(page);
243 
244  for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
245  {
246  iid = PageGetItemId(page, i);
247  idxtuple = (IndexTuple) PageGetItem(page, iid);
248 
249  ptr = (GistBDItem *) palloc(sizeof(GistBDItem));
250  ptr->blkno = ItemPointerGetBlockNumber(&(idxtuple->t_tid));
251  ptr->parentlsn = BufferGetLSNAtomic(buffer);
252  ptr->next = stack->next;
253  stack->next = ptr;
254 
255  if (GistTupleIsInvalid(idxtuple))
256  ereport(LOG,
257  (errmsg("index \"%s\" contains an inner tuple marked as invalid",
259  errdetail("This is caused by an incomplete page split at crash recovery before upgrading to PostgreSQL 9.1."),
260  errhint("Please REINDEX it.")));
261  }
262  }
263 
264  UnlockReleaseBuffer(buffer);
265 
266  ptr = stack->next;
267  pfree(stack);
268  stack = ptr;
269 
271  }
272 
273  return stats;
274 }
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:103
XLogRecPtr gistGetFakeLSN(Relation rel)
Definition: gistutil.c:980
uint16 OffsetNumber
Definition: off.h:24
void pfree(void *pointer)
Definition: mcxt.c:1031
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3332
static void callback(struct sockaddr *addr, struct sockaddr *mask, void *unused)
Definition: test_ifaddrs.c:48
XLogRecPtr BufferGetLSNAtomic(Buffer buffer)
Definition: bufmgr.c:2832
#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:441
#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:955
BlockNumber blkno
Definition: gistvacuum.c:104
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:215
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:510
void * palloc(Size size)
Definition: mcxt.c:924
int errmsg(const char *fmt,...)
Definition: elog.c:797
int i
struct GistBDItem * next
Definition: gistvacuum.c:105
#define GIST_ROOT_BLKNO
Definition: gist_private.h:249
#define ItemPointerGetBlockNumber(pointer)
Definition: itemptr.h:98
void vacuum_delay_point(void)
Definition: vacuum.c:1672
#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:109

◆ gistvacuumcleanup()

IndexBulkDeleteResult* gistvacuumcleanup ( IndexVacuumInfo info,
IndexBulkDeleteResult stats 
)

Definition at line 29 of file gistvacuum.c.

References IndexVacuumInfo::analyze_only, DataPageDeleteStack::blkno, buffer, BufferGetPage, IndexBulkDeleteResult::estimated_count, ExclusiveLock, GIST_ROOT_BLKNO, GIST_SHARE, GistPageIsDeleted, GistPageIsLeaf, IndexVacuumInfo::index, IndexFreeSpaceMapVacuum(), LockBuffer(), LockRelationForExtension(), MAIN_FORKNUM, 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 gisthandler().

30 {
31  Relation rel = info->index;
32  BlockNumber npages,
33  blkno;
34  BlockNumber totFreePages;
35  double tuplesCount;
36  bool needLock;
37 
38  /* No-op in ANALYZE ONLY mode */
39  if (info->analyze_only)
40  return stats;
41 
42  /* Set up all-zero stats if gistbulkdelete wasn't called */
43  if (stats == NULL)
45 
46  /*
47  * Need lock unless it's local to this backend.
48  */
49  needLock = !RELATION_IS_LOCAL(rel);
50 
51  /* try to find deleted pages */
52  if (needLock)
54  npages = RelationGetNumberOfBlocks(rel);
55  if (needLock)
57 
58  totFreePages = 0;
59  tuplesCount = 0;
60  for (blkno = GIST_ROOT_BLKNO + 1; blkno < npages; blkno++)
61  {
62  Buffer buffer;
63  Page page;
64 
66 
67  buffer = ReadBufferExtended(rel, MAIN_FORKNUM, blkno, RBM_NORMAL,
68  info->strategy);
69  LockBuffer(buffer, GIST_SHARE);
70  page = (Page) BufferGetPage(buffer);
71 
72  if (PageIsNew(page) || GistPageIsDeleted(page))
73  {
74  totFreePages++;
75  RecordFreeIndexPage(rel, blkno);
76  }
77  else if (GistPageIsLeaf(page))
78  {
79  /* count tuples in index (considering only leaf tuples) */
80  tuplesCount += PageGetMaxOffsetNumber(page);
81  }
82  UnlockReleaseBuffer(buffer);
83  }
84 
85  /* Finally, vacuum the FSM */
87 
88  /* return statistics */
89  stats->pages_free = totFreePages;
90  if (needLock)
93  if (needLock)
95  stats->num_index_tuples = tuplesCount;
96  stats->estimated_count = false;
97 
98  return stats;
99 }
#define GistPageIsDeleted(page)
Definition: gist.h:135
#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
uint32 BlockNumber
Definition: block.h:31
#define PageGetMaxOffsetNumber(page)
Definition: bufpage.h:353
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
#define GistPageIsLeaf(page)
Definition: gist.h:132
void LockRelationForExtension(Relation relation, LOCKMODE lockmode)
Definition: lmgr.c:332
void * palloc0(Size size)
Definition: mcxt.c:955
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
void IndexFreeSpaceMapVacuum(Relation rel)
Definition: indexfsm.c:71
WalTimeSample buffer[LAG_TRACKER_BUFFER_SIZE]
Definition: walsender.c:215
#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: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
Pointer Page
Definition: bufpage.h:74

◆ pushStackIfSplited()

static void pushStackIfSplited ( Page  page,
GistBDItem stack 
)
static

Definition at line 109 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().

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