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

📄 ginvacuum.c

📁 postgresql8.3.4源码,开源数据库
💻 C
📖 第 1 页 / 共 2 页
字号:
/*------------------------------------------------------------------------- * * ginvacuum.c *	  delete & vacuum routines for the postgres GIN * * * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION *			$PostgreSQL: pgsql/src/backend/access/gin/ginvacuum.c,v 1.19 2008/01/01 19:45:46 momjian Exp $ *------------------------------------------------------------------------- */#include "postgres.h"#include "access/genam.h"#include "access/gin.h"#include "access/heapam.h"#include "miscadmin.h"#include "storage/freespace.h"#include "storage/freespace.h"#include "commands/vacuum.h"typedef struct{	Relation	index;	IndexBulkDeleteResult *result;	IndexBulkDeleteCallback callback;	void	   *callback_state;	GinState	ginstate;	BufferAccessStrategy strategy;} GinVacuumState;/* * Cleans array of ItemPointer (removes dead pointers) * Results are always stored in *cleaned, which will be allocated * if it's needed. In case of *cleaned!=NULL caller is responsible to * have allocated enough space. *cleaned and items may point to the same * memory address. */static uint32ginVacuumPostingList(GinVacuumState *gvs, ItemPointerData *items, uint32 nitem, ItemPointerData **cleaned){	uint32		i,				j = 0;	/*	 * just scan over ItemPointer array	 */	for (i = 0; i < nitem; i++)	{		if (gvs->callback(items + i, gvs->callback_state))		{			gvs->result->tuples_removed += 1;			if (!*cleaned)			{				*cleaned = (ItemPointerData *) palloc(sizeof(ItemPointerData) * nitem);				if (i != 0)					memcpy(*cleaned, items, sizeof(ItemPointerData) * i);			}		}		else		{			gvs->result->num_index_tuples += 1;			if (i != j)				(*cleaned)[j] = items[i];			j++;		}	}	return j;}/* * fills WAL record for vacuum leaf page */static voidxlogVacuumPage(Relation index, Buffer buffer){	Page		page = BufferGetPage(buffer);	XLogRecPtr	recptr;	XLogRecData rdata[3];	ginxlogVacuumPage data;	char	   *backup;	char		itups[BLCKSZ];	uint32		len = 0;	Assert(GinPageIsLeaf(page));	if (index->rd_istemp)		return;	data.node = index->rd_node;	data.blkno = BufferGetBlockNumber(buffer);	if (GinPageIsData(page))	{		backup = GinDataPageGetData(page);		data.nitem = GinPageGetOpaque(page)->maxoff;		if (data.nitem)			len = MAXALIGN(sizeof(ItemPointerData) * data.nitem);	}	else	{		char	   *ptr;		OffsetNumber i;		ptr = backup = itups;		for (i = FirstOffsetNumber; i <= PageGetMaxOffsetNumber(page); i++)		{			IndexTuple	itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, i));			memcpy(ptr, itup, IndexTupleSize(itup));			ptr += MAXALIGN(IndexTupleSize(itup));		}		data.nitem = PageGetMaxOffsetNumber(page);		len = ptr - backup;	}	rdata[0].buffer = buffer;	rdata[0].buffer_std = (GinPageIsData(page)) ? FALSE : TRUE;	rdata[0].len = 0;	rdata[0].data = NULL;	rdata[0].next = rdata + 1;	rdata[1].buffer = InvalidBuffer;	rdata[1].len = sizeof(ginxlogVacuumPage);	rdata[1].data = (char *) &data;	if (len == 0)	{		rdata[1].next = NULL;	}	else	{		rdata[1].next = rdata + 2;		rdata[2].buffer = InvalidBuffer;		rdata[2].len = len;		rdata[2].data = backup;		rdata[2].next = NULL;	}	recptr = XLogInsert(RM_GIN_ID, XLOG_GIN_VACUUM_PAGE, rdata);	PageSetLSN(page, recptr);	PageSetTLI(page, ThisTimeLineID);}static boolginVacuumPostingTreeLeaves(GinVacuumState *gvs, BlockNumber blkno, bool isRoot, Buffer *rootBuffer){	Buffer		buffer = ReadBufferWithStrategy(gvs->index, blkno, gvs->strategy);	Page		page = BufferGetPage(buffer);	bool		hasVoidPage = FALSE;	/*	 * We should be sure that we don't concurrent with inserts, insert process	 * never release root page until end (but it can unlock it and lock	 * again). New scan can't start but previously started ones work	 * concurrently.	 */	if (isRoot)		LockBufferForCleanup(buffer);	else		LockBuffer(buffer, GIN_EXCLUSIVE);	Assert(GinPageIsData(page));	if (GinPageIsLeaf(page))	{		OffsetNumber newMaxOff,					oldMaxOff = GinPageGetOpaque(page)->maxoff;		ItemPointerData *cleaned = NULL;		newMaxOff = ginVacuumPostingList(gvs,				(ItemPointer) GinDataPageGetData(page), oldMaxOff, &cleaned);		/* saves changes about deleted tuple ... */		if (oldMaxOff != newMaxOff)		{			START_CRIT_SECTION();			if (newMaxOff > 0)				memcpy(GinDataPageGetData(page), cleaned, sizeof(ItemPointerData) * newMaxOff);			pfree(cleaned);			GinPageGetOpaque(page)->maxoff = newMaxOff;			MarkBufferDirty(buffer);			xlogVacuumPage(gvs->index, buffer);			END_CRIT_SECTION();			/* if root is a leaf page, we don't desire further processing */			if (!isRoot && GinPageGetOpaque(page)->maxoff < FirstOffsetNumber)				hasVoidPage = TRUE;		}	}	else	{		OffsetNumber i;		bool		isChildHasVoid = FALSE;		for (i = FirstOffsetNumber; i <= GinPageGetOpaque(page)->maxoff; i++)		{			PostingItem *pitem = (PostingItem *) GinDataPageGetItem(page, i);			if (ginVacuumPostingTreeLeaves(gvs, PostingItemGetBlockNumber(pitem), FALSE, NULL))				isChildHasVoid = TRUE;		}		if (isChildHasVoid)			hasVoidPage = TRUE;	}	/*	 * if we have root and theres void pages in tree, then we don't release	 * lock to go further processing and guarantee that tree is unused	 */	if (!(isRoot && hasVoidPage))	{		UnlockReleaseBuffer(buffer);	}	else	{		Assert(rootBuffer);		*rootBuffer = buffer;	}	return hasVoidPage;}static voidginDeletePage(GinVacuumState *gvs, BlockNumber deleteBlkno, BlockNumber leftBlkno,			  BlockNumber parentBlkno, OffsetNumber myoff, bool isParentRoot){	Buffer		dBuffer = ReadBufferWithStrategy(gvs->index, deleteBlkno, gvs->strategy);	Buffer		lBuffer = (leftBlkno == InvalidBlockNumber) ?	InvalidBuffer : ReadBufferWithStrategy(gvs->index, leftBlkno, gvs->strategy);	Buffer		pBuffer = ReadBufferWithStrategy(gvs->index, parentBlkno, gvs->strategy);	Page		page,				parentPage;	LockBuffer(dBuffer, GIN_EXCLUSIVE);	if (!isParentRoot)			/* parent is already locked by								 * LockBufferForCleanup() */		LockBuffer(pBuffer, GIN_EXCLUSIVE);	if (leftBlkno != InvalidBlockNumber)		LockBuffer(lBuffer, GIN_EXCLUSIVE);	START_CRIT_SECTION();	if (leftBlkno != InvalidBlockNumber)	{		BlockNumber rightlink;		page = BufferGetPage(dBuffer);		rightlink = GinPageGetOpaque(page)->rightlink;		page = BufferGetPage(lBuffer);		GinPageGetOpaque(page)->rightlink = rightlink;	}	parentPage = BufferGetPage(pBuffer);#ifdef USE_ASSERT_CHECKING	do	{		PostingItem *tod = (PostingItem *) GinDataPageGetItem(parentPage, myoff);		Assert(PostingItemGetBlockNumber(tod) == deleteBlkno);	} while (0);#endif	PageDeletePostingItem(parentPage, myoff);	page = BufferGetPage(dBuffer);	/*	 * we shouldn't change rightlink field to save workability of running	 * search scan	 */	GinPageGetOpaque(page)->flags = GIN_DELETED;	MarkBufferDirty(pBuffer);	if (leftBlkno != InvalidBlockNumber)		MarkBufferDirty(lBuffer);	MarkBufferDirty(dBuffer);	if (!gvs->index->rd_istemp)	{		XLogRecPtr	recptr;		XLogRecData rdata[4];		ginxlogDeletePage data;		int			n;		data.node = gvs->index->rd_node;		data.blkno = deleteBlkno;		data.parentBlkno = parentBlkno;		data.parentOffset = myoff;		data.leftBlkno = leftBlkno;		data.rightLink = GinPageGetOpaque(page)->rightlink;		rdata[0].buffer = dBuffer;		rdata[0].buffer_std = FALSE;		rdata[0].data = NULL;		rdata[0].len = 0;		rdata[0].next = rdata + 1;		rdata[1].buffer = pBuffer;		rdata[1].buffer_std = FALSE;		rdata[1].data = NULL;		rdata[1].len = 0;		rdata[1].next = rdata + 2;		if (leftBlkno != InvalidBlockNumber)		{			rdata[2].buffer = lBuffer;			rdata[2].buffer_std = FALSE;			rdata[2].data = NULL;			rdata[2].len = 0;			rdata[2].next = rdata + 3;			n = 3;		}		else			n = 2;		rdata[n].buffer = InvalidBuffer;		rdata[n].buffer_std = FALSE;		rdata[n].len = sizeof(ginxlogDeletePage);		rdata[n].data = (char *) &data;		rdata[n].next = NULL;		recptr = XLogInsert(RM_GIN_ID, XLOG_GIN_DELETE_PAGE, rdata);		PageSetLSN(page, recptr);		PageSetTLI(page, ThisTimeLineID);		PageSetLSN(parentPage, recptr);		PageSetTLI(parentPage, ThisTimeLineID);		if (leftBlkno != InvalidBlockNumber)		{			page = BufferGetPage(lBuffer);			PageSetLSN(page, recptr);			PageSetTLI(page, ThisTimeLineID);		}	}	if (!isParentRoot)		LockBuffer(pBuffer, GIN_UNLOCK);	ReleaseBuffer(pBuffer);	if (leftBlkno != InvalidBlockNumber)		UnlockReleaseBuffer(lBuffer);	UnlockReleaseBuffer(dBuffer);	END_CRIT_SECTION();	gvs->result->pages_deleted++;}typedef struct DataPageDeleteStack{	struct DataPageDeleteStack *child;	struct DataPageDeleteStack *parent;	BlockNumber blkno;			/* current block number */	BlockNumber leftBlkno;		/* rightest non-deleted page on left */	bool		isRoot;} DataPageDeleteStack;/* * scans posting tree and deletes empty pages */static boolginScanToDelete(GinVacuumState *gvs, BlockNumber blkno, bool isRoot, DataPageDeleteStack *parent, OffsetNumber myoff){	DataPageDeleteStack *me;	Buffer		buffer;	Page		page;	bool		meDelete = FALSE;	if (isRoot)	{

⌨️ 快捷键说明

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