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

📄 ginvacuum.c

📁 postgresql8.3.4源码,开源数据库
💻 C
📖 第 1 页 / 共 2 页
字号:
		me = parent;	}	else	{		if (!parent->child)		{			me = (DataPageDeleteStack *) palloc0(sizeof(DataPageDeleteStack));			me->parent = parent;			parent->child = me;			me->leftBlkno = InvalidBlockNumber;		}		else			me = parent->child;	}	buffer = ReadBufferWithStrategy(gvs->index, blkno, gvs->strategy);	page = BufferGetPage(buffer);	Assert(GinPageIsData(page));	if (!GinPageIsLeaf(page))	{		OffsetNumber i;		me->blkno = blkno;		for (i = FirstOffsetNumber; i <= GinPageGetOpaque(page)->maxoff; i++)		{			PostingItem *pitem = (PostingItem *) GinDataPageGetItem(page, i);			if (ginScanToDelete(gvs, PostingItemGetBlockNumber(pitem), FALSE, me, i))				i--;		}	}	if (GinPageGetOpaque(page)->maxoff < FirstOffsetNumber)	{		if (!(me->leftBlkno == InvalidBlockNumber && GinPageRightMost(page)))		{			/* we never delete right most branch */			Assert(!isRoot);			if (GinPageGetOpaque(page)->maxoff < FirstOffsetNumber)			{				ginDeletePage(gvs, blkno, me->leftBlkno, me->parent->blkno, myoff, me->parent->isRoot);				meDelete = TRUE;			}		}	}	ReleaseBuffer(buffer);	if (!meDelete)		me->leftBlkno = blkno;	return meDelete;}static voidginVacuumPostingTree(GinVacuumState *gvs, BlockNumber rootBlkno){	Buffer		rootBuffer = InvalidBuffer;	DataPageDeleteStack root,			   *ptr,			   *tmp;	if (ginVacuumPostingTreeLeaves(gvs, rootBlkno, TRUE, &rootBuffer) == FALSE)	{		Assert(rootBuffer == InvalidBuffer);		return;	}	memset(&root, 0, sizeof(DataPageDeleteStack));	root.leftBlkno = InvalidBlockNumber;	root.isRoot = TRUE;	vacuum_delay_point();	ginScanToDelete(gvs, rootBlkno, TRUE, &root, InvalidOffsetNumber);	ptr = root.child;	while (ptr)	{		tmp = ptr->child;		pfree(ptr);		ptr = tmp;	}	UnlockReleaseBuffer(rootBuffer);}/* * returns modified page or NULL if page isn't modified. * Function works with original page until first change is occurred, * then page is copied into temporary one. */static PageginVacuumEntryPage(GinVacuumState *gvs, Buffer buffer, BlockNumber *roots, uint32 *nroot){	Page		origpage = BufferGetPage(buffer),				tmppage;	OffsetNumber i,				maxoff = PageGetMaxOffsetNumber(origpage);	tmppage = origpage;	*nroot = 0;	for (i = FirstOffsetNumber; i <= maxoff; i++)	{		IndexTuple	itup = (IndexTuple) PageGetItem(tmppage, PageGetItemId(tmppage, i));		if (GinIsPostingTree(itup))		{			/*			 * store posting tree's roots for further processing, we can't			 * vacuum it just now due to risk of deadlocks with scans/inserts			 */			roots[*nroot] = GinItemPointerGetBlockNumber(&itup->t_tid);			(*nroot)++;		}		else if (GinGetNPosting(itup) > 0)		{			/*			 * if we already create temporary page, we will make changes in			 * place			 */			ItemPointerData *cleaned = (tmppage == origpage) ? NULL : GinGetPosting(itup);			uint32		newN = ginVacuumPostingList(gvs, GinGetPosting(itup), GinGetNPosting(itup), &cleaned);			if (GinGetNPosting(itup) != newN)			{				bool		isnull;				Datum		value;				/*				 * Some ItemPointers was deleted, so we should remake our				 * tuple				 */				if (tmppage == origpage)				{					/*					 * On first difference we create temporary page in memory					 * and copies content in to it.					 */					tmppage = GinPageGetCopyPage(origpage);					if (newN > 0)					{						Size		pos = ((char *) GinGetPosting(itup)) - ((char *) origpage);						memcpy(tmppage + pos, cleaned, sizeof(ItemPointerData) * newN);					}					pfree(cleaned);					/* set itup pointer to new page */					itup = (IndexTuple) PageGetItem(tmppage, PageGetItemId(tmppage, i));				}				value = index_getattr(itup, FirstOffsetNumber, gvs->ginstate.tupdesc, &isnull);				itup = GinFormTuple(&gvs->ginstate, value, GinGetPosting(itup), newN);				PageIndexTupleDelete(tmppage, i);				if (PageAddItem(tmppage, (Item) itup, IndexTupleSize(itup), i, false, false) != i)					elog(ERROR, "failed to add item to index page in \"%s\"",						 RelationGetRelationName(gvs->index));				pfree(itup);			}		}	}	return (tmppage == origpage) ? NULL : tmppage;}Datumginbulkdelete(PG_FUNCTION_ARGS){	IndexVacuumInfo *info = (IndexVacuumInfo *) PG_GETARG_POINTER(0);	IndexBulkDeleteResult *stats = (IndexBulkDeleteResult *) PG_GETARG_POINTER(1);	IndexBulkDeleteCallback callback = (IndexBulkDeleteCallback) PG_GETARG_POINTER(2);	void	   *callback_state = (void *) PG_GETARG_POINTER(3);	Relation	index = info->index;	BlockNumber blkno = GIN_ROOT_BLKNO;	GinVacuumState gvs;	Buffer		buffer;	BlockNumber rootOfPostingTree[BLCKSZ / (sizeof(IndexTupleData) + sizeof(ItemId))];	uint32		nRoot;	/* first time through? */	if (stats == NULL)		stats = (IndexBulkDeleteResult *) palloc0(sizeof(IndexBulkDeleteResult));	/* we'll re-count the tuples each time */	stats->num_index_tuples = 0;	gvs.index = index;	gvs.result = stats;	gvs.callback = callback;	gvs.callback_state = callback_state;	gvs.strategy = info->strategy;	initGinState(&gvs.ginstate, index);	buffer = ReadBufferWithStrategy(index, blkno, info->strategy);	/* find leaf page */	for (;;)	{		Page		page = BufferGetPage(buffer);		IndexTuple	itup;		LockBuffer(buffer, GIN_SHARE);		Assert(!GinPageIsData(page));		if (GinPageIsLeaf(page))		{			LockBuffer(buffer, GIN_UNLOCK);			LockBuffer(buffer, GIN_EXCLUSIVE);			if (blkno == GIN_ROOT_BLKNO && !GinPageIsLeaf(page))			{				LockBuffer(buffer, GIN_UNLOCK);				continue;		/* check it one more */			}			break;		}		Assert(PageGetMaxOffsetNumber(page) >= FirstOffsetNumber);		itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, FirstOffsetNumber));		blkno = GinItemPointerGetBlockNumber(&(itup)->t_tid);		Assert(blkno != InvalidBlockNumber);		UnlockReleaseBuffer(buffer);		buffer = ReadBufferWithStrategy(index, blkno, info->strategy);	}	/* right now we found leftmost page in entry's BTree */	for (;;)	{		Page		page = BufferGetPage(buffer);		Page		resPage;		uint32		i;		Assert(!GinPageIsData(page));		resPage = ginVacuumEntryPage(&gvs, buffer, rootOfPostingTree, &nRoot);		blkno = GinPageGetOpaque(page)->rightlink;		if (resPage)		{			START_CRIT_SECTION();			PageRestoreTempPage(resPage, page);			MarkBufferDirty(buffer);			xlogVacuumPage(gvs.index, buffer);			UnlockReleaseBuffer(buffer);			END_CRIT_SECTION();		}		else		{			UnlockReleaseBuffer(buffer);		}		vacuum_delay_point();		for (i = 0; i < nRoot; i++)		{			ginVacuumPostingTree(&gvs, rootOfPostingTree[i]);			vacuum_delay_point();		}		if (blkno == InvalidBlockNumber)		/* rightmost page */			break;		buffer = ReadBufferWithStrategy(index, blkno, info->strategy);		LockBuffer(buffer, GIN_EXCLUSIVE);	}	PG_RETURN_POINTER(gvs.result);}Datumginvacuumcleanup(PG_FUNCTION_ARGS){	IndexVacuumInfo *info = (IndexVacuumInfo *) PG_GETARG_POINTER(0);	IndexBulkDeleteResult *stats = (IndexBulkDeleteResult *) PG_GETARG_POINTER(1);	Relation	index = info->index;	bool		needLock;	BlockNumber npages,				blkno;	BlockNumber totFreePages,				nFreePages,			   *freePages,				maxFreePages;	BlockNumber lastBlock = GIN_ROOT_BLKNO,				lastFilledBlock = GIN_ROOT_BLKNO;	/* Set up all-zero stats if ginbulkdelete wasn't called */	if (stats == NULL)		stats = (IndexBulkDeleteResult *) palloc0(sizeof(IndexBulkDeleteResult));	/*	 * XXX we always report the heap tuple count as the number of index	 * entries.  This is bogus if the index is partial, but it's real hard to	 * tell how many distinct heap entries are referenced by a GIN index.	 */	stats->num_index_tuples = info->num_heap_tuples;	/*	 * 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(index);	if (needLock)		LockRelationForExtension(index, ExclusiveLock);	npages = RelationGetNumberOfBlocks(index);	if (needLock)		UnlockRelationForExtension(index, ExclusiveLock);	maxFreePages = npages;	if (maxFreePages > MaxFSMPages)		maxFreePages = MaxFSMPages;	totFreePages = nFreePages = 0;	freePages = (BlockNumber *) palloc(sizeof(BlockNumber) * maxFreePages);	for (blkno = GIN_ROOT_BLKNO + 1; blkno < npages; blkno++)	{		Buffer		buffer;		Page		page;		vacuum_delay_point();		buffer = ReadBufferWithStrategy(index, blkno, info->strategy);		LockBuffer(buffer, GIN_SHARE);		page = (Page) BufferGetPage(buffer);		if (GinPageIsDeleted(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(index, lastFilledBlock + 1);		stats->pages_removed = lastBlock - lastFilledBlock;	}	RecordIndexFreeSpace(&index->rd_node, totFreePages, nFreePages, freePages);	stats->pages_free = totFreePages;	if (needLock)		LockRelationForExtension(index, ExclusiveLock);	stats->num_pages = RelationGetNumberOfBlocks(index);	if (needLock)		UnlockRelationForExtension(index, ExclusiveLock);	PG_RETURN_POINTER(stats);}

⌨️ 快捷键说明

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