⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 gistvacuum.c

📁 postgresql8.3.4源码,开源数据库
💻 C
📖 第 1 页 / 共 2 页
字号:
		 * will mark our page as deleted. In case of page split we never will		 * be here...		 *		 * If page was empty it can't become non-empty during processing		 */		res.emptypage = true;		UnlockReleaseBuffer(buffer);	}	else	{		/* write page and remove its childs if it need */		START_CRIT_SECTION();		if (tempPage && needwrite)		{			PageRestoreTempPage(tempPage, page);			tempPage = NULL;		}		/* Empty index */		if (PageIsEmpty(page) && blkno == GIST_ROOT_BLKNO)		{			needwrite = true;			GistPageSetLeaf(page);		}		if (needwrite)		{			MarkBufferDirty(buffer);			GistClearTuplesDeleted(page);			if (!gv->index->rd_istemp)			{				XLogRecData *rdata;				XLogRecPtr	recptr;				char	   *xlinfo;				rdata = formUpdateRdata(gv->index->rd_node, buffer,										offToDelete, nOffToDelete,										addon, curlenaddon, NULL);				xlinfo = rdata->next->data;				recptr = XLogInsert(RM_GIST_ID, XLOG_GIST_PAGE_UPDATE, rdata);				PageSetLSN(page, recptr);				PageSetTLI(page, ThisTimeLineID);				pfree(xlinfo);				pfree(rdata);			}			else				PageSetLSN(page, XLogRecPtrForTemp);		}		END_CRIT_SECTION();		if (needunion && !PageIsEmpty(page))		{			res.itup = (IndexTuple *) palloc(sizeof(IndexTuple));			res.ituplen = 1;			res.itup[0] = PageMakeUnionKey(gv, buffer);		}		UnlockReleaseBuffer(buffer);		/* delete empty children, now we havn't any links to pointed subtrees */		for (i = 0; i < nBlkToDelete; i++)			gistDeleteSubtree(gv, blkToDelete[i]);		if (ncompleted && !gv->index->rd_istemp)			gistxlogInsertCompletion(gv->index->rd_node, completed, ncompleted);	}	for (i = 0; i < curlenaddon; i++)		pfree(addon[i]);	if (addon)		pfree(addon);	if (completed)		pfree(completed);	if (tempPage)		pfree(tempPage);	return res;}/* * For usual vacuum just update FSM, for full vacuum * reforms parent tuples if some of childs was deleted or changed, * update invalid tuples (they can exist from last crash recovery only), * tries to get smaller index */Datumgistvacuumcleanup(PG_FUNCTION_ARGS){	IndexVacuumInfo *info = (IndexVacuumInfo *) PG_GETARG_POINTER(0);	GistBulkDeleteResult *stats = (GistBulkDeleteResult *) PG_GETARG_POINTER(1);	Relation	rel = info->index;	BlockNumber npages,				blkno;	BlockNumber totFreePages,				nFreePages,			   *freePages,				maxFreePages;	BlockNumber lastBlock = GIST_ROOT_BLKNO,				lastFilledBlock = GIST_ROOT_BLKNO;	bool		needLock;	/* Set up all-zero stats if gistbulkdelete wasn't called */	if (stats == NULL)	{		stats = (GistBulkDeleteResult *) palloc0(sizeof(GistBulkDeleteResult));		/* use heap's tuple count */		Assert(info->num_heap_tuples >= 0);		stats->std.num_index_tuples = info->num_heap_tuples;		/*		 * XXX the above is wrong if index is partial.	Would it be OK to just		 * return NULL, or is there work we must do below?		 */	}	/* gistVacuumUpdate may cause hard work */	if (info->vacuum_full)	{		GistVacuum	gv;		ArrayTuple	res;		/* note: vacuum.c already acquired AccessExclusiveLock on index */		gv.index = rel;		initGISTstate(&(gv.giststate), rel);		gv.opCtx = createTempGistContext();		gv.result = stats;		gv.strategy = info->strategy;		/* walk through the entire index for update tuples */		res = gistVacuumUpdate(&gv, GIST_ROOT_BLKNO, false);		/* cleanup */		if (res.itup)		{			int			i;			for (i = 0; i < res.ituplen; i++)				pfree(res.itup[i]);			pfree(res.itup);		}		freeGISTstate(&(gv.giststate));		MemoryContextDelete(gv.opCtx);	}	else if (stats->needFullVacuum)		ereport(NOTICE,				(errmsg("index \"%s\" needs VACUUM FULL or REINDEX to finish crash recovery",						RelationGetRelationName(rel))));	/*	 * If vacuum full, we already have exclusive lock on the index. Otherwise,	 * need lock unless it's local to this backend.	 */	if (info->vacuum_full)		needLock = false;	else		needLock = !RELATION_IS_LOCAL(rel);	/* try to find deleted pages */	if (needLock)		LockRelationForExtension(rel, ExclusiveLock);	npages = RelationGetNumberOfBlocks(rel);	if (needLock)		UnlockRelationForExtension(rel, ExclusiveLock);	maxFreePages = npages;	if (maxFreePages > MaxFSMPages)		maxFreePages = MaxFSMPages;	totFreePages = nFreePages = 0;	freePages = (BlockNumber *) palloc(sizeof(BlockNumber) * maxFreePages);	for (blkno = GIST_ROOT_BLKNO + 1; blkno < npages; blkno++)	{		Buffer		buffer;		Page		page;		vacuum_delay_point();		buffer = ReadBufferWithStrategy(rel, blkno, info->strategy);		LockBuffer(buffer, GIST_SHARE);		page = (Page) BufferGetPage(buffer);		if (PageIsNew(page) || GistPageIsDeleted(page))		{			if (nFreePages < maxFreePages)				freePages[nFreePages++] = blkno;			totFreePages++;		}		else			lastFilledBlock = blkno;		UnlockReleaseBuffer(buffer);	}	lastBlock = npages - 1;	if (info->vacuum_full && nFreePages > 0)	{							/* try to truncate index */		int			i;		for (i = 0; i < nFreePages; i++)			if (freePages[i] >= lastFilledBlock)			{				totFreePages = nFreePages = i;				break;			}		if (lastBlock > lastFilledBlock)			RelationTruncate(rel, lastFilledBlock + 1);		stats->std.pages_removed = lastBlock - lastFilledBlock;	}	RecordIndexFreeSpace(&rel->rd_node, totFreePages, nFreePages, freePages);	pfree(freePages);	/* return statistics */	stats->std.pages_free = totFreePages;	if (needLock)		LockRelationForExtension(rel, ExclusiveLock);	stats->std.num_pages = RelationGetNumberOfBlocks(rel);	if (needLock)		UnlockRelationForExtension(rel, ExclusiveLock);	PG_RETURN_POINTER(stats);}typedef struct GistBDItem{	GistNSN		parentlsn;	BlockNumber blkno;	struct GistBDItem *next;} GistBDItem;static voidpushStackIfSplited(Page page, GistBDItem *stack){	GISTPageOpaque opaque = GistPageGetOpaque(page);	if (stack->blkno != GIST_ROOT_BLKNO && !XLogRecPtrIsInvalid(stack->parentlsn) &&		XLByteLT(stack->parentlsn, opaque->nsn) &&		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 after crash recovery. * The set of target tuples is specified via a callback routine that tells * whether any given heap tuple (identified by ItemPointer) is being deleted. * * Result: a palloc'd struct containing statistical info for VACUUM displays. */Datumgistbulkdelete(PG_FUNCTION_ARGS){	IndexVacuumInfo *info = (IndexVacuumInfo *) PG_GETARG_POINTER(0);	GistBulkDeleteResult *stats = (GistBulkDeleteResult *) PG_GETARG_POINTER(1);	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 = (GistBulkDeleteResult *) palloc0(sizeof(GistBulkDeleteResult));	/* we'll re-count the tuples each time */	stats->std.num_index_tuples = 0;	stack = (GistBDItem *) palloc0(sizeof(GistBDItem));	stack->blkno = GIST_ROOT_BLKNO;	while (stack)	{		Buffer		buffer = ReadBufferWithStrategy(rel, stack->blkno, info->strategy);		Page		page;		OffsetNumber i,					maxoff;		IndexTuple	idxtuple;		ItemId		iid;		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->std.tuples_removed += 1;				}				else					stats->std.num_index_tuples += 1;			}			if (ntodelete)			{				START_CRIT_SECTION();				MarkBufferDirty(buffer);				for (i = 0; i < ntodelete; i++)					PageIndexTupleDelete(page, todelete[i]);				GistMarkTuplesDeleted(page);				if (!rel->rd_istemp)				{					XLogRecData *rdata;					XLogRecPtr	recptr;					gistxlogPageUpdate *xlinfo;					rdata = formUpdateRdata(rel->rd_node, buffer,											todelete, ntodelete,											NULL, 0,											NULL);					xlinfo = (gistxlogPageUpdate *) rdata->next->data;					recptr = XLogInsert(RM_GIST_ID, XLOG_GIST_PAGE_UPDATE, rdata);					PageSetLSN(page, recptr);					PageSetTLI(page, ThisTimeLineID);					pfree(xlinfo);					pfree(rdata);				}				else					PageSetLSN(page, XLogRecPtrForTemp);				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))					stats->needFullVacuum = true;			}		}		UnlockReleaseBuffer(buffer);		ptr = stack->next;		pfree(stack);		stack = ptr;		vacuum_delay_point();	}	PG_RETURN_POINTER(stats);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -