コード例 #1
0
ファイル: pg_archivecleanup.c プロジェクト: jmickeyd/postgres
/*
 * SetWALFileNameForCleanup()
 *
 *	  Set the earliest WAL filename that we want to keep on the archive
 *	  and decide whether we need_cleanup
 */
static void
SetWALFileNameForCleanup(void)
{
	bool		fnameOK = false;

	TrimExtension(restartWALFileName, additional_ext);

	/*
	 * If restartWALFileName is a WAL file name then just use it directly. If
	 * restartWALFileName is a .backup filename, make sure we use the prefix
	 * of the filename, otherwise we will remove wrong files since
	 * 000000010000000000000010.00000020.backup is after
	 * 000000010000000000000010.
	 */
	if (IsXLogFileName(restartWALFileName))
	{
		strcpy(exclusiveCleanupFileName, restartWALFileName);
		fnameOK = true;
	}
	else if (IsBackupHistoryFileName(restartWALFileName))
	{
		int			args;
		uint32		tli = 1,
					log = 0,
					seg = 0,
					offset = 0;

		args = sscanf(restartWALFileName, "%08X%08X%08X.%08X.backup", &tli, &log, &seg, &offset);
		if (args == 4)
		{
			fnameOK = true;

			/*
			 * Use just the prefix of the filename, ignore everything after
			 * first period
			 */
			XLogFileNameById(exclusiveCleanupFileName, tli, log, seg);
		}
	}

	if (!fnameOK)
	{
		fprintf(stderr, "%s: invalid filename input\n", progname);
		fprintf(stderr, "Try \"%s --help\" for more information.\n", progname);
		exit(2);
	}
}
コード例 #2
0
ファイル: pg_resetxlog.c プロジェクト: bocap/postgres
/*
 * Remove existing XLOG files
 */
static void
KillExistingXLOG(void)
{
	DIR		   *xldir;
	struct dirent *xlde;
	char		path[MAXPGPATH];

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

	while (errno = 0, (xlde = readdir(xldir)) != NULL)
	{
		if (IsXLogFileName(xlde->d_name) ||
			IsPartialXLogFileName(xlde->d_name))
		{
			snprintf(path, MAXPGPATH, "%s/%s", XLOGDIR, xlde->d_name);
			if (unlink(path) < 0)
			{
				fprintf(stderr, _("%s: could not delete file \"%s\": %s\n"),
						progname, path, strerror(errno));
				exit(1);
			}
		}
	}

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

	if (closedir(xldir))
	{
		fprintf(stderr, _("%s: could not close directory \"%s\": %s\n"),
				progname, XLOGDIR, strerror(errno));
		exit(1);
	}
}
コード例 #3
0
static void
CleanupPriorWALFiles(void)
{
	int			rc;
	DIR		   *xldir;
	struct dirent *xlde;
	char		walfile[MAXPGPATH];

	if ((xldir = opendir(archiveLocation)) != NULL)
	{
		while (errno = 0, (xlde = readdir(xldir)) != NULL)
		{
			/*
			 * Truncation is essentially harmless, because we skip names of
			 * length other than XLOG_FNAME_LEN.  (In principle, one
			 * could use a 1000-character additional_ext and get trouble.)
			 */
			strlcpy(walfile, xlde->d_name, MAXPGPATH);
			TrimExtension(walfile, additional_ext);

			/*
			 * We ignore the timeline part of the XLOG segment identifiers in
			 * deciding whether a segment is still needed.  This ensures that
			 * we won't prematurely remove a segment from a parent timeline.
			 * We could probably be a little more proactive about removing
			 * segments of non-parent timelines, but that would be a whole lot
			 * more complicated.
			 *
			 * We use the alphanumeric sorting property of the filenames to
			 * decide which ones are earlier than the exclusiveCleanupFileName
			 * file. Note that this means files are not removed in the order
			 * they were originally written, in case this worries you.
			 */
			if ((IsXLogFileName(walfile) || IsPartialXLogFileName(walfile)) &&
				strcmp(walfile + 8, exclusiveCleanupFileName + 8) < 0)
			{
				/*
				 * Use the original file name again now, including any
				 * extension that might have been chopped off before testing
				 * the sequence.
				 */
				snprintf(WALFilePath, MAXPGPATH, "%s/%s",
						 archiveLocation, xlde->d_name);

				if (dryrun)
				{
					/*
					 * Prints the name of the file to be removed and skips the
					 * actual removal.  The regular printout is so that the
					 * user can pipe the output into some other program.
					 */
					printf("%s\n", WALFilePath);
					if (debug)
						fprintf(stderr,
								"%s: file \"%s\" would be removed\n",
								progname, WALFilePath);
					continue;
				}

				if (debug)
					fprintf(stderr, "%s: removing file \"%s\"\n",
							progname, WALFilePath);

				rc = unlink(WALFilePath);
				if (rc != 0)
				{
					fprintf(stderr, "%s: ERROR: could not remove file \"%s\": %s\n",
							progname, WALFilePath, strerror(errno));
					break;
				}
			}
		}

		if (errno)
			fprintf(stderr, "%s: could not read archive location \"%s\": %s\n",
					progname, archiveLocation, strerror(errno));
		if (closedir(xldir))
			fprintf(stderr, "%s: could not close archive location \"%s\": %s\n",
					progname, archiveLocation, strerror(errno));
	}
	else
		fprintf(stderr, "%s: could not open archive location \"%s\": %s\n",
				progname, archiveLocation, strerror(errno));
}
コード例 #4
0
ファイル: pg_standby.c プロジェクト: AmiGanguli/postgres
static void
CustomizableCleanupPriorWALFiles(void)
{
	/*
	 * Work out name of prior file from current filename
	 */
	if (nextWALFileType == XLOG_DATA)
	{
		int			rc;
		DIR		   *xldir;
		struct dirent *xlde;

		/*
		 * Assume it's OK to keep failing. The failure situation may change
		 * over time, so we'd rather keep going on the main processing than
		 * fail because we couldn't clean up yet.
		 */
		if ((xldir = opendir(archiveLocation)) != NULL)
		{
			while (errno = 0, (xlde = readdir(xldir)) != NULL)
			{
				/*
				 * We ignore the timeline part of the XLOG segment identifiers
				 * in deciding whether a segment is still needed.  This
				 * ensures that we won't prematurely remove a segment from a
				 * parent timeline. We could probably be a little more
				 * proactive about removing segments of non-parent timelines,
				 * but that would be a whole lot more complicated.
				 *
				 * We use the alphanumeric sorting property of the filenames
				 * to decide which ones are earlier than the
				 * exclusiveCleanupFileName file. Note that this means files
				 * are not removed in the order they were originally written,
				 * in case this worries you.
				 */
				if (IsXLogFileName(xlde->d_name) &&
					strcmp(xlde->d_name + 8, exclusiveCleanupFileName + 8) < 0)
				{
#ifdef WIN32
					snprintf(WALFilePath, sizeof(WALFilePath), "%s\\%s", archiveLocation, xlde->d_name);
#else
					snprintf(WALFilePath, sizeof(WALFilePath), "%s/%s", archiveLocation, xlde->d_name);
#endif

					if (debug)
						fprintf(stderr, "\nremoving file \"%s\"", WALFilePath);

					rc = unlink(WALFilePath);
					if (rc != 0)
					{
						fprintf(stderr, "\n%s: ERROR: could not remove file \"%s\": %s\n",
								progname, WALFilePath, strerror(errno));
						break;
					}
				}
			}

			if (errno)
				fprintf(stderr, "%s: could not read archive location \"%s\": %s\n",
						progname, archiveLocation, strerror(errno));
			if (debug)
				fprintf(stderr, "\n");
		}
		else
			fprintf(stderr, "%s: could not open archive location \"%s\": %s\n",
					progname, archiveLocation, strerror(errno));

		if (closedir(xldir))
			fprintf(stderr, "%s: could not close archive location \"%s\": %s\n",
					progname, archiveLocation, strerror(errno));

		fflush(stderr);
	}
}
コード例 #5
0
ファイル: pg_standby.c プロジェクト: AmiGanguli/postgres
/*
 * CustomizableNextWALFileReady()
 *
 *	  Is the requested file ready yet?
 */
static bool
CustomizableNextWALFileReady(void)
{
	if (stat(WALFilePath, &stat_buf) == 0)
	{
		/*
		 * If we've not seen any WAL segments, we don't know the WAL segment
		 * size, which we need. If it looks like a WAL segment, determine size
		 * of segments for the cluster.
		 */
		if (WalSegSz == -1 && IsXLogFileName(nextWALFileName))
		{
			if (SetWALSegSize())
			{
				/*
				 * Successfully determined WAL segment size. Can compute
				 * cleanup cutoff now.
				 */
				need_cleanup = SetWALFileNameForCleanup();
				if (debug)
				{
					fprintf(stderr,
							_("WAL segment size:     %d \n"), WalSegSz);
					fprintf(stderr, "Keep archive history: ");

					if (need_cleanup)
						fprintf(stderr, "%s and later\n",
								exclusiveCleanupFileName);
					else
						fprintf(stderr, "no cleanup required\n");
				}
			}
		}

		/*
		 * If it's a backup file, return immediately. If it's a regular file
		 * return only if it's the right size already.
		 */
		if (IsBackupHistoryFileName(nextWALFileName))
		{
			nextWALFileType = XLOG_BACKUP_LABEL;
			return true;
		}
		else if (WalSegSz > 0 && stat_buf.st_size == WalSegSz)
		{
#ifdef WIN32

			/*
			 * Windows 'cp' sets the final file size before the copy is
			 * complete, and not yet ready to be opened by pg_standby. So we
			 * wait for sleeptime secs before attempting to restore. If that
			 * is not enough, we will rely on the retry/holdoff mechanism.
			 * GNUWin32's cp does not have this problem.
			 */
			pg_usleep(sleeptime * 1000000L);
#endif
			nextWALFileType = XLOG_DATA;
			return true;
		}

		/*
		 * If still too small, wait until it is the correct size
		 */
		if (WalSegSz > 0 && stat_buf.st_size > WalSegSz)
		{
			if (debug)
			{
				fprintf(stderr, "file size greater than expected\n");
				fflush(stderr);
			}
			exit(3);
		}
	}

	return false;
}
コード例 #6
0
ファイル: delete.c プロジェクト: stalkerg/pg_arman
int
do_delete(pgBackupRange *range)
{
	int			i;
	int			ret;
	parray	   *backup_list;
	bool		do_delete = false;
	XLogRecPtr	oldest_lsn = InvalidXLogRecPtr;
	TimeLineID	oldest_tli;

	/* DATE are always required */
	if (!pgBackupRangeIsValid(range))
		elog(ERROR, "required delete range option not specified: delete DATE");

	/* Lock backup catalog */
	ret = catalog_lock();
	if (ret == -1)
		elog(ERROR, "can't lock backup catalog.");
	else if (ret == 1)
		elog(ERROR,
			"another pg_arman is running, stop delete.");

	/* Get complete list of backups */
	backup_list = catalog_get_backup_list(NULL);
	if (!backup_list)
		elog(ERROR, "No backup list found, can't process any more.");

	/* Find backups to be deleted */
	for (i = 0; i < parray_num(backup_list); i++)
	{
		pgBackup *backup = (pgBackup *) parray_get(backup_list, i);

		/* delete backup and update status to DELETED */
		if (do_delete)
		{
			/* check for interrupt */
			if (interrupted)
				elog(ERROR, "interrupted during delete backup");

			pgBackupDeleteFiles(backup);
			continue;
		}

		/* Found the latest full backup */
		if (backup->backup_mode >= BACKUP_MODE_FULL &&
			backup->status == BACKUP_STATUS_OK &&
			backup->start_time <= range->begin)
		{
			do_delete = true;
			oldest_lsn = backup->start_lsn;
			oldest_tli = backup->tli;
		}
	}

	/* release catalog lock */
	catalog_unlock();

	/* cleanup */
	parray_walk(backup_list, pgBackupFree);
	parray_free(backup_list);

	/*
	 * Delete in archive WAL segments that are not needed anymore. The oldest
	 * segment to be kept is the first segment that the oldest full backup
	 * found around needs to keep.
	 */
	if (!XLogRecPtrIsInvalid(oldest_lsn))
	{
		XLogSegNo   targetSegNo;
		char		oldestSegmentNeeded[MAXFNAMELEN];
		DIR		   *arcdir;
		struct dirent *arcde;
		char		wal_file[MAXPGPATH];
		int			rc;

		XLByteToSeg(oldest_lsn, targetSegNo);
		XLogFileName(oldestSegmentNeeded, oldest_tli, targetSegNo);
		elog(LOG, "Removing segments older than %s", oldestSegmentNeeded);

		/*
		 * Now is time to do the actual work and to remove all the segments
		 * not needed anymore.
		 */
		if ((arcdir = opendir(arclog_path)) != NULL)
		{
			while (errno = 0, (arcde = readdir(arcdir)) != NULL)
			{
				/*
				 * We ignore the timeline part of the XLOG segment identifiers in
				 * deciding whether a segment is still needed.  This ensures that
				 * we won't prematurely remove a segment from a parent timeline.
				 * We could probably be a little more proactive about removing
				 * segments of non-parent timelines, but that would be a whole lot
				 * more complicated.
				 *
				 * We use the alphanumeric sorting property of the filenames to
				 * decide which ones are earlier than the exclusiveCleanupFileName
				 * file. Note that this means files are not removed in the order
				 * they were originally written, in case this worries you.
				 */
				if ((IsXLogFileName(arcde->d_name) ||
					 IsPartialXLogFileName(arcde->d_name)) &&
					strcmp(arcde->d_name + 8, oldestSegmentNeeded + 8) < 0)
				{
					/*
					 * Use the original file name again now, including any
					 * extension that might have been chopped off before testing
					 * the sequence.
					 */
					snprintf(wal_file, MAXPGPATH, "%s/%s",
							 arclog_path, arcde->d_name);

					rc = unlink(wal_file);
					if (rc != 0)
					{
						elog(WARNING, "could not remove file \"%s\": %s",
							 wal_file, strerror(errno));
						break;
					}
					elog(LOG, "removed WAL segment \"%s\"", wal_file);
				}
			}
			if (errno)
				elog(WARNING, "could not read archive location \"%s\": %s",
					 arclog_path, strerror(errno));
			if (closedir(arcdir))
				elog(WARNING, "could not close archive location \"%s\": %s",
					 arclog_path, strerror(errno));
		}
		else
			elog(WARNING, "could not open archive location \"%s\": %s",
				 arclog_path, strerror(errno));
	}

	return 0;
}
コード例 #7
0
ファイル: pg_resetxlog.c プロジェクト: bocap/postgres
/*
 * 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;
	uint64		segs_per_xlogid;
	uint64		xlogbytepos;

	/*
	 * 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.
	 */
	segs_per_xlogid = (UINT64CONST(0x0000000100000000) / ControlFile.xlog_seg_size);
	newXlogSegNo = ControlFile.checkPointCopy.redo / 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);
	}

	while (errno = 0, (xlde = readdir(xldir)) != NULL)
	{
		if (IsXLogFileName(xlde->d_name) ||
			IsPartialXLogFileName(xlde->d_name))
		{
			unsigned int tli,
						log,
						seg;
			XLogSegNo	segno;

			/*
			 * Note: We don't use XLogFromFileName here, because we want to
			 * use the segment size from the control file, not the size the
			 * pg_resetxlog binary was compiled with
			 */
			sscanf(xlde->d_name, "%08X%08X%08X", &tli, &log, &seg);
			segno = ((uint64) log) * segs_per_xlogid + 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 (segno > newXlogSegNo)
				newXlogSegNo = segno;
		}
	}

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

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

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