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

📄 bufmgr.c

📁 postgresql8.3.4源码,开源数据库
💻 C
📖 第 1 页 / 共 5 页
字号:
			{				BgWriterStats.m_maxwritten_clean++;				break;			}		}		else if (buffer_state & BUF_REUSABLE)			reusable_buffers++;	}	BgWriterStats.m_buf_written_clean += num_written;#ifdef BGW_DEBUG	elog(DEBUG1, "bgwriter: recent_alloc=%u smoothed=%.2f delta=%ld ahead=%d density=%.2f reusable_est=%d upcoming_est=%d scanned=%d wrote=%d reusable=%d",		 recent_alloc, smoothed_alloc, strategy_delta, bufs_ahead,		 smoothed_density, reusable_buffers_est, upcoming_alloc_est,		 bufs_to_lap - num_to_scan,		 num_written,		 reusable_buffers - reusable_buffers_est);#endif	/*	 * Consider the above scan as being like a new allocation scan.	 * Characterize its density and update the smoothed one based on it. This	 * effectively halves the moving average period in cases where both the	 * strategy and the background writer are doing some useful scanning,	 * which is helpful because a long memory isn't as desirable on the	 * density estimates.	 */	strategy_delta = bufs_to_lap - num_to_scan;	recent_alloc = reusable_buffers - reusable_buffers_est;	if (strategy_delta > 0 && recent_alloc > 0)	{		scans_per_alloc = (float) strategy_delta / (float) recent_alloc;		smoothed_density += (scans_per_alloc - smoothed_density) /			smoothing_samples;#ifdef BGW_DEBUG		elog(DEBUG2, "bgwriter: cleaner density alloc=%u scan=%ld density=%.2f new smoothed=%.2f",			 recent_alloc, strategy_delta, scans_per_alloc, smoothed_density);#endif	}}/* * SyncOneBuffer -- process a single buffer during syncing. * * If skip_recently_used is true, we don't write currently-pinned buffers, nor * buffers marked recently used, as these are not replacement candidates. * * Returns a bitmask containing the following flag bits: *	BUF_WRITTEN: we wrote the buffer. *	BUF_REUSABLE: buffer is available for replacement, ie, it has *		pin count 0 and usage count 0. * * (BUF_WRITTEN could be set in error if FlushBuffers finds the buffer clean * after locking it, but we don't care all that much.) * * Note: caller must have done ResourceOwnerEnlargeBuffers. */static intSyncOneBuffer(int buf_id, bool skip_recently_used){	volatile BufferDesc *bufHdr = &BufferDescriptors[buf_id];	int			result = 0;	/*	 * Check whether buffer needs writing.	 *	 * We can make this check without taking the buffer content lock so long	 * as we mark pages dirty in access methods *before* logging changes with	 * XLogInsert(): if someone marks the buffer dirty just after our check we	 * don't worry because our checkpoint.redo points before log record for	 * upcoming changes and so we are not required to write such dirty buffer.	 */	LockBufHdr(bufHdr);	if (bufHdr->refcount == 0 && bufHdr->usage_count == 0)		result |= BUF_REUSABLE;	else if (skip_recently_used)	{		/* Caller told us not to write recently-used buffers */		UnlockBufHdr(bufHdr);		return result;	}	if (!(bufHdr->flags & BM_VALID) || !(bufHdr->flags & BM_DIRTY))	{		/* It's clean, so nothing to do */		UnlockBufHdr(bufHdr);		return result;	}	/*	 * Pin it, share-lock it, write it.  (FlushBuffer will do nothing if the	 * buffer is clean by the time we've locked it.)	 */	PinBuffer_Locked(bufHdr);	LWLockAcquire(bufHdr->content_lock, LW_SHARED);	FlushBuffer(bufHdr, NULL);	LWLockRelease(bufHdr->content_lock);	UnpinBuffer(bufHdr, true);	return result | BUF_WRITTEN;}/* * Return a palloc'd string containing buffer usage statistics. */char *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);}/* * 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);			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);}/* * CheckPointBuffers * * Flush all dirty blocks in buffer pool to disk at checkpoint time. * * Note: temporary relations do not participate in checkpoints, so they don't * need to be flushed. */voidCheckPointBuffers(int flags){	CheckpointStats.ckpt_write_t = GetCurrentTimestamp();	BufferSync(flags);	CheckpointStats.ckpt_sync_t = GetCurrentTimestamp();	smgrsync();	CheckpointStats.ckpt_sync_end_t = GetCurrentTimestamp();}/* * 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(buf);	buf->flags &= ~BM_JUST_DIRTIED;	UnlockBufHdr(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

⌨️ 快捷键说明

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