On 19/11/14 19:51, Simon Riggs wrote:
On 19 November 2014 16:11, Petr Jelinek <p...@2ndquadrant.com> wrote:
We need to be able to tell the difference between a crashed Startup
process and this usage.
As long as we can tell, I don't mind how we do it.
Suggestions please.
Different exit code?
Try this one.
Ok this seems ok, I did couple of fixes - used exit code 3 as 2 is used
in some places - given the "if (pid == StartupPID)" it would probably
never conflict in practice, but better be safe than sorry in this case IMHO.
And you forgot to actually set the postmaster into one of the Shutdown
states so I added that.
--
Petr Jelinek http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
diff --git a/doc/src/sgml/recovery-config.sgml b/doc/src/sgml/recovery-config.sgml
index 0f1ff34..a145a3f 100644
--- a/doc/src/sgml/recovery-config.sgml
+++ b/doc/src/sgml/recovery-config.sgml
@@ -289,12 +289,39 @@ restore_command = 'copy "C:\\server\\archivedir\\%f" "%p"' # Windows
</term>
<listitem>
<para>
- Specifies whether recovery should pause when the recovery target
- is reached. The default is true.
- This is intended to allow queries to be executed against the
- database to check if this recovery target is the most desirable
- point for recovery. The paused state can be resumed by using
- <function>pg_xlog_replay_resume()</> (See
+ Alias for action_at_recovery_target, <literal>true</> is same as
+ action_at_recovery_target = <literal>pause</> and <literal>false</>
+ is same as action_at_recovery_target = <literal>promote</>.
+ </para>
+ <para>
+ This setting has no effect if <xref linkend="guc-hot-standby"> is not
+ enabled, or if no recovery target is set.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ </variablelist>
+
+ <varlistentry id="action-at-recovery-target"
+ xreflabel="action_at_recovery_target">
+ <term><varname>action_at_recovery_target</varname> (<type>enum</type>)
+ <indexterm>
+ <primary><varname>action_at_recovery_target</> recovery parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies what action the server should take once the recovery target is
+ reached. The default is <literal>pause</>, which means recovery will
+ be paused. <literal>promote</> means recovery process will finish and
+ the server will start to accept connections.
+ Finally <literal>shutdown</> will stop the server after reaching the
+ recovery target.
+ </para>
+ The intended use of <literal>pause</> setting is to allow queries to be
+ executed against the database to check if this recovery target is the
+ most desirable point for recovery. The paused state can be resumed by
+ using <function>pg_xlog_replay_resume()</> (See
<xref linkend="functions-recovery-control-table">), which then
causes recovery to end. If this recovery target is not the
desired stopping point, then shutdown the server, change the
@@ -302,8 +329,23 @@ restore_command = 'copy "C:\\server\\archivedir\\%f" "%p"' # Windows
continue recovery.
</para>
<para>
- This setting has no effect if <xref linkend="guc-hot-standby"> is not
- enabled, or if no recovery target is set.
+ The <literal>shutdown</> setting is useful to have instance ready at
+ exact replay point desired.
+ The instance will still be able to replay more WAL records (and in fact
+ will have to replay WAL records since last checkpoint next time it is
+ started).
+ </para>
+ <para>
+ Note that because <filename>recovery.conf</> will not be renamed when
+ <varname>action_at_recovery_target</> is set to <literal>shutdown</>,
+ any subsequent start will end with immediate shutdown unless the
+ configuration is changed or the <filename>recovery.conf</> is removed
+ manually.
+ </para>
+ <para>
+ This setting has no effect if no recovery target is set.
+ If <xref linkend="guc-hot-standby"> is not enabled, a setting of
+ <literal>pause</> will act the same as <literal>shutdown</>.
</para>
</listitem>
</varlistentry>
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 99f702c..6747ea6 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -228,7 +228,7 @@ static char *recoveryEndCommand = NULL;
static char *archiveCleanupCommand = NULL;
static RecoveryTargetType recoveryTarget = RECOVERY_TARGET_UNSET;
static bool recoveryTargetInclusive = true;
-static bool recoveryPauseAtTarget = true;
+static RecoveryTargetAction actionAtRecoveryTarget = RECOVERY_TARGET_ACTION_PAUSE;
static TransactionId recoveryTargetXid;
static TimestampTz recoveryTargetTime;
static char *recoveryTargetName;
@@ -4643,6 +4643,9 @@ readRecoveryCommandFile(void)
ConfigVariable *item,
*head = NULL,
*tail = NULL;
+ bool recoveryPauseAtTargetSet = false;
+ bool actionAtRecoveryTargetSet = false;
+
fd = AllocateFile(RECOVERY_COMMAND_FILE, "r");
if (fd == NULL)
@@ -4688,13 +4691,43 @@ readRecoveryCommandFile(void)
}
else if (strcmp(item->name, "pause_at_recovery_target") == 0)
{
+ bool recoveryPauseAtTarget;
+
if (!parse_bool(item->value, &recoveryPauseAtTarget))
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("parameter \"%s\" requires a Boolean value", "pause_at_recovery_target")));
+
ereport(DEBUG2,
(errmsg_internal("pause_at_recovery_target = '%s'",
item->value)));
+
+ actionAtRecoveryTarget = recoveryPauseAtTarget ?
+ RECOVERY_TARGET_ACTION_PAUSE :
+ RECOVERY_TARGET_ACTION_PROMOTE;
+
+ recoveryPauseAtTargetSet = true;
+ }
+ else if (strcmp(item->name, "action_at_recovery_target") == 0)
+ {
+ if (strcmp(item->value, "pause") == 0)
+ actionAtRecoveryTarget = RECOVERY_TARGET_ACTION_PAUSE;
+ else if (strcmp(item->value, "promote") == 0)
+ actionAtRecoveryTarget = RECOVERY_TARGET_ACTION_PROMOTE;
+ else if (strcmp(item->value, "shutdown") == 0)
+ actionAtRecoveryTarget = RECOVERY_TARGET_ACTION_SHUTDOWN;
+ else
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("invalid value for recovery parameter \"%s\"",
+ "action_at_recovery_target"),
+ errhint("The allowed values are \"pause\", \"promote\" and \"shutdown\".")));
+
+ ereport(DEBUG2,
+ (errmsg_internal("action_at_recovery_target = '%s'",
+ item->value)));
+
+ actionAtRecoveryTargetSet = true;
}
else if (strcmp(item->name, "recovery_target_timeline") == 0)
{
@@ -4859,6 +4892,25 @@ readRecoveryCommandFile(void)
RECOVERY_COMMAND_FILE)));
}
+ /*
+ * Check for mutually exclusive parameters
+ */
+ if (recoveryPauseAtTargetSet && actionAtRecoveryTargetSet)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("cannot set both \"%s\" and \"%s\" recovery parameters",
+ "pause_at_recovery_target",
+ "action_at_recovery_target"),
+ errhint("The \"pause_at_recovery_target\" is deprecated.")));
+
+
+ /*
+ * Override any inconsistent requests
+ */
+ if (actionAtRecoveryTarget == RECOVERY_TARGET_ACTION_PAUSE &&
+ standbyState == STANDBY_DISABLED)
+ actionAtRecoveryTarget = RECOVERY_TARGET_ACTION_SHUTDOWN;
+
/* Enable fetching from archive recovery area */
ArchiveRecoveryRequested = true;
@@ -6408,10 +6460,37 @@ StartupXLOG(void)
* end of main redo apply loop
*/
- if (recoveryPauseAtTarget && reachedStopPoint)
+ if (reachedStopPoint)
{
- SetRecoveryPause(true);
- recoveryPausesHere();
+ if (!reachedConsistency)
+ ereport(FATAL,
+ (errmsg("requested recovery stop point is before consistent recovery point")));
+
+ /*
+ * This is the last point where we can restart recovery with a
+ * new recovery target, if we shutdown and begin again. After
+ * this, Resource Managers may choose to do permanent corrective
+ * actions at end of recovery.
+ */
+ switch (actionAtRecoveryTarget)
+ {
+ case RECOVERY_TARGET_ACTION_SHUTDOWN:
+ /*
+ * exit with special return code to request shutdown
+ * of postmaster. Log messages issued from
+ * postmaster.
+ */
+ proc_exit(3);
+
+ case RECOVERY_TARGET_ACTION_PAUSE:
+ SetRecoveryPause(true);
+ recoveryPausesHere();
+
+ /* drop into promote */
+
+ case RECOVERY_TARGET_ACTION_PROMOTE:
+ break;
+ }
}
/* Allow resource managers to do any required cleanup. */
@@ -6429,6 +6508,7 @@ StartupXLOG(void)
ereport(LOG,
(errmsg("last completed transaction was at log time %s",
timestamptz_to_str(xtime))));
+
InRedo = false;
}
else
@@ -6479,13 +6559,6 @@ StartupXLOG(void)
(EndOfLog < minRecoveryPoint ||
!XLogRecPtrIsInvalid(ControlFile->backupStartPoint)))
{
- if (reachedStopPoint)
- {
- /* stopped because of stop request */
- ereport(FATAL,
- (errmsg("requested recovery stop point is before consistent recovery point")));
- }
-
/*
* Ran off end of WAL before reaching end-of-backup WAL record, or
* minRecoveryPoint. That's usually a bad sign, indicating that you
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index 6220a8e..5106f52 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -509,6 +509,7 @@ static void ShmemBackendArrayRemove(Backend *bn);
/* Macros to check exit status of a child process */
#define EXIT_STATUS_0(st) ((st) == 0)
#define EXIT_STATUS_1(st) (WIFEXITED(st) && WEXITSTATUS(st) == 1)
+#define EXIT_STATUS_3(st) (WIFEXITED(st) && WEXITSTATUS(st) == 3)
#ifndef WIN32
/*
@@ -2555,6 +2556,17 @@ reaper(SIGNAL_ARGS)
continue;
}
+ if (EXIT_STATUS_3(exitstatus))
+ {
+ ereport(LOG,
+ (errmsg("shutdown at recovery target")));
+ Shutdown = SmartShutdown;
+ TerminateChildren(SIGTERM);
+ pmState = PM_WAIT_BACKENDS;
+ /* PostmasterStateMachine logic does the rest */
+ continue;
+ }
+
/*
* Unexpected exit of startup process (including FATAL exit)
* during PM_STARTUP is treated as catastrophic. There are no
diff --git a/src/include/access/xlog_internal.h b/src/include/access/xlog_internal.h
index 19b2ef8..04866e6 100644
--- a/src/include/access/xlog_internal.h
+++ b/src/include/access/xlog_internal.h
@@ -204,6 +204,16 @@ typedef struct xl_end_of_recovery
} xl_end_of_recovery;
/*
+ * Recovery target action.
+ */
+typedef enum
+{
+ RECOVERY_TARGET_ACTION_PAUSE,
+ RECOVERY_TARGET_ACTION_PROMOTE,
+ RECOVERY_TARGET_ACTION_SHUTDOWN,
+} RecoveryTargetAction;
+
+/*
* Method table for resource managers.
*
* This struct must be kept in sync with the PG_RMGR definition in
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers