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

📄 nbtpage.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 3 页
字号:
/*------------------------------------------------------------------------- * * nbtpage.c *	  BTree-specific page management code for the Postgres btree 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/nbtree/nbtpage.c,v 1.88.2.1 2005/11/22 18:23:04 momjian Exp $ * *	NOTES *	   Postgres btree pages look like ordinary relation pages.	The opaque *	   data at high addresses includes pointers to left and right siblings *	   and flag data describing page state.  The first page in a btree, page *	   zero, is special -- it stores meta-information describing the tree. *	   Pages one and higher store the actual tree data. * *------------------------------------------------------------------------- */#include "postgres.h"#include "access/nbtree.h"#include "miscadmin.h"#include "storage/freespace.h"#include "storage/lmgr.h"/* *	_bt_metapinit() -- Initialize the metadata page of a new btree. * * Note: this is actually not used for standard btree index building; * nbtsort.c prefers not to make the metadata page valid until completion * of build. * * Note: there's no real need for any locking here.  Since the transaction * creating the index hasn't committed yet, no one else can even see the index * much less be trying to use it.  (In a REINDEX-in-place scenario, that's * not true, but we assume the caller holds sufficient locks on the index.) */void_bt_metapinit(Relation rel){	Buffer		buf;	Page		pg;	BTMetaPageData *metad;	if (RelationGetNumberOfBlocks(rel) != 0)		elog(ERROR, "cannot initialize non-empty btree index \"%s\"",			 RelationGetRelationName(rel));	buf = ReadBuffer(rel, P_NEW);	Assert(BufferGetBlockNumber(buf) == BTREE_METAPAGE);	pg = BufferGetPage(buf);	_bt_initmetapage(pg, P_NONE, 0);	metad = BTPageGetMeta(pg);	/* NO ELOG(ERROR) from here till newmeta op is logged */	START_CRIT_SECTION();	/* XLOG stuff */	if (!rel->rd_istemp)	{		xl_btree_newmeta xlrec;		XLogRecPtr	recptr;		XLogRecData rdata[1];		xlrec.node = rel->rd_node;		xlrec.meta.root = metad->btm_root;		xlrec.meta.level = metad->btm_level;		xlrec.meta.fastroot = metad->btm_fastroot;		xlrec.meta.fastlevel = metad->btm_fastlevel;		rdata[0].data = (char *) &xlrec;		rdata[0].len = SizeOfBtreeNewmeta;		rdata[0].buffer = InvalidBuffer;		rdata[0].next = NULL;		recptr = XLogInsert(RM_BTREE_ID,							XLOG_BTREE_NEWMETA,							rdata);		PageSetLSN(pg, recptr);		PageSetTLI(pg, ThisTimeLineID);	}	END_CRIT_SECTION();	WriteBuffer(buf);}/* *	_bt_initmetapage() -- Fill a page buffer with a correct metapage image */void_bt_initmetapage(Page page, BlockNumber rootbknum, uint32 level){	BTMetaPageData *metad;	BTPageOpaque metaopaque;	_bt_pageinit(page, BLCKSZ);	metad = BTPageGetMeta(page);	metad->btm_magic = BTREE_MAGIC;	metad->btm_version = BTREE_VERSION;	metad->btm_root = rootbknum;	metad->btm_level = level;	metad->btm_fastroot = rootbknum;	metad->btm_fastlevel = level;	metaopaque = (BTPageOpaque) PageGetSpecialPointer(page);	metaopaque->btpo_flags = BTP_META;	/*	 * Set pd_lower just past the end of the metadata.	This is not essential	 * but it makes the page look compressible to xlog.c.	 */	((PageHeader) page)->pd_lower =		((char *) metad + sizeof(BTMetaPageData)) - (char *) page;}/* *	_bt_getroot() -- Get the root page of the btree. * *		Since the root page can move around the btree file, we have to read *		its location from the metadata page, and then read the root page *		itself.  If no root page exists yet, we have to create one.  The *		standard class of race conditions exists here; I think I covered *		them all in the Hopi Indian rain dance of lock requests below. * *		The access type parameter (BT_READ or BT_WRITE) controls whether *		a new root page will be created or not.  If access = BT_READ, *		and no root page exists, we just return InvalidBuffer.	For *		BT_WRITE, we try to create the root page if it doesn't exist. *		NOTE that the returned root page will have only a read lock set *		on it even if access = BT_WRITE! * *		The returned page is not necessarily the true root --- it could be *		a "fast root" (a page that is alone in its level due to deletions). *		Also, if the root page is split while we are "in flight" to it, *		what we will return is the old root, which is now just the leftmost *		page on a probably-not-very-wide level.  For most purposes this is *		as good as or better than the true root, so we do not bother to *		insist on finding the true root.  We do, however, guarantee to *		return a live (not deleted or half-dead) page. * *		On successful return, the root page is pinned and read-locked. *		The metadata page is not locked or pinned on exit. */Buffer_bt_getroot(Relation rel, int access){	Buffer		metabuf;	Page		metapg;	BTPageOpaque metaopaque;	Buffer		rootbuf;	Page		rootpage;	BTPageOpaque rootopaque;	BlockNumber rootblkno;	uint32		rootlevel;	BTMetaPageData *metad;	metabuf = _bt_getbuf(rel, BTREE_METAPAGE, BT_READ);	metapg = BufferGetPage(metabuf);	metaopaque = (BTPageOpaque) PageGetSpecialPointer(metapg);	metad = BTPageGetMeta(metapg);	/* sanity-check the metapage */	if (!(metaopaque->btpo_flags & BTP_META) ||		metad->btm_magic != BTREE_MAGIC)		ereport(ERROR,				(errcode(ERRCODE_INDEX_CORRUPTED),				 errmsg("index \"%s\" is not a btree",						RelationGetRelationName(rel))));	if (metad->btm_version != BTREE_VERSION)		ereport(ERROR,				(errcode(ERRCODE_INDEX_CORRUPTED),				 errmsg("version mismatch in index \"%s\": file version %d, code version %d",						RelationGetRelationName(rel),						metad->btm_version, BTREE_VERSION)));	/* if no root page initialized yet, do it */	if (metad->btm_root == P_NONE)	{		/* If access = BT_READ, caller doesn't want us to create root yet */		if (access == BT_READ)		{			_bt_relbuf(rel, metabuf);			return InvalidBuffer;		}		/* trade in our read lock for a write lock */		LockBuffer(metabuf, BUFFER_LOCK_UNLOCK);		LockBuffer(metabuf, BT_WRITE);		/*		 * Race condition:	if someone else initialized the metadata between		 * the time we released the read lock and acquired the write lock, we		 * must avoid doing it again.		 */		if (metad->btm_root != P_NONE)		{			/*			 * Metadata initialized by someone else.  In order to guarantee no			 * deadlocks, we have to release the metadata page and start all			 * over again.	(Is that really true? But it's hardly worth trying			 * to optimize this case.)			 */			_bt_relbuf(rel, metabuf);			return _bt_getroot(rel, access);		}		/*		 * Get, initialize, write, and leave a lock of the appropriate type on		 * the new root page.  Since this is the first page in the tree, it's		 * a leaf as well as the root.		 */		rootbuf = _bt_getbuf(rel, P_NEW, BT_WRITE);		rootblkno = BufferGetBlockNumber(rootbuf);		rootpage = BufferGetPage(rootbuf);		_bt_pageinit(rootpage, BufferGetPageSize(rootbuf));		rootopaque = (BTPageOpaque) PageGetSpecialPointer(rootpage);		rootopaque->btpo_prev = rootopaque->btpo_next = P_NONE;		rootopaque->btpo_flags = (BTP_LEAF | BTP_ROOT);		rootopaque->btpo.level = 0;		/* NO ELOG(ERROR) till meta is updated */		START_CRIT_SECTION();		metad->btm_root = rootblkno;		metad->btm_level = 0;		metad->btm_fastroot = rootblkno;		metad->btm_fastlevel = 0;		/* XLOG stuff */		if (!rel->rd_istemp)		{			xl_btree_newroot xlrec;			XLogRecPtr	recptr;			XLogRecData rdata;			xlrec.node = rel->rd_node;			xlrec.rootblk = rootblkno;			xlrec.level = 0;			rdata.data = (char *) &xlrec;			rdata.len = SizeOfBtreeNewroot;			rdata.buffer = InvalidBuffer;			rdata.next = NULL;			recptr = XLogInsert(RM_BTREE_ID, XLOG_BTREE_NEWROOT, &rdata);			PageSetLSN(rootpage, recptr);			PageSetTLI(rootpage, ThisTimeLineID);			PageSetLSN(metapg, recptr);			PageSetTLI(metapg, ThisTimeLineID);		}		END_CRIT_SECTION();		_bt_wrtnorelbuf(rel, rootbuf);		/*		 * swap root write lock for read lock.	There is no danger of anyone		 * else accessing the new root page while it's unlocked, since no one		 * else knows where it is yet.		 */		LockBuffer(rootbuf, BUFFER_LOCK_UNLOCK);		LockBuffer(rootbuf, BT_READ);		/* okay, metadata is correct, write and release it */		_bt_wrtbuf(rel, metabuf);	}	else	{		rootblkno = metad->btm_fastroot;		Assert(rootblkno != P_NONE);		rootlevel = metad->btm_fastlevel;		/*		 * We are done with the metapage; arrange to release it via first		 * _bt_relandgetbuf call		 */		rootbuf = metabuf;		for (;;)		{			rootbuf = _bt_relandgetbuf(rel, rootbuf, rootblkno, BT_READ);			rootpage = BufferGetPage(rootbuf);			rootopaque = (BTPageOpaque) PageGetSpecialPointer(rootpage);			if (!P_IGNORE(rootopaque))				break;			/* it's dead, Jim.  step right one page */			if (P_RIGHTMOST(rootopaque))				elog(ERROR, "no live root page found in \"%s\"",					 RelationGetRelationName(rel));			rootblkno = rootopaque->btpo_next;		}		/* Note: can't check btpo.level on deleted pages */		if (rootopaque->btpo.level != rootlevel)			elog(ERROR, "root page %u of \"%s\" has level %u, expected %u",				 rootblkno, RelationGetRelationName(rel),				 rootopaque->btpo.level, rootlevel);	}	/*	 * By here, we have a pin and read lock on the root page, and no lock set	 * on the metadata page.  Return the root page's buffer.	 */	return rootbuf;}/* *	_bt_gettrueroot() -- Get the true root page of the btree. * *		This is the same as the BT_READ case of _bt_getroot(), except *		we follow the true-root link not the fast-root link. * * By the time we acquire lock on the root page, it might have been split and * not be the true root anymore.  This is okay for the present uses of this * routine; we only really need to be able to move up at least one tree level * from whatever non-root page we were at.	If we ever do need to lock the * one true root page, we could loop here, re-reading the metapage on each * failure.  (Note that it wouldn't do to hold the lock on the metapage while * moving to the root --- that'd deadlock against any concurrent root split.) */Buffer_bt_gettrueroot(Relation rel){	Buffer		metabuf;	Page		metapg;	BTPageOpaque metaopaque;	Buffer		rootbuf;	Page		rootpage;	BTPageOpaque rootopaque;	BlockNumber rootblkno;	uint32		rootlevel;	BTMetaPageData *metad;	metabuf = _bt_getbuf(rel, BTREE_METAPAGE, BT_READ);	metapg = BufferGetPage(metabuf);	metaopaque = (BTPageOpaque) PageGetSpecialPointer(metapg);	metad = BTPageGetMeta(metapg);	if (!(metaopaque->btpo_flags & BTP_META) ||		metad->btm_magic != BTREE_MAGIC)		ereport(ERROR,				(errcode(ERRCODE_INDEX_CORRUPTED),				 errmsg("index \"%s\" is not a btree",						RelationGetRelationName(rel))));	if (metad->btm_version != BTREE_VERSION)		ereport(ERROR,				(errcode(ERRCODE_INDEX_CORRUPTED),				 errmsg("version mismatch in index \"%s\": file version %d, code version %d",						RelationGetRelationName(rel),						metad->btm_version, BTREE_VERSION)));	/* if no root page initialized yet, fail */	if (metad->btm_root == P_NONE)	{		_bt_relbuf(rel, metabuf);		return InvalidBuffer;	}	rootblkno = metad->btm_root;	rootlevel = metad->btm_level;	/*	 * We are done with the metapage; arrange to release it via first	 * _bt_relandgetbuf call	 */

⌨️ 快捷键说明

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