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

📄 nbtpage.c

📁 postgresql8.3.4源码,开源数据库
💻 C
📖 第 1 页 / 共 3 页
字号:
/*------------------------------------------------------------------------- * * nbtpage.c *	  BTree-specific page management code for the Postgres btree 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/nbtree/nbtpage.c,v 1.106 2008/01/01 19:45:46 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 "access/transam.h"#include "miscadmin.h"#include "storage/freespace.h"#include "storage/lmgr.h"#include "utils/inval.h"/* *	_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;	/*	 * Try to use previously-cached metapage data to find the root.  This	 * normally saves one buffer access per index search, which is a very	 * helpful savings in bufmgr traffic and hence contention.	 */	if (rel->rd_amcache != NULL)	{		metad = (BTMetaPageData *) rel->rd_amcache;		/* We shouldn't have cached it if any of these fail */		Assert(metad->btm_magic == BTREE_MAGIC);		Assert(metad->btm_version == BTREE_VERSION);		Assert(metad->btm_root != P_NONE);		rootblkno = metad->btm_fastroot;		Assert(rootblkno != P_NONE);		rootlevel = metad->btm_fastlevel;		rootbuf = _bt_getbuf(rel, rootblkno, BT_READ);		rootpage = BufferGetPage(rootbuf);		rootopaque = (BTPageOpaque) PageGetSpecialPointer(rootpage);		/*		 * Since the cache might be stale, we check the page more carefully		 * here than normal.  We *must* check that it's not deleted. If it's		 * not alone on its level, then we reject too --- this may be overly		 * paranoid but better safe than sorry.  Note we don't check P_ISROOT,		 * because that's not set in a "fast root".		 */		if (!P_IGNORE(rootopaque) &&			rootopaque->btpo.level == rootlevel &&			P_LEFTMOST(rootopaque) &&			P_RIGHTMOST(rootopaque))		{			/* OK, accept cached page as the root */			return rootbuf;		}		_bt_relbuf(rel, rootbuf);		/* Cache is stale, throw it away */		if (rel->rd_amcache)			pfree(rel->rd_amcache);		rel->rd_amcache = NULL;	}	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);		rootopaque = (BTPageOpaque) PageGetSpecialPointer(rootpage);		rootopaque->btpo_prev = rootopaque->btpo_next = P_NONE;		rootopaque->btpo_flags = (BTP_LEAF | BTP_ROOT);		rootopaque->btpo.level = 0;		rootopaque->btpo_cycleid = 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;		MarkBufferDirty(rootbuf);		MarkBufferDirty(metabuf);		/* 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();		/*		 * Send out relcache inval for metapage change (probably unnecessary		 * here, but let's be safe).		 */		CacheInvalidateRelcache(rel);		/*		 * 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, release lock on it */		_bt_relbuf(rel, metabuf);	}	else	{		rootblkno = metad->btm_fastroot;		Assert(rootblkno != P_NONE);		rootlevel = metad->btm_fastlevel;		/*		 * Cache the metapage data for next time		 */		rel->rd_amcache = MemoryContextAlloc(rel->rd_indexcxt,											 sizeof(BTMetaPageData));		memcpy(rel->rd_amcache, metad, sizeof(BTMetaPageData));		/*		 * 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 index \"%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 index \"%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;	/*	 * We don't try to use cached metapage data here, since (a) this path is	 * not performance-critical, and (b) if we are here it suggests our cache	 * is out-of-date anyway.  In light of point (b), it's probably safest to	 * actively flush any cached metapage info.	 */	if (rel->rd_amcache)		pfree(rel->rd_amcache);	rel->rd_amcache = NULL;	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	 */	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 index \"%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 index \"%s\" has level %u, expected %u",			 rootblkno, RelationGetRelationName(rel),			 rootopaque->btpo.level, rootlevel);	return rootbuf;}/* *	_bt_checkpage() -- Verify that a freshly-read page looks sane. */void_bt_checkpage(Relation rel, Buffer buf){	Page		page = BufferGetPage(buf);	/*	 * ReadBuffer verifies that every newly-read page passes	 * PageHeaderIsValid, which means it either contains a reasonably sane	 * page header or is all-zero.	We have to defend against the all-zero	 * case, however.	 */	if (PageIsNew(page))		ereport(ERROR,				(errcode(ERRCODE_INDEX_CORRUPTED),			 errmsg("index \"%s\" contains unexpected zero page at block %u",					RelationGetRelationName(rel),					BufferGetBlockNumber(buf)),				 errhint("Please REINDEX it.")));	/*	 * Additionally check that the special area looks sane.	 */	if (((PageHeader) (page))->pd_special !=		(BLCKSZ - MAXALIGN(sizeof(BTPageOpaqueData))))		ereport(ERROR,				(errcode(ERRCODE_INDEX_CORRUPTED),				 errmsg("index \"%s\" contains corrupted page at block %u",						RelationGetRelationName(rel),						BufferGetBlockNumber(buf)),

⌨️ 快捷键说明

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