Allow external recovery_config_directory
authorSimon Riggs <simon@2ndQuadrant.com>
Wed, 27 Mar 2013 11:45:42 +0000 (11:45 +0000)
committerSimon Riggs <simon@2ndQuadrant.com>
Wed, 27 Mar 2013 11:45:42 +0000 (11:45 +0000)
If required, recovery.conf can now be located outside of the data directory.
Server needs read/write permissions on this directory.

doc/src/sgml/config.sgml
src/backend/access/transam/xlog.c
src/backend/utils/init/globals.c
src/backend/utils/init/miscinit.c
src/backend/utils/misc/guc.c
src/include/miscadmin.h
src/include/utils/guc.h

index d750f0800b70083311112904c90658110d33b96c..6488399708f2db3cb4d1d574cc3b2925db1c1e5c 100644 (file)
@@ -330,6 +330,23 @@ include 'filename'
       </listitem>
      </varlistentry>
 
+     <variablelist>
+     <varlistentry id="guc-recovery-config-directory" xreflabel="recovery_config_directory">
+      <term><varname>recovery_config_directory</varname> (<type>string</type>)</term>
+      <indexterm>
+       <primary><varname>recovery_config_directory</> configuration parameter</primary>
+      </indexterm>
+      <listitem>
+       <para>
+         Specifies the directory to use for the recovery.conf file. Note
+         the server requires read and write permission on this directory
+         because the file will be renamed to recovery.done at the end of
+         recovery.
+         This parameter can only be set at server start.
+       </para>
+      </listitem>
+     </varlistentry>
+
      <varlistentry id="guc-config-file" xreflabel="config_file">
       <term><varname>config_file</varname> (<type>string</type>)</term>
       <indexterm>
index 07c68adf0bcda74ddd6ae102e6da281733d792e7..2f91bc88eaa884ba14054c31b99c14aadbb0ba4e 100644 (file)
@@ -62,6 +62,7 @@
 
 extern bool bootstrap_data_checksums;
 
+char   recoveryConfPath[MAXPGPATH];
 /* File path names (all relative to $PGDATA) */
 #define RECOVERY_COMMAND_FILE  "recovery.conf"
 #define RECOVERY_COMMAND_DONE  "recovery.done"
@@ -4163,7 +4164,8 @@ readRecoveryCommandFile(void)
               *head = NULL,
               *tail = NULL;
 
-   fd = AllocateFile(RECOVERY_COMMAND_FILE, "r");
+   snprintf(recoveryConfPath, MAXPGPATH, "%s/%s", RecoveryConfDir, RECOVERY_COMMAND_FILE);
+   fd = AllocateFile(recoveryConfPath, "r");
    if (fd == NULL)
    {
        if (errno == ENOENT)
@@ -4171,7 +4173,7 @@ readRecoveryCommandFile(void)
        ereport(FATAL,
                (errcode_for_file_access(),
                 errmsg("could not open recovery command file \"%s\": %m",
-                       RECOVERY_COMMAND_FILE)));
+                       recoveryConfPath)));
    }
 
    /*
@@ -4345,7 +4347,7 @@ readRecoveryCommandFile(void)
        if (PrimaryConnInfo == NULL && recoveryRestoreCommand == NULL)
            ereport(WARNING,
                    (errmsg("recovery command file \"%s\" specified neither primary_conninfo nor restore_command",
-                           RECOVERY_COMMAND_FILE),
+                           recoveryConfPath),
                     errhint("The database server will regularly poll the pg_xlog subdirectory to check for files placed there.")));
    }
    else
@@ -4353,7 +4355,7 @@ readRecoveryCommandFile(void)
        if (recoveryRestoreCommand == NULL)
            ereport(FATAL,
                    (errmsg("recovery command file \"%s\" must specify restore_command when standby mode is not enabled",
-                           RECOVERY_COMMAND_FILE)));
+                           recoveryConfPath)));
    }
 
    /* Enable fetching from archive recovery area */
@@ -4395,6 +4397,7 @@ static void
 exitArchiveRecovery(TimeLineID endTLI, XLogSegNo endLogSegNo)
 {
    char        recoveryPath[MAXPGPATH];
+   char        recoveryDonePath[MAXPGPATH];
    char        xlogpath[MAXPGPATH];
 
    /*
@@ -4459,12 +4462,13 @@ exitArchiveRecovery(TimeLineID endTLI, XLogSegNo endLogSegNo)
     * Rename the config file out of the way, so that we don't accidentally
     * re-enter archive recovery mode in a subsequent crash.
     */
-   unlink(RECOVERY_COMMAND_DONE);
-   if (rename(RECOVERY_COMMAND_FILE, RECOVERY_COMMAND_DONE) != 0)
+   snprintf(recoveryDonePath, MAXPGPATH, "%s/%s", RecoveryConfDir, RECOVERY_COMMAND_DONE);
+   unlink(recoveryDonePath);
+   if (rename(recoveryConfPath, recoveryDonePath) != 0)
        ereport(FATAL,
                (errcode_for_file_access(),
                 errmsg("could not rename file \"%s\" to \"%s\": %m",
-                       RECOVERY_COMMAND_FILE, RECOVERY_COMMAND_DONE)));
+                       recoveryConfPath, recoveryDonePath)));
 
    ereport(LOG,
            (errmsg("archive recovery complete")));
index 9f51929191d5b23d12e13068843117a988df3436..8bf702191730472cfad72f0a7a1f750592cf4548 100644 (file)
@@ -46,6 +46,7 @@ int           MyPMChildSlot;
  * explicitly.
  */
 char      *DataDir = NULL;
+char      *RecoveryConfDir = NULL;
 
 char       OutputFileName[MAXPGPATH];  /* debugging output file */
 
index 24ca97d55c73ab5072de0bc29d629fce2145c769..3d48eb8c9d35740dbdd8112ed3d74eec64a85a76 100644 (file)
@@ -99,6 +99,25 @@ SetDataDir(const char *dir)
    DataDir = new;
 }
 
+/*
+ * Set recovery config directory, but make sure it's an absolute path.  Use this,
+ * never set RecoveryConfDir directly.
+ */
+void
+SetRecoveryConfDir(const char *dir)
+{
+   char       *new;
+
+   AssertArg(dir);
+
+   /* If presented path is relative, convert to absolute */
+   new = make_absolute_path(dir);
+
+   if (RecoveryConfDir)
+       free(RecoveryConfDir);
+   RecoveryConfDir = new;
+}
+
 /*
  * Change working directory to DataDir.  Most of the postmaster and backend
  * code assumes that we are in DataDir so it can use relative paths to access
index 22ba35fef93fda2d13f0058cee1085ea6f3e416b..0459dd1c09bc7bf1c981a98cc484185ee27b72aa 100644 (file)
@@ -424,6 +424,7 @@ int         temp_file_limit = -1;
 int            num_temp_buffers = 1024;
 
 char      *data_directory;
+char      *recovery_config_directory;
 char      *ConfigFileName;
 char      *HbaFileName;
 char      *IdentFileName;
@@ -2960,6 +2961,17 @@ static struct config_string ConfigureNamesString[] =
        NULL, NULL, NULL
    },
 
+   {
+       {"recovery_config_directory", PGC_POSTMASTER, FILE_LOCATIONS,
+           gettext_noop("Sets the server's recovery configuration directory."),
+           NULL,
+           GUC_SUPERUSER_ONLY
+       },
+       &recovery_config_directory,
+       NULL,
+       NULL, NULL, NULL
+   },
+
    {
        {"config_file", PGC_POSTMASTER, FILE_LOCATIONS,
            gettext_noop("Sets the server's main configuration file."),
@@ -4181,6 +4193,18 @@ SelectConfigFiles(const char *userDoption, const char *progname)
     */
    SetConfigOption("data_directory", DataDir, PGC_POSTMASTER, PGC_S_OVERRIDE);
 
+   /*
+    * If the recovery_config_directory GUC variable has been set, use that,
+    * otherwise use DataDir.
+    *
+    * Note: SetRecoveryConfDir will copy and absolute-ize its argument,
+    * so we don't have to.
+    */
+   if (recovery_config_directory)
+       SetRecoveryConfDir(recovery_config_directory);
+   else
+       SetRecoveryConfDir(DataDir);
+
    /*
     * If timezone_abbreviations wasn't set in the configuration file, install
     * the default value.  We do it this way because we can't safely install a
index 99858a765f1a0e18ff32c973eccb04ba196a7dc5..2bc513045d766aa40b250dff3810a04bb7a6f5d3 100644 (file)
@@ -137,6 +137,7 @@ extern bool IsBinaryUpgrade;
 extern bool ExitOnAnyError;
 
 extern PGDLLIMPORT char *DataDir;
+extern PGDLLIMPORT char *RecoveryConfDir;
 
 extern PGDLLIMPORT int NBuffers;
 extern int MaxBackends;
@@ -301,6 +302,7 @@ extern Oid  GetCurrentRoleId(void);
 extern void SetCurrentRoleId(Oid roleid, bool is_superuser);
 
 extern void SetDataDir(const char *dir);
+extern void SetRecoveryConfDir(const char *dir);
 extern void ChangeToDataDir(void);
 extern char *make_absolute_path(const char *path);
 
index d497b1f6546d2dd0d41a34285c066e2a11b19748..42428cbd4351cfdcf79b0844018220b530581ff9 100644 (file)
@@ -220,6 +220,7 @@ extern int  temp_file_limit;
 extern int num_temp_buffers;
 
 extern char *data_directory;
+extern char *recovery_config_directory;
 extern char *ConfigFileName;
 extern char *HbaFileName;
 extern char *IdentFileName;