On 12/09/2013 03:05 PM, MauMau wrote:
From: "Heikki Linnakangas" <hlinnakan...@vmware.com>
Thanks. Looks sane, although I don't much like the proposed interface
to trigger this, setting recovery_target_time='backup_point'. What the
code actually does is to stop recovery as soon as you reach
consistency, which might not have anything to do with a backup. If you
set it on a warm standby server, for example, it will end recovery as
soon as it reaches consistency, but there was probably no backup taken
at that point.

Thank you for reviewing so rapidly.  I thought I would check the end of
backup in recoveryStopsHere(), by matching XLOG_BACKUP_END and
ControlFile->backupStartPoint for backups taken on the primary, and
comparing the current redo location with ControlFile->backupEndPoint for
backups taken on the standby.  However, that would duplicate much code
in XLOG_BACKUP_END redo processing and checkRecoveryConsistency().
Besides, the code works only when the user explicitly requests recovery
to backup point, not when he starts the warm standby server.  (I wonder
I'm answering correctly.)

I was thinking that you have a warm standby server, and you decide to stop using it as a warm standby, and promote it. You'd do that by stopping it, modifying recovery.conf to remove standby_mode, and set a recovery target, and then restart.

After some refactoring and fixing bugs in the existing code, I came up with the attached patch. I called the option simply "recovery_target", with the only allowed value of "immediate". IOW, if you want to stop recovery as early as possible, you add recovery_target='immediate' to recovery.conf. Now that we have four different options to set the recovery target with, I rearranged the docs slightly. How does this look to you?

- Heikki
diff --git a/doc/src/sgml/backup.sgml b/doc/src/sgml/backup.sgml
index a2361d7..854b5fd 100644
--- a/doc/src/sgml/backup.sgml
+++ b/doc/src/sgml/backup.sgml
@@ -1124,7 +1124,7 @@ restore_command = 'cp /mnt/server/archivedir/%f %p'
    <para>
     If you want to recover to some previous point in time (say, right before
     the junior DBA dropped your main transaction table), just specify the
-    required stopping point in <filename>recovery.conf</>.  You can specify
+    required <link linkend="recovery-target-settings">stopping point</link> in <filename>recovery.conf</>.  You can specify
     the stop point, known as the <quote>recovery target</>, either by
     date/time, named restore point or by completion of a specific transaction
     ID.  As of this writing only the date/time and named restore point options
diff --git a/doc/src/sgml/recovery-config.sgml b/doc/src/sgml/recovery-config.sgml
index 550cdce..a723338 100644
--- a/doc/src/sgml/recovery-config.sgml
+++ b/doc/src/sgml/recovery-config.sgml
@@ -199,8 +199,33 @@ restore_command = 'copy "C:\\server\\archivedir\\%f" "%p"'  # Windows
   <sect1 id="recovery-target-settings">
 
     <title>Recovery Target Settings</title>
+     <para>
+      By default, recovery will recover to the end of the WAL log. The
+      following parameters can be used to specify an earlier stopping point.
+      At most one of <varname>recovery_target</>,
+      <varname>recovery_target_name</>, <varname>recovery_target_time</>, or
+      <varname>recovery_target_xid</> can be specified. 
+     </para>
      <variablelist>
 
+     <varlistentry id="recovery-target" xreflabel="recovery_target_name">
+      <term><varname>recovery_target</varname><literal> = 'immediate'</literal></term>
+      <indexterm>
+        <primary><varname>recovery_target</> recovery parameter</primary>
+      </indexterm>
+      <listitem>
+       <para>
+        This parameter specifies that recovery should end as soon as a
+        consistency is reached, ie. as early as possible. When restoring from an
+        online backup, this means the point where taking the backup ended.
+       </para>
+       <para>
+        Technically, this is a string parameter, but <literal>'immediate'</l>
+        is currently the only allowed value.
+       </para>
+      </listitem>
+     </varlistentry>
+
      <varlistentry id="recovery-target-name" xreflabel="recovery_target_name">
       <term><varname>recovery_target_name</varname>
            (<type>string</type>)
@@ -212,10 +237,6 @@ restore_command = 'copy "C:\\server\\archivedir\\%f" "%p"'  # Windows
        <para>
         This parameter specifies the named restore point, created with
         <function>pg_create_restore_point()</> to which recovery will proceed.
-        At most one of <varname>recovery_target_name</>,
-        <xref linkend="recovery-target-time"> or
-        <xref linkend="recovery-target-xid"> can be specified.  The default is to
-        recover to the end of the WAL log.
        </para>
       </listitem>
      </varlistentry>
@@ -231,10 +252,6 @@ restore_command = 'copy "C:\\server\\archivedir\\%f" "%p"'  # Windows
        <para>
         This parameter specifies the time stamp up to which recovery
         will proceed.
-        At most one of <varname>recovery_target_time</>,
-        <xref linkend="recovery-target-name"> or
-        <xref linkend="recovery-target-xid"> can be specified.
-        The default is to recover to the end of the WAL log.
         The precise stopping point is also influenced by
         <xref linkend="recovery-target-inclusive">.
        </para>
@@ -254,15 +271,18 @@ restore_command = 'copy "C:\\server\\archivedir\\%f" "%p"'  # Windows
         start, transactions can complete in a different numeric order.
         The transactions that will be recovered are those that committed
         before (and optionally including) the specified one.
-        At most one of <varname>recovery_target_xid</>,
-        <xref linkend="recovery-target-name"> or
-        <xref linkend="recovery-target-time"> can be specified.
-        The default is to recover to the end of the WAL log.
         The precise stopping point is also influenced by
         <xref linkend="recovery-target-inclusive">.
        </para>
       </listitem>
      </varlistentry>
+     </variablelist>
+     <para>
+       The following options further specify the recovery target, and affect
+       what happens when the target is reached:
+     </para>
+
+     <variablelist>
 
      <varlistentry id="recovery-target-inclusive"
                    xreflabel="recovery_target_inclusive">
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index b53ae87..a24586a 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -5434,6 +5434,19 @@ readRecoveryCommandFile(void)
 					(errmsg_internal("recovery_target_name = '%s'",
 									 recoveryTargetName)));
 		}
+		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 recovery_target parameter"),
+						 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)
 		{
 			/*
@@ -5502,7 +5515,7 @@ readRecoveryCommandFile(void)
 							RECOVERY_COMMAND_FILE),
 					 errhint("The database server will regularly poll the pg_xlog subdirectory to check for files placed there.")));
 	}
-	else
+	else if (recoveryTargetTime != 0)
 	{
 		if (recoveryRestoreCommand == NULL)
 			ereport(FATAL,
@@ -5676,7 +5689,20 @@ recoveryStopsBefore(XLogRecord *record)
 	bool		isCommit;
 	TimestampTz recordXtime = 0;
 
-	/* We only consider stopping before COMMIT or ABORT records. */
+	/* Check if we should stop as soon as reaching consistency */
+	if (recoveryTarget == RECOVERY_TARGET_IMMEDIATE && reachedConsistency)
+	{
+		ereport(LOG,
+				(errmsg("recovery stopping after reaching consistency")));
+
+		recoveryStopAfter = false;
+		recoveryStopXid = InvalidTransactionId;
+		recoveryStopTime = 0;
+		recoveryStopName[0] = '\0';
+		return true;
+	}
+
+	/* Otherwise we only consider stopping before COMMIT or ABORT records. */
 	if (record->xl_rmid != RM_XACT_ID)
 		return false;
 	record_info = record->xl_info & ~XLR_INFO_MASK;
@@ -5825,6 +5851,19 @@ recoveryStopsAfter(XLogRecord *record)
 		}
 	}
 
+	/* Check if we should stop as soon as reaching consistency */
+	if (recoveryTarget == RECOVERY_TARGET_IMMEDIATE && reachedConsistency)
+	{
+		ereport(LOG,
+				(errmsg("recovery stopping after reaching consistency")));
+
+		recoveryStopAfter = true;
+		recoveryStopXid = InvalidTransactionId;
+		recoveryStopTime = 0;
+		recoveryStopName[0] = '\0';
+		return true;
+	}
+
 	return false;
 }
 
@@ -6238,6 +6277,10 @@ StartupXLOG(void)
 			ereport(LOG,
 					(errmsg("starting point-in-time recovery to XID %u",
 							recoveryTargetXid)));
+		else if (recoveryTarget == RECOVERY_TARGET_TIME &&
+			recoveryTargetTime == 0)
+			ereport(LOG,
+					(errmsg("starting point-in-time recovery to backup point")));
 		else if (recoveryTarget == RECOVERY_TARGET_TIME)
 			ereport(LOG,
 					(errmsg("starting point-in-time recovery to %s",
@@ -6246,6 +6289,9 @@ StartupXLOG(void)
 			ereport(LOG,
 					(errmsg("starting point-in-time recovery to \"%s\"",
 							recoveryTargetName)));
+		else if (recoveryTarget == RECOVERY_TARGET_IMMEDIATE)
+			ereport(LOG,
+					(errmsg("starting point-in-time recovery to earliest consistent point")));
 		else
 			ereport(LOG,
 					(errmsg("starting archive recovery")));
@@ -6971,6 +7017,22 @@ StartupXLOG(void)
 				if (switchedTLI && AllowCascadeReplication())
 					WalSndWakeup();
 
+				/*
+				 * If we have reached the end of base backup during recovery
+				 * to the backup point, exit redo loop.
+				 */
+				if (recoveryTarget == RECOVERY_TARGET_TIME &&
+					recoveryTargetTime == 0 && reachedConsistency)
+				{
+					if (recoveryPauseAtTarget)
+					{
+						SetRecoveryPause(true);
+						recoveryPausesHere();
+					}
+					reachedStopPoint = true;
+					break;
+				}
+
 				/* Exit loop if we reached inclusive recovery target */
 				if (recoveryStopsAfter(record))
 				{
@@ -7116,6 +7178,9 @@ StartupXLOG(void)
 					 "%s transaction %u",
 					 recoveryStopAfter ? "after" : "before",
 					 recoveryStopXid);
+		else if (recoveryTarget == RECOVERY_TARGET_TIME &&
+			recoveryStopTime == 0)
+			snprintf(reason, sizeof(reason), "at backup point");
 		else if (recoveryTarget == RECOVERY_TARGET_TIME)
 			snprintf(reason, sizeof(reason),
 					 "%s %s\n",
@@ -7125,6 +7190,8 @@ StartupXLOG(void)
 			snprintf(reason, sizeof(reason),
 					 "at restore point \"%s\"",
 					 recoveryStopName);
+		else if (recoveryTarget == RECOVERY_TARGET_IMMEDIATE)
+			snprintf(reason, sizeof(reason), "reached consistency");
 		else
 			snprintf(reason, sizeof(reason), "no recovery target specified");
 
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index 017e74d..0a8f54d 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -173,7 +173,8 @@ typedef enum
 	RECOVERY_TARGET_UNSET,
 	RECOVERY_TARGET_XID,
 	RECOVERY_TARGET_TIME,
-	RECOVERY_TARGET_NAME
+	RECOVERY_TARGET_NAME,
+	RECOVERY_TARGET_IMMEDIATE
 } RecoveryTargetType;
 
 extern XLogRecPtr XactLastRecEnd;
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to