hello.
i recode vacuum for gist index.
all tests is ok.
also i test vacuum on table size 2 million rows. all is ok.
on my machine old vaccum work about 9 second. this version work about 6-7 sec .
review please.
thanks.
*** a/src/backend/access/gist/gistvacuum.c
--- b/src/backend/access/gist/gistvacuum.c
***************
*** 101,134 **** gistvacuumcleanup(PG_FUNCTION_ARGS)
PG_RETURN_POINTER(stats);
}
- typedef struct GistBDItem
- {
- GistNSN parentlsn;
- BlockNumber blkno;
- struct GistBDItem *next;
- } GistBDItem;
-
- static void
- pushStackIfSplited(Page page, GistBDItem *stack)
- {
- GISTPageOpaque opaque = GistPageGetOpaque(page);
-
- if (stack->blkno != GIST_ROOT_BLKNO && !XLogRecPtrIsInvalid(stack->parentlsn) &&
- (GistFollowRight(page) || stack->parentlsn < GistPageGetNSN(page)) &&
- opaque->rightlink != InvalidBlockNumber /* sanity check */ )
- {
- /* split page detected, install right link to the stack */
-
- GistBDItem *ptr = (GistBDItem *) palloc(sizeof(GistBDItem));
-
- ptr->blkno = opaque->rightlink;
- ptr->parentlsn = stack->parentlsn;
- ptr->next = stack->next;
- stack->next = ptr;
- }
- }
-
-
/*
* Bulk deletion of all index entries pointing to a set of heap tuples and
* check invalid tuples left after upgrade.
--- 101,106 ----
***************
*** 145,283 **** gistbulkdelete(PG_FUNCTION_ARGS)
IndexBulkDeleteCallback callback = (IndexBulkDeleteCallback) PG_GETARG_POINTER(2);
void *callback_state = (void *) PG_GETARG_POINTER(3);
Relation rel = info->index;
! GistBDItem *stack,
! *ptr;
!
! /* first time through? */
if (stats == NULL)
stats = (IndexBulkDeleteResult *) palloc0(sizeof(IndexBulkDeleteResult));
- /* we'll re-count the tuples each time */
stats->estimated_count = false;
stats->num_index_tuples = 0;
! stack = (GistBDItem *) palloc0(sizeof(GistBDItem));
! stack->blkno = GIST_ROOT_BLKNO;
!
! while (stack)
! {
! Buffer buffer;
! Page page;
! OffsetNumber i,
! maxoff;
! IndexTuple idxtuple;
! ItemId iid;
!
! buffer = ReadBufferExtended(rel, MAIN_FORKNUM, stack->blkno,
! RBM_NORMAL, info->strategy);
! LockBuffer(buffer, GIST_SHARE);
! gistcheckpage(rel, buffer);
! page = (Page) BufferGetPage(buffer);
!
! if (GistPageIsLeaf(page))
{
! OffsetNumber todelete[MaxOffsetNumber];
! int ntodelete = 0;
!
! LockBuffer(buffer, GIST_UNLOCK);
! LockBuffer(buffer, GIST_EXCLUSIVE);
page = (Page) BufferGetPage(buffer);
- if (stack->blkno == GIST_ROOT_BLKNO && !GistPageIsLeaf(page))
- {
- /* only the root can become non-leaf during relock */
- UnlockReleaseBuffer(buffer);
- /* one more check */
- continue;
- }
-
- /*
- * check for split proceeded after look at parent, we should check
- * it after relock
- */
- pushStackIfSplited(page, stack);
! /*
! * Remove deletable tuples from page
! */
!
! maxoff = PageGetMaxOffsetNumber(page);
!
! for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
{
! iid = PageGetItemId(page, i);
! idxtuple = (IndexTuple) PageGetItem(page, iid);
!
! if (callback(&(idxtuple->t_tid), callback_state))
{
! todelete[ntodelete] = i - ntodelete;
! ntodelete++;
! stats->tuples_removed += 1;
}
- else
- stats->num_index_tuples += 1;
- }
-
- if (ntodelete)
- {
- START_CRIT_SECTION();
-
- MarkBufferDirty(buffer);
-
- for (i = 0; i < ntodelete; i++)
- PageIndexTupleDelete(page, todelete[i]);
- GistMarkTuplesDeleted(page);
! if (RelationNeedsWAL(rel))
{
! XLogRecPtr recptr;
! recptr = gistXLogUpdate(rel->rd_node, buffer,
! todelete, ntodelete,
! NULL, 0, InvalidBuffer);
! PageSetLSN(page, recptr);
! }
! else
! PageSetLSN(page, gistGetFakeLSN(rel));
!
! END_CRIT_SECTION();
! }
! }
! else
! {
! /* check for split proceeded after look at parent */
! pushStackIfSplited(page, stack);
!
! maxoff = PageGetMaxOffsetNumber(page);
! for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
! {
! iid = PageGetItemId(page, i);
! idxtuple = (IndexTuple) PageGetItem(page, iid);
! ptr = (GistBDItem *) palloc(sizeof(GistBDItem));
! ptr->blkno = ItemPointerGetBlockNumber(&(idxtuple->t_tid));
! ptr->parentlsn = PageGetLSN(page);
! ptr->next = stack->next;
! stack->next = ptr;
! if (GistTupleIsInvalid(idxtuple))
! ereport(LOG,
! (errmsg("index \"%s\" contains an inner tuple marked as invalid",
! RelationGetRelationName(rel)),
! errdetail("This is caused by an incomplete page split at crash recovery before upgrading to PostgreSQL 9.1."),
! errhint("Please REINDEX it.")));
}
- }
-
- UnlockReleaseBuffer(buffer);
! ptr = stack->next;
! pfree(stack);
! stack = ptr;
!
! vacuum_delay_point();
}
PG_RETURN_POINTER(stats);
}
--- 117,208 ----
IndexBulkDeleteCallback callback = (IndexBulkDeleteCallback) PG_GETARG_POINTER(2);
void *callback_state = (void *) PG_GETARG_POINTER(3);
Relation rel = info->index;
! BlockNumber blkno = GIST_ROOT_BLKNO + 1;
! bool needLock = !RELATION_IS_LOCAL(rel);
if (stats == NULL)
stats = (IndexBulkDeleteResult *) palloc0(sizeof(IndexBulkDeleteResult));
stats->estimated_count = false;
stats->num_index_tuples = 0;
! for(;;) {
! BlockNumber npages;
! if (needLock)
! LockRelationForExtension(rel, ExclusiveLock);
! npages = RelationGetNumberOfBlocks(rel);
! if (needLock)
! UnlockRelationForExtension(rel, ExclusiveLock);
! if (blkno >= npages)
! break;
! for ( ; blkno < npages; blkno++)
{
! Buffer buffer;
! Page page;
+ buffer = ReadBufferExtended(rel, MAIN_FORKNUM, blkno,
+ RBM_NORMAL, info->strategy);
+ LockBuffer(buffer, GIST_SHARE);
+ gistcheckpage(rel, buffer);
page = (Page) BufferGetPage(buffer);
! if (GistPageIsLeaf(page))
{
! OffsetNumber todelete[MaxOffsetNumber];
! int ntodelete = 0;
! OffsetNumber i,
! maxoff;
! IndexTuple idxtuple;
! ItemId iid;
! LockBuffer(buffer, GIST_UNLOCK);
! LockBuffer(buffer, GIST_EXCLUSIVE);
!
! page = (Page) BufferGetPage(buffer);
! maxoff = PageGetMaxOffsetNumber(page);
!
! for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
{
! iid = PageGetItemId(page, i);
! idxtuple = (IndexTuple) PageGetItem(page, iid);
!
! if (callback(&(idxtuple->t_tid), callback_state))
! {
! todelete[ntodelete] = i - ntodelete;
! ntodelete++;
! stats->tuples_removed += 1;
! }
! else
! stats->num_index_tuples += 1;
}
! if (ntodelete)
{
! START_CRIT_SECTION();
! MarkBufferDirty(buffer);
! for (i = 0; i < ntodelete; i++)
! PageIndexTupleDelete(page, todelete[i]);
! GistMarkTuplesDeleted(page);
! if (RelationNeedsWAL(rel))
! {
! XLogRecPtr recptr;
! recptr = gistXLogUpdate(rel->rd_node, buffer,
! todelete, ntodelete,
! NULL, 0, InvalidBuffer);
! PageSetLSN(page, recptr);
! }
! else
! PageSetLSN(page, gistGetFakeLSN(rel));
! END_CRIT_SECTION();
! }
}
! UnlockReleaseBuffer(buffer);
! }
}
+
PG_RETURN_POINTER(stats);
}
-- Sent via pgsql-hackers mailing list ([email protected]) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers
