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

📄 gist.c

📁 postgresql8.3.4源码,开源数据库
💻 C
📖 第 1 页 / 共 2 页
字号:
/*------------------------------------------------------------------------- * * gist.c *	  interface routines for the postgres GiST index access method. * * * 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/gist/gist.c,v 1.149 2008/01/01 19:45:46 momjian Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#include "access/genam.h"#include "access/gist_private.h"#include "catalog/index.h"#include "miscadmin.h"#include "utils/memutils.h"const XLogRecPtr XLogRecPtrForTemp = {1, 1};/* Working state for gistbuild and its callback */typedef struct{	GISTSTATE	giststate;	int			numindexattrs;	double		indtuples;	MemoryContext tmpCtx;} GISTBuildState;/* non-export function prototypes */static void gistbuildCallback(Relation index,				  HeapTuple htup,				  Datum *values,				  bool *isnull,				  bool tupleIsAlive,				  void *state);static void gistdoinsert(Relation r,			 IndexTuple itup,			 Size freespace,			 GISTSTATE *GISTstate);static void gistfindleaf(GISTInsertState *state,			 GISTSTATE *giststate);#define ROTATEDIST(d) do { \	SplitedPageLayout *tmp=(SplitedPageLayout*)palloc(sizeof(SplitedPageLayout)); \	memset(tmp,0,sizeof(SplitedPageLayout)); \	tmp->block.blkno = InvalidBlockNumber;	\	tmp->buffer = InvalidBuffer;	\	tmp->next = (d); \	(d)=tmp; \} while(0)/* * Create and return a temporary memory context for use by GiST. We * _always_ invoke user-provided methods in a temporary memory * context, so that memory leaks in those functions cannot cause * problems. Also, we use some additional temporary contexts in the * GiST code itself, to avoid the need to do some awkward manual * memory management. */MemoryContextcreateTempGistContext(void){	return AllocSetContextCreate(CurrentMemoryContext,								 "GiST temporary context",								 ALLOCSET_DEFAULT_MINSIZE,								 ALLOCSET_DEFAULT_INITSIZE,								 ALLOCSET_DEFAULT_MAXSIZE);}/* * Routine to build an index.  Basically calls insert over and over. * * XXX: it would be nice to implement some sort of bulk-loading * algorithm, but it is not clear how to do that. */Datumgistbuild(PG_FUNCTION_ARGS){	Relation	heap = (Relation) PG_GETARG_POINTER(0);	Relation	index = (Relation) PG_GETARG_POINTER(1);	IndexInfo  *indexInfo = (IndexInfo *) PG_GETARG_POINTER(2);	IndexBuildResult *result;	double		reltuples;	GISTBuildState buildstate;	Buffer		buffer;	Page		page;	/*	 * We expect to be called exactly once for any index relation. If that's	 * not the case, big trouble's what we have.	 */	if (RelationGetNumberOfBlocks(index) != 0)		elog(ERROR, "index \"%s\" already contains data",			 RelationGetRelationName(index));	/* no locking is needed */	initGISTstate(&buildstate.giststate, index);	/* initialize the root page */	buffer = gistNewBuffer(index);	Assert(BufferGetBlockNumber(buffer) == GIST_ROOT_BLKNO);	page = BufferGetPage(buffer);	START_CRIT_SECTION();	GISTInitBuffer(buffer, F_LEAF);	MarkBufferDirty(buffer);	if (!index->rd_istemp)	{		XLogRecPtr	recptr;		XLogRecData rdata;		rdata.data = (char *) &(index->rd_node);		rdata.len = sizeof(RelFileNode);		rdata.buffer = InvalidBuffer;		rdata.next = NULL;		recptr = XLogInsert(RM_GIST_ID, XLOG_GIST_CREATE_INDEX, &rdata);		PageSetLSN(page, recptr);		PageSetTLI(page, ThisTimeLineID);	}	else		PageSetLSN(page, XLogRecPtrForTemp);	UnlockReleaseBuffer(buffer);	END_CRIT_SECTION();	/* build the index */	buildstate.numindexattrs = indexInfo->ii_NumIndexAttrs;	buildstate.indtuples = 0;	/*	 * create a temporary memory context that is reset once for each tuple	 * inserted into the index	 */	buildstate.tmpCtx = createTempGistContext();	/* do the heap scan */	reltuples = IndexBuildHeapScan(heap, index, indexInfo,								   gistbuildCallback, (void *) &buildstate);	/* okay, all heap tuples are indexed */	MemoryContextDelete(buildstate.tmpCtx);	freeGISTstate(&buildstate.giststate);	/*	 * Return statistics	 */	result = (IndexBuildResult *) palloc(sizeof(IndexBuildResult));	result->heap_tuples = reltuples;	result->index_tuples = buildstate.indtuples;	PG_RETURN_POINTER(result);}/* * Per-tuple callback from IndexBuildHeapScan */static voidgistbuildCallback(Relation index,				  HeapTuple htup,				  Datum *values,				  bool *isnull,				  bool tupleIsAlive,				  void *state){	GISTBuildState *buildstate = (GISTBuildState *) state;	IndexTuple	itup;	MemoryContext oldCtx;	oldCtx = MemoryContextSwitchTo(buildstate->tmpCtx);	/* form an index tuple and point it at the heap tuple */	itup = gistFormTuple(&buildstate->giststate, index,						 values, isnull, true /* size is currently bogus */ );	itup->t_tid = htup->t_self;	/*	 * Since we already have the index relation locked, we call gistdoinsert	 * directly.  Normal access method calls dispatch through gistinsert,	 * which locks the relation for write.	This is the right thing to do if	 * you're inserting single tups, but not when you're initializing the	 * whole index at once.	 *	 * In this path we respect the fillfactor setting, whereas insertions	 * after initial build do not.	 */	gistdoinsert(index, itup,			  RelationGetTargetPageFreeSpace(index, GIST_DEFAULT_FILLFACTOR),				 &buildstate->giststate);	buildstate->indtuples += 1;	MemoryContextSwitchTo(oldCtx);	MemoryContextReset(buildstate->tmpCtx);}/* *	gistinsert -- wrapper for GiST tuple insertion. * *	  This is the public interface routine for tuple insertion in GiSTs. *	  It doesn't do any work; just locks the relation and passes the buck. */Datumgistinsert(PG_FUNCTION_ARGS){	Relation	r = (Relation) PG_GETARG_POINTER(0);	Datum	   *values = (Datum *) PG_GETARG_POINTER(1);	bool	   *isnull = (bool *) PG_GETARG_POINTER(2);	ItemPointer ht_ctid = (ItemPointer) PG_GETARG_POINTER(3);#ifdef NOT_USED	Relation	heapRel = (Relation) PG_GETARG_POINTER(4);	bool		checkUnique = PG_GETARG_BOOL(5);#endif	IndexTuple	itup;	GISTSTATE	giststate;	MemoryContext oldCtx;	MemoryContext insertCtx;	insertCtx = createTempGistContext();	oldCtx = MemoryContextSwitchTo(insertCtx);	initGISTstate(&giststate, r);	itup = gistFormTuple(&giststate, r,						 values, isnull, true /* size is currently bogus */ );	itup->t_tid = *ht_ctid;	gistdoinsert(r, itup, 0, &giststate);	/* cleanup */	freeGISTstate(&giststate);	MemoryContextSwitchTo(oldCtx);	MemoryContextDelete(insertCtx);	PG_RETURN_BOOL(true);}/* * Workhouse routine for doing insertion into a GiST index. Note that * this routine assumes it is invoked in a short-lived memory context, * so it does not bother releasing palloc'd allocations. */static voidgistdoinsert(Relation r, IndexTuple itup, Size freespace, GISTSTATE *giststate){	GISTInsertState state;	memset(&state, 0, sizeof(GISTInsertState));	state.itup = (IndexTuple *) palloc(sizeof(IndexTuple));	state.itup[0] = (IndexTuple) palloc(IndexTupleSize(itup));	memcpy(state.itup[0], itup, IndexTupleSize(itup));	state.ituplen = 1;	state.freespace = freespace;	state.r = r;	state.key = itup->t_tid;	state.needInsertComplete = true;	state.stack = (GISTInsertStack *) palloc0(sizeof(GISTInsertStack));	state.stack->blkno = GIST_ROOT_BLKNO;	gistfindleaf(&state, giststate);	gistmakedeal(&state, giststate);}static boolgistplacetopage(GISTInsertState *state, GISTSTATE *giststate){	bool		is_splitted = false;	bool		is_leaf = (GistPageIsLeaf(state->stack->page)) ? true : false;	/*	 * if (!is_leaf) remove old key: This node's key has been modified, either	 * because a child split occurred or because we needed to adjust our key	 * for an insert in a child node. Therefore, remove the old version of	 * this node's key.	 *	 * for WAL replay, in the non-split case we handle this by setting up a	 * one-element todelete array; in the split case, it's handled implicitly	 * because the tuple vector passed to gistSplit won't include this tuple.	 *	 * XXX: If we want to change fillfactors between node and leaf, fillfactor	 * = (is_leaf ? state->leaf_fillfactor : state->node_fillfactor)	 */	if (gistnospace(state->stack->page, state->itup, state->ituplen,					is_leaf ? InvalidOffsetNumber : state->stack->childoffnum,					state->freespace))	{		/* no space for insertion */		IndexTuple *itvec;		int			tlen;		SplitedPageLayout *dist = NULL,				   *ptr;		BlockNumber rrlink = InvalidBlockNumber;		GistNSN		oldnsn;		is_splitted = true;		/*		 * Form index tuples vector to split: remove old tuple if t's needed		 * and add new tuples to vector		 */		itvec = gistextractpage(state->stack->page, &tlen);		if (!is_leaf)		{			/* on inner page we should remove old tuple */			int			pos = state->stack->childoffnum - FirstOffsetNumber;			tlen--;			if (pos != tlen)				memmove(itvec + pos, itvec + pos + 1, sizeof(IndexTuple) * (tlen - pos));		}		itvec = gistjoinvector(itvec, &tlen, state->itup, state->ituplen);		dist = gistSplit(state->r, state->stack->page, itvec, tlen, giststate);		state->itup = (IndexTuple *) palloc(sizeof(IndexTuple) * tlen);		state->ituplen = 0;		if (state->stack->blkno != GIST_ROOT_BLKNO)		{			/*			 * if non-root split then we should not allocate new buffer, but			 * we must create temporary page to operate			 */			dist->buffer = state->stack->buffer;			dist->page = PageGetTempPage(BufferGetPage(dist->buffer), sizeof(GISTPageOpaqueData));			/* clean all flags except F_LEAF */			GistPageGetOpaque(dist->page)->flags = (is_leaf) ? F_LEAF : 0;		}		/* make new pages and fills them */		for (ptr = dist; ptr; ptr = ptr->next)		{			int			i;			char	   *data;			/* get new page */			if (ptr->buffer == InvalidBuffer)			{				ptr->buffer = gistNewBuffer(state->r);				GISTInitBuffer(ptr->buffer, (is_leaf) ? F_LEAF : 0);				ptr->page = BufferGetPage(ptr->buffer);			}			ptr->block.blkno = BufferGetBlockNumber(ptr->buffer);			/*			 * fill page, we can do it because all these pages are new (ie not			 * linked in tree or masked by temp page			 */			data = (char *) (ptr->list);			for (i = 0; i < ptr->block.num; i++)			{				if (PageAddItem(ptr->page, (Item) data, IndexTupleSize((IndexTuple) data), i + FirstOffsetNumber, false, false) == InvalidOffsetNumber)					elog(ERROR, "failed to add item to index page in \"%s\"", RelationGetRelationName(state->r));				data += IndexTupleSize((IndexTuple) data);			}			/* set up ItemPointer and remember it for parent */			ItemPointerSetBlockNumber(&(ptr->itup->t_tid), ptr->block.blkno);			state->itup[state->ituplen] = ptr->itup;			state->ituplen++;		}		/* saves old rightlink */		if (state->stack->blkno != GIST_ROOT_BLKNO)			rrlink = GistPageGetOpaque(dist->page)->rightlink;		START_CRIT_SECTION();		/*		 * must mark buffers dirty before XLogInsert, even though we'll still		 * be changing their opaque fields below. set up right links.		 */		for (ptr = dist; ptr; ptr = ptr->next)		{			MarkBufferDirty(ptr->buffer);			GistPageGetOpaque(ptr->page)->rightlink = (ptr->next) ?				ptr->next->block.blkno : rrlink;		}		/* restore splitted non-root page */		if (state->stack->blkno != GIST_ROOT_BLKNO)		{			PageRestoreTempPage(dist->page, BufferGetPage(dist->buffer));			dist->page = BufferGetPage(dist->buffer);		}		if (!state->r->rd_istemp)		{			XLogRecPtr	recptr;			XLogRecData *rdata;			rdata = formSplitRdata(state->r->rd_node, state->stack->blkno,								   is_leaf, &(state->key), dist);			recptr = XLogInsert(RM_GIST_ID, XLOG_GIST_PAGE_SPLIT, rdata);			for (ptr = dist; ptr; ptr = ptr->next)			{				PageSetLSN(ptr->page, recptr);				PageSetTLI(ptr->page, ThisTimeLineID);			}		}		else		{			for (ptr = dist; ptr; ptr = ptr->next)			{				PageSetLSN(ptr->page, XLogRecPtrForTemp);			}		}		/* set up NSN */		oldnsn = GistPageGetOpaque(dist->page)->nsn;		if (state->stack->blkno == GIST_ROOT_BLKNO)			/* if root split we should put initial value */			oldnsn = PageGetLSN(dist->page);		for (ptr = dist; ptr; ptr = ptr->next)		{			/* only for last set oldnsn */			GistPageGetOpaque(ptr->page)->nsn = (ptr->next) ?				PageGetLSN(ptr->page) : oldnsn;		}		/*		 * release buffers, if it was a root split then release all buffers		 * because we create all buffers		 */		ptr = (state->stack->blkno == GIST_ROOT_BLKNO) ? dist : dist->next;		for (; ptr; ptr = ptr->next)			UnlockReleaseBuffer(ptr->buffer);		if (state->stack->blkno == GIST_ROOT_BLKNO)		{			gistnewroot(state->r, state->stack->buffer, state->itup, state->ituplen, &(state->key));			state->needInsertComplete = false;		}		END_CRIT_SECTION();	}	else	{		/* enough space */		START_CRIT_SECTION();		if (!is_leaf)			PageIndexTupleDelete(state->stack->page, state->stack->childoffnum);		gistfillbuffer(state->r, state->stack->page, state->itup, state->ituplen, InvalidOffsetNumber);		MarkBufferDirty(state->stack->buffer);		if (!state->r->rd_istemp)		{			OffsetNumber noffs = 0,						offs[1];			XLogRecPtr	recptr;			XLogRecData *rdata;			if (!is_leaf)			{				/* only on inner page we should delete previous version */				offs[0] = state->stack->childoffnum;				noffs = 1;			}			rdata = formUpdateRdata(state->r->rd_node, state->stack->buffer,									offs, noffs,									state->itup, state->ituplen,									&(state->key));			recptr = XLogInsert(RM_GIST_ID, XLOG_GIST_PAGE_UPDATE, rdata);			PageSetLSN(state->stack->page, recptr);			PageSetTLI(state->stack->page, ThisTimeLineID);		}		else			PageSetLSN(state->stack->page, XLogRecPtrForTemp);		if (state->stack->blkno == GIST_ROOT_BLKNO)			state->needInsertComplete = false;		END_CRIT_SECTION();		if (state->ituplen > 1)		{						/* previous is_splitted==true */			/*			 * child was splited, so we must form union for insertion in			 * parent			 */			IndexTuple	newtup = gistunion(state->r, state->itup, state->ituplen, giststate);			ItemPointerSetBlockNumber(&(newtup->t_tid), state->stack->blkno);			state->itup[0] = newtup;			state->ituplen = 1;		}		else if (is_leaf)		{			/*			 * itup[0] store key to adjust parent, we set it to valid to			 * correct check by GistTupleIsInvalid macro in gistgetadjusted()			 */			ItemPointerSetBlockNumber(&(state->itup[0]->t_tid), state->stack->blkno);			GistTupleSetValid(state->itup[0]);		}	}	return is_splitted;}/* * returns stack of pages, all pages in stack are pinned, and * leaf is X-locked */static voidgistfindleaf(GISTInsertState *state, GISTSTATE *giststate){	ItemId		iid;	IndexTuple	idxtuple;	GISTPageOpaque opaque;	/*	 * walk down, We don't lock page for a long time, but so we should be

⌨️ 快捷键说明

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