PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
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-2017, 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  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 }
101 
102 typedef struct GistBDItem
103 {
106  struct GistBDItem *next;
107 } GistBDItem;
108 
109 static void
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 }
128 
129 
130 /*
131  * Bulk deletion of all index entries pointing to a set of heap tuples and
132  * check invalid tuples left after upgrade.
133  * The set of target tuples is specified via a callback routine that tells
134  * whether any given heap tuple (identified by ItemPointer) is being deleted.
135  *
136  * Result: a palloc'd struct containing statistical info for VACUUM displays.
137  */
140  IndexBulkDeleteCallback callback, void *callback_state)
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 }
#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:139
#define RELATION_IS_LOCAL(relation)
Definition: rel.h:524
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:132
BufferAccessStrategy strategy
Definition: genam.h:51
#define InvalidBuffer
Definition: buf.h:25
#define START_CRIT_SECTION()
Definition: miscadmin.h:130
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:354
GistNSN parentlsn
Definition: gistvacuum.c:104
XLogRecPtr gistGetFakeLSN(Relation rel)
Definition: gistutil.c:946
uint16 OffsetNumber
Definition: off.h:24
void pfree(void *pointer)
Definition: mcxt.c:950
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:118
#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:437
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:232
void LockRelationForExtension(Relation relation, LOCKMODE lockmode)
Definition: lmgr.c:332
void * palloc0(Size size)
Definition: mcxt.c:878
void UnlockRelationForExtension(Relation relation, LOCKMODE lockmode)
Definition: lmgr.c:382
BlockNumber blkno
Definition: gistvacuum.c:105
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
double num_heap_tuples
Definition: genam.h:50
#define NULL
Definition: c.h:229
uint64 XLogRecPtr
Definition: xlogdefs.h:21
void IndexFreeSpaceMapVacuum(Relation rel)
Definition: indexfsm.c:71
WalTimeSample buffer[LAG_TRACKER_BUFFER_SIZE]
Definition: walsender.c:207
void PageIndexMultiDelete(Page page, OffsetNumber *itemnos, int nitems)
Definition: bufpage.c:836
void gistcheckpage(Relation rel, Buffer buf)
Definition: gistutil.c:723
#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:506
XLogRecPtr GistNSN
Definition: gist.h:50
#define PageGetLSN(page)
Definition: bufpage.h:363
#define PageIsNew(page)
Definition: bufpage.h:226
void * palloc(Size size)
Definition: mcxt.c:849
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
BlockNumber rightlink
Definition: gist.h:61
#define ItemPointerGetBlockNumber(pointer)
Definition: itemptr.h:66
void vacuum_delay_point(void)
Definition: vacuum.c:1560
#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:365
double num_index_tuples
Definition: genam.h:76
int Buffer
Definition: buf.h:23
bool estimated_count
Definition: genam.h:75
bool(* IndexBulkDeleteCallback)(ItemPointer itemptr, void *state)
Definition: genam.h:83
#define PageGetItem(page, itemId)
Definition: bufpage.h:337
Pointer Page
Definition: bufpage.h:74
static void pushStackIfSplited(Page page, GistBDItem *stack)
Definition: gistvacuum.c:110
bool estimated_count
Definition: genam.h:48