From bc5334d8679c428a709d150666b288171795bd76 Mon Sep 17 00:00:00 2001 From: Simon Riggs Date: Wed, 27 Mar 2013 11:45:42 +0000 Subject: [PATCH] Allow external recovery_config_directory 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 | 17 +++++++++++++++++ src/backend/access/transam/xlog.c | 18 +++++++++++------- src/backend/utils/init/globals.c | 1 + src/backend/utils/init/miscinit.c | 19 +++++++++++++++++++ src/backend/utils/misc/guc.c | 24 ++++++++++++++++++++++++ src/include/miscadmin.h | 2 ++ src/include/utils/guc.h | 1 + 7 files changed, 75 insertions(+), 7 deletions(-) diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml index d750f0800b..6488399708 100644 --- a/doc/src/sgml/config.sgml +++ b/doc/src/sgml/config.sgml @@ -330,6 +330,23 @@ include 'filename' + + + recovery_config_directory (string) + + recovery_config_directory configuration parameter + + + + 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. + + + + config_file (string) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 07c68adf0b..2f91bc88ea 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -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"))); diff --git a/src/backend/utils/init/globals.c b/src/backend/utils/init/globals.c index 9f51929191..8bf7021917 100644 --- a/src/backend/utils/init/globals.c +++ b/src/backend/utils/init/globals.c @@ -46,6 +46,7 @@ int MyPMChildSlot; * explicitly. */ char *DataDir = NULL; +char *RecoveryConfDir = NULL; char OutputFileName[MAXPGPATH]; /* debugging output file */ diff --git a/src/backend/utils/init/miscinit.c b/src/backend/utils/init/miscinit.c index 24ca97d55c..3d48eb8c9d 100644 --- a/src/backend/utils/init/miscinit.c +++ b/src/backend/utils/init/miscinit.c @@ -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 diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 22ba35fef9..0459dd1c09 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -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 diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h index 99858a765f..2bc513045d 100644 --- a/src/include/miscadmin.h +++ b/src/include/miscadmin.h @@ -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); diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h index d497b1f654..42428cbd43 100644 --- a/src/include/utils/guc.h +++ b/src/include/utils/guc.h @@ -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; -- 2.40.0