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 (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers