PostgreSQL Source Code  git master
gistvacuum.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * gistvacuum.c
4  * vacuuming routines for the postgres GiST index access method.
5  *
6  *
7  * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group
8  * Portions Copyright (c) 1994, Regents of the University of California
9  *
10  * IDENTIFICATION
11  * src/backend/access/gist/gistvacuum.c
12  *
13  *-------------------------------------------------------------------------
14  */
15 #include "postgres.h"
16 
17 #include "access/genam.h"
18 #include "access/gist_private.h"
19 #include "commands/vacuum.h"
20 #include "miscadmin.h"
21 #include "storage/indexfsm.h"
22 #include "storage/lmgr.h"
23 
24 
25 /*
26  * VACUUM cleanup: update FSM
27  */
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 }
100 
101 typedef struct GistBDItem
102 {
105  struct GistBDItem *next;
106 } GistBDItem;
107 
108 static void
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 }
127 
128 
129 /*
130  * Bulk deletion of all index entries pointing to a set of heap tuples and
131  * check invalid tuples left after upgrade.
132  * The set of target tuples is specified via a callback routine that tells
133  * whether any given heap tuple (identified by ItemPointer) is being deleted.
134  *
135  * Result: a palloc'd struct containing statistical info for VACUUM displays.
136  */
139  IndexBulkDeleteCallback callback, void *callback_state)
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 }
#define GistFollowRight(page)
Definition: gist.h:147
#define GistPageGetNSN(page)
Definition: gist.h:151
#define GistPageIsDeleted(page)
Definition: gist.h:135
int errhint(const char *fmt,...)
Definition: elog.c:987
double tuples_removed
Definition: genam.h:77
IndexBulkDeleteResult * gistvacuumcleanup(IndexVacuumInfo *info, IndexBulkDeleteResult *stats)
Definition: gistvacuum.c:29
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:1450
#define ExclusiveLock
Definition: lockdefs.h:44
#define MaxOffsetNumber
Definition: off.h:28
#define GistMarkTuplesDeleted(page)
Definition: gist.h:140
IndexBulkDeleteResult * gistbulkdelete(IndexVacuumInfo *info, IndexBulkDeleteResult *stats, IndexBulkDeleteCallback callback, void *callback_state)
Definition: gistvacuum.c:138
#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
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
uint32 BlockNumber
Definition: block.h:31
#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
BlockNumber num_pages
Definition: genam.h:73
BlockNumber pages_free
Definition: genam.h:79
static void callback(struct sockaddr *addr, struct sockaddr *mask, void *unused)
Definition: test_ifaddrs.c:48
BlockNumber blkno
Definition: ginvacuum.c:119
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
struct GistBDItem GistBDItem
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
#define ereport(elevel, rest)
Definition: elog.h:122
#define GistPageIsLeaf(page)
Definition: gist.h:132
#define XLogRecPtrIsInvalid(r)
Definition: xlogdefs.h:29
#define PageGetItemId(page, offsetNumber)
Definition: bufpage.h:231
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
BlockNumber blkno
Definition: gistvacuum.c:104
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3546
#define RelationGetNumberOfBlocks(reln)
Definition: bufmgr.h:199
XLogRecPtr gistXLogUpdate(Buffer buffer, OffsetNumber *todelete, int ntodelete, IndexTuple *itup, int ituplen, Buffer leftchildbuf)
Definition: gistxlog.c:457
#define GistPageGetOpaque(page)
Definition: gist.h:130
uint64 XLogRecPtr
Definition: xlogdefs.h:21
void IndexFreeSpaceMapVacuum(Relation rel)
Definition: indexfsm.c:71
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 InvalidBlockNumber
Definition: block.h:33
#define GIST_SHARE
Definition: gist_private.h:43
#define RelationNeedsWAL(relation)
Definition: rel.h:510
XLogRecPtr GistNSN
Definition: gist.h:50
#define PageIsNew(page)
Definition: bufpage.h:225
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
BlockNumber rightlink
Definition: gist.h:61
#define ItemPointerGetBlockNumber(pointer)
Definition: itemptr.h:98
void vacuum_delay_point(void)
Definition: vacuum.c:1672
#define GIST_EXCLUSIVE
Definition: gist_private.h:44
void RecordFreeIndexPage(Relation rel, BlockNumber freeBlock)
Definition: indexfsm.c:52
#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
bool(* IndexBulkDeleteCallback)(ItemPointer itemptr, void *state)
Definition: genam.h:83
static void pushStackIfSplited(Page page, GistBDItem *stack)
Definition: gistvacuum.c:109