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

📄 bufmgr.c

📁 postgresql8.3.4源码,开源数据库
💻 C
📖 第 1 页 / 共 5 页
字号:
 * *		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);	}}/* --------------------------------------------------------------------- *		DropDatabaseBuffers * *		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. * -------------------------------------------------------------------- */voidDropDatabaseBuffers(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;	}	/* Make sure we can handle the pin inside the loop */	ResourceOwnerEnlargeBuffers(CurrentResourceOwner);	for (i = 0; i < NBuffers; i++)	{		bufHdr = &BufferDescriptors[i];		LockBufHdr(bufHdr);		if (RelFileNodeEquals(bufHdr->tag.rnode, rel->rd_node) &&			(bufHdr->flags & BM_VALID) && (bufHdr->flags & BM_DIRTY))		{			PinBuffer_Locked(bufHdr);			LWLockAcquire(bufHdr->content_lock, LW_SHARED);			FlushBuffer(bufHdr, rel->rd_smgr);			LWLockRelease(bufHdr->content_lock);			UnpinBuffer(bufHdr, true);		}		else			UnlockBufHdr(bufHdr);	}}/* --------------------------------------------------------------------- *		FlushDatabaseBuffers * *		This function writes all dirty pages of a database out to disk *		(or more accurately, out to kernel disk buffers), ensuring that the *		kernel has an up-to-date view of the database. * *		Generally, the caller should be holding an appropriate lock to ensure *		no other backend is active in the target database; otherwise more *		pages could get dirtied. * *		Note we don't worry about flushing any pages of temporary relations. *		It's assumed these wouldn't be interesting. * -------------------------------------------------------------------- */voidFlushDatabaseBuffers(Oid dbid){	int			i;	volatile BufferDesc *bufHdr;	/* Make sure we can handle the pin inside the loop */	ResourceOwnerEnlargeBuffers(CurrentResourceOwner);	for (i = 0; i < NBuffers; i++)	{		bufHdr = &BufferDescriptors[i];		LockBufHdr(bufHdr);		if (bufHdr->tag.rnode.dbNode == dbid &&			(bufHdr->flags & BM_VALID) && (bufHdr->flags & BM_DIRTY))		{			PinBuffer_Locked(bufHdr);			LWLockAcquire(bufHdr->content_lock, LW_SHARED);			FlushBuffer(bufHdr, NULL);			LWLockRelease(bufHdr->content_lock);			UnpinBuffer(bufHdr, true);		}		else			UnlockBufHdr(bufHdr);	}}/* * ReleaseBuffer -- release the pin on a buffer */voidReleaseBuffer(Buffer buffer){	volatile BufferDesc *bufHdr;	if (!BufferIsValid(buffer))		elog(ERROR, "bad buffer id: %d", buffer);	ResourceOwnerForgetBuffer(CurrentResourceOwner, buffer);	if (BufferIsLocal(buffer))	{		Assert(LocalRefCount[-buffer - 1] > 0);		LocalRefCount[-buffer - 1]--;		return;	}	bufHdr = &BufferDescriptors[buffer - 1];	Assert(PrivateRefCount[buffer - 1] > 0);	if (PrivateRefCount[buffer - 1] > 1)		PrivateRefCount[buffer - 1]--;	else		UnpinBuffer(bufHdr, false);}/* * UnlockReleaseBuffer -- release the content lock and pin on a buffer * * This is just a shorthand for a common combination. */voidUnlockReleaseBuffer(Buffer buffer){	LockBuffer(buffer, BUFFER_LOCK_UNLOCK);	ReleaseBuffer(buffer);}/* * IncrBufferRefCount *		Increment the pin count on a buffer that we have *already* pinned *		at least once. * *		This function cannot be used on a buffer we do not have pinned, *		because it doesn't change the shared buffer state. */voidIncrBufferRefCount(Buffer buffer){	Assert(BufferIsPinned(buffer));	ResourceOwnerEnlargeBuffers(CurrentResourceOwner);	ResourceOwnerRememberBuffer(CurrentResourceOwner, buffer);	if (BufferIsLocal(buffer))		LocalRefCount[-buffer - 1]++;	else		PrivateRefCount[buffer - 1]++;}/* * SetBufferCommitInfoNeedsSave * *	Mark a buffer dirty when we have updated tuple commit-status bits in it. * * This is essentially the same as MarkBufferDirty, except that the caller * might have only share-lock instead of exclusive-lock on the buffer's * content lock.  We preserve the distinction mainly as a way of documenting * that the caller has not made a critical data change --- the status-bit * update could be redone by someone else just as easily.  Therefore, no WAL * log record need be generated, whereas calls to MarkBufferDirty really ought * to be associated with a WAL-entry-creating action. */voidSetBufferCommitInfoNeedsSave(Buffer buffer){	volatile BufferDesc *bufHdr;	if (!BufferIsValid(buffer))		elog(ERROR, "bad buffer id: %d", buffer);	if (BufferIsLocal(buffer))	{		MarkLocalBufferDirty(buffer);		return;	}	bufHdr = &BufferDescriptors[buffer - 1];	Assert(PrivateRefCount[buffer - 1] > 0);	/* here, either share or exclusive lock is OK */	Assert(LWLockHeldByMe(bufHdr->content_lock));	/*	 * This routine might get called many times on the same page, if we are	 * making the first scan after commit of an xact that added/deleted many	 * tuples.	So, be as quick as we can if the buffer is already dirty.  We	 * do this by not acquiring spinlock if it looks like the status bits are	 * already OK.	(Note it is okay if someone else clears BM_JUST_DIRTIED	 * immediately after we look, because the buffer content update is already	 * done and will be reflected in the I/O.)	 */	if ((bufHdr->flags & (BM_DIRTY | BM_JUST_DIRTIED)) !=		(BM_DIRTY | BM_JUST_DIRTIED))	{		LockBufHdr(bufHdr);		Assert(bufHdr->refcount > 0);		if (!(bufHdr->flags & BM_DIRTY) && VacuumCostActive)			VacuumCostBalance += VacuumCostPageDirty;		bufHdr->flags |= (BM_DIRTY | BM_JUST_DIRTIED);		UnlockBufHdr(bufHdr);	}}/* * Release buffer content locks for shared buffers. * * Used to clean up after errors. * * Currently, we can expect that lwlock.c's LWLockReleaseAll() took care * of releasing buffer content locks per se; the only thing we need to deal * with here is clearing any PIN_COUNT request that was in progress. */voidUnlockBuffers(void){	volatile BufferDesc *buf = PinCountWaitBuf;	if (buf)	{		LockBufHdr(buf);		/*		 * Don't complain if flag bit not set; it could have been reset but we		 * got a cancel/die interrupt before getting the signal.		 */		if ((buf->flags & BM_PIN_COUNT_WAITER) != 0 &&			buf->wait_backend_pid == MyProcPid)			buf->flags &= ~BM_PIN_COUNT_WAITER;		UnlockBufHdr(buf);		PinCountWaitBuf = NULL;	}}/* * Acquire or release the content_lock for the buffer. */voidLockBuffer(Buffer buffer, int mode){	volatile BufferDesc *buf;	Assert(BufferIsValid(buffer));	if (BufferIsLocal(buffer))		return;					/* local buffers need no lock */	buf = &(BufferDescriptors[buffer - 1]);	if (mode == BUFFER_LOCK_UNLOCK)		LWLockRelease(buf->content_lock);	else if (mode == BUFFER_LOCK_SHARE)		LWLockAcquire(buf->content_lock, LW_SHARED);	else if (mode == BUFFER_LOCK_EXCLUSIVE)		LWLockAcquire(buf->content_lock, LW_EXCLUSIVE);	else		elog(ERROR, "unrecognized buffer lock mode: %d", mode);}/* * Acquire the content_lock for the buffer, but only if we don't have to wait. * * This assumes the caller wants BUFFER_LOCK_EXCLUSIVE mode. */boolConditionalLockBuffer(Buffer buffer){	volatile BufferDesc *buf;	Assert(BufferIsValid(buffer));	if (BufferIsLocal(buffer))		return true;			/* act as though we got it */	buf = &(BufferDescriptors[buffer - 1]);	r

⌨️ 快捷键说明

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