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

📄 hashovfl.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 2 页
字号:
/*------------------------------------------------------------------------- * * hashovfl.c *	  Overflow page management code for the Postgres hash 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/hash/hashovfl.c,v 1.47.2.1 2005/11/22 18:23:03 momjian Exp $ * * NOTES *	  Overflow pages look like ordinary relation pages. * *------------------------------------------------------------------------- */#include "postgres.h"#include "access/hash.h"static BlockNumber _hash_getovflpage(Relation rel, Buffer metabuf);static uint32 _hash_firstfreebit(uint32 map);/* * Convert overflow page bit number (its index in the free-page bitmaps) * to block number within the index. */static BlockNumberbitno_to_blkno(HashMetaPage metap, uint32 ovflbitnum){	uint32		splitnum = metap->hashm_ovflpoint;	uint32		i;	/* Convert zero-based bitnumber to 1-based page number */	ovflbitnum += 1;	/* Determine the split number for this page (must be >= 1) */	for (i = 1;		 i < splitnum && ovflbitnum > metap->hashm_spares[i];		 i++)		 /* loop */ ;	/*	 * Convert to absolute page number by adding the number of bucket pages	 * that exist before this split point.	 */	return (BlockNumber) ((1 << i) + ovflbitnum);}/* * Convert overflow page block number to bit number for free-page bitmap. */static uint32blkno_to_bitno(HashMetaPage metap, BlockNumber ovflblkno){	uint32		splitnum = metap->hashm_ovflpoint;	uint32		i;	uint32		bitnum;	/* Determine the split number containing this page */	for (i = 1; i <= splitnum; i++)	{		if (ovflblkno <= (BlockNumber) (1 << i))			break;				/* oops */		bitnum = ovflblkno - (1 << i);		if (bitnum <= metap->hashm_spares[i])			return bitnum - 1;	/* -1 to convert 1-based to 0-based */	}	elog(ERROR, "invalid overflow block number %u", ovflblkno);	return 0;					/* keep compiler quiet */}/* *	_hash_addovflpage * *	Add an overflow page to the bucket whose last page is pointed to by 'buf'. * *	On entry, the caller must hold a pin but no lock on 'buf'.	The pin is *	dropped before exiting (we assume the caller is not interested in 'buf' *	anymore).  The returned overflow page will be pinned and write-locked; *	it is guaranteed to be empty. * *	The caller must hold a pin, but no lock, on the metapage buffer. *	That buffer is returned in the same state. * *	The caller must hold at least share lock on the bucket, to ensure that *	no one else tries to compact the bucket meanwhile.	This guarantees that *	'buf' won't stop being part of the bucket while it's unlocked. * * NB: since this could be executed concurrently by multiple processes, * one should not assume that the returned overflow page will be the * immediate successor of the originally passed 'buf'.	Additional overflow * pages might have been added to the bucket chain in between. */Buffer_hash_addovflpage(Relation rel, Buffer metabuf, Buffer buf){	BlockNumber ovflblkno;	Buffer		ovflbuf;	Page		page;	Page		ovflpage;	HashPageOpaque pageopaque;	HashPageOpaque ovflopaque;	/* allocate an empty overflow page */	ovflblkno = _hash_getovflpage(rel, metabuf);	/* lock the overflow page */	ovflbuf = _hash_getbuf(rel, ovflblkno, HASH_WRITE);	ovflpage = BufferGetPage(ovflbuf);	/*	 * Write-lock the tail page.  It is okay to hold two buffer locks here	 * since there cannot be anyone else contending for access to ovflbuf.	 */	_hash_chgbufaccess(rel, buf, HASH_NOLOCK, HASH_WRITE);	/* loop to find current tail page, in case someone else inserted too */	for (;;)	{		BlockNumber nextblkno;		page = BufferGetPage(buf);		_hash_checkpage(rel, page, LH_BUCKET_PAGE | LH_OVERFLOW_PAGE);		pageopaque = (HashPageOpaque) PageGetSpecialPointer(page);		nextblkno = pageopaque->hasho_nextblkno;		if (!BlockNumberIsValid(nextblkno))			break;		/* we assume we do not need to write the unmodified page */		_hash_relbuf(rel, buf);		buf = _hash_getbuf(rel, nextblkno, HASH_WRITE);	}	/* now that we have correct backlink, initialize new overflow page */	_hash_pageinit(ovflpage, BufferGetPageSize(ovflbuf));	ovflopaque = (HashPageOpaque) PageGetSpecialPointer(ovflpage);	ovflopaque->hasho_prevblkno = BufferGetBlockNumber(buf);	ovflopaque->hasho_nextblkno = InvalidBlockNumber;	ovflopaque->hasho_bucket = pageopaque->hasho_bucket;	ovflopaque->hasho_flag = LH_OVERFLOW_PAGE;	ovflopaque->hasho_filler = HASHO_FILL;	_hash_wrtnorelbuf(rel, ovflbuf);	/* logically chain overflow page to previous page */	pageopaque->hasho_nextblkno = ovflblkno;	_hash_wrtbuf(rel, buf);	return ovflbuf;}/* *	_hash_getovflpage() * *	Find an available overflow page and return its block number. * * The caller must hold a pin, but no lock, on the metapage buffer. * The buffer is returned in the same state. */static BlockNumber_hash_getovflpage(Relation rel, Buffer metabuf){	HashMetaPage metap;	Buffer		mapbuf = 0;	BlockNumber blkno;	uint32		orig_firstfree;	uint32		splitnum;	uint32	   *freep = NULL;	uint32		max_ovflpg;	uint32		bit;	uint32		first_page;	uint32		last_bit;	uint32		last_page;	uint32		i,				j;	/* Get exclusive lock on the meta page */	_hash_chgbufaccess(rel, metabuf, HASH_NOLOCK, HASH_WRITE);	metap = (HashMetaPage) BufferGetPage(metabuf);	_hash_checkpage(rel, (Page) metap, LH_META_PAGE);	/* start search at hashm_firstfree */	orig_firstfree = metap->hashm_firstfree;	first_page = orig_firstfree >> BMPG_SHIFT(metap);	bit = orig_firstfree & BMPG_MASK(metap);	i = first_page;	j = bit / BITS_PER_MAP;	bit &= ~(BITS_PER_MAP - 1);	/* outer loop iterates once per bitmap page */	for (;;)	{		BlockNumber mapblkno;		Page		mappage;		uint32		last_inpage;		/* want to end search with the last existing overflow page */		splitnum = metap->hashm_ovflpoint;		max_ovflpg = metap->hashm_spares[splitnum] - 1;		last_page = max_ovflpg >> BMPG_SHIFT(metap);		last_bit = max_ovflpg & BMPG_MASK(metap);		if (i > last_page)			break;		Assert(i < metap->hashm_nmaps);		mapblkno = metap->hashm_mapp[i];		if (i == last_page)			last_inpage = last_bit;		else			last_inpage = BMPGSZ_BIT(metap) - 1;		/* Release exclusive lock on metapage while reading bitmap page */		_hash_chgbufaccess(rel, metabuf, HASH_READ, HASH_NOLOCK);		mapbuf = _hash_getbuf(rel, mapblkno, HASH_WRITE);		mappage = BufferGetPage(mapbuf);		_hash_checkpage(rel, mappage, LH_BITMAP_PAGE);		freep = HashPageGetBitmap(mappage);		for (; bit <= last_inpage; j++, bit += BITS_PER_MAP)		{			if (freep[j] != ALL_SET)				goto found;		}		/* No free space here, try to advance to next map page */		_hash_relbuf(rel, mapbuf);		i++;		j = 0;					/* scan from start of next map page */		bit = 0;		/* Reacquire exclusive lock on the meta page */		_hash_chgbufaccess(rel, metabuf, HASH_NOLOCK, HASH_WRITE);	}	/* No Free Page Found - have to allocate a new page */	bit = metap->hashm_spares[splitnum];	metap->hashm_spares[splitnum]++;	/* Check if we need to allocate a new bitmap page */	if (last_bit == (uint32) (BMPGSZ_BIT(metap) - 1))	{		/*		 * We create the new bitmap page with all pages marked "in use".		 * Actually two pages in the new bitmap's range will exist		 * immediately: the bitmap page itself, and the following page which		 * is the one we return to the caller.	Both of these are correctly		 * marked "in use".  Subsequent pages do not exist yet, but it is		 * convenient to pre-mark them as "in use" too.		 */		_hash_initbitmap(rel, metap, bitno_to_blkno(metap, bit));		bit = metap->hashm_spares[splitnum];		metap->hashm_spares[splitnum]++;	}	else	{		/*		 * Nothing to do here; since the page was past the last used page, we		 * know its bitmap bit was preinitialized to "in use".		 */	}	/* Calculate address of the new overflow page */	blkno = bitno_to_blkno(metap, bit);	/*	 * Adjust hashm_firstfree to avoid redundant searches.	But don't risk	 * changing it if someone moved it while we were searching bitmap pages.	 */	if (metap->hashm_firstfree == orig_firstfree)		metap->hashm_firstfree = bit + 1;	/* Write updated metapage and release lock, but not pin */	_hash_chgbufaccess(rel, metabuf, HASH_WRITE, HASH_NOLOCK);	return blkno;found:	/* convert bit to bit number within page */	bit += _hash_firstfreebit(freep[j]);	/* mark page "in use" in the bitmap */	SETBIT(freep, bit);	_hash_wrtbuf(rel, mapbuf);	/* Reacquire exclusive lock on the meta page */	_hash_chgbufaccess(rel, metabuf, HASH_NOLOCK, HASH_WRITE);	/* convert bit to absolute bit number */	bit += (i << BMPG_SHIFT(metap));	/* Calculate address of the new overflow page */	blkno = bitno_to_blkno(metap, bit);	/*	 * Adjust hashm_firstfree to avoid redundant searches.	But don't risk	 * changing it if someone moved it while we were searching bitmap pages.	 */	if (metap->hashm_firstfree == orig_firstfree)	{		metap->hashm_firstfree = bit + 1;		/* Write updated metapage and release lock, but not pin */		_hash_chgbufaccess(rel, metabuf, HASH_WRITE, HASH_NOLOCK);	}	else	{		/* We didn't change the metapage, so no need to write */		_hash_chgbufaccess(rel, metabuf, HASH_READ, HASH_NOLOCK);	}	return blkno;}/* *	_hash_firstfreebit() * *	Return the number of the first bit that is not set in the word 'map'. */static uint32_hash_firstfreebit(uint32 map){	uint32		i,				mask;	mask = 0x1;	for (i = 0; i < BITS_PER_MAP; i++)	{		if (!(mask & map))			return i;		mask <<= 1;	}	elog(ERROR, "firstfreebit found no free bit");	return 0;					/* keep compiler quiet */}/* *	_hash_freeovflpage() - *

⌨️ 快捷键说明

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