Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "postgres.h"
00016
00017 #include "access/genam.h"
00018 #include "access/gist_private.h"
00019 #include "commands/vacuum.h"
00020 #include "miscadmin.h"
00021 #include "storage/indexfsm.h"
00022 #include "storage/lmgr.h"
00023
00024
00025
00026
00027
00028 Datum
00029 gistvacuumcleanup(PG_FUNCTION_ARGS)
00030 {
00031 IndexVacuumInfo *info = (IndexVacuumInfo *) PG_GETARG_POINTER(0);
00032 IndexBulkDeleteResult *stats = (IndexBulkDeleteResult *) PG_GETARG_POINTER(1);
00033 Relation rel = info->index;
00034 BlockNumber npages,
00035 blkno;
00036 BlockNumber totFreePages;
00037 bool needLock;
00038
00039
00040 if (info->analyze_only)
00041 PG_RETURN_POINTER(stats);
00042
00043
00044 if (stats == NULL)
00045 {
00046 stats = (IndexBulkDeleteResult *) palloc0(sizeof(IndexBulkDeleteResult));
00047
00048 stats->num_index_tuples = info->num_heap_tuples;
00049 stats->estimated_count = info->estimated_count;
00050
00051
00052
00053
00054
00055 }
00056
00057
00058
00059
00060 needLock = !RELATION_IS_LOCAL(rel);
00061
00062
00063 if (needLock)
00064 LockRelationForExtension(rel, ExclusiveLock);
00065 npages = RelationGetNumberOfBlocks(rel);
00066 if (needLock)
00067 UnlockRelationForExtension(rel, ExclusiveLock);
00068
00069 totFreePages = 0;
00070 for (blkno = GIST_ROOT_BLKNO + 1; blkno < npages; blkno++)
00071 {
00072 Buffer buffer;
00073 Page page;
00074
00075 vacuum_delay_point();
00076
00077 buffer = ReadBufferExtended(rel, MAIN_FORKNUM, blkno, RBM_NORMAL,
00078 info->strategy);
00079 LockBuffer(buffer, GIST_SHARE);
00080 page = (Page) BufferGetPage(buffer);
00081
00082 if (PageIsNew(page) || GistPageIsDeleted(page))
00083 {
00084 totFreePages++;
00085 RecordFreeIndexPage(rel, blkno);
00086 }
00087 UnlockReleaseBuffer(buffer);
00088 }
00089
00090
00091 IndexFreeSpaceMapVacuum(info->index);
00092
00093
00094 stats->pages_free = totFreePages;
00095 if (needLock)
00096 LockRelationForExtension(rel, ExclusiveLock);
00097 stats->num_pages = RelationGetNumberOfBlocks(rel);
00098 if (needLock)
00099 UnlockRelationForExtension(rel, ExclusiveLock);
00100
00101 PG_RETURN_POINTER(stats);
00102 }
00103
00104 typedef struct GistBDItem
00105 {
00106 GistNSN parentlsn;
00107 BlockNumber blkno;
00108 struct GistBDItem *next;
00109 } GistBDItem;
00110
00111 static void
00112 pushStackIfSplited(Page page, GistBDItem *stack)
00113 {
00114 GISTPageOpaque opaque = GistPageGetOpaque(page);
00115
00116 if (stack->blkno != GIST_ROOT_BLKNO && !XLogRecPtrIsInvalid(stack->parentlsn) &&
00117 (GistFollowRight(page) || stack->parentlsn < GistPageGetNSN(page)) &&
00118 opaque->rightlink != InvalidBlockNumber )
00119 {
00120
00121
00122 GistBDItem *ptr = (GistBDItem *) palloc(sizeof(GistBDItem));
00123
00124 ptr->blkno = opaque->rightlink;
00125 ptr->parentlsn = stack->parentlsn;
00126 ptr->next = stack->next;
00127 stack->next = ptr;
00128 }
00129 }
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140 Datum
00141 gistbulkdelete(PG_FUNCTION_ARGS)
00142 {
00143 IndexVacuumInfo *info = (IndexVacuumInfo *) PG_GETARG_POINTER(0);
00144 IndexBulkDeleteResult *stats = (IndexBulkDeleteResult *) PG_GETARG_POINTER(1);
00145 IndexBulkDeleteCallback callback = (IndexBulkDeleteCallback) PG_GETARG_POINTER(2);
00146 void *callback_state = (void *) PG_GETARG_POINTER(3);
00147 Relation rel = info->index;
00148 GistBDItem *stack,
00149 *ptr;
00150
00151
00152 if (stats == NULL)
00153 stats = (IndexBulkDeleteResult *) palloc0(sizeof(IndexBulkDeleteResult));
00154
00155 stats->estimated_count = false;
00156 stats->num_index_tuples = 0;
00157
00158 stack = (GistBDItem *) palloc0(sizeof(GistBDItem));
00159 stack->blkno = GIST_ROOT_BLKNO;
00160
00161 while (stack)
00162 {
00163 Buffer buffer;
00164 Page page;
00165 OffsetNumber i,
00166 maxoff;
00167 IndexTuple idxtuple;
00168 ItemId iid;
00169
00170 buffer = ReadBufferExtended(rel, MAIN_FORKNUM, stack->blkno,
00171 RBM_NORMAL, info->strategy);
00172 LockBuffer(buffer, GIST_SHARE);
00173 gistcheckpage(rel, buffer);
00174 page = (Page) BufferGetPage(buffer);
00175
00176 if (GistPageIsLeaf(page))
00177 {
00178 OffsetNumber todelete[MaxOffsetNumber];
00179 int ntodelete = 0;
00180
00181 LockBuffer(buffer, GIST_UNLOCK);
00182 LockBuffer(buffer, GIST_EXCLUSIVE);
00183
00184 page = (Page) BufferGetPage(buffer);
00185 if (stack->blkno == GIST_ROOT_BLKNO && !GistPageIsLeaf(page))
00186 {
00187
00188 UnlockReleaseBuffer(buffer);
00189
00190 continue;
00191 }
00192
00193
00194
00195
00196
00197 pushStackIfSplited(page, stack);
00198
00199
00200
00201
00202
00203 maxoff = PageGetMaxOffsetNumber(page);
00204
00205 for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
00206 {
00207 iid = PageGetItemId(page, i);
00208 idxtuple = (IndexTuple) PageGetItem(page, iid);
00209
00210 if (callback(&(idxtuple->t_tid), callback_state))
00211 {
00212 todelete[ntodelete] = i - ntodelete;
00213 ntodelete++;
00214 stats->tuples_removed += 1;
00215 }
00216 else
00217 stats->num_index_tuples += 1;
00218 }
00219
00220 if (ntodelete)
00221 {
00222 START_CRIT_SECTION();
00223
00224 MarkBufferDirty(buffer);
00225
00226 for (i = 0; i < ntodelete; i++)
00227 PageIndexTupleDelete(page, todelete[i]);
00228 GistMarkTuplesDeleted(page);
00229
00230 if (RelationNeedsWAL(rel))
00231 {
00232 XLogRecPtr recptr;
00233
00234 recptr = gistXLogUpdate(rel->rd_node, buffer,
00235 todelete, ntodelete,
00236 NULL, 0, InvalidBuffer);
00237 PageSetLSN(page, recptr);
00238 }
00239 else
00240 PageSetLSN(page, gistGetFakeLSN(rel));
00241
00242 END_CRIT_SECTION();
00243 }
00244
00245 }
00246 else
00247 {
00248
00249 pushStackIfSplited(page, stack);
00250
00251 maxoff = PageGetMaxOffsetNumber(page);
00252
00253 for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
00254 {
00255 iid = PageGetItemId(page, i);
00256 idxtuple = (IndexTuple) PageGetItem(page, iid);
00257
00258 ptr = (GistBDItem *) palloc(sizeof(GistBDItem));
00259 ptr->blkno = ItemPointerGetBlockNumber(&(idxtuple->t_tid));
00260 ptr->parentlsn = PageGetLSN(page);
00261 ptr->next = stack->next;
00262 stack->next = ptr;
00263
00264 if (GistTupleIsInvalid(idxtuple))
00265 ereport(LOG,
00266 (errmsg("index \"%s\" contains an inner tuple marked as invalid",
00267 RelationGetRelationName(rel)),
00268 errdetail("This is caused by an incomplete page split at crash recovery before upgrading to PostgreSQL 9.1."),
00269 errhint("Please REINDEX it.")));
00270 }
00271 }
00272
00273 UnlockReleaseBuffer(buffer);
00274
00275 ptr = stack->next;
00276 pfree(stack);
00277 stack = ptr;
00278
00279 vacuum_delay_point();
00280 }
00281
00282 PG_RETURN_POINTER(stats);
00283 }