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

📄 slru.c

📁 postgresql8.3.4源码,开源数据库
💻 C
📖 第 1 页 / 共 3 页
字号:
	/*	 * If not part of Flush, need to fsync now.  We assume this happens	 * infrequently enough that it's not a performance issue.	 */	if (!fdata)	{		if (ctl->do_fsync && pg_fsync(fd))		{			slru_errcause = SLRU_FSYNC_FAILED;			slru_errno = errno;			close(fd);			return false;		}		if (close(fd))		{			slru_errcause = SLRU_CLOSE_FAILED;			slru_errno = errno;			return false;		}	}	return true;}/* * Issue the error message after failure of SlruPhysicalReadPage or * SlruPhysicalWritePage.  Call this after cleaning up shared-memory state. */static voidSlruReportIOError(SlruCtl ctl, int pageno, TransactionId xid){	int			segno = pageno / SLRU_PAGES_PER_SEGMENT;	int			rpageno = pageno % SLRU_PAGES_PER_SEGMENT;	int			offset = rpageno * BLCKSZ;	char		path[MAXPGPATH];	SlruFileName(ctl, path, segno);	errno = slru_errno;	switch (slru_errcause)	{		case SLRU_OPEN_FAILED:			ereport(ERROR,					(errcode_for_file_access(),					 errmsg("could not access status of transaction %u", xid),					 errdetail("Could not open file \"%s\": %m.", path)));			break;		case SLRU_SEEK_FAILED:			ereport(ERROR,					(errcode_for_file_access(),					 errmsg("could not access status of transaction %u", xid),				 errdetail("Could not seek in file \"%s\" to offset %u: %m.",						   path, offset)));			break;		case SLRU_READ_FAILED:			ereport(ERROR,					(errcode_for_file_access(),					 errmsg("could not access status of transaction %u", xid),			   errdetail("Could not read from file \"%s\" at offset %u: %m.",						 path, offset)));			break;		case SLRU_WRITE_FAILED:			ereport(ERROR,					(errcode_for_file_access(),					 errmsg("could not access status of transaction %u", xid),				errdetail("Could not write to file \"%s\" at offset %u: %m.",						  path, offset)));			break;		case SLRU_FSYNC_FAILED:			ereport(ERROR,					(errcode_for_file_access(),					 errmsg("could not access status of transaction %u", xid),					 errdetail("Could not fsync file \"%s\": %m.",							   path)));			break;		case SLRU_CLOSE_FAILED:			ereport(ERROR,					(errcode_for_file_access(),					 errmsg("could not access status of transaction %u", xid),					 errdetail("Could not close file \"%s\": %m.",							   path)));			break;		default:			/* can't get here, we trust */			elog(ERROR, "unrecognized SimpleLru error cause: %d",				 (int) slru_errcause);			break;	}}/* * Select the slot to re-use when we need a free slot. * * The target page number is passed because we need to consider the * possibility that some other process reads in the target page while * we are doing I/O to free a slot.  Hence, check or recheck to see if * any slot already holds the target page, and return that slot if so. * Thus, the returned slot is *either* a slot already holding the pageno * (could be any state except EMPTY), *or* a freeable slot (state EMPTY * or CLEAN). * * Control lock must be held at entry, and will be held at exit. */static intSlruSelectLRUPage(SlruCtl ctl, int pageno){	SlruShared	shared = ctl->shared;	/* Outer loop handles restart after I/O */	for (;;)	{		int			slotno;		int			cur_count;		int			bestslot;		int			best_delta;		int			best_page_number;		/* See if page already has a buffer assigned */		for (slotno = 0; slotno < shared->num_slots; slotno++)		{			if (shared->page_number[slotno] == pageno &&				shared->page_status[slotno] != SLRU_PAGE_EMPTY)				return slotno;		}		/*		 * If we find any EMPTY slot, just select that one. Else locate the		 * least-recently-used slot to replace.		 *		 * Normally the page_lru_count values will all be different and so		 * there will be a well-defined LRU page.  But since we allow		 * concurrent execution of SlruRecentlyUsed() within		 * SimpleLruReadPage_ReadOnly(), it is possible that multiple pages		 * acquire the same lru_count values.  In that case we break ties by		 * choosing the furthest-back page.		 *		 * In no case will we select the slot containing latest_page_number		 * for replacement, even if it appears least recently used.		 *		 * Notice that this next line forcibly advances cur_lru_count to a		 * value that is certainly beyond any value that will be in the		 * page_lru_count array after the loop finishes.  This ensures that		 * the next execution of SlruRecentlyUsed will mark the page newly		 * used, even if it's for a page that has the current counter value.		 * That gets us back on the path to having good data when there are		 * multiple pages with the same lru_count.		 */		cur_count = (shared->cur_lru_count)++;		best_delta = -1;		bestslot = 0;			/* no-op, just keeps compiler quiet */		best_page_number = 0;	/* ditto */		for (slotno = 0; slotno < shared->num_slots; slotno++)		{			int			this_delta;			int			this_page_number;			if (shared->page_status[slotno] == SLRU_PAGE_EMPTY)				return slotno;			this_delta = cur_count - shared->page_lru_count[slotno];			if (this_delta < 0)			{				/*				 * Clean up in case shared updates have caused cur_count				 * increments to get "lost".  We back off the page counts,				 * rather than trying to increase cur_count, to avoid any				 * question of infinite loops or failure in the presence of				 * wrapped-around counts.				 */				shared->page_lru_count[slotno] = cur_count;				this_delta = 0;			}			this_page_number = shared->page_number[slotno];			if ((this_delta > best_delta ||				 (this_delta == best_delta &&				  ctl->PagePrecedes(this_page_number, best_page_number))) &&				this_page_number != shared->latest_page_number)			{				bestslot = slotno;				best_delta = this_delta;				best_page_number = this_page_number;			}		}		/*		 * If the selected page is clean, we're set.		 */		if (shared->page_status[bestslot] == SLRU_PAGE_VALID &&			!shared->page_dirty[bestslot])			return bestslot;		/*		 * We need to wait for I/O.  Normal case is that it's dirty and we		 * must initiate a write, but it's possible that the page is already		 * write-busy, or in the worst case still read-busy.  In those cases		 * we wait for the existing I/O to complete.		 */		if (shared->page_status[bestslot] == SLRU_PAGE_VALID)			SimpleLruWritePage(ctl, bestslot, NULL);		else			SimpleLruWaitIO(ctl, bestslot);		/*		 * Now loop back and try again.  This is the easiest way of dealing		 * with corner cases such as the victim page being re-dirtied while we		 * wrote it.		 */	}}/* * Flush dirty pages to disk during checkpoint or database shutdown */voidSimpleLruFlush(SlruCtl ctl, bool checkpoint){	SlruShared	shared = ctl->shared;	SlruFlushData fdata;	int			slotno;	int			pageno = 0;	int			i;	bool		ok;	/*	 * Find and write dirty pages	 */	fdata.num_files = 0;	LWLockAcquire(shared->ControlLock, LW_EXCLUSIVE);	for (slotno = 0; slotno < shared->num_slots; slotno++)	{		SimpleLruWritePage(ctl, slotno, &fdata);		/*		 * When called during a checkpoint, we cannot assert that the slot is		 * clean now, since another process might have re-dirtied it already.		 * That's okay.		 */		Assert(checkpoint ||			   shared->page_status[slotno] == SLRU_PAGE_EMPTY ||			   (shared->page_status[slotno] == SLRU_PAGE_VALID &&				!shared->page_dirty[slotno]));	}	LWLockRelease(shared->ControlLock);	/*	 * Now fsync and close any files that were open	 */	ok = true;	for (i = 0; i < fdata.num_files; i++)	{		if (ctl->do_fsync && pg_fsync(fdata.fd[i]))		{			slru_errcause = SLRU_FSYNC_FAILED;			slru_errno = errno;			pageno = fdata.segno[i] * SLRU_PAGES_PER_SEGMENT;			ok = false;		}		if (close(fdata.fd[i]))		{			slru_errcause = SLRU_CLOSE_FAILED;			slru_errno = errno;			pageno = fdata.segno[i] * SLRU_PAGES_PER_SEGMENT;			ok = false;		}	}	if (!ok)		SlruReportIOError(ctl, pageno, InvalidTransactionId);}/* * Remove all segments before the one holding the passed page number */voidSimpleLruTruncate(SlruCtl ctl, int cutoffPage){	SlruShared	shared = ctl->shared;	int			slotno;	/*	 * The cutoff point is the start of the segment containing cutoffPage.	 */	cutoffPage -= cutoffPage % SLRU_PAGES_PER_SEGMENT;	/*	 * Scan shared memory and remove any pages preceding the cutoff page, to	 * ensure we won't rewrite them later.  (Since this is normally called in	 * or just after a checkpoint, any dirty pages should have been flushed	 * already ... we're just being extra careful here.)	 */	LWLockAcquire(shared->ControlLock, LW_EXCLUSIVE);restart:;	/*	 * While we are holding the lock, make an important safety check: the	 * planned cutoff point must be <= the current endpoint page. Otherwise we	 * have already wrapped around, and proceeding with the truncation would	 * risk removing the current segment.	 */	if (ctl->PagePrecedes(shared->latest_page_number, cutoffPage))	{		LWLockRelease(shared->ControlLock);		ereport(LOG,		  (errmsg("could not truncate directory \"%s\": apparent wraparound",				  ctl->Dir)));		return;	}	for (slotno = 0; slotno < shared->num_slots; slotno++)	{		if (shared->page_status[slotno] == SLRU_PAGE_EMPTY)			continue;		if (!ctl->PagePrecedes(shared->page_number[slotno], cutoffPage))			continue;		/*		 * If page is clean, just change state to EMPTY (expected case).		 */		if (shared->page_status[slotno] == SLRU_PAGE_VALID &&			!shared->page_dirty[slotno])		{			shared->page_status[slotno] = SLRU_PAGE_EMPTY;			continue;		}		/*		 * Hmm, we have (or may have) I/O operations acting on the page, so		 * we've got to wait for them to finish and then start again. This is		 * the same logic as in SlruSelectLRUPage.	(XXX if page is dirty,		 * wouldn't it be OK to just discard it without writing it?  For now,		 * keep the logic the same as it was.)		 */		if (shared->page_status[slotno] == SLRU_PAGE_VALID)			SimpleLruWritePage(ctl, slotno, NULL);		else			SimpleLruWaitIO(ctl, slotno);		goto restart;	}	LWLockRelease(shared->ControlLock);	/* Now we can remove the old segment(s) */	(void) SlruScanDirectory(ctl, cutoffPage, true);}/* * SimpleLruTruncate subroutine: scan directory for removable segments. * Actually remove them iff doDeletions is true.  Return TRUE iff any * removable segments were found.  Note: no locking is needed. * * This can be called directly from clog.c, for reasons explained there. */boolSlruScanDirectory(SlruCtl ctl, int cutoffPage, bool doDeletions){	bool		found = false;	DIR		   *cldir;	struct dirent *clde;	int			segno;	int			segpage;	char		path[MAXPGPATH];	/*	 * The cutoff point is the start of the segment containing cutoffPage.	 * (This is redundant when called from SimpleLruTruncate, but not when	 * called directly from clog.c.)	 */	cutoffPage -= cutoffPage % SLRU_PAGES_PER_SEGMENT;	cldir = AllocateDir(ctl->Dir);	while ((clde = ReadDir(cldir, ctl->Dir)) != NULL)	{		if (strlen(clde->d_name) == 4 &&			strspn(clde->d_name, "0123456789ABCDEF") == 4)		{			segno = (int) strtol(clde->d_name, NULL, 16);			segpage = segno * SLRU_PAGES_PER_SEGMENT;			if (ctl->PagePrecedes(segpage, cutoffPage))			{				found = true;				if (doDeletions)				{					snprintf(path, MAXPGPATH, "%s/%s", ctl->Dir, clde->d_name);					ereport(DEBUG2,							(errmsg("removing file \"%s\"", path)));					unlink(path);				}			}		}	}	FreeDir(cldir);	return found;}

⌨️ 快捷键说明

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