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

📄 gist.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 3 页
字号:
/*------------------------------------------------------------------------- * * gist.c *	  interface routines for the postgres GiST index access method. * * * Portions Copyright (c) 1996-2005, 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.127 2005/10/18 01:06:22 tgl Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#include "access/genam.h"#include "access/gist_private.h"#include "access/gistscan.h"#include "access/heapam.h"#include "catalog/index.h"#include "commands/vacuum.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,			 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->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);	double		reltuples;	GISTBuildState buildstate;	Buffer		buffer;	/*	 * 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);	GISTInitBuffer(buffer, F_LEAF);	if (!index->rd_istemp)	{		XLogRecPtr	recptr;		XLogRecData rdata;		Page		page;		rdata.buffer = InvalidBuffer;		rdata.data = (char *) &(index->rd_node);		rdata.len = sizeof(RelFileNode);		rdata.next = NULL;		page = BufferGetPage(buffer);		START_CRIT_SECTION();		recptr = XLogInsert(RM_GIST_ID, XLOG_GIST_CREATE_INDEX, &rdata);		PageSetLSN(page, recptr);		PageSetTLI(page, ThisTimeLineID);		END_CRIT_SECTION();	}	else		PageSetLSN(BufferGetPage(buffer), XLogRecPtrForTemp);	LockBuffer(buffer, GIST_UNLOCK);	WriteBuffer(buffer);	/* 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);	/* since we just counted the # of tuples, may as well update stats */	IndexCloseAndUpdateStats(heap, reltuples, index, buildstate.indtuples);	freeGISTstate(&buildstate.giststate);	PG_RETURN_VOID();}/* * 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;	GISTENTRY	tmpcentry;	int			i;	MemoryContext oldCtx;	/* GiST cannot index tuples with leading NULLs */	if (isnull[0])		return;	oldCtx = MemoryContextSwitchTo(buildstate->tmpCtx);	/* immediately compress keys to normalize */	for (i = 0; i < buildstate->numindexattrs; i++)	{		if (isnull[i])			values[i] = (Datum) 0;		else		{			gistcentryinit(&buildstate->giststate, i, &tmpcentry, values[i],						   NULL, NULL, (OffsetNumber) 0,						   -1 /* size is currently bogus */ , TRUE, FALSE);			values[i] = tmpcentry.key;		}	}	/* form an index tuple and point it at the heap tuple */	itup = index_form_tuple(buildstate->giststate.tupdesc, values, isnull);	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.	 */	gistdoinsert(index, itup, &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;	GISTENTRY	tmpentry;	int			i;	MemoryContext oldCtx;	MemoryContext insertCtx;	/* GiST cannot index tuples with leading NULLs */	if (isnull[0])		PG_RETURN_BOOL(false);	insertCtx = createTempGistContext();	oldCtx = MemoryContextSwitchTo(insertCtx);	initGISTstate(&giststate, r);	/* immediately compress keys to normalize */	for (i = 0; i < r->rd_att->natts; i++)	{		if (isnull[i])			values[i] = (Datum) 0;		else		{			gistcentryinit(&giststate, i, &tmpentry, values[i],						   NULL, NULL, (OffsetNumber) 0,						   -1 /* size is currently bogus */ , TRUE, FALSE);			values[i] = tmpentry.key;		}	}	itup = index_form_tuple(giststate.tupdesc, values, isnull);	itup->t_tid = *ht_ctid;	gistdoinsert(r, itup, &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, 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.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)		/*		 * 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.		 */		PageIndexTupleDelete(state->stack->page, state->stack->childoffnum);	if (gistnospace(state->stack->page, state->itup, state->ituplen))	{		/* no space for insertion */		IndexTuple *itvec,				   *newitup;		int			tlen;		SplitedPageLayout *dist = NULL,				   *ptr;		is_splitted = true;		itvec = gistextractbuffer(state->stack->buffer, &tlen);		itvec = gistjoinvector(itvec, &tlen, state->itup, state->ituplen);		newitup = gistSplit(state->r, state->stack->buffer, itvec, &tlen, &dist, giststate);		if (!state->r->rd_istemp)		{			XLogRecPtr	recptr;			XLogRecData *rdata;			rdata = formSplitRdata(state->r->rd_node, state->stack->blkno,								   &(state->key), dist);			START_CRIT_SECTION();			recptr = XLogInsert(RM_GIST_ID, XLOG_GIST_PAGE_SPLIT, rdata);			ptr = dist;			while (ptr)			{				PageSetLSN(BufferGetPage(ptr->buffer), recptr);				PageSetTLI(BufferGetPage(ptr->buffer), ThisTimeLineID);				ptr = ptr->next;			}			END_CRIT_SECTION();		}		else		{			ptr = dist;			while (ptr)			{				PageSetLSN(BufferGetPage(ptr->buffer), XLogRecPtrForTemp);				ptr = ptr->next;			}		}		state->itup = newitup;		state->ituplen = tlen;	/* now tlen >= 2 */		if (state->stack->blkno == GIST_ROOT_BLKNO)		{			gistnewroot(state->r, state->stack->buffer, state->itup, state->ituplen, &(state->key));			state->needInsertComplete = false;			ptr = dist;			while (ptr)			{				Page		page = (Page) BufferGetPage(ptr->buffer);				GistPageGetOpaque(page)->rightlink = (ptr->next) ?					ptr->next->block.blkno : InvalidBlockNumber;				GistPageGetOpaque(page)->nsn = PageGetLSN(page);				LockBuffer(ptr->buffer, GIST_UNLOCK);				WriteBuffer(ptr->buffer);				ptr = ptr->next;			}		}		else		{			Page		page;			BlockNumber rightrightlink = InvalidBlockNumber;			SplitedPageLayout *ourpage = NULL;			GistNSN		oldnsn;			GISTPageOpaque opaque;			/* move origpage to first in chain */			if (dist->block.blkno != state->stack->blkno)			{				ptr = dist;				while (ptr->next)				{					if (ptr->next->block.blkno == state->stack->blkno)					{						ourpage = ptr->next;						ptr->next = ptr->next->next;						ourpage->next = dist;						dist = ourpage;						break;					}					ptr = ptr->next;				}				Assert(ourpage != NULL);			}			else				ourpage = dist;			/* now gets all needed data, and sets nsn's */			page = (Page) BufferGetPage(ourpage->buffer);			opaque = GistPageGetOpaque(page);			rightrightlink = opaque->rightlink;			oldnsn = opaque->nsn;

⌨️ 快捷键说明

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