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

📄 xlog.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 5 页
字号:
 * * use_lock: if TRUE, acquire ControlFileLock while moving file into * place.  This should be TRUE except during bootstrap log creation.  The * caller must *not* hold the lock at call. * * Returns FD of opened file. * * Note: errors here are ERROR not PANIC because we might or might not be * inside a critical section (eg, during checkpoint there is no reason to * take down the system on failure).  They will promote to PANIC if we are * in a critical section. */static intXLogFileInit(uint32 log, uint32 seg,			 bool *use_existent, bool use_lock){	char		path[MAXPGPATH];	char		tmppath[MAXPGPATH];	char		zbuffer[BLCKSZ];	uint32		installed_log;	uint32		installed_seg;	int			max_advance;	int			fd;	int			nbytes;	XLogFilePath(path, ThisTimeLineID, log, seg);	/*	 * Try to use existent file (checkpoint maker may have created it already)	 */	if (*use_existent)	{		fd = BasicOpenFile(path, O_RDWR | PG_BINARY | XLOG_SYNC_BIT,						   S_IRUSR | S_IWUSR);		if (fd < 0)		{			if (errno != ENOENT)				ereport(ERROR,						(errcode_for_file_access(),						 errmsg("could not open file \"%s\" (log file %u, segment %u): %m",								path, log, seg)));		}		else			return (fd);	}	/*	 * Initialize an empty (all zeroes) segment.  NOTE: it is possible that	 * another process is doing the same thing.  If so, we will end up	 * pre-creating an extra log segment.  That seems OK, and better than	 * holding the lock throughout this lengthy process.	 */	snprintf(tmppath, MAXPGPATH, XLOGDIR "/xlogtemp.%d", (int) getpid());	unlink(tmppath);	/* do not use XLOG_SYNC_BIT here --- want to fsync only at end of fill */	fd = BasicOpenFile(tmppath, O_RDWR | O_CREAT | O_EXCL | PG_BINARY,					   S_IRUSR | S_IWUSR);	if (fd < 0)		ereport(ERROR,				(errcode_for_file_access(),				 errmsg("could not create file \"%s\": %m", tmppath)));	/*	 * Zero-fill the file.	We have to do this the hard way to ensure that all	 * the file space has really been allocated --- on platforms that allow	 * "holes" in files, just seeking to the end doesn't allocate intermediate	 * space.  This way, we know that we have all the space and (after the	 * fsync below) that all the indirect blocks are down on disk.	Therefore,	 * fdatasync(2) or O_DSYNC will be sufficient to sync future writes to the	 * log file.	 */	MemSet(zbuffer, 0, sizeof(zbuffer));	for (nbytes = 0; nbytes < XLogSegSize; nbytes += sizeof(zbuffer))	{		errno = 0;		if ((int) write(fd, zbuffer, sizeof(zbuffer)) != (int) sizeof(zbuffer))		{			int			save_errno = errno;			/*			 * If we fail to make the file, delete it to release disk space			 */			unlink(tmppath);			/* if write didn't set errno, assume problem is no disk space */			errno = save_errno ? save_errno : ENOSPC;			ereport(ERROR,					(errcode_for_file_access(),					 errmsg("could not write to file \"%s\": %m", tmppath)));		}	}	if (pg_fsync(fd) != 0)		ereport(ERROR,				(errcode_for_file_access(),				 errmsg("could not fsync file \"%s\": %m", tmppath)));	if (close(fd))		ereport(ERROR,				(errcode_for_file_access(),				 errmsg("could not close file \"%s\": %m", tmppath)));	/*	 * Now move the segment into place with its final name.	 *	 * If caller didn't want to use a pre-existing file, get rid of any	 * pre-existing file.  Otherwise, cope with possibility that someone else	 * has created the file while we were filling ours: if so, use ours to	 * pre-create a future log segment.	 */	installed_log = log;	installed_seg = seg;	max_advance = XLOGfileslop;	if (!InstallXLogFileSegment(&installed_log, &installed_seg, tmppath,								*use_existent, &max_advance,								use_lock))	{		/* No need for any more future segments... */		unlink(tmppath);	}	/* Set flag to tell caller there was no existent file */	*use_existent = false;	/* Now open original target segment (might not be file I just made) */	fd = BasicOpenFile(path, O_RDWR | PG_BINARY | XLOG_SYNC_BIT,					   S_IRUSR | S_IWUSR);	if (fd < 0)		ereport(ERROR,				(errcode_for_file_access(),		   errmsg("could not open file \"%s\" (log file %u, segment %u): %m",				  path, log, seg)));	return (fd);}/* * Create a new XLOG file segment by copying a pre-existing one. * * log, seg: identify segment to be created. * * srcTLI, srclog, srcseg: identify segment to be copied (could be from *		a different timeline) * * Currently this is only used during recovery, and so there are no locking * considerations.	But we should be just as tense as XLogFileInit to avoid * emplacing a bogus file. */static voidXLogFileCopy(uint32 log, uint32 seg,			 TimeLineID srcTLI, uint32 srclog, uint32 srcseg){	char		path[MAXPGPATH];	char		tmppath[MAXPGPATH];	char		buffer[BLCKSZ];	int			srcfd;	int			fd;	int			nbytes;	/*	 * Open the source file	 */	XLogFilePath(path, srcTLI, srclog, srcseg);	srcfd = BasicOpenFile(path, O_RDONLY | PG_BINARY, 0);	if (srcfd < 0)		ereport(ERROR,				(errcode_for_file_access(),				 errmsg("could not open file \"%s\": %m", path)));	/*	 * Copy into a temp file name.	 */	snprintf(tmppath, MAXPGPATH, XLOGDIR "/xlogtemp.%d", (int) getpid());	unlink(tmppath);	/* do not use XLOG_SYNC_BIT here --- want to fsync only at end of fill */	fd = BasicOpenFile(tmppath, O_RDWR | O_CREAT | O_EXCL | PG_BINARY,					   S_IRUSR | S_IWUSR);	if (fd < 0)		ereport(ERROR,				(errcode_for_file_access(),				 errmsg("could not create file \"%s\": %m", tmppath)));	/*	 * Do the data copying.	 */	for (nbytes = 0; nbytes < XLogSegSize; nbytes += sizeof(buffer))	{		errno = 0;		if ((int) read(srcfd, buffer, sizeof(buffer)) != (int) sizeof(buffer))		{			if (errno != 0)				ereport(ERROR,						(errcode_for_file_access(),						 errmsg("could not read file \"%s\": %m", path)));			else				ereport(ERROR,						(errmsg("not enough data in file \"%s\"", path)));		}		errno = 0;		if ((int) write(fd, buffer, sizeof(buffer)) != (int) sizeof(buffer))		{			int			save_errno = errno;			/*			 * If we fail to make the file, delete it to release disk space			 */			unlink(tmppath);			/* if write didn't set errno, assume problem is no disk space */			errno = save_errno ? save_errno : ENOSPC;			ereport(ERROR,					(errcode_for_file_access(),					 errmsg("could not write to file \"%s\": %m", tmppath)));		}	}	if (pg_fsync(fd) != 0)		ereport(ERROR,				(errcode_for_file_access(),				 errmsg("could not fsync file \"%s\": %m", tmppath)));	if (close(fd))		ereport(ERROR,				(errcode_for_file_access(),				 errmsg("could not close file \"%s\": %m", tmppath)));	close(srcfd);	/*	 * Now move the segment into place with its final name.	 */	if (!InstallXLogFileSegment(&log, &seg, tmppath, false, NULL, false))		elog(ERROR, "InstallXLogFileSegment should not have failed");}/* * Install a new XLOG segment file as a current or future log segment. * * This is used both to install a newly-created segment (which has a temp * filename while it's being created) and to recycle an old segment. * * *log, *seg: identify segment to install as (or first possible target). * When find_free is TRUE, these are modified on return to indicate the * actual installation location or last segment searched. * * tmppath: initial name of file to install.  It will be renamed into place. * * find_free: if TRUE, install the new segment at the first empty log/seg * number at or after the passed numbers.  If FALSE, install the new segment * exactly where specified, deleting any existing segment file there. * * *max_advance: maximum number of log/seg slots to advance past the starting * point.  Fail if no free slot is found in this range.  On return, reduced * by the number of slots skipped over.  (Irrelevant, and may be NULL, * when find_free is FALSE.) * * use_lock: if TRUE, acquire ControlFileLock while moving file into * place.  This should be TRUE except during bootstrap log creation.  The * caller must *not* hold the lock at call. * * Returns TRUE if file installed, FALSE if not installed because of * exceeding max_advance limit.  (Any other kind of failure causes ereport().) */static boolInstallXLogFileSegment(uint32 *log, uint32 *seg, char *tmppath,					   bool find_free, int *max_advance,					   bool use_lock){	char		path[MAXPGPATH];	struct stat stat_buf;	XLogFilePath(path, ThisTimeLineID, *log, *seg);	/*	 * We want to be sure that only one process does this at a time.	 */	if (use_lock)		LWLockAcquire(ControlFileLock, LW_EXCLUSIVE);	if (!find_free)	{		/* Force installation: get rid of any pre-existing segment file */		unlink(path);	}	else	{		/* Find a free slot to put it in */		while (stat(path, &stat_buf) == 0)		{			if (*max_advance <= 0)			{				/* Failed to find a free slot within specified range */				if (use_lock)					LWLockRelease(ControlFileLock);				return false;			}			NextLogSeg(*log, *seg);			(*max_advance)--;			XLogFilePath(path, ThisTimeLineID, *log, *seg);		}	}	/*	 * Prefer link() to rename() here just to be really sure that we don't	 * overwrite an existing logfile.  However, there shouldn't be one, so	 * rename() is an acceptable substitute except for the truly paranoid.	 */#if HAVE_WORKING_LINK	if (link(tmppath, path) < 0)		ereport(ERROR,				(errcode_for_file_access(),				 errmsg("could not link file \"%s\" to \"%s\" (initialization of log file %u, segment %u): %m",						tmppath, path, *log, *seg)));	unlink(tmppath);#else	if (rename(tmppath, path) < 0)		ereport(ERROR,				(errcode_for_file_access(),				 errmsg("could not rename file \"%s\" to \"%s\" (initialization of log file %u, segment %u): %m",						tmppath, path, *log, *seg)));#endif	if (use_lock)		LWLockRelease(ControlFileLock);	return true;}/* * Open a pre-existing logfile segment for writing. */static intXLogFileOpen(uint32 log, uint32 seg){	char		path[MAXPGPATH];	int			fd;	XLogFilePath(path, ThisTimeLineID, log, seg);	fd = BasicOpenFile(path, O_RDWR | PG_BINARY | XLOG_SYNC_BIT,					   S_IRUSR | S_IWUSR);	if (fd < 0)		ereport(PANIC,				(errcode_for_file_access(),		   errmsg("could not open file \"%s\" (log file %u, segment %u): %m",				  path, log, seg)));	return fd;}/* * Open a logfile segment for reading (during recovery). */static intXLogFileRead(uint32 log, uint32 seg, int emode){	char		path[MAXPGPATH];	char		xlogfname[MAXFNAMELEN];	ListCell   *cell;	int			fd;	/*	 * Loop looking for a suitable timeline ID: we might need to read any of	 * the timelines listed in expectedTLIs.	 *	 * We expect curFileTLI on entry to be the TLI of the preceding file in	 * sequence, or 0 if there was no predecessor.	We do not allow curFileTLI	 * to go backwards; this prevents us from picking up the wrong file when a	 * parent timeline extends to higher segment numbers than the child we	 * want to read.	 */	foreach(cell, expectedTLIs)	{		TimeLineID	tli = (TimeLineID) lfirst_int(cell);		if (tli < curFileTLI)			break;				/* don't bother looking at too-old TLIs */		if (InArchiveRecovery)		{			XLogFileName(xlogfname, tli, log, seg);			restoredFromArchive = RestoreArchivedFile(path, xlogfname,													  "RECOVERYXLOG",													  XLogSegSize);		}		else			XLogFilePath(path, tli, log, seg);		fd = BasicOpenFile(path, O_RDONLY | PG_BINARY, 0);		if (fd >= 0)		{			/* Success! */			curFileTLI = tli;			return fd;		}		if (errno != ENOENT)	/* unexpected failure? */			ereport(PANIC,					(errcode_for_file_access(),			errmsg("could not open file \"%s\" (log file %u, segment %u): %m",				   path, log, seg)));	}	/* Couldn't find it.  For simplicity, complain about front timeline */	XLogFilePath(path, recoveryTargetTLI, log, seg);	errno = ENOENT;	ereport(emode,			(errcode_for_file_access(),		   errmsg("could not open file \"%s\" (log file %u, segment %u): %m",				  path, log, seg)));	return -1;}/* * Attempt to retrieve the specified file from off-line archival storage. * If successful, fill "path" with its complete path (note that this will be * a temp file name that doesn't follow the normal naming convention), and * return TRUE. * * If not successful, fill "path" with the name of the norm

⌨️ 快捷键说明

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