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

📄 gist.c

📁 postgresql8.3.4源码,开源数据库
💻 C
📖 第 1 页 / 共 2 页
字号:
	 * ready to recheck path in a bad case... We remember, that page->lsn	 * should never be invalid.	 */	for (;;)	{		if (XLogRecPtrIsInvalid(state->stack->lsn))			state->stack->buffer = ReadBuffer(state->r, state->stack->blkno);		LockBuffer(state->stack->buffer, GIST_SHARE);		gistcheckpage(state->r, state->stack->buffer);		state->stack->page = (Page) BufferGetPage(state->stack->buffer);		opaque = GistPageGetOpaque(state->stack->page);		state->stack->lsn = PageGetLSN(state->stack->page);		Assert(state->r->rd_istemp || !XLogRecPtrIsInvalid(state->stack->lsn));		if (state->stack->blkno != GIST_ROOT_BLKNO &&			XLByteLT(state->stack->parent->lsn, opaque->nsn))		{			/*			 * caused split non-root page is detected, go up to parent to			 * choose best child			 */			UnlockReleaseBuffer(state->stack->buffer);			state->stack = state->stack->parent;			continue;		}		if (!GistPageIsLeaf(state->stack->page))		{			/*			 * This is an internal page, so continue to walk down the tree. We			 * find the child node that has the minimum insertion penalty and			 * recursively invoke ourselves to modify that node. Once the			 * recursive call returns, we may need to adjust the parent node			 * for two reasons: the child node split, or the key in this node			 * needs to be adjusted for the newly inserted key below us.			 */			GISTInsertStack *item = (GISTInsertStack *) palloc0(sizeof(GISTInsertStack));			state->stack->childoffnum = gistchoose(state->r, state->stack->page, state->itup[0], giststate);			iid = PageGetItemId(state->stack->page, state->stack->childoffnum);			idxtuple = (IndexTuple) PageGetItem(state->stack->page, iid);			item->blkno = ItemPointerGetBlockNumber(&(idxtuple->t_tid));			LockBuffer(state->stack->buffer, GIST_UNLOCK);			item->parent = state->stack;			item->child = NULL;			if (state->stack)				state->stack->child = item;			state->stack = item;		}		else		{			/* be carefull, during unlock/lock page may be changed... */			LockBuffer(state->stack->buffer, GIST_UNLOCK);			LockBuffer(state->stack->buffer, GIST_EXCLUSIVE);			state->stack->page = (Page) BufferGetPage(state->stack->buffer);			opaque = GistPageGetOpaque(state->stack->page);			if (state->stack->blkno == GIST_ROOT_BLKNO)			{				/*				 * the only page can become inner instead of leaf is a root				 * page, so for root we should recheck it				 */				if (!GistPageIsLeaf(state->stack->page))				{					/*					 * very rarely situation: during unlock/lock index with					 * number of pages = 1 was increased					 */					LockBuffer(state->stack->buffer, GIST_UNLOCK);					continue;				}				/*				 * we don't need to check root split, because checking				 * leaf/inner is enough to recognize split for root				 */			}			else if (XLByteLT(state->stack->parent->lsn, opaque->nsn))			{				/*				 * detecting split during unlock/lock, so we should find				 * better child on parent				 */				/* forget buffer */				UnlockReleaseBuffer(state->stack->buffer);				state->stack = state->stack->parent;				continue;			}			state->stack->lsn = PageGetLSN(state->stack->page);			/* ok we found a leaf page and it X-locked */			break;		}	}	/* now state->stack->(page, buffer and blkno) points to leaf page */}/* * Traverse the tree to find path from root page to specified "child" block. * * returns from the beginning of closest parent; * * To prevent deadlocks, this should lock only one page simultaneously. */GISTInsertStack *gistFindPath(Relation r, BlockNumber child){	Page		page;	Buffer		buffer;	OffsetNumber i,				maxoff;	ItemId		iid;	IndexTuple	idxtuple;	GISTInsertStack *top,			   *tail,			   *ptr;	BlockNumber blkno;	top = tail = (GISTInsertStack *) palloc0(sizeof(GISTInsertStack));	top->blkno = GIST_ROOT_BLKNO;	while (top && top->blkno != child)	{		buffer = ReadBuffer(r, top->blkno);		LockBuffer(buffer, GIST_SHARE);		gistcheckpage(r, buffer);		page = (Page) BufferGetPage(buffer);		if (GistPageIsLeaf(page))		{			/* we can safety go away, follows only leaf pages */			UnlockReleaseBuffer(buffer);			return NULL;		}		top->lsn = PageGetLSN(page);		if (top->parent && XLByteLT(top->parent->lsn, GistPageGetOpaque(page)->nsn) &&			GistPageGetOpaque(page)->rightlink != InvalidBlockNumber /* sanity check */ )		{			/* page splited while we thinking of... */			ptr = (GISTInsertStack *) palloc0(sizeof(GISTInsertStack));			ptr->blkno = GistPageGetOpaque(page)->rightlink;			ptr->childoffnum = InvalidOffsetNumber;			ptr->parent = top;			ptr->next = NULL;			tail->next = ptr;			tail = ptr;		}		maxoff = PageGetMaxOffsetNumber(page);		for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))		{			iid = PageGetItemId(page, i);			idxtuple = (IndexTuple) PageGetItem(page, iid);			blkno = ItemPointerGetBlockNumber(&(idxtuple->t_tid));			if (blkno == child)			{				OffsetNumber poff = InvalidOffsetNumber;				/* make childs links */				ptr = top;				while (ptr->parent)				{					/* set child link */					ptr->parent->child = ptr;					/* move childoffnum.. */					if (ptr == top)					{						/* first iteration */						poff = ptr->parent->childoffnum;						ptr->parent->childoffnum = ptr->childoffnum;					}					else					{						OffsetNumber tmp = ptr->parent->childoffnum;						ptr->parent->childoffnum = poff;						poff = tmp;					}					ptr = ptr->parent;				}				top->childoffnum = i;				UnlockReleaseBuffer(buffer);				return top;			}			else			{				/* Install next inner page to the end of stack */				ptr = (GISTInsertStack *) palloc0(sizeof(GISTInsertStack));				ptr->blkno = blkno;				ptr->childoffnum = i;	/* set offsetnumber of child to child										 * !!! */				ptr->parent = top;				ptr->next = NULL;				tail->next = ptr;				tail = ptr;			}		}		UnlockReleaseBuffer(buffer);		top = top->next;	}	return NULL;}/* * Returns X-locked parent of stack page */static voidgistFindCorrectParent(Relation r, GISTInsertStack *child){	GISTInsertStack *parent = child->parent;	LockBuffer(parent->buffer, GIST_EXCLUSIVE);	gistcheckpage(r, parent->buffer);	parent->page = (Page) BufferGetPage(parent->buffer);	/* here we don't need to distinguish between split and page update */	if (parent->childoffnum == InvalidOffsetNumber || !XLByteEQ(parent->lsn, PageGetLSN(parent->page)))	{		/* parent is changed, look child in right links until found */		OffsetNumber i,					maxoff;		ItemId		iid;		IndexTuple	idxtuple;		GISTInsertStack *ptr;		while (true)		{			maxoff = PageGetMaxOffsetNumber(parent->page);			for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))			{				iid = PageGetItemId(parent->page, i);				idxtuple = (IndexTuple) PageGetItem(parent->page, iid);				if (ItemPointerGetBlockNumber(&(idxtuple->t_tid)) == child->blkno)				{					/* yes!!, found */					parent->childoffnum = i;					return;				}			}			parent->blkno = GistPageGetOpaque(parent->page)->rightlink;			UnlockReleaseBuffer(parent->buffer);			if (parent->blkno == InvalidBlockNumber)				/*				 * end of chain and still didn't found parent, It's very-very				 * rare situation when root splited				 */				break;			parent->buffer = ReadBuffer(r, parent->blkno);			LockBuffer(parent->buffer, GIST_EXCLUSIVE);			gistcheckpage(r, parent->buffer);			parent->page = (Page) BufferGetPage(parent->buffer);		}		/*		 * awful!!, we need search tree to find parent ... , but before we		 * should release all old parent		 */		ptr = child->parent->parent;	/* child->parent already released										 * above */		while (ptr)		{			ReleaseBuffer(ptr->buffer);			ptr = ptr->parent;		}		/* ok, find new path */		ptr = parent = gistFindPath(r, child->blkno);		Assert(ptr != NULL);		/* read all buffers as expected by caller */		/* note we don't lock them or gistcheckpage them here! */		while (ptr)		{			ptr->buffer = ReadBuffer(r, ptr->blkno);			ptr->page = (Page) BufferGetPage(ptr->buffer);			ptr = ptr->parent;		}		/* install new chain of parents to stack */		child->parent = parent;		parent->child = child;		/* make recursive call to normal processing */		gistFindCorrectParent(r, child);	}	return;}voidgistmakedeal(GISTInsertState *state, GISTSTATE *giststate){	int			is_splitted;	ItemId		iid;	IndexTuple	oldtup,				newtup;	/* walk up */	while (true)	{		/*		 * After this call: 1. if child page was splited, then itup contains		 * keys for each page 2. if  child page wasn't splited, then itup		 * contains additional for adjustment of current key		 */		if (state->stack->parent)		{			/*			 * X-lock parent page before proceed child, gistFindCorrectParent			 * should find and lock it			 */			gistFindCorrectParent(state->r, state->stack);		}		is_splitted = gistplacetopage(state, giststate);		/* parent locked above, so release child buffer */		UnlockReleaseBuffer(state->stack->buffer);		/* pop parent page from stack */		state->stack = state->stack->parent;		/* stack is void */		if (!state->stack)			break;		/*		 * child did not split, so we can check is it needed to update parent		 * tuple		 */		if (!is_splitted)		{			/* parent's tuple */			iid = PageGetItemId(state->stack->page, state->stack->childoffnum);			oldtup = (IndexTuple) PageGetItem(state->stack->page, iid);			newtup = gistgetadjusted(state->r, oldtup, state->itup[0], giststate);			if (!newtup)			{					/* not need to update key */				LockBuffer(state->stack->buffer, GIST_UNLOCK);				break;			}			state->itup[0] = newtup;		}	}							/* while */	/* release all parent buffers */	while (state->stack)	{		ReleaseBuffer(state->stack->buffer);		state->stack = state->stack->parent;	}	/* say to xlog that insert is completed */	if (state->needInsertComplete && !state->r->rd_istemp)		gistxlogInsertCompletion(state->r->rd_node, &(state->key), 1);}/* * gistSplit -- split a page in the tree and fill struct * used for XLOG and real writes buffers. Function is recursive, ie * it will split page until keys will fit in every page. */SplitedPageLayout *gistSplit(Relation r,		  Page page,		  IndexTuple *itup,		/* contains compressed entry */		  int len,		  GISTSTATE *giststate){	IndexTuple *lvectup,			   *rvectup;	GistSplitVector v;	GistEntryVector *entryvec;	int			i;	SplitedPageLayout *res = NULL;	/* generate the item array */	entryvec = palloc(GEVHDRSZ + (len + 1) * sizeof(GISTENTRY));	entryvec->n = len + 1;	memset(v.spl_lisnull, TRUE, sizeof(bool) * giststate->tupdesc->natts);	memset(v.spl_risnull, TRUE, sizeof(bool) * giststate->tupdesc->natts);	gistSplitByKey(r, page, itup, len, giststate,				   &v, entryvec, 0);	/* form left and right vector */	lvectup = (IndexTuple *) palloc(sizeof(IndexTuple) * (len + 1));	rvectup = (IndexTuple *) palloc(sizeof(IndexTuple) * (len + 1));	for (i = 0; i < v.splitVector.spl_nleft; i++)		lvectup[i] = itup[v.splitVector.spl_left[i] - 1];	for (i = 0; i < v.splitVector.spl_nright; i++)		rvectup[i] = itup[v.splitVector.spl_right[i] - 1];	/* finalize splitting (may need another split) */	if (!gistfitpage(rvectup, v.splitVector.spl_nright))	{		res = gistSplit(r, page, rvectup, v.splitVector.spl_nright, giststate);	}	else	{		ROTATEDIST(res);		res->block.num = v.splitVector.spl_nright;		res->list = gistfillitupvec(rvectup, v.splitVector.spl_nright, &(res->lenlist));		res->itup = (v.spl_rightvalid) ? gistFormTuple(giststate, r, v.spl_rattr, v.spl_risnull, false)			: gist_form_invalid_tuple(GIST_ROOT_BLKNO);	}	if (!gistfitpage(lvectup, v.splitVector.spl_nleft))	{		SplitedPageLayout *resptr,				   *subres;		resptr = subres = gistSplit(r, page, lvectup, v.splitVector.spl_nleft, giststate);		/* install on list's tail */		while (resptr->next)			resptr = resptr->next;		resptr->next = res;		res = subres;	}	else	{		ROTATEDIST(res);		res->block.num = v.splitVector.spl_nleft;		res->list = gistfillitupvec(lvectup, v.splitVector.spl_nleft, &(res->lenlist));		res->itup = (v.spl_leftvalid) ? gistFormTuple(giststate, r, v.spl_lattr, v.spl_lisnull, false)			: gist_form_invalid_tuple(GIST_ROOT_BLKNO);	}	return res;}/* * buffer must be pinned and locked by caller */voidgistnewroot(Relation r, Buffer buffer, IndexTuple *itup, int len, ItemPointer key){	Page		page;	Assert(BufferGetBlockNumber(buffer) == GIST_ROOT_BLKNO);	page = BufferGetPage(buffer);	START_CRIT_SECTION();	GISTInitBuffer(buffer, 0);	gistfillbuffer(r, page, itup, len, FirstOffsetNumber);	MarkBufferDirty(buffer);	if (!r->rd_istemp)	{		XLogRecPtr	recptr;		XLogRecData *rdata;		rdata = formUpdateRdata(r->rd_node, buffer,								NULL, 0,								itup, len, key);		recptr = XLogInsert(RM_GIST_ID, XLOG_GIST_NEW_ROOT, rdata);		PageSetLSN(page, recptr);		PageSetTLI(page, ThisTimeLineID);	}	else		PageSetLSN(page, XLogRecPtrForTemp);	END_CRIT_SECTION();}voidinitGISTstate(GISTSTATE *giststate, Relation index){	int			i;	if (index->rd_att->natts > INDEX_MAX_KEYS)		elog(ERROR, "numberOfAttributes %d > %d",			 index->rd_att->natts, INDEX_MAX_KEYS);	giststate->tupdesc = index->rd_att;	for (i = 0; i < index->rd_att->natts; i++)	{		fmgr_info_copy(&(giststate->consistentFn[i]),					   index_getprocinfo(index, i + 1, GIST_CONSISTENT_PROC),					   CurrentMemoryContext);		fmgr_info_copy(&(giststate->unionFn[i]),					   index_getprocinfo(index, i + 1, GIST_UNION_PROC),					   CurrentMemoryContext);		fmgr_info_copy(&(giststate->compressFn[i]),					   index_getprocinfo(index, i + 1, GIST_COMPRESS_PROC),					   CurrentMemoryContext);		fmgr_info_copy(&(giststate->decompressFn[i]),					   index_getprocinfo(index, i + 1, GIST_DECOMPRESS_PROC),					   CurrentMemoryContext);		fmgr_info_copy(&(giststate->penaltyFn[i]),					   index_getprocinfo(index, i + 1, GIST_PENALTY_PROC),					   CurrentMemoryContext);		fmgr_info_copy(&(giststate->picksplitFn[i]),					   index_getprocinfo(index, i + 1, GIST_PICKSPLIT_PROC),					   CurrentMemoryContext);		fmgr_info_copy(&(giststate->equalFn[i]),					   index_getprocinfo(index, i + 1, GIST_EQUAL_PROC),					   CurrentMemoryContext);	}}voidfreeGISTstate(GISTSTATE *giststate){	/* no work */}

⌨️ 快捷键说明

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