Add a startup check that pg_xlog and pg_xlog/archive_status exist.

If the latter doesn't exist, automatically recreate it.  (We don't do
this for pg_xlog, though, per discussion.)

Jonah Harris
This commit is contained in:
Tom Lane 2008-11-09 17:51:15 +00:00
parent dbf57d31f8
commit 1d577f5e49
2 changed files with 57 additions and 4 deletions

View File

@ -1,4 +1,4 @@
<!-- $PostgreSQL: pgsql/doc/src/sgml/backup.sgml,v 2.120 2008/07/18 17:33:17 momjian Exp $ -->
<!-- $PostgreSQL: pgsql/doc/src/sgml/backup.sgml,v 2.121 2008/11/09 17:51:15 tgl Exp $ -->
<chapter id="backup">
<title>Backup and Restore</title>
@ -945,8 +945,6 @@ SELECT pg_stop_backup();
If you didn't archive <filename>pg_xlog/</> at all, then recreate it,
being careful to ensure that you re-establish it as a symbolic link
if you had it set up that way before.
Be sure to recreate the subdirectory
<filename>pg_xlog/archive_status/</> as well.
</para>
</listitem>
<listitem>

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.321 2008/10/31 15:04:59 heikki Exp $
* $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.322 2008/11/09 17:51:15 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -416,6 +416,7 @@ static bool RestoreArchivedFile(char *path, const char *xlogfname,
const char *recovername, off_t expectedSize);
static void PreallocXlogFiles(XLogRecPtr endptr);
static void RemoveOldXlogFiles(uint32 log, uint32 seg, XLogRecPtr endptr);
static void ValidateXLOGDirectoryStructure(void);
static void CleanupBackupHistory(void);
static XLogRecord *ReadRecord(XLogRecPtr *RecPtr, int emode);
static bool ValidXLOGHeader(XLogPageHeader hdr, int emode);
@ -2824,6 +2825,53 @@ RemoveOldXlogFiles(uint32 log, uint32 seg, XLogRecPtr endptr)
FreeDir(xldir);
}
/*
* Verify whether pg_xlog and pg_xlog/archive_status exist.
* If the latter does not exist, recreate it.
*
* It is not the goal of this function to verify the contents of these
* directories, but to help in cases where someone has performed a cluster
* copy for PITR purposes but omitted pg_xlog from the copy.
*
* We could also recreate pg_xlog if it doesn't exist, but a deliberate
* policy decision was made not to. It is fairly common for pg_xlog to be
* a symlink, and if that was the DBA's intent then automatically making a
* plain directory would result in degraded performance with no notice.
*/
static void
ValidateXLOGDirectoryStructure(void)
{
char path[MAXPGPATH];
struct stat stat_buf;
/* Check for pg_xlog; if it doesn't exist, error out */
if (stat(XLOGDIR, &stat_buf) != 0 ||
!S_ISDIR(stat_buf.st_mode))
ereport(FATAL,
(errmsg("required WAL directory \"%s\" does not exist",
XLOGDIR)));
/* Check for archive_status */
snprintf(path, MAXPGPATH, XLOGDIR "/archive_status");
if (stat(path, &stat_buf) == 0)
{
/* Check for weird cases where it exists but isn't a directory */
if (!S_ISDIR(stat_buf.st_mode))
ereport(FATAL,
(errmsg("required WAL directory \"%s\" does not exist",
path)));
}
else
{
ereport(LOG,
(errmsg("creating missing WAL directory \"%s\"", path)));
if (mkdir(path, 0700) < 0)
ereport(FATAL,
(errmsg("could not create missing directory \"%s\": %m",
path)));
}
}
/*
* Remove previous backup history files. This also retries creation of
* .ready files for any backup history files for which XLogArchiveNotify
@ -4878,6 +4926,13 @@ StartupXLOG(void)
pg_usleep(60000000L);
#endif
/*
* Verify that pg_xlog and pg_xlog/archive_status exist. In cases where
* someone has performed a copy for PITR, these directories may have
* been excluded and need to be re-created.
*/
ValidateXLOGDirectoryStructure();
/*
* Initialize on the assumption we want to recover to the same timeline
* that's active according to pg_control.