Example #1
0
/*
 * Write out the new pg_control file.
 */
static void
RewriteControlFile(void)
{
	int			fd;
	char		buffer[PG_CONTROL_SIZE];		/* need not be aligned */

	/*
	 * Adjust fields as needed to force an empty XLOG starting at the next
	 * available segment.
	 */
	newXlogId = ControlFile.logId;
	newXlogSeg = ControlFile.logSeg;

	/* adjust in case we are changing segment size */
	newXlogSeg *= ControlFile.xlog_seg_size;
	newXlogSeg = (newXlogSeg + XLogSegSize - 1) / XLogSegSize;

	/* be sure we wrap around correctly at end of a logfile */
	NextLogSeg(newXlogId, newXlogSeg);

	/* Now we can force the recorded xlog seg size to the right thing. */
	ControlFile.xlog_seg_size = XLogSegSize;

	ControlFile.checkPointCopy.redo.xlogid = newXlogId;
	ControlFile.checkPointCopy.redo.xrecoff =
		newXlogSeg * XLogSegSize + SizeOfXLogLongPHD;
	ControlFile.checkPointCopy.time = (pg_time_t) time(NULL);

	ControlFile.state = DB_SHUTDOWNED;
	ControlFile.time = (pg_time_t) time(NULL);
	ControlFile.checkPoint = ControlFile.checkPointCopy.redo;
	ControlFile.prevCheckPoint.xlogid = 0;
	ControlFile.prevCheckPoint.xrecoff = 0;
	ControlFile.minRecoveryPoint.xlogid = 0;
	ControlFile.minRecoveryPoint.xrecoff = 0;

	/* Contents are protected with a CRC */
	INIT_CRC32C(ControlFile.crc);
	COMP_CRC32C(ControlFile.crc, &ControlFile, offsetof(ControlFileData, crc));
	FIN_CRC32C(ControlFile.crc);
	/*
	INIT_LEGACY_CRC32(ControlFile.crc);
	COMP_LEGACY_CRC32(ControlFile.crc,
			   (char *) &ControlFile,
			   offsetof(ControlFileData, crc));
	FIN_LEGACY_CRC32(ControlFile.crc);
	*/

	/*
	 * We write out PG_CONTROL_SIZE bytes into pg_control, zero-padding the
	 * excess over sizeof(ControlFileData).  This reduces the odds of
	 * premature-EOF errors when reading pg_control.  We'll still fail when we
	 * check the contents of the file, but hopefully with a more specific
	 * error than "couldn't read pg_control".
	 */
	if (sizeof(ControlFileData) > PG_CONTROL_SIZE)
	{
		fprintf(stderr,
				_("%s: internal error -- sizeof(ControlFileData) is too large ... fix PG_CONTROL_SIZE\n"),
				progname);
		exit(1);
	}

	memset(buffer, 0, PG_CONTROL_SIZE);
	memcpy(buffer, &ControlFile, sizeof(ControlFileData));

	unlink(XLOG_CONTROL_FILE);

	fd = open(XLOG_CONTROL_FILE,
			  O_RDWR | O_CREAT | O_EXCL | PG_BINARY,
			  S_IRUSR | S_IWUSR);
	if (fd < 0)
	{
		fprintf(stderr, _("%s: could not create pg_control file: %s\n"),
				progname, strerror(errno));
		exit(1);
	}

	errno = 0;
	if (write(fd, buffer, PG_CONTROL_SIZE) != PG_CONTROL_SIZE)
	{
		/* if write didn't set errno, assume problem is no disk space */
		if (errno == 0)
			errno = ENOSPC;
		fprintf(stderr, _("%s: could not write pg_control file: %s\n"),
				progname, strerror(errno));
		exit(1);
	}

	if (fsync(fd) != 0)
	{
		fprintf(stderr, _("%s: fsync error: %s\n"), progname, strerror(errno));
		exit(1);
	}

	close(fd);
}
Example #2
0
/*
 * Determine starting location for streaming, based on:
 * 1. If there are existing xlog segments, start at the end of the last one
 *	  that is complete (size matches XLogSegSize)
 * 2. If no valid xlog exists, start from the beginning of the current
 *	  WAL segment.
 */
static XLogRecPtr
FindStreamingStart(XLogRecPtr currentpos, uint32 currenttimeline)
{
	DIR		   *dir;
	struct dirent *dirent;
	int			i;
	bool		b;
	uint32		high_log = 0;
	uint32		high_seg = 0;

	dir = opendir(basedir);
	if (dir == NULL)
	{
		fprintf(stderr, _("%s: could not open directory \"%s\": %s\n"),
				progname, basedir, strerror(errno));
		disconnect_and_exit(1);
	}

	while ((dirent = readdir(dir)) != NULL)
	{
		char		fullpath[MAXPGPATH];
		struct stat statbuf;
		uint32		tli,
					log,
					seg;

		if (strcmp(dirent->d_name, ".") == 0 ||
			strcmp(dirent->d_name, "..") == 0)
			continue;

		/* xlog files are always 24 characters */
		if (strlen(dirent->d_name) != 24)
			continue;

		/* Filenames are always made out of 0-9 and A-F */
		b = false;
		for (i = 0; i < 24; i++)
		{
			if (!(dirent->d_name[i] >= '0' && dirent->d_name[i] <= '9') &&
				!(dirent->d_name[i] >= 'A' && dirent->d_name[i] <= 'F'))
			{
				b = true;
				break;
			}
		}
		if (b)
			continue;

		/*
		 * Looks like an xlog file. Parse its position.
		 */
		if (sscanf(dirent->d_name, "%08X%08X%08X", &tli, &log, &seg) != 3)
		{
			fprintf(stderr,
				 _("%s: could not parse transaction log file name \"%s\"\n"),
					progname, dirent->d_name);
			disconnect_and_exit(1);
		}

		/* Ignore any files that are for another timeline */
		if (tli != currenttimeline)
			continue;

		/* Check if this is a completed segment or not */
		snprintf(fullpath, sizeof(fullpath), "%s/%s", basedir, dirent->d_name);
		if (stat(fullpath, &statbuf) != 0)
		{
			fprintf(stderr, _("%s: could not stat file \"%s\": %s\n"),
					progname, fullpath, strerror(errno));
			disconnect_and_exit(1);
		}

		if (statbuf.st_size == XLOG_SEG_SIZE)
		{
			/* Completed segment */
			if (log > high_log ||
				(log == high_log && seg > high_seg))
			{
				high_log = log;
				high_seg = seg;
				continue;
			}
		}
		else
		{
			fprintf(stderr,
			  _("%s: segment file \"%s\" has incorrect size %d, skipping\n"),
					progname, dirent->d_name, (int) statbuf.st_size);
			continue;
		}
	}

	closedir(dir);

	if (high_log > 0 || high_seg > 0)
	{
		XLogRecPtr	high_ptr;

		/*
		 * Move the starting pointer to the start of the next segment, since
		 * the highest one we've seen was completed.
		 */
		NextLogSeg(high_log, high_seg);

		high_ptr.xlogid = high_log;
		high_ptr.xrecoff = high_seg * XLOG_SEG_SIZE;

		return high_ptr;
	}
	else
		return currentpos;
}
Example #3
0
/*
 * Scan existing XLOG files and determine the highest existing WAL address
 *
 * On entry, ControlFile.checkPointCopy.redo and ControlFile.xlog_seg_size
 * are assumed valid (note that we allow the old xlog seg size to differ
 * from what we're using).  On exit, newXlogId and newXlogSeg are set to
 * suitable values for the beginning of replacement WAL (in our seg size).
 */
static void
FindEndOfXLOG(void)
{
	DIR		   *xldir;
	struct dirent *xlde;

	/*
	 * Initialize the max() computation using the last checkpoint address
	 * from old pg_control.  Note that for the moment we are working with
	 * segment numbering according to the old xlog seg size.
	 */
	newXlogId = ControlFile.checkPointCopy.redo.xlogid;
	newXlogSeg = ControlFile.checkPointCopy.redo.xrecoff / ControlFile.xlog_seg_size;

	/*
	 * Scan the pg_xlog directory to find existing WAL segment files.
	 * We assume any present have been used; in most scenarios this should
	 * be conservative, because of xlog.c's attempts to pre-create files.
	 */
	xldir = opendir(XLOGDIR);
	if (xldir == NULL)
	{
		fprintf(stderr, _("%s: could not open directory \"%s\": %s\n"),
				progname, XLOGDIR, strerror(errno));
		exit(1);
	}

	errno = 0;
	while ((xlde = readdir(xldir)) != NULL)
	{
		if (strlen(xlde->d_name) == 24 &&
			strspn(xlde->d_name, "0123456789ABCDEF") == 24)
		{
			unsigned int	tli,
							log,
							seg;

			sscanf(xlde->d_name, "%08X%08X%08X", &tli, &log, &seg);
			/*
			 * Note: we take the max of all files found, regardless of their
			 * timelines.  Another possibility would be to ignore files of
			 * timelines other than the target TLI, but this seems safer.
			 * Better too large a result than too small...
			 */
			if (log > newXlogId ||
				(log == newXlogId && seg > newXlogSeg))
			{
				newXlogId = log;
				newXlogSeg = seg;
			}
		}
		errno = 0;
	}
#ifdef WIN32

	/*
	 * This fix is in mingw cvs (runtime/mingwex/dirent.c rev 1.4), but not in
	 * released version
	 */
	if (GetLastError() == ERROR_NO_MORE_FILES)
		errno = 0;
#endif

	if (errno)
	{
		fprintf(stderr, _("%s: could not read from directory \"%s\": %s\n"),
				progname, XLOGDIR, strerror(errno));
		exit(1);
	}
	closedir(xldir);

	/*
	 * Finally, convert to new xlog seg size, and advance by one to ensure
	 * we are in virgin territory.
	 */
	newXlogSeg *= ControlFile.xlog_seg_size;
	newXlogSeg = (newXlogSeg + XLogSegSize - 1) / XLogSegSize;

	/* be sure we wrap around correctly at end of a logfile */
	NextLogSeg(newXlogId, newXlogSeg);
}