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

📄 bufmgr.c

📁 关系型数据库 Postgresql 6.5.2
💻 C
📖 第 1 页 / 共 4 页
字号:
					bufHdr->flags |= BM_IO_ERROR;					elog(ERROR, "BufferSync: cannot write %u for %s",						 bufHdr->tag.blockNum, bufHdr->sb_relname);				}				BufferFlushCount++;				/*				 * If this buffer was marked by someone as DIRTY while we				 * were flushing it out we must not clear DIRTY flag -				 * vadim 01/17/97				 */				if (!(bufHdr->flags & BM_JUST_DIRTIED))					bufHdr->flags &= ~BM_DIRTY;				if (reln != (Relation) NULL)					RelationDecrementReferenceCount(reln);			}		}	}	SpinRelease(BufMgrLock);	LocalBufferSync();}/* * WaitIO -- Block until the IO_IN_PROGRESS flag on 'buf' *		is cleared.  Because IO_IN_PROGRESS conflicts are *		expected to be rare, there is only one BufferIO *		lock in the entire system.	All processes block *		on this semaphore when they try to use a buffer *		that someone else is faulting in.  Whenever a *		process finishes an IO and someone is waiting for *		the buffer, BufferIO is signaled (SignalIO).  All *		waiting processes then wake up and check to see *		if their buffer is now ready.  This implementation *		is simple, but efficient enough if WaitIO is *		rarely called by multiple processes simultaneously. * *	ProcSleep atomically releases the spinlock and goes to *		sleep. * *	Note: there is an easy fix if the queue becomes long. *		save the id of the buffer we are waiting for in *		the queue structure.  That way signal can figure *		out which proc to wake up. */#ifdef HAS_TEST_AND_SETstatic voidWaitIO(BufferDesc *buf, SPINLOCK spinlock){	SpinRelease(spinlock);	S_LOCK(&(buf->io_in_progress_lock));	S_UNLOCK(&(buf->io_in_progress_lock));	SpinAcquire(spinlock);}#else							/* HAS_TEST_AND_SET */IpcSemaphoreId WaitIOSemId;IpcSemaphoreId WaitCLSemId;static voidWaitIO(BufferDesc *buf, SPINLOCK spinlock){	bool		inProgress;	for (;;)	{		/* wait until someone releases IO lock */		(*NWaitIOBackendP)++;		SpinRelease(spinlock);		IpcSemaphoreLock(WaitIOSemId, 0, 1);		SpinAcquire(spinlock);		inProgress = (buf->flags & BM_IO_IN_PROGRESS);		if (!inProgress)			break;	}}/* * SignalIO */static voidSignalIO(BufferDesc *buf){	/* somebody better be waiting. */	Assert(buf->refcount > 1);	IpcSemaphoreUnlock(WaitIOSemId, 0, *NWaitIOBackendP);	*NWaitIOBackendP = 0;}#endif	 /* HAS_TEST_AND_SET */long		NDirectFileRead;	/* some I/O's are direct file access.								 * bypass bufmgr */long		NDirectFileWrite;	/* e.g., I/O in psort and hashjoin.					*/voidPrintBufferUsage(FILE *statfp){	float		hitrate;	float		localhitrate;	if (ReadBufferCount == 0)		hitrate = 0.0;	else		hitrate = (float) BufferHitCount *100.0 / ReadBufferCount;	if (ReadLocalBufferCount == 0)		localhitrate = 0.0;	else		localhitrate = (float) LocalBufferHitCount *100.0 / ReadLocalBufferCount;	fprintf(statfp, "!\tShared blocks: %10ld read, %10ld written, buffer hit rate = %.2f%%\n",			ReadBufferCount - BufferHitCount, BufferFlushCount, hitrate);	fprintf(statfp, "!\tLocal  blocks: %10ld read, %10ld written, buffer hit rate = %.2f%%\n",			ReadLocalBufferCount - LocalBufferHitCount, LocalBufferFlushCount, localhitrate);	fprintf(statfp, "!\tDirect blocks: %10ld read, %10ld written\n",			NDirectFileRead, NDirectFileWrite);}voidResetBufferUsage(){	BufferHitCount = 0;	ReadBufferCount = 0;	BufferFlushCount = 0;	LocalBufferHitCount = 0;	ReadLocalBufferCount = 0;	LocalBufferFlushCount = 0;	NDirectFileRead = 0;	NDirectFileWrite = 0;}/* ---------------------------------------------- *		ResetBufferPool * *		this routine is supposed to be called when a transaction aborts. *		it will release all the buffer pins held by the transaciton. * * ---------------------------------------------- */voidResetBufferPool(){	int			i;	for (i = 1; i <= NBuffers; i++)	{		CommitInfoNeedsSave[i - 1] = 0;		if (BufferIsValid(i))		{			while (PrivateRefCount[i - 1] > 0)				ReleaseBuffer(i);		}		LastRefCount[i - 1] = 0;	}	ResetLocalBufferPool();}/* ----------------------------------------------- *		BufferPoolCheckLeak * *		check if there is buffer leak * * ----------------------------------------------- */intBufferPoolCheckLeak(){	int			i;	int			result = 0;	for (i = 1; i <= NBuffers; i++)	{		if (BufferIsValid(i))		{			BufferDesc *buf = &(BufferDescriptors[i - 1]);			elog(NOTICE,				 "Buffer Leak: [%03d] (freeNext=%d, freePrev=%d, \relname=%s, blockNum=%d, flags=0x%x, refcount=%d %d)",				 i - 1, buf->freeNext, buf->freePrev,				 buf->sb_relname, buf->tag.blockNum, buf->flags,				 buf->refcount, PrivateRefCount[i - 1]);			result = 1;		}	}	return (result);}/* ------------------------------------------------ *		FlushBufferPool * *		flush all dirty blocks in buffer pool to disk * * ------------------------------------------------ */voidFlushBufferPool(int StableMainMemoryFlag){	if (!StableMainMemoryFlag)	{		BufferSync();		smgrcommit();	}}/* * BufferGetBlockNumber *		Returns the block number associated with a buffer. * * Note: *		Assumes that the buffer is valid. */BlockNumberBufferGetBlockNumber(Buffer buffer){	Assert(BufferIsValid(buffer));	/* XXX should be a critical section */	if (BufferIsLocal(buffer))		return LocalBufferDescriptors[-buffer - 1].tag.blockNum;	else		return BufferDescriptors[buffer - 1].tag.blockNum;}#ifdef NOT_USED/* * BufferGetRelation *		Returns the relation desciptor associated with a buffer. * * Note: *		Assumes buffer is valid. */RelationBufferGetRelation(Buffer buffer){	Relation	relation;	Oid			relid;	Assert(BufferIsValid(buffer));	Assert(!BufferIsLocal(buffer));		/* not supported for local buffers */	/* XXX should be a critical section */	relid = BufferDescriptors[buffer - 1].tag.relId.relId;	relation = RelationIdGetRelation(relid);	RelationDecrementReferenceCount(relation);	if (RelationHasReferenceCountZero(relation))	{		/*		 * elog(NOTICE, "BufferGetRelation: 0->1");		 */		RelationIncrementReferenceCount(relation);	}	return relation;}#endif/* * BufferReplace * * Flush the buffer corresponding to 'bufHdr' * */static intBufferReplace(BufferDesc *bufHdr, bool bufferLockHeld){	Relation	reln;	Oid			bufdb,				bufrel;	int			status;	if (!bufferLockHeld)		SpinAcquire(BufMgrLock);	/*	 * first try to find the reldesc in the cache, if no luck, don't	 * bother to build the reldesc from scratch, just do a blind write.	 */	bufdb = bufHdr->tag.relId.dbId;	bufrel = bufHdr->tag.relId.relId;	if (bufdb == MyDatabaseId || bufdb == (Oid) NULL)		reln = RelationIdCacheGetRelation(bufrel);	else		reln = (Relation) NULL;	/* To check if block content changed while flushing. - vadim 01/17/97 */	bufHdr->flags &= ~BM_JUST_DIRTIED;	SpinRelease(BufMgrLock);	if (reln != (Relation) NULL)	{		status = smgrflush(DEFAULT_SMGR, reln, bufHdr->tag.blockNum,						   (char *) MAKE_PTR(bufHdr->data));	}	else	{		/* blind write always flushes */		status = smgrblindwrt(DEFAULT_SMGR, bufHdr->sb_dbname,							  bufHdr->sb_relname, bufdb, bufrel,							  bufHdr->tag.blockNum,							  (char *) MAKE_PTR(bufHdr->data));	}	if (reln != (Relation) NULL)		RelationDecrementReferenceCount(reln);	if (status == SM_FAIL)		return FALSE;	BufferFlushCount++;	return TRUE;}/* * RelationGetNumberOfBlocks *		Returns the buffer descriptor associated with a page in a relation. * * Note: *		XXX may fail for huge relations. *		XXX should be elsewhere. *		XXX maybe should be hidden */BlockNumberRelationGetNumberOfBlocks(Relation relation){	return ((relation->rd_myxactonly) ? relation->rd_nblocks :			smgrnblocks(DEFAULT_SMGR, relation));}/* --------------------------------------------------------------------- *		ReleaseRelationBuffers * *		this function unmarks all the dirty pages of a relation *		in the buffer pool so that at the end of transaction *		these pages will not be flushed. *		XXX currently it sequentially searches the buffer pool, should be *		changed to more clever ways of searching. * -------------------------------------------------------------------- */voidReleaseRelationBuffers(Relation rel){	int			i;	int			holding = 0;	BufferDesc *buf;	if (rel->rd_myxactonly)	{		for (i = 0; i < NLocBuffer; i++)		{			buf = &LocalBufferDescriptors[i];			if ((buf->flags & BM_DIRTY) &&				(buf->tag.relId.relId == RelationGetRelid(rel)))				buf->flags &= ~BM_DIRTY;		}		return;	}	for (i = 1; i <= NBuffers; i++)	{		buf = &BufferDescriptors[i - 1];		if (!holding)		{			SpinAcquire(BufMgrLock);			holding = 1;		}		if ((buf->flags & BM_DIRTY) &&			(buf->tag.relId.dbId == MyDatabaseId) &&			(buf->tag.relId.relId == RelationGetRelid(rel)))		{			buf->flags &= ~BM_DIRTY;			if (!(buf->flags & BM_FREE))			{				SpinRelease(BufMgrLock);				holding = 0;				ReleaseBuffer(i);			}		}	}	if (holding)		SpinRelease(BufMgrLock);}/* --------------------------------------------------------------------- *		DropBuffers * *		This function marks all the buffers in the buffer cache for a *		particular database as clean.  This is used when we destroy a *		database, to avoid trying to flush data to disk when the directory *		tree no longer exists. * *		This is an exceedingly non-public interface. * -------------------------------------------------------------------- */voidDropBuffers(Oid dbid){	int			i;	BufferDesc *buf;	SpinAcquire(BufMgrLock);	for (i = 1; i <= NBuffers; i++)	{		buf = &BufferDescriptors[i - 1];		if ((buf->tag.relId.dbId == dbid) && (buf->flags & BM_DIRTY))			buf->flags &= ~BM_DIRTY;	}	SpinRelease(BufMgrLock);}/* ----------------------------------------------------------------- *		PrintBufferDescs * *		this function prints all the buffer descriptors, for debugging *		use only. * ----------------------------------------------------------------- */voidPrintBufferDescs(){	int			i;	BufferDesc *buf = BufferDescriptors;	if (IsUnderPostmaster)	{		SpinAcquire(BufMgrLock);		for (i = 0; i < NBuffers; ++i, ++buf)		{			elog(DEBUG, "[%02d] (freeNext=%d, freePrev=%d, relname=%s, \blockNum=%d, flags=0x%x, refcount=%d %d)",				 i, buf->freeNext, buf->freePrev,				 buf->sb_relname, buf->tag.blockNum, buf->flags,				 buf->refcount, PrivateRefCount[i]);		}		SpinRelease(BufMgrLock);	}	else	{		/* interactive backend */		for (i = 0; i < NBuffers; ++i, ++buf)		{			printf("[%-2d] (%s, %d) flags=0x%x, refcnt=%d %ld)\n",				   i, buf->sb_relname, buf->tag.blockNum,				   buf->flags, buf->refcount, PrivateRefCount[i]);		}	}}voidPrintPinnedBufs(){	int			i;	BufferDesc *buf = BufferDescriptors;	SpinAcquire(BufMgrLock);	for (i = 0; i < NBuffers; ++i, ++buf)	{		if (PrivateRefCount[i] > 0)			elog(NOTICE, "[%02d] (freeNext=%d, freePrev=%d, relname=%s, \blockNum=%d, flags=0x%x, refcount=%d %d)\n",				 i, buf->freeNext, buf->freePrev, buf->sb_relname,				 buf->tag.blockNum, buf->flags,				 buf->refcount, PrivateRefCount[i]);	}	SpinRelease(BufMgrLock);}/* * BufferPoolBlowaway * * this routine is solely for the purpose of experiments -- sometimes * you may want to blowaway whatever is left from the past in buffer * pool and start measuring some performance with a clean empty buffer * pool. */#ifdef NOT_USEDvoidBufferPoolBlowaway(){	int			i;	BufferSync();	for (i = 1; i <= NBuffers; i++)	{		if (BufferIsValid(i))		{			while (BufferIsValid(i))				ReleaseBuffer(i);		}		BufTableDelete(&BufferDescriptors[i - 1]);	}}#endif/* --------------------------------------------------------------------- *		BlowawayRelationBuffers * *		This function blowaway all the pages with blocknumber >= passed *		of a relation in the buffer pool. Used by vacuum before truncation... * *		Returns: 0 - Ok, -1 - DIRTY, -2 - PINNED * *		XXX currently it sequentially searches the buffer pool, should be *		changed to more clever ways of searching. * -------------------------------------------------------------------- */intBlowawayRelationBuffers(Relation rel, BlockNumber block){	int			i;	BufferDesc *buf;

⌨️ 快捷键说明

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