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

📄 slru.c

📁 postgresql8.3.4源码,开源数据库
💻 C
📖 第 1 页 / 共 3 页
字号:
			/* Otherwise, it's ready to use */			SlruRecentlyUsed(shared, slotno);			return slotno;		}		/* We found no match; assert we selected a freeable slot */		Assert(shared->page_status[slotno] == SLRU_PAGE_EMPTY ||			   (shared->page_status[slotno] == SLRU_PAGE_VALID &&				!shared->page_dirty[slotno]));		/* Mark the slot read-busy */		shared->page_number[slotno] = pageno;		shared->page_status[slotno] = SLRU_PAGE_READ_IN_PROGRESS;		shared->page_dirty[slotno] = false;		/* Acquire per-buffer lock (cannot deadlock, see notes at top) */		LWLockAcquire(shared->buffer_locks[slotno], LW_EXCLUSIVE);		/*		 * Temporarily mark page as recently-used to discourage		 * SlruSelectLRUPage from selecting it again for someone else.		 */		SlruRecentlyUsed(shared, slotno);		/* Release control lock while doing I/O */		LWLockRelease(shared->ControlLock);		/* Do the read */		ok = SlruPhysicalReadPage(ctl, pageno, slotno);		/* Set the LSNs for this newly read-in page to zero */		SimpleLruZeroLSNs(ctl, slotno);		/* Re-acquire control lock and update page state */		LWLockAcquire(shared->ControlLock, LW_EXCLUSIVE);		Assert(shared->page_number[slotno] == pageno &&			   shared->page_status[slotno] == SLRU_PAGE_READ_IN_PROGRESS &&			   !shared->page_dirty[slotno]);		shared->page_status[slotno] = ok ? SLRU_PAGE_VALID : SLRU_PAGE_EMPTY;		LWLockRelease(shared->buffer_locks[slotno]);		/* Now it's okay to ereport if we failed */		if (!ok)			SlruReportIOError(ctl, pageno, xid);		SlruRecentlyUsed(shared, slotno);		return slotno;	}}/* * Find a page in a shared buffer, reading it in if necessary. * The page number must correspond to an already-initialized page. * The caller must intend only read-only access to the page. * * The passed-in xid is used only for error reporting, and may be * InvalidTransactionId if no specific xid is associated with the action. * * Return value is the shared-buffer slot number now holding the page. * The buffer's LRU access info is updated. * * Control lock must NOT be held at entry, but will be held at exit. * It is unspecified whether the lock will be shared or exclusive. */intSimpleLruReadPage_ReadOnly(SlruCtl ctl, int pageno, TransactionId xid){	SlruShared	shared = ctl->shared;	int			slotno;	/* Try to find the page while holding only shared lock */	LWLockAcquire(shared->ControlLock, LW_SHARED);	/* See if page is already in a buffer */	for (slotno = 0; slotno < shared->num_slots; slotno++)	{		if (shared->page_number[slotno] == pageno &&			shared->page_status[slotno] != SLRU_PAGE_EMPTY &&			shared->page_status[slotno] != SLRU_PAGE_READ_IN_PROGRESS)		{			/* See comments for SlruRecentlyUsed macro */			SlruRecentlyUsed(shared, slotno);			return slotno;		}	}	/* No luck, so switch to normal exclusive lock and do regular read */	LWLockRelease(shared->ControlLock);	LWLockAcquire(shared->ControlLock, LW_EXCLUSIVE);	return SimpleLruReadPage(ctl, pageno, true, xid);}/* * Write a page from a shared buffer, if necessary. * Does nothing if the specified slot is not dirty. * * NOTE: only one write attempt is made here.  Hence, it is possible that * the page is still dirty at exit (if someone else re-dirtied it during * the write).	However, we *do* attempt a fresh write even if the page * is already being written; this is for checkpoints. * * Control lock must be held at entry, and will be held at exit. */voidSimpleLruWritePage(SlruCtl ctl, int slotno, SlruFlush fdata){	SlruShared	shared = ctl->shared;	int			pageno = shared->page_number[slotno];	bool		ok;	/* If a write is in progress, wait for it to finish */	while (shared->page_status[slotno] == SLRU_PAGE_WRITE_IN_PROGRESS &&		   shared->page_number[slotno] == pageno)	{		SimpleLruWaitIO(ctl, slotno);	}	/*	 * Do nothing if page is not dirty, or if buffer no longer contains the	 * same page we were called for.	 */	if (!shared->page_dirty[slotno] ||		shared->page_status[slotno] != SLRU_PAGE_VALID ||		shared->page_number[slotno] != pageno)		return;	/*	 * Mark the slot write-busy, and clear the dirtybit.  After this point, a	 * transaction status update on this page will mark it dirty again.	 */	shared->page_status[slotno] = SLRU_PAGE_WRITE_IN_PROGRESS;	shared->page_dirty[slotno] = false;	/* Acquire per-buffer lock (cannot deadlock, see notes at top) */	LWLockAcquire(shared->buffer_locks[slotno], LW_EXCLUSIVE);	/* Release control lock while doing I/O */	LWLockRelease(shared->ControlLock);	/* Do the write */	ok = SlruPhysicalWritePage(ctl, pageno, slotno, fdata);	/* If we failed, and we're in a flush, better close the files */	if (!ok && fdata)	{		int			i;		for (i = 0; i < fdata->num_files; i++)			close(fdata->fd[i]);	}	/* Re-acquire control lock and update page state */	LWLockAcquire(shared->ControlLock, LW_EXCLUSIVE);	Assert(shared->page_number[slotno] == pageno &&		   shared->page_status[slotno] == SLRU_PAGE_WRITE_IN_PROGRESS);	/* If we failed to write, mark the page dirty again */	if (!ok)		shared->page_dirty[slotno] = true;	shared->page_status[slotno] = SLRU_PAGE_VALID;	LWLockRelease(shared->buffer_locks[slotno]);	/* Now it's okay to ereport if we failed */	if (!ok)		SlruReportIOError(ctl, pageno, InvalidTransactionId);}/* * Physical read of a (previously existing) page into a buffer slot * * On failure, we cannot just ereport(ERROR) since caller has put state in * shared memory that must be undone.  So, we return FALSE and save enough * info in static variables to let SlruReportIOError make the report. * * For now, assume it's not worth keeping a file pointer open across * read/write operations.  We could cache one virtual file pointer ... */static boolSlruPhysicalReadPage(SlruCtl ctl, int pageno, int slotno){	SlruShared	shared = ctl->shared;	int			segno = pageno / SLRU_PAGES_PER_SEGMENT;	int			rpageno = pageno % SLRU_PAGES_PER_SEGMENT;	int			offset = rpageno * BLCKSZ;	char		path[MAXPGPATH];	int			fd;	SlruFileName(ctl, path, segno);	/*	 * In a crash-and-restart situation, it's possible for us to receive	 * commands to set the commit status of transactions whose bits are in	 * already-truncated segments of the commit log (see notes in	 * SlruPhysicalWritePage).	Hence, if we are InRecovery, allow the case	 * where the file doesn't exist, and return zeroes instead.	 */	fd = BasicOpenFile(path, O_RDWR | PG_BINARY, S_IRUSR | S_IWUSR);	if (fd < 0)	{		if (errno != ENOENT || !InRecovery)		{			slru_errcause = SLRU_OPEN_FAILED;			slru_errno = errno;			return false;		}		ereport(LOG,				(errmsg("file \"%s\" doesn't exist, reading as zeroes",						path)));		MemSet(shared->page_buffer[slotno], 0, BLCKSZ);		return true;	}	if (lseek(fd, (off_t) offset, SEEK_SET) < 0)	{		slru_errcause = SLRU_SEEK_FAILED;		slru_errno = errno;		close(fd);		return false;	}	errno = 0;	if (read(fd, shared->page_buffer[slotno], BLCKSZ) != BLCKSZ)	{		slru_errcause = SLRU_READ_FAILED;		slru_errno = errno;		close(fd);		return false;	}	if (close(fd))	{		slru_errcause = SLRU_CLOSE_FAILED;		slru_errno = errno;		return false;	}	return true;}/* * Physical write of a page from a buffer slot * * On failure, we cannot just ereport(ERROR) since caller has put state in * shared memory that must be undone.  So, we return FALSE and save enough * info in static variables to let SlruReportIOError make the report. * * For now, assume it's not worth keeping a file pointer open across * independent read/write operations.  We do batch operations during * SimpleLruFlush, though. * * fdata is NULL for a standalone write, pointer to open-file info during * SimpleLruFlush. */static boolSlruPhysicalWritePage(SlruCtl ctl, int pageno, int slotno, SlruFlush fdata){	SlruShared	shared = ctl->shared;	int			segno = pageno / SLRU_PAGES_PER_SEGMENT;	int			rpageno = pageno % SLRU_PAGES_PER_SEGMENT;	int			offset = rpageno * BLCKSZ;	char		path[MAXPGPATH];	int			fd = -1;	/*	 * Honor the write-WAL-before-data rule, if appropriate, so that we do not	 * write out data before associated WAL records.  This is the same action	 * performed during FlushBuffer() in the main buffer manager.	 */	if (shared->group_lsn != NULL)	{		/*		 * We must determine the largest async-commit LSN for the page. This		 * is a bit tedious, but since this entire function is a slow path		 * anyway, it seems better to do this here than to maintain a per-page		 * LSN variable (which'd need an extra comparison in the		 * transaction-commit path).		 */		XLogRecPtr	max_lsn;		int			lsnindex,					lsnoff;		lsnindex = slotno * shared->lsn_groups_per_page;		max_lsn = shared->group_lsn[lsnindex++];		for (lsnoff = 1; lsnoff < shared->lsn_groups_per_page; lsnoff++)		{			XLogRecPtr	this_lsn = shared->group_lsn[lsnindex++];			if (XLByteLT(max_lsn, this_lsn))				max_lsn = this_lsn;		}		if (!XLogRecPtrIsInvalid(max_lsn))		{			/*			 * As noted above, elog(ERROR) is not acceptable here, so if			 * XLogFlush were to fail, we must PANIC.  This isn't much of a			 * restriction because XLogFlush is just about all critical			 * section anyway, but let's make sure.			 */			START_CRIT_SECTION();			XLogFlush(max_lsn);			END_CRIT_SECTION();		}	}	/*	 * During a Flush, we may already have the desired file open.	 */	if (fdata)	{		int			i;		for (i = 0; i < fdata->num_files; i++)		{			if (fdata->segno[i] == segno)			{				fd = fdata->fd[i];				break;			}		}	}	if (fd < 0)	{		/*		 * If the file doesn't already exist, we should create it.  It is		 * possible for this to need to happen when writing a page that's not		 * first in its segment; we assume the OS can cope with that. (Note:		 * it might seem that it'd be okay to create files only when		 * SimpleLruZeroPage is called for the first page of a segment.		 * However, if after a crash and restart the REDO logic elects to		 * replay the log from a checkpoint before the latest one, then it's		 * possible that we will get commands to set transaction status of		 * transactions that have already been truncated from the commit log.		 * Easiest way to deal with that is to accept references to		 * nonexistent files here and in SlruPhysicalReadPage.)		 *		 * Note: it is possible for more than one backend to be executing this		 * code simultaneously for different pages of the same file. Hence,		 * don't use O_EXCL or O_TRUNC or anything like that.		 */		SlruFileName(ctl, path, segno);		fd = BasicOpenFile(path, O_RDWR | O_CREAT | PG_BINARY,						   S_IRUSR | S_IWUSR);		if (fd < 0)		{			slru_errcause = SLRU_OPEN_FAILED;			slru_errno = errno;			return false;		}		if (fdata)		{			if (fdata->num_files < MAX_FLUSH_BUFFERS)			{				fdata->fd[fdata->num_files] = fd;				fdata->segno[fdata->num_files] = segno;				fdata->num_files++;			}			else			{				/*				 * In the unlikely event that we exceed MAX_FLUSH_BUFFERS,				 * fall back to treating it as a standalone write.				 */				fdata = NULL;			}		}	}	if (lseek(fd, (off_t) offset, SEEK_SET) < 0)	{		slru_errcause = SLRU_SEEK_FAILED;		slru_errno = errno;		if (!fdata)			close(fd);		return false;	}	errno = 0;	if (write(fd, shared->page_buffer[slotno], BLCKSZ) != BLCKSZ)	{		/* if write didn't set errno, assume problem is no disk space */		if (errno == 0)			errno = ENOSPC;		slru_errcause = SLRU_WRITE_FAILED;		slru_errno = errno;		if (!fdata)			close(fd);		return false;	}

⌨️ 快捷键说明

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