Add a startup check that pg_xlog and pg_xlog/archive_status exist.
authorTom Lane
Sun, 9 Nov 2008 17:51:15 +0000 (17:51 +0000)
committerTom Lane
Sun, 9 Nov 2008 17:51:15 +0000 (17:51 +0000)
If the latter doesn't exist, automatically recreate it.  (We don't do
this for pg_xlog, though, per discussion.)

Jonah Harris

doc/src/sgml/backup.sgml
src/backend/access/transam/xlog.c

index 3f62e8fa5a00479fb3a054f47cd2674a65a7e099..1c9b5cfb4bd4547c10b581c123912d8faa7cebfd 100644 (file)
@@ -1,4 +1,4 @@
-
+
 
 
  Backup and Restore
@@ -945,8 +945,6 @@ SELECT pg_stop_backup();
      If you didn't archive 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
-     pg_xlog/archive_status/ as well.
     
    
    
index 77ab05b53d62e46636721e7ecaa87c4fba5cf1d7..f48dd5f7812f508e8f3e011b164fd8a4ec373799 100644 (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.