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

📄 xlog.c

📁 PostgreSQL7.4.6 for Linux
💻 C
📖 第 1 页 / 共 5 页
字号:
	 * bad LSN on a data page.	 */	if (XLByteLT(LogwrtResult.Flush, record))		elog(InRecovery ? WARNING : ERROR,			 "xlog flush request %X/%X is not satisfied --- flushed only to %X/%X",			 record.xlogid, record.xrecoff,			 LogwrtResult.Flush.xlogid, LogwrtResult.Flush.xrecoff);}/* * Create a new XLOG file segment, or open a pre-existing one. * * log, seg: identify segment to be created/opened. * * *use_existent: if TRUE, OK to use a pre-existing file (else, any * pre-existing file will be deleted).	On return, TRUE if a pre-existing * file was used. * * 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. */static intXLogFileInit(uint32 log, uint32 seg,			 bool *use_existent, bool use_lock){	char		path[MAXPGPATH];	char		tmppath[MAXPGPATH];	char		zbuffer[BLCKSZ];	int			fd;	int			nbytes;	XLogFileName(path, 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(PANIC,						(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, "%s/xlogtemp.%d",			 XLogDir, (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(PANIC,				(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(PANIC,					(errcode_for_file_access(),					 errmsg("could not write to file \"%s\": %m", tmppath)));		}	}	if (pg_fsync(fd) != 0)		ereport(PANIC,				(errcode_for_file_access(),				 errmsg("could not fsync file \"%s\": %m", tmppath)));	close(fd);	/*	 * 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.	 */	if (!InstallXLogFileSegment(log, seg, tmppath,								*use_existent, XLOGfileslop,								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(PANIC,				(errcode_for_file_access(),			errmsg("could not open file \"%s\" (log file %u, segment %u): %m",				   path, log, seg)));	return (fd);}/* * 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). * * 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.  (Irrelevant if * 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;	XLogFileName(path, 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);			XLogFileName(path, 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(PANIC,				(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(PANIC,				(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. */static intXLogFileOpen(uint32 log, uint32 seg, bool econt){	char		path[MAXPGPATH];	int			fd;	XLogFileName(path, log, seg);	fd = BasicOpenFile(path, O_RDWR | PG_BINARY | XLOG_SYNC_BIT,					   S_IRUSR | S_IWUSR);	if (fd < 0)	{		if (econt && errno == ENOENT)		{			ereport(LOG,					(errcode_for_file_access(),			errmsg("could not open file \"%s\" (log file %u, segment %u): %m",				   path, log, seg)));			return (fd);		}		ereport(PANIC,				(errcode_for_file_access(),			errmsg("could not open file \"%s\" (log file %u, segment %u): %m",				   path, log, seg)));	}	return (fd);}/* * Preallocate log files beyond the specified log endpoint, according to * the XLOGfile user parameter. */static voidPreallocXlogFiles(XLogRecPtr endptr){	uint32		_logId;	uint32		_logSeg;	int			lf;	bool		use_existent;	XLByteToPrevSeg(endptr, _logId, _logSeg);	if ((endptr.xrecoff - 1) % XLogSegSize >=		(uint32) (0.75 * XLogSegSize))	{		NextLogSeg(_logId, _logSeg);		use_existent = true;		lf = XLogFileInit(_logId, _logSeg, &use_existent, true);		close(lf);	}}/* * Remove or move offline all log files older or equal to passed log/seg# * * endptr is current (or recent) end of xlog; this is used to determine * whether we want to recycle rather than delete no-longer-wanted log files. */static voidMoveOfflineLogs(uint32 log, uint32 seg, XLogRecPtr endptr){	uint32		endlogId;	uint32		endlogSeg;	DIR		   *xldir;	struct dirent *xlde;	char		lastoff[32];	char		path[MAXPGPATH];	XLByteToPrevSeg(endptr, endlogId, endlogSeg);	xldir = AllocateDir(XLogDir);	if (xldir == NULL)		ereport(ERROR,				(errcode_for_file_access(),			errmsg("could not open transaction log directory \"%s\": %m",				   XLogDir)));	sprintf(lastoff, "%08X%08X", log, seg);	errno = 0;	while ((xlde = readdir(xldir)) != NULL)	{		if (strlen(xlde->d_name) == 16 &&			strspn(xlde->d_name, "0123456789ABCDEF") == 16 &&			strcmp(xlde->d_name, lastoff) <= 0)		{			snprintf(path, MAXPGPATH, "%s/%s", XLogDir, xlde->d_name);			if (XLOG_archive_dir[0])			{				ereport(LOG,						(errmsg("archiving transaction log file \"%s\"",								xlde->d_name)));				elog(WARNING, "archiving log files is not implemented");			}			else			{				/*				 * Before deleting the file, see if it can be recycled as				 * a future log segment.  We allow recycling segments up				 * to XLOGfileslop segments beyond the current XLOG				 * location.				 */				if (InstallXLogFileSegment(endlogId, endlogSeg, path,										   true, XLOGfileslop,										   true))				{					ereport(LOG,						  (errmsg("recycled transaction log file \"%s\"",								  xlde->d_name)));				}				else				{					/* No need for any more future segments... */					ereport(LOG,						  (errmsg("removing transaction log file \"%s\"",								  xlde->d_name)));					unlink(path);				}			}		}		errno = 0;	}	if (errno)		ereport(ERROR,				(errcode_for_file_access(),			errmsg("could not read transaction log directory \"%s\": %m",				   XLogDir)));	FreeDir(xldir);}/* * Restore the backup blocks present in an XLOG record, if any. * * We assume all of the record has been read into memory at *record. */static voidRestoreBkpBlocks(XLogRecord *record, XLogRecPtr lsn){	Relation	reln;	Buffer		buffer;	Page		page;	BkpBlock	bkpb;	char	   *blk;	int			i;	blk = (char *) XLogRecGetData(record) + record->xl_len;	for (i = 0; i < XLR_MAX_BKP_BLOCKS; i++)	{		if (!(record->xl_info & XLR_SET_BKP_BLOCK(i)))			continue;		memcpy((char *) &bkpb, blk, sizeof(BkpBlock));		blk += sizeof(BkpBlock);		reln = XLogOpenRelation(true, record->xl_rmid, bkpb.node);		if (reln)		{			buffer = XLogReadBuffer(true, reln, bkpb.block);			if (BufferIsValid(buffer))			{				page = (Page) BufferGetPage(buffer);				memcpy((char *) page, blk, BLCKSZ);				PageSetLSN(page, lsn);				PageSetSUI(page, ThisStartUpID);				UnlockAndWriteBuffer(buffer);			}		}		blk += BLCKSZ;	}}/* * CRC-check an XLOG record.  We do not believe the contents of an XLOG * record (other than to the minimal extent of computing the amount of * data to read in) until we've checked the CRCs. * * We assume all of the record has been read into memory at *record. */static boolRecordIsValid(XLogRecord *record, XLogRecPtr recptr, int emode){	crc64		crc;	crc64		cbuf;	int			i;	uint32		len = record->xl_len;	char	   *blk;	/* Check CRC of rmgr data and record header */	INIT_CRC64(crc);	COMP_CRC64(crc, XLogRecGetData(record), len);	COMP_CRC64(crc, (char *) record + sizeof(crc64),			   SizeOfXLogRecord - sizeof(crc64));	FIN_CRC64(crc);	if (!EQ_CRC64(record->xl_crc, crc))	{		ereport(emode,		 (errmsg("incorrect resource manager data checksum in record at %X/%X",				 recptr.xlogid, recptr.xrecoff)));

⌨️ 快捷键说明

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