aboutsummaryrefslogtreecommitdiff
path: root/src/backend/access/transam/xlog.c
diff options
context:
space:
mode:
authorPeter Eisentraut <peter_e@gmx.net>2018-11-25 16:31:16 +0100
committerPeter Eisentraut <peter_e@gmx.net>2018-11-25 16:33:40 +0100
commit2dedf4d9a899b36d1a8ed29be5efbd1b31a8fe85 (patch)
tree5564005e2fe623af69b01d56c9c72baf8ec68402 /src/backend/access/transam/xlog.c
parentab69ea9feeb9a02c6299b5c1b786005552343f22 (diff)
downloadpostgresql-2dedf4d9a899b36d1a8ed29be5efbd1b31a8fe85.tar.gz
postgresql-2dedf4d9a899b36d1a8ed29be5efbd1b31a8fe85.zip
Integrate recovery.conf into postgresql.conf
recovery.conf settings are now set in postgresql.conf (or other GUC sources). Currently, all the affected settings are PGC_POSTMASTER; this could be refined in the future case by case. Recovery is now initiated by a file recovery.signal. Standby mode is initiated by a file standby.signal. The standby_mode setting is gone. If a recovery.conf file is found, an error is issued. The trigger_file setting has been renamed to promote_trigger_file as part of the move. The documentation chapter "Recovery Configuration" has been integrated into "Server Configuration". pg_basebackup -R now appends settings to postgresql.auto.conf and creates a standby.signal file. Author: Fujii Masao <masao.fujii@gmail.com> Author: Simon Riggs <simon@2ndquadrant.com> Author: Abhijit Menon-Sen <ams@2ndquadrant.com> Author: Sergei Kornilov <sk@zsrv.org> Discussion: https://www.postgresql.org/message-id/flat/607741529606767@web3g.yandex.ru/
Diffstat (limited to 'src/backend/access/transam/xlog.c')
-rw-r--r--src/backend/access/transam/xlog.c500
1 files changed, 163 insertions, 337 deletions
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 7397b6ee06b..c80b14ed971 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -69,7 +69,6 @@
#include "utils/builtins.h"
#include "utils/guc.h"
#include "utils/memutils.h"
-#include "utils/pg_lsn.h"
#include "utils/ps_status.h"
#include "utils/relmapper.h"
#include "utils/snapmgr.h"
@@ -78,6 +77,9 @@
extern uint32 bootstrap_data_checksum_version;
+/* Unsupported old recovery command file names (relative to $PGDATA) */
+#define RECOVERY_COMMAND_FILE "recovery.conf"
+#define RECOVERY_COMMAND_DONE "recovery.done"
/* User-settable parameters */
int max_wal_size_mb = 1024; /* 1 GB */
@@ -161,6 +163,13 @@ const struct config_enum_entry archive_mode_options[] = {
{NULL, 0, false}
};
+const struct config_enum_entry recovery_target_action_options[] = {
+ {"pause", RECOVERY_TARGET_ACTION_PAUSE, false},
+ {"promote", RECOVERY_TARGET_ACTION_PROMOTE, false},
+ {"shutdown", RECOVERY_TARGET_ACTION_SHUTDOWN, false},
+ {NULL, 0, false}
+};
+
/*
* Statistics for current checkpoint are collected in this global struct.
* Because only the checkpointer or a stand-alone backend can perform
@@ -230,7 +239,7 @@ static int LocalXLogInsertAllowed = -1;
/*
* When ArchiveRecoveryRequested is set, archive recovery was requested,
- * ie. recovery.conf file was present. When InArchiveRecovery is set, we are
+ * ie. signal files were present. When InArchiveRecovery is set, we are
* currently recovering using offline XLOG archives. These variables are only
* valid in the startup process.
*
@@ -242,6 +251,9 @@ static int LocalXLogInsertAllowed = -1;
bool ArchiveRecoveryRequested = false;
bool InArchiveRecovery = false;
+static bool standby_signal_file_found = false;
+static bool recovery_signal_file_found = false;
+
/* Was the last xlog file restored from archive, or local? */
static bool restoredFromArchive = false;
@@ -249,25 +261,25 @@ static bool restoredFromArchive = false;
static char *replay_image_masked = NULL;
static char *master_image_masked = NULL;
-/* options taken from recovery.conf for archive recovery */
+/* options formerly taken from recovery.conf for archive recovery */
char *recoveryRestoreCommand = NULL;
-static char *recoveryEndCommand = NULL;
-static char *archiveCleanupCommand = NULL;
-static RecoveryTargetType recoveryTarget = RECOVERY_TARGET_UNSET;
-static bool recoveryTargetInclusive = true;
-static RecoveryTargetAction recoveryTargetAction = RECOVERY_TARGET_ACTION_PAUSE;
-static TransactionId recoveryTargetXid;
-static TimestampTz recoveryTargetTime;
-static char *recoveryTargetName;
-static XLogRecPtr recoveryTargetLSN;
-static int recovery_min_apply_delay = 0;
-static TimestampTz recoveryDelayUntilTime;
-
-/* options taken from recovery.conf for XLOG streaming */
-static bool StandbyModeRequested = false;
-static char *PrimaryConnInfo = NULL;
-static char *PrimarySlotName = NULL;
-static char *TriggerFile = NULL;
+char *recoveryEndCommand = NULL;
+char *archiveCleanupCommand = NULL;
+RecoveryTargetType recoveryTarget = RECOVERY_TARGET_UNSET;
+bool recoveryTargetInclusive = true;
+int recoveryTargetAction = RECOVERY_TARGET_ACTION_PAUSE;
+TransactionId recoveryTargetXid;
+TimestampTz recoveryTargetTime;
+char *recoveryTargetName;
+XLogRecPtr recoveryTargetLSN;
+int recovery_min_apply_delay = 0;
+TimestampTz recoveryDelayUntilTime;
+
+/* options formerly taken from recovery.conf for XLOG streaming */
+bool StandbyModeRequested = false;
+char *PrimaryConnInfo = NULL;
+char *PrimarySlotName = NULL;
+char *PromoteTriggerFile = NULL;
/* are we currently in standby mode? */
bool StandbyMode = false;
@@ -293,7 +305,11 @@ static bool recoveryStopAfter;
* the currently-scanned WAL record was generated). We also need these
* timeline values:
*
- * recoveryTargetTLI: the desired timeline that we want to end in.
+ * recoveryTargetTimeLineGoal: what the user requested, if any
+ *
+ * recoveryTargetTLIRequested: numeric value of requested timeline, if constant
+ *
+ * recoveryTargetTLI: the currently understood target timeline; changes
*
* recoveryTargetIsLatest: was the requested target timeline 'latest'?
*
@@ -309,8 +325,9 @@ static bool recoveryStopAfter;
* file was created.) During a sequential scan we do not allow this value
* to decrease.
*/
-static TimeLineID recoveryTargetTLI;
-static bool recoveryTargetIsLatest = false;
+RecoveryTargetTimeLineGoal recoveryTargetTimeLineGoal = RECOVERY_TARGET_TIMELINE_CONTROLFILE;
+TimeLineID recoveryTargetTLIRequested = 0;
+TimeLineID recoveryTargetTLI = 0;
static List *expectedTLEs;
static TimeLineID curFileTLI;
@@ -625,12 +642,6 @@ typedef struct XLogCtlData
TimeLineID PrevTimeLineID;
/*
- * archiveCleanupCommand is read from recovery.conf but needs to be in
- * shared memory so that the checkpointer process can access it.
- */
- char archiveCleanupCommand[MAXPGPATH];
-
- /*
* SharedRecoveryInProgress indicates if we're still in crash or archive
* recovery. Protected by info_lck.
*/
@@ -846,7 +857,8 @@ static bool holdingAllLocks = false;
static MemoryContext walDebugCxt = NULL;
#endif
-static void readRecoveryCommandFile(void);
+static void readRecoverySignalFile(void);
+static void validateRecoveryParameters(void);
static void exitArchiveRecovery(TimeLineID endTLI, XLogRecPtr endOfLog);
static bool recoveryStopsBefore(XLogReaderState *record);
static bool recoveryStopsAfter(XLogReaderState *record);
@@ -5285,283 +5297,111 @@ str_time(pg_time_t tnow)
}
/*
- * See if there is a recovery command file (recovery.conf), and if so
- * read in parameters for archive recovery and XLOG streaming.
+ * See if there are any recovery signal files and if so, set state for
+ * recovery.
*
- * The file is parsed using the main configuration parser.
+ * See if there is a recovery command file (recovery.conf), and if so
+ * throw an ERROR since as of PG12 we no longer recognize that.
*/
static void
-readRecoveryCommandFile(void)
+readRecoverySignalFile(void)
{
- FILE *fd;
- TimeLineID rtli = 0;
- bool rtliGiven = false;
- ConfigVariable *item,
- *head = NULL,
- *tail = NULL;
- bool recoveryTargetActionSet = false;
+ struct stat stat_buf;
+ if (IsBootstrapProcessingMode())
+ return;
- fd = AllocateFile(RECOVERY_COMMAND_FILE, "r");
- if (fd == NULL)
- {
- if (errno == ENOENT)
- return; /* not there, so no archive recovery */
+ /*
+ * Check for old recovery API file: recovery.conf
+ */
+ if (stat(RECOVERY_COMMAND_FILE, &stat_buf) == 0)
ereport(FATAL,
(errcode_for_file_access(),
- errmsg("could not open recovery command file \"%s\": %m",
+ errmsg("using recovery command file \"%s\" is not supported",
RECOVERY_COMMAND_FILE)));
- }
/*
- * Since we're asking ParseConfigFp() to report errors as FATAL, there's
- * no need to check the return value.
+ * Remove unused .done file, if present. Ignore if absent.
*/
- (void) ParseConfigFp(fd, RECOVERY_COMMAND_FILE, 0, FATAL, &head, &tail);
-
- FreeFile(fd);
+ unlink(RECOVERY_COMMAND_DONE);
- for (item = head; item; item = item->next)
+ /*
+ * Check for recovery signal files and if found, fsync them since they
+ * represent server state information.
+ *
+ * If present, standby signal file takes precedence. If neither is present
+ * then we won't enter archive recovery.
+ */
+ if (stat(STANDBY_SIGNAL_FILE, &stat_buf) == 0)
{
- if (strcmp(item->name, "restore_command") == 0)
- {
- recoveryRestoreCommand = pstrdup(item->value);
- ereport(DEBUG2,
- (errmsg_internal("restore_command = '%s'",
- recoveryRestoreCommand)));
- }
- else if (strcmp(item->name, "recovery_end_command") == 0)
- {
- recoveryEndCommand = pstrdup(item->value);
- ereport(DEBUG2,
- (errmsg_internal("recovery_end_command = '%s'",
- recoveryEndCommand)));
- }
- else if (strcmp(item->name, "archive_cleanup_command") == 0)
- {
- archiveCleanupCommand = pstrdup(item->value);
- ereport(DEBUG2,
- (errmsg_internal("archive_cleanup_command = '%s'",
- archiveCleanupCommand)));
- }
- else if (strcmp(item->name, "recovery_target_action") == 0)
- {
- if (strcmp(item->value, "pause") == 0)
- recoveryTargetAction = RECOVERY_TARGET_ACTION_PAUSE;
- else if (strcmp(item->value, "promote") == 0)
- recoveryTargetAction = RECOVERY_TARGET_ACTION_PROMOTE;
- else if (strcmp(item->value, "shutdown") == 0)
- recoveryTargetAction = RECOVERY_TARGET_ACTION_SHUTDOWN;
- else
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
- errmsg("invalid value for recovery parameter \"%s\": \"%s\"",
- "recovery_target_action",
- item->value),
- errhint("Valid values are \"pause\", \"promote\", and \"shutdown\".")));
-
- ereport(DEBUG2,
- (errmsg_internal("recovery_target_action = '%s'",
- item->value)));
-
- recoveryTargetActionSet = true;
- }
- else if (strcmp(item->name, "recovery_target_timeline") == 0)
- {
- rtliGiven = true;
- if (strcmp(item->value, "latest") == 0)
- rtli = 0;
- else
- {
- errno = 0;
- rtli = (TimeLineID) strtoul(item->value, NULL, 0);
- if (errno == EINVAL || errno == ERANGE)
- ereport(FATAL,
- (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
- errmsg("recovery_target_timeline is not a valid number: \"%s\"",
- item->value)));
- }
- if (rtli)
- ereport(DEBUG2,
- (errmsg_internal("recovery_target_timeline = %u", rtli)));
- else
- ereport(DEBUG2,
- (errmsg_internal("recovery_target_timeline = latest")));
- }
- else if (strcmp(item->name, "recovery_target_xid") == 0)
- {
- errno = 0;
- recoveryTargetXid = (TransactionId) strtoul(item->value, NULL, 0);
- if (errno == EINVAL || errno == ERANGE)
- ereport(FATAL,
- (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
- errmsg("recovery_target_xid is not a valid number: \"%s\"",
- item->value)));
- ereport(DEBUG2,
- (errmsg_internal("recovery_target_xid = %u",
- recoveryTargetXid)));
- recoveryTarget = RECOVERY_TARGET_XID;
- }
- else if (strcmp(item->name, "recovery_target_time") == 0)
- {
- recoveryTarget = RECOVERY_TARGET_TIME;
-
- if (strcmp(item->value, "epoch") == 0 ||
- strcmp(item->value, "infinity") == 0 ||
- strcmp(item->value, "-infinity") == 0 ||
- strcmp(item->value, "now") == 0 ||
- strcmp(item->value, "today") == 0 ||
- strcmp(item->value, "tomorrow") == 0 ||
- strcmp(item->value, "yesterday") == 0)
- ereport(FATAL,
- (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
- errmsg("recovery_target_time is not a valid timestamp: \"%s\"",
- item->value)));
+ int fd;
- /*
- * Convert the time string given by the user to TimestampTz form.
- */
- recoveryTargetTime =
- DatumGetTimestampTz(DirectFunctionCall3(timestamptz_in,
- CStringGetDatum(item->value),
- ObjectIdGetDatum(InvalidOid),
- Int32GetDatum(-1)));
- ereport(DEBUG2,
- (errmsg_internal("recovery_target_time = '%s'",
- timestamptz_to_str(recoveryTargetTime))));
- }
- else if (strcmp(item->name, "recovery_target_name") == 0)
- {
- recoveryTarget = RECOVERY_TARGET_NAME;
+ fd = BasicOpenFilePerm(STANDBY_SIGNAL_FILE, O_RDWR | PG_BINARY | get_sync_bit(sync_method),
+ S_IRUSR | S_IWUSR);
+ pg_fsync(fd);
+ close(fd);
+ standby_signal_file_found = true;
+ }
+ else if (stat(RECOVERY_SIGNAL_FILE, &stat_buf) == 0)
+ {
+ int fd;
- recoveryTargetName = pstrdup(item->value);
- if (strlen(recoveryTargetName) >= MAXFNAMELEN)
- ereport(FATAL,
- (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
- errmsg("recovery_target_name is too long (maximum %d characters)",
- MAXFNAMELEN - 1)));
+ fd = BasicOpenFilePerm(RECOVERY_SIGNAL_FILE, O_RDWR | PG_BINARY | get_sync_bit(sync_method),
+ S_IRUSR | S_IWUSR);
+ pg_fsync(fd);
+ close(fd);
+ recovery_signal_file_found = true;
+ }
- ereport(DEBUG2,
- (errmsg_internal("recovery_target_name = '%s'",
- recoveryTargetName)));
- }
- else if (strcmp(item->name, "recovery_target_lsn") == 0)
- {
- recoveryTarget = RECOVERY_TARGET_LSN;
+ StandbyModeRequested = false;
+ ArchiveRecoveryRequested = false;
+ if (standby_signal_file_found)
+ {
+ StandbyModeRequested = true;
+ ArchiveRecoveryRequested = true;
+ }
+ else if (recovery_signal_file_found)
+ {
+ StandbyModeRequested = false;
+ ArchiveRecoveryRequested = true;
+ }
+ else
+ return;
- /*
- * Convert the LSN string given by the user to XLogRecPtr form.
- */
- recoveryTargetLSN =
- DatumGetLSN(DirectFunctionCall3(pg_lsn_in,
- CStringGetDatum(item->value),
- ObjectIdGetDatum(InvalidOid),
- Int32GetDatum(-1)));
- ereport(DEBUG2,
- (errmsg_internal("recovery_target_lsn = '%X/%X'",
- (uint32) (recoveryTargetLSN >> 32),
- (uint32) recoveryTargetLSN)));
- }
- else if (strcmp(item->name, "recovery_target") == 0)
- {
- if (strcmp(item->value, "immediate") == 0)
- recoveryTarget = RECOVERY_TARGET_IMMEDIATE;
- else
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
- errmsg("invalid value for recovery parameter \"%s\": \"%s\"",
- "recovery_target",
- item->value),
- errhint("The only allowed value is \"immediate\".")));
- ereport(DEBUG2,
- (errmsg_internal("recovery_target = '%s'",
- item->value)));
- }
- else if (strcmp(item->name, "recovery_target_inclusive") == 0)
- {
- /*
- * does nothing if a recovery_target is not also set
- */
- if (!parse_bool(item->value, &recoveryTargetInclusive))
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
- errmsg("parameter \"%s\" requires a Boolean value",
- "recovery_target_inclusive")));
- ereport(DEBUG2,
- (errmsg_internal("recovery_target_inclusive = %s",
- item->value)));
- }
- else if (strcmp(item->name, "standby_mode") == 0)
- {
- if (!parse_bool(item->value, &StandbyModeRequested))
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
- errmsg("parameter \"%s\" requires a Boolean value",
- "standby_mode")));
- ereport(DEBUG2,
- (errmsg_internal("standby_mode = '%s'", item->value)));
- }
- else if (strcmp(item->name, "primary_conninfo") == 0)
- {
- PrimaryConnInfo = pstrdup(item->value);
- ereport(DEBUG2,
- (errmsg_internal("primary_conninfo = '%s'",
- PrimaryConnInfo)));
- }
- else if (strcmp(item->name, "primary_slot_name") == 0)
- {
- ReplicationSlotValidateName(item->value, ERROR);
- PrimarySlotName = pstrdup(item->value);
- ereport(DEBUG2,
- (errmsg_internal("primary_slot_name = '%s'",
- PrimarySlotName)));
- }
- else if (strcmp(item->name, "trigger_file") == 0)
- {
- TriggerFile = pstrdup(item->value);
- ereport(DEBUG2,
- (errmsg_internal("trigger_file = '%s'",
- TriggerFile)));
- }
- else if (strcmp(item->name, "recovery_min_apply_delay") == 0)
- {
- const char *hintmsg;
+ /*
+ * We don't support standby mode in standalone backends; that requires
+ * other processes such as the WAL receiver to be alive.
+ */
+ if (StandbyModeRequested && !IsUnderPostmaster)
+ ereport(FATAL,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("standby mode is not supported by single-user servers")));
+}
- if (!parse_int(item->value, &recovery_min_apply_delay, GUC_UNIT_MS,
- &hintmsg))
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
- errmsg("parameter \"%s\" requires a temporal value",
- "recovery_min_apply_delay"),
- hintmsg ? errhint("%s", _(hintmsg)) : 0));
- ereport(DEBUG2,
- (errmsg_internal("recovery_min_apply_delay = '%s'", item->value)));
- }
- else
- ereport(FATAL,
- (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
- errmsg("unrecognized recovery parameter \"%s\"",
- item->name)));
- }
+static void
+validateRecoveryParameters(void)
+{
+ if (!ArchiveRecoveryRequested)
+ return;
/*
* Check for compulsory parameters
*/
if (StandbyModeRequested)
{
- if (PrimaryConnInfo == NULL && recoveryRestoreCommand == NULL)
+ if ((PrimaryConnInfo == NULL || strcmp(PrimaryConnInfo, "") == 0) &&
+ (recoveryRestoreCommand == NULL || strcmp(recoveryRestoreCommand, "") == 0))
ereport(WARNING,
- (errmsg("recovery command file \"%s\" specified neither primary_conninfo nor restore_command",
- RECOVERY_COMMAND_FILE),
+ (errmsg("specified neither primary_conninfo nor restore_command"),
errhint("The database server will regularly poll the pg_wal subdirectory to check for files placed there.")));
}
else
{
- if (recoveryRestoreCommand == NULL)
+ if (recoveryRestoreCommand == NULL ||
+ strcmp(recoveryRestoreCommand, "") == 0)
ereport(FATAL,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
- errmsg("recovery command file \"%s\" must specify restore_command when standby mode is not enabled",
- RECOVERY_COMMAND_FILE)));
+ errmsg("must specify restore_command when standby mode is not enabled")));
}
/*
@@ -5570,50 +5410,40 @@ readRecoveryCommandFile(void)
* hot_standby = off, which was surprising behaviour.
*/
if (recoveryTargetAction == RECOVERY_TARGET_ACTION_PAUSE &&
- recoveryTargetActionSet &&
!EnableHotStandby)
recoveryTargetAction = RECOVERY_TARGET_ACTION_SHUTDOWN;
/*
- * We don't support standby_mode in standalone backends; that requires
- * other processes such as the WAL receiver to be alive.
- */
- if (StandbyModeRequested && !IsUnderPostmaster)
- ereport(FATAL,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("standby mode is not supported by single-user servers")));
-
- /* Enable fetching from archive recovery area */
- ArchiveRecoveryRequested = true;
-
- /*
* If user specified recovery_target_timeline, validate it or compute the
* "latest" value. We can't do this until after we've gotten the restore
* command and set InArchiveRecovery, because we need to fetch timeline
* history files from the archive.
*/
- if (rtliGiven)
+ if (recoveryTargetTimeLineGoal == RECOVERY_TARGET_TIMELINE_NUMERIC)
{
- if (rtli)
- {
- /* Timeline 1 does not have a history file, all else should */
- if (rtli != 1 && !existsTimeLineHistory(rtli))
- ereport(FATAL,
- (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
- errmsg("recovery target timeline %u does not exist",
- rtli)));
- recoveryTargetTLI = rtli;
- recoveryTargetIsLatest = false;
- }
- else
- {
- /* We start the "latest" search from pg_control's timeline */
- recoveryTargetTLI = findNewestTimeLine(recoveryTargetTLI);
- recoveryTargetIsLatest = true;
- }
- }
+ TimeLineID rtli = recoveryTargetTLIRequested;
- FreeConfigVariables(head);
+ /* Timeline 1 does not have a history file, all else should */
+ if (rtli != 1 && !existsTimeLineHistory(rtli))
+ ereport(FATAL,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("recovery target timeline %u does not exist",
+ rtli)));
+ recoveryTargetTLI = rtli;
+ }
+ else if (recoveryTargetTimeLineGoal == RECOVERY_TARGET_TIMELINE_LATEST)
+ {
+ /* We start the "latest" search from pg_control's timeline */
+ recoveryTargetTLI = findNewestTimeLine(recoveryTargetTLI);
+ }
+ else
+ {
+ /*
+ * else we just use the recoveryTargetTLI as already read from
+ * ControlFile
+ */
+ Assert(recoveryTargetTimeLineGoal == RECOVERY_TARGET_TIMELINE_CONTROLFILE);
+ }
}
/*
@@ -5714,11 +5544,14 @@ exitArchiveRecovery(TimeLineID endTLI, XLogRecPtr endOfLog)
unlink(recoveryPath); /* ignore any error */
/*
- * Rename the config file out of the way, so that we don't accidentally
+ * Remove the signal files out of the way, so that we don't accidentally
* re-enter archive recovery mode in a subsequent crash.
*/
- unlink(RECOVERY_COMMAND_DONE);
- durable_rename(RECOVERY_COMMAND_FILE, RECOVERY_COMMAND_DONE, FATAL);
+ if (standby_signal_file_found)
+ durable_unlink(STANDBY_SIGNAL_FILE, FATAL);
+
+ if (recovery_signal_file_found)
+ durable_unlink(RECOVERY_SIGNAL_FILE, FATAL);
ereport(LOG,
(errmsg("archive recovery complete")));
@@ -6461,18 +6294,10 @@ StartupXLOG(void)
recoveryTargetTLI = ControlFile->checkPointCopy.ThisTimeLineID;
/*
- * Check for recovery control file, and if so set up state for offline
- * recovery
- */
- readRecoveryCommandFile();
-
- /*
- * Save archive_cleanup_command in shared memory so that other processes
- * can see it.
+ * Check for signal files, and if so set up state for offline recovery
*/
- strlcpy(XLogCtl->archiveCleanupCommand,
- archiveCleanupCommand ? archiveCleanupCommand : "",
- sizeof(XLogCtl->archiveCleanupCommand));
+ readRecoverySignalFile();
+ validateRecoveryParameters();
if (ArchiveRecoveryRequested)
{
@@ -6652,7 +6477,8 @@ StartupXLOG(void)
* This can happen for example if a base backup is taken from a
* running server using an atomic filesystem snapshot, without calling
* pg_start/stop_backup. Or if you just kill a running master server
- * and put it into archive recovery by creating a recovery.conf file.
+ * and put it into archive recovery by creating a recovery signal
+ * file.
*
* Our strategy in that case is to perform crash recovery first,
* replaying all the WAL present in pg_wal, and only enter archive
@@ -6687,7 +6513,7 @@ StartupXLOG(void)
{
/*
* We used to attempt to go back to a secondary checkpoint record
- * here, but only when not in standby_mode. We now just fail if we
+ * here, but only when not in standby mode. We now just fail if we
* can't read the last checkpoint because this allows us to
* simplify processing around checkpoints.
*/
@@ -6878,7 +6704,7 @@ StartupXLOG(void)
/*
* Check whether we need to force recovery from WAL. If it appears to
- * have been a clean shutdown and we did not have a recovery.conf file,
+ * have been a clean shutdown and we did not have a recovery signal file,
* then assume no recovery needed.
*/
if (checkPoint.redo < RecPtr)
@@ -6892,7 +6718,7 @@ StartupXLOG(void)
InRecovery = true;
else if (ArchiveRecoveryRequested)
{
- /* force recovery due to presence of recovery.conf */
+ /* force recovery due to presence of recovery signal file */
InRecovery = true;
}
@@ -7763,7 +7589,7 @@ StartupXLOG(void)
/*
* And finally, execute the recovery_end_command, if any.
*/
- if (recoveryEndCommand)
+ if (recoveryEndCommand && strcmp(recoveryEndCommand, "") != 0)
ExecuteRecoveryCommand(recoveryEndCommand,
"recovery_end_command",
true);
@@ -9485,8 +9311,8 @@ CreateRestartPoint(int flags)
/*
* Finally, execute archive_cleanup_command, if any.
*/
- if (XLogCtl->archiveCleanupCommand[0])
- ExecuteRecoveryCommand(XLogCtl->archiveCleanupCommand,
+ if (archiveCleanupCommand && strcmp(archiveCleanupCommand, "") != 0)
+ ExecuteRecoveryCommand(archiveCleanupCommand,
"archive_cleanup_command",
false);
@@ -11995,7 +11821,7 @@ WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess,
* that when we later jump backwards to start redo at
* RedoStartLSN, we will have the logs streamed already.
*/
- if (PrimaryConnInfo)
+ if (PrimaryConnInfo && strcmp(PrimaryConnInfo, "") != 0)
{
XLogRecPtr ptr;
TimeLineID tli;
@@ -12064,7 +11890,7 @@ WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess,
* Before we sleep, re-scan for possible new timelines if
* we were requested to recover to the latest timeline.
*/
- if (recoveryTargetIsLatest)
+ if (recoveryTargetTimeLineGoal == RECOVERY_TARGET_TIMELINE_LATEST)
{
if (rescanLatestTimeLine())
{
@@ -12367,14 +12193,14 @@ CheckForStandbyTrigger(void)
return true;
}
- if (TriggerFile == NULL)
+ if (PromoteTriggerFile == NULL || strcmp(PromoteTriggerFile, "") == 0)
return false;
- if (stat(TriggerFile, &stat_buf) == 0)
+ if (stat(PromoteTriggerFile, &stat_buf) == 0)
{
ereport(LOG,
- (errmsg("trigger file found: %s", TriggerFile)));
- unlink(TriggerFile);
+ (errmsg("promote trigger file found: %s", PromoteTriggerFile)));
+ unlink(PromoteTriggerFile);
triggered = true;
fast_promote = true;
return true;
@@ -12382,8 +12208,8 @@ CheckForStandbyTrigger(void)
else if (errno != ENOENT)
ereport(ERROR,
(errcode_for_file_access(),
- errmsg("could not stat trigger file \"%s\": %m",
- TriggerFile)));
+ errmsg("could not stat promote trigger file \"%s\": %m",
+ PromoteTriggerFile)));
return false;
}