Hi,
Attached is the v2 of the patch with the review comments addressed (see
below).
On 29/10/14 21:08, Petr Jelinek wrote:
On 29/10/14 20:27, Asif Naeem wrote:
1. It seems that following log message need to be more descriptive about
reason for shutdown i.e.
+ if (recoveryShutdownAtTarget && reachedStopPoint)
+ {
+ ereport(LOG, (errmsg("shutting
down")));
Agreed, I just wasn't sure on what exactly to writes, I originally had
there "shutting down by user request" or some such but that's misleading.
I changed it to "shutting down at recovery target" hope that's better.
2. As Simon suggesting following recovery settings are not clear i.e.
shutdown_at_recovery_target = true
pause_at_recovery_target = true
Hmm I completely missed Simon's email, strange. Well other option would
be to throw error if both are set to true - error will have to happen
anyway if action_at_recovery_target is set to shutdown while
pause_at_recovery_target is true (I think we need to keep
pause_at_recovery_target for compatibility).
But considering all of you think something like
action_at_recovery_target is better solution, I will do it that way then.
Done, there is now action_at_recovery_target which can be set to either
pause, continue or shutdown, defaulting to pause (which is same as old
behavior of pause_at_recovery_target defaulting to true).
I also added check that prohibits using both pause_at_recovery_target
and action_at_recovery_target in the same config, mainly to avoid users
shooting themselves in the foot.
3. As it don’t rename reconvery.conf, subsequent attempt (without any
changes in reconvery.conf) to start of server keep showing the following
i.e.
...
LOG: redo starts at 0/1803620
DEBUG: checkpointer updated shared memory configuration values
LOG: consistent recovery state reached at 0/1803658
LOG: restored log file "000000010000000000000002" from archive
DEBUG: got WAL segment from archive
LOG: restored log file "000000010000000000000003" from archive
DEBUG: got WAL segment from archive
LOG: restored log file "000000010000000000000004" from archive
DEBUG: got WAL segment from archive
LOG: restored log file "000000010000000000000005" from archive
DEBUG: got WAL segment from archive
LOG: restored log file "000000010000000000000006" from archive
DEBUG: got WAL segment from archive
…
Yes, it will still replay everything since last checkpoint, that's by
design since otherwise we would have to write checkpoint on shutdown and
that would mean the instance can't be used as hot standby anymore and I
consider that an important feature to have.
I added note to the documentation that says this will happen.
--
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..fe42394 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>continue</>.
+ </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 should PostgreSQL do once the recovery target is
+ reached. The default is <literal>pause</>, which means recovery will
+ be paused. <literal>continue</> means there will be no special action
+ taken when recovery target is reached and normal operation will continue.
+ Finally <literal>shutdown</> will stop the PostgreSQL instance at
+ 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,6 +329,20 @@ restore_command = 'copy "C:\\server\\archivedir\\%f" "%p"' # Windows
continue recovery.
</para>
<para>
+ 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 upon 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 <xref linkend="guc-hot-standby"> is not
enabled, or if no recovery target is set.
</para>
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 3c9aeae..974e6c1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -227,7 +227,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;
@@ -5068,6 +5068,9 @@ readRecoveryCommandFile(void)
ConfigVariable *item,
*head = NULL,
*tail = NULL;
+ bool recoveryPauseAtTargetSet = false;
+ bool actionAtRecoveryTargetSet = false;
+
fd = AllocateFile(RECOVERY_COMMAND_FILE, "r");
if (fd == NULL)
@@ -5113,13 +5116,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_CONTINUE;
+
+ 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, "continue") == 0)
+ actionAtRecoveryTarget = RECOVERY_TARGET_ACTION_CONTINUE;
+ 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\", \"continue\" and \"shutdown\".")));
+
+ ereport(DEBUG2,
+ (errmsg_internal("action_at_recovery_target = '%s'",
+ item->value)));
+
+ actionAtRecoveryTargetSet = true;
}
else if (strcmp(item->name, "recovery_target_timeline") == 0)
{
@@ -5284,6 +5317,18 @@ 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.")));
+
+
/* Enable fetching from archive recovery area */
ArchiveRecoveryRequested = true;
@@ -6832,7 +6877,8 @@ StartupXLOG(void)
* end of main redo apply loop
*/
- if (recoveryPauseAtTarget && reachedStopPoint)
+ if (actionAtRecoveryTarget == RECOVERY_TARGET_ACTION_PAUSE &&
+ reachedStopPoint)
{
SetRecoveryPause(true);
recoveryPausesHere();
@@ -6853,6 +6899,25 @@ StartupXLOG(void)
ereport(LOG,
(errmsg("last completed transaction was at log time %s",
timestamptz_to_str(xtime))));
+
+ /*
+ * Shutdown here when requested. We need to exit this early because
+ * we want to be able to continue the WAL replay when started
+ * the next time.
+ */
+ if (actionAtRecoveryTarget == RECOVERY_TARGET_ACTION_SHUTDOWN &&
+ reachedStopPoint)
+ {
+ ereport(LOG, (errmsg("shutting down at recovery target")));
+ /*
+ * Note that we exit with status 2 instead of 0 here to force
+ * postmaster shutdown the whole instance. This produces one
+ * unnecessary log line, but we don't have better way to
+ * shutdown postmaster from within single backend.
+ */
+ proc_exit(2);
+ }
+
InRedo = false;
}
else
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index 0ae110f..7e48138 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -179,6 +179,16 @@ typedef enum
RECOVERY_TARGET_IMMEDIATE
} RecoveryTargetType;
+/*
+ * Recovery target action.
+ */
+typedef enum
+{
+ RECOVERY_TARGET_ACTION_PAUSE,
+ RECOVERY_TARGET_ACTION_CONTINUE,
+ RECOVERY_TARGET_ACTION_SHUTDOWN,
+} RecoveryTargetAction;
+
extern XLogRecPtr XactLastRecEnd;
extern bool reachedConsistency;
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers