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

📄 bufmgr.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 4 页
字号:
ShowBufferUsage(void){	StringInfoData str;	float		hitrate;	float		localhitrate;	initStringInfo(&str);	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;	appendStringInfo(&str,	"!\tShared blocks: %10ld read, %10ld written, buffer hit rate = %.2f%%\n",				ReadBufferCount - BufferHitCount, BufferFlushCount, hitrate);	appendStringInfo(&str,	"!\tLocal  blocks: %10ld read, %10ld written, buffer hit rate = %.2f%%\n",					 ReadLocalBufferCount - LocalBufferHitCount, LocalBufferFlushCount, localhitrate);	appendStringInfo(&str,					 "!\tDirect blocks: %10ld read, %10ld written\n",					 NDirectFileRead, NDirectFileWrite);	return str.data;}voidResetBufferUsage(void){	BufferHitCount = 0;	ReadBufferCount = 0;	BufferFlushCount = 0;	LocalBufferHitCount = 0;	ReadLocalBufferCount = 0;	LocalBufferFlushCount = 0;	NDirectFileRead = 0;	NDirectFileWrite = 0;}/* *		AtEOXact_Buffers - clean up at end of transaction. * *		As of PostgreSQL 8.0, buffer pins should get released by the *		ResourceOwner mechanism.  This routine is just a debugging *		cross-check that no pins remain. */voidAtEOXact_Buffers(bool isCommit){#ifdef USE_ASSERT_CHECKING	if (assert_enabled)	{		int			i;		for (i = 0; i < NBuffers; i++)		{			Assert(PrivateRefCount[i] == 0);		}	}#endif	AtEOXact_LocalBuffers(isCommit);	/* Make sure we reset the strategy hint in case VACUUM errored out */	StrategyHintVacuum(false);}/* * InitBufferPoolBackend --- second-stage initialization of a new backend * * This is called after we have acquired a PGPROC and so can safely get * LWLocks.  We don't currently need to do anything at this stage ... * except register a shmem-exit callback.  AtProcExit_Buffers needs LWLock * access, and thereby has to be called at the corresponding phase of * backend shutdown. */voidInitBufferPoolBackend(void){	on_shmem_exit(AtProcExit_Buffers, 0);}/* * Ensure we have released all shared-buffer locks and pins during backend exit */static voidAtProcExit_Buffers(int code, Datum arg){	int			i;	AbortBufferIO();	UnlockBuffers();	for (i = 0; i < NBuffers; i++)	{		if (PrivateRefCount[i] != 0)		{			volatile BufferDesc *buf = &(BufferDescriptors[i]);			/*			 * We don't worry about updating ResourceOwner; if we even got			 * here, it suggests that ResourceOwners are messed up.			 */			PrivateRefCount[i] = 1;		/* make sure we release shared pin */			UnpinBuffer(buf, false, false /* don't change freelist */ );			Assert(PrivateRefCount[i] == 0);		}	}	/* localbuf.c needs a chance too */	AtProcExit_LocalBuffers();}/* * Helper routine to issue warnings when a buffer is unexpectedly pinned */voidPrintBufferLeakWarning(Buffer buffer){	volatile BufferDesc *buf;	int32		loccount;	Assert(BufferIsValid(buffer));	if (BufferIsLocal(buffer))	{		buf = &LocalBufferDescriptors[-buffer - 1];		loccount = LocalRefCount[-buffer - 1];	}	else	{		buf = &BufferDescriptors[buffer - 1];		loccount = PrivateRefCount[buffer - 1];	}	/* theoretically we should lock the bufhdr here */	elog(WARNING,		 "buffer refcount leak: [%03d] "		 "(rel=%u/%u/%u, blockNum=%u, flags=0x%x, refcount=%u %d)",		 buffer,		 buf->tag.rnode.spcNode, buf->tag.rnode.dbNode,		 buf->tag.rnode.relNode,		 buf->tag.blockNum, buf->flags,		 buf->refcount, loccount);}/* * FlushBufferPool * * Flush all dirty blocks in buffer pool to disk at the checkpoint time. * Local relations do not participate in checkpoints, so they don't need to be * flushed. */voidFlushBufferPool(void){	BufferSync();	smgrsync();}/* * Do whatever is needed to prepare for commit at the bufmgr and smgr levels */voidBufmgrCommit(void){	/* Nothing to do in bufmgr anymore... */	smgrcommit();}/* * BufferGetBlockNumber *		Returns the block number associated with a buffer. * * Note: *		Assumes that the buffer is valid and pinned, else the *		value may be obsolete immediately... */BlockNumberBufferGetBlockNumber(Buffer buffer){	volatile BufferDesc *bufHdr;	Assert(BufferIsPinned(buffer));	if (BufferIsLocal(buffer))		bufHdr = &(LocalBufferDescriptors[-buffer - 1]);	else		bufHdr = &BufferDescriptors[buffer - 1];	/* pinned, so OK to read tag without spinlock */	return bufHdr->tag.blockNum;}/* * BufferGetFileNode *		Returns the relation ID (RelFileNode) associated with a buffer. * * This should make the same checks as BufferGetBlockNumber, but since the * two are generally called together, we don't bother. */RelFileNodeBufferGetFileNode(Buffer buffer){	volatile BufferDesc *bufHdr;	if (BufferIsLocal(buffer))		bufHdr = &(LocalBufferDescriptors[-buffer - 1]);	else		bufHdr = &BufferDescriptors[buffer - 1];	return bufHdr->tag.rnode;}/* * FlushBuffer *		Physically write out a shared buffer. * * NOTE: this actually just passes the buffer contents to the kernel; the * real write to disk won't happen until the kernel feels like it.  This * is okay from our point of view since we can redo the changes from WAL. * However, we will need to force the changes to disk via fsync before * we can checkpoint WAL. * * The caller must hold a pin on the buffer and have share-locked the * buffer contents.  (Note: a share-lock does not prevent updates of * hint bits in the buffer, so the page could change while the write * is in progress, but we assume that that will not invalidate the data * written.) * * If the caller has an smgr reference for the buffer's relation, pass it * as the second parameter.  If not, pass NULL. */static voidFlushBuffer(volatile BufferDesc *buf, SMgrRelation reln){	XLogRecPtr	recptr;	ErrorContextCallback errcontext;	/*	 * Acquire the buffer's io_in_progress lock.  If StartBufferIO returns	 * false, then someone else flushed the buffer before we could, so we need	 * not do anything.	 */	if (!StartBufferIO(buf, false))		return;	/* Setup error traceback support for ereport() */	errcontext.callback = buffer_write_error_callback;	errcontext.arg = (void *) buf;	errcontext.previous = error_context_stack;	error_context_stack = &errcontext;	/* Find smgr relation for buffer */	if (reln == NULL)		reln = smgropen(buf->tag.rnode);	/*	 * Force XLOG flush up to buffer's LSN.  This implements the basic WAL	 * rule that log updates must hit disk before any of the data-file changes	 * they describe do.	 */	recptr = BufferGetLSN(buf);	XLogFlush(recptr);	/*	 * Now it's safe to write buffer to disk. Note that no one else should	 * have been able to write it while we were busy with log flushing because	 * we have the io_in_progress lock.	 */	/* To check if block content changes while flushing. - vadim 01/17/97 */	LockBufHdr_NoHoldoff(buf);	buf->flags &= ~BM_JUST_DIRTIED;	UnlockBufHdr_NoHoldoff(buf);	smgrwrite(reln,			  buf->tag.blockNum,			  (char *) BufHdrGetBlock(buf),			  false);	BufferFlushCount++;	/*	 * Mark the buffer as clean (unless BM_JUST_DIRTIED has become set) and	 * end the io_in_progress state.	 */	TerminateBufferIO(buf, true, 0);	/* Pop the error context stack */	error_context_stack = errcontext.previous;}/* * RelationGetNumberOfBlocks *		Determines the current number of pages in the relation. */BlockNumberRelationGetNumberOfBlocks(Relation relation){	/* Open it at the smgr level if not already done */	RelationOpenSmgr(relation);	return smgrnblocks(relation->rd_smgr);}/* * RelationTruncate *		Physically truncate a relation to the specified number of blocks. * * As of Postgres 8.1, this includes getting rid of any buffers for the * blocks that are to be dropped; previously, callers had to do that. */voidRelationTruncate(Relation rel, BlockNumber nblocks){	/* Open it at the smgr level if not already done */	RelationOpenSmgr(rel);	/* Make sure rd_targblock isn't pointing somewhere past end */	rel->rd_targblock = InvalidBlockNumber;	/* Do the real work */	smgrtruncate(rel->rd_smgr, nblocks, rel->rd_istemp);}/* --------------------------------------------------------------------- *		DropRelFileNodeBuffers * *		This function removes from the buffer pool all the pages of the *		specified relation that have block numbers >= firstDelBlock. *		(In particular, with firstDelBlock = 0, all pages are removed.) *		Dirty pages are simply dropped, without bothering to write them *		out first.	Therefore, this is NOT rollback-able, and so should be *		used only with extreme caution! * *		Currently, this is called only from smgr.c when the underlying file *		is about to be deleted or truncated (firstDelBlock is needed for *		the truncation case).  The data in the affected pages would therefore *		be deleted momentarily anyway, and there is no point in writing it. *		It is the responsibility of higher-level code to ensure that the *		deletion or truncation does not lose any data that could be needed *		later.	It is also the responsibility of higher-level code to ensure *		that no other process could be trying to load more pages of the *		relation into buffers. * *		XXX currently it sequentially searches the buffer pool, should be *		changed to more clever ways of searching.  However, this routine *		is used only in code paths that aren't very performance-critical, *		and we shouldn't slow down the hot paths to make it faster ... * -------------------------------------------------------------------- */voidDropRelFileNodeBuffers(RelFileNode rnode, bool istemp,					   BlockNumber firstDelBlock){	int			i;	if (istemp)	{		DropRelFileNodeLocalBuffers(rnode, firstDelBlock);		return;	}	for (i = 0; i < NBuffers; i++)	{		volatile BufferDesc *bufHdr = &BufferDescriptors[i];		LockBufHdr(bufHdr);		if (RelFileNodeEquals(bufHdr->tag.rnode, rnode) &&			bufHdr->tag.blockNum >= firstDelBlock)			InvalidateBuffer(bufHdr);	/* releases spinlock */		else			UnlockBufHdr(bufHdr);	}}/* --------------------------------------------------------------------- *		DropBuffers * *		This function removes all the buffers in the buffer cache for a *		particular database.  Dirty pages are simply dropped, without *		bothering to write them out first.	This is used when we destroy a *		database, to avoid trying to flush data to disk when the directory *		tree no longer exists.	Implementation is pretty similar to *		DropRelFileNodeBuffers() which is for destroying just one relation. * -------------------------------------------------------------------- */voidDropBuffers(Oid dbid){	int			i;	volatile BufferDesc *bufHdr;	/*	 * We needn't consider local buffers, since by assumption the target	 * database isn't our own.	 */	for (i = 0; i < NBuffers; i++)	{		bufHdr = &BufferDescriptors[i];		LockBufHdr(bufHdr);		if (bufHdr->tag.rnode.dbNode == dbid)			InvalidateBuffer(bufHdr);	/* releases spinlock */		else			UnlockBufHdr(bufHdr);	}}/* ----------------------------------------------------------------- *		PrintBufferDescs * *		this function prints all the buffer descriptors, for debugging *		use only. * ----------------------------------------------------------------- */#ifdef NOT_USEDvoidPrintBufferDescs(void){	int			i;	volatile BufferDesc *buf = BufferDescriptors;	for (i = 0; i < NBuffers; ++i, ++buf)	{		/* theoretically we should lock the bufhdr here */		elog(LOG,			 "[%02d] (freeNext=%d, rel=%u/%u/%u, "			 "blockNum=%u, flags=0x%x, refcount=%u %d)",			 i, buf->freeNext,			 buf->tag.rnode.spcNode, buf->tag.rnode.dbNode,			 buf->tag.rnode.relNode,			 buf->tag.blockNum, buf->flags,			 buf->refcount, PrivateRefCount[i]);	}}#endif#ifdef NOT_USEDvoidPrintPinnedBufs(void){	int			i;	volatile BufferDesc *buf = BufferDescriptors;	for (i = 0; i < NBuffers; ++i, ++buf)	{		if (PrivateRefCount[i] > 0)		{			/* theoretically we should lock the bufhdr here */			elog(LOG,				 "[%02d] (freeNext=%d, rel=%u/%u/%u, "				 "blockNum=%u, flags=0x%x, refcount=%u %d)",				 i, buf->freeNext,				 buf->tag.rnode.spcNode, buf->tag.rnode.dbNode,				 buf->tag.rnode.relNode,				 buf->tag.blockNum, buf->flags,				 buf->refcount, PrivateRefCount[i]);		}	}}#endif/* --------------------------------------------------------------------- *		FlushRelationBuffers * *		This function writes all dirty pages of a relation out to disk *		(or more accurately, out to kernel disk buffers), ensuring that the *		kernel has an up-to-date view of the relation. * *		Generally, the caller should be holding AccessExclusiveLock on the *		target relation to ensure that no other backend is busy dirtying *		more blocks of the relation; the effects can't be expected to last *		after the lock is released. * *		XXX currently it sequentially searches the buffer pool, should be *		changed to more clever ways of searching.  This routine is not *		used in any performance-critical code paths, so it's not worth *		adding additional overhead to normal paths to make it go faster; *		but see also DropRelFileNodeBuffers. * -------------------------------------------------------------------- */voidFlushRelationBuffers(Relation rel){	int			i;	volatile BufferDesc *bufHdr;	/* Open rel at the smgr level if not already done */	RelationOpenSmgr(rel);	if (rel->rd_istemp)	{		for (i = 0; i < NLocBuffer; i++)		{			bufHdr = &LocalBufferDescriptors[i];			if (RelFileNodeEquals(bufHdr->tag.rnode, rel->rd_node) &&				(bufHdr->flags & BM_VALID) && (bufHdr->flags & BM_DIRTY))			{				ErrorContextCallback errcontext;				/* Setup error traceback support for ereport() */				errcontext.callback = buffer_write_error_callback;				errcontext.arg = (void *) bufHdr;				errcontext.previous = error_context_stack;				error_context_stack = &errcontext;				smgrwrite(rel->rd_smgr,						  bufHdr->tag.blockNum,						  (char *) LocalBufHdrGetBlock(bufHdr),						  true);				bufHdr->flags &= ~(BM_DIRTY | BM_JUST_DIRTIED);				/* Pop the error context stack */				error_context_stack = errcontext.previous;			}		}		return;	}

⌨️ 快捷键说明

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