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

Reply via email to