Request for vote to move forward with recovery.conf overhaul

Started by Bruce Momjianabout 13 years ago29 messages
#1Bruce Momjian
bruce@momjian.us

There has been discussion in the past of removing or significantly
changing the way streaming replication/point-in-time-recovery (PITR) is
setup in Postgres. Currently the file recovery.conf is used, but that
was designed for PITR and does not serve streaming replication well.

This all should have been overhauled when streaming replication was
added in 2010 in Postgres 9.0. However, time constraints and concern
about backward compatibility has hampered this overhaul.

At this point, backward compatibility seems to be hampering our ability
to move forward. I would like a vote that supports creation of a new
method for setting up streaming replication/point-in-time-recovery,
where backward compatibility is considered only where it is minimally
invasive.

--
Bruce Momjian <bruce@momjian.us> http://momjian.us
EnterpriseDB http://enterprisedb.com

+ It's impossible for everything to be true. +

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#2Simon Riggs
simon@2ndQuadrant.com
In reply to: Bruce Momjian (#1)
Re: Request for vote to move forward with recovery.conf overhaul

On 21 December 2012 19:46, Bruce Momjian <bruce@momjian.us> wrote:

There has been discussion in the past of removing or significantly
changing the way streaming replication/point-in-time-recovery (PITR) is
setup in Postgres. Currently the file recovery.conf is used, but that
was designed for PITR and does not serve streaming replication well.

This all should have been overhauled when streaming replication was
added in 2010 in Postgres 9.0. However, time constraints and concern
about backward compatibility has hampered this overhaul.

At this point, backward compatibility seems to be hampering our ability
to move forward. I would like a vote that supports creation of a new
method for setting up streaming replication/point-in-time-recovery,
where backward compatibility is considered only where it is minimally
invasive.

Given that I've said all along that I want change, I'll vote for that,
especially since it is so reasonably worded.

I also want backwards compatibility, so I would like whoever does this
change to also spend some time on that, since it seems that the
balance of time/cost is good enough to make it sensible to do so. I
hope we can spend the time on that investigation, rather than further
debate around what we mean by the word minimally.

--
Simon Riggs http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#3Phil Sorber
phil@omniti.com
In reply to: Bruce Momjian (#1)
Re: Request for vote to move forward with recovery.conf overhaul

On Fri, Dec 21, 2012 at 2:46 PM, Bruce Momjian <bruce@momjian.us> wrote:

There has been discussion in the past of removing or significantly
changing the way streaming replication/point-in-time-recovery (PITR) is
setup in Postgres. Currently the file recovery.conf is used, but that
was designed for PITR and does not serve streaming replication well.

This all should have been overhauled when streaming replication was
added in 2010 in Postgres 9.0. However, time constraints and concern
about backward compatibility has hampered this overhaul.

At this point, backward compatibility seems to be hampering our ability
to move forward. I would like a vote that supports creation of a new
method for setting up streaming replication/point-in-time-recovery,
where backward compatibility is considered only where it is minimally
invasive.

--
Bruce Momjian <bruce@momjian.us> http://momjian.us
EnterpriseDB http://enterprisedb.com

+ It's impossible for everything to be true. +

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

+1

I seemed to have lost track of the thread that this spawned out of. Is
there a coherent plan for a way forward at this point? Last I recall
it was Simon's plan vs Bruce's plan. I also seem to recall there was a
patch out there too. I think it's even in the commitfest waiting on
author.

/me searches

Here:
https://commitfest.postgresql.org/action/patch_view?id=1026

Perhaps we can get the two plans enumerated, vote, and then get a patch out?

I'd really like to see this in 9.3, but not sure if that ship has
sailed for this feature or not.

Thanks.

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#4Michael Paquier
michael.paquier@gmail.com
In reply to: Phil Sorber (#3)
Re: Request for vote to move forward with recovery.conf overhaul

On Tue, Jan 22, 2013 at 1:11 AM, Phil Sorber <phil@omniti.com> wrote:

On Fri, Dec 21, 2012 at 2:46 PM, Bruce Momjian <bruce@momjian.us> wrote:

There has been discussion in the past of removing or significantly
changing the way streaming replication/point-in-time-recovery (PITR) is
setup in Postgres. Currently the file recovery.conf is used, but that
was designed for PITR and does not serve streaming replication well.

This all should have been overhauled when streaming replication was
added in 2010 in Postgres 9.0. However, time constraints and concern
about backward compatibility has hampered this overhaul.

At this point, backward compatibility seems to be hampering our ability
to move forward. I would like a vote that supports creation of a new
method for setting up streaming replication/point-in-time-recovery,
where backward compatibility is considered only where it is minimally
invasive.

--
Bruce Momjian <bruce@momjian.us> http://momjian.us
EnterpriseDB http://enterprisedb.com

+ It's impossible for everything to be true. +

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

+1

I seemed to have lost track of the thread that this spawned out of. Is
there a coherent plan for a way forward at this point? Last I recall
it was Simon's plan vs Bruce's plan. I also seem to recall there was a
patch out there too. I think it's even in the commitfest waiting on
author.

/me searches

Here:
https://commitfest.postgresql.org/action/patch_view?id=1026

Perhaps we can get the two plans enumerated, vote, and then get a patch
out?

I'd really like to see this in 9.3, but not sure if that ship has
sailed for this feature or not.

Yes, that is one of the most important patches in the list, and I could put
some effort in it for either review or coding.
It is an 17-month-old-patch, so of course it does not apply on master.
However before taking any actions, I would like to know the following:
- Simon, are you planning to update this patch?
- As we are rushing to finish wrapping up 9.3, do you consider it is too
late to begin that?

Thanks,
--
Michael Paquier
http://michael.otacoo.com

#5Robert Haas
robertmhaas@gmail.com
In reply to: Michael Paquier (#4)
Re: Request for vote to move forward with recovery.conf overhaul

On Mon, Jan 21, 2013 at 6:23 PM, Michael Paquier
<michael.paquier@gmail.com> wrote:

Yes, that is one of the most important patches in the list, and I could put
some effort in it for either review or coding.

I think it would be great if you could elaborate on your reasons for
feeling that this patch is particularly important.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#6Michael Paquier
michael.paquier@gmail.com
In reply to: Robert Haas (#5)
Re: Request for vote to move forward with recovery.conf overhaul

On Tue, Jan 22, 2013 at 9:27 AM, Robert Haas <robertmhaas@gmail.com> wrote:

On Mon, Jan 21, 2013 at 6:23 PM, Michael Paquier
<michael.paquier@gmail.com> wrote:

Yes, that is one of the most important patches in the list, and I could

put

some effort in it for either review or coding.

I think it would be great if you could elaborate on your reasons for
feeling that this patch is particularly important.

Sure. recovery.conf has been initially created for PITR management, but
since 9.0 and the introduction of streaming replication it is being used
for too many things that it was first targeting for, like now it can be
used to define where a slave can connect to a root node, fetch the
archives, etc. I am seeing for a long time on hackers (2010?) that postgres
should make the move on giving up recovery.conf and merge it with
postgresql.conf.

I didn't know about the existence of a patch aimed to merge the parameters
of postgresql.conf and recovery.conf, and, just by looking at the patch,
half of the work looks to be already done. I thought it might be worth to
at least update the patch or provide some feedback.

I agree that this might break backward-compatibility and that it would be
more suited for a 10.0(?), but as 9.3 development is already close to its
end, progressing on this discussion and decide whether this could be
shipped for 9.3 or later release is important. If it is decided to give up
on this feature, well let's do that later. If it is worth the shot, let's
put some effort for it.
--
Michael Paquier
http://michael.otacoo.com

#7Cédric Villemain
cedric@2ndquadrant.com
In reply to: Michael Paquier (#6)
Re: Request for vote to move forward with recovery.conf overhaul

Le mardi 22 janvier 2013 01:54:50, Michael Paquier a écrit :

On Tue, Jan 22, 2013 at 9:27 AM, Robert Haas <robertmhaas@gmail.com> wrote:

On Mon, Jan 21, 2013 at 6:23 PM, Michael Paquier
<michael.paquier@gmail.com> wrote:

Yes, that is one of the most important patches in the list, and I could

put

some effort in it for either review or coding.

I think it would be great if you could elaborate on your reasons for
feeling that this patch is particularly important.

Sure. recovery.conf has been initially created for PITR management, but
since 9.0 and the introduction of streaming replication it is being used
for too many things that it was first targeting for, like now it can be
used to define where a slave can connect to a root node, fetch the
archives, etc. I am seeing for a long time on hackers (2010?) that postgres
should make the move on giving up recovery.conf and merge it with
postgresql.conf.

I didn't know about the existence of a patch aimed to merge the parameters
of postgresql.conf and recovery.conf, and, just by looking at the patch,
half of the work looks to be already done. I thought it might be worth to
at least update the patch or provide some feedback.

I agree that this might break backward-compatibility and that it would be
more suited for a 10.0(?), but as 9.3 development is already close to its
end, progressing on this discussion and decide whether this could be
shipped for 9.3 or later release is important. If it is decided to give up
on this feature, well let's do that later. If it is worth the shot, let's
put some effort for it.

I though the idea is that for 9.3 we can have new feature, so everything can
go in postgreql.conf, and also allows using recovery.conf so it does not break
backward-compatibility.

--
Cédric Villemain +33 (0)6 20 30 22 52
http://2ndQuadrant.fr/
PostgreSQL: Support 24x7 - Développement, Expertise et Formation

#8Simon Riggs
simon@2ndquadrant.com
In reply to: Michael Paquier (#4)
Re: Request for vote to move forward with recovery.conf overhaul

On 21 January 2013 23:23, Michael Paquier <michael.paquier@gmail.com> wrote:

It is an 17-month-old-patch, so of course it does not apply on master.
However before taking any actions, I would like to know the following:
- Simon, are you planning to update this patch?

It's on my list, but not at the front to the queue.

If you want to know what my priority queue looks like... (preliminary opinion)
1. Skip checkpoint on promoting from streaming replication (almost ready)
2. Further review of WAL decoding (opinion pending, but very solid)
3. Performance Improvement by reducing WAL for Update Operation (likely commit)
4. Row Level Security (possible commit)
5. Checksums (maybe commit)
6. Make recovery.conf parameters into GUCs (commit something of use,
but very basic)

Which is at least 2 weeks work

- As we are rushing to finish wrapping up 9.3, do you consider it is too
late to begin that?

It's late. And it doesn't get to jump my queue. Whether its too late
is not for me to say.

--
Simon Riggs http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#9Michael Paquier
michael.paquier@gmail.com
In reply to: Simon Riggs (#8)
1 attachment(s)
Re: Request for vote to move forward with recovery.conf overhaul

On Wed, Jan 23, 2013 at 8:51 AM, Simon Riggs <simon@2ndquadrant.com> wrote:

On 21 January 2013 23:23, Michael Paquier <michael.paquier@gmail.com>
wrote:

It is an 17-month-old-patch, so of course it does not apply on master.
However before taking any actions, I would like to know the following:
- Simon, are you planning to update this patch?

It's on my list, but not at the front to the queue.

If you want to know what my priority queue looks like... (preliminary
opinion)
1. Skip checkpoint on promoting from streaming replication (almost ready)
2. Further review of WAL decoding (opinion pending, but very solid)
3. Performance Improvement by reducing WAL for Update Operation (likely
commit)
4. Row Level Security (possible commit)
5. Checksums (maybe commit)
6. Make recovery.conf parameters into GUCs (commit something of use,
but very basic)

Thanks. It is good to know.
As you are not planning to touch the patch, I took myself the last version
of Masao and realigned it with current head.
Here is what the patch does in details:
- Move all the recovery.conf parameters in postgresql.conf
- recovery.conf is removed (no backward compatibility in this version of
the patch)
- if you want to trigger a recovery at promotion or have the recovery
parameters read on slave at startup, you need to create a file called
recovery.trigger in PGDATA. (something like "touch recovery.conf" is
enough). Once recovery is done, recovery.trigger is changed to
recovery.done.

I found in the original patch a couple of bugs, which might have been there
because things have changed a bit since 9.2 dev, especially around the
trigger file. Those bugs are fixed. I also tested this new configuration
set with several slaves, cascading slaves and even played with timeline
switches... And it worked correctly.
I found that support for pg_basebackup -R was in the old patch, and I
haven't done anything for that yet.

Hope it helps. Thanks,
--
Michael Paquier
http://michael.otacoo.com

Attachments:

20130123_recovery_unite.patchapplication/octet-stream; name=20130123_recovery_unite.patchDownload
diff --git a/contrib/pg_archivecleanup/pg_archivecleanup.c b/contrib/pg_archivecleanup/pg_archivecleanup.c
index e97a11c..fb01da9 100644
--- a/contrib/pg_archivecleanup/pg_archivecleanup.c
+++ b/contrib/pg_archivecleanup/pg_archivecleanup.c
@@ -255,7 +255,7 @@ usage(void)
 	printf("  -x EXT         clean up files if they have this extension\n");
 	printf("  -?, --help     show this help, then exit\n");
 	printf("\n"
-		   "For use as archive_cleanup_command in recovery.conf when standby_mode = on:\n"
+		   "For use as archive_cleanup_command in postgresql.conf when standby_mode = on:\n"
 		   "  archive_cleanup_command = 'pg_archivecleanup [OPTION]... ARCHIVELOCATION %%r'\n"
 		   "e.g.\n"
 		   "  archive_cleanup_command = 'pg_archivecleanup /mnt/server/archiverdir %%r'\n");
diff --git a/contrib/pg_standby/pg_standby.c b/contrib/pg_standby/pg_standby.c
index 659bd50..115c25e 100644
--- a/contrib/pg_standby/pg_standby.c
+++ b/contrib/pg_standby/pg_standby.c
@@ -531,7 +531,7 @@ usage(void)
 	printf("  -w MAXWAITTIME     max seconds to wait for a file (0=no limit) (default=0)\n");
 	printf("  -?, --help         show this help, then exit\n");
 	printf("\n"
-		   "Main intended use as restore_command in recovery.conf:\n"
+		   "Main intended use as restore_command in postgresql.conf:\n"
 		   "  restore_command = 'pg_standby [OPTION]... ARCHIVELOCATION %%f %%p %%r'\n"
 		   "e.g.\n"
 	"  restore_command = 'pg_standby /mnt/server/archiverdir %%f %%p %%r'\n");
diff --git a/doc/src/sgml/backup.sgml b/doc/src/sgml/backup.sgml
index c4215be..7ed5337 100644
--- a/doc/src/sgml/backup.sgml
+++ b/doc/src/sgml/backup.sgml
@@ -1002,8 +1002,15 @@ SELECT pg_stop_backup();
    </listitem>
    <listitem>
     <para>
-     Create a recovery command file <filename>recovery.conf</> in the cluster
-     data directory (see <xref linkend="recovery-config">). You might
+     Set up recovery parameters in <filename>postgresql.conf</> (see
+     <xref linkend="runtime-config-wal-archive-recovery"> and
+     <xref linkend="runtime-config-wal-recovery-target">).
+    </para>
+   </listitem>
+   <listitem>
+    <para>
+     Create a recovery trigger file <filename>recovery.trigger</>
+     in the cluster data directory. You might
      also want to temporarily modify <filename>pg_hba.conf</> to prevent
      ordinary users from connecting until you are sure the recovery was successful.
     </para>
@@ -1015,7 +1022,7 @@ SELECT pg_stop_backup();
      recovery be terminated because of an external error, the server can
      simply be restarted and it will continue recovery.  Upon completion
      of the recovery process, the server will rename
-     <filename>recovery.conf</> to <filename>recovery.done</> (to prevent
+     <filename>recovery.trigger</> to <filename>recovery.done</> (to prevent
      accidentally re-entering recovery mode later) and then
      commence normal database operations.
     </para>
@@ -1031,12 +1038,11 @@ SELECT pg_stop_backup();
    </para>
 
    <para>
-    The key part of all this is to set up a recovery configuration file that
-    describes how you want to recover and how far the recovery should
-    run.  You can use <filename>recovery.conf.sample</> (normally
-    located in the installation's <filename>share/</> directory) as a
-    prototype.  The one thing that you absolutely must specify in
-    <filename>recovery.conf</> is the <varname>restore_command</>,
+    The key part of all this is to set up recovery parameters that
+    specify how you want to recover and how far the recovery should
+    run. The one thing that you absolutely must specify in
+    <filename>postgresql.conf</> to recover from the backup is
+    the <varname>restore_command</>,
     which tells <productname>PostgreSQL</> how to retrieve archived
     WAL file segments.  Like the <varname>archive_command</>, this is
     a shell command string.  It can contain <literal>%f</>, which is
@@ -1090,7 +1096,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 stopping point in <filename>postgresql.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
@@ -1187,8 +1193,9 @@ restore_command = 'cp /mnt/server/archivedir/%f %p'
     The default behavior of recovery is to recover along the same timeline
     that was current when the base backup was taken.  If you wish to recover
     into some child timeline (that is, you want to return to some state that
-    was itself generated after a recovery attempt), you need to specify the
-    target timeline ID in <filename>recovery.conf</>.  You cannot recover into
+    was itself generated after a recovery attempt), you need to set
+    <xref linkend="guc-recovery-target-timeline"> to the
+    target timeline ID in <filename>postgresql.conf</>.  You cannot recover into
     timelines that branched off earlier than the base backup.
    </para>
   </sect2>
diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index b7df8ce..3b26bb7 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -2161,6 +2161,278 @@ include 'filename'
      </variablelist>
     </sect2>
 
+    <sect2 id="runtime-config-wal-archive-recovery">
+     <title>Archive Recovery</title>
+
+     <variablelist>
+      <varlistentry id="guc-restore-command" xreflabel="restore_command">
+       <term><varname>restore_command</varname> (<type>string</type>)</term>
+       <indexterm>
+        <primary><varname>restore_command</> configuration parameter</primary>
+       </indexterm>
+       <listitem>
+        <para>
+         The shell command to execute to retrieve an archived segment of
+         the WAL file series. This parameter is required for archive recovery,
+         but optional for streaming replication.
+         Any <literal>%f</> in the string is
+         replaced by the name of the file to retrieve from the archive,
+         and any <literal>%p</> is replaced by the copy destination path name
+         on the server.
+         (The path name is relative to the current working directory,
+         i.e., the cluster's data directory.)
+         Any <literal>%r</> is replaced by the name of the file containing the
+         last valid restart point. That is the earliest file that must be kept
+         to allow a restore to be restartable, so this information can be used
+         to truncate the archive to just the minimum required to support
+         restarting from the current restore. <literal>%r</> is typically only
+         used by warm-standby configurations
+         (see <xref linkend="warm-standby">).
+         Write <literal>%%</> to embed an actual <literal>%</> character.
+        </para>
+        <para>
+         It is important for the command to return a zero exit status
+         only if it succeeds.  The command <emphasis>will</> be asked for file
+         names that are not present in the archive; it must return nonzero
+         when so asked.  Examples:
+<programlisting>
+restore_command = 'cp /mnt/server/archivedir/%f "%p"'
+restore_command = 'copy "C:\\server\\archivedir\\%f" "%p"'  # Windows
+</programlisting>
+        </para>
+        <para>
+         This parameter can only be set in the <filename>postgresql.conf</>
+         file or on the server command line. It only has effect during archive
+         recovery or in standby mode.
+        </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry id="guc-archive-cleanup-command" xreflabel="archive_cleanup_command">
+       <term><varname>archive_cleanup_command</varname> (<type>string</type>)</term>
+       <indexterm>
+         <primary><varname>archive_cleanup_command</> configuration parameter</primary>
+       </indexterm>
+       <listitem>
+        <para>
+         The shell command that will be executed at every restartpoint.
+         The purpose of <varname>archive_cleanup_command</> is to
+         provide a mechanism for cleaning up old archived WAL files that
+         are no longer needed by the standby server.
+         Any <literal>%r</> is replaced by the name of the file containing the
+         last valid restart point.
+         That is the earliest file that must be <emphasis>kept</> to allow a
+         restore to be restartable, and so all files earlier than <literal>%r</>
+         may be safely removed.
+         This information can be used to truncate the archive to just the
+         minimum required to support restart from the current restore.
+         The <xref linkend="pgarchivecleanup"> module
+         is often used in <varname>archive_cleanup_command</> for
+         single-standby configurations, for example:
+<programlisting>archive_cleanup_command = 'pg_archivecleanup /mnt/server/archivedir %r'</programlisting>
+         Note however that if multiple standby servers are restoring from the
+         same archive directory, you will need to ensure that you do not delete
+         WAL files until they are no longer needed by any of the servers.
+         <varname>archive_cleanup_command</> would typically be used in a
+         warm-standby configuration (see <xref linkend="warm-standby">).
+         Write <literal>%%</> to embed an actual <literal>%</> character in the
+         command.
+        </para>
+        <para>
+         If the command returns a non-zero exit status then a WARNING log
+         message will be written.
+        </para>
+        <para>
+         This parameter can only be set in the <filename>postgresql.conf</>
+         file or on the server command line. It only has effect during archive
+         recovery or in standby mode.
+        </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry id="guc-recovery-end-command" xreflabel="recovery_end_command">
+       <term><varname>recovery_end_command</varname> (<type>string</type>)</term>
+       <indexterm>
+         <primary><varname>recovery_end_command</> configuration parameter</primary>
+       </indexterm>
+       <listitem>
+        <para>
+         The shell command that will be executed once only
+         at the end of recovery. This parameter is optional. The purpose of the
+         <varname>recovery_end_command</> is to provide a mechanism for cleanup
+         following replication or recovery.
+         Any <literal>%r</> is replaced by the name of the file containing the
+         last valid restart point, like in <varname>archive_cleanup_command</>.
+        </para>
+        <para>
+         If the command returns a non-zero exit status then a WARNING log
+         message will be written and the database will proceed to start up
+         anyway.  An exception is that if the command was terminated by a
+         signal, the database will not proceed with startup.
+        </para>
+        <para>
+         This parameter can only be set in the <filename>postgresql.conf</>
+         file or on the server command line. It only has effect during archive
+         recovery or in standby mode.
+        </para>
+       </listitem>
+      </varlistentry>
+     </variablelist>
+    </sect2>
+
+    <sect2 id="runtime-config-wal-recovery-target">
+     <title>Recovery Target</title>
+
+     <variablelist>
+      <varlistentry id="guc-recovery-target-name" xreflabel="recovery_target_name">
+       <term><varname>recovery_target_name</varname> (<type>string</type>)</term>
+       <indexterm>
+        <primary><varname>recovery_target_name</> configuration parameter</primary>
+       </indexterm>
+       <listitem>
+        <para>
+         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</>,
+         <varname>recovery_target_time</> or
+         <varname>recovery_target_xid</> can be specified.  The default
+         value is an empty string, which will recover to the end of the WAL log.
+        </para>
+        <para>
+         This parameter can only be set in the <filename>postgresql.conf</>
+         file or on the server command line. It only has effect during archive
+         recovery or in standby mode.
+        </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry id="guc-recovery-target-time" xreflabel="recovery_target_time">
+       <term><varname>recovery_target_time</varname> (<type>string</type>)</term>
+       <indexterm>
+        <primary><varname>recovery_target_time</> configuration parameter</primary>
+       </indexterm>
+       <listitem>
+        <para>
+         Specifies the time stamp up to which recovery will proceed.
+         This parameter must be specified in the date/time format
+         (see <xref linkend="datatype-datetime-input"> for details).
+         At most one of <varname>recovery_target_time</>,
+         <varname>recovery_target_name</> or
+         <varname>recovery_target_xid</> can be specified.
+         The default value is an empty string, which will recover to
+         the end of the WAL log. The precise stopping point is also
+         influenced by <varname>recovery_target_inclusive</>.
+        </para>
+        <para>
+         This parameter can only be set in the <filename>postgresql.conf</>
+         file or on the server command line. It only has effect during archive
+         recovery or in standby mode.
+        </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry id="guc-recovery-target-xid" xreflabel="recovery_target_xid">
+       <term><varname>recovery_target_xid</varname> (<type>string</type>)</term>
+       <indexterm>
+        <primary><varname>recovery_target_xid</> configuration parameter</primary>
+       </indexterm>
+       <listitem>
+        <para>
+         Specifies the transaction ID up to which recovery will proceed.
+         Keep in mind that while transaction IDs are assigned sequentially
+         at transaction 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</>,
+         <varname>recovery_target_name</> or
+         <varname>recovery_target_time</> can be specified.
+         The default value is an empty string, which will recover to the end of
+         the WAL log. The precise stopping point is also influenced by
+         <varname>recovery_target_inclusive</>.
+        </para>
+        <para>
+         This parameter can only be set in the <filename>postgresql.conf</>
+         file or on the server command line. It only has effect during archive
+         recovery or in standby mode.
+        </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry id="guc-recovery-target-inclusive" xreflabel="recovery_target_inclusive">
+       <term><varname>recovery_target_inclusive</varname> (<type>boolean</type>)</term>
+       <indexterm>
+        <primary><varname>recovery_target_inclusive</> configuration parameter</primary>
+       </indexterm>
+       <listitem>
+        <para>
+         Specifies whether we stop just after the specified recovery target
+         (<literal>on</>), or just before the recovery target (<literal>off</>).
+         Applies to both <varname>recovery_target_time</>
+         and <varname>recovery_target_xid</>, whichever one is
+         specified for this recovery.  This indicates whether transactions
+         having exactly the target commit time or ID, respectively, will
+         be included in the recovery.  Default is <literal>on</>.
+        </para>
+        <para>
+         This parameter can only be set in the <filename>postgresql.conf</>
+         file or on the server command line. It only has effect during archive
+         recovery or in standby mode.
+        </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry id="guc-recovery-target-timeline" xreflabel="recovery_target_timeline">
+       <term><varname>recovery_target_timeline</varname> (<type>string</type>)</term>
+       <indexterm>
+        <primary><varname>recovery_target_timeline</> configuration parameter</primary>
+       </indexterm>
+       <listitem>
+        <para>
+         Specifies recovering into a particular timeline.  The default value is
+         an empty string, which will recover along the same timeline that was
+         current when the base backup was taken. Setting this to
+         <literal>latest</> recovers to the latest timeline found in the archive,
+         which is useful in a standby server. Other than that you only need to
+         set this parameter in complex re-recovery situations, where you need
+         to return to a state that itself was reached after a point-in-time
+         recovery. See <xref linkend="backup-timelines"> for discussion.
+        </para>
+        <para>
+         This parameter can only be set at server start. It only has effect
+         during archive recovery or in standby mode.
+        </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry id="guc-pause-at-recovery-target" xreflabel="pause_at_recovery_target">
+       <term><varname>pause_at_recovery_target</varname> (<type>boolean</type>)</term>
+       <indexterm>
+        <primary><varname>pause_at_recovery_target</> configuration parameter</primary>
+       </indexterm>
+       <listitem>
+        <para>
+         Specifies whether recovery should pause when the recovery target
+         is reached. The default is <literal>on</>.
+         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
+         <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
+         recovery target settings to a later target and restart to
+         continue recovery.
+        </para>
+        <para>
+         This parameter can only be set in the <filename>postgresql.conf</>
+         file or on the server command line. It only has effect during archive
+         recovery or in standby mode if recovery target is set.
+        </para>
+       </listitem>
+      </varlistentry>
+     </variablelist>
+     </sect2>
+
    </sect1>
 
    <sect1 id="runtime-config-replication">
@@ -2380,6 +2652,93 @@ include 'filename'
 
     <variablelist>
 
+     <varlistentry id="guc-standby-mode" xreflabel="standby_mode">
+      <term><varname>standby_mode</varname> (<type>boolean</type>)</term>
+      <indexterm>
+       <primary><varname>standby_mode</> configuration parameter</primary>
+      </indexterm>
+      <listitem>
+       <para>
+        Specifies whether to start the <productname>PostgreSQL</> server as
+        a standby when recovery trigger file <filename>recovery.trigger</> exists.
+        The default value is <literal>off</>.
+        If this parameter is <literal>on</>, the server will not
+        stop recovery when the end of archived WAL is reached,
+        but will keep trying to continue recovery by fetching new WAL segments
+        using <varname>restore_command</> and/or by connecting to
+        the primary server as specified by the <varname>primary_conninfo</>
+        setting.
+       </para>
+       <para>
+        This parameter can only be set at server start. It only has effect
+        if recovery trigger file <filename>recovery.trigger</> exists.
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry id="guc-primary-conninfo" xreflabel="primary_conninfo">
+      <term><varname>primary_conninfo</varname> (<type>string</type>)</term>
+      <indexterm>
+        <primary><varname>primary_conninfo</> configuration parameter</primary>
+      </indexterm>
+      <listitem>
+       <para>
+        Specifies a connection string to be used for the standby server
+        to connect with the primary. This string is in the format
+        accepted by the libpq <function>PQconnectdb</function> function,
+        described in <xref linkend="libpq-connect">. If any option is
+        unspecified in this string, then the corresponding environment
+        variable (see <xref linkend="libpq-envars">) is checked. If the
+        environment variable is not set either, then defaults are used.
+        If this parameter is an empty string (the default), no attempt is
+        made to connect to the master.
+       </para>
+       <para>
+        The connection string should specify the host name (or address)
+        of the primary server, as well as the port number if it is not
+        the same as the standby server's default.
+        Also specify a user name corresponding to a role that has the
+        <literal>REPLICATION</> and <literal>LOGIN</> privileges on the
+        primary (see
+        <xref linkend="streaming-replication-authentication">).
+        A password needs to be provided too, if the primary demands password
+        authentication.  It can be provided in the
+        <varname>primary_conninfo</varname> string, or in a separate
+        <filename>~/.pgpass</> file on the standby server (use
+        <literal>replication</> as the database name).
+        Do not specify a database name in the
+        <varname>primary_conninfo</varname> string.
+       </para>
+       <para>
+        This parameter can only be set in the <filename>postgresql.conf</>
+        file or on the server command line. It only has effect in standby mode.
+       </para>
+       <para>
+        If this parameter is changed while replication is in progress,
+        the standby terminates replication, and then tries to restart
+        replication with new setting.
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry id="guc-trigger-file" xreflabel="trigger_file">
+      <term><varname>trigger_file</varname> (<type>string</type>)</term>
+      <indexterm>
+        <primary><varname>trigger_file</> configuration parameter</primary>
+      </indexterm>
+      <listitem>
+       <para>
+        Specifies a trigger file whose presence ends recovery in the
+        standby.  Even if this value is not set, you can still promote
+        the standby using <command>pg_ctl promote</>.
+       </para>
+       <para>
+        This parameter can only be set in the <filename>postgresql.conf</>
+        file or on the server command line. It only has effect in standby mode.
+       </para>
+      </listitem>
+    </varlistentry>
+
      <varlistentry id="guc-hot-standby" xreflabel="hot_standby">
       <term><varname>hot_standby</varname> (<type>boolean</type>)</term>
       <indexterm>
diff --git a/doc/src/sgml/filelist.sgml b/doc/src/sgml/filelist.sgml
index 368f932..e701ca3 100644
--- a/doc/src/sgml/filelist.sgml
+++ b/doc/src/sgml/filelist.sgml
@@ -43,7 +43,6 @@
 <!ENTITY manage-ag     SYSTEM "manage-ag.sgml">
 <!ENTITY monitoring    SYSTEM "monitoring.sgml">
 <!ENTITY regress       SYSTEM "regress.sgml">
-<!ENTITY recovery-config SYSTEM "recovery-config.sgml">
 <!ENTITY runtime       SYSTEM "runtime.sgml">
 <!ENTITY config        SYSTEM "config.sgml">
 <!ENTITY user-manag    SYSTEM "user-manag.sgml">
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 35c7f75..48cfe9e 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -14670,7 +14670,7 @@ postgres=# select pg_start_backup('label_goes_here');
     <function>pg_create_restore_point</> creates a named transaction log
     record that can be used as recovery target, and returns the corresponding
     transaction log location.  The given name can then be used with
-    <xref linkend="recovery-target-name"> to specify the point up to which
+    <xref linkend="guc-recovery-target-name"> to specify the point up to which
     recovery will proceed.  Avoid creating multiple restore points with the
     same name, since recovery will stop at the first one whose name matches
     the recovery target.
diff --git a/doc/src/sgml/high-availability.sgml b/doc/src/sgml/high-availability.sgml
index c8f6fa8..18be3a3 100644
--- a/doc/src/sgml/high-availability.sgml
+++ b/doc/src/sgml/high-availability.sgml
@@ -591,7 +591,7 @@ protocol to make nodes agree on a serializable transactional order.
    <para>
     In standby mode, the server continuously applies WAL received from the
     master server. The standby server can read WAL from a WAL archive
-    (see <xref linkend="restore-command">) or directly from the master
+    (see <xref linkend="guc-restore-command">) or directly from the master
     over a TCP connection (streaming replication). The standby server will
     also attempt to restore any WAL found in the standby cluster's
     <filename>pg_xlog</> directory. That typically happens after a server
@@ -658,8 +658,8 @@ protocol to make nodes agree on a serializable transactional order.
    <para>
     To set up the standby server, restore the base backup taken from primary
     server (see <xref linkend="backup-pitr-recovery">). Create a recovery
-    command file <filename>recovery.conf</> in the standby's cluster data
-    directory, and turn on <varname>standby_mode</>. Set
+    trigger file <filename>recovery.trigger</> in the standby's cluster data
+    directory. Turn on <varname>standby_mode</> and set
     <varname>restore_command</> to a simple command to copy files from
     the WAL archive. If you plan to have multiple standby servers for high
     availability purposes, set <varname>recovery_target_timeline</> to
@@ -695,7 +695,7 @@ protocol to make nodes agree on a serializable transactional order.
 
    <para>
     If you're using a WAL archive, its size can be minimized using the <xref
-    linkend="archive-cleanup-command"> parameter to remove files that are no
+    linkend="guc-archive-cleanup-command"> parameter to remove files that are no
     longer required by the standby server.
     The <application>pg_archivecleanup</> utility is designed specifically to
     be used with <varname>archive_cleanup_command</> in typical single-standby
@@ -706,7 +706,7 @@ protocol to make nodes agree on a serializable transactional order.
    </para>
 
    <para>
-    A simple example of a <filename>recovery.conf</> is:
+    A simple example of standby settings is:
 <programlisting>
 standby_mode = 'on'
 primary_conninfo = 'host=192.168.1.50 port=5432 user=foo password=foopass'
@@ -763,8 +763,8 @@ archive_cleanup_command = 'pg_archivecleanup /path/to/archive %r'
     To use streaming replication, set up a file-based log-shipping standby
     server as described in <xref linkend="warm-standby">. The step that
     turns a file-based log-shipping standby into streaming replication
-    standby is setting <varname>primary_conninfo</> setting in the
-    <filename>recovery.conf</> file to point to the primary server. Set
+    standby is setting <varname>primary_conninfo</> to
+    point to the primary server. Set
     <xref linkend="guc-listen-addresses"> and authentication options
     (see <filename>pg_hba.conf</>) on the primary so that the standby server
     can connect to the <literal>replication</> pseudo-database on the primary
@@ -824,15 +824,14 @@ host    replication     foo             192.168.1.100/32        md5
     </para>
     <para>
      The host name and port number of the primary, connection user name,
-     and password are specified in the <filename>recovery.conf</> file.
+     and password are specified in <varname>primary_conninfo</>.
      The password can also be set in the <filename>~/.pgpass</> file on the
      standby (specify <literal>replication</> in the <replaceable>database</>
      field).
      For example, if the primary is running on host IP <literal>192.168.1.50</>,
      port <literal>5432</literal>, the account name for replication is
      <literal>foo</>, and the password is <literal>foopass</>, the administrator
-     can add the following line to the <filename>recovery.conf</> file on the
-     standby:
+     can set <varname>primary_conninfo</> on the standby like this:
 
 <programlisting>
 # The standby connects to the primary that is running on host 192.168.1.50
@@ -1212,8 +1211,8 @@ primary_conninfo = 'host=192.168.1.50 port=5432 user=foo password=foopass'
    <para>
     To trigger failover of a log-shipping standby server,
     run <command>pg_ctl promote</> or create a trigger
-    file with the file name and path specified by the <varname>trigger_file</>
-    setting in <filename>recovery.conf</>. If you're planning to use
+    file with the file name and path specified by the <varname>trigger_file</>.
+    If you're planning to use
     <command>pg_ctl promote</> to fail over, <varname>trigger_file</> is
     not required. If you're setting up the reporting servers that are
     only used to offload read-only queries from the primary, not for high
@@ -1258,8 +1257,7 @@ primary_conninfo = 'host=192.168.1.50 port=5432 user=foo password=foopass'
     The magic that makes the two loosely coupled servers work together is
     simply a <varname>restore_command</> used on the standby that,
     when asked for the next WAL file, waits for it to become available from
-    the primary. The <varname>restore_command</> is specified in the
-    <filename>recovery.conf</> file on the standby server. Normal recovery
+    the primary. Normal recovery
     processing would request a file from the WAL archive, reporting failure
     if the file was unavailable.  For standby processing it is normal for
     the next WAL file to be unavailable, so the standby must wait for
@@ -1346,8 +1344,14 @@ if (!triggered)
      </listitem>
      <listitem>
       <para>
+       Create a recovery trigger file <filename>recovery.trigger</>
+       in the standby's cluster data directory.
+      </para>
+     </listitem>
+     <listitem>
+      <para>
        Begin recovery on the standby server from the local WAL
-       archive, using a <filename>recovery.conf</> that specifies a
+       archive, specifying a
        <varname>restore_command</> that waits as described
        previously (see <xref linkend="backup-pitr-recovery">).
       </para>
@@ -1838,9 +1842,9 @@ if (!triggered)
    <title>Administrator's Overview</title>
 
    <para>
-    If <varname>hot_standby</> is turned <literal>on</> in
-    <filename>postgresql.conf</> and there is a <filename>recovery.conf</>
-    file present, the server will run in Hot Standby mode.
+    If <varname>hot_standby</> is turned <literal>on</>
+    and there is a recovery trigger file
+    <filename>recovery.trigger</> present, the server will run in Hot Standby mode.
     However, it may take some time for Hot Standby connections to be allowed,
     because the server will not accept connections until it has completed
     sufficient recovery to provide a consistent state against which queries
diff --git a/doc/src/sgml/pgarchivecleanup.sgml b/doc/src/sgml/pgarchivecleanup.sgml
index 932914b..2984da4 100644
--- a/doc/src/sgml/pgarchivecleanup.sgml
+++ b/doc/src/sgml/pgarchivecleanup.sgml
@@ -38,8 +38,8 @@
 
   <para>
    To configure a standby
-   server to use <application>pg_archivecleanup</>, put this into its
-   <filename>recovery.conf</filename> configuration file:
+   server to use <application>pg_archivecleanup</>, specify
+   <xref linkend="guc-archive-cleanup-command"> like this:
 <programlisting>
 archive_cleanup_command = 'pg_archivecleanup <replaceable>archivelocation</> %r'
 </programlisting>
@@ -47,7 +47,7 @@ archive_cleanup_command = 'pg_archivecleanup <replaceable>archivelocation</> %r'
    files should be removed.
   </para>
   <para>
-   When used within <xref linkend="archive-cleanup-command">, all WAL files
+   When used within <varname>archive_cleanup_command</>, all WAL files
    logically preceding the value of the <literal>%r</> argument will be removed
    from <replaceable>archivelocation</>. This minimizes the number of files
    that need to be retained, while preserving crash-restart capability.  Use of
diff --git a/doc/src/sgml/pgstandby.sgml b/doc/src/sgml/pgstandby.sgml
index ca2b5c0..15097ca 100644
--- a/doc/src/sgml/pgstandby.sgml
+++ b/doc/src/sgml/pgstandby.sgml
@@ -46,8 +46,8 @@
 
   <para>
    To configure a standby
-   server to use <application>pg_standby</>, put this into its
-   <filename>recovery.conf</filename> configuration file:
+   server to use <application>pg_standby</>, specify
+   <xref linkend="guc-restore-command"> like this:
 <programlisting>
 restore_command = 'pg_standby <replaceable>archiveDir</> %f %p %r'
 </programlisting>
diff --git a/doc/src/sgml/postgres.sgml b/doc/src/sgml/postgres.sgml
index 15e4ef6..26e8dc2 100644
--- a/doc/src/sgml/postgres.sgml
+++ b/doc/src/sgml/postgres.sgml
@@ -155,7 +155,6 @@
   &maintenance;
   &backup;
   &high-availability;
-  &recovery-config;
   &monitoring;
   &diskusage;
   &wal;
diff --git a/doc/src/sgml/release-9.1.sgml b/doc/src/sgml/release-9.1.sgml
index 1143fdf..36546bb 100644
--- a/doc/src/sgml/release-9.1.sgml
+++ b/doc/src/sgml/release-9.1.sgml
@@ -3957,7 +3957,7 @@
       <listitem>
        <para>
         Add <filename>recovery.conf</> setting <link
-        linkend="pause-at-recovery-target"><varname>pause_at_recovery_target</></link>
+        linkend="guc-pause-at-recovery-target"><varname>pause_at_recovery_target</></link>
         to pause recovery at target (Simon Riggs)
        </para>
 
@@ -3977,7 +3977,7 @@
        <para>
         These named restore points can be specified as recovery
         targets using the new <filename>recovery.conf</> setting
-        <link linkend="recovery-target-name"><varname>recovery_target_name</></link>.
+        <link linkend="guc-recovery-target-name"><varname>recovery_target_name</></link>.
        </para>
       </listitem>
 
@@ -4009,8 +4009,7 @@
 
       <listitem>
        <para>
-        Allow <link
-        linkend="recovery-config"><filename>recovery.conf</></link>
+        Allow <filename>recovery.conf</>
         to use the same quoting behavior as <filename>postgresql.conf</>
         (Dimitri Fontaine)
        </para>
diff --git a/doc/src/sgml/release.sgml b/doc/src/sgml/release.sgml
index 2515329..fb70d4e 100644
--- a/doc/src/sgml/release.sgml
+++ b/doc/src/sgml/release.sgml
@@ -5,8 +5,8 @@ Typical markup:
 
 &<>                             use & escapes
 PostgreSQL                      <productname>
-postgresql.conf, pg_hba.conf,
-        recovery.conf           <filename>
+postgresql.conf, pg_hba.conf
+        recovery.trigger           <filename>
 [A-Z][A-Z_ ]+[A-Z_]             <command>, <literal>, <envar>
 [A-Za-z_][A-Za-z0-9_]+()        <function>
 -[-A-Za-z_]+                    <option>
diff --git a/src/backend/Makefile b/src/backend/Makefile
index 323b417..06d5f59 100644
--- a/src/backend/Makefile
+++ b/src/backend/Makefile
@@ -223,7 +223,6 @@ endif
 	$(INSTALL_DATA) $(srcdir)/libpq/pg_hba.conf.sample '$(DESTDIR)$(datadir)/pg_hba.conf.sample'
 	$(INSTALL_DATA) $(srcdir)/libpq/pg_ident.conf.sample '$(DESTDIR)$(datadir)/pg_ident.conf.sample'
 	$(INSTALL_DATA) $(srcdir)/utils/misc/postgresql.conf.sample '$(DESTDIR)$(datadir)/postgresql.conf.sample'
-	$(INSTALL_DATA) $(srcdir)/access/transam/recovery.conf.sample '$(DESTDIR)$(datadir)/recovery.conf.sample'
 
 install-bin: postgres $(POSTGRES_IMP) installdirs
 	$(INSTALL_PROGRAM) postgres$(X) '$(DESTDIR)$(bindir)/postgres$(X)'
@@ -280,8 +279,7 @@ endif
 	$(MAKE) -C tsearch uninstall-data
 	rm -f '$(DESTDIR)$(datadir)/pg_hba.conf.sample' \
 	      '$(DESTDIR)$(datadir)/pg_ident.conf.sample' \
-              '$(DESTDIR)$(datadir)/postgresql.conf.sample' \
-	      '$(DESTDIR)$(datadir)/recovery.conf.sample'
+              '$(DESTDIR)$(datadir)/postgresql.conf.sample'
 
 
 ##########################################################################
diff --git a/src/backend/access/transam/recovery.conf.sample b/src/backend/access/transam/recovery.conf.sample
deleted file mode 100644
index 5acfa57..0000000
--- a/src/backend/access/transam/recovery.conf.sample
+++ /dev/null
@@ -1,132 +0,0 @@
-# -------------------------------
-# PostgreSQL recovery config file
-# -------------------------------
-#
-# Edit this file to provide the parameters that PostgreSQL needs to
-# perform an archive recovery of a database, or to act as a replication
-# standby.
-#
-# If "recovery.conf" is present in the PostgreSQL data directory, it is
-# read on postmaster startup.  After successful recovery, it is renamed
-# to "recovery.done" to ensure that we do not accidentally re-enter
-# archive recovery or standby mode.
-#
-# This file consists of lines of the form:
-#
-#   name = value
-#
-# Comments are introduced with '#'.
-#
-# The complete list of option names and allowed values can be found
-# in the PostgreSQL documentation.
-#
-#---------------------------------------------------------------------------
-# ARCHIVE RECOVERY PARAMETERS
-#---------------------------------------------------------------------------
-#
-# restore_command
-#
-# specifies the shell command that is executed to copy log files
-# back from archival storage.  The command string may contain %f,
-# which is replaced by the name of the desired log file, and %p,
-# which is replaced by the absolute path to copy the log file to.
-#
-# This parameter is *required* for an archive recovery, but optional
-# for streaming replication.
-#
-# It is important that the command return nonzero exit status on failure.
-# The command *will* be asked for log files that are not present in the
-# archive; it must return nonzero when so asked.
-#
-# NOTE that the basename of %p will be different from %f; do not
-# expect them to be interchangeable.
-#
-#restore_command = ''		# e.g. 'cp /mnt/server/archivedir/%f %p'
-#
-#
-# archive_cleanup_command
-#
-# specifies an optional shell command to execute at every restartpoint.
-# This can be useful for cleaning up the archive of a standby server.
-#
-#archive_cleanup_command = ''
-#
-# recovery_end_command
-#
-# specifies an optional shell command to execute at completion of recovery.
-# This can be useful for cleaning up after the restore_command.
-#
-#recovery_end_command = ''
-#
-#---------------------------------------------------------------------------
-# RECOVERY TARGET PARAMETERS
-#---------------------------------------------------------------------------
-#
-# By default, recovery will rollforward to the end of the WAL log.
-# If you want to stop rollforward at a specific point, you
-# must set a recovery target.
-#
-# You may set a recovery target either by transactionId, by name,
-# or by timestamp. Recovery may either include or exclude the
-# transaction(s) with the recovery target value (ie, stop either
-# just after or just before the given target, respectively).
-#
-#
-#recovery_target_name = ''	# e.g. 'daily backup 2011-01-26'
-#
-#recovery_target_time = ''	# e.g. '2004-07-14 22:39:00 EST'
-#
-#recovery_target_xid = ''
-#
-#recovery_target_inclusive = true
-#
-#
-# If you want to recover into a timeline other than the "main line" shown in
-# pg_control, specify the timeline number here, or write 'latest' to get
-# the latest branch for which there's a history file.
-#
-#recovery_target_timeline = 'latest'
-#
-#
-# If pause_at_recovery_target is enabled, recovery will pause when
-# the recovery target is reached. The pause state will continue until
-# pg_xlog_replay_resume() is called. This setting has no effect if
-# hot standby is not enabled, or if no recovery target is set.
-#
-#pause_at_recovery_target = true
-#
-#---------------------------------------------------------------------------
-# STANDBY SERVER PARAMETERS
-#---------------------------------------------------------------------------
-#
-# standby_mode
-#
-# When standby_mode is enabled, the PostgreSQL server will work as a
-# standby. It will continuously wait for the additional XLOG records, using
-# restore_command and/or primary_conninfo.
-#
-#standby_mode = off
-#
-# primary_conninfo
-#
-# If set, the PostgreSQL server will try to connect to the primary using this
-# connection string and receive XLOG records continuously.
-#
-#primary_conninfo = ''		# e.g. 'host=localhost port=5432'
-#
-#
-# By default, a standby server keeps restoring XLOG records from the
-# primary indefinitely. If you want to stop the standby mode, finish recovery
-# and open the system in read/write mode, specify path to a trigger file.
-# The server will poll the trigger file path periodically and start as a
-# primary server when it's found.
-#
-#trigger_file = ''
-#
-#---------------------------------------------------------------------------
-# HOT STANDBY PARAMETERS
-#---------------------------------------------------------------------------
-#
-# Hot Standby related parameters are listed in postgresql.conf
-#
-#---------------------------------------------------------------------------
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 9ad9227..9dd6227 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -63,7 +63,7 @@
 
 
 /* File path names (all relative to $PGDATA) */
-#define RECOVERY_COMMAND_FILE	"recovery.conf"
+#define RECOVERY_COMMAND_READY	"recovery.trigger"
 #define RECOVERY_COMMAND_DONE	"recovery.done"
 #define PROMOTE_SIGNAL_FILE "promote"
 
@@ -82,6 +82,20 @@ int			sync_method = DEFAULT_SYNC_METHOD;
 int			wal_level = WAL_LEVEL_MINIMAL;
 int			CommitDelay = 0;	/* precommit delay in microseconds */
 int			CommitSiblings = 5; /* # concurrent xacts needed to sleep */
+char	   *restore_command = NULL;
+char	   *archive_cleanup_command = NULL;
+char	   *recovery_end_command = NULL;
+bool		standby_mode = false;
+char	   *primary_conninfo = NULL;
+char	   *trigger_file = NULL;
+RecoveryTargetType	recovery_target = RECOVERY_TARGET_UNSET;
+TransactionId		recovery_target_xid = InvalidTransactionId;
+TimestampTz			recovery_target_time = 0;
+char	   *recovery_target_name = NULL;
+bool		recovery_target_inclusive = true;
+bool		pause_at_recovery_target = true;
+char	   *recovery_target_timeline_string = NULL;
+TimeLineID	recovery_target_timeline = 0;
 
 #ifdef WAL_DEBUG
 bool		XLOG_DEBUG = false;
@@ -194,23 +208,8 @@ bool InArchiveRecovery = false;
 /* Was the last xlog file restored from archive, or local? */
 static bool restoredFromArchive = false;
 
-/* options 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 bool recoveryPauseAtTarget = true;
-static TransactionId recoveryTargetXid;
-static TimestampTz recoveryTargetTime;
-static char *recoveryTargetName;
-
-/* options taken from recovery.conf for XLOG streaming */
-bool StandbyMode = false;
-static char *PrimaryConnInfo = NULL;
-static char *TriggerFile = NULL;
-
 /* if recoveryStopsHere returns true, it saves actual stop xid/time/name here */
+static RecoveryTargetType recoveryStopTarget;
 static TransactionId recoveryStopXid;
 static TimestampTz recoveryStopTime;
 static char recoveryStopName[MAXFNAMELEN];
@@ -407,12 +406,6 @@ typedef struct XLogCtlData
 	TimeLineID	ThisTimeLineID;
 
 	/*
-	 * 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.
 	 */
@@ -601,7 +594,7 @@ static bool InRedo = false;
 static bool bgwriterLaunched = false;
 
 
-static void readRecoveryCommandFile(void);
+static void CheckRecoveryReadyFile(void);
 static void exitArchiveRecovery(TimeLineID endTLI, XLogSegNo endLogSegNo);
 static bool recoveryStopsHere(XLogRecord *record, bool *includeThis);
 static void recoveryPausesHere(void);
@@ -3222,7 +3215,7 @@ ReadRecord(XLogReaderState *xlogreader, XLogRecPtr RecPtr, int emode,
 			/*
 			 * We only end up here without a message when XLogPageRead() failed
 			 * - in that case we already logged something.
-			 * In StandbyMode that only happens if we have been triggered, so
+			 * In standby_mode that only happens if we have been triggered, so
 			 * we shouldn't loop anymore in that case.
 			 */
 			if (errormsg)
@@ -3257,7 +3250,7 @@ ReadRecord(XLogReaderState *xlogreader, XLogRecPtr RecPtr, int emode,
 			record = NULL;
 			continue;
 		}
-	} while (StandbyMode && record == NULL && !CheckForStandbyTrigger());
+	} while (standby_mode && record == NULL && !CheckForStandbyTrigger());
 
 	return record;
 }
@@ -3997,212 +3990,40 @@ 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.
- *
- * The file is parsed using the main configuration parser.
+ * Check to see if there is a recovery trigger file (recovery.trigger).
+ * If so, validate recovery parameters and determine recovery target timeline.
  */
 static void
-readRecoveryCommandFile(void)
+CheckRecoveryReadyFile(void)
 {
-	FILE	   *fd;
-	TimeLineID	rtli = 0;
-	bool		rtliGiven = false;
-	ConfigVariable *item,
-			   *head = NULL,
-			   *tail = NULL;
-
-	fd = AllocateFile(RECOVERY_COMMAND_FILE, "r");
+	FILE *fd;
+
+	/* Check the presence of recovery trigger file */
+	fd = AllocateFile(RECOVERY_COMMAND_READY, "r");
 	if (fd == NULL)
 	{
 		if (errno == ENOENT)
-			return;				/* not there, so no archive recovery */
+			return;		/* not there, so no archive recovery */
 		ereport(FATAL,
 				(errcode_for_file_access(),
-				 errmsg("could not open recovery command file \"%s\": %m",
-						RECOVERY_COMMAND_FILE)));
+				 errmsg("could not open recovery file trigger \"%s\": %m",
+						RECOVERY_COMMAND_READY)));
 	}
 
-	/*
-	 * Since we're asking ParseConfigFp() to report errors as FATAL, there's
-	 * no need to check the return value.
-	 */
-	(void) ParseConfigFp(fd, RECOVERY_COMMAND_FILE, 0, FATAL, &head, &tail);
-
-	FreeFile(fd);
-
-	for (item = head; item; item = item->next)
+	/* Check for compulsory parameters */
+	if (standby_mode)
 	{
-		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, "pause_at_recovery_target") == 0)
-		{
-			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)));
-		}
-		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,
-							(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,
-				 (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)
-		{
-			/*
-			 * if recovery_target_xid or recovery_target_name specified, then
-			 * this overrides recovery_target_time
-			 */
-			if (recoveryTarget == RECOVERY_TARGET_XID ||
-				recoveryTarget == RECOVERY_TARGET_NAME)
-				continue;
-			recoveryTarget = RECOVERY_TARGET_TIME;
-
-			/*
-			 * 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)
-		{
-			/*
-			 * if recovery_target_xid specified, then this overrides
-			 * recovery_target_name
-			 */
-			if (recoveryTarget == RECOVERY_TARGET_XID)
-				continue;
-			recoveryTarget = RECOVERY_TARGET_NAME;
-
-			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)));
-
-			ereport(DEBUG2,
-					(errmsg_internal("recovery_target_name = '%s'",
-									 recoveryTargetName)));
-		}
-		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, &StandbyMode))
-				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, "trigger_file") == 0)
-		{
-			TriggerFile = pstrdup(item->value);
-			ereport(DEBUG2,
-					(errmsg_internal("trigger_file = '%s'",
-									 TriggerFile)));
-		}
-		else
-			ereport(FATAL,
-					(errmsg("unrecognized recovery parameter \"%s\"",
-							item->name)));
-	}
-
-	/*
-	 * Check for compulsory parameters
-	 */
-	if (StandbyMode)
-	{
-		if (PrimaryConnInfo == NULL && recoveryRestoreCommand == NULL)
+		if (!restore_command[0] && !primary_conninfo[0])
 			ereport(WARNING,
-					(errmsg("recovery command file \"%s\" specified neither primary_conninfo nor restore_command",
-							RECOVERY_COMMAND_FILE),
+					(errmsg("Neither primary_conninfo nor restore_command specified"),
 					 errhint("The database server will regularly poll the pg_xlog subdirectory to check for files placed there.")));
 	}
 	else
 	{
-		if (recoveryRestoreCommand == NULL)
+		if (!restore_command[0])
 			ereport(FATAL,
-					(errmsg("recovery command file \"%s\" must specify restore_command when standby mode is not enabled",
-							RECOVERY_COMMAND_FILE)));
+					(errmsg("restore_command must be specified when "
+							"standby_mode is not enabled")));
 	}
 
 	/* Enable fetching from archive recovery area */
@@ -4214,16 +4035,17 @@ readRecoveryCommandFile(void)
 	 * command and set InArchiveRecovery, because we need to fetch timeline
 	 * history files from the archive.
 	 */
-	if (rtliGiven)
+	if (strcmp(recovery_target_timeline_string, "") != 0)
 	{
-		if (rtli)
+		if (recovery_target_timeline)
 		{
 			/* Timeline 1 does not have a history file, all else should */
-			if (rtli != 1 && !existsTimeLineHistory(rtli))
+			if (recovery_target_timeline != 1 &&
+				!existsTimeLineHistory(recovery_target_timeline))
 				ereport(FATAL,
 						(errmsg("recovery target timeline %u does not exist",
-								rtli)));
-			recoveryTargetTLI = rtli;
+								recovery_target_timeline)));
+			recoveryTargetTLI = recovery_target_timeline;
 			recoveryTargetIsLatest = false;
 		}
 		else
@@ -4233,8 +4055,6 @@ readRecoveryCommandFile(void)
 			recoveryTargetIsLatest = true;
 		}
 	}
-
-	FreeConfigVariables(head);
 }
 
 /*
@@ -4309,11 +4129,11 @@ exitArchiveRecovery(TimeLineID endTLI, XLogSegNo endLogSegNo)
 	 * re-enter archive recovery mode in a subsequent crash.
 	 */
 	unlink(RECOVERY_COMMAND_DONE);
-	if (rename(RECOVERY_COMMAND_FILE, RECOVERY_COMMAND_DONE) != 0)
+	if (rename(RECOVERY_COMMAND_READY, RECOVERY_COMMAND_DONE) != 0)
 		ereport(FATAL,
 				(errcode_for_file_access(),
 				 errmsg("could not rename file \"%s\" to \"%s\": %m",
-						RECOVERY_COMMAND_FILE, RECOVERY_COMMAND_DONE)));
+						RECOVERY_COMMAND_READY, RECOVERY_COMMAND_DONE)));
 
 	ereport(LOG,
 			(errmsg("archive recovery complete")));
@@ -4376,7 +4196,7 @@ recoveryStopsHere(XLogRecord *record, bool *includeThis)
 		return false;
 
 	/* Do we have a PITR target at all? */
-	if (recoveryTarget == RECOVERY_TARGET_UNSET)
+	if (recovery_target == RECOVERY_TARGET_UNSET)
 	{
 		/*
 		 * Save timestamp of latest transaction commit/abort if this is a
@@ -4387,7 +4207,7 @@ recoveryStopsHere(XLogRecord *record, bool *includeThis)
 		return false;
 	}
 
-	if (recoveryTarget == RECOVERY_TARGET_XID)
+	if (recovery_target == RECOVERY_TARGET_XID)
 	{
 		/*
 		 * There can be only one transaction end record with this exact
@@ -4398,17 +4218,17 @@ recoveryStopsHere(XLogRecord *record, bool *includeThis)
 		 * they complete. A higher numbered xid will complete before you about
 		 * 50% of the time...
 		 */
-		stopsHere = (record->xl_xid == recoveryTargetXid);
+		stopsHere = (record->xl_xid == recovery_target_xid);
 		if (stopsHere)
-			*includeThis = recoveryTargetInclusive;
+			*includeThis = recovery_target_inclusive;
 	}
-	else if (recoveryTarget == RECOVERY_TARGET_NAME)
+	else if (recovery_target == RECOVERY_TARGET_NAME)
 	{
 		/*
 		 * There can be many restore points that share the same name, so we
 		 * stop at the first one
 		 */
-		stopsHere = (strcmp(recordRPName, recoveryTargetName) == 0);
+		stopsHere = (strcmp(recordRPName, recovery_target_name) == 0);
 
 		/*
 		 * Ignore recoveryTargetInclusive because this is not a transaction
@@ -4423,16 +4243,17 @@ recoveryStopsHere(XLogRecord *record, bool *includeThis)
 		 * we stop after the last one, if we are inclusive, or stop at the
 		 * first one if we are exclusive
 		 */
-		if (recoveryTargetInclusive)
-			stopsHere = (recordXtime > recoveryTargetTime);
+		if (recovery_target_inclusive)
+			stopsHere = (recordXtime > recovery_target_time);
 		else
-			stopsHere = (recordXtime >= recoveryTargetTime);
+			stopsHere = (recordXtime >= recovery_target_time);
 		if (stopsHere)
 			*includeThis = false;
 	}
 
 	if (stopsHere)
 	{
+		recoveryStopTarget = recovery_target;
 		recoveryStopXid = record->xl_xid;
 		recoveryStopTime = recordXtime;
 		recoveryStopAfter = *includeThis;
@@ -4780,36 +4601,28 @@ 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 recovery trigger file, and if so set up state for offline
+	 * recovery.
 	 */
-	strncpy(XLogCtl->archiveCleanupCommand,
-			archiveCleanupCommand ? archiveCleanupCommand : "",
-			sizeof(XLogCtl->archiveCleanupCommand));
+	CheckRecoveryReadyFile();
 
 	if (InArchiveRecovery)
 	{
-		if (StandbyMode)
+		if (standby_mode)
 			ereport(LOG,
 					(errmsg("entering standby mode")));
-		else if (recoveryTarget == RECOVERY_TARGET_XID)
+		else if (recovery_target == RECOVERY_TARGET_XID)
 			ereport(LOG,
 					(errmsg("starting point-in-time recovery to XID %u",
-							recoveryTargetXid)));
-		else if (recoveryTarget == RECOVERY_TARGET_TIME)
+							recovery_target_xid)));
+		else if (recovery_target == RECOVERY_TARGET_TIME)
 			ereport(LOG,
 					(errmsg("starting point-in-time recovery to %s",
-							timestamptz_to_str(recoveryTargetTime))));
-		else if (recoveryTarget == RECOVERY_TARGET_NAME)
+							timestamptz_to_str(recovery_target_time))));
+		else if (recovery_target == RECOVERY_TARGET_NAME)
 			ereport(LOG,
 					(errmsg("starting point-in-time recovery to \"%s\"",
-							recoveryTargetName)));
+							recovery_target_name)));
 		else
 			ereport(LOG,
 					(errmsg("starting archive recovery")));
@@ -4819,7 +4632,7 @@ StartupXLOG(void)
 	 * Take ownership of the wakeup latch if we're going to sleep during
 	 * recovery.
 	 */
-	if (StandbyMode)
+	if (standby_mode)
 		OwnLatch(&XLogCtl->recoveryWakeupLatch);
 
 	/* Set up XLOG reader facility */
@@ -4888,7 +4701,7 @@ StartupXLOG(void)
 					(errmsg("checkpoint record is at %X/%X",
 							(uint32) (checkPointLoc >> 32), (uint32) checkPointLoc)));
 		}
-		else if (StandbyMode)
+		else if (standby_mode)
 		{
 			/*
 			 * The last valid checkpoint record required for a streaming
@@ -5003,7 +4816,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.trigger file,
 	 * then assume no recovery needed.
 	 */
 	if (checkPoint.redo < RecPtr)
@@ -5017,7 +4830,7 @@ StartupXLOG(void)
 		InRecovery = true;
 	else if (InArchiveRecovery)
 	{
-		/* force recovery due to presence of recovery.conf */
+		/* force recovery due to presence of recovery.trigger */
 		InRecovery = true;
 	}
 
@@ -5330,7 +5143,7 @@ StartupXLOG(void)
 				 */
 				if (recoveryStopsHere(record, &recoveryApply))
 				{
-					if (recoveryPauseAtTarget)
+					if (pause_at_recovery_target)
 					{
 						SetRecoveryPause(true);
 						recoveryPausesHere();
@@ -5480,7 +5293,7 @@ StartupXLOG(void)
 	 * We don't need the latch anymore. It's not strictly necessary to disown
 	 * it, but let's do it for the sake of tidiness.
 	 */
-	if (StandbyMode)
+	if (standby_mode)
 		DisownLatch(&XLogCtl->recoveryWakeupLatch);
 
 	/*
@@ -5488,7 +5301,7 @@ StartupXLOG(void)
 	 * recovery to force fetching the files (which would be required at end of
 	 * recovery, e.g., timeline history file) from archive or pg_xlog.
 	 */
-	StandbyMode = false;
+	SetConfigOption("standby_mode", "false", PGC_POSTMASTER, PGC_S_OVERRIDE);
 
 	/*
 	 * Re-fetch the last valid or last applied record, so we can identify the
@@ -5567,17 +5380,17 @@ StartupXLOG(void)
 		 * Create a comment for the history file to explain why and where
 		 * timeline changed.
 		 */
-		if (recoveryTarget == RECOVERY_TARGET_XID)
+		if (recovery_target == RECOVERY_TARGET_XID)
 			snprintf(reason, sizeof(reason),
 					 "%s transaction %u",
 					 recoveryStopAfter ? "after" : "before",
 					 recoveryStopXid);
-		else if (recoveryTarget == RECOVERY_TARGET_TIME)
+		else if (recovery_target == RECOVERY_TARGET_TIME)
 			snprintf(reason, sizeof(reason),
 					 "%s %s\n",
 					 recoveryStopAfter ? "after" : "before",
 					 timestamptz_to_str(recoveryStopTime));
-		else if (recoveryTarget == RECOVERY_TARGET_NAME)
+		else if (recovery_target == RECOVERY_TARGET_NAME)
 			snprintf(reason, sizeof(reason),
 					 "at restore point \"%s\"",
 					 recoveryStopName);
@@ -5711,8 +5524,8 @@ StartupXLOG(void)
 		/*
 		 * And finally, execute the recovery_end_command, if any.
 		 */
-		if (recoveryEndCommand)
-			ExecuteRecoveryCommand(recoveryEndCommand,
+		if (recovery_end_command[0])
+			ExecuteRecoveryCommand(recovery_end_command,
 								   "recovery_end_command",
 								   true);
 	}
@@ -6565,7 +6378,7 @@ CreateCheckPoint(int flags)
 		XLogRecPtr	curInsert;
 
 		INSERT_RECPTR(curInsert, Insert, Insert->curridx);
-		if (curInsert == ControlFile->checkPoint + 
+		if (curInsert == ControlFile->checkPoint +
 			MAXALIGN(SizeOfXLogRecord + sizeof(CheckPoint)) &&
 			ControlFile->checkPoint == ControlFile->checkPointCopy.redo)
 		{
@@ -7140,8 +6953,8 @@ CreateRestartPoint(int flags)
 	/*
 	 * Finally, execute archive_cleanup_command, if any.
 	 */
-	if (XLogCtl->archiveCleanupCommand[0])
-		ExecuteRecoveryCommand(XLogCtl->archiveCleanupCommand,
+	if (archive_cleanup_command[0])
+		ExecuteRecoveryCommand(archive_cleanup_command,
 							   "archive_cleanup_command",
 							   false);
 
@@ -8854,7 +8667,7 @@ XLogPageRead(XLogReaderState *xlogreader, XLogRecPtr targetPagePtr, int reqLen,
 		 * Request a restartpoint if we've replayed too much xlog since the
 		 * last one.
 		 */
-		if (StandbyMode && bgwriterLaunched)
+		if (standby_mode && bgwriterLaunched)
 		{
 			if (XLogCheckpointNeeded(readSegNo))
 			{
@@ -8877,7 +8690,7 @@ retry:
 		(readSource == XLOG_FROM_STREAM &&
 		 receivedUpto < targetPagePtr + reqLen))
 	{
-		if (StandbyMode)
+		if (standby_mode)
 		{
 			if (!WaitForWALToBecomeAvailable(targetPagePtr + reqLen,
 											 private->randAccess,
@@ -8966,7 +8779,7 @@ next_record_is_invalid:
 	readSource = 0;
 
 	/* In standby-mode, keep trying */
-	if (StandbyMode)
+	if (standby_mode)
 		goto retry;
 	else
 		return -1;
@@ -9073,7 +8886,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 (primary_conninfo[0])
 					{
 						XLogRecPtr ptr;
 						TimeLineID tli;
@@ -9094,7 +8907,7 @@ WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess,
 									 tli, curFileTLI);
 						}
 						curFileTLI = tli;
-						RequestXLogStreaming(curFileTLI, ptr, PrimaryConnInfo);
+						RequestXLogStreaming(curFileTLI, ptr);
 					}
 					/*
 					 * Move to XLOG_FROM_STREAM state in either case. We'll get
@@ -9380,14 +9193,14 @@ CheckForStandbyTrigger(void)
 		return true;
 	}
 
-	if (TriggerFile == NULL)
+	if (!trigger_file[0])
 		return false;
 
-	if (stat(TriggerFile, &stat_buf) == 0)
+	if (stat(trigger_file, &stat_buf) == 0)
 	{
 		ereport(LOG,
-				(errmsg("trigger file found: %s", TriggerFile)));
-		unlink(TriggerFile);
+				(errmsg("trigger file found: %s", trigger_file)));
+		unlink(trigger_file);
 		triggered = true;
 		return true;
 	}
diff --git a/src/backend/access/transam/xlogarchive.c b/src/backend/access/transam/xlogarchive.c
index 52922da..20275c8 100644
--- a/src/backend/access/transam/xlogarchive.c
+++ b/src/backend/access/transam/xlogarchive.c
@@ -67,7 +67,7 @@ RestoreArchivedFile(char *path, const char *xlogfname,
 	TimeLineID	restartTli;
 
 	/* In standby mode, restore_command might not be supplied */
-	if (recoveryRestoreCommand == NULL)
+	if (restore_command == NULL)
 		goto not_available;
 
 	/*
@@ -150,7 +150,7 @@ RestoreArchivedFile(char *path, const char *xlogfname,
 	endp = xlogRestoreCmd + MAXPGPATH - 1;
 	*endp = '\0';
 
-	for (sp = recoveryRestoreCommand; *sp; sp++)
+	for (sp = restore_command; *sp; sp++)
 	{
 		if (*sp == '%')
 		{
@@ -236,7 +236,7 @@ RestoreArchivedFile(char *path, const char *xlogfname,
 				 * incorrectly conclude we've reached the end of WAL and we're
 				 * done recovering ...
 				 */
-				if (StandbyMode && stat_buf.st_size < expectedSize)
+				if (standby_mode && stat_buf.st_size < expectedSize)
 					elevel = DEBUG1;
 				else
 					elevel = FATAL;
diff --git a/src/backend/commands/extension.c b/src/backend/commands/extension.c
index c02101f..9babd74 100644
--- a/src/backend/commands/extension.c
+++ b/src/backend/commands/extension.c
@@ -9,7 +9,7 @@
  * dependent objects can be associated with it.  An extension is created by
  * populating the pg_extension catalog from a "control" file.
  * The extension control file is parsed with the same parser we use for
- * postgresql.conf and recovery.conf.  An extension also has an installation
+ * postgresql.conf.  An extension also has an installation
  * script file, containing SQL commands to create the extension's objects.
  *
  * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index 7359297..325f6de 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -185,7 +185,6 @@ DisableWalRcvImmediateExit(void)
 void
 WalReceiverMain(void)
 {
-	char		conninfo[MAXCONNINFO];
 	XLogRecPtr	startpoint;
 	TimeLineID	startpointTLI;
 	TimeLineID	primaryTLI;
@@ -239,7 +238,6 @@ WalReceiverMain(void)
 	walrcv->walRcvState = WALRCV_STREAMING;
 
 	/* Fetch information required to start streaming */
-	strlcpy(conninfo, (char *) walrcv->conninfo, MAXCONNINFO);
 	startpoint = walrcv->receiveStart;
 	startpointTLI = walrcv->receiveStartTLI;
 
@@ -306,7 +304,7 @@ WalReceiverMain(void)
 
 	/* Establish the connection to the primary for XLOG streaming */
 	EnableWalRcvImmediateExit();
-	walrcv_connect(conninfo);
+	walrcv_connect(primary_conninfo);
 	DisableWalRcvImmediateExit();
 
 	first_stream = true;
@@ -404,8 +402,21 @@ WalReceiverMain(void)
 
 				if (got_SIGHUP)
 				{
+					char    *conninfo = pstrdup(primary_conninfo);
+
 					got_SIGHUP = false;
 					ProcessConfigFile(PGC_SIGHUP);
+
+					/*
+					 * If primary_conninfo has been changed while walreceiver is running,
+					 * shut down walreceiver so that new walreceiver is started and
+					 * it initiates replication with new primary_conninfo.
+					 */
+					if (strcmp(conninfo, primary_conninfo) != 0)
+						ereport(FATAL,
+								(errcode(ERRCODE_ADMIN_SHUTDOWN),
+								 errmsg("terminating walreceiver process because primary_conninfo was changed")));
+					pfree(conninfo);
 				}
 
 				/* Wait a while for data to arrive */
diff --git a/src/backend/replication/walreceiverfuncs.c b/src/backend/replication/walreceiverfuncs.c
index d414808..d6a5e06 100644
--- a/src/backend/replication/walreceiverfuncs.c
+++ b/src/backend/replication/walreceiverfuncs.c
@@ -219,11 +219,10 @@ ShutdownWalRcv(void)
 /*
  * Request postmaster to start walreceiver.
  *
- * recptr indicates the position where streaming should begin, and conninfo
- * is a libpq connection string to use.
+ * recptr indicates the position where streaming should begin.
  */
 void
-RequestXLogStreaming(TimeLineID tli, XLogRecPtr recptr, const char *conninfo)
+RequestXLogStreaming(TimeLineID tli, XLogRecPtr recptr)
 {
 	/* use volatile pointer to prevent code rearrangement */
 	volatile WalRcvData *walrcv = WalRcv;
@@ -245,11 +244,6 @@ RequestXLogStreaming(TimeLineID tli, XLogRecPtr recptr, const char *conninfo)
 	Assert(walrcv->walRcvState == WALRCV_STOPPED ||
 		   walrcv->walRcvState == WALRCV_WAITING);
 
-	if (conninfo != NULL)
-		strlcpy((char *) walrcv->conninfo, conninfo, MAXCONNINFO);
-	else
-		walrcv->conninfo[0] = '\0';
-
 	if (walrcv->walRcvState == WALRCV_STOPPED)
 	{
 		launch = true;
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 6128694..f49b8fe 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -30,6 +30,7 @@
 #include "access/transam.h"
 #include "access/twophase.h"
 #include "access/xact.h"
+#include "access/xlog_internal.h"
 #include "catalog/namespace.h"
 #include "commands/async.h"
 #include "commands/prepare.h"
@@ -196,6 +197,14 @@ static bool check_application_name(char **newval, void **extra, GucSource source
 static void assign_application_name(const char *newval, void *extra);
 static const char *show_unix_socket_permissions(void);
 static const char *show_log_file_mode(void);
+static bool check_recovery_target_xid(char **newval, void **extra, GucSource source);
+static void assign_recovery_target_xid(const char *newval, void *extra);
+static bool check_recovery_target_name(char **newval, void **extra, GucSource source);
+static void assign_recovery_target_name(const char *newval, void *extra);
+static bool check_recovery_target_time(char **newval, void **extra, GucSource source);
+static void assign_recovery_target_time(const char *newval, void *extra);
+static bool check_recovery_target_timeline(char **newval, void **extra, GucSource source);
+static void assign_recovery_target_timeline(const char *newval, void *extra);
 
 static char *config_enum_get_options(struct config_enum * record,
 						const char *prefix, const char *suffix,
@@ -468,6 +477,8 @@ static int	wal_block_size;
 static int	wal_segment_size;
 static bool integer_datetimes;
 static int	effective_io_concurrency;
+static char *recovery_target_xid_string;
+static char *recovery_target_time_string;
 
 /* should be static, but commands/variable.c needs to get at this */
 char	   *role_string;
@@ -547,6 +558,10 @@ const char *const config_group_names[] =
 	gettext_noop("Write-Ahead Log / Checkpoints"),
 	/* WAL_ARCHIVING */
 	gettext_noop("Write-Ahead Log / Archiving"),
+	/* WAL_ARCHIVE_RECOVERY */
+	gettext_noop("Write-Ahead Log / Archive Recovery"),
+	/* WAL_RECOVERY_TARGET */
+	gettext_noop("Write-Ahead Log / Recovery Target"),
 	/* REPLICATION */
 	gettext_noop("Replication"),
 	/* REPLICATION_SENDING */
@@ -1375,6 +1390,36 @@ static struct config_bool ConfigureNamesBool[] =
 	},
 
 	{
+		{"recovery_target_inclusive", PGC_SIGHUP, WAL_RECOVERY_TARGET,
+			gettext_noop("Sets whether to include or exclude transaction with recovery target."),
+			NULL
+		},
+		&recovery_target_inclusive,
+		true,
+		NULL, NULL, NULL
+	},
+
+	{
+		{"pause_at_recovery_target", PGC_SIGHUP, WAL_RECOVERY_TARGET,
+			gettext_noop("Sets whether recovery should pause when the recovery target is reached."),
+			NULL
+		},
+		&pause_at_recovery_target,
+		true,
+		NULL, NULL, NULL
+	},
+
+	{
+		{"standby_mode", PGC_POSTMASTER, REPLICATION_STANDBY,
+			gettext_noop("Sets whether to start the server as a standby."),
+			NULL
+		},
+		&standby_mode,
+		false,
+		NULL, NULL, NULL
+	},
+
+	{
 		{"hot_standby", PGC_POSTMASTER, REPLICATION_STANDBY,
 			gettext_noop("Allows connections and queries during recovery."),
 			NULL
@@ -2543,6 +2588,97 @@ static struct config_string ConfigureNamesString[] =
 	},
 
 	{
+		{"restore_command", PGC_SIGHUP, WAL_ARCHIVE_RECOVERY,
+			gettext_noop("Sets the shell command that will retrieve an archived WAL file."),
+			NULL
+		},
+		&restore_command,
+		"",
+		NULL, NULL, NULL
+	},
+
+	{
+		{"archive_cleanup_command", PGC_SIGHUP, WAL_ARCHIVE_RECOVERY,
+			gettext_noop("Sets the shell command that will be executed at every restartpoint."),
+			NULL
+		},
+		&archive_cleanup_command,
+		"",
+		NULL, NULL, NULL
+	},
+
+	{
+		{"recovery_end_command", PGC_SIGHUP, WAL_ARCHIVE_RECOVERY,
+			gettext_noop("Sets the shell command that will be executed once only at the end of recovery."),
+			NULL
+		},
+		&recovery_end_command,
+		"",
+		NULL, NULL, NULL
+	},
+
+	{
+		{"recovery_target_xid", PGC_SIGHUP, WAL_RECOVERY_TARGET,
+			gettext_noop("Sets the transaction ID up to which recovery will proceed."),
+			NULL
+		},
+		&recovery_target_xid_string,
+		"",
+		check_recovery_target_xid, assign_recovery_target_xid, NULL
+	},
+
+	{
+		{"recovery_target_name", PGC_SIGHUP, WAL_RECOVERY_TARGET,
+			gettext_noop("Sets the named restore point."),
+			NULL
+		},
+		&recovery_target_name,
+		"",
+		check_recovery_target_name, assign_recovery_target_name, NULL
+	},
+
+	{
+		{"recovery_target_time", PGC_SIGHUP, WAL_RECOVERY_TARGET,
+			gettext_noop("Sets the time stamp up to which recovery will proceed."),
+			NULL
+		},
+		&recovery_target_time_string,
+		"",
+		check_recovery_target_time, assign_recovery_target_time, NULL
+	},
+
+	{
+		{"recovery_target_timeline", PGC_POSTMASTER, WAL_RECOVERY_TARGET,
+			gettext_noop("Sets recoverying into a particular timeline."),
+			NULL
+		},
+		&recovery_target_timeline_string,
+		"",
+		check_recovery_target_timeline, assign_recovery_target_timeline, NULL
+	},
+
+	{
+		{"primary_conninfo", PGC_SIGHUP, REPLICATION_STANDBY,
+			gettext_noop("Sets the connection string to be used to connect with the primary."),
+			NULL,
+			GUC_SUPERUSER_ONLY
+		},
+		&primary_conninfo,
+		"",
+		NULL, NULL, NULL
+	},
+
+	{
+		{"trigger_file", PGC_SIGHUP, REPLICATION_STANDBY,
+			gettext_noop("Sets the trigger file whose presence ends recovery in the standby."),
+			NULL
+		},
+		&trigger_file,
+		"",
+		NULL, NULL, NULL
+	},
+
+	{
 		{"client_encoding", PGC_USERSET, CLIENT_CONN_LOCALE,
 			gettext_noop("Sets the client's character set encoding."),
 			NULL,
@@ -8760,4 +8896,158 @@ show_log_file_mode(void)
 	return buf;
 }
 
+static bool
+check_recovery_target_xid(char **newval, void **extra, GucSource source)
+{
+	TransactionId   xid;
+	TransactionId   *myextra;
+
+	if (strcmp(*newval, "") == 0)
+		xid = InvalidTransactionId;
+	else
+	{
+		errno = 0;
+		xid = (TransactionId) strtoul(*newval, NULL, 0);
+		if (errno == EINVAL || errno == ERANGE)
+		{
+			GUC_check_errdetail("recovery_target_xid is not a valid number: \"%s\"",
+								*newval);
+			return false;
+		}
+	}
+
+	myextra = (TransactionId *) guc_malloc(ERROR, sizeof(TransactionId));
+	*myextra = xid;
+	*extra = (void *) myextra;
+
+	return true;
+}
+
+static void
+assign_recovery_target_xid(const char *newval, void *extra)
+{
+	recovery_target_xid = *((TransactionId *) extra);
+
+	if (recovery_target_xid != InvalidTransactionId)
+		recovery_target = RECOVERY_TARGET_XID;
+	else if (recovery_target_name[0])
+		recovery_target = RECOVERY_TARGET_NAME;
+	else if (recovery_target_time != 0)
+		recovery_target = RECOVERY_TARGET_TIME;
+	else
+		recovery_target = RECOVERY_TARGET_UNSET;
+}
+
+static bool
+check_recovery_target_name(char **newval, void **extra, GucSource source)
+{
+	if (strlen(*newval) >= MAXFNAMELEN)
+	{
+		GUC_check_errdetail("\"recovery_target_name\" is too long (maximum %d characters)",
+							MAXFNAMELEN - 1);
+		return false;
+	}
+	return true;
+}
+
+static void
+assign_recovery_target_name(const char *newval, void *extra)
+{
+	if (recovery_target_xid != InvalidTransactionId)
+		recovery_target = RECOVERY_TARGET_XID;
+	else if (newval[0])
+		recovery_target = RECOVERY_TARGET_NAME;
+	else if (recovery_target_time != 0)
+		recovery_target = RECOVERY_TARGET_TIME;
+	else
+		recovery_target = RECOVERY_TARGET_UNSET;
+}
+
+static bool
+check_recovery_target_time(char **newval, void **extra, GucSource source)
+{
+	TimestampTz     time;
+	TimestampTz     *myextra;
+	MemoryContext oldcontext = CurrentMemoryContext;
+
+	PG_TRY();
+	{
+		time = (strcmp(*newval, "") == 0) ?
+			0 :
+			DatumGetTimestampTz(DirectFunctionCall3(timestamptz_in,
+													CStringGetDatum(*newval),
+													ObjectIdGetDatum(InvalidOid),
+													Int32GetDatum(-1)));
+	}
+	PG_CATCH();
+	{
+		ErrorData  *edata;
+
+		/* Save error info */
+		MemoryContextSwitchTo(oldcontext);
+		edata = CopyErrorData();
+		FlushErrorState();
+
+		/* Pass the error message */
+		GUC_check_errdetail("%s", edata->message);
+		FreeErrorData(edata);
+		return false;
+	}
+	PG_END_TRY();
+
+	myextra = (TimestampTz *) guc_malloc(ERROR, sizeof(TimestampTz));
+	*myextra = time;
+	*extra = (void *) myextra;
+
+	return true;
+}
+
+static void
+assign_recovery_target_time(const char *newval, void *extra)
+{
+	recovery_target_time = *((TimestampTz *) extra);
+
+	if (recovery_target_xid != InvalidTransactionId)
+		recovery_target = RECOVERY_TARGET_XID;
+	else if (recovery_target_name[0])
+		recovery_target = RECOVERY_TARGET_NAME;
+	else if (recovery_target_time != 0)
+		recovery_target = RECOVERY_TARGET_TIME;
+	else
+		recovery_target = RECOVERY_TARGET_UNSET;
+}
+
+static bool
+check_recovery_target_timeline(char **newval, void **extra, GucSource source)
+{
+	TimeLineID	tli = 0;
+	TimeLineID	*myextra;
+
+	if (strcmp(*newval, "") == 0 || strcmp(*newval, "latest") == 0)
+		tli = 0;
+	else
+	{
+		errno = 0;
+		tli = (TimeLineID) strtoul(*newval, NULL, 0);
+		if (errno == EINVAL || errno == ERANGE)
+		{
+			GUC_check_errdetail("recovery_target_timeline is not a valid number: \"%s\"",
+								*newval);
+			return false;
+		}
+	}
+
+	myextra = (TimeLineID *) guc_malloc(ERROR, sizeof(TimeLineID));
+	*myextra = tli;
+	*extra = (void *) myextra;
+
+	return true;
+}
+
+static void
+assign_recovery_target_timeline(const char *newval, void *extra)
+{
+	recovery_target_timeline = *((TimeLineID *) extra);
+}
+
 #include "guc-file.c"
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
index 62aea2f..52a4e71 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -198,6 +198,23 @@
 #archive_timeout = 0		# force a logfile segment switch after this
 				# number of seconds; 0 disables
 
+# - Archive Recovery -
+#restore_command = ''		# command to use to restore an archived logfile segment
+				# placeholders: %p = path of file to restore
+				#               %f = file name only
+				# e.g. 'cp /mnt/server/archivedir/%f %p'
+#archive_cleanup_command = ''	# command to execute at every restartpoint
+#recovery_end_command = ''	# command to execute at completion of recovery
+
+# - Recovery Target -
+#recovery_target_xid = ''
+#recovery_target_name = ''		# e.g. 'daily backup 2011-01-26'
+#recovery_target_time = ''		# e.g. '2004-07-14 22:39:00 EST'
+#recovery_target_timeline = ''		# timeline ID or 'latest'
+					# (change requires restart)
+#recovery_target_inclusive = on
+#pause_at_recovery_target = on		# Pause recovery once target is reached
+
 
 #------------------------------------------------------------------------------
 # REPLICATION
@@ -240,6 +257,11 @@
 #wal_receiver_timeout = 60s		# time that receiver waits for
 					# communication from master
 					# in milliseconds; 0 disables
+#standby_mode = off			# "on" starts the server as a standby
+					# (change requires restart)
+#primary_conninfo = ''			# connection string to connect to the master
+					# e.g. 'host=localhost port=5432'
+#trigger_file = ''			# trigger file to promote the standby
 
 
 #------------------------------------------------------------------------------
diff --git a/src/bin/pg_ctl/pg_ctl.c b/src/bin/pg_ctl/pg_ctl.c
index e412d71..3a02481 100644
--- a/src/bin/pg_ctl/pg_ctl.c
+++ b/src/bin/pg_ctl/pg_ctl.c
@@ -928,7 +928,7 @@ do_stop(void)
 		/*
 		 * If backup_label exists, an online backup is running. Warn the user
 		 * that smart shutdown will wait for it to finish. However, if
-		 * recovery.conf is also present, we're recovering from an online
+		 * recovery.trigger is also present, we're recovering from an online
 		 * backup instead of performing one.
 		 */
 		if (shutdown_mode == SMART_MODE &&
@@ -1016,7 +1016,7 @@ do_restart(void)
 		/*
 		 * If backup_label exists, an online backup is running. Warn the user
 		 * that smart shutdown will wait for it to finish. However, if
-		 * recovery.conf is also present, we're recovering from an online
+		 * recovery.trigger is also present, we're recovering from an online
 		 * backup instead of performing one.
 		 */
 		if (shutdown_mode == SMART_MODE &&
@@ -1127,7 +1127,7 @@ do_promote(void)
 		exit(1);
 	}
 
-	/* If recovery.conf doesn't exist, the server is not in standby mode */
+	/* If recovery.trigger doesn't exist, the server is not in standby mode */
 	if (stat(recovery_file, &statbuf) != 0)
 	{
 		write_stderr(_("%s: cannot promote server; "
@@ -2270,7 +2270,7 @@ main(int argc, char **argv)
 		snprintf(postopts_file, MAXPGPATH, "%s/postmaster.opts", pg_data);
 		snprintf(pid_file, MAXPGPATH, "%s/postmaster.pid", pg_data);
 		snprintf(backup_file, MAXPGPATH, "%s/backup_label", pg_data);
-		snprintf(recovery_file, MAXPGPATH, "%s/recovery.conf", pg_data);
+		snprintf(recovery_file, MAXPGPATH, "%s/recovery.trigger", pg_data);
 		snprintf(promote_file, MAXPGPATH, "%s/promote", pg_data);
 	}
 
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index 72e3242..c831345 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -190,6 +190,20 @@ extern char *XLogArchiveCommand;
 extern bool EnableHotStandby;
 extern bool fullPageWrites;
 extern bool log_checkpoints;
+extern char *restore_command;
+extern char *archive_cleanup_command;
+extern char *recovery_end_command;
+extern bool standby_mode;
+extern char *primary_conninfo;
+extern char *trigger_file;
+extern RecoveryTargetType recovery_target;
+extern TransactionId recovery_target_xid;
+extern TimestampTz recovery_target_time;
+extern char *recovery_target_name;
+extern bool recovery_target_inclusive;
+extern bool pause_at_recovery_target;
+extern char *recovery_target_timeline_string;
+extern TimeLineID recovery_target_timeline;
 
 /* WAL levels */
 typedef enum WalLevel
diff --git a/src/include/replication/walreceiver.h b/src/include/replication/walreceiver.h
index 72878f8..d51d86f 100644
--- a/src/include/replication/walreceiver.h
+++ b/src/include/replication/walreceiver.h
@@ -149,7 +149,7 @@ extern void WalRcvShmemInit(void);
 extern void ShutdownWalRcv(void);
 extern bool WalRcvStreaming(void);
 extern bool WalRcvRunning(void);
-extern void RequestXLogStreaming(TimeLineID tli, XLogRecPtr recptr, const char *conninfo);
+extern void RequestXLogStreaming(TimeLineID tli, XLogRecPtr recptr);
 extern XLogRecPtr GetWalRcvWriteRecPtr(XLogRecPtr *latestChunkStart, TimeLineID *receiveTLI);
 extern int	GetReplicationApplyDelay(void);
 extern int	GetReplicationTransferLatency(void);
diff --git a/src/include/utils/guc_tables.h b/src/include/utils/guc_tables.h
index 7360ce3..a2d3281 100644
--- a/src/include/utils/guc_tables.h
+++ b/src/include/utils/guc_tables.h
@@ -68,6 +68,8 @@ enum config_group
 	WAL_SETTINGS,
 	WAL_CHECKPOINTS,
 	WAL_ARCHIVING,
+	WAL_ARCHIVE_RECOVERY,
+	WAL_RECOVERY_TARGET,
 	REPLICATION,
 	REPLICATION_SENDING,
 	REPLICATION_MASTER,
#10Michael Paquier
michael.paquier@gmail.com
In reply to: Michael Paquier (#9)
Re: Request for vote to move forward with recovery.conf overhaul

On Wed, Jan 23, 2013 at 1:49 PM, Michael Paquier
<michael.paquier@gmail.com>wrote:

I found that support for pg_basebackup -R was in the old patch, and I
haven't done anything for that yet.

Sorry, I meant that pg_basebackup -R support was NOT in the old patch, and
I haven't done anything about that.
Typed too quickly...
--
Michael Paquier
http://michael.otacoo.com

#11Josh Berkus
josh@agliodbs.com
In reply to: Michael Paquier (#9)
Re: Request for vote to move forward with recovery.conf overhaul

- if you want to trigger a recovery at promotion or have the recovery
parameters read on slave at startup, you need to create a file called
recovery.trigger in PGDATA. (something like "touch recovery.conf" is
enough). Once recovery is done, recovery.trigger is changed to
recovery.done.

So, per our compromise, we'd want to change the name of that file back
to recovery.conf. There's no point in renaming the file if we're not
going to get rid of it.

--
Josh Berkus
PostgreSQL Experts Inc.
http://pgexperts.com

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#12Simon Riggs
simon@2ndQuadrant.com
In reply to: Michael Paquier (#9)
Re: Request for vote to move forward with recovery.conf overhaul

On 23 January 2013 04:49, Michael Paquier <michael.paquier@gmail.com> wrote:

- recovery.conf is removed (no backward compatibility in this version of the
patch)

If you want to pursue that, you know where it leads. No, rebasing a
rejected patch doesn't help, its just relighting a fire that shouldn't
ever have been lit.

Pushing to do that out of order is just going to drain essential time
out of this CF from all of us.

--
Simon Riggs http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#13Michael Paquier
michael.paquier@gmail.com
In reply to: Simon Riggs (#12)
Re: Request for vote to move forward with recovery.conf overhaul

On 2013/01/23, at 18:12, Simon Riggs <simon@2ndQuadrant.com> wrote:

On 23 January 2013 04:49, Michael Paquier <michael.paquier@gmail.com> wrote:

- recovery.conf is removed (no backward compatibility in this version of the
patch)

If you want to pursue that, you know where it leads. No, rebasing a
rejected patch doesn't help, its just relighting a fire that shouldn't
ever have been lit.

Pushing to do that out of order is just going to drain essential time
out of this CF from all of us.

No problem to support both. The only problem I see is if the same parameter is defined in recovery.conf and postgresql.conf, is the priority given to recovery.conf?
--
Michael Paquier
http://michael.otacoo.com
(Sent from my mobile phone)

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#14Phil Sorber
phil@omniti.com
In reply to: Michael Paquier (#13)
Re: Request for vote to move forward with recovery.conf overhaul

On Wed, Jan 23, 2013 at 6:36 AM, Michael Paquier
<michael.paquier@gmail.com> wrote:

On 2013/01/23, at 18:12, Simon Riggs <simon@2ndQuadrant.com> wrote:

On 23 January 2013 04:49, Michael Paquier <michael.paquier@gmail.com> wrote:

- recovery.conf is removed (no backward compatibility in this version of the
patch)

If you want to pursue that, you know where it leads. No, rebasing a
rejected patch doesn't help, its just relighting a fire that shouldn't
ever have been lit.

Pushing to do that out of order is just going to drain essential time
out of this CF from all of us.

No problem to support both. The only problem I see is if the same parameter is defined in recovery.conf and postgresql.conf, is the priority given to recovery.conf?

I would think that if someone created a recovery.conf file they would
expect that to be given priority. Otherwise they would know that was a
deprecated method and would set it in postgresql.conf only.

--
Michael Paquier
http://michael.otacoo.com
(Sent from my mobile phone)

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#15Michael Paquier
michael.paquier@gmail.com
In reply to: Phil Sorber (#14)
1 attachment(s)
Re: Request for vote to move forward with recovery.conf overhaul

On Sun, Jan 27, 2013 at 7:14 AM, Phil Sorber <phil@omniti.com> wrote:

On Wed, Jan 23, 2013 at 6:36 AM, Michael Paquier
<michael.paquier@gmail.com> wrote:

On 2013/01/23, at 18:12, Simon Riggs <simon@2ndQuadrant.com> wrote:

On 23 January 2013 04:49, Michael Paquier <michael.paquier@gmail.com>

wrote:

- recovery.conf is removed (no backward compatibility in this version

of the

patch)

If you want to pursue that, you know where it leads. No, rebasing a
rejected patch doesn't help, its just relighting a fire that shouldn't
ever have been lit.

Pushing to do that out of order is just going to drain essential time
out of this CF from all of us.

No problem to support both. The only problem I see is if the same

parameter is defined in recovery.conf and postgresql.conf, is the priority
given to recovery.conf?

I would think that if someone created a recovery.conf file they would
expect that to be given priority. Otherwise they would know that was a
deprecated method and would set it in postgresql.conf only.

Please find attached an half-cooked patch supporting both postgresql.conf
and recovery.conf. Priority is given to recovery.conf if the same parameter
is specified in both files. I have updated the docs in consequence but I
think they can be improved.
The main modification here is in xlog.c:readRecoveryCommandFile where the
deparsed output values of recovery.conf is transferred to the new GUCs
using SetConfigOption($OPTION, $VALUE, PGC_POSTMASTER, PGC_S_OVERRIDE) as
bridge. This does not work yet, SetConfigOption is not able to detect the
new values. Comments?
--
Michael Paquier
http://michael.otacoo.com

Attachments:

20130126_recovery_unite.patchapplication/octet-stream; name=20130126_recovery_unite.patchDownload
diff --git a/contrib/pg_archivecleanup/pg_archivecleanup.c b/contrib/pg_archivecleanup/pg_archivecleanup.c
index e97a11c..fb01da9 100644
--- a/contrib/pg_archivecleanup/pg_archivecleanup.c
+++ b/contrib/pg_archivecleanup/pg_archivecleanup.c
@@ -255,7 +255,7 @@ usage(void)
 	printf("  -x EXT         clean up files if they have this extension\n");
 	printf("  -?, --help     show this help, then exit\n");
 	printf("\n"
-		   "For use as archive_cleanup_command in recovery.conf when standby_mode = on:\n"
+		   "For use as archive_cleanup_command in postgresql.conf when standby_mode = on:\n"
 		   "  archive_cleanup_command = 'pg_archivecleanup [OPTION]... ARCHIVELOCATION %%r'\n"
 		   "e.g.\n"
 		   "  archive_cleanup_command = 'pg_archivecleanup /mnt/server/archiverdir %%r'\n");
diff --git a/contrib/pg_standby/pg_standby.c b/contrib/pg_standby/pg_standby.c
index 659bd50..115c25e 100644
--- a/contrib/pg_standby/pg_standby.c
+++ b/contrib/pg_standby/pg_standby.c
@@ -531,7 +531,7 @@ usage(void)
 	printf("  -w MAXWAITTIME     max seconds to wait for a file (0=no limit) (default=0)\n");
 	printf("  -?, --help         show this help, then exit\n");
 	printf("\n"
-		   "Main intended use as restore_command in recovery.conf:\n"
+		   "Main intended use as restore_command in postgresql.conf:\n"
 		   "  restore_command = 'pg_standby [OPTION]... ARCHIVELOCATION %%f %%p %%r'\n"
 		   "e.g.\n"
 	"  restore_command = 'pg_standby /mnt/server/archiverdir %%f %%p %%r'\n");
diff --git a/doc/src/sgml/backup.sgml b/doc/src/sgml/backup.sgml
index c4215be..e57d521 100644
--- a/doc/src/sgml/backup.sgml
+++ b/doc/src/sgml/backup.sgml
@@ -1002,8 +1002,16 @@ SELECT pg_stop_backup();
    </listitem>
    <listitem>
     <para>
-     Create a recovery command file <filename>recovery.conf</> in the cluster
-     data directory (see <xref linkend="recovery-config">). You might
+     Set up recovery parameters in <filename>postgresql.conf</> (see
+     <xref linkend="runtime-config-wal-archive-recovery"> and
+     <xref linkend="runtime-config-wal-recovery-target">). You can also
+     use the same parameters in <filename>recovery.conf</>.
+    </para>
+   </listitem>
+   <listitem>
+    <para>
+     Create a recovery command file <filename>recovery.conf</>
+     in the cluster data directory. You might
      also want to temporarily modify <filename>pg_hba.conf</> to prevent
      ordinary users from connecting until you are sure the recovery was successful.
     </para>
@@ -1031,12 +1039,11 @@ SELECT pg_stop_backup();
    </para>
 
    <para>
-    The key part of all this is to set up a recovery configuration file that
-    describes how you want to recover and how far the recovery should
-    run.  You can use <filename>recovery.conf.sample</> (normally
-    located in the installation's <filename>share/</> directory) as a
-    prototype.  The one thing that you absolutely must specify in
-    <filename>recovery.conf</> is the <varname>restore_command</>,
+    The key part of all this is to set up recovery parameters that
+    specify how you want to recover and how far the recovery should
+    run. The one thing that you absolutely must specify in
+    <filename>postgresql.conf</> or <filename>recovery.conf</> to
+    recover from the backup is the <varname>restore_command</>,
     which tells <productname>PostgreSQL</> how to retrieve archived
     WAL file segments.  Like the <varname>archive_command</>, this is
     a shell command string.  It can contain <literal>%f</>, which is
@@ -1090,8 +1097,8 @@ 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
-    the stop point, known as the <quote>recovery target</>, either by
+    required stopping point in <filename>postgresql.conf</> or <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
     are very usable, since there are no tools to help you identify with any
@@ -1187,9 +1194,11 @@ restore_command = 'cp /mnt/server/archivedir/%f %p'
     The default behavior of recovery is to recover along the same timeline
     that was current when the base backup was taken.  If you wish to recover
     into some child timeline (that is, you want to return to some state that
-    was itself generated after a recovery attempt), you need to specify the
-    target timeline ID in <filename>recovery.conf</>.  You cannot recover into
-    timelines that branched off earlier than the base backup.
+    was itself generated after a recovery attempt), you need to set
+    <xref linkend="guc-recovery-target-timeline"> to the
+    target timeline ID in <filename>postgresql.conf</> or <filename>recovery.conf</>.
+    You cannot recover into timelines that branched off earlier than the
+    base backup.
    </para>
   </sect2>
 
diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index b7df8ce..3b26bb7 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -2161,6 +2161,278 @@ include 'filename'
      </variablelist>
     </sect2>
 
+    <sect2 id="runtime-config-wal-archive-recovery">
+     <title>Archive Recovery</title>
+
+     <variablelist>
+      <varlistentry id="guc-restore-command" xreflabel="restore_command">
+       <term><varname>restore_command</varname> (<type>string</type>)</term>
+       <indexterm>
+        <primary><varname>restore_command</> configuration parameter</primary>
+       </indexterm>
+       <listitem>
+        <para>
+         The shell command to execute to retrieve an archived segment of
+         the WAL file series. This parameter is required for archive recovery,
+         but optional for streaming replication.
+         Any <literal>%f</> in the string is
+         replaced by the name of the file to retrieve from the archive,
+         and any <literal>%p</> is replaced by the copy destination path name
+         on the server.
+         (The path name is relative to the current working directory,
+         i.e., the cluster's data directory.)
+         Any <literal>%r</> is replaced by the name of the file containing the
+         last valid restart point. That is the earliest file that must be kept
+         to allow a restore to be restartable, so this information can be used
+         to truncate the archive to just the minimum required to support
+         restarting from the current restore. <literal>%r</> is typically only
+         used by warm-standby configurations
+         (see <xref linkend="warm-standby">).
+         Write <literal>%%</> to embed an actual <literal>%</> character.
+        </para>
+        <para>
+         It is important for the command to return a zero exit status
+         only if it succeeds.  The command <emphasis>will</> be asked for file
+         names that are not present in the archive; it must return nonzero
+         when so asked.  Examples:
+<programlisting>
+restore_command = 'cp /mnt/server/archivedir/%f "%p"'
+restore_command = 'copy "C:\\server\\archivedir\\%f" "%p"'  # Windows
+</programlisting>
+        </para>
+        <para>
+         This parameter can only be set in the <filename>postgresql.conf</>
+         file or on the server command line. It only has effect during archive
+         recovery or in standby mode.
+        </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry id="guc-archive-cleanup-command" xreflabel="archive_cleanup_command">
+       <term><varname>archive_cleanup_command</varname> (<type>string</type>)</term>
+       <indexterm>
+         <primary><varname>archive_cleanup_command</> configuration parameter</primary>
+       </indexterm>
+       <listitem>
+        <para>
+         The shell command that will be executed at every restartpoint.
+         The purpose of <varname>archive_cleanup_command</> is to
+         provide a mechanism for cleaning up old archived WAL files that
+         are no longer needed by the standby server.
+         Any <literal>%r</> is replaced by the name of the file containing the
+         last valid restart point.
+         That is the earliest file that must be <emphasis>kept</> to allow a
+         restore to be restartable, and so all files earlier than <literal>%r</>
+         may be safely removed.
+         This information can be used to truncate the archive to just the
+         minimum required to support restart from the current restore.
+         The <xref linkend="pgarchivecleanup"> module
+         is often used in <varname>archive_cleanup_command</> for
+         single-standby configurations, for example:
+<programlisting>archive_cleanup_command = 'pg_archivecleanup /mnt/server/archivedir %r'</programlisting>
+         Note however that if multiple standby servers are restoring from the
+         same archive directory, you will need to ensure that you do not delete
+         WAL files until they are no longer needed by any of the servers.
+         <varname>archive_cleanup_command</> would typically be used in a
+         warm-standby configuration (see <xref linkend="warm-standby">).
+         Write <literal>%%</> to embed an actual <literal>%</> character in the
+         command.
+        </para>
+        <para>
+         If the command returns a non-zero exit status then a WARNING log
+         message will be written.
+        </para>
+        <para>
+         This parameter can only be set in the <filename>postgresql.conf</>
+         file or on the server command line. It only has effect during archive
+         recovery or in standby mode.
+        </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry id="guc-recovery-end-command" xreflabel="recovery_end_command">
+       <term><varname>recovery_end_command</varname> (<type>string</type>)</term>
+       <indexterm>
+         <primary><varname>recovery_end_command</> configuration parameter</primary>
+       </indexterm>
+       <listitem>
+        <para>
+         The shell command that will be executed once only
+         at the end of recovery. This parameter is optional. The purpose of the
+         <varname>recovery_end_command</> is to provide a mechanism for cleanup
+         following replication or recovery.
+         Any <literal>%r</> is replaced by the name of the file containing the
+         last valid restart point, like in <varname>archive_cleanup_command</>.
+        </para>
+        <para>
+         If the command returns a non-zero exit status then a WARNING log
+         message will be written and the database will proceed to start up
+         anyway.  An exception is that if the command was terminated by a
+         signal, the database will not proceed with startup.
+        </para>
+        <para>
+         This parameter can only be set in the <filename>postgresql.conf</>
+         file or on the server command line. It only has effect during archive
+         recovery or in standby mode.
+        </para>
+       </listitem>
+      </varlistentry>
+     </variablelist>
+    </sect2>
+
+    <sect2 id="runtime-config-wal-recovery-target">
+     <title>Recovery Target</title>
+
+     <variablelist>
+      <varlistentry id="guc-recovery-target-name" xreflabel="recovery_target_name">
+       <term><varname>recovery_target_name</varname> (<type>string</type>)</term>
+       <indexterm>
+        <primary><varname>recovery_target_name</> configuration parameter</primary>
+       </indexterm>
+       <listitem>
+        <para>
+         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</>,
+         <varname>recovery_target_time</> or
+         <varname>recovery_target_xid</> can be specified.  The default
+         value is an empty string, which will recover to the end of the WAL log.
+        </para>
+        <para>
+         This parameter can only be set in the <filename>postgresql.conf</>
+         file or on the server command line. It only has effect during archive
+         recovery or in standby mode.
+        </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry id="guc-recovery-target-time" xreflabel="recovery_target_time">
+       <term><varname>recovery_target_time</varname> (<type>string</type>)</term>
+       <indexterm>
+        <primary><varname>recovery_target_time</> configuration parameter</primary>
+       </indexterm>
+       <listitem>
+        <para>
+         Specifies the time stamp up to which recovery will proceed.
+         This parameter must be specified in the date/time format
+         (see <xref linkend="datatype-datetime-input"> for details).
+         At most one of <varname>recovery_target_time</>,
+         <varname>recovery_target_name</> or
+         <varname>recovery_target_xid</> can be specified.
+         The default value is an empty string, which will recover to
+         the end of the WAL log. The precise stopping point is also
+         influenced by <varname>recovery_target_inclusive</>.
+        </para>
+        <para>
+         This parameter can only be set in the <filename>postgresql.conf</>
+         file or on the server command line. It only has effect during archive
+         recovery or in standby mode.
+        </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry id="guc-recovery-target-xid" xreflabel="recovery_target_xid">
+       <term><varname>recovery_target_xid</varname> (<type>string</type>)</term>
+       <indexterm>
+        <primary><varname>recovery_target_xid</> configuration parameter</primary>
+       </indexterm>
+       <listitem>
+        <para>
+         Specifies the transaction ID up to which recovery will proceed.
+         Keep in mind that while transaction IDs are assigned sequentially
+         at transaction 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</>,
+         <varname>recovery_target_name</> or
+         <varname>recovery_target_time</> can be specified.
+         The default value is an empty string, which will recover to the end of
+         the WAL log. The precise stopping point is also influenced by
+         <varname>recovery_target_inclusive</>.
+        </para>
+        <para>
+         This parameter can only be set in the <filename>postgresql.conf</>
+         file or on the server command line. It only has effect during archive
+         recovery or in standby mode.
+        </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry id="guc-recovery-target-inclusive" xreflabel="recovery_target_inclusive">
+       <term><varname>recovery_target_inclusive</varname> (<type>boolean</type>)</term>
+       <indexterm>
+        <primary><varname>recovery_target_inclusive</> configuration parameter</primary>
+       </indexterm>
+       <listitem>
+        <para>
+         Specifies whether we stop just after the specified recovery target
+         (<literal>on</>), or just before the recovery target (<literal>off</>).
+         Applies to both <varname>recovery_target_time</>
+         and <varname>recovery_target_xid</>, whichever one is
+         specified for this recovery.  This indicates whether transactions
+         having exactly the target commit time or ID, respectively, will
+         be included in the recovery.  Default is <literal>on</>.
+        </para>
+        <para>
+         This parameter can only be set in the <filename>postgresql.conf</>
+         file or on the server command line. It only has effect during archive
+         recovery or in standby mode.
+        </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry id="guc-recovery-target-timeline" xreflabel="recovery_target_timeline">
+       <term><varname>recovery_target_timeline</varname> (<type>string</type>)</term>
+       <indexterm>
+        <primary><varname>recovery_target_timeline</> configuration parameter</primary>
+       </indexterm>
+       <listitem>
+        <para>
+         Specifies recovering into a particular timeline.  The default value is
+         an empty string, which will recover along the same timeline that was
+         current when the base backup was taken. Setting this to
+         <literal>latest</> recovers to the latest timeline found in the archive,
+         which is useful in a standby server. Other than that you only need to
+         set this parameter in complex re-recovery situations, where you need
+         to return to a state that itself was reached after a point-in-time
+         recovery. See <xref linkend="backup-timelines"> for discussion.
+        </para>
+        <para>
+         This parameter can only be set at server start. It only has effect
+         during archive recovery or in standby mode.
+        </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry id="guc-pause-at-recovery-target" xreflabel="pause_at_recovery_target">
+       <term><varname>pause_at_recovery_target</varname> (<type>boolean</type>)</term>
+       <indexterm>
+        <primary><varname>pause_at_recovery_target</> configuration parameter</primary>
+       </indexterm>
+       <listitem>
+        <para>
+         Specifies whether recovery should pause when the recovery target
+         is reached. The default is <literal>on</>.
+         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
+         <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
+         recovery target settings to a later target and restart to
+         continue recovery.
+        </para>
+        <para>
+         This parameter can only be set in the <filename>postgresql.conf</>
+         file or on the server command line. It only has effect during archive
+         recovery or in standby mode if recovery target is set.
+        </para>
+       </listitem>
+      </varlistentry>
+     </variablelist>
+     </sect2>
+
    </sect1>
 
    <sect1 id="runtime-config-replication">
@@ -2380,6 +2652,93 @@ include 'filename'
 
     <variablelist>
 
+     <varlistentry id="guc-standby-mode" xreflabel="standby_mode">
+      <term><varname>standby_mode</varname> (<type>boolean</type>)</term>
+      <indexterm>
+       <primary><varname>standby_mode</> configuration parameter</primary>
+      </indexterm>
+      <listitem>
+       <para>
+        Specifies whether to start the <productname>PostgreSQL</> server as
+        a standby when recovery trigger file <filename>recovery.trigger</> exists.
+        The default value is <literal>off</>.
+        If this parameter is <literal>on</>, the server will not
+        stop recovery when the end of archived WAL is reached,
+        but will keep trying to continue recovery by fetching new WAL segments
+        using <varname>restore_command</> and/or by connecting to
+        the primary server as specified by the <varname>primary_conninfo</>
+        setting.
+       </para>
+       <para>
+        This parameter can only be set at server start. It only has effect
+        if recovery trigger file <filename>recovery.trigger</> exists.
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry id="guc-primary-conninfo" xreflabel="primary_conninfo">
+      <term><varname>primary_conninfo</varname> (<type>string</type>)</term>
+      <indexterm>
+        <primary><varname>primary_conninfo</> configuration parameter</primary>
+      </indexterm>
+      <listitem>
+       <para>
+        Specifies a connection string to be used for the standby server
+        to connect with the primary. This string is in the format
+        accepted by the libpq <function>PQconnectdb</function> function,
+        described in <xref linkend="libpq-connect">. If any option is
+        unspecified in this string, then the corresponding environment
+        variable (see <xref linkend="libpq-envars">) is checked. If the
+        environment variable is not set either, then defaults are used.
+        If this parameter is an empty string (the default), no attempt is
+        made to connect to the master.
+       </para>
+       <para>
+        The connection string should specify the host name (or address)
+        of the primary server, as well as the port number if it is not
+        the same as the standby server's default.
+        Also specify a user name corresponding to a role that has the
+        <literal>REPLICATION</> and <literal>LOGIN</> privileges on the
+        primary (see
+        <xref linkend="streaming-replication-authentication">).
+        A password needs to be provided too, if the primary demands password
+        authentication.  It can be provided in the
+        <varname>primary_conninfo</varname> string, or in a separate
+        <filename>~/.pgpass</> file on the standby server (use
+        <literal>replication</> as the database name).
+        Do not specify a database name in the
+        <varname>primary_conninfo</varname> string.
+       </para>
+       <para>
+        This parameter can only be set in the <filename>postgresql.conf</>
+        file or on the server command line. It only has effect in standby mode.
+       </para>
+       <para>
+        If this parameter is changed while replication is in progress,
+        the standby terminates replication, and then tries to restart
+        replication with new setting.
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry id="guc-trigger-file" xreflabel="trigger_file">
+      <term><varname>trigger_file</varname> (<type>string</type>)</term>
+      <indexterm>
+        <primary><varname>trigger_file</> configuration parameter</primary>
+      </indexterm>
+      <listitem>
+       <para>
+        Specifies a trigger file whose presence ends recovery in the
+        standby.  Even if this value is not set, you can still promote
+        the standby using <command>pg_ctl promote</>.
+       </para>
+       <para>
+        This parameter can only be set in the <filename>postgresql.conf</>
+        file or on the server command line. It only has effect in standby mode.
+       </para>
+      </listitem>
+    </varlistentry>
+
      <varlistentry id="guc-hot-standby" xreflabel="hot_standby">
       <term><varname>hot_standby</varname> (<type>boolean</type>)</term>
       <indexterm>
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 35c7f75..48cfe9e 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -14670,7 +14670,7 @@ postgres=# select pg_start_backup('label_goes_here');
     <function>pg_create_restore_point</> creates a named transaction log
     record that can be used as recovery target, and returns the corresponding
     transaction log location.  The given name can then be used with
-    <xref linkend="recovery-target-name"> to specify the point up to which
+    <xref linkend="guc-recovery-target-name"> to specify the point up to which
     recovery will proceed.  Avoid creating multiple restore points with the
     same name, since recovery will stop at the first one whose name matches
     the recovery target.
diff --git a/doc/src/sgml/high-availability.sgml b/doc/src/sgml/high-availability.sgml
index c8f6fa8..21e1ee0 100644
--- a/doc/src/sgml/high-availability.sgml
+++ b/doc/src/sgml/high-availability.sgml
@@ -591,7 +591,7 @@ protocol to make nodes agree on a serializable transactional order.
    <para>
     In standby mode, the server continuously applies WAL received from the
     master server. The standby server can read WAL from a WAL archive
-    (see <xref linkend="restore-command">) or directly from the master
+    (see <xref linkend="guc-restore-command">) or directly from the master
     over a TCP connection (streaming replication). The standby server will
     also attempt to restore any WAL found in the standby cluster's
     <filename>pg_xlog</> directory. That typically happens after a server
@@ -658,13 +658,14 @@ protocol to make nodes agree on a serializable transactional order.
    <para>
     To set up the standby server, restore the base backup taken from primary
     server (see <xref linkend="backup-pitr-recovery">). Create a recovery
-    command file <filename>recovery.conf</> in the standby's cluster data
-    directory, and turn on <varname>standby_mode</>. Set
+    command file <filename>recovery.done</> in the standby's cluster data
+    directory. Turn on <varname>standby_mode</> and set
     <varname>restore_command</> to a simple command to copy files from
     the WAL archive. If you plan to have multiple standby servers for high
     availability purposes, set <varname>recovery_target_timeline</> to
     <literal>latest</>, to make the standby server follow the timeline change
-    that occurs at failover to another standby.
+    that occurs at failover to another standby. Parameters can be set up
+    in either <filename>postgresql.conf</> or <filename>recovery.conf</>.
    </para>
 
    <note>
@@ -695,7 +696,7 @@ protocol to make nodes agree on a serializable transactional order.
 
    <para>
     If you're using a WAL archive, its size can be minimized using the <xref
-    linkend="archive-cleanup-command"> parameter to remove files that are no
+    linkend="guc-archive-cleanup-command"> parameter to remove files that are no
     longer required by the standby server.
     The <application>pg_archivecleanup</> utility is designed specifically to
     be used with <varname>archive_cleanup_command</> in typical single-standby
@@ -706,7 +707,7 @@ protocol to make nodes agree on a serializable transactional order.
    </para>
 
    <para>
-    A simple example of a <filename>recovery.conf</> is:
+    A simple example of standby settings is:
 <programlisting>
 standby_mode = 'on'
 primary_conninfo = 'host=192.168.1.50 port=5432 user=foo password=foopass'
@@ -763,8 +764,8 @@ archive_cleanup_command = 'pg_archivecleanup /path/to/archive %r'
     To use streaming replication, set up a file-based log-shipping standby
     server as described in <xref linkend="warm-standby">. The step that
     turns a file-based log-shipping standby into streaming replication
-    standby is setting <varname>primary_conninfo</> setting in the
-    <filename>recovery.conf</> file to point to the primary server. Set
+    standby is setting <varname>primary_conninfo</> to
+    point to the primary server. Set
     <xref linkend="guc-listen-addresses"> and authentication options
     (see <filename>pg_hba.conf</>) on the primary so that the standby server
     can connect to the <literal>replication</> pseudo-database on the primary
@@ -824,15 +825,14 @@ host    replication     foo             192.168.1.100/32        md5
     </para>
     <para>
      The host name and port number of the primary, connection user name,
-     and password are specified in the <filename>recovery.conf</> file.
+     and password are specified in <varname>primary_conninfo</>.
      The password can also be set in the <filename>~/.pgpass</> file on the
      standby (specify <literal>replication</> in the <replaceable>database</>
      field).
      For example, if the primary is running on host IP <literal>192.168.1.50</>,
      port <literal>5432</literal>, the account name for replication is
      <literal>foo</>, and the password is <literal>foopass</>, the administrator
-     can add the following line to the <filename>recovery.conf</> file on the
-     standby:
+     can set <varname>primary_conninfo</> on the standby like this:
 
 <programlisting>
 # The standby connects to the primary that is running on host 192.168.1.50
@@ -1212,8 +1212,8 @@ primary_conninfo = 'host=192.168.1.50 port=5432 user=foo password=foopass'
    <para>
     To trigger failover of a log-shipping standby server,
     run <command>pg_ctl promote</> or create a trigger
-    file with the file name and path specified by the <varname>trigger_file</>
-    setting in <filename>recovery.conf</>. If you're planning to use
+    file with the file name and path specified by the <varname>trigger_file</>.
+    If you're planning to use
     <command>pg_ctl promote</> to fail over, <varname>trigger_file</> is
     not required. If you're setting up the reporting servers that are
     only used to offload read-only queries from the primary, not for high
@@ -1258,8 +1258,7 @@ primary_conninfo = 'host=192.168.1.50 port=5432 user=foo password=foopass'
     The magic that makes the two loosely coupled servers work together is
     simply a <varname>restore_command</> used on the standby that,
     when asked for the next WAL file, waits for it to become available from
-    the primary. The <varname>restore_command</> is specified in the
-    <filename>recovery.conf</> file on the standby server. Normal recovery
+    the primary. Normal recovery
     processing would request a file from the WAL archive, reporting failure
     if the file was unavailable.  For standby processing it is normal for
     the next WAL file to be unavailable, so the standby must wait for
@@ -1347,9 +1346,10 @@ if (!triggered)
      <listitem>
       <para>
        Begin recovery on the standby server from the local WAL
-       archive, using a <filename>recovery.conf</> that specifies a
+       archive, create a <filename>recovery.conf</> file, then specify a
        <varname>restore_command</> that waits as described
-       previously (see <xref linkend="backup-pitr-recovery">).
+       previously (see <xref linkend="backup-pitr-recovery">) in either
+       <filename>postgresql.conf</> or <filename>recovery.conf</>.
       </para>
      </listitem>
     </orderedlist>
diff --git a/doc/src/sgml/pgarchivecleanup.sgml b/doc/src/sgml/pgarchivecleanup.sgml
index 932914b..2984da4 100644
--- a/doc/src/sgml/pgarchivecleanup.sgml
+++ b/doc/src/sgml/pgarchivecleanup.sgml
@@ -38,8 +38,8 @@
 
   <para>
    To configure a standby
-   server to use <application>pg_archivecleanup</>, put this into its
-   <filename>recovery.conf</filename> configuration file:
+   server to use <application>pg_archivecleanup</>, specify
+   <xref linkend="guc-archive-cleanup-command"> like this:
 <programlisting>
 archive_cleanup_command = 'pg_archivecleanup <replaceable>archivelocation</> %r'
 </programlisting>
@@ -47,7 +47,7 @@ archive_cleanup_command = 'pg_archivecleanup <replaceable>archivelocation</> %r'
    files should be removed.
   </para>
   <para>
-   When used within <xref linkend="archive-cleanup-command">, all WAL files
+   When used within <varname>archive_cleanup_command</>, all WAL files
    logically preceding the value of the <literal>%r</> argument will be removed
    from <replaceable>archivelocation</>. This minimizes the number of files
    that need to be retained, while preserving crash-restart capability.  Use of
diff --git a/doc/src/sgml/pgstandby.sgml b/doc/src/sgml/pgstandby.sgml
index ca2b5c0..15097ca 100644
--- a/doc/src/sgml/pgstandby.sgml
+++ b/doc/src/sgml/pgstandby.sgml
@@ -46,8 +46,8 @@
 
   <para>
    To configure a standby
-   server to use <application>pg_standby</>, put this into its
-   <filename>recovery.conf</filename> configuration file:
+   server to use <application>pg_standby</>, specify
+   <xref linkend="guc-restore-command"> like this:
 <programlisting>
 restore_command = 'pg_standby <replaceable>archiveDir</> %f %p %r'
 </programlisting>
diff --git a/doc/src/sgml/recovery-config.sgml b/doc/src/sgml/recovery-config.sgml
index 7e39c0d..52b75b7 100644
--- a/doc/src/sgml/recovery-config.sgml
+++ b/doc/src/sgml/recovery-config.sgml
@@ -42,34 +42,8 @@
       </indexterm>
       <listitem>
        <para>
-        The shell command to execute to retrieve an archived segment of
-        the WAL file series. This parameter is required for archive recovery,
-        but optional for streaming replication.
-        Any <literal>%f</> in the string is
-        replaced by the name of the file to retrieve from the archive,
-        and any <literal>%p</> is replaced by the copy destination path name
-        on the server.
-        (The path name is relative to the current working directory,
-        i.e., the cluster's data directory.)
-        Any <literal>%r</> is replaced by the name of the file containing the
-        last valid restart point. That is the earliest file that must be kept
-        to allow a restore to be restartable, so this information can be used
-        to truncate the archive to just the minimum required to support
-        restarting from the current restore. <literal>%r</> is typically only
-        used by warm-standby configurations
-        (see <xref linkend="warm-standby">).
-        Write <literal>%%</> to embed an actual <literal>%</> character.
-       </para>
-
-       <para>
-        It is important for the command to return a zero exit status
-        only if it succeeds.  The command <emphasis>will</> be asked for file
-        names that are not present in the archive; it must return nonzero
-        when so asked.  Examples:
-<programlisting>
-restore_command = 'cp /mnt/server/archivedir/%f "%p"'
-restore_command = 'copy "C:\\server\\archivedir\\%f" "%p"'  # Windows
-</programlisting>
+        Refer to <xref linkend="guc-restore-command"> for detailed
+        description.
        </para>
       </listitem>
      </varlistentry>
@@ -81,33 +55,8 @@ restore_command = 'copy "C:\\server\\archivedir\\%f" "%p"'  # Windows
       </indexterm>
       <listitem>
        <para>
-        This optional parameter specifies a shell command that will be executed
-        at every restartpoint.  The purpose of
-        <varname>archive_cleanup_command</> is to provide a mechanism for
-        cleaning up old archived WAL files that are no longer needed by the
-        standby server.
-        Any <literal>%r</> is replaced by the name of the file containing the
-        last valid restart point.
-        That is the earliest file that must be <emphasis>kept</> to allow a
-        restore to be restartable, and so all files earlier than <literal>%r</>
-        may be safely removed.
-        This information can be used to truncate the archive to just the
-        minimum required to support restart from the current restore.
-        The <xref linkend="pgarchivecleanup"> module
-        is often used in <varname>archive_cleanup_command</> for
-        single-standby configurations, for example:
-<programlisting>archive_cleanup_command = 'pg_archivecleanup /mnt/server/archivedir %r'</programlisting>
-        Note however that if multiple standby servers are restoring from the
-        same archive directory, you will need to ensure that you do not delete
-        WAL files until they are no longer needed by any of the servers.
-        <varname>archive_cleanup_command</> would typically be used in a
-        warm-standby configuration (see <xref linkend="warm-standby">).
-        Write <literal>%%</> to embed an actual <literal>%</> character in the
-        command.
-       </para>
-       <para>
-        If the command returns a non-zero exit status then a WARNING log
-        message will be written.
+        Refer to <xref linkend="guc-archive-cleanup-command"> for detailed
+        description.
        </para>
       </listitem>
      </varlistentry>
@@ -119,18 +68,8 @@ restore_command = 'copy "C:\\server\\archivedir\\%f" "%p"'  # Windows
       </indexterm>
       <listitem>
        <para>
-        This parameter specifies a shell command that will be executed once only
-        at the end of recovery. This parameter is optional. The purpose of the
-        <varname>recovery_end_command</> is to provide a mechanism for cleanup
-        following replication or recovery.
-        Any <literal>%r</> is replaced by the name of the file containing the
-        last valid restart point, like in <xref linkend="archive-cleanup-command">.
-       </para>
-       <para>
-        If the command returns a non-zero exit status then a WARNING log
-        message will be written and the database will proceed to start up
-        anyway.  An exception is that if the command was terminated by a
-        signal, the database will not proceed with startup.
+        Refer to <xref linkend="guc-recovery-end-command"> for detailed
+        description.
        </para>
       </listitem>
      </varlistentry>
@@ -153,12 +92,8 @@ restore_command = 'copy "C:\\server\\archivedir\\%f" "%p"'  # Windows
       </indexterm>
       <listitem>
        <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.
+        Refer to <xref linkend="guc-recovery-target-name"> for detailed
+        description.
        </para>
       </listitem>
      </varlistentry>
@@ -172,14 +107,8 @@ restore_command = 'copy "C:\\server\\archivedir\\%f" "%p"'  # Windows
       </indexterm>
       <listitem>
        <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">.
+        Refer to <xref linkend="guc-recovery-target-time"> for detailed
+        description.
        </para>
       </listitem>
      </varlistentry>
@@ -191,18 +120,7 @@ restore_command = 'copy "C:\\server\\archivedir\\%f" "%p"'  # Windows
       </indexterm>
       <listitem>
        <para>
-        This parameter specifies the transaction ID up to which recovery
-        will proceed. Keep in mind
-        that while transaction IDs are assigned sequentially at transaction
-        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">.
+        Refer to <xref linkend="guc-recovery-target-xid"> for detailed description.
        </para>
       </listitem>
      </varlistentry>
@@ -217,14 +135,8 @@ restore_command = 'copy "C:\\server\\archivedir\\%f" "%p"'  # Windows
       </indexterm>
       <listitem>
        <para>
-        Specifies whether we stop just after the specified recovery target
-        (<literal>true</literal>), or just before the recovery target
-        (<literal>false</literal>).
-        Applies to both <xref linkend="recovery-target-time">
-        and <xref linkend="recovery-target-xid">, whichever one is
-        specified for this recovery.  This indicates whether transactions
-        having exactly the target commit time or ID, respectively, will
-        be included in the recovery.  Default is <literal>true</>.
+        Refer to <xref linkend="guc-recovery-target-inclusive"> for detailed
+        description.
        </para>
       </listitem>
      </varlistentry>
@@ -239,14 +151,7 @@ restore_command = 'copy "C:\\server\\archivedir\\%f" "%p"'  # Windows
       </indexterm>
       <listitem>
        <para>
-        Specifies recovering into a particular timeline.  The default is
-        to recover along the same timeline that was current when the
-        base backup was taken. Setting this to <literal>latest</> recovers
-        to the latest timeline found in the archive, which is useful in
-        a standby server. Other than that you only need to set this parameter
-        in complex re-recovery situations, where you need to return to
-        a state that itself was reached after a point-in-time recovery.
-        See <xref linkend="backup-timelines"> for discussion.
+        Refer to <xref linkend="guc-recovery-target-timeline"> for more details.
        </para>
       </listitem>
      </varlistentry>
@@ -261,21 +166,7 @@ restore_command = 'copy "C:\\server\\archivedir\\%f" "%p"'  # Windows
       </indexterm>
       <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
-        <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
-        recovery target settings to a later target and restart to
-        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.
+        Refer to <xref linkend="guc-pause-at-recovery-target"> for more details.
        </para>
       </listitem>
      </varlistentry>
@@ -295,13 +186,7 @@ restore_command = 'copy "C:\\server\\archivedir\\%f" "%p"'  # Windows
         </indexterm>
         <listitem>
          <para>
-          Specifies whether to start the <productname>PostgreSQL</> server as
-          a standby. If this parameter is <literal>on</>, the server will
-          not stop recovery when the end of archived WAL is reached, but
-          will keep trying to continue recovery by fetching new WAL segments
-          using <varname>restore_command</>
-          and/or by connecting to the primary server as specified by the
-          <varname>primary_conninfo</> setting.
+          Refer to <xref linkend="guc-standby-mode"> for more details.
          </para>
         </listitem>
        </varlistentry>
@@ -312,32 +197,7 @@ restore_command = 'copy "C:\\server\\archivedir\\%f" "%p"'  # Windows
         </indexterm>
         <listitem>
          <para>
-          Specifies a connection string to be used for the standby server
-          to connect with the primary. This string is in the format
-          accepted by the libpq <function>PQconnectdb</function> function,
-          described in <xref linkend="libpq-connect">. If any option is
-          unspecified in this string, then the corresponding environment
-          variable (see <xref linkend="libpq-envars">) is checked. If the
-          environment variable is not set either, then
-          defaults are used.
-         </para>
-         <para>
-          The connection string should specify the host name (or address)
-          of the primary server, as well as the port number if it is not
-          the same as the standby server's default.
-          Also specify a user name corresponding to a suitably-privileged role
-          on the primary (see
-          <xref linkend="streaming-replication-authentication">).
-          A password needs to be provided too, if the primary demands password
-          authentication.  It can be provided in the
-          <varname>primary_conninfo</varname> string, or in a separate
-          <filename>~/.pgpass</> file on the standby server (use
-          <literal>replication</> as the database name).
-          Do not specify a database name in the
-          <varname>primary_conninfo</varname> string.
-         </para>
-         <para>
-          This setting has no effect if <varname>standby_mode</> is <literal>off</>.
+          Refer to <xref linkend="guc-primary-conninfo"> for more details.
          </para>
         </listitem>
        </varlistentry>
@@ -348,10 +208,7 @@ restore_command = 'copy "C:\\server\\archivedir\\%f" "%p"'  # Windows
         </indexterm>
         <listitem>
          <para>
-          Specifies a trigger file whose presence ends recovery in the
-          standby.  Even if this value is not set, you can still promote
-          the standby using <command>pg_ctl promote</>.
-          This setting has no effect if <varname>standby_mode</> is <literal>off</>.
+          Refer to <xref linkend="guc-trigger-file"> for more details.
          </para>
         </listitem>
        </varlistentry>
diff --git a/doc/src/sgml/release-9.1.sgml b/doc/src/sgml/release-9.1.sgml
index 1143fdf..36546bb 100644
--- a/doc/src/sgml/release-9.1.sgml
+++ b/doc/src/sgml/release-9.1.sgml
@@ -3957,7 +3957,7 @@
       <listitem>
        <para>
         Add <filename>recovery.conf</> setting <link
-        linkend="pause-at-recovery-target"><varname>pause_at_recovery_target</></link>
+        linkend="guc-pause-at-recovery-target"><varname>pause_at_recovery_target</></link>
         to pause recovery at target (Simon Riggs)
        </para>
 
@@ -3977,7 +3977,7 @@
        <para>
         These named restore points can be specified as recovery
         targets using the new <filename>recovery.conf</> setting
-        <link linkend="recovery-target-name"><varname>recovery_target_name</></link>.
+        <link linkend="guc-recovery-target-name"><varname>recovery_target_name</></link>.
        </para>
       </listitem>
 
@@ -4009,8 +4009,7 @@
 
       <listitem>
        <para>
-        Allow <link
-        linkend="recovery-config"><filename>recovery.conf</></link>
+        Allow <filename>recovery.conf</>
         to use the same quoting behavior as <filename>postgresql.conf</>
         (Dimitri Fontaine)
        </para>
diff --git a/doc/src/sgml/release.sgml b/doc/src/sgml/release.sgml
index 2515329..de7f68d 100644
--- a/doc/src/sgml/release.sgml
+++ b/doc/src/sgml/release.sgml
@@ -5,7 +5,7 @@ Typical markup:
 
 &<>                             use & escapes
 PostgreSQL                      <productname>
-postgresql.conf, pg_hba.conf,
+postgresql.conf, pg_hba.conf
         recovery.conf           <filename>
 [A-Z][A-Z_ ]+[A-Z_]             <command>, <literal>, <envar>
 [A-Za-z_][A-Za-z0-9_]+()        <function>
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index cf2f6e7..3671862 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -82,6 +82,20 @@ int			sync_method = DEFAULT_SYNC_METHOD;
 int			wal_level = WAL_LEVEL_MINIMAL;
 int			CommitDelay = 0;	/* precommit delay in microseconds */
 int			CommitSiblings = 5; /* # concurrent xacts needed to sleep */
+char	   *restore_command = NULL;
+char	   *archive_cleanup_command = NULL;
+char	   *recovery_end_command = NULL;
+bool		standby_mode = false;
+char	   *primary_conninfo = NULL;
+char	   *trigger_file = NULL;
+RecoveryTargetType	recovery_target = RECOVERY_TARGET_UNSET;
+TransactionId		recovery_target_xid = InvalidTransactionId;
+TimestampTz			recovery_target_time = 0;
+char	   *recovery_target_name = NULL;
+bool		recovery_target_inclusive = true;
+bool		pause_at_recovery_target = true;
+char	   *recovery_target_timeline_string = NULL;
+TimeLineID	recovery_target_timeline = 0;
 
 #ifdef WAL_DEBUG
 bool		XLOG_DEBUG = false;
@@ -194,23 +208,8 @@ bool InArchiveRecovery = false;
 /* Was the last xlog file restored from archive, or local? */
 static bool restoredFromArchive = false;
 
-/* options 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 bool recoveryPauseAtTarget = true;
-static TransactionId recoveryTargetXid;
-static TimestampTz recoveryTargetTime;
-static char *recoveryTargetName;
-
-/* options taken from recovery.conf for XLOG streaming */
-bool StandbyMode = false;
-static char *PrimaryConnInfo = NULL;
-static char *TriggerFile = NULL;
-
 /* if recoveryStopsHere returns true, it saves actual stop xid/time/name here */
+static RecoveryTargetType recoveryStopTarget;
 static TransactionId recoveryStopXid;
 static TimestampTz recoveryStopTime;
 static char recoveryStopName[MAXFNAMELEN];
@@ -407,12 +406,6 @@ typedef struct XLogCtlData
 	TimeLineID	ThisTimeLineID;
 
 	/*
-	 * 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.
 	 */
@@ -3222,7 +3215,7 @@ ReadRecord(XLogReaderState *xlogreader, XLogRecPtr RecPtr, int emode,
 			/*
 			 * We only end up here without a message when XLogPageRead() failed
 			 * - in that case we already logged something.
-			 * In StandbyMode that only happens if we have been triggered, so
+			 * In standby_mode that only happens if we have been triggered, so
 			 * we shouldn't loop anymore in that case.
 			 */
 			if (errormsg)
@@ -3257,7 +3250,7 @@ ReadRecord(XLogReaderState *xlogreader, XLogRecPtr RecPtr, int emode,
 			record = NULL;
 			continue;
 		}
-	} while (StandbyMode && record == NULL && !CheckForStandbyTrigger());
+	} while (standby_mode && record == NULL && !CheckForStandbyTrigger());
 
 	return record;
 }
@@ -4006,21 +3999,18 @@ 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.
- *
- * The file is parsed using the main configuration parser.
+ * Check to see if there is a recovery trigger file (recovery.trigger).
+ * If so, validate recovery parameters and determine recovery target timeline.
  */
 static void
 readRecoveryCommandFile(void)
 {
-	FILE	   *fd;
-	TimeLineID	rtli = 0;
-	bool		rtliGiven = false;
+	FILE *fd;
 	ConfigVariable *item,
-			   *head = NULL,
-			   *tail = NULL;
+		*head = NULL,
+		*tail = NULL;
 
+	/* Check the presence of recovery command file */
 	fd = AllocateFile(RECOVERY_COMMAND_FILE, "r");
 	if (fd == NULL)
 	{
@@ -4040,72 +4030,63 @@ readRecoveryCommandFile(void)
 
 	FreeFile(fd);
 
+	/*
+	 * Parse each item in recovery command file and set the related GUC
+	 * parameters in consequence. Priority is given to recovery command
+	 * file if parameters are already set in postgresql.conf.
+	 */
 	for (item = head; item; item = item->next)
 	{
 		if (strcmp(item->name, "restore_command") == 0)
 		{
-			recoveryRestoreCommand = pstrdup(item->value);
+			SetConfigOption("restore_command",
+							pstrdup(item->value), PGC_POSTMASTER, PGC_S_OVERRIDE);
 			ereport(DEBUG2,
 					(errmsg_internal("restore_command = '%s'",
-									 recoveryRestoreCommand)));
+									 restore_command)));
 		}
 		else if (strcmp(item->name, "recovery_end_command") == 0)
 		{
-			recoveryEndCommand = pstrdup(item->value);
+			SetConfigOption("recovery_end_command",
+							pstrdup(item->value), PGC_POSTMASTER, PGC_S_OVERRIDE);
 			ereport(DEBUG2,
 					(errmsg_internal("recovery_end_command = '%s'",
-									 recoveryEndCommand)));
+									 recovery_end_command)));
 		}
 		else if (strcmp(item->name, "archive_cleanup_command") == 0)
 		{
-			archiveCleanupCommand = pstrdup(item->value);
+			SetConfigOption("archive_cleanup_command",
+							pstrdup(item->value), PGC_POSTMASTER, PGC_S_OVERRIDE);
 			ereport(DEBUG2,
 					(errmsg_internal("archive_cleanup_command = '%s'",
-									 archiveCleanupCommand)));
+									 archive_cleanup_command)));
 		}
 		else if (strcmp(item->name, "pause_at_recovery_target") == 0)
 		{
-			if (!parse_bool(item->value, &recoveryPauseAtTarget))
-				ereport(ERROR,
-						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-						 errmsg("parameter \"%s\" requires a Boolean value", "pause_at_recovery_target")));
+			SetConfigOption("pause_at_recovery_target",
+							pstrdup(item->value), PGC_POSTMASTER, PGC_S_OVERRIDE);
 			ereport(DEBUG2,
 					(errmsg_internal("pause_at_recovery_target = '%s'",
-									 item->value)));
+									 pause_at_recovery_target ? "true" : "false")));
 		}
 		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,
-							(errmsg("recovery_target_timeline is not a valid number: \"%s\"",
-									item->value)));
-			}
-			if (rtli)
+			SetConfigOption("recovery_target_timeline",
+							pstrdup(item->value), PGC_POSTMASTER, PGC_S_OVERRIDE);
+			if (strcmp(recovery_target_timeline_string, "") != 0)
 				ereport(DEBUG2,
-				   (errmsg_internal("recovery_target_timeline = %u", rtli)));
-			else
-				ereport(DEBUG2,
-					 (errmsg_internal("recovery_target_timeline = latest")));
+						(errmsg_internal("recovery_target_timeline = %u",
+										 recovery_target_timeline)));
+			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,
-				 (errmsg("recovery_target_xid is not a valid number: \"%s\"",
-						 item->value)));
+			SetConfigOption("recovery_target_xid",
+							pstrdup(item->value), PGC_POSTMASTER, PGC_S_OVERRIDE);
 			ereport(DEBUG2,
 					(errmsg_internal("recovery_target_xid = %u",
-									 recoveryTargetXid)));
-			recoveryTarget = RECOVERY_TARGET_XID;
+									 recovery_target_xid)));
 		}
 		else if (strcmp(item->name, "recovery_target_time") == 0)
 		{
@@ -4113,22 +4094,15 @@ readRecoveryCommandFile(void)
 			 * if recovery_target_xid or recovery_target_name specified, then
 			 * this overrides recovery_target_time
 			 */
-			if (recoveryTarget == RECOVERY_TARGET_XID ||
-				recoveryTarget == RECOVERY_TARGET_NAME)
+			if (recovery_target == RECOVERY_TARGET_XID ||
+				recovery_target == RECOVERY_TARGET_NAME)
 				continue;
-			recoveryTarget = RECOVERY_TARGET_TIME;
 
-			/*
-			 * Convert the time string given by the user to TimestampTz form.
-			 */
-			recoveryTargetTime =
-				DatumGetTimestampTz(DirectFunctionCall3(timestamptz_in,
-												CStringGetDatum(item->value),
-												ObjectIdGetDatum(InvalidOid),
-														Int32GetDatum(-1)));
+			SetConfigOption("recovery_target_time",
+							pstrdup(item->value), PGC_POSTMASTER, PGC_S_OVERRIDE);
 			ereport(DEBUG2,
 					(errmsg_internal("recovery_target_time = '%s'",
-								   timestamptz_to_str(recoveryTargetTime))));
+									 timestamptz_to_str(recovery_target_time))));
 		}
 		else if (strcmp(item->name, "recovery_target_name") == 0)
 		{
@@ -4136,58 +4110,45 @@ readRecoveryCommandFile(void)
 			 * if recovery_target_xid specified, then this overrides
 			 * recovery_target_name
 			 */
-			if (recoveryTarget == RECOVERY_TARGET_XID)
+			if (recovery_target == RECOVERY_TARGET_XID)
 				continue;
-			recoveryTarget = RECOVERY_TARGET_NAME;
-
-			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)));
 
+			SetConfigOption("recovery_target_name",
+							pstrdup(item->value), PGC_POSTMASTER, PGC_S_OVERRIDE);
 			ereport(DEBUG2,
 					(errmsg_internal("recovery_target_name = '%s'",
-									 recoveryTargetName)));
+									 recovery_target_name)));
 		}
 		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")));
+			SetConfigOption("recovery_target_inclusive",
+							pstrdup(item->value), PGC_POSTMASTER, PGC_S_OVERRIDE);
 			ereport(DEBUG2,
 					(errmsg_internal("recovery_target_inclusive = %s",
-									 item->value)));
+									 recovery_target_inclusive ? "true" : "false")));
 		}
 		else if (strcmp(item->name, "standby_mode") == 0)
 		{
-			if (!parse_bool(item->value, &StandbyMode))
-				ereport(ERROR,
-						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-						 errmsg("parameter \"%s\" requires a Boolean value",
-								"standby_mode")));
+			SetConfigOption("standby_mode",
+							pstrdup(item->value), PGC_POSTMASTER, PGC_S_OVERRIDE);
 			ereport(DEBUG2,
 					(errmsg_internal("standby_mode = '%s'", item->value)));
 		}
 		else if (strcmp(item->name, "primary_conninfo") == 0)
 		{
-			PrimaryConnInfo = pstrdup(item->value);
+			SetConfigOption("primary_conninfo",
+							pstrdup(item->value), PGC_POSTMASTER, PGC_S_OVERRIDE);
 			ereport(DEBUG2,
 					(errmsg_internal("primary_conninfo = '%s'",
-									 PrimaryConnInfo)));
+									 primary_conninfo)));
 		}
 		else if (strcmp(item->name, "trigger_file") == 0)
 		{
-			TriggerFile = pstrdup(item->value);
+			SetConfigOption("trigger_file",
+							pstrdup(item->value), PGC_POSTMASTER, PGC_S_OVERRIDE);
 			ereport(DEBUG2,
 					(errmsg_internal("trigger_file = '%s'",
-									 TriggerFile)));
+									 trigger_file)));
 		}
 		else
 			ereport(FATAL,
@@ -4195,23 +4156,20 @@ readRecoveryCommandFile(void)
 							item->name)));
 	}
 
-	/*
-	 * Check for compulsory parameters
-	 */
-	if (StandbyMode)
+	/* Check for compulsory parameters */
+	if (standby_mode)
 	{
-		if (PrimaryConnInfo == NULL && recoveryRestoreCommand == NULL)
+		if (!restore_command[0] && !primary_conninfo[0])
 			ereport(WARNING,
-					(errmsg("recovery command file \"%s\" specified neither primary_conninfo nor restore_command",
-							RECOVERY_COMMAND_FILE),
+					(errmsg("Neither primary_conninfo nor restore_command specified"),
 					 errhint("The database server will regularly poll the pg_xlog subdirectory to check for files placed there.")));
 	}
 	else
 	{
-		if (recoveryRestoreCommand == NULL)
+		if (!restore_command[0])
 			ereport(FATAL,
-					(errmsg("recovery command file \"%s\" must specify restore_command when standby mode is not enabled",
-							RECOVERY_COMMAND_FILE)));
+					(errmsg("restore_command must be specified when "
+							"standby_mode is not enabled")));
 	}
 
 	/* Enable fetching from archive recovery area */
@@ -4223,16 +4181,17 @@ readRecoveryCommandFile(void)
 	 * command and set InArchiveRecovery, because we need to fetch timeline
 	 * history files from the archive.
 	 */
-	if (rtliGiven)
+	if (strcmp(recovery_target_timeline_string, "") != 0)
 	{
-		if (rtli)
+		if (recovery_target_timeline)
 		{
 			/* Timeline 1 does not have a history file, all else should */
-			if (rtli != 1 && !existsTimeLineHistory(rtli))
+			if (recovery_target_timeline != 1 &&
+				!existsTimeLineHistory(recovery_target_timeline))
 				ereport(FATAL,
 						(errmsg("recovery target timeline %u does not exist",
-								rtli)));
-			recoveryTargetTLI = rtli;
+								recovery_target_timeline)));
+			recoveryTargetTLI = recovery_target_timeline;
 			recoveryTargetIsLatest = false;
 		}
 		else
@@ -4385,7 +4344,7 @@ recoveryStopsHere(XLogRecord *record, bool *includeThis)
 		return false;
 
 	/* Do we have a PITR target at all? */
-	if (recoveryTarget == RECOVERY_TARGET_UNSET)
+	if (recovery_target == RECOVERY_TARGET_UNSET)
 	{
 		/*
 		 * Save timestamp of latest transaction commit/abort if this is a
@@ -4396,7 +4355,7 @@ recoveryStopsHere(XLogRecord *record, bool *includeThis)
 		return false;
 	}
 
-	if (recoveryTarget == RECOVERY_TARGET_XID)
+	if (recovery_target == RECOVERY_TARGET_XID)
 	{
 		/*
 		 * There can be only one transaction end record with this exact
@@ -4407,17 +4366,17 @@ recoveryStopsHere(XLogRecord *record, bool *includeThis)
 		 * they complete. A higher numbered xid will complete before you about
 		 * 50% of the time...
 		 */
-		stopsHere = (record->xl_xid == recoveryTargetXid);
+		stopsHere = (record->xl_xid == recovery_target_xid);
 		if (stopsHere)
-			*includeThis = recoveryTargetInclusive;
+			*includeThis = recovery_target_inclusive;
 	}
-	else if (recoveryTarget == RECOVERY_TARGET_NAME)
+	else if (recovery_target == RECOVERY_TARGET_NAME)
 	{
 		/*
 		 * There can be many restore points that share the same name, so we
 		 * stop at the first one
 		 */
-		stopsHere = (strcmp(recordRPName, recoveryTargetName) == 0);
+		stopsHere = (strcmp(recordRPName, recovery_target_name) == 0);
 
 		/*
 		 * Ignore recoveryTargetInclusive because this is not a transaction
@@ -4432,16 +4391,17 @@ recoveryStopsHere(XLogRecord *record, bool *includeThis)
 		 * we stop after the last one, if we are inclusive, or stop at the
 		 * first one if we are exclusive
 		 */
-		if (recoveryTargetInclusive)
-			stopsHere = (recordXtime > recoveryTargetTime);
+		if (recovery_target_inclusive)
+			stopsHere = (recordXtime > recovery_target_time);
 		else
-			stopsHere = (recordXtime >= recoveryTargetTime);
+			stopsHere = (recordXtime >= recovery_target_time);
 		if (stopsHere)
 			*includeThis = false;
 	}
 
 	if (stopsHere)
 	{
+		recoveryStopTarget = recovery_target;
 		recoveryStopXid = record->xl_xid;
 		recoveryStopTime = recordXtime;
 		recoveryStopAfter = *includeThis;
@@ -4789,36 +4749,28 @@ StartupXLOG(void)
 	recoveryTargetTLI = ControlFile->checkPointCopy.ThisTimeLineID;
 
 	/*
-	 * Check for recovery control file, and if so set up state for offline
-	 * recovery
+	 * Check for recovery trigger 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.
-	 */
-	strncpy(XLogCtl->archiveCleanupCommand,
-			archiveCleanupCommand ? archiveCleanupCommand : "",
-			sizeof(XLogCtl->archiveCleanupCommand));
-
 	if (InArchiveRecovery)
 	{
-		if (StandbyMode)
+		if (standby_mode)
 			ereport(LOG,
 					(errmsg("entering standby mode")));
-		else if (recoveryTarget == RECOVERY_TARGET_XID)
+		else if (recovery_target == RECOVERY_TARGET_XID)
 			ereport(LOG,
 					(errmsg("starting point-in-time recovery to XID %u",
-							recoveryTargetXid)));
-		else if (recoveryTarget == RECOVERY_TARGET_TIME)
+							recovery_target_xid)));
+		else if (recovery_target == RECOVERY_TARGET_TIME)
 			ereport(LOG,
 					(errmsg("starting point-in-time recovery to %s",
-							timestamptz_to_str(recoveryTargetTime))));
-		else if (recoveryTarget == RECOVERY_TARGET_NAME)
+							timestamptz_to_str(recovery_target_time))));
+		else if (recovery_target == RECOVERY_TARGET_NAME)
 			ereport(LOG,
 					(errmsg("starting point-in-time recovery to \"%s\"",
-							recoveryTargetName)));
+							recovery_target_name)));
 		else
 			ereport(LOG,
 					(errmsg("starting archive recovery")));
@@ -4828,7 +4780,7 @@ StartupXLOG(void)
 	 * Take ownership of the wakeup latch if we're going to sleep during
 	 * recovery.
 	 */
-	if (StandbyMode)
+	if (standby_mode)
 		OwnLatch(&XLogCtl->recoveryWakeupLatch);
 
 	/* Set up XLOG reader facility */
@@ -4897,7 +4849,7 @@ StartupXLOG(void)
 					(errmsg("checkpoint record is at %X/%X",
 							(uint32) (checkPointLoc >> 32), (uint32) checkPointLoc)));
 		}
-		else if (StandbyMode)
+		else if (standby_mode)
 		{
 			/*
 			 * The last valid checkpoint record required for a streaming
@@ -5030,7 +4982,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.trigger file,
 	 * then assume no recovery needed.
 	 */
 	if (checkPoint.redo < RecPtr)
@@ -5044,7 +4996,7 @@ StartupXLOG(void)
 		InRecovery = true;
 	else if (InArchiveRecovery)
 	{
-		/* force recovery due to presence of recovery.conf */
+		/* force recovery due to presence of recovery.trigger */
 		InRecovery = true;
 	}
 
@@ -5357,7 +5309,7 @@ StartupXLOG(void)
 				 */
 				if (recoveryStopsHere(record, &recoveryApply))
 				{
-					if (recoveryPauseAtTarget)
+					if (pause_at_recovery_target)
 					{
 						SetRecoveryPause(true);
 						recoveryPausesHere();
@@ -5507,7 +5459,7 @@ StartupXLOG(void)
 	 * We don't need the latch anymore. It's not strictly necessary to disown
 	 * it, but let's do it for the sake of tidiness.
 	 */
-	if (StandbyMode)
+	if (standby_mode)
 		DisownLatch(&XLogCtl->recoveryWakeupLatch);
 
 	/*
@@ -5515,7 +5467,7 @@ StartupXLOG(void)
 	 * recovery to force fetching the files (which would be required at end of
 	 * recovery, e.g., timeline history file) from archive or pg_xlog.
 	 */
-	StandbyMode = false;
+	SetConfigOption("standby_mode", "false", PGC_POSTMASTER, PGC_S_OVERRIDE);
 
 	/*
 	 * Re-fetch the last valid or last applied record, so we can identify the
@@ -5594,17 +5546,17 @@ StartupXLOG(void)
 		 * Create a comment for the history file to explain why and where
 		 * timeline changed.
 		 */
-		if (recoveryTarget == RECOVERY_TARGET_XID)
+		if (recovery_target == RECOVERY_TARGET_XID)
 			snprintf(reason, sizeof(reason),
 					 "%s transaction %u",
 					 recoveryStopAfter ? "after" : "before",
 					 recoveryStopXid);
-		else if (recoveryTarget == RECOVERY_TARGET_TIME)
+		else if (recovery_target == RECOVERY_TARGET_TIME)
 			snprintf(reason, sizeof(reason),
 					 "%s %s\n",
 					 recoveryStopAfter ? "after" : "before",
 					 timestamptz_to_str(recoveryStopTime));
-		else if (recoveryTarget == RECOVERY_TARGET_NAME)
+		else if (recovery_target == RECOVERY_TARGET_NAME)
 			snprintf(reason, sizeof(reason),
 					 "at restore point \"%s\"",
 					 recoveryStopName);
@@ -5738,8 +5690,8 @@ StartupXLOG(void)
 		/*
 		 * And finally, execute the recovery_end_command, if any.
 		 */
-		if (recoveryEndCommand)
-			ExecuteRecoveryCommand(recoveryEndCommand,
+		if (recovery_end_command[0])
+			ExecuteRecoveryCommand(recovery_end_command,
 								   "recovery_end_command",
 								   true);
 	}
@@ -6592,7 +6544,7 @@ CreateCheckPoint(int flags)
 		XLogRecPtr	curInsert;
 
 		INSERT_RECPTR(curInsert, Insert, Insert->curridx);
-		if (curInsert == ControlFile->checkPoint + 
+		if (curInsert == ControlFile->checkPoint +
 			MAXALIGN(SizeOfXLogRecord + sizeof(CheckPoint)) &&
 			ControlFile->checkPoint == ControlFile->checkPointCopy.redo)
 		{
@@ -7169,8 +7121,8 @@ CreateRestartPoint(int flags)
 	/*
 	 * Finally, execute archive_cleanup_command, if any.
 	 */
-	if (XLogCtl->archiveCleanupCommand[0])
-		ExecuteRecoveryCommand(XLogCtl->archiveCleanupCommand,
+	if (archive_cleanup_command[0])
+		ExecuteRecoveryCommand(archive_cleanup_command,
 							   "archive_cleanup_command",
 							   false);
 
@@ -8886,7 +8838,7 @@ XLogPageRead(XLogReaderState *xlogreader, XLogRecPtr targetPagePtr, int reqLen,
 		 * Request a restartpoint if we've replayed too much xlog since the
 		 * last one.
 		 */
-		if (StandbyMode && bgwriterLaunched)
+		if (standby_mode && bgwriterLaunched)
 		{
 			if (XLogCheckpointNeeded(readSegNo))
 			{
@@ -8909,7 +8861,7 @@ retry:
 		(readSource == XLOG_FROM_STREAM &&
 		 receivedUpto < targetPagePtr + reqLen))
 	{
-		if (StandbyMode)
+		if (standby_mode)
 		{
 			if (!WaitForWALToBecomeAvailable(targetPagePtr + reqLen,
 											 private->randAccess,
@@ -8998,7 +8950,7 @@ next_record_is_invalid:
 	readSource = 0;
 
 	/* In standby-mode, keep trying */
-	if (StandbyMode)
+	if (standby_mode)
 		goto retry;
 	else
 		return -1;
@@ -9105,7 +9057,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 (primary_conninfo[0])
 					{
 						XLogRecPtr ptr;
 						TimeLineID tli;
@@ -9126,7 +9078,7 @@ WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess,
 									 tli, curFileTLI);
 						}
 						curFileTLI = tli;
-						RequestXLogStreaming(curFileTLI, ptr, PrimaryConnInfo);
+						RequestXLogStreaming(curFileTLI, ptr);
 					}
 					/*
 					 * Move to XLOG_FROM_STREAM state in either case. We'll get
@@ -9412,14 +9364,14 @@ CheckForStandbyTrigger(void)
 		return true;
 	}
 
-	if (TriggerFile == NULL)
+	if (!trigger_file[0])
 		return false;
 
-	if (stat(TriggerFile, &stat_buf) == 0)
+	if (stat(trigger_file, &stat_buf) == 0)
 	{
 		ereport(LOG,
-				(errmsg("trigger file found: %s", TriggerFile)));
-		unlink(TriggerFile);
+				(errmsg("trigger file found: %s", trigger_file)));
+		unlink(trigger_file);
 		triggered = true;
 		return true;
 	}
diff --git a/src/backend/access/transam/xlogarchive.c b/src/backend/access/transam/xlogarchive.c
index 52922da..20275c8 100644
--- a/src/backend/access/transam/xlogarchive.c
+++ b/src/backend/access/transam/xlogarchive.c
@@ -67,7 +67,7 @@ RestoreArchivedFile(char *path, const char *xlogfname,
 	TimeLineID	restartTli;
 
 	/* In standby mode, restore_command might not be supplied */
-	if (recoveryRestoreCommand == NULL)
+	if (restore_command == NULL)
 		goto not_available;
 
 	/*
@@ -150,7 +150,7 @@ RestoreArchivedFile(char *path, const char *xlogfname,
 	endp = xlogRestoreCmd + MAXPGPATH - 1;
 	*endp = '\0';
 
-	for (sp = recoveryRestoreCommand; *sp; sp++)
+	for (sp = restore_command; *sp; sp++)
 	{
 		if (*sp == '%')
 		{
@@ -236,7 +236,7 @@ RestoreArchivedFile(char *path, const char *xlogfname,
 				 * incorrectly conclude we've reached the end of WAL and we're
 				 * done recovering ...
 				 */
-				if (StandbyMode && stat_buf.st_size < expectedSize)
+				if (standby_mode && stat_buf.st_size < expectedSize)
 					elevel = DEBUG1;
 				else
 					elevel = FATAL;
diff --git a/src/backend/commands/extension.c b/src/backend/commands/extension.c
index c02101f..9babd74 100644
--- a/src/backend/commands/extension.c
+++ b/src/backend/commands/extension.c
@@ -9,7 +9,7 @@
  * dependent objects can be associated with it.  An extension is created by
  * populating the pg_extension catalog from a "control" file.
  * The extension control file is parsed with the same parser we use for
- * postgresql.conf and recovery.conf.  An extension also has an installation
+ * postgresql.conf.  An extension also has an installation
  * script file, containing SQL commands to create the extension's objects.
  *
  * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index 7359297..325f6de 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -185,7 +185,6 @@ DisableWalRcvImmediateExit(void)
 void
 WalReceiverMain(void)
 {
-	char		conninfo[MAXCONNINFO];
 	XLogRecPtr	startpoint;
 	TimeLineID	startpointTLI;
 	TimeLineID	primaryTLI;
@@ -239,7 +238,6 @@ WalReceiverMain(void)
 	walrcv->walRcvState = WALRCV_STREAMING;
 
 	/* Fetch information required to start streaming */
-	strlcpy(conninfo, (char *) walrcv->conninfo, MAXCONNINFO);
 	startpoint = walrcv->receiveStart;
 	startpointTLI = walrcv->receiveStartTLI;
 
@@ -306,7 +304,7 @@ WalReceiverMain(void)
 
 	/* Establish the connection to the primary for XLOG streaming */
 	EnableWalRcvImmediateExit();
-	walrcv_connect(conninfo);
+	walrcv_connect(primary_conninfo);
 	DisableWalRcvImmediateExit();
 
 	first_stream = true;
@@ -404,8 +402,21 @@ WalReceiverMain(void)
 
 				if (got_SIGHUP)
 				{
+					char    *conninfo = pstrdup(primary_conninfo);
+
 					got_SIGHUP = false;
 					ProcessConfigFile(PGC_SIGHUP);
+
+					/*
+					 * If primary_conninfo has been changed while walreceiver is running,
+					 * shut down walreceiver so that new walreceiver is started and
+					 * it initiates replication with new primary_conninfo.
+					 */
+					if (strcmp(conninfo, primary_conninfo) != 0)
+						ereport(FATAL,
+								(errcode(ERRCODE_ADMIN_SHUTDOWN),
+								 errmsg("terminating walreceiver process because primary_conninfo was changed")));
+					pfree(conninfo);
 				}
 
 				/* Wait a while for data to arrive */
diff --git a/src/backend/replication/walreceiverfuncs.c b/src/backend/replication/walreceiverfuncs.c
index d414808..d6a5e06 100644
--- a/src/backend/replication/walreceiverfuncs.c
+++ b/src/backend/replication/walreceiverfuncs.c
@@ -219,11 +219,10 @@ ShutdownWalRcv(void)
 /*
  * Request postmaster to start walreceiver.
  *
- * recptr indicates the position where streaming should begin, and conninfo
- * is a libpq connection string to use.
+ * recptr indicates the position where streaming should begin.
  */
 void
-RequestXLogStreaming(TimeLineID tli, XLogRecPtr recptr, const char *conninfo)
+RequestXLogStreaming(TimeLineID tli, XLogRecPtr recptr)
 {
 	/* use volatile pointer to prevent code rearrangement */
 	volatile WalRcvData *walrcv = WalRcv;
@@ -245,11 +244,6 @@ RequestXLogStreaming(TimeLineID tli, XLogRecPtr recptr, const char *conninfo)
 	Assert(walrcv->walRcvState == WALRCV_STOPPED ||
 		   walrcv->walRcvState == WALRCV_WAITING);
 
-	if (conninfo != NULL)
-		strlcpy((char *) walrcv->conninfo, conninfo, MAXCONNINFO);
-	else
-		walrcv->conninfo[0] = '\0';
-
 	if (walrcv->walRcvState == WALRCV_STOPPED)
 	{
 		launch = true;
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 6128694..f49b8fe 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -30,6 +30,7 @@
 #include "access/transam.h"
 #include "access/twophase.h"
 #include "access/xact.h"
+#include "access/xlog_internal.h"
 #include "catalog/namespace.h"
 #include "commands/async.h"
 #include "commands/prepare.h"
@@ -196,6 +197,14 @@ static bool check_application_name(char **newval, void **extra, GucSource source
 static void assign_application_name(const char *newval, void *extra);
 static const char *show_unix_socket_permissions(void);
 static const char *show_log_file_mode(void);
+static bool check_recovery_target_xid(char **newval, void **extra, GucSource source);
+static void assign_recovery_target_xid(const char *newval, void *extra);
+static bool check_recovery_target_name(char **newval, void **extra, GucSource source);
+static void assign_recovery_target_name(const char *newval, void *extra);
+static bool check_recovery_target_time(char **newval, void **extra, GucSource source);
+static void assign_recovery_target_time(const char *newval, void *extra);
+static bool check_recovery_target_timeline(char **newval, void **extra, GucSource source);
+static void assign_recovery_target_timeline(const char *newval, void *extra);
 
 static char *config_enum_get_options(struct config_enum * record,
 						const char *prefix, const char *suffix,
@@ -468,6 +477,8 @@ static int	wal_block_size;
 static int	wal_segment_size;
 static bool integer_datetimes;
 static int	effective_io_concurrency;
+static char *recovery_target_xid_string;
+static char *recovery_target_time_string;
 
 /* should be static, but commands/variable.c needs to get at this */
 char	   *role_string;
@@ -547,6 +558,10 @@ const char *const config_group_names[] =
 	gettext_noop("Write-Ahead Log / Checkpoints"),
 	/* WAL_ARCHIVING */
 	gettext_noop("Write-Ahead Log / Archiving"),
+	/* WAL_ARCHIVE_RECOVERY */
+	gettext_noop("Write-Ahead Log / Archive Recovery"),
+	/* WAL_RECOVERY_TARGET */
+	gettext_noop("Write-Ahead Log / Recovery Target"),
 	/* REPLICATION */
 	gettext_noop("Replication"),
 	/* REPLICATION_SENDING */
@@ -1375,6 +1390,36 @@ static struct config_bool ConfigureNamesBool[] =
 	},
 
 	{
+		{"recovery_target_inclusive", PGC_SIGHUP, WAL_RECOVERY_TARGET,
+			gettext_noop("Sets whether to include or exclude transaction with recovery target."),
+			NULL
+		},
+		&recovery_target_inclusive,
+		true,
+		NULL, NULL, NULL
+	},
+
+	{
+		{"pause_at_recovery_target", PGC_SIGHUP, WAL_RECOVERY_TARGET,
+			gettext_noop("Sets whether recovery should pause when the recovery target is reached."),
+			NULL
+		},
+		&pause_at_recovery_target,
+		true,
+		NULL, NULL, NULL
+	},
+
+	{
+		{"standby_mode", PGC_POSTMASTER, REPLICATION_STANDBY,
+			gettext_noop("Sets whether to start the server as a standby."),
+			NULL
+		},
+		&standby_mode,
+		false,
+		NULL, NULL, NULL
+	},
+
+	{
 		{"hot_standby", PGC_POSTMASTER, REPLICATION_STANDBY,
 			gettext_noop("Allows connections and queries during recovery."),
 			NULL
@@ -2543,6 +2588,97 @@ static struct config_string ConfigureNamesString[] =
 	},
 
 	{
+		{"restore_command", PGC_SIGHUP, WAL_ARCHIVE_RECOVERY,
+			gettext_noop("Sets the shell command that will retrieve an archived WAL file."),
+			NULL
+		},
+		&restore_command,
+		"",
+		NULL, NULL, NULL
+	},
+
+	{
+		{"archive_cleanup_command", PGC_SIGHUP, WAL_ARCHIVE_RECOVERY,
+			gettext_noop("Sets the shell command that will be executed at every restartpoint."),
+			NULL
+		},
+		&archive_cleanup_command,
+		"",
+		NULL, NULL, NULL
+	},
+
+	{
+		{"recovery_end_command", PGC_SIGHUP, WAL_ARCHIVE_RECOVERY,
+			gettext_noop("Sets the shell command that will be executed once only at the end of recovery."),
+			NULL
+		},
+		&recovery_end_command,
+		"",
+		NULL, NULL, NULL
+	},
+
+	{
+		{"recovery_target_xid", PGC_SIGHUP, WAL_RECOVERY_TARGET,
+			gettext_noop("Sets the transaction ID up to which recovery will proceed."),
+			NULL
+		},
+		&recovery_target_xid_string,
+		"",
+		check_recovery_target_xid, assign_recovery_target_xid, NULL
+	},
+
+	{
+		{"recovery_target_name", PGC_SIGHUP, WAL_RECOVERY_TARGET,
+			gettext_noop("Sets the named restore point."),
+			NULL
+		},
+		&recovery_target_name,
+		"",
+		check_recovery_target_name, assign_recovery_target_name, NULL
+	},
+
+	{
+		{"recovery_target_time", PGC_SIGHUP, WAL_RECOVERY_TARGET,
+			gettext_noop("Sets the time stamp up to which recovery will proceed."),
+			NULL
+		},
+		&recovery_target_time_string,
+		"",
+		check_recovery_target_time, assign_recovery_target_time, NULL
+	},
+
+	{
+		{"recovery_target_timeline", PGC_POSTMASTER, WAL_RECOVERY_TARGET,
+			gettext_noop("Sets recoverying into a particular timeline."),
+			NULL
+		},
+		&recovery_target_timeline_string,
+		"",
+		check_recovery_target_timeline, assign_recovery_target_timeline, NULL
+	},
+
+	{
+		{"primary_conninfo", PGC_SIGHUP, REPLICATION_STANDBY,
+			gettext_noop("Sets the connection string to be used to connect with the primary."),
+			NULL,
+			GUC_SUPERUSER_ONLY
+		},
+		&primary_conninfo,
+		"",
+		NULL, NULL, NULL
+	},
+
+	{
+		{"trigger_file", PGC_SIGHUP, REPLICATION_STANDBY,
+			gettext_noop("Sets the trigger file whose presence ends recovery in the standby."),
+			NULL
+		},
+		&trigger_file,
+		"",
+		NULL, NULL, NULL
+	},
+
+	{
 		{"client_encoding", PGC_USERSET, CLIENT_CONN_LOCALE,
 			gettext_noop("Sets the client's character set encoding."),
 			NULL,
@@ -8760,4 +8896,158 @@ show_log_file_mode(void)
 	return buf;
 }
 
+static bool
+check_recovery_target_xid(char **newval, void **extra, GucSource source)
+{
+	TransactionId   xid;
+	TransactionId   *myextra;
+
+	if (strcmp(*newval, "") == 0)
+		xid = InvalidTransactionId;
+	else
+	{
+		errno = 0;
+		xid = (TransactionId) strtoul(*newval, NULL, 0);
+		if (errno == EINVAL || errno == ERANGE)
+		{
+			GUC_check_errdetail("recovery_target_xid is not a valid number: \"%s\"",
+								*newval);
+			return false;
+		}
+	}
+
+	myextra = (TransactionId *) guc_malloc(ERROR, sizeof(TransactionId));
+	*myextra = xid;
+	*extra = (void *) myextra;
+
+	return true;
+}
+
+static void
+assign_recovery_target_xid(const char *newval, void *extra)
+{
+	recovery_target_xid = *((TransactionId *) extra);
+
+	if (recovery_target_xid != InvalidTransactionId)
+		recovery_target = RECOVERY_TARGET_XID;
+	else if (recovery_target_name[0])
+		recovery_target = RECOVERY_TARGET_NAME;
+	else if (recovery_target_time != 0)
+		recovery_target = RECOVERY_TARGET_TIME;
+	else
+		recovery_target = RECOVERY_TARGET_UNSET;
+}
+
+static bool
+check_recovery_target_name(char **newval, void **extra, GucSource source)
+{
+	if (strlen(*newval) >= MAXFNAMELEN)
+	{
+		GUC_check_errdetail("\"recovery_target_name\" is too long (maximum %d characters)",
+							MAXFNAMELEN - 1);
+		return false;
+	}
+	return true;
+}
+
+static void
+assign_recovery_target_name(const char *newval, void *extra)
+{
+	if (recovery_target_xid != InvalidTransactionId)
+		recovery_target = RECOVERY_TARGET_XID;
+	else if (newval[0])
+		recovery_target = RECOVERY_TARGET_NAME;
+	else if (recovery_target_time != 0)
+		recovery_target = RECOVERY_TARGET_TIME;
+	else
+		recovery_target = RECOVERY_TARGET_UNSET;
+}
+
+static bool
+check_recovery_target_time(char **newval, void **extra, GucSource source)
+{
+	TimestampTz     time;
+	TimestampTz     *myextra;
+	MemoryContext oldcontext = CurrentMemoryContext;
+
+	PG_TRY();
+	{
+		time = (strcmp(*newval, "") == 0) ?
+			0 :
+			DatumGetTimestampTz(DirectFunctionCall3(timestamptz_in,
+													CStringGetDatum(*newval),
+													ObjectIdGetDatum(InvalidOid),
+													Int32GetDatum(-1)));
+	}
+	PG_CATCH();
+	{
+		ErrorData  *edata;
+
+		/* Save error info */
+		MemoryContextSwitchTo(oldcontext);
+		edata = CopyErrorData();
+		FlushErrorState();
+
+		/* Pass the error message */
+		GUC_check_errdetail("%s", edata->message);
+		FreeErrorData(edata);
+		return false;
+	}
+	PG_END_TRY();
+
+	myextra = (TimestampTz *) guc_malloc(ERROR, sizeof(TimestampTz));
+	*myextra = time;
+	*extra = (void *) myextra;
+
+	return true;
+}
+
+static void
+assign_recovery_target_time(const char *newval, void *extra)
+{
+	recovery_target_time = *((TimestampTz *) extra);
+
+	if (recovery_target_xid != InvalidTransactionId)
+		recovery_target = RECOVERY_TARGET_XID;
+	else if (recovery_target_name[0])
+		recovery_target = RECOVERY_TARGET_NAME;
+	else if (recovery_target_time != 0)
+		recovery_target = RECOVERY_TARGET_TIME;
+	else
+		recovery_target = RECOVERY_TARGET_UNSET;
+}
+
+static bool
+check_recovery_target_timeline(char **newval, void **extra, GucSource source)
+{
+	TimeLineID	tli = 0;
+	TimeLineID	*myextra;
+
+	if (strcmp(*newval, "") == 0 || strcmp(*newval, "latest") == 0)
+		tli = 0;
+	else
+	{
+		errno = 0;
+		tli = (TimeLineID) strtoul(*newval, NULL, 0);
+		if (errno == EINVAL || errno == ERANGE)
+		{
+			GUC_check_errdetail("recovery_target_timeline is not a valid number: \"%s\"",
+								*newval);
+			return false;
+		}
+	}
+
+	myextra = (TimeLineID *) guc_malloc(ERROR, sizeof(TimeLineID));
+	*myextra = tli;
+	*extra = (void *) myextra;
+
+	return true;
+}
+
+static void
+assign_recovery_target_timeline(const char *newval, void *extra)
+{
+	recovery_target_timeline = *((TimeLineID *) extra);
+}
+
 #include "guc-file.c"
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
index 62aea2f..52a4e71 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -198,6 +198,23 @@
 #archive_timeout = 0		# force a logfile segment switch after this
 				# number of seconds; 0 disables
 
+# - Archive Recovery -
+#restore_command = ''		# command to use to restore an archived logfile segment
+				# placeholders: %p = path of file to restore
+				#               %f = file name only
+				# e.g. 'cp /mnt/server/archivedir/%f %p'
+#archive_cleanup_command = ''	# command to execute at every restartpoint
+#recovery_end_command = ''	# command to execute at completion of recovery
+
+# - Recovery Target -
+#recovery_target_xid = ''
+#recovery_target_name = ''		# e.g. 'daily backup 2011-01-26'
+#recovery_target_time = ''		# e.g. '2004-07-14 22:39:00 EST'
+#recovery_target_timeline = ''		# timeline ID or 'latest'
+					# (change requires restart)
+#recovery_target_inclusive = on
+#pause_at_recovery_target = on		# Pause recovery once target is reached
+
 
 #------------------------------------------------------------------------------
 # REPLICATION
@@ -240,6 +257,11 @@
 #wal_receiver_timeout = 60s		# time that receiver waits for
 					# communication from master
 					# in milliseconds; 0 disables
+#standby_mode = off			# "on" starts the server as a standby
+					# (change requires restart)
+#primary_conninfo = ''			# connection string to connect to the master
+					# e.g. 'host=localhost port=5432'
+#trigger_file = ''			# trigger file to promote the standby
 
 
 #------------------------------------------------------------------------------
diff --git a/src/bin/pg_ctl/pg_ctl.c b/src/bin/pg_ctl/pg_ctl.c
index e412d71..3a02481 100644
--- a/src/bin/pg_ctl/pg_ctl.c
+++ b/src/bin/pg_ctl/pg_ctl.c
@@ -928,7 +928,7 @@ do_stop(void)
 		/*
 		 * If backup_label exists, an online backup is running. Warn the user
 		 * that smart shutdown will wait for it to finish. However, if
-		 * recovery.conf is also present, we're recovering from an online
+		 * recovery.trigger is also present, we're recovering from an online
 		 * backup instead of performing one.
 		 */
 		if (shutdown_mode == SMART_MODE &&
@@ -1016,7 +1016,7 @@ do_restart(void)
 		/*
 		 * If backup_label exists, an online backup is running. Warn the user
 		 * that smart shutdown will wait for it to finish. However, if
-		 * recovery.conf is also present, we're recovering from an online
+		 * recovery.trigger is also present, we're recovering from an online
 		 * backup instead of performing one.
 		 */
 		if (shutdown_mode == SMART_MODE &&
@@ -1127,7 +1127,7 @@ do_promote(void)
 		exit(1);
 	}
 
-	/* If recovery.conf doesn't exist, the server is not in standby mode */
+	/* If recovery.trigger doesn't exist, the server is not in standby mode */
 	if (stat(recovery_file, &statbuf) != 0)
 	{
 		write_stderr(_("%s: cannot promote server; "
@@ -2270,7 +2270,7 @@ main(int argc, char **argv)
 		snprintf(postopts_file, MAXPGPATH, "%s/postmaster.opts", pg_data);
 		snprintf(pid_file, MAXPGPATH, "%s/postmaster.pid", pg_data);
 		snprintf(backup_file, MAXPGPATH, "%s/backup_label", pg_data);
-		snprintf(recovery_file, MAXPGPATH, "%s/recovery.conf", pg_data);
+		snprintf(recovery_file, MAXPGPATH, "%s/recovery.trigger", pg_data);
 		snprintf(promote_file, MAXPGPATH, "%s/promote", pg_data);
 	}
 
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index 72e3242..c831345 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -190,6 +190,20 @@ extern char *XLogArchiveCommand;
 extern bool EnableHotStandby;
 extern bool fullPageWrites;
 extern bool log_checkpoints;
+extern char *restore_command;
+extern char *archive_cleanup_command;
+extern char *recovery_end_command;
+extern bool standby_mode;
+extern char *primary_conninfo;
+extern char *trigger_file;
+extern RecoveryTargetType recovery_target;
+extern TransactionId recovery_target_xid;
+extern TimestampTz recovery_target_time;
+extern char *recovery_target_name;
+extern bool recovery_target_inclusive;
+extern bool pause_at_recovery_target;
+extern char *recovery_target_timeline_string;
+extern TimeLineID recovery_target_timeline;
 
 /* WAL levels */
 typedef enum WalLevel
diff --git a/src/include/replication/walreceiver.h b/src/include/replication/walreceiver.h
index 72878f8..d51d86f 100644
--- a/src/include/replication/walreceiver.h
+++ b/src/include/replication/walreceiver.h
@@ -149,7 +149,7 @@ extern void WalRcvShmemInit(void);
 extern void ShutdownWalRcv(void);
 extern bool WalRcvStreaming(void);
 extern bool WalRcvRunning(void);
-extern void RequestXLogStreaming(TimeLineID tli, XLogRecPtr recptr, const char *conninfo);
+extern void RequestXLogStreaming(TimeLineID tli, XLogRecPtr recptr);
 extern XLogRecPtr GetWalRcvWriteRecPtr(XLogRecPtr *latestChunkStart, TimeLineID *receiveTLI);
 extern int	GetReplicationApplyDelay(void);
 extern int	GetReplicationTransferLatency(void);
diff --git a/src/include/utils/guc_tables.h b/src/include/utils/guc_tables.h
index 7360ce3..a2d3281 100644
--- a/src/include/utils/guc_tables.h
+++ b/src/include/utils/guc_tables.h
@@ -68,6 +68,8 @@ enum config_group
 	WAL_SETTINGS,
 	WAL_CHECKPOINTS,
 	WAL_ARCHIVING,
+	WAL_ARCHIVE_RECOVERY,
+	WAL_RECOVERY_TARGET,
 	REPLICATION,
 	REPLICATION_SENDING,
 	REPLICATION_MASTER,
#16Robert Haas
robertmhaas@gmail.com
In reply to: Michael Paquier (#15)
Re: Request for vote to move forward with recovery.conf overhaul

On Sat, Jan 26, 2013 at 9:49 PM, Michael Paquier
<michael.paquier@gmail.com> wrote:

On Sun, Jan 27, 2013 at 7:14 AM, Phil Sorber <phil@omniti.com> wrote:

On Wed, Jan 23, 2013 at 6:36 AM, Michael Paquier
<michael.paquier@gmail.com> wrote:

On 2013/01/23, at 18:12, Simon Riggs <simon@2ndQuadrant.com> wrote:

On 23 January 2013 04:49, Michael Paquier <michael.paquier@gmail.com>
wrote:

- recovery.conf is removed (no backward compatibility in this version
of the
patch)

If you want to pursue that, you know where it leads. No, rebasing a
rejected patch doesn't help, its just relighting a fire that shouldn't
ever have been lit.

Pushing to do that out of order is just going to drain essential time
out of this CF from all of us.

No problem to support both. The only problem I see is if the same
parameter is defined in recovery.conf and postgresql.conf, is the priority
given to recovery.conf?

I would think that if someone created a recovery.conf file they would
expect that to be given priority. Otherwise they would know that was a
deprecated method and would set it in postgresql.conf only.

Please find attached an half-cooked patch supporting both postgresql.conf
and recovery.conf. Priority is given to recovery.conf if the same parameter
is specified in both files. I have updated the docs in consequence but I
think they can be improved.
The main modification here is in xlog.c:readRecoveryCommandFile where the
deparsed output values of recovery.conf is transferred to the new GUCs using
SetConfigOption($OPTION, $VALUE, PGC_POSTMASTER, PGC_S_OVERRIDE) as bridge.
This does not work yet, SetConfigOption is not able to detect the new
values. Comments?

So... what happens when recovery ends? Do the settings loaded from
recovery.conf get reverted, or what?

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#17Michael Paquier
michael.paquier@gmail.com
In reply to: Robert Haas (#16)
Re: Request for vote to move forward with recovery.conf overhaul

On Sun, Jan 27, 2013 at 1:41 PM, Robert Haas <robertmhaas@gmail.com> wrote:

On Sat, Jan 26, 2013 at 9:49 PM, Michael Paquier
<michael.paquier@gmail.com> wrote:

On Sun, Jan 27, 2013 at 7:14 AM, Phil Sorber <phil@omniti.com> wrote:

On Wed, Jan 23, 2013 at 6:36 AM, Michael Paquier
<michael.paquier@gmail.com> wrote:

On 2013/01/23, at 18:12, Simon Riggs <simon@2ndQuadrant.com> wrote:

On 23 January 2013 04:49, Michael Paquier <michael.paquier@gmail.com

wrote:

- recovery.conf is removed (no backward compatibility in this

version

of the
patch)

If you want to pursue that, you know where it leads. No, rebasing a
rejected patch doesn't help, its just relighting a fire that

shouldn't

ever have been lit.

Pushing to do that out of order is just going to drain essential time
out of this CF from all of us.

No problem to support both. The only problem I see is if the same
parameter is defined in recovery.conf and postgresql.conf, is the

priority

given to recovery.conf?

I would think that if someone created a recovery.conf file they would
expect that to be given priority. Otherwise they would know that was a
deprecated method and would set it in postgresql.conf only.

Please find attached an half-cooked patch supporting both postgresql.conf
and recovery.conf. Priority is given to recovery.conf if the same

parameter

is specified in both files. I have updated the docs in consequence but I
think they can be improved.
The main modification here is in xlog.c:readRecoveryCommandFile where the
deparsed output values of recovery.conf is transferred to the new GUCs

using

SetConfigOption($OPTION, $VALUE, PGC_POSTMASTER, PGC_S_OVERRIDE) as

bridge.

This does not work yet, SetConfigOption is not able to detect the new
values. Comments?

So... what happens when recovery ends? Do the settings loaded from
recovery.conf get reverted, or what?

With current patch the settings are kept if set in postgresql.conf and
discarded if they are loaded as GUC after a server restart or reload.
--
Michael Paquier
http://michael.otacoo.com

#18Robert Haas
robertmhaas@gmail.com
In reply to: Michael Paquier (#17)
Re: Request for vote to move forward with recovery.conf overhaul

On Sun, Jan 27, 2013 at 1:01 AM, Michael Paquier
<michael.paquier@gmail.com> wrote:

So... what happens when recovery ends? Do the settings loaded from
recovery.conf get reverted, or what?

With current patch the settings are kept if set in postgresql.conf and
discarded if they are loaded as GUC after a server restart or reload.

I can't understand that answer. Is there a word missing or something?

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#19Greg Smith
greg@2ndQuadrant.com
In reply to: Michael Paquier (#13)
Re: Request for vote to move forward with recovery.conf overhaul

On 1/23/13 6:36 AM, Michael Paquier wrote:

The only problem I see is if the same parameter is defined in recovery.conf and postgresql.conf, is the priority given to recovery.conf?

This sort of thing is what dragged down the past work on this. I don't
really agree with the idea this thread is based on, that it was backward
compatibility that kept this from being finished last year. I put a
good bit of time into a proposal that a few people seemed happy with;
all its ideas seem to have washed away. That balanced a couple of goals:

-Allow a "pg_ctl standby" and "pg_ctl recover" command that work
similarly to "promote". This should slim down the work needed for the
first replication setup people do.
-Make it obvious when people try to use recovery.conf that it's not
supported anymore.
-Provide a migration path for tool authors strictly in the form of some
documentation and error message hints. That was it as far as
concessions to backward compatibility.

The wrap-up I did started at
/messages/by-id/4EE91248.8010505@2ndQuadrant.com
and only had a few responses/controversy from there. Robert wrote a
good summary:

1. Get rid of recovery.conf - error out if it is seen
2. For each parameter that was previously a recovery.conf parameter,
make it a GUC
3. For the parameter that was "does recovery.conf exist?", replace it
with "does standby.enabled exist?".

I thought this stopped from there because no one went back to clean up
Fujii's submission, which Simon and Michael have now put more time into.
There is not much distance between it and the last update Michael
sent. Here's the detailed notes from my original proposal, with updates
to incorporate the main feedback I got then; note that much of this is
documentation rather than code:

-Creating a standby.enabled file puts the system into recovery mode.
That feature needs to save some state, and making those decisions based
on existence of a file is already a thing we do. Rather than emulating
the rename to recovery.done that happens now, the server can just delete
it, to keep from incorrectly returning to a state it's exited. A UI
along the lines of the promote one, allowing "pg_ctl standby", should
fall out of here.

This file can be relocated to the config directory, similarly to how the
include directory looks for things. There was a concern that this would
require write permissions that don't exist on systems that relocate
configs, like Debian/Ubuntu. That doesn't look to be a real issue
though. Here's a random Debian server showing the postgres user can
write to all of those:

$ ls -ld /etc/postgresql
drwxr-xr-x 4 root root 4096 Jun 29 2012 /etc/postgresql
$ ls -ld /etc/postgresql/9.1
drwxr-xr-x 3 postgres postgres 4096 Jul 1 2012 /etc/postgresql/9.1
$ ls -ld /etc/postgresql/9.1/main
drwxr-xr-x 2 postgres postgres 4096 Mar 3 11:00 /etc/postgresql/9.1/main

-A similar recovery.enabled file turns on PITR recovery.

-It should be possible to copy a postgresql.conf file from master to
standby and just use it. For example:
--"standby_mode = on": Ignored unless you've started the server with
standby.enabled, won't bother the master if you include it.
--"primary_conninfo": This will look funny on the master showing it
connecting to itself, but it will get ignored there too.

-If startup finds a recovery.conf file where it used to live at,
abort--someone is expecting the old behavior. Hint to RTFM or include a
short migration guide right on the spot. That can have a nice section
about how you might use the various postgresql.conf include* features if
they want to continue managing those files separately. Example: rename
what you used to make recovery.conf as replication.conf and use
include_if_exists if you want to be able to rename it to recovery.done
like before. Or drop it into a config/ directory (similarly to the
proposal for SET PERSISTENT) where the rename to recovery.done will make
it then skipped. (Only files ending with .conf are processed by
include_dir)

-Tools such as pgpool that want to write a simple configuration file,
only touching the things that used to go into recovery.conf, can tell
people to do the same trick. End their postgresql.conf with a call to
\include_if_exists replication.conf as part of setup. While I don't
like pushing problems toward tool vendors, as one I think validating if
this has been done doesn't require the sort of fully GUC compatible
parser people (rightly) want to avoid. A simple scan of the
postgresql.conf looking for the recommended text at the front of a line
could confirm whether that bit is there. And adding a single
"include_if_exists" line to the end of the postgresql.conf is not a
terrible edit job to consider pushing toward tools. None of this is any
more complicated than the little search and replace job that initdb does
right now.

-If you want to do something special yourself to clean up when recovery
finishes, perhaps to better emulate the old "those settings go away"
implementation, there's already recovery_end_command available for that.
Let's say you wanted to force the old name and did "include_if_exists
config/recovery.conf". Now you could do:

recovery_end_command = 'rm -f /tmp/pgsql.trigger.5432 && mv
conf.d/recovery.conf conf.d/recovery.done'

--
Greg Smith 2ndQuadrant US greg@2ndQuadrant.com Baltimore, MD
PostgreSQL Training, Services, and 24x7 Support www.2ndQuadrant.com

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#20Robert Haas
robertmhaas@gmail.com
In reply to: Greg Smith (#19)
Re: Request for vote to move forward with recovery.conf overhaul

On Sun, Mar 3, 2013 at 9:25 PM, Greg Smith <greg@2ndquadrant.com> wrote:

-Allow a "pg_ctl standby" and "pg_ctl recover" command that work similarly
to "promote". This should slim down the work needed for the first
replication setup people do.
-Make it obvious when people try to use recovery.conf that it's not
supported anymore.
-Provide a migration path for tool authors strictly in the form of some
documentation and error message hints. That was it as far as concessions to
backward compatibility.

The wrap-up I did started at
/messages/by-id/4EE91248.8010505@2ndQuadrant.com and
only had a few responses/controversy from there. Robert wrote a good
summary:

1. Get rid of recovery.conf - error out if it is seen
2. For each parameter that was previously a recovery.conf parameter, make it
a GUC
3. For the parameter that was "does recovery.conf exist?", replace it with
"does standby.enabled exist?".

All that works for me.

I thought this stopped from there because no one went back to clean up
Fujii's submission, which Simon and Michael have now put more time into.
There is not much distance between it and the last update Michael sent.
Here's the detailed notes from my original proposal, with updates to
incorporate the main feedback I got then; note that much of this is
documentation rather than code:

-Creating a standby.enabled file puts the system into recovery mode. That
feature needs to save some state, and making those decisions based on
existence of a file is already a thing we do. Rather than emulating the
rename to recovery.done that happens now, the server can just delete it, to
keep from incorrectly returning to a state it's exited. A UI along the
lines of the promote one, allowing "pg_ctl standby", should fall out of
here.

This file can be relocated to the config directory, similarly to how the
include directory looks for things. There was a concern that this would
require write permissions that don't exist on systems that relocate configs,
like Debian/Ubuntu. That doesn't look to be a real issue though. Here's a
random Debian server showing the postgres user can write to all of those:

$ ls -ld /etc/postgresql
drwxr-xr-x 4 root root 4096 Jun 29 2012 /etc/postgresql
$ ls -ld /etc/postgresql/9.1
drwxr-xr-x 3 postgres postgres 4096 Jul 1 2012 /etc/postgresql/9.1
$ ls -ld /etc/postgresql/9.1/main
drwxr-xr-x 2 postgres postgres 4096 Mar 3 11:00 /etc/postgresql/9.1/main

-A similar recovery.enabled file turns on PITR recovery.

-It should be possible to copy a postgresql.conf file from master to standby
and just use it. For example:
--"standby_mode = on": Ignored unless you've started the server with
standby.enabled, won't bother the master if you include it.
--"primary_conninfo": This will look funny on the master showing it
connecting to itself, but it will get ignored there too.

-If startup finds a recovery.conf file where it used to live at,
abort--someone is expecting the old behavior. Hint to RTFM or include a
short migration guide right on the spot. That can have a nice section about
how you might use the various postgresql.conf include* features if they want
to continue managing those files separately. Example: rename what you used
to make recovery.conf as replication.conf and use include_if_exists if you
want to be able to rename it to recovery.done like before. Or drop it into
a config/ directory (similarly to the proposal for SET PERSISTENT) where the
rename to recovery.done will make it then skipped. (Only files ending with
.conf are processed by include_dir)

-Tools such as pgpool that want to write a simple configuration file,
only touching the things that used to go into recovery.conf, can tell
people to do the same trick. End their postgresql.conf with a call to
\include_if_exists replication.conf as part of setup. While I don't
like pushing problems toward tool vendors, as one I think validating if
this has been done doesn't require the sort of fully GUC compatible
parser people (rightly) want to avoid. A simple scan of the
postgresql.conf looking for the recommended text at the front of a line
could confirm whether that bit is there. And adding a single
"include_if_exists" line to the end of the postgresql.conf is not a
terrible edit job to consider pushing toward tools. None of this is any
more complicated than the little search and replace job that initdb does
right now.

-If you want to do something special yourself to clean up when recovery
finishes, perhaps to better emulate the old "those settings go away"
implementation, there's already recovery_end_command available for that.
Let's say you wanted to force the old name and did "include_if_exists
config/recovery.conf". Now you could do:

recovery_end_command = 'rm -f /tmp/pgsql.trigger.5432 && mv
conf.d/recovery.conf conf.d/recovery.done'

No argument with any of that, either.

If that's what we're implementing, I'm on board.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#21Michael Paquier
michael.paquier@gmail.com
In reply to: Greg Smith (#19)
Re: Request for vote to move forward with recovery.conf overhaul

Thanks for taking time in typing a complete summary of the situation. That
really helps.

On Mon, Mar 4, 2013 at 11:25 AM, Greg Smith <greg@2ndquadrant.com> wrote:

On 1/23/13 6:36 AM, Michael Paquier wrote:

The only problem I see is if the same parameter is defined in
recovery.conf and postgresql.conf, is the priority given to recovery.conf?

This sort of thing is what dragged down the past work on this. I don't
really agree with the idea this thread is based on, that it was backward
compatibility that kept this from being finished last year. I put a good
bit of time into a proposal that a few people seemed happy with; all its
ideas seem to have washed away. That balanced a couple of goals:

-Allow a "pg_ctl standby" and "pg_ctl recover" command that work similarly
to "promote". This should slim down the work needed for the first
replication setup people do.
-Make it obvious when people try to use recovery.conf that it's not
supported anymore.
-Provide a migration path for tool authors strictly in the form of some
documentation and error message hints. That was it as far as concessions
to backward compatibility.

The wrap-up I did started at http://www.postgresql.org/**
message-id/4EE91248.8010505@**2ndQuadrant.com</messages/by-id/4EE91248.8010505@2ndQuadrant.com&gt;and only had a few responses/controversy from there. Robert wrote a good
summary:

1. Get rid of recovery.conf - error out if it is seen
2. For each parameter that was previously a recovery.conf parameter, make
it a GUC
3. For the parameter that was "does recovery.conf exist?", replace it with
"does standby.enabled exist?".

Agreed on that.

I thought this stopped from there because no one went back to clean up
Fujii's submission, which Simon and Michael have now put more time into.
There is not much distance between it and the last update Michael sent.

Just to be picky. I recommend using the version dated of 23rd of January as
a work base if we definitely get rid of recovery.conf, the patch file is
called 20130123_recovery_unite.patch.
The second patch I sent on the 27th tried to support both recovery.conf and
postgresql.conf, but this finishes with a lot of duplicated code as two
sets of functions are necessary to deparse options for both postgresql.conf
and recovery.conf...

Here's the detailed notes from my original proposal, with updates to
incorporate the main feedback I got then; note that much of this is
documentation rather than code:

-Creating a standby.enabled file puts the system into recovery mode. That
feature needs to save some state, and making those decisions based on
existence of a file is already a thing we do. Rather than emulating the
rename to recovery.done that happens now, the server can just delete it, to
keep from incorrectly returning to a state it's exited. A UI along the
lines of the promote one, allowing "pg_ctl standby", should fall out of
here.

This file can be relocated to the config directory, similarly to how the
include directory looks for things. There was a concern that this would
require write permissions that don't exist on systems that relocate
configs, like Debian/Ubuntu. That doesn't look to be a real issue though.
Here's a random Debian server showing the postgres user can write to all
of those:

$ ls -ld /etc/postgresql
drwxr-xr-x 4 root root 4096 Jun 29 2012 /etc/postgresql
$ ls -ld /etc/postgresql/9.1
drwxr-xr-x 3 postgres postgres 4096 Jul 1 2012 /etc/postgresql/9.1
$ ls -ld /etc/postgresql/9.1/main
drwxr-xr-x 2 postgres postgres 4096 Mar 3 11:00 /etc/postgresql/9.1/main

-A similar recovery.enabled file turns on PITR recovery.

-It should be possible to copy a postgresql.conf file from master to
standby and just use it. For example:
--"standby_mode = on": Ignored unless you've started the server with
standby.enabled, won't bother the master if you include it.
--"primary_conninfo": This will look funny on the master showing it
connecting to itself, but it will get ignored there too.

-If startup finds a recovery.conf file where it used to live at,
abort--someone is expecting the old behavior. Hint to RTFM or include a
short migration guide right on the spot. That can have a nice section
about how you might use the various postgresql.conf include* features if
they want to continue managing those files separately. Example: rename
what you used to make recovery.conf as replication.conf and use
include_if_exists if you want to be able to rename it to recovery.done like
before. Or drop it into a config/ directory (similarly to the proposal for
SET PERSISTENT) where the rename to recovery.done will make it then
skipped. (Only files ending with .conf are processed by include_dir)

-Tools such as pgpool that want to write a simple configuration file,
only touching the things that used to go into recovery.conf, can tell
people to do the same trick. End their postgresql.conf with a call to
\include_if_exists replication.conf as part of setup. While I don't
like pushing problems toward tool vendors, as one I think validating if
this has been done doesn't require the sort of fully GUC compatible
parser people (rightly) want to avoid. A simple scan of the
postgresql.conf looking for the recommended text at the front of a line
could confirm whether that bit is there. And adding a single
"include_if_exists" line to the end of the postgresql.conf is not a
terrible edit job to consider pushing toward tools. None of this is any
more complicated than the little search and replace job that initdb does
right now.

-If you want to do something special yourself to clean up when recovery
finishes, perhaps to better emulate the old "those settings go away"
implementation, there's already recovery_end_command available for that.
Let's say you wanted to force the old name and did "include_if_exists
config/recovery.conf". Now you could do:

recovery_end_command = 'rm -f /tmp/pgsql.trigger.5432 && mv
conf.d/recovery.conf conf.d/recovery.done'

Looks good to me too.
Based on the patch I already sent before, there are a couple of things
missing:
- There are no pg_ctl standby/recover commands implemented yet (no that
difficult to add)
- a certain amount of work is needed for documentation

Btw, I have a concern about that: is it really the time to finish that for
this release knowing that the 9.3 feature freeze is getting close? I still
don't know when it will be but it is... close.
--
Michael

#22Michael Paquier
michael.paquier@gmail.com
In reply to: Michael Paquier (#21)
Re: Request for vote to move forward with recovery.conf overhaul

On Wed, Mar 6, 2013 at 2:08 PM, Michael Paquier
<michael.paquier@gmail.com>wrote:

Thanks for taking time in typing a complete summary of the situation. That
really helps.

On Mon, Mar 4, 2013 at 11:25 AM, Greg Smith <greg@2ndquadrant.com> wrote:

On 1/23/13 6:36 AM, Michael Paquier wrote:

The only problem I see is if the same parameter is defined in
recovery.conf and postgresql.conf, is the priority given to recovery.conf?

This sort of thing is what dragged down the past work on this. I don't
really agree with the idea this thread is based on, that it was backward
compatibility that kept this from being finished last year. I put a good
bit of time into a proposal that a few people seemed happy with; all its
ideas seem to have washed away. That balanced a couple of goals:

-Allow a "pg_ctl standby" and "pg_ctl recover" command that work
similarly to "promote". This should slim down the work needed for the
first replication setup people do.
-Make it obvious when people try to use recovery.conf that it's not
supported anymore.
-Provide a migration path for tool authors strictly in the form of some
documentation and error message hints. That was it as far as concessions
to backward compatibility.

The wrap-up I did started at http://www.postgresql.org/**
message-id/4EE91248.8010505@**2ndQuadrant.com</messages/by-id/4EE91248.8010505@2ndQuadrant.com&gt;and only had a few responses/controversy from there. Robert wrote a good
summary:

1. Get rid of recovery.conf - error out if it is seen
2. For each parameter that was previously a recovery.conf parameter, make
it a GUC
3. For the parameter that was "does recovery.conf exist?", replace it
with "does standby.enabled exist?".

Agreed on that.

I thought this stopped from there because no one went back to clean up
Fujii's submission, which Simon and Michael have now put more time into.
There is not much distance between it and the last update Michael sent.

Just to be picky. I recommend using the version dated of 23rd of January
as a work base if we definitely get rid of recovery.conf, the patch file is
called 20130123_recovery_unite.patch.
The second patch I sent on the 27th tried to support both recovery.conf
and postgresql.conf, but this finishes with a lot of duplicated code as two
sets of functions are necessary to deparse options for both postgresql.conf
and recovery.conf...

Here's the detailed notes from my original proposal, with updates to
incorporate the main feedback I got then; note that much of this is
documentation rather than code:

-Creating a standby.enabled file puts the system into recovery mode. That
feature needs to save some state, and making those decisions based on
existence of a file is already a thing we do. Rather than emulating the
rename to recovery.done that happens now, the server can just delete it, to
keep from incorrectly returning to a state it's exited. A UI along the
lines of the promote one, allowing "pg_ctl standby", should fall out of
here.

This file can be relocated to the config directory, similarly to how the
include directory looks for things. There was a concern that this would
require write permissions that don't exist on systems that relocate
configs, like Debian/Ubuntu. That doesn't look to be a real issue though.
Here's a random Debian server showing the postgres user can write to all
of those:

$ ls -ld /etc/postgresql
drwxr-xr-x 4 root root 4096 Jun 29 2012 /etc/postgresql
$ ls -ld /etc/postgresql/9.1
drwxr-xr-x 3 postgres postgres 4096 Jul 1 2012 /etc/postgresql/9.1
$ ls -ld /etc/postgresql/9.1/main
drwxr-xr-x 2 postgres postgres 4096 Mar 3 11:00 /etc/postgresql/9.1/main

-A similar recovery.enabled file turns on PITR recovery.

-It should be possible to copy a postgresql.conf file from master to
standby and just use it. For example:
--"standby_mode = on": Ignored unless you've started the server with
standby.enabled, won't bother the master if you include it.
--"primary_conninfo": This will look funny on the master showing it
connecting to itself, but it will get ignored there too.

-If startup finds a recovery.conf file where it used to live at,
abort--someone is expecting the old behavior. Hint to RTFM or include a
short migration guide right on the spot. That can have a nice section
about how you might use the various postgresql.conf include* features if
they want to continue managing those files separately. Example: rename
what you used to make recovery.conf as replication.conf and use
include_if_exists if you want to be able to rename it to recovery.done like
before. Or drop it into a config/ directory (similarly to the proposal for
SET PERSISTENT) where the rename to recovery.done will make it then
skipped. (Only files ending with .conf are processed by include_dir)

-Tools such as pgpool that want to write a simple configuration file,
only touching the things that used to go into recovery.conf, can tell
people to do the same trick. End their postgresql.conf with a call to
\include_if_exists replication.conf as part of setup. While I don't
like pushing problems toward tool vendors, as one I think validating if
this has been done doesn't require the sort of fully GUC compatible
parser people (rightly) want to avoid. A simple scan of the
postgresql.conf looking for the recommended text at the front of a line
could confirm whether that bit is there. And adding a single
"include_if_exists" line to the end of the postgresql.conf is not a
terrible edit job to consider pushing toward tools. None of this is any
more complicated than the little search and replace job that initdb does
right now.

-If you want to do something special yourself to clean up when recovery
finishes, perhaps to better emulate the old "those settings go away"
implementation, there's already recovery_end_command available for that.
Let's say you wanted to force the old name and did "include_if_exists
config/recovery.conf". Now you could do:

recovery_end_command = 'rm -f /tmp/pgsql.trigger.5432 && mv
conf.d/recovery.conf conf.d/recovery.done'

Looks good to me too.
Based on the patch I already sent before, there are a couple of things
missing:
- There are no pg_ctl standby/recover commands implemented yet (no that
difficult to add)
- a certain amount of work is needed for documentation

Btw, I have a concern about that: is it really the time to finish that for
this release knowing that the 9.3 feature freeze is getting close? I still
don't know when it will be but it is... close.

This patch is still in the current commit fest. Any objections in marking
it as returned with feedback and put it in the next commit fest? We could
work on that again at the next release as it looks that there is not much
time to work on it for 9.3.
--
Michael

#23Alvaro Herrera
alvherre@2ndquadrant.com
In reply to: Michael Paquier (#22)
Re: Request for vote to move forward with recovery.conf overhaul

Michael Paquier escribió:

On Wed, Mar 6, 2013 at 2:08 PM, Michael Paquier
<michael.paquier@gmail.com>wrote:

Looks good to me too.
Based on the patch I already sent before, there are a couple of things
missing:
- There are no pg_ctl standby/recover commands implemented yet (no that
difficult to add)
- a certain amount of work is needed for documentation

Btw, I have a concern about that: is it really the time to finish that for
this release knowing that the 9.3 feature freeze is getting close? I still
don't know when it will be but it is... close.

This patch is still in the current commit fest. Any objections in marking
it as returned with feedback and put it in the next commit fest? We could
work on that again at the next release as it looks that there is not much
time to work on it for 9.3.

If the patch is almost ready, IMHO you should complete it and post a
version that implements the consensus design.

--
Álvaro Herrera http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#24Greg Smith
greg@2ndQuadrant.com
In reply to: Michael Paquier (#22)
Re: Request for vote to move forward with recovery.conf overhaul

On 3/8/13 10:34 PM, Michael Paquier wrote:

This patch is still in the current commit fest. Any objections in
marking it as returned with feedback and put it in the next commit fest?

There are currently 20 "Needs Review" and 14 "Waiting on Author" things
left in the queue, so it's not quite that there's no time left. There
really isn't very much left to do on this. The rough consensus idea
from before takes a while to describe, but there was not a complicated
implementation in that. The overlap with the still possible to commit
SET PERSISTENT is probably the worst potential issue this is facing now,
but that's not even a real issue yet.

If you're out of time to work on it and want to back out of here having
made good progress, that's fine. I'd be tempted to work on this thing
myself for a bit just to try and finally get it done. If it gets punted
forward, we'll be right back to facing bit rot and remembering what was
going on again, which is what killed the momentum toward committing this
the last time.

--
Greg Smith 2ndQuadrant US greg@2ndQuadrant.com Baltimore, MD
PostgreSQL Training, Services, and 24x7 Support www.2ndQuadrant.com

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#25Michael Paquier
michael.paquier@gmail.com
In reply to: Greg Smith (#24)
Re: Request for vote to move forward with recovery.conf overhaul

On Sat, Mar 9, 2013 at 1:20 PM, Greg Smith <greg@2ndquadrant.com> wrote:

There are currently 20 "Needs Review" and 14 "Waiting on Author" things
left in the queue, so it's not quite that there's no time left. There
really isn't very much left to do on this. The rough consensus idea from
before takes a while to describe, but there was not a complicated
implementation in that. The overlap with the still possible to commit SET
PERSISTENT is probably the worst potential issue this is facing now, but
that's not even a real issue yet.

OK thanks for your feedback.

If you're out of time to work on it and want to back out of here having
made good progress, that's fine. I'd be tempted to work on this thing
myself for a bit just to try and finally get it done. If it gets punted
forward, we'll be right back to facing bit rot and remembering what was
going on again, which is what killed the momentum toward committing this
the last time.

I think I will be able to work on that but not before Monday. This depends
also on how REINDEX CONCURRENTLY goes...
--
Michael

#26Michael Paquier
michael.paquier@gmail.com
In reply to: Greg Smith (#19)
1 attachment(s)
Re: Request for vote to move forward with recovery.conf overhaul

Hi all,

Please find attached an updated patch doing what is written below.

On Mon, Mar 4, 2013 at 11:25 AM, Greg Smith <greg@2ndquadrant.com> wrote:

Robert wrote a good summary:
1. Get rid of recovery.conf - error out if it is seen
2. For each parameter that was previously a recovery.conf parameter, make
it a GUC
3. For the parameter that was "does recovery.conf exist?", replace it with
"does standby.enabled exist?".

There are still a couple of things missing:
- pg_basebackup supports an option --write-recovery-conf, I haven't
modified anything yet, but I think that we should replace that by an option
that write standby.enabled in base backup and adds the relevant parameters
in postgresql.conf. Any input on that is welcome.
- no migration guide is written yet. Where to write it? I think I will need
some help here...
- The current error message if recovery.conf is found in data folder is
that:
+       if (AllocateFile(RECOVERY_COMMAND_FILE, "r") != NULL)
+               ereport(FATAL,
+                               (errmsg("\"%s\" is not supported anymore as
a recovery method",
+                                               RECOVERY_COMMAND_FILE),
+                                errdetail("Refer to appropriate
documentation about migration methods")));
Any better ideas?

I found some inconsistent behavior when a slave had no standby.enabled
files and recovery settings: the slave with "hot_standby = on" tried to
recover WAL files from archives instead of failing with errors of the type
"could not locate required checkpoint record" and then stop. This is fixed.

Regards,
--
Michael

Attachments:

20130313_recovery_guc.patchapplication/octet-stream; name=20130313_recovery_guc.patchDownload
diff --git a/contrib/pg_archivecleanup/pg_archivecleanup.c b/contrib/pg_archivecleanup/pg_archivecleanup.c
index e97a11c..fb01da9 100644
--- a/contrib/pg_archivecleanup/pg_archivecleanup.c
+++ b/contrib/pg_archivecleanup/pg_archivecleanup.c
@@ -255,7 +255,7 @@ usage(void)
 	printf("  -x EXT         clean up files if they have this extension\n");
 	printf("  -?, --help     show this help, then exit\n");
 	printf("\n"
-		   "For use as archive_cleanup_command in recovery.conf when standby_mode = on:\n"
+		   "For use as archive_cleanup_command in postgresql.conf when standby_mode = on:\n"
 		   "  archive_cleanup_command = 'pg_archivecleanup [OPTION]... ARCHIVELOCATION %%r'\n"
 		   "e.g.\n"
 		   "  archive_cleanup_command = 'pg_archivecleanup /mnt/server/archiverdir %%r'\n");
diff --git a/contrib/pg_standby/pg_standby.c b/contrib/pg_standby/pg_standby.c
index 659bd50..115c25e 100644
--- a/contrib/pg_standby/pg_standby.c
+++ b/contrib/pg_standby/pg_standby.c
@@ -531,7 +531,7 @@ usage(void)
 	printf("  -w MAXWAITTIME     max seconds to wait for a file (0=no limit) (default=0)\n");
 	printf("  -?, --help         show this help, then exit\n");
 	printf("\n"
-		   "Main intended use as restore_command in recovery.conf:\n"
+		   "Main intended use as restore_command in postgresql.conf:\n"
 		   "  restore_command = 'pg_standby [OPTION]... ARCHIVELOCATION %%f %%p %%r'\n"
 		   "e.g.\n"
 	"  restore_command = 'pg_standby /mnt/server/archiverdir %%f %%p %%r'\n");
diff --git a/doc/src/sgml/backup.sgml b/doc/src/sgml/backup.sgml
index c4215be..f3040ff 100644
--- a/doc/src/sgml/backup.sgml
+++ b/doc/src/sgml/backup.sgml
@@ -1002,10 +1002,17 @@ SELECT pg_stop_backup();
    </listitem>
    <listitem>
     <para>
-     Create a recovery command file <filename>recovery.conf</> in the cluster
-     data directory (see <xref linkend="recovery-config">). You might
-     also want to temporarily modify <filename>pg_hba.conf</> to prevent
-     ordinary users from connecting until you are sure the recovery was successful.
+     Set up recovery parameters in <filename>postgresql.conf</> (see
+     <xref linkend="runtime-config-wal-archive-recovery"> and
+     <xref linkend="runtime-config-wal-recovery-target">).
+    </para>
+   </listitem>
+   <listitem>
+    <para>
+     Create a file called <filename>standby.enabled</> in the cluster data
+     directory. You might also want to temporarily modify <filename>pg_hba.conf</>
+     to prevent ordinary users from connecting until you are sure the recovery
+     was successful.
     </para>
    </listitem>
    <listitem>
@@ -1014,10 +1021,9 @@ SELECT pg_stop_backup();
      proceed to read through the archived WAL files it needs.  Should the
      recovery be terminated because of an external error, the server can
      simply be restarted and it will continue recovery.  Upon completion
-     of the recovery process, the server will rename
-     <filename>recovery.conf</> to <filename>recovery.done</> (to prevent
-     accidentally re-entering recovery mode later) and then
-     commence normal database operations.
+     of the recovery process, the server will delete
+     <filename>standby.enabled</> (to prevent accidentally re-entering
+     recovery mode later) and then commence normal database operations.
     </para>
    </listitem>
    <listitem>
@@ -1031,12 +1037,11 @@ SELECT pg_stop_backup();
    </para>
 
    <para>
-    The key part of all this is to set up a recovery configuration file that
-    describes how you want to recover and how far the recovery should
-    run.  You can use <filename>recovery.conf.sample</> (normally
-    located in the installation's <filename>share/</> directory) as a
-    prototype.  The one thing that you absolutely must specify in
-    <filename>recovery.conf</> is the <varname>restore_command</>,
+    The key part of all this is to set up recovery parameters that
+    specify how you want to recover and how far the recovery should
+    run. The one thing that you absolutely must specify in
+    <filename>postgresql.conf</> to recover from the backup is
+    the <varname>restore_command</>,
     which tells <productname>PostgreSQL</> how to retrieve archived
     WAL file segments.  Like the <varname>archive_command</>, this is
     a shell command string.  It can contain <literal>%f</>, which is
@@ -1090,7 +1095,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 stopping point in <filename>postgresql.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
@@ -1187,8 +1192,9 @@ restore_command = 'cp /mnt/server/archivedir/%f %p'
     The default behavior of recovery is to recover along the same timeline
     that was current when the base backup was taken.  If you wish to recover
     into some child timeline (that is, you want to return to some state that
-    was itself generated after a recovery attempt), you need to specify the
-    target timeline ID in <filename>recovery.conf</>.  You cannot recover into
+    was itself generated after a recovery attempt), you need to set
+    <xref linkend="guc-recovery-target-timeline"> to the
+    target timeline ID in <filename>postgresql.conf</>.  You cannot recover into
     timelines that branched off earlier than the base backup.
    </para>
   </sect2>
diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index ae6ee60..70c4c08 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -2163,6 +2163,278 @@ include 'filename'
      </variablelist>
     </sect2>
 
+    <sect2 id="runtime-config-wal-archive-recovery">
+     <title>Archive Recovery</title>
+
+     <variablelist>
+      <varlistentry id="guc-restore-command" xreflabel="restore_command">
+       <term><varname>restore_command</varname> (<type>string</type>)</term>
+       <indexterm>
+        <primary><varname>restore_command</> configuration parameter</primary>
+       </indexterm>
+       <listitem>
+        <para>
+         The shell command to execute to retrieve an archived segment of
+         the WAL file series. This parameter is required for archive recovery,
+         but optional for streaming replication.
+         Any <literal>%f</> in the string is
+         replaced by the name of the file to retrieve from the archive,
+         and any <literal>%p</> is replaced by the copy destination path name
+         on the server.
+         (The path name is relative to the current working directory,
+         i.e., the cluster's data directory.)
+         Any <literal>%r</> is replaced by the name of the file containing the
+         last valid restart point. That is the earliest file that must be kept
+         to allow a restore to be restartable, so this information can be used
+         to truncate the archive to just the minimum required to support
+         restarting from the current restore. <literal>%r</> is typically only
+         used by warm-standby configurations
+         (see <xref linkend="warm-standby">).
+         Write <literal>%%</> to embed an actual <literal>%</> character.
+        </para>
+        <para>
+         It is important for the command to return a zero exit status
+         only if it succeeds.  The command <emphasis>will</> be asked for file
+         names that are not present in the archive; it must return nonzero
+         when so asked.  Examples:
+<programlisting>
+restore_command = 'cp /mnt/server/archivedir/%f "%p"'
+restore_command = 'copy "C:\\server\\archivedir\\%f" "%p"'  # Windows
+</programlisting>
+        </para>
+        <para>
+         This parameter can only be set in the <filename>postgresql.conf</>
+         file or on the server command line. It only has effect during archive
+         recovery or in standby mode.
+        </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry id="guc-archive-cleanup-command" xreflabel="archive_cleanup_command">
+       <term><varname>archive_cleanup_command</varname> (<type>string</type>)</term>
+       <indexterm>
+         <primary><varname>archive_cleanup_command</> configuration parameter</primary>
+       </indexterm>
+       <listitem>
+        <para>
+         The shell command that will be executed at every restartpoint.
+         The purpose of <varname>archive_cleanup_command</> is to
+         provide a mechanism for cleaning up old archived WAL files that
+         are no longer needed by the standby server.
+         Any <literal>%r</> is replaced by the name of the file containing the
+         last valid restart point.
+         That is the earliest file that must be <emphasis>kept</> to allow a
+         restore to be restartable, and so all files earlier than <literal>%r</>
+         may be safely removed.
+         This information can be used to truncate the archive to just the
+         minimum required to support restart from the current restore.
+         The <xref linkend="pgarchivecleanup"> module
+         is often used in <varname>archive_cleanup_command</> for
+         single-standby configurations, for example:
+<programlisting>archive_cleanup_command = 'pg_archivecleanup /mnt/server/archivedir %r'</programlisting>
+         Note however that if multiple standby servers are restoring from the
+         same archive directory, you will need to ensure that you do not delete
+         WAL files until they are no longer needed by any of the servers.
+         <varname>archive_cleanup_command</> would typically be used in a
+         warm-standby configuration (see <xref linkend="warm-standby">).
+         Write <literal>%%</> to embed an actual <literal>%</> character in the
+         command.
+        </para>
+        <para>
+         If the command returns a non-zero exit status then a WARNING log
+         message will be written.
+        </para>
+        <para>
+         This parameter can only be set in the <filename>postgresql.conf</>
+         file or on the server command line. It only has effect during archive
+         recovery or in standby mode.
+        </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry id="guc-recovery-end-command" xreflabel="recovery_end_command">
+       <term><varname>recovery_end_command</varname> (<type>string</type>)</term>
+       <indexterm>
+         <primary><varname>recovery_end_command</> configuration parameter</primary>
+       </indexterm>
+       <listitem>
+        <para>
+         The shell command that will be executed once only
+         at the end of recovery. This parameter is optional. The purpose of the
+         <varname>recovery_end_command</> is to provide a mechanism for cleanup
+         following replication or recovery.
+         Any <literal>%r</> is replaced by the name of the file containing the
+         last valid restart point, like in <varname>archive_cleanup_command</>.
+        </para>
+        <para>
+         If the command returns a non-zero exit status then a WARNING log
+         message will be written and the database will proceed to start up
+         anyway.  An exception is that if the command was terminated by a
+         signal, the database will not proceed with startup.
+        </para>
+        <para>
+         This parameter can only be set in the <filename>postgresql.conf</>
+         file or on the server command line. It only has effect during archive
+         recovery or in standby mode.
+        </para>
+       </listitem>
+      </varlistentry>
+     </variablelist>
+    </sect2>
+
+    <sect2 id="runtime-config-wal-recovery-target">
+     <title>Recovery Target</title>
+
+     <variablelist>
+      <varlistentry id="guc-recovery-target-name" xreflabel="recovery_target_name">
+       <term><varname>recovery_target_name</varname> (<type>string</type>)</term>
+       <indexterm>
+        <primary><varname>recovery_target_name</> configuration parameter</primary>
+       </indexterm>
+       <listitem>
+        <para>
+         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</>,
+         <varname>recovery_target_time</> or
+         <varname>recovery_target_xid</> can be specified.  The default
+         value is an empty string, which will recover to the end of the WAL log.
+        </para>
+        <para>
+         This parameter can only be set in the <filename>postgresql.conf</>
+         file or on the server command line. It only has effect during archive
+         recovery or in standby mode.
+        </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry id="guc-recovery-target-time" xreflabel="recovery_target_time">
+       <term><varname>recovery_target_time</varname> (<type>string</type>)</term>
+       <indexterm>
+        <primary><varname>recovery_target_time</> configuration parameter</primary>
+       </indexterm>
+       <listitem>
+        <para>
+         Specifies the time stamp up to which recovery will proceed.
+         This parameter must be specified in the date/time format
+         (see <xref linkend="datatype-datetime-input"> for details).
+         At most one of <varname>recovery_target_time</>,
+         <varname>recovery_target_name</> or
+         <varname>recovery_target_xid</> can be specified.
+         The default value is an empty string, which will recover to
+         the end of the WAL log. The precise stopping point is also
+         influenced by <varname>recovery_target_inclusive</>.
+        </para>
+        <para>
+         This parameter can only be set in the <filename>postgresql.conf</>
+         file or on the server command line. It only has effect during archive
+         recovery or in standby mode.
+        </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry id="guc-recovery-target-xid" xreflabel="recovery_target_xid">
+       <term><varname>recovery_target_xid</varname> (<type>string</type>)</term>
+       <indexterm>
+        <primary><varname>recovery_target_xid</> configuration parameter</primary>
+       </indexterm>
+       <listitem>
+        <para>
+         Specifies the transaction ID up to which recovery will proceed.
+         Keep in mind that while transaction IDs are assigned sequentially
+         at transaction 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</>,
+         <varname>recovery_target_name</> or
+         <varname>recovery_target_time</> can be specified.
+         The default value is an empty string, which will recover to the end of
+         the WAL log. The precise stopping point is also influenced by
+         <varname>recovery_target_inclusive</>.
+        </para>
+        <para>
+         This parameter can only be set in the <filename>postgresql.conf</>
+         file or on the server command line. It only has effect during archive
+         recovery or in standby mode.
+        </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry id="guc-recovery-target-inclusive" xreflabel="recovery_target_inclusive">
+       <term><varname>recovery_target_inclusive</varname> (<type>boolean</type>)</term>
+       <indexterm>
+        <primary><varname>recovery_target_inclusive</> configuration parameter</primary>
+       </indexterm>
+       <listitem>
+        <para>
+         Specifies whether we stop just after the specified recovery target
+         (<literal>on</>), or just before the recovery target (<literal>off</>).
+         Applies to both <varname>recovery_target_time</>
+         and <varname>recovery_target_xid</>, whichever one is
+         specified for this recovery.  This indicates whether transactions
+         having exactly the target commit time or ID, respectively, will
+         be included in the recovery.  Default is <literal>on</>.
+        </para>
+        <para>
+         This parameter can only be set in the <filename>postgresql.conf</>
+         file or on the server command line. It only has effect during archive
+         recovery or in standby mode.
+        </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry id="guc-recovery-target-timeline" xreflabel="recovery_target_timeline">
+       <term><varname>recovery_target_timeline</varname> (<type>string</type>)</term>
+       <indexterm>
+        <primary><varname>recovery_target_timeline</> configuration parameter</primary>
+       </indexterm>
+       <listitem>
+        <para>
+         Specifies recovering into a particular timeline.  The default value is
+         an empty string, which will recover along the same timeline that was
+         current when the base backup was taken. Setting this to
+         <literal>latest</> recovers to the latest timeline found in the archive,
+         which is useful in a standby server. Other than that you only need to
+         set this parameter in complex re-recovery situations, where you need
+         to return to a state that itself was reached after a point-in-time
+         recovery. See <xref linkend="backup-timelines"> for discussion.
+        </para>
+        <para>
+         This parameter can only be set at server start. It only has effect
+         during archive recovery or in standby mode.
+        </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry id="guc-pause-at-recovery-target" xreflabel="pause_at_recovery_target">
+       <term><varname>pause_at_recovery_target</varname> (<type>boolean</type>)</term>
+       <indexterm>
+        <primary><varname>pause_at_recovery_target</> configuration parameter</primary>
+       </indexterm>
+       <listitem>
+        <para>
+         Specifies whether recovery should pause when the recovery target
+         is reached. The default is <literal>on</>.
+         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
+         <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
+         recovery target settings to a later target and restart to
+         continue recovery.
+        </para>
+        <para>
+         This parameter can only be set in the <filename>postgresql.conf</>
+         file or on the server command line. It only has effect during archive
+         recovery or in standby mode if recovery target is set.
+        </para>
+       </listitem>
+      </varlistentry>
+     </variablelist>
+     </sect2>
+
    </sect1>
 
    <sect1 id="runtime-config-replication">
@@ -2382,6 +2654,93 @@ include 'filename'
 
     <variablelist>
 
+     <varlistentry id="guc-standby-mode" xreflabel="standby_mode">
+      <term><varname>standby_mode</varname> (<type>boolean</type>)</term>
+      <indexterm>
+       <primary><varname>standby_mode</> configuration parameter</primary>
+      </indexterm>
+      <listitem>
+       <para>
+        Specifies whether to start the <productname>PostgreSQL</> server as
+        a standby when the file called <filename>standby.enabled</> exists.
+        The default value is <literal>off</>.
+        If this parameter is <literal>on</>, the server will not
+        stop recovery when the end of archived WAL is reached,
+        but will keep trying to continue recovery by fetching new WAL segments
+        using <varname>restore_command</> and/or by connecting to
+        the primary server as specified by the <varname>primary_conninfo</>
+        setting.
+       </para>
+       <para>
+        This parameter can only be set at server start. It only has effect
+        if file <filename>standby.enabled</> exists.
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry id="guc-primary-conninfo" xreflabel="primary_conninfo">
+      <term><varname>primary_conninfo</varname> (<type>string</type>)</term>
+      <indexterm>
+        <primary><varname>primary_conninfo</> configuration parameter</primary>
+      </indexterm>
+      <listitem>
+       <para>
+        Specifies a connection string to be used for the standby server
+        to connect with the primary. This string is in the format
+        accepted by the libpq <function>PQconnectdb</function> function,
+        described in <xref linkend="libpq-connect">. If any option is
+        unspecified in this string, then the corresponding environment
+        variable (see <xref linkend="libpq-envars">) is checked. If the
+        environment variable is not set either, then defaults are used.
+        If this parameter is an empty string (the default), no attempt is
+        made to connect to the master.
+       </para>
+       <para>
+        The connection string should specify the host name (or address)
+        of the primary server, as well as the port number if it is not
+        the same as the standby server's default.
+        Also specify a user name corresponding to a role that has the
+        <literal>REPLICATION</> and <literal>LOGIN</> privileges on the
+        primary (see
+        <xref linkend="streaming-replication-authentication">).
+        A password needs to be provided too, if the primary demands password
+        authentication.  It can be provided in the
+        <varname>primary_conninfo</varname> string, or in a separate
+        <filename>~/.pgpass</> file on the standby server (use
+        <literal>replication</> as the database name).
+        Do not specify a database name in the
+        <varname>primary_conninfo</varname> string.
+       </para>
+       <para>
+        This parameter can only be set in the <filename>postgresql.conf</>
+        file or on the server command line. It only has effect in standby mode.
+       </para>
+       <para>
+        If this parameter is changed while replication is in progress,
+        the standby terminates replication, and then tries to restart
+        replication with new setting.
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry id="guc-trigger-file" xreflabel="trigger_file">
+      <term><varname>trigger_file</varname> (<type>string</type>)</term>
+      <indexterm>
+        <primary><varname>trigger_file</> configuration parameter</primary>
+      </indexterm>
+      <listitem>
+       <para>
+        Specifies a trigger file whose presence ends recovery in the
+        standby.  Even if this value is not set, you can still promote
+        the standby using <command>pg_ctl promote</>.
+       </para>
+       <para>
+        This parameter can only be set in the <filename>postgresql.conf</>
+        file or on the server command line. It only has effect in standby mode.
+       </para>
+      </listitem>
+    </varlistentry>
+
      <varlistentry id="guc-hot-standby" xreflabel="hot_standby">
       <term><varname>hot_standby</varname> (<type>boolean</type>)</term>
       <indexterm>
diff --git a/doc/src/sgml/filelist.sgml b/doc/src/sgml/filelist.sgml
index b623f58..2eef816 100644
--- a/doc/src/sgml/filelist.sgml
+++ b/doc/src/sgml/filelist.sgml
@@ -43,7 +43,6 @@
 <!ENTITY manage-ag     SYSTEM "manage-ag.sgml">
 <!ENTITY monitoring    SYSTEM "monitoring.sgml">
 <!ENTITY regress       SYSTEM "regress.sgml">
-<!ENTITY recovery-config SYSTEM "recovery-config.sgml">
 <!ENTITY runtime       SYSTEM "runtime.sgml">
 <!ENTITY config        SYSTEM "config.sgml">
 <!ENTITY user-manag    SYSTEM "user-manag.sgml">
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 372e2b6..cd50730 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -14739,7 +14739,7 @@ postgres=# select pg_start_backup('label_goes_here');
     <function>pg_create_restore_point</> creates a named transaction log
     record that can be used as recovery target, and returns the corresponding
     transaction log location.  The given name can then be used with
-    <xref linkend="recovery-target-name"> to specify the point up to which
+    <xref linkend="guc-recovery-target-name"> to specify the point up to which
     recovery will proceed.  Avoid creating multiple restore points with the
     same name, since recovery will stop at the first one whose name matches
     the recovery target.
diff --git a/doc/src/sgml/high-availability.sgml b/doc/src/sgml/high-availability.sgml
index c8f6fa8..a2993f5 100644
--- a/doc/src/sgml/high-availability.sgml
+++ b/doc/src/sgml/high-availability.sgml
@@ -591,7 +591,7 @@ protocol to make nodes agree on a serializable transactional order.
    <para>
     In standby mode, the server continuously applies WAL received from the
     master server. The standby server can read WAL from a WAL archive
-    (see <xref linkend="restore-command">) or directly from the master
+    (see <xref linkend="guc-restore-command">) or directly from the master
     over a TCP connection (streaming replication). The standby server will
     also attempt to restore any WAL found in the standby cluster's
     <filename>pg_xlog</> directory. That typically happens after a server
@@ -658,8 +658,8 @@ protocol to make nodes agree on a serializable transactional order.
    <para>
     To set up the standby server, restore the base backup taken from primary
     server (see <xref linkend="backup-pitr-recovery">). Create a recovery
-    command file <filename>recovery.conf</> in the standby's cluster data
-    directory, and turn on <varname>standby_mode</>. Set
+    trigger file <filename>standby.enabled</> in the standby's cluster data
+    directory. Turn on <varname>standby_mode</> and set
     <varname>restore_command</> to a simple command to copy files from
     the WAL archive. If you plan to have multiple standby servers for high
     availability purposes, set <varname>recovery_target_timeline</> to
@@ -695,7 +695,7 @@ protocol to make nodes agree on a serializable transactional order.
 
    <para>
     If you're using a WAL archive, its size can be minimized using the <xref
-    linkend="archive-cleanup-command"> parameter to remove files that are no
+    linkend="guc-archive-cleanup-command"> parameter to remove files that are no
     longer required by the standby server.
     The <application>pg_archivecleanup</> utility is designed specifically to
     be used with <varname>archive_cleanup_command</> in typical single-standby
@@ -706,7 +706,7 @@ protocol to make nodes agree on a serializable transactional order.
    </para>
 
    <para>
-    A simple example of a <filename>recovery.conf</> is:
+    A simple example of standby settings is:
 <programlisting>
 standby_mode = 'on'
 primary_conninfo = 'host=192.168.1.50 port=5432 user=foo password=foopass'
@@ -763,8 +763,8 @@ archive_cleanup_command = 'pg_archivecleanup /path/to/archive %r'
     To use streaming replication, set up a file-based log-shipping standby
     server as described in <xref linkend="warm-standby">. The step that
     turns a file-based log-shipping standby into streaming replication
-    standby is setting <varname>primary_conninfo</> setting in the
-    <filename>recovery.conf</> file to point to the primary server. Set
+    standby is setting <varname>primary_conninfo</> to
+    point to the primary server. Set
     <xref linkend="guc-listen-addresses"> and authentication options
     (see <filename>pg_hba.conf</>) on the primary so that the standby server
     can connect to the <literal>replication</> pseudo-database on the primary
@@ -824,15 +824,14 @@ host    replication     foo             192.168.1.100/32        md5
     </para>
     <para>
      The host name and port number of the primary, connection user name,
-     and password are specified in the <filename>recovery.conf</> file.
+     and password are specified in <varname>primary_conninfo</>.
      The password can also be set in the <filename>~/.pgpass</> file on the
      standby (specify <literal>replication</> in the <replaceable>database</>
      field).
      For example, if the primary is running on host IP <literal>192.168.1.50</>,
      port <literal>5432</literal>, the account name for replication is
      <literal>foo</>, and the password is <literal>foopass</>, the administrator
-     can add the following line to the <filename>recovery.conf</> file on the
-     standby:
+     can set <varname>primary_conninfo</> on the standby like this:
 
 <programlisting>
 # The standby connects to the primary that is running on host 192.168.1.50
@@ -1212,8 +1211,8 @@ primary_conninfo = 'host=192.168.1.50 port=5432 user=foo password=foopass'
    <para>
     To trigger failover of a log-shipping standby server,
     run <command>pg_ctl promote</> or create a trigger
-    file with the file name and path specified by the <varname>trigger_file</>
-    setting in <filename>recovery.conf</>. If you're planning to use
+    file with the file name and path specified by the <varname>trigger_file</>.
+    If you're planning to use
     <command>pg_ctl promote</> to fail over, <varname>trigger_file</> is
     not required. If you're setting up the reporting servers that are
     only used to offload read-only queries from the primary, not for high
@@ -1258,8 +1257,7 @@ primary_conninfo = 'host=192.168.1.50 port=5432 user=foo password=foopass'
     The magic that makes the two loosely coupled servers work together is
     simply a <varname>restore_command</> used on the standby that,
     when asked for the next WAL file, waits for it to become available from
-    the primary. The <varname>restore_command</> is specified in the
-    <filename>recovery.conf</> file on the standby server. Normal recovery
+    the primary. Normal recovery
     processing would request a file from the WAL archive, reporting failure
     if the file was unavailable.  For standby processing it is normal for
     the next WAL file to be unavailable, so the standby must wait for
@@ -1346,8 +1344,14 @@ if (!triggered)
      </listitem>
      <listitem>
       <para>
+       Create a file called <filename>standby.enabled</> in the standby's
+       cluster data directory to trigger the recovery.
+      </para>
+     </listitem>
+     <listitem>
+      <para>
        Begin recovery on the standby server from the local WAL
-       archive, using a <filename>recovery.conf</> that specifies a
+       archive, specifying a
        <varname>restore_command</> that waits as described
        previously (see <xref linkend="backup-pitr-recovery">).
       </para>
@@ -1838,9 +1842,8 @@ if (!triggered)
    <title>Administrator's Overview</title>
 
    <para>
-    If <varname>hot_standby</> is turned <literal>on</> in
-    <filename>postgresql.conf</> and there is a <filename>recovery.conf</>
-    file present, the server will run in Hot Standby mode.
+    If <varname>hot_standby</> is turned <literal>on</> and there is a file
+    <filename>standby.enabled</> present, the server will run in Hot Standby mode.
     However, it may take some time for Hot Standby connections to be allowed,
     because the server will not accept connections until it has completed
     sufficient recovery to provide a consistent state against which queries
diff --git a/doc/src/sgml/pgarchivecleanup.sgml b/doc/src/sgml/pgarchivecleanup.sgml
index 932914b..2984da4 100644
--- a/doc/src/sgml/pgarchivecleanup.sgml
+++ b/doc/src/sgml/pgarchivecleanup.sgml
@@ -38,8 +38,8 @@
 
   <para>
    To configure a standby
-   server to use <application>pg_archivecleanup</>, put this into its
-   <filename>recovery.conf</filename> configuration file:
+   server to use <application>pg_archivecleanup</>, specify
+   <xref linkend="guc-archive-cleanup-command"> like this:
 <programlisting>
 archive_cleanup_command = 'pg_archivecleanup <replaceable>archivelocation</> %r'
 </programlisting>
@@ -47,7 +47,7 @@ archive_cleanup_command = 'pg_archivecleanup <replaceable>archivelocation</> %r'
    files should be removed.
   </para>
   <para>
-   When used within <xref linkend="archive-cleanup-command">, all WAL files
+   When used within <varname>archive_cleanup_command</>, all WAL files
    logically preceding the value of the <literal>%r</> argument will be removed
    from <replaceable>archivelocation</>. This minimizes the number of files
    that need to be retained, while preserving crash-restart capability.  Use of
diff --git a/doc/src/sgml/pgstandby.sgml b/doc/src/sgml/pgstandby.sgml
index ca2b5c0..15097ca 100644
--- a/doc/src/sgml/pgstandby.sgml
+++ b/doc/src/sgml/pgstandby.sgml
@@ -46,8 +46,8 @@
 
   <para>
    To configure a standby
-   server to use <application>pg_standby</>, put this into its
-   <filename>recovery.conf</filename> configuration file:
+   server to use <application>pg_standby</>, specify
+   <xref linkend="guc-restore-command"> like this:
 <programlisting>
 restore_command = 'pg_standby <replaceable>archiveDir</> %f %p %r'
 </programlisting>
diff --git a/doc/src/sgml/postgres.sgml b/doc/src/sgml/postgres.sgml
index 15e4ef6..26e8dc2 100644
--- a/doc/src/sgml/postgres.sgml
+++ b/doc/src/sgml/postgres.sgml
@@ -155,7 +155,6 @@
   &maintenance;
   &backup;
   &high-availability;
-  &recovery-config;
   &monitoring;
   &diskusage;
   &wal;
diff --git a/doc/src/sgml/recovery-config.sgml b/doc/src/sgml/recovery-config.sgml
deleted file mode 100644
index c0c543e..0000000
--- a/doc/src/sgml/recovery-config.sgml
+++ /dev/null
@@ -1,361 +0,0 @@
-<!-- doc/src/sgml/recovery-config.sgml -->
-
-<chapter id="recovery-config">
-  <title>Recovery Configuration</title>
-
-  <indexterm>
-   <primary>configuration</primary>
-   <secondary>of recovery</secondary>
-   <tertiary>of a standby server</tertiary>
-  </indexterm>
-
-   <para>
-    This chapter describes the settings available in the
-    <filename>recovery.conf</><indexterm><primary>recovery.conf</></>
-    file. They apply only for the duration of the
-    recovery.  They must be reset for any subsequent recovery you wish to
-    perform.  They cannot be changed once recovery has begun.
-   </para>
-
-   <para>
-     Settings in <filename>recovery.conf</> are specified in the format
-     <literal>name = 'value'</>. One parameter is specified per line.
-     Hash marks (<literal>#</literal>) designate the rest of the
-     line as a comment.  To embed a single quote in a parameter
-     value, write two quotes (<literal>''</>).
-   </para>
-
-   <para>
-    A sample file, <filename>share/recovery.conf.sample</>,
-    is provided in the installation's <filename>share/</> directory.
-   </para>
-
-  <sect1 id="archive-recovery-settings">
-
-    <title>Archive Recovery Settings</title>
-     <variablelist>
-
-     <varlistentry id="restore-command" xreflabel="restore_command">
-      <term><varname>restore_command</varname> (<type>string</type>)</term>
-      <indexterm>
-        <primary><varname>restore_command</> recovery parameter</primary>
-      </indexterm>
-      <listitem>
-       <para>
-        The shell command to execute to retrieve an archived segment of
-        the WAL file series. This parameter is required for archive recovery,
-        but optional for streaming replication.
-        Any <literal>%f</> in the string is
-        replaced by the name of the file to retrieve from the archive,
-        and any <literal>%p</> is replaced by the copy destination path name
-        on the server.
-        (The path name is relative to the current working directory,
-        i.e., the cluster's data directory.)
-        Any <literal>%r</> is replaced by the name of the file containing the
-        last valid restart point. That is the earliest file that must be kept
-        to allow a restore to be restartable, so this information can be used
-        to truncate the archive to just the minimum required to support
-        restarting from the current restore. <literal>%r</> is typically only
-        used by warm-standby configurations
-        (see <xref linkend="warm-standby">).
-        Write <literal>%%</> to embed an actual <literal>%</> character.
-       </para>
-
-       <para>
-        It is important for the command to return a zero exit status
-        only if it succeeds.  The command <emphasis>will</> be asked for file
-        names that are not present in the archive; it must return nonzero
-        when so asked.  Examples:
-<programlisting>
-restore_command = 'cp /mnt/server/archivedir/%f "%p"'
-restore_command = 'copy "C:\\server\\archivedir\\%f" "%p"'  # Windows
-</programlisting>
-       </para>
-      </listitem>
-     </varlistentry>
-
-     <varlistentry id="archive-cleanup-command" xreflabel="archive_cleanup_command">
-      <term><varname>archive_cleanup_command</varname> (<type>string</type>)</term>
-      <indexterm>
-        <primary><varname>archive_cleanup_command</> recovery parameter</primary>
-      </indexterm>
-      <listitem>
-       <para>
-        This optional parameter specifies a shell command that will be executed
-        at every restartpoint.  The purpose of
-        <varname>archive_cleanup_command</> is to provide a mechanism for
-        cleaning up old archived WAL files that are no longer needed by the
-        standby server.
-        Any <literal>%r</> is replaced by the name of the file containing the
-        last valid restart point.
-        That is the earliest file that must be <emphasis>kept</> to allow a
-        restore to be restartable, and so all files earlier than <literal>%r</>
-        may be safely removed.
-        This information can be used to truncate the archive to just the
-        minimum required to support restart from the current restore.
-        The <xref linkend="pgarchivecleanup"> module
-        is often used in <varname>archive_cleanup_command</> for
-        single-standby configurations, for example:
-<programlisting>archive_cleanup_command = 'pg_archivecleanup /mnt/server/archivedir %r'</programlisting>
-        Note however that if multiple standby servers are restoring from the
-        same archive directory, you will need to ensure that you do not delete
-        WAL files until they are no longer needed by any of the servers.
-        <varname>archive_cleanup_command</> would typically be used in a
-        warm-standby configuration (see <xref linkend="warm-standby">).
-        Write <literal>%%</> to embed an actual <literal>%</> character in the
-        command.
-       </para>
-       <para>
-        If the command returns a non-zero exit status then a WARNING log
-        message will be written.
-       </para>
-      </listitem>
-     </varlistentry>
-
-     <varlistentry id="recovery-end-command" xreflabel="recovery_end_command">
-      <term><varname>recovery_end_command</varname> (<type>string</type>)</term>
-      <indexterm>
-        <primary><varname>recovery_end_command</> recovery parameter</primary>
-      </indexterm>
-      <listitem>
-       <para>
-        This parameter specifies a shell command that will be executed once only
-        at the end of recovery. This parameter is optional. The purpose of the
-        <varname>recovery_end_command</> is to provide a mechanism for cleanup
-        following replication or recovery.
-        Any <literal>%r</> is replaced by the name of the file containing the
-        last valid restart point, like in <xref linkend="archive-cleanup-command">.
-       </para>
-       <para>
-        If the command returns a non-zero exit status then a WARNING log
-        message will be written and the database will proceed to start up
-        anyway.  An exception is that if the command was terminated by a
-        signal, the database will not proceed with startup.
-       </para>
-      </listitem>
-     </varlistentry>
-
-    </variablelist>
-
-  </sect1>
-
-  <sect1 id="recovery-target-settings">
-
-    <title>Recovery Target Settings</title>
-     <variablelist>
-
-     <varlistentry id="recovery-target-name" xreflabel="recovery_target_name">
-      <term><varname>recovery_target_name</varname>
-           (<type>string</type>)
-      </term>
-      <indexterm>
-        <primary><varname>recovery_target_name</> recovery parameter</primary>
-      </indexterm>
-      <listitem>
-       <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>
-
-     <varlistentry id="recovery-target-time" xreflabel="recovery_target_time">
-      <term><varname>recovery_target_time</varname>
-           (<type>timestamp</type>)
-      </term>
-      <indexterm>
-        <primary><varname>recovery_target_time</> recovery parameter</primary>
-      </indexterm>
-      <listitem>
-       <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>
-      </listitem>
-     </varlistentry>
-
-     <varlistentry id="recovery-target-xid" xreflabel="recovery_target_xid">
-      <term><varname>recovery_target_xid</varname> (<type>string</type>)</term>
-      <indexterm>
-        <primary><varname>recovery_target_xid</> recovery parameter</primary>
-      </indexterm>
-      <listitem>
-       <para>
-        This parameter specifies the transaction ID up to which recovery
-        will proceed. Keep in mind
-        that while transaction IDs are assigned sequentially at transaction
-        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>
-
-     <varlistentry id="recovery-target-inclusive"
-                   xreflabel="recovery_target_inclusive">
-      <term><varname>recovery_target_inclusive</varname>
-        (<type>boolean</type>)
-      </term>
-      <indexterm>
-        <primary><varname>recovery_target_inclusive</> recovery parameter</primary>
-      </indexterm>
-      <listitem>
-       <para>
-        Specifies whether we stop just after the specified recovery target
-        (<literal>true</literal>), or just before the recovery target
-        (<literal>false</literal>).
-        Applies to both <xref linkend="recovery-target-time">
-        and <xref linkend="recovery-target-xid">, whichever one is
-        specified for this recovery.  This indicates whether transactions
-        having exactly the target commit time or ID, respectively, will
-        be included in the recovery.  Default is <literal>true</>.
-       </para>
-      </listitem>
-     </varlistentry>
-
-     <varlistentry id="recovery-target-timeline"
-                   xreflabel="recovery_target_timeline">
-      <term><varname>recovery_target_timeline</varname>
-        (<type>string</type>)
-      </term>
-      <indexterm>
-        <primary><varname>recovery_target_timeline</> recovery parameter</primary>
-      </indexterm>
-      <listitem>
-       <para>
-        Specifies recovering into a particular timeline.  The default is
-        to recover along the same timeline that was current when the
-        base backup was taken. Setting this to <literal>latest</> recovers
-        to the latest timeline found in the archive, which is useful in
-        a standby server. Other than that you only need to set this parameter
-        in complex re-recovery situations, where you need to return to
-        a state that itself was reached after a point-in-time recovery.
-        See <xref linkend="backup-timelines"> for discussion.
-       </para>
-      </listitem>
-     </varlistentry>
-
-     <varlistentry id="pause-at-recovery-target"
-                   xreflabel="pause_at_recovery_target">
-      <term><varname>pause_at_recovery_target</varname>
-        (<type>boolean</type>)
-      </term>
-      <indexterm>
-        <primary><varname>pause_at_recovery_target</> recovery parameter</primary>
-      </indexterm>
-      <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
-        <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
-        recovery target settings to a later target and restart to
-        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.
-       </para>
-      </listitem>
-     </varlistentry>
-
-     </variablelist>
-   </sect1>
-
-  <sect1 id="standby-settings">
-
-    <title>Standby Server Settings</title>
-     <variablelist>
-
-       <varlistentry id="standby-mode" xreflabel="standby_mode">
-        <term><varname>standby_mode</varname> (<type>boolean</type>)</term>
-        <indexterm>
-          <primary><varname>standby_mode</> recovery parameter</primary>
-        </indexterm>
-        <listitem>
-         <para>
-          Specifies whether to start the <productname>PostgreSQL</> server as
-          a standby. If this parameter is <literal>on</>, the server will
-          not stop recovery when the end of archived WAL is reached, but
-          will keep trying to continue recovery by fetching new WAL segments
-          using <varname>restore_command</>
-          and/or by connecting to the primary server as specified by the
-          <varname>primary_conninfo</> setting.
-         </para>
-        </listitem>
-       </varlistentry>
-       <varlistentry id="primary-conninfo" xreflabel="primary_conninfo">
-        <term><varname>primary_conninfo</varname> (<type>string</type>)</term>
-        <indexterm>
-          <primary><varname>primary_conninfo</> recovery parameter</primary>
-        </indexterm>
-        <listitem>
-         <para>
-          Specifies a connection string to be used for the standby server
-          to connect with the primary. This string is in the format
-          described in <xref linkend="libpq-connstring">. If any option is
-          unspecified in this string, then the corresponding environment
-          variable (see <xref linkend="libpq-envars">) is checked. If the
-          environment variable is not set either, then
-          defaults are used.
-         </para>
-         <para>
-          The connection string should specify the host name (or address)
-          of the primary server, as well as the port number if it is not
-          the same as the standby server's default.
-          Also specify a user name corresponding to a suitably-privileged role
-          on the primary (see
-          <xref linkend="streaming-replication-authentication">).
-          A password needs to be provided too, if the primary demands password
-          authentication.  It can be provided in the
-          <varname>primary_conninfo</varname> string, or in a separate
-          <filename>~/.pgpass</> file on the standby server (use
-          <literal>replication</> as the database name).
-          Do not specify a database name in the
-          <varname>primary_conninfo</varname> string.
-         </para>
-         <para>
-          This setting has no effect if <varname>standby_mode</> is <literal>off</>.
-         </para>
-        </listitem>
-       </varlistentry>
-       <varlistentry id="trigger-file" xreflabel="trigger_file">
-        <term><varname>trigger_file</varname> (<type>string</type>)</term>
-        <indexterm>
-          <primary><varname>trigger_file</> recovery parameter</primary>
-        </indexterm>
-        <listitem>
-         <para>
-          Specifies a trigger file whose presence ends recovery in the
-          standby.  Even if this value is not set, you can still promote
-          the standby using <command>pg_ctl promote</>.
-          This setting has no effect if <varname>standby_mode</> is <literal>off</>.
-         </para>
-        </listitem>
-       </varlistentry>
-
-     </variablelist>
-   </sect1>
-
-</chapter>
diff --git a/doc/src/sgml/release-9.1.sgml b/doc/src/sgml/release-9.1.sgml
index b524477..f10e02f 100644
--- a/doc/src/sgml/release-9.1.sgml
+++ b/doc/src/sgml/release-9.1.sgml
@@ -4279,7 +4279,7 @@
       <listitem>
        <para>
         Add <filename>recovery.conf</> setting <link
-        linkend="pause-at-recovery-target"><varname>pause_at_recovery_target</></link>
+        linkend="guc-pause-at-recovery-target"><varname>pause_at_recovery_target</></link>
         to pause recovery at target (Simon Riggs)
        </para>
 
@@ -4299,7 +4299,7 @@
        <para>
         These named restore points can be specified as recovery
         targets using the new <filename>recovery.conf</> setting
-        <link linkend="recovery-target-name"><varname>recovery_target_name</></link>.
+        <link linkend="guc-recovery-target-name"><varname>recovery_target_name</></link>.
        </para>
       </listitem>
 
@@ -4331,8 +4331,7 @@
 
       <listitem>
        <para>
-        Allow <link
-        linkend="recovery-config"><filename>recovery.conf</></link>
+        Allow <filename>recovery.conf</>
         to use the same quoting behavior as <filename>postgresql.conf</>
         (Dimitri Fontaine)
        </para>
diff --git a/doc/src/sgml/release.sgml b/doc/src/sgml/release.sgml
index 2515329..252bf13 100644
--- a/doc/src/sgml/release.sgml
+++ b/doc/src/sgml/release.sgml
@@ -5,8 +5,8 @@ Typical markup:
 
 &<>                             use & escapes
 PostgreSQL                      <productname>
-postgresql.conf, pg_hba.conf,
-        recovery.conf           <filename>
+postgresql.conf, pg_hba.conf
+        standby.enabled         <filename>
 [A-Z][A-Z_ ]+[A-Z_]             <command>, <literal>, <envar>
 [A-Za-z_][A-Za-z0-9_]+()        <function>
 -[-A-Za-z_]+                    <option>
diff --git a/src/backend/Makefile b/src/backend/Makefile
index 318cdbc..58d42c5 100644
--- a/src/backend/Makefile
+++ b/src/backend/Makefile
@@ -225,7 +225,6 @@ endif
 	$(INSTALL_DATA) $(srcdir)/libpq/pg_hba.conf.sample '$(DESTDIR)$(datadir)/pg_hba.conf.sample'
 	$(INSTALL_DATA) $(srcdir)/libpq/pg_ident.conf.sample '$(DESTDIR)$(datadir)/pg_ident.conf.sample'
 	$(INSTALL_DATA) $(srcdir)/utils/misc/postgresql.conf.sample '$(DESTDIR)$(datadir)/postgresql.conf.sample'
-	$(INSTALL_DATA) $(srcdir)/access/transam/recovery.conf.sample '$(DESTDIR)$(datadir)/recovery.conf.sample'
 
 install-bin: postgres $(POSTGRES_IMP) installdirs
 	$(INSTALL_PROGRAM) postgres$(X) '$(DESTDIR)$(bindir)/postgres$(X)'
@@ -282,8 +281,7 @@ endif
 	$(MAKE) -C tsearch uninstall-data
 	rm -f '$(DESTDIR)$(datadir)/pg_hba.conf.sample' \
 	      '$(DESTDIR)$(datadir)/pg_ident.conf.sample' \
-              '$(DESTDIR)$(datadir)/postgresql.conf.sample' \
-	      '$(DESTDIR)$(datadir)/recovery.conf.sample'
+              '$(DESTDIR)$(datadir)/postgresql.conf.sample'
 
 
 ##########################################################################
diff --git a/src/backend/access/transam/recovery.conf.sample b/src/backend/access/transam/recovery.conf.sample
deleted file mode 100644
index 5acfa57..0000000
--- a/src/backend/access/transam/recovery.conf.sample
+++ /dev/null
@@ -1,132 +0,0 @@
-# -------------------------------
-# PostgreSQL recovery config file
-# -------------------------------
-#
-# Edit this file to provide the parameters that PostgreSQL needs to
-# perform an archive recovery of a database, or to act as a replication
-# standby.
-#
-# If "recovery.conf" is present in the PostgreSQL data directory, it is
-# read on postmaster startup.  After successful recovery, it is renamed
-# to "recovery.done" to ensure that we do not accidentally re-enter
-# archive recovery or standby mode.
-#
-# This file consists of lines of the form:
-#
-#   name = value
-#
-# Comments are introduced with '#'.
-#
-# The complete list of option names and allowed values can be found
-# in the PostgreSQL documentation.
-#
-#---------------------------------------------------------------------------
-# ARCHIVE RECOVERY PARAMETERS
-#---------------------------------------------------------------------------
-#
-# restore_command
-#
-# specifies the shell command that is executed to copy log files
-# back from archival storage.  The command string may contain %f,
-# which is replaced by the name of the desired log file, and %p,
-# which is replaced by the absolute path to copy the log file to.
-#
-# This parameter is *required* for an archive recovery, but optional
-# for streaming replication.
-#
-# It is important that the command return nonzero exit status on failure.
-# The command *will* be asked for log files that are not present in the
-# archive; it must return nonzero when so asked.
-#
-# NOTE that the basename of %p will be different from %f; do not
-# expect them to be interchangeable.
-#
-#restore_command = ''		# e.g. 'cp /mnt/server/archivedir/%f %p'
-#
-#
-# archive_cleanup_command
-#
-# specifies an optional shell command to execute at every restartpoint.
-# This can be useful for cleaning up the archive of a standby server.
-#
-#archive_cleanup_command = ''
-#
-# recovery_end_command
-#
-# specifies an optional shell command to execute at completion of recovery.
-# This can be useful for cleaning up after the restore_command.
-#
-#recovery_end_command = ''
-#
-#---------------------------------------------------------------------------
-# RECOVERY TARGET PARAMETERS
-#---------------------------------------------------------------------------
-#
-# By default, recovery will rollforward to the end of the WAL log.
-# If you want to stop rollforward at a specific point, you
-# must set a recovery target.
-#
-# You may set a recovery target either by transactionId, by name,
-# or by timestamp. Recovery may either include or exclude the
-# transaction(s) with the recovery target value (ie, stop either
-# just after or just before the given target, respectively).
-#
-#
-#recovery_target_name = ''	# e.g. 'daily backup 2011-01-26'
-#
-#recovery_target_time = ''	# e.g. '2004-07-14 22:39:00 EST'
-#
-#recovery_target_xid = ''
-#
-#recovery_target_inclusive = true
-#
-#
-# If you want to recover into a timeline other than the "main line" shown in
-# pg_control, specify the timeline number here, or write 'latest' to get
-# the latest branch for which there's a history file.
-#
-#recovery_target_timeline = 'latest'
-#
-#
-# If pause_at_recovery_target is enabled, recovery will pause when
-# the recovery target is reached. The pause state will continue until
-# pg_xlog_replay_resume() is called. This setting has no effect if
-# hot standby is not enabled, or if no recovery target is set.
-#
-#pause_at_recovery_target = true
-#
-#---------------------------------------------------------------------------
-# STANDBY SERVER PARAMETERS
-#---------------------------------------------------------------------------
-#
-# standby_mode
-#
-# When standby_mode is enabled, the PostgreSQL server will work as a
-# standby. It will continuously wait for the additional XLOG records, using
-# restore_command and/or primary_conninfo.
-#
-#standby_mode = off
-#
-# primary_conninfo
-#
-# If set, the PostgreSQL server will try to connect to the primary using this
-# connection string and receive XLOG records continuously.
-#
-#primary_conninfo = ''		# e.g. 'host=localhost port=5432'
-#
-#
-# By default, a standby server keeps restoring XLOG records from the
-# primary indefinitely. If you want to stop the standby mode, finish recovery
-# and open the system in read/write mode, specify path to a trigger file.
-# The server will poll the trigger file path periodically and start as a
-# primary server when it's found.
-#
-#trigger_file = ''
-#
-#---------------------------------------------------------------------------
-# HOT STANDBY PARAMETERS
-#---------------------------------------------------------------------------
-#
-# Hot Standby related parameters are listed in postgresql.conf
-#
-#---------------------------------------------------------------------------
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index a02eebc..fce202f 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -63,11 +63,12 @@
 
 
 /* File path names (all relative to $PGDATA) */
-#define RECOVERY_COMMAND_FILE	"recovery.conf"
-#define RECOVERY_COMMAND_DONE	"recovery.done"
-#define PROMOTE_SIGNAL_FILE "promote"
+#define RECOVERY_ENABLE_FILE	"standby.enabled"
+#define PROMOTE_SIGNAL_FILE	"promote"
 #define FAST_PROMOTE_SIGNAL_FILE "fast_promote"
 
+/* recovery.conf is not supported anymore */
+#define RECOVERY_COMMAND_FILE	"recovery.conf"
 
 /* User-settable parameters */
 int			CheckPointSegments = 3;
@@ -83,6 +84,23 @@ int			sync_method = DEFAULT_SYNC_METHOD;
 int			wal_level = WAL_LEVEL_MINIMAL;
 int			CommitDelay = 0;	/* precommit delay in microseconds */
 int			CommitSiblings = 5; /* # concurrent xacts needed to sleep */
+char	   *restore_command = NULL;
+char	   *archive_cleanup_command = NULL;
+char	   *recovery_end_command = NULL;
+bool		StandbyModeRequested = false;
+char	   *primary_conninfo = NULL;
+char	   *trigger_file = NULL;
+RecoveryTargetType	recovery_target = RECOVERY_TARGET_UNSET;
+TransactionId		recovery_target_xid = InvalidTransactionId;
+TimestampTz			recovery_target_time = 0;
+char	   *recovery_target_name = NULL;
+bool		recovery_target_inclusive = true;
+bool		pause_at_recovery_target = true;
+char	   *recovery_target_timeline_string = NULL;
+TimeLineID	recovery_target_timeline = 0;
+
+/* are we currently in standby mode? */
+bool StandbyMode = false;
 
 #ifdef WAL_DEBUG
 bool		XLOG_DEBUG = false;
@@ -206,29 +224,11 @@ bool InArchiveRecovery = false;
 /* Was the last xlog file restored from archive, or local? */
 static bool restoredFromArchive = false;
 
-/* options 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 bool recoveryPauseAtTarget = true;
-static TransactionId recoveryTargetXid;
-static TimestampTz recoveryTargetTime;
-static char *recoveryTargetName;
-
-/* options taken from recovery.conf for XLOG streaming */
-static bool StandbyModeRequested = false;
-static char *PrimaryConnInfo = NULL;
-static char *TriggerFile = NULL;
-
-/* are we currently in standby mode? */
-bool StandbyMode = false;
-
 /* whether request for fast promotion has been made yet */
 static bool fast_promote = false;
 
 /* if recoveryStopsHere returns true, it saves actual stop xid/time/name here */
+static RecoveryTargetType recoveryStopTarget;
 static TransactionId recoveryStopXid;
 static TimestampTz recoveryStopTime;
 static char recoveryStopName[MAXFNAMELEN];
@@ -437,12 +437,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.
 	 */
@@ -631,7 +625,7 @@ static bool InRedo = false;
 static bool bgwriterLaunched = false;
 
 
-static void readRecoveryCommandFile(void);
+static void CheckRecoveryReadyFile(void);
 static void exitArchiveRecovery(TimeLineID endTLI, XLogSegNo endLogSegNo);
 static bool recoveryStopsHere(XLogRecord *record, bool *includeThis);
 static void recoveryPausesHere(void);
@@ -3309,7 +3303,7 @@ ReadRecord(XLogReaderState *xlogreader, XLogRecPtr RecPtr, int emode,
 				ereport(DEBUG1,
 						(errmsg_internal("reached end of WAL in pg_xlog, entering archive recovery")));
 				InArchiveRecovery = true;
-				if (StandbyModeRequested)
+				if (ArchiveRecoveryRequested && StandbyModeRequested)
 					StandbyMode = true;
 
 				/* initialize minRecoveryPoint to this record */
@@ -4120,212 +4114,47 @@ 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.
- *
- * The file is parsed using the main configuration parser.
+ * Check to see if there is a recovery trigger file (standby.enabled).
+ * If so, validate recovery parameters and determine recovery target timeline.
  */
 static void
-readRecoveryCommandFile(void)
+CheckRecoveryReadyFile(void)
 {
-	FILE	   *fd;
-	TimeLineID	rtli = 0;
-	bool		rtliGiven = false;
-	ConfigVariable *item,
-			   *head = NULL,
-			   *tail = NULL;
-
-	fd = AllocateFile(RECOVERY_COMMAND_FILE, "r");
+	FILE *fd;
+
+	/* Check the presence of recovery.conf, it is not supported anymore */
+	if (AllocateFile(RECOVERY_COMMAND_FILE, "r") != NULL)
+		ereport(FATAL,
+				(errmsg("\"%s\" is not supported anymore as a recovery method",
+						RECOVERY_COMMAND_FILE),
+				 errdetail("Refer to appropriate documentation about migration methods")));
+
+	/* Check the presence of file standby.enabled, the file triggering recovery */
+	fd = AllocateFile(RECOVERY_ENABLE_FILE, "r");
 	if (fd == NULL)
 	{
 		if (errno == ENOENT)
 			return;				/* not there, so no archive recovery */
 		ereport(FATAL,
 				(errcode_for_file_access(),
-				 errmsg("could not open recovery command file \"%s\": %m",
-						RECOVERY_COMMAND_FILE)));
-	}
-
-	/*
-	 * Since we're asking ParseConfigFp() to report errors as FATAL, there's
-	 * no need to check the return value.
-	 */
-	(void) ParseConfigFp(fd, RECOVERY_COMMAND_FILE, 0, FATAL, &head, &tail);
-
-	FreeFile(fd);
-
-	for (item = head; item; item = item->next)
-	{
-		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, "pause_at_recovery_target") == 0)
-		{
-			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)));
-		}
-		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,
-							(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,
-				 (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)
-		{
-			/*
-			 * if recovery_target_xid or recovery_target_name specified, then
-			 * this overrides recovery_target_time
-			 */
-			if (recoveryTarget == RECOVERY_TARGET_XID ||
-				recoveryTarget == RECOVERY_TARGET_NAME)
-				continue;
-			recoveryTarget = RECOVERY_TARGET_TIME;
-
-			/*
-			 * 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)
-		{
-			/*
-			 * if recovery_target_xid specified, then this overrides
-			 * recovery_target_name
-			 */
-			if (recoveryTarget == RECOVERY_TARGET_XID)
-				continue;
-			recoveryTarget = RECOVERY_TARGET_NAME;
-
-			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)));
-
-			ereport(DEBUG2,
-					(errmsg_internal("recovery_target_name = '%s'",
-									 recoveryTargetName)));
-		}
-		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, "trigger_file") == 0)
-		{
-			TriggerFile = pstrdup(item->value);
-			ereport(DEBUG2,
-					(errmsg_internal("trigger_file = '%s'",
-									 TriggerFile)));
-		}
-		else
-			ereport(FATAL,
-					(errmsg("unrecognized recovery parameter \"%s\"",
-							item->name)));
+				 errmsg("could not open recovery file trigger \"%s\": %m",
+						RECOVERY_ENABLE_FILE)));
 	}
 
-	/*
-	 * Check for compulsory parameters
-	 */
+	/* Check for compulsory parameters */
 	if (StandbyModeRequested)
 	{
-		if (PrimaryConnInfo == NULL && recoveryRestoreCommand == NULL)
+		if (!restore_command[0] && !primary_conninfo[0])
 			ereport(WARNING,
-					(errmsg("recovery command file \"%s\" specified neither primary_conninfo nor restore_command",
-							RECOVERY_COMMAND_FILE),
+					(errmsg("Neither primary_conninfo nor restore_command specified"),
 					 errhint("The database server will regularly poll the pg_xlog subdirectory to check for files placed there.")));
 	}
 	else
 	{
-		if (recoveryRestoreCommand == NULL)
+		if (!restore_command[0])
 			ereport(FATAL,
-					(errmsg("recovery command file \"%s\" must specify restore_command when standby mode is not enabled",
-							RECOVERY_COMMAND_FILE)));
+					(errmsg("restore_command must be specified when "
+							"standby_mode is not enabled")));
 	}
 
 	/* Enable fetching from archive recovery area */
@@ -4337,16 +4166,17 @@ readRecoveryCommandFile(void)
 	 * command and set InArchiveRecovery, because we need to fetch timeline
 	 * history files from the archive.
 	 */
-	if (rtliGiven)
+	if (strcmp(recovery_target_timeline_string, "") != 0)
 	{
-		if (rtli)
+		if (recovery_target_timeline)
 		{
 			/* Timeline 1 does not have a history file, all else should */
-			if (rtli != 1 && !existsTimeLineHistory(rtli))
+			if (recovery_target_timeline != 1 &&
+				!existsTimeLineHistory(recovery_target_timeline))
 				ereport(FATAL,
 						(errmsg("recovery target timeline %u does not exist",
-								rtli)));
-			recoveryTargetTLI = rtli;
+								recovery_target_timeline)));
+			recoveryTargetTLI = recovery_target_timeline;
 			recoveryTargetIsLatest = false;
 		}
 		else
@@ -4356,8 +4186,6 @@ readRecoveryCommandFile(void)
 			recoveryTargetIsLatest = true;
 		}
 	}
-
-	FreeConfigVariables(head);
 }
 
 /*
@@ -4428,15 +4256,13 @@ exitArchiveRecovery(TimeLineID endTLI, XLogSegNo endLogSegNo)
 	unlink(recoveryPath);		/* ignore any error */
 
 	/*
-	 * Rename the config file out of the way, so that we don't accidentally
-	 * re-enter archive recovery mode in a subsequent crash.
+	 * Remove file that triggered the recovery
 	 */
-	unlink(RECOVERY_COMMAND_DONE);
-	if (rename(RECOVERY_COMMAND_FILE, RECOVERY_COMMAND_DONE) != 0)
+	if (unlink(RECOVERY_ENABLE_FILE) != 0)
 		ereport(FATAL,
 				(errcode_for_file_access(),
-				 errmsg("could not rename file \"%s\" to \"%s\": %m",
-						RECOVERY_COMMAND_FILE, RECOVERY_COMMAND_DONE)));
+				 errmsg("could not remove file \"%s\": %m",
+						RECOVERY_ENABLE_FILE)));
 
 	ereport(LOG,
 			(errmsg("archive recovery complete")));
@@ -4499,7 +4325,7 @@ recoveryStopsHere(XLogRecord *record, bool *includeThis)
 		return false;
 
 	/* Do we have a PITR target at all? */
-	if (recoveryTarget == RECOVERY_TARGET_UNSET)
+	if (recovery_target == RECOVERY_TARGET_UNSET)
 	{
 		/*
 		 * Save timestamp of latest transaction commit/abort if this is a
@@ -4510,7 +4336,7 @@ recoveryStopsHere(XLogRecord *record, bool *includeThis)
 		return false;
 	}
 
-	if (recoveryTarget == RECOVERY_TARGET_XID)
+	if (recovery_target == RECOVERY_TARGET_XID)
 	{
 		/*
 		 * There can be only one transaction end record with this exact
@@ -4521,17 +4347,17 @@ recoveryStopsHere(XLogRecord *record, bool *includeThis)
 		 * they complete. A higher numbered xid will complete before you about
 		 * 50% of the time...
 		 */
-		stopsHere = (record->xl_xid == recoveryTargetXid);
+		stopsHere = (record->xl_xid == recovery_target_xid);
 		if (stopsHere)
-			*includeThis = recoveryTargetInclusive;
+			*includeThis = recovery_target_inclusive;
 	}
-	else if (recoveryTarget == RECOVERY_TARGET_NAME)
+	else if (recovery_target == RECOVERY_TARGET_NAME)
 	{
 		/*
 		 * There can be many restore points that share the same name, so we
 		 * stop at the first one
 		 */
-		stopsHere = (strcmp(recordRPName, recoveryTargetName) == 0);
+		stopsHere = (strcmp(recordRPName, recovery_target_name) == 0);
 
 		/*
 		 * Ignore recoveryTargetInclusive because this is not a transaction
@@ -4546,16 +4372,17 @@ recoveryStopsHere(XLogRecord *record, bool *includeThis)
 		 * we stop after the last one, if we are inclusive, or stop at the
 		 * first one if we are exclusive
 		 */
-		if (recoveryTargetInclusive)
-			stopsHere = (recordXtime > recoveryTargetTime);
+		if (recovery_target_inclusive)
+			stopsHere = (recordXtime > recovery_target_time);
 		else
-			stopsHere = (recordXtime >= recoveryTargetTime);
+			stopsHere = (recordXtime >= recovery_target_time);
 		if (stopsHere)
 			*includeThis = false;
 	}
 
 	if (stopsHere)
 	{
+		recoveryStopTarget = recovery_target;
 		recoveryStopXid = record->xl_xid;
 		recoveryStopTime = recordXtime;
 		recoveryStopAfter = *includeThis;
@@ -4905,36 +4732,28 @@ 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 recovery trigger file, and if so set up state for offline
+	 * recovery.
 	 */
-	strncpy(XLogCtl->archiveCleanupCommand,
-			archiveCleanupCommand ? archiveCleanupCommand : "",
-			sizeof(XLogCtl->archiveCleanupCommand));
+	CheckRecoveryReadyFile();
 
 	if (ArchiveRecoveryRequested)
 	{
 		if (StandbyModeRequested)
 			ereport(LOG,
 					(errmsg("entering standby mode")));
-		else if (recoveryTarget == RECOVERY_TARGET_XID)
+		else if (recovery_target == RECOVERY_TARGET_XID)
 			ereport(LOG,
 					(errmsg("starting point-in-time recovery to XID %u",
-							recoveryTargetXid)));
-		else if (recoveryTarget == RECOVERY_TARGET_TIME)
+							recovery_target_xid)));
+		else if (recovery_target == RECOVERY_TARGET_TIME)
 			ereport(LOG,
 					(errmsg("starting point-in-time recovery to %s",
-							timestamptz_to_str(recoveryTargetTime))));
-		else if (recoveryTarget == RECOVERY_TARGET_NAME)
+							timestamptz_to_str(recovery_target_time))));
+		else if (recovery_target == RECOVERY_TARGET_NAME)
 			ereport(LOG,
 					(errmsg("starting point-in-time recovery to \"%s\"",
-							recoveryTargetName)));
+							recovery_target_name)));
 		else
 			ereport(LOG,
 					(errmsg("starting archive recovery")));
@@ -4960,7 +4779,7 @@ StartupXLOG(void)
 	 * Take ownership of the wakeup latch if we're going to sleep during
 	 * recovery.
 	 */
-	if (StandbyModeRequested)
+	if (ArchiveRecoveryRequested && StandbyModeRequested)
 		OwnLatch(&XLogCtl->recoveryWakeupLatch);
 
 	/* Set up XLOG reader facility */
@@ -4982,7 +4801,7 @@ StartupXLOG(void)
 		 * archive recovery directly.
 		 */
 		InArchiveRecovery = true;
-		if (StandbyModeRequested)
+		if (ArchiveRecoveryRequested && StandbyModeRequested)
 			StandbyMode = true;
 
 		/*
@@ -5048,7 +4867,7 @@ StartupXLOG(void)
 			 ControlFile->state == DB_SHUTDOWNED))
 		{
 			InArchiveRecovery = true;
-			if (StandbyModeRequested)
+			if (ArchiveRecoveryRequested && StandbyModeRequested)
 				StandbyMode = true;
 		}
 
@@ -5208,7 +5027,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 standby.enabled file,
 	 * then assume no recovery needed.
 	 */
 	if (checkPoint.redo < RecPtr)
@@ -5222,7 +5041,7 @@ StartupXLOG(void)
 		InRecovery = true;
 	else if (ArchiveRecoveryRequested)
 	{
-		/* force recovery due to presence of recovery.conf */
+		/* force recovery due to presence of standby.enabled */
 		InRecovery = true;
 	}
 
@@ -5541,7 +5360,7 @@ StartupXLOG(void)
 				 */
 				if (recoveryStopsHere(record, &recoveryApply))
 				{
-					if (recoveryPauseAtTarget)
+					if (pause_at_recovery_target)
 					{
 						SetRecoveryPause(true);
 						recoveryPausesHere();
@@ -5705,7 +5524,7 @@ StartupXLOG(void)
 	 * We don't need the latch anymore. It's not strictly necessary to disown
 	 * it, but let's do it for the sake of tidiness.
 	 */
-	if (StandbyModeRequested)
+	if (ArchiveRecoveryRequested && StandbyModeRequested)
 		DisownLatch(&XLogCtl->recoveryWakeupLatch);
 
 	/*
@@ -5795,17 +5614,17 @@ StartupXLOG(void)
 		 * Create a comment for the history file to explain why and where
 		 * timeline changed.
 		 */
-		if (recoveryTarget == RECOVERY_TARGET_XID)
+		if (recovery_target == RECOVERY_TARGET_XID)
 			snprintf(reason, sizeof(reason),
 					 "%s transaction %u",
 					 recoveryStopAfter ? "after" : "before",
 					 recoveryStopXid);
-		else if (recoveryTarget == RECOVERY_TARGET_TIME)
+		else if (recovery_target == RECOVERY_TARGET_TIME)
 			snprintf(reason, sizeof(reason),
 					 "%s %s\n",
 					 recoveryStopAfter ? "after" : "before",
 					 timestamptz_to_str(recoveryStopTime));
-		else if (recoveryTarget == RECOVERY_TARGET_NAME)
+		else if (recovery_target == RECOVERY_TARGET_NAME)
 			snprintf(reason, sizeof(reason),
 					 "at restore point \"%s\"",
 					 recoveryStopName);
@@ -5964,8 +5783,8 @@ StartupXLOG(void)
 		/*
 		 * And finally, execute the recovery_end_command, if any.
 		 */
-		if (recoveryEndCommand)
-			ExecuteRecoveryCommand(recoveryEndCommand,
+		if (recovery_end_command[0])
+			ExecuteRecoveryCommand(recovery_end_command,
 								   "recovery_end_command",
 								   true);
 	}
@@ -6833,7 +6652,7 @@ CreateCheckPoint(int flags)
 		XLogRecPtr	curInsert;
 
 		INSERT_RECPTR(curInsert, Insert, Insert->curridx);
-		if (curInsert == ControlFile->checkPoint + 
+		if (curInsert == ControlFile->checkPoint +
 			MAXALIGN(SizeOfXLogRecord + sizeof(CheckPoint)) &&
 			ControlFile->checkPoint == ControlFile->checkPointCopy.redo)
 		{
@@ -7481,8 +7300,8 @@ CreateRestartPoint(int flags)
 	/*
 	 * Finally, execute archive_cleanup_command, if any.
 	 */
-	if (XLogCtl->archiveCleanupCommand[0])
-		ExecuteRecoveryCommand(XLogCtl->archiveCleanupCommand,
+	if (archive_cleanup_command[0])
+		ExecuteRecoveryCommand(archive_cleanup_command,
 							   "archive_cleanup_command",
 							   false);
 
@@ -9224,7 +9043,7 @@ XLogPageRead(XLogReaderState *xlogreader, XLogRecPtr targetPagePtr, int reqLen,
 		 * Request a restartpoint if we've replayed too much xlog since the
 		 * last one.
 		 */
-		if (StandbyModeRequested && bgwriterLaunched)
+		if (ArchiveRecoveryRequested && StandbyModeRequested && bgwriterLaunched)
 		{
 			if (XLogCheckpointNeeded(readSegNo))
 			{
@@ -9440,7 +9259,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 (primary_conninfo[0])
 					{
 						XLogRecPtr ptr;
 						TimeLineID tli;
@@ -9461,7 +9280,7 @@ WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess,
 									 tli, curFileTLI);
 						}
 						curFileTLI = tli;
-						RequestXLogStreaming(curFileTLI, ptr, PrimaryConnInfo);
+						RequestXLogStreaming(curFileTLI, ptr);
 					}
 					/*
 					 * Move to XLOG_FROM_STREAM state in either case. We'll get
@@ -9779,14 +9598,14 @@ CheckForStandbyTrigger(void)
 		return true;
 	}
 
-	if (TriggerFile == NULL)
+	if (!trigger_file[0])
 		return false;
 
-	if (stat(TriggerFile, &stat_buf) == 0)
+	if (stat(trigger_file, &stat_buf) == 0)
 	{
 		ereport(LOG,
-				(errmsg("trigger file found: %s", TriggerFile)));
-		unlink(TriggerFile);
+				(errmsg("trigger file found: %s", trigger_file)));
+		unlink(trigger_file);
 		triggered = true;
 		return true;
 	}
diff --git a/src/backend/access/transam/xlogarchive.c b/src/backend/access/transam/xlogarchive.c
index 0c178c5..21e2eee 100644
--- a/src/backend/access/transam/xlogarchive.c
+++ b/src/backend/access/transam/xlogarchive.c
@@ -67,7 +67,7 @@ RestoreArchivedFile(char *path, const char *xlogfname,
 	TimeLineID	restartTli;
 
 	/* In standby mode, restore_command might not be supplied */
-	if (recoveryRestoreCommand == NULL)
+	if (restore_command == NULL)
 		goto not_available;
 
 	/*
@@ -150,7 +150,7 @@ RestoreArchivedFile(char *path, const char *xlogfname,
 	endp = xlogRestoreCmd + MAXPGPATH - 1;
 	*endp = '\0';
 
-	for (sp = recoveryRestoreCommand; *sp; sp++)
+	for (sp = restore_command; *sp; sp++)
 	{
 		if (*sp == '%')
 		{
diff --git a/src/backend/commands/extension.c b/src/backend/commands/extension.c
index 6b7cb5b..69aa528 100644
--- a/src/backend/commands/extension.c
+++ b/src/backend/commands/extension.c
@@ -9,7 +9,7 @@
  * dependent objects can be associated with it.  An extension is created by
  * populating the pg_extension catalog from a "control" file.
  * The extension control file is parsed with the same parser we use for
- * postgresql.conf and recovery.conf.  An extension also has an installation
+ * postgresql.conf.  An extension also has an installation
  * script file, containing SQL commands to create the extension's objects.
  *
  * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index 911a66b..9f8d450 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -186,7 +186,6 @@ DisableWalRcvImmediateExit(void)
 void
 WalReceiverMain(void)
 {
-	char		conninfo[MAXCONNINFO];
 	XLogRecPtr	startpoint;
 	TimeLineID	startpointTLI;
 	TimeLineID	primaryTLI;
@@ -240,7 +239,6 @@ WalReceiverMain(void)
 	walrcv->walRcvState = WALRCV_STREAMING;
 
 	/* Fetch information required to start streaming */
-	strlcpy(conninfo, (char *) walrcv->conninfo, MAXCONNINFO);
 	startpoint = walrcv->receiveStart;
 	startpointTLI = walrcv->receiveStartTLI;
 
@@ -307,7 +305,7 @@ WalReceiverMain(void)
 
 	/* Establish the connection to the primary for XLOG streaming */
 	EnableWalRcvImmediateExit();
-	walrcv_connect(conninfo);
+	walrcv_connect(primary_conninfo);
 	DisableWalRcvImmediateExit();
 
 	first_stream = true;
@@ -405,8 +403,22 @@ WalReceiverMain(void)
 
 				if (got_SIGHUP)
 				{
+					char    *conninfo = pstrdup(primary_conninfo);
+
 					got_SIGHUP = false;
 					ProcessConfigFile(PGC_SIGHUP);
+
+					/*
+					 * If primary_conninfo has been changed while walreceiver is running,
+					 * shut down walreceiver so that new walreceiver is started and
+					 * it initiates replication with new primary_conninfo.
+					 */
+					if (strcmp(conninfo, primary_conninfo) != 0)
+						ereport(FATAL,
+								(errcode(ERRCODE_ADMIN_SHUTDOWN),
+								 errmsg("terminating walreceiver process because primary_conninfo was changed")));
+					pfree(conninfo);
+
 					XLogWalRcvSendHSFeedback(true);
 				}
 
diff --git a/src/backend/replication/walreceiverfuncs.c b/src/backend/replication/walreceiverfuncs.c
index d414808..d6a5e06 100644
--- a/src/backend/replication/walreceiverfuncs.c
+++ b/src/backend/replication/walreceiverfuncs.c
@@ -219,11 +219,10 @@ ShutdownWalRcv(void)
 /*
  * Request postmaster to start walreceiver.
  *
- * recptr indicates the position where streaming should begin, and conninfo
- * is a libpq connection string to use.
+ * recptr indicates the position where streaming should begin.
  */
 void
-RequestXLogStreaming(TimeLineID tli, XLogRecPtr recptr, const char *conninfo)
+RequestXLogStreaming(TimeLineID tli, XLogRecPtr recptr)
 {
 	/* use volatile pointer to prevent code rearrangement */
 	volatile WalRcvData *walrcv = WalRcv;
@@ -245,11 +244,6 @@ RequestXLogStreaming(TimeLineID tli, XLogRecPtr recptr, const char *conninfo)
 	Assert(walrcv->walRcvState == WALRCV_STOPPED ||
 		   walrcv->walRcvState == WALRCV_WAITING);
 
-	if (conninfo != NULL)
-		strlcpy((char *) walrcv->conninfo, conninfo, MAXCONNINFO);
-	else
-		walrcv->conninfo[0] = '\0';
-
 	if (walrcv->walRcvState == WALRCV_STOPPED)
 	{
 		launch = true;
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 98149fc..55427aa 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -30,6 +30,7 @@
 #include "access/transam.h"
 #include "access/twophase.h"
 #include "access/xact.h"
+#include "access/xlog_internal.h"
 #include "catalog/namespace.h"
 #include "commands/async.h"
 #include "commands/prepare.h"
@@ -196,6 +197,14 @@ static bool check_application_name(char **newval, void **extra, GucSource source
 static void assign_application_name(const char *newval, void *extra);
 static const char *show_unix_socket_permissions(void);
 static const char *show_log_file_mode(void);
+static bool check_recovery_target_xid(char **newval, void **extra, GucSource source);
+static void assign_recovery_target_xid(const char *newval, void *extra);
+static bool check_recovery_target_name(char **newval, void **extra, GucSource source);
+static void assign_recovery_target_name(const char *newval, void *extra);
+static bool check_recovery_target_time(char **newval, void **extra, GucSource source);
+static void assign_recovery_target_time(const char *newval, void *extra);
+static bool check_recovery_target_timeline(char **newval, void **extra, GucSource source);
+static void assign_recovery_target_timeline(const char *newval, void *extra);
 
 static char *config_enum_get_options(struct config_enum * record,
 						const char *prefix, const char *suffix,
@@ -468,6 +477,8 @@ static int	wal_block_size;
 static int	wal_segment_size;
 static bool integer_datetimes;
 static int	effective_io_concurrency;
+static char *recovery_target_xid_string;
+static char *recovery_target_time_string;
 
 /* should be static, but commands/variable.c needs to get at this */
 char	   *role_string;
@@ -548,6 +559,10 @@ const char *const config_group_names[] =
 	gettext_noop("Write-Ahead Log / Checkpoints"),
 	/* WAL_ARCHIVING */
 	gettext_noop("Write-Ahead Log / Archiving"),
+	/* WAL_ARCHIVE_RECOVERY */
+	gettext_noop("Write-Ahead Log / Archive Recovery"),
+	/* WAL_RECOVERY_TARGET */
+	gettext_noop("Write-Ahead Log / Recovery Target"),
 	/* REPLICATION */
 	gettext_noop("Replication"),
 	/* REPLICATION_SENDING */
@@ -1376,6 +1391,36 @@ static struct config_bool ConfigureNamesBool[] =
 	},
 
 	{
+		{"recovery_target_inclusive", PGC_SIGHUP, WAL_RECOVERY_TARGET,
+			gettext_noop("Sets whether to include or exclude transaction with recovery target."),
+			NULL
+		},
+		&recovery_target_inclusive,
+		true,
+		NULL, NULL, NULL
+	},
+
+	{
+		{"pause_at_recovery_target", PGC_SIGHUP, WAL_RECOVERY_TARGET,
+			gettext_noop("Sets whether recovery should pause when the recovery target is reached."),
+			NULL
+		},
+		&pause_at_recovery_target,
+		true,
+		NULL, NULL, NULL
+	},
+
+	{
+		{"standby_mode", PGC_POSTMASTER, REPLICATION_STANDBY,
+			gettext_noop("Sets whether to start the server as a standby."),
+			NULL
+		},
+		&StandbyModeRequested,
+		false,
+		NULL, NULL, NULL
+	},
+
+	{
 		{"hot_standby", PGC_POSTMASTER, REPLICATION_STANDBY,
 			gettext_noop("Allows connections and queries during recovery."),
 			NULL
@@ -2544,6 +2589,97 @@ static struct config_string ConfigureNamesString[] =
 	},
 
 	{
+		{"restore_command", PGC_SIGHUP, WAL_ARCHIVE_RECOVERY,
+			gettext_noop("Sets the shell command that will retrieve an archived WAL file."),
+			NULL
+		},
+		&restore_command,
+		"",
+		NULL, NULL, NULL
+	},
+
+	{
+		{"archive_cleanup_command", PGC_SIGHUP, WAL_ARCHIVE_RECOVERY,
+			gettext_noop("Sets the shell command that will be executed at every restartpoint."),
+			NULL
+		},
+		&archive_cleanup_command,
+		"",
+		NULL, NULL, NULL
+	},
+
+	{
+		{"recovery_end_command", PGC_SIGHUP, WAL_ARCHIVE_RECOVERY,
+			gettext_noop("Sets the shell command that will be executed once only at the end of recovery."),
+			NULL
+		},
+		&recovery_end_command,
+		"",
+		NULL, NULL, NULL
+	},
+
+	{
+		{"recovery_target_xid", PGC_SIGHUP, WAL_RECOVERY_TARGET,
+			gettext_noop("Sets the transaction ID up to which recovery will proceed."),
+			NULL
+		},
+		&recovery_target_xid_string,
+		"",
+		check_recovery_target_xid, assign_recovery_target_xid, NULL
+	},
+
+	{
+		{"recovery_target_name", PGC_SIGHUP, WAL_RECOVERY_TARGET,
+			gettext_noop("Sets the named restore point."),
+			NULL
+		},
+		&recovery_target_name,
+		"",
+		check_recovery_target_name, assign_recovery_target_name, NULL
+	},
+
+	{
+		{"recovery_target_time", PGC_SIGHUP, WAL_RECOVERY_TARGET,
+			gettext_noop("Sets the time stamp up to which recovery will proceed."),
+			NULL
+		},
+		&recovery_target_time_string,
+		"",
+		check_recovery_target_time, assign_recovery_target_time, NULL
+	},
+
+	{
+		{"recovery_target_timeline", PGC_POSTMASTER, WAL_RECOVERY_TARGET,
+			gettext_noop("Sets recoverying into a particular timeline."),
+			NULL
+		},
+		&recovery_target_timeline_string,
+		"",
+		check_recovery_target_timeline, assign_recovery_target_timeline, NULL
+	},
+
+	{
+		{"primary_conninfo", PGC_SIGHUP, REPLICATION_STANDBY,
+			gettext_noop("Sets the connection string to be used to connect with the primary."),
+			NULL,
+			GUC_SUPERUSER_ONLY
+		},
+		&primary_conninfo,
+		"",
+		NULL, NULL, NULL
+	},
+
+	{
+		{"trigger_file", PGC_SIGHUP, REPLICATION_STANDBY,
+			gettext_noop("Sets the trigger file whose presence ends recovery in the standby."),
+			NULL
+		},
+		&trigger_file,
+		"",
+		NULL, NULL, NULL
+	},
+
+	{
 		{"client_encoding", PGC_USERSET, CLIENT_CONN_LOCALE,
 			gettext_noop("Sets the client's character set encoding."),
 			NULL,
@@ -8770,4 +8906,158 @@ show_log_file_mode(void)
 	return buf;
 }
 
+static bool
+check_recovery_target_xid(char **newval, void **extra, GucSource source)
+{
+	TransactionId   xid;
+	TransactionId   *myextra;
+
+	if (strcmp(*newval, "") == 0)
+		xid = InvalidTransactionId;
+	else
+	{
+		errno = 0;
+		xid = (TransactionId) strtoul(*newval, NULL, 0);
+		if (errno == EINVAL || errno == ERANGE)
+		{
+			GUC_check_errdetail("recovery_target_xid is not a valid number: \"%s\"",
+								*newval);
+			return false;
+		}
+	}
+
+	myextra = (TransactionId *) guc_malloc(ERROR, sizeof(TransactionId));
+	*myextra = xid;
+	*extra = (void *) myextra;
+
+	return true;
+}
+
+static void
+assign_recovery_target_xid(const char *newval, void *extra)
+{
+	recovery_target_xid = *((TransactionId *) extra);
+
+	if (recovery_target_xid != InvalidTransactionId)
+		recovery_target = RECOVERY_TARGET_XID;
+	else if (recovery_target_name[0])
+		recovery_target = RECOVERY_TARGET_NAME;
+	else if (recovery_target_time != 0)
+		recovery_target = RECOVERY_TARGET_TIME;
+	else
+		recovery_target = RECOVERY_TARGET_UNSET;
+}
+
+static bool
+check_recovery_target_name(char **newval, void **extra, GucSource source)
+{
+	if (strlen(*newval) >= MAXFNAMELEN)
+	{
+		GUC_check_errdetail("\"recovery_target_name\" is too long (maximum %d characters)",
+							MAXFNAMELEN - 1);
+		return false;
+	}
+	return true;
+}
+
+static void
+assign_recovery_target_name(const char *newval, void *extra)
+{
+	if (recovery_target_xid != InvalidTransactionId)
+		recovery_target = RECOVERY_TARGET_XID;
+	else if (newval[0])
+		recovery_target = RECOVERY_TARGET_NAME;
+	else if (recovery_target_time != 0)
+		recovery_target = RECOVERY_TARGET_TIME;
+	else
+		recovery_target = RECOVERY_TARGET_UNSET;
+}
+
+static bool
+check_recovery_target_time(char **newval, void **extra, GucSource source)
+{
+	TimestampTz     time;
+	TimestampTz     *myextra;
+	MemoryContext oldcontext = CurrentMemoryContext;
+
+	PG_TRY();
+	{
+		time = (strcmp(*newval, "") == 0) ?
+			0 :
+			DatumGetTimestampTz(DirectFunctionCall3(timestamptz_in,
+													CStringGetDatum(*newval),
+													ObjectIdGetDatum(InvalidOid),
+													Int32GetDatum(-1)));
+	}
+	PG_CATCH();
+	{
+		ErrorData  *edata;
+
+		/* Save error info */
+		MemoryContextSwitchTo(oldcontext);
+		edata = CopyErrorData();
+		FlushErrorState();
+
+		/* Pass the error message */
+		GUC_check_errdetail("%s", edata->message);
+		FreeErrorData(edata);
+		return false;
+	}
+	PG_END_TRY();
+
+	myextra = (TimestampTz *) guc_malloc(ERROR, sizeof(TimestampTz));
+	*myextra = time;
+	*extra = (void *) myextra;
+
+	return true;
+}
+
+static void
+assign_recovery_target_time(const char *newval, void *extra)
+{
+	recovery_target_time = *((TimestampTz *) extra);
+
+	if (recovery_target_xid != InvalidTransactionId)
+		recovery_target = RECOVERY_TARGET_XID;
+	else if (recovery_target_name[0])
+		recovery_target = RECOVERY_TARGET_NAME;
+	else if (recovery_target_time != 0)
+		recovery_target = RECOVERY_TARGET_TIME;
+	else
+		recovery_target = RECOVERY_TARGET_UNSET;
+}
+
+static bool
+check_recovery_target_timeline(char **newval, void **extra, GucSource source)
+{
+	TimeLineID	tli = 0;
+	TimeLineID	*myextra;
+
+	if (strcmp(*newval, "") == 0 || strcmp(*newval, "latest") == 0)
+		tli = 0;
+	else
+	{
+		errno = 0;
+		tli = (TimeLineID) strtoul(*newval, NULL, 0);
+		if (errno == EINVAL || errno == ERANGE)
+		{
+			GUC_check_errdetail("recovery_target_timeline is not a valid number: \"%s\"",
+								*newval);
+			return false;
+		}
+	}
+
+	myextra = (TimeLineID *) guc_malloc(ERROR, sizeof(TimeLineID));
+	*myextra = tli;
+	*extra = (void *) myextra;
+
+	return true;
+}
+
+static void
+assign_recovery_target_timeline(const char *newval, void *extra)
+{
+	recovery_target_timeline = *((TimeLineID *) extra);
+}
+
 #include "guc-file.c"
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
index 62aea2f..52a4e71 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -198,6 +198,23 @@
 #archive_timeout = 0		# force a logfile segment switch after this
 				# number of seconds; 0 disables
 
+# - Archive Recovery -
+#restore_command = ''		# command to use to restore an archived logfile segment
+				# placeholders: %p = path of file to restore
+				#               %f = file name only
+				# e.g. 'cp /mnt/server/archivedir/%f %p'
+#archive_cleanup_command = ''	# command to execute at every restartpoint
+#recovery_end_command = ''	# command to execute at completion of recovery
+
+# - Recovery Target -
+#recovery_target_xid = ''
+#recovery_target_name = ''		# e.g. 'daily backup 2011-01-26'
+#recovery_target_time = ''		# e.g. '2004-07-14 22:39:00 EST'
+#recovery_target_timeline = ''		# timeline ID or 'latest'
+					# (change requires restart)
+#recovery_target_inclusive = on
+#pause_at_recovery_target = on		# Pause recovery once target is reached
+
 
 #------------------------------------------------------------------------------
 # REPLICATION
@@ -240,6 +257,11 @@
 #wal_receiver_timeout = 60s		# time that receiver waits for
 					# communication from master
 					# in milliseconds; 0 disables
+#standby_mode = off			# "on" starts the server as a standby
+					# (change requires restart)
+#primary_conninfo = ''			# connection string to connect to the master
+					# e.g. 'host=localhost port=5432'
+#trigger_file = ''			# trigger file to promote the standby
 
 
 #------------------------------------------------------------------------------
diff --git a/src/bin/pg_ctl/pg_ctl.c b/src/bin/pg_ctl/pg_ctl.c
index 7d5e168..274c3a3 100644
--- a/src/bin/pg_ctl/pg_ctl.c
+++ b/src/bin/pg_ctl/pg_ctl.c
@@ -890,7 +890,7 @@ do_stop(void)
 		/*
 		 * If backup_label exists, an online backup is running. Warn the user
 		 * that smart shutdown will wait for it to finish. However, if
-		 * recovery.conf is also present, we're recovering from an online
+		 * standby.enabled is also present, we're recovering from an online
 		 * backup instead of performing one.
 		 */
 		if (shutdown_mode == SMART_MODE &&
@@ -978,7 +978,7 @@ do_restart(void)
 		/*
 		 * If backup_label exists, an online backup is running. Warn the user
 		 * that smart shutdown will wait for it to finish. However, if
-		 * recovery.conf is also present, we're recovering from an online
+		 * standby.enabled is also present, we're recovering from an online
 		 * backup instead of performing one.
 		 */
 		if (shutdown_mode == SMART_MODE &&
@@ -1089,7 +1089,7 @@ do_promote(void)
 		exit(1);
 	}
 
-	/* If recovery.conf doesn't exist, the server is not in standby mode */
+	/* If standby.enabled doesn't exist, the server is not in standby mode */
 	if (stat(recovery_file, &statbuf) != 0)
 	{
 		write_stderr(_("%s: cannot promote server; "
@@ -2245,7 +2245,7 @@ main(int argc, char **argv)
 		snprintf(postopts_file, MAXPGPATH, "%s/postmaster.opts", pg_data);
 		snprintf(pid_file, MAXPGPATH, "%s/postmaster.pid", pg_data);
 		snprintf(backup_file, MAXPGPATH, "%s/backup_label", pg_data);
-		snprintf(recovery_file, MAXPGPATH, "%s/recovery.conf", pg_data);
+		snprintf(recovery_file, MAXPGPATH, "%s/standby.enabled", pg_data);
 	}
 
 	switch (ctl_command)
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index 8a65492..d85bd6d 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -190,6 +190,20 @@ extern char *XLogArchiveCommand;
 extern bool EnableHotStandby;
 extern bool fullPageWrites;
 extern bool log_checkpoints;
+extern char *restore_command;
+extern char *archive_cleanup_command;
+extern char *recovery_end_command;
+extern bool	StandbyModeRequested;
+extern char *primary_conninfo;
+extern char *trigger_file;
+extern RecoveryTargetType recovery_target;
+extern TransactionId recovery_target_xid;
+extern TimestampTz recovery_target_time;
+extern char *recovery_target_name;
+extern bool recovery_target_inclusive;
+extern bool pause_at_recovery_target;
+extern char *recovery_target_timeline_string;
+extern TimeLineID recovery_target_timeline;
 
 /* WAL levels */
 typedef enum WalLevel
diff --git a/src/include/replication/walreceiver.h b/src/include/replication/walreceiver.h
index 72878f8..d51d86f 100644
--- a/src/include/replication/walreceiver.h
+++ b/src/include/replication/walreceiver.h
@@ -149,7 +149,7 @@ extern void WalRcvShmemInit(void);
 extern void ShutdownWalRcv(void);
 extern bool WalRcvStreaming(void);
 extern bool WalRcvRunning(void);
-extern void RequestXLogStreaming(TimeLineID tli, XLogRecPtr recptr, const char *conninfo);
+extern void RequestXLogStreaming(TimeLineID tli, XLogRecPtr recptr);
 extern XLogRecPtr GetWalRcvWriteRecPtr(XLogRecPtr *latestChunkStart, TimeLineID *receiveTLI);
 extern int	GetReplicationApplyDelay(void);
 extern int	GetReplicationTransferLatency(void);
diff --git a/src/include/utils/guc_tables.h b/src/include/utils/guc_tables.h
index 7360ce3..a2d3281 100644
--- a/src/include/utils/guc_tables.h
+++ b/src/include/utils/guc_tables.h
@@ -68,6 +68,8 @@ enum config_group
 	WAL_SETTINGS,
 	WAL_CHECKPOINTS,
 	WAL_ARCHIVING,
+	WAL_ARCHIVE_RECOVERY,
+	WAL_RECOVERY_TARGET,
 	REPLICATION,
 	REPLICATION_SENDING,
 	REPLICATION_MASTER,
#27Michael Paquier
michael.paquier@gmail.com
In reply to: Michael Paquier (#26)
1 attachment(s)
Re: Request for vote to move forward with recovery.conf overhaul

Hi all,

pg_basebackup contains an option called --write-recovery-conf allowing the
user to generate automatically some values for recovery.conf.
As in this patch all the recovery parameters are moved to postgresql.conf
as GUCs, I replaced the existing option by a new option called
--write-enable-standby that simply creates an empty standby.enabled file in
the base backup if specified. By looking at the code of pg_basebackup, I
noticed that adding some automatically-generated input to postgresql.conf
would not impact so much the code when using plain format. However adding
special handling in the code for tar format would make the code less
readable and less intuitive. Also do we really need to generate recovery
parameters with pg_basebackup? In the spec discussed we want the user to
define once recovery parameters in the master's postgresql.conf such as the
same values could be reused directly in the slave's base backup.

I have also reworked the documentation a bit:
- Addition of a section called "Recovery" in the configuration section to
describe all the parameters that are activated only if standby.enabled is
found at server startup.
- Addition of a note at the end of the new "Recovery" section indicating
how to migrate an existing configuration using recovery.conf to the new
system using include_dir or include_if_exists.

Feedback is warmly welcome.
Regards,
--
Michael

Attachments:

20130325_recovery_guc_v3.patchapplication/octet-stream; name=20130325_recovery_guc_v3.patchDownload
diff --git a/contrib/pg_archivecleanup/pg_archivecleanup.c b/contrib/pg_archivecleanup/pg_archivecleanup.c
index e97a11c..fb01da9 100644
--- a/contrib/pg_archivecleanup/pg_archivecleanup.c
+++ b/contrib/pg_archivecleanup/pg_archivecleanup.c
@@ -255,7 +255,7 @@ usage(void)
 	printf("  -x EXT         clean up files if they have this extension\n");
 	printf("  -?, --help     show this help, then exit\n");
 	printf("\n"
-		   "For use as archive_cleanup_command in recovery.conf when standby_mode = on:\n"
+		   "For use as archive_cleanup_command in postgresql.conf when standby_mode = on:\n"
 		   "  archive_cleanup_command = 'pg_archivecleanup [OPTION]... ARCHIVELOCATION %%r'\n"
 		   "e.g.\n"
 		   "  archive_cleanup_command = 'pg_archivecleanup /mnt/server/archiverdir %%r'\n");
diff --git a/contrib/pg_standby/pg_standby.c b/contrib/pg_standby/pg_standby.c
index 11615eb..c76b116 100644
--- a/contrib/pg_standby/pg_standby.c
+++ b/contrib/pg_standby/pg_standby.c
@@ -531,7 +531,7 @@ usage(void)
 	printf("  -w MAXWAITTIME     max seconds to wait for a file (0=no limit) (default=0)\n");
 	printf("  -?, --help         show this help, then exit\n");
 	printf("\n"
-		   "Main intended use as restore_command in recovery.conf:\n"
+		   "Main intended use as restore_command in postgresql.conf:\n"
 		   "  restore_command = 'pg_standby [OPTION]... ARCHIVELOCATION %%f %%p %%r'\n"
 		   "e.g.\n"
 	"  restore_command = 'pg_standby /mnt/server/archiverdir %%f %%p %%r'\n");
diff --git a/doc/src/sgml/backup.sgml b/doc/src/sgml/backup.sgml
index c4215be..f3040ff 100644
--- a/doc/src/sgml/backup.sgml
+++ b/doc/src/sgml/backup.sgml
@@ -1002,10 +1002,17 @@ SELECT pg_stop_backup();
    </listitem>
    <listitem>
     <para>
-     Create a recovery command file <filename>recovery.conf</> in the cluster
-     data directory (see <xref linkend="recovery-config">). You might
-     also want to temporarily modify <filename>pg_hba.conf</> to prevent
-     ordinary users from connecting until you are sure the recovery was successful.
+     Set up recovery parameters in <filename>postgresql.conf</> (see
+     <xref linkend="runtime-config-wal-archive-recovery"> and
+     <xref linkend="runtime-config-wal-recovery-target">).
+    </para>
+   </listitem>
+   <listitem>
+    <para>
+     Create a file called <filename>standby.enabled</> in the cluster data
+     directory. You might also want to temporarily modify <filename>pg_hba.conf</>
+     to prevent ordinary users from connecting until you are sure the recovery
+     was successful.
     </para>
    </listitem>
    <listitem>
@@ -1014,10 +1021,9 @@ SELECT pg_stop_backup();
      proceed to read through the archived WAL files it needs.  Should the
      recovery be terminated because of an external error, the server can
      simply be restarted and it will continue recovery.  Upon completion
-     of the recovery process, the server will rename
-     <filename>recovery.conf</> to <filename>recovery.done</> (to prevent
-     accidentally re-entering recovery mode later) and then
-     commence normal database operations.
+     of the recovery process, the server will delete
+     <filename>standby.enabled</> (to prevent accidentally re-entering
+     recovery mode later) and then commence normal database operations.
     </para>
    </listitem>
    <listitem>
@@ -1031,12 +1037,11 @@ SELECT pg_stop_backup();
    </para>
 
    <para>
-    The key part of all this is to set up a recovery configuration file that
-    describes how you want to recover and how far the recovery should
-    run.  You can use <filename>recovery.conf.sample</> (normally
-    located in the installation's <filename>share/</> directory) as a
-    prototype.  The one thing that you absolutely must specify in
-    <filename>recovery.conf</> is the <varname>restore_command</>,
+    The key part of all this is to set up recovery parameters that
+    specify how you want to recover and how far the recovery should
+    run. The one thing that you absolutely must specify in
+    <filename>postgresql.conf</> to recover from the backup is
+    the <varname>restore_command</>,
     which tells <productname>PostgreSQL</> how to retrieve archived
     WAL file segments.  Like the <varname>archive_command</>, this is
     a shell command string.  It can contain <literal>%f</>, which is
@@ -1090,7 +1095,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 stopping point in <filename>postgresql.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
@@ -1187,8 +1192,9 @@ restore_command = 'cp /mnt/server/archivedir/%f %p'
     The default behavior of recovery is to recover along the same timeline
     that was current when the base backup was taken.  If you wish to recover
     into some child timeline (that is, you want to return to some state that
-    was itself generated after a recovery attempt), you need to specify the
-    target timeline ID in <filename>recovery.conf</>.  You cannot recover into
+    was itself generated after a recovery attempt), you need to set
+    <xref linkend="guc-recovery-target-timeline"> to the
+    target timeline ID in <filename>postgresql.conf</>.  You cannot recover into
     timelines that branched off earlier than the base backup.
    </para>
   </sect2>
diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index 6e1b084..7fc45c6 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -2166,6 +2166,312 @@ include 'filename'
 
      </variablelist>
     </sect2>
+   </sect1>
+
+   <sect1 id="runtime-config-recovery">
+    <title>Recovery</title>
+
+    <sect2 id="runtime-config-wal-archive-recovery">
+     <title>Archive Recovery</title>
+
+     <para>
+      These settings control the behavior of server when put in recovery by
+      creating a recovery trigger file <filename>standby.enabled</> in data
+      folder. Those parameters are not used if server is not in recovery.
+     </para>
+
+     <variablelist>
+      <varlistentry id="guc-restore-command" xreflabel="restore_command">
+       <term><varname>restore_command</varname> (<type>string</type>)</term>
+       <indexterm>
+        <primary><varname>restore_command</> configuration parameter</primary>
+       </indexterm>
+       <listitem>
+        <para>
+         The shell command to execute to retrieve an archived segment of
+         the WAL file series. This parameter is required for archive recovery,
+         but optional for streaming replication.
+         Any <literal>%f</> in the string is
+         replaced by the name of the file to retrieve from the archive,
+         and any <literal>%p</> is replaced by the copy destination path name
+         on the server.
+         (The path name is relative to the current working directory,
+         i.e., the cluster's data directory.)
+         Any <literal>%r</> is replaced by the name of the file containing the
+         last valid restart point. That is the earliest file that must be kept
+         to allow a restore to be restartable, so this information can be used
+         to truncate the archive to just the minimum required to support
+         restarting from the current restore. <literal>%r</> is typically only
+         used by warm-standby configurations
+         (see <xref linkend="warm-standby">).
+         Write <literal>%%</> to embed an actual <literal>%</> character.
+        </para>
+        <para>
+         It is important for the command to return a zero exit status
+         only if it succeeds.  The command <emphasis>will</> be asked for file
+         names that are not present in the archive; it must return nonzero
+         when so asked.  Examples:
+<programlisting>
+restore_command = 'cp /mnt/server/archivedir/%f "%p"'
+restore_command = 'copy "C:\\server\\archivedir\\%f" "%p"'  # Windows
+</programlisting>
+        </para>
+        <para>
+         This parameter can only be set in the <filename>postgresql.conf</>
+         file or on the server command line. It only has effect during archive
+         recovery or in standby mode.
+        </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry id="guc-archive-cleanup-command" xreflabel="archive_cleanup_command">
+       <term><varname>archive_cleanup_command</varname> (<type>string</type>)</term>
+       <indexterm>
+         <primary><varname>archive_cleanup_command</> configuration parameter</primary>
+       </indexterm>
+       <listitem>
+        <para>
+         The shell command that will be executed at every restartpoint.
+         The purpose of <varname>archive_cleanup_command</> is to
+         provide a mechanism for cleaning up old archived WAL files that
+         are no longer needed by the standby server.
+         Any <literal>%r</> is replaced by the name of the file containing the
+         last valid restart point.
+         That is the earliest file that must be <emphasis>kept</> to allow a
+         restore to be restartable, and so all files earlier than <literal>%r</>
+         may be safely removed.
+         This information can be used to truncate the archive to just the
+         minimum required to support restart from the current restore.
+         The <xref linkend="pgarchivecleanup"> module
+         is often used in <varname>archive_cleanup_command</> for
+         single-standby configurations, for example:
+<programlisting>archive_cleanup_command = 'pg_archivecleanup /mnt/server/archivedir %r'</programlisting>
+         Note however that if multiple standby servers are restoring from the
+         same archive directory, you will need to ensure that you do not delete
+         WAL files until they are no longer needed by any of the servers.
+         <varname>archive_cleanup_command</> would typically be used in a
+         warm-standby configuration (see <xref linkend="warm-standby">).
+         Write <literal>%%</> to embed an actual <literal>%</> character in the
+         command.
+        </para>
+        <para>
+         If the command returns a non-zero exit status then a WARNING log
+         message will be written.
+        </para>
+        <para>
+         This parameter can only be set in the <filename>postgresql.conf</>
+         file or on the server command line. It only has effect during archive
+         recovery or in standby mode.
+        </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry id="guc-recovery-end-command" xreflabel="recovery_end_command">
+       <term><varname>recovery_end_command</varname> (<type>string</type>)</term>
+       <indexterm>
+         <primary><varname>recovery_end_command</> configuration parameter</primary>
+       </indexterm>
+       <listitem>
+        <para>
+         The shell command that will be executed once only
+         at the end of recovery. This parameter is optional. The purpose of the
+         <varname>recovery_end_command</> is to provide a mechanism for cleanup
+         following replication or recovery.
+         Any <literal>%r</> is replaced by the name of the file containing the
+         last valid restart point, like in <varname>archive_cleanup_command</>.
+        </para>
+        <para>
+         If the command returns a non-zero exit status then a WARNING log
+         message will be written and the database will proceed to start up
+         anyway.  An exception is that if the command was terminated by a
+         signal, the database will not proceed with startup.
+        </para>
+        <para>
+         This parameter can only be set in the <filename>postgresql.conf</>
+         file or on the server command line. It only has effect during archive
+         recovery or in standby mode.
+        </para>
+       </listitem>
+      </varlistentry>
+     </variablelist>
+    </sect2>
+
+    <sect2 id="runtime-config-wal-recovery-target">
+     <title>Recovery Target</title>
+
+     <variablelist>
+      <varlistentry id="guc-recovery-target-name" xreflabel="recovery_target_name">
+       <term><varname>recovery_target_name</varname> (<type>string</type>)</term>
+       <indexterm>
+        <primary><varname>recovery_target_name</> configuration parameter</primary>
+       </indexterm>
+       <listitem>
+        <para>
+         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</>,
+         <varname>recovery_target_time</> or
+         <varname>recovery_target_xid</> can be specified.  The default
+         value is an empty string, which will recover to the end of the WAL log.
+        </para>
+        <para>
+         This parameter can only be set in the <filename>postgresql.conf</>
+         file or on the server command line. It only has effect during archive
+         recovery or in standby mode.
+        </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry id="guc-recovery-target-time" xreflabel="recovery_target_time">
+       <term><varname>recovery_target_time</varname> (<type>string</type>)</term>
+       <indexterm>
+        <primary><varname>recovery_target_time</> configuration parameter</primary>
+       </indexterm>
+       <listitem>
+        <para>
+         Specifies the time stamp up to which recovery will proceed.
+         This parameter must be specified in the date/time format
+         (see <xref linkend="datatype-datetime-input"> for details).
+         At most one of <varname>recovery_target_time</>,
+         <varname>recovery_target_name</> or
+         <varname>recovery_target_xid</> can be specified.
+         The default value is an empty string, which will recover to
+         the end of the WAL log. The precise stopping point is also
+         influenced by <varname>recovery_target_inclusive</>.
+        </para>
+        <para>
+         This parameter can only be set in the <filename>postgresql.conf</>
+         file or on the server command line. It only has effect during archive
+         recovery or in standby mode.
+        </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry id="guc-recovery-target-xid" xreflabel="recovery_target_xid">
+       <term><varname>recovery_target_xid</varname> (<type>string</type>)</term>
+       <indexterm>
+        <primary><varname>recovery_target_xid</> configuration parameter</primary>
+       </indexterm>
+       <listitem>
+        <para>
+         Specifies the transaction ID up to which recovery will proceed.
+         Keep in mind that while transaction IDs are assigned sequentially
+         at transaction 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</>,
+         <varname>recovery_target_name</> or
+         <varname>recovery_target_time</> can be specified.
+         The default value is an empty string, which will recover to the end of
+         the WAL log. The precise stopping point is also influenced by
+         <varname>recovery_target_inclusive</>.
+        </para>
+        <para>
+         This parameter can only be set in the <filename>postgresql.conf</>
+         file or on the server command line. It only has effect during archive
+         recovery or in standby mode.
+        </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry id="guc-recovery-target-inclusive" xreflabel="recovery_target_inclusive">
+       <term><varname>recovery_target_inclusive</varname> (<type>boolean</type>)</term>
+       <indexterm>
+        <primary><varname>recovery_target_inclusive</> configuration parameter</primary>
+       </indexterm>
+       <listitem>
+        <para>
+         Specifies whether we stop just after the specified recovery target
+         (<literal>on</>), or just before the recovery target (<literal>off</>).
+         Applies to both <varname>recovery_target_time</>
+         and <varname>recovery_target_xid</>, whichever one is
+         specified for this recovery.  This indicates whether transactions
+         having exactly the target commit time or ID, respectively, will
+         be included in the recovery.  Default is <literal>on</>.
+        </para>
+        <para>
+         This parameter can only be set in the <filename>postgresql.conf</>
+         file or on the server command line. It only has effect during archive
+         recovery or in standby mode.
+        </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry id="guc-recovery-target-timeline" xreflabel="recovery_target_timeline">
+       <term><varname>recovery_target_timeline</varname> (<type>string</type>)</term>
+       <indexterm>
+        <primary><varname>recovery_target_timeline</> configuration parameter</primary>
+       </indexterm>
+       <listitem>
+        <para>
+         Specifies recovering into a particular timeline.  The default value is
+         an empty string, which will recover along the same timeline that was
+         current when the base backup was taken. Setting this to
+         <literal>latest</> recovers to the latest timeline found in the archive,
+         which is useful in a standby server. Other than that you only need to
+         set this parameter in complex re-recovery situations, where you need
+         to return to a state that itself was reached after a point-in-time
+         recovery. See <xref linkend="backup-timelines"> for discussion.
+        </para>
+        <para>
+         This parameter can only be set at server start. It only has effect
+         during archive recovery or in standby mode.
+        </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry id="guc-pause-at-recovery-target" xreflabel="pause_at_recovery_target">
+       <term><varname>pause_at_recovery_target</varname> (<type>boolean</type>)</term>
+       <indexterm>
+        <primary><varname>pause_at_recovery_target</> configuration parameter</primary>
+       </indexterm>
+       <listitem>
+        <para>
+         Specifies whether recovery should pause when the recovery target
+         is reached. The default is <literal>on</>.
+         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
+         <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
+         recovery target settings to a later target and restart to
+         continue recovery.
+        </para>
+        <para>
+         This parameter can only be set in the <filename>postgresql.conf</>
+         file or on the server command line. It only has effect during archive
+         recovery or in standby mode if recovery target is set.
+        </para>
+       </listitem>
+      </varlistentry>
+     </variablelist>
+     </sect2>
+
+    <sect2 id="runtime-config-">
+     <title>Migration from recovery.conf</title>
+
+     <para>
+      Prior <productname>PostgreSQL</> 9.2, all the recovery parameters had
+      to be specified in a configuration file called <filename>recovery.conf</>
+      located at the root of data folder of server. Servers running
+      <productname>PostgreSQL</> 9.3 and above return an error if
+      <filename>recovery.conf</> is found in data folder.
+     </para>
+
+     <para>
+      <filename>postgresql.conf</> provides two parameters allowing the
+      inclusion of external configuration files by either setting
+      <literal>include_if_exists</> to include a given file or <literal>include_dir</>
+      to include a directory containing a set of files configuration files.
+      In order to migrate an existing <filename>recovery.conf</> used with
+      a server whose version is lower than 9.2, set one of those parameters to
+      include it correctly. It is also necessary to rename <filename>recovery.conf</>
+      to a new name if the file included is located at root of data folder.
+     </para>
+
+    </sect2>
 
    </sect1>
 
@@ -2386,6 +2692,93 @@ include 'filename'
 
     <variablelist>
 
+     <varlistentry id="guc-standby-mode" xreflabel="standby_mode">
+      <term><varname>standby_mode</varname> (<type>boolean</type>)</term>
+      <indexterm>
+       <primary><varname>standby_mode</> configuration parameter</primary>
+      </indexterm>
+      <listitem>
+       <para>
+        Specifies whether to start the <productname>PostgreSQL</> server as
+        a standby when the file called <filename>standby.enabled</> exists.
+        The default value is <literal>off</>.
+        If this parameter is <literal>on</>, the server will not
+        stop recovery when the end of archived WAL is reached,
+        but will keep trying to continue recovery by fetching new WAL segments
+        using <varname>restore_command</> and/or by connecting to
+        the primary server as specified by the <varname>primary_conninfo</>
+        setting.
+       </para>
+       <para>
+        This parameter can only be set at server start. It only has effect
+        if file <filename>standby.enabled</> exists.
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry id="guc-primary-conninfo" xreflabel="primary_conninfo">
+      <term><varname>primary_conninfo</varname> (<type>string</type>)</term>
+      <indexterm>
+        <primary><varname>primary_conninfo</> configuration parameter</primary>
+      </indexterm>
+      <listitem>
+       <para>
+        Specifies a connection string to be used for the standby server
+        to connect with the primary. This string is in the format
+        accepted by the libpq <function>PQconnectdb</function> function,
+        described in <xref linkend="libpq-connect">. If any option is
+        unspecified in this string, then the corresponding environment
+        variable (see <xref linkend="libpq-envars">) is checked. If the
+        environment variable is not set either, then defaults are used.
+        If this parameter is an empty string (the default), no attempt is
+        made to connect to the master.
+       </para>
+       <para>
+        The connection string should specify the host name (or address)
+        of the primary server, as well as the port number if it is not
+        the same as the standby server's default.
+        Also specify a user name corresponding to a role that has the
+        <literal>REPLICATION</> and <literal>LOGIN</> privileges on the
+        primary (see
+        <xref linkend="streaming-replication-authentication">).
+        A password needs to be provided too, if the primary demands password
+        authentication.  It can be provided in the
+        <varname>primary_conninfo</varname> string, or in a separate
+        <filename>~/.pgpass</> file on the standby server (use
+        <literal>replication</> as the database name).
+        Do not specify a database name in the
+        <varname>primary_conninfo</varname> string.
+       </para>
+       <para>
+        This parameter can only be set in the <filename>postgresql.conf</>
+        file or on the server command line. It only has effect in standby mode.
+       </para>
+       <para>
+        If this parameter is changed while replication is in progress,
+        the standby terminates replication, and then tries to restart
+        replication with new setting.
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry id="guc-trigger-file" xreflabel="trigger_file">
+      <term><varname>trigger_file</varname> (<type>string</type>)</term>
+      <indexterm>
+        <primary><varname>trigger_file</> configuration parameter</primary>
+      </indexterm>
+      <listitem>
+       <para>
+        Specifies a trigger file whose presence ends recovery in the
+        standby.  Even if this value is not set, you can still promote
+        the standby using <command>pg_ctl promote</>.
+       </para>
+       <para>
+        This parameter can only be set in the <filename>postgresql.conf</>
+        file or on the server command line. It only has effect in standby mode.
+       </para>
+      </listitem>
+    </varlistentry>
+
      <varlistentry id="guc-hot-standby" xreflabel="hot_standby">
       <term><varname>hot_standby</varname> (<type>boolean</type>)</term>
       <indexterm>
diff --git a/doc/src/sgml/filelist.sgml b/doc/src/sgml/filelist.sgml
index b623f58..2eef816 100644
--- a/doc/src/sgml/filelist.sgml
+++ b/doc/src/sgml/filelist.sgml
@@ -43,7 +43,6 @@
 <!ENTITY manage-ag     SYSTEM "manage-ag.sgml">
 <!ENTITY monitoring    SYSTEM "monitoring.sgml">
 <!ENTITY regress       SYSTEM "regress.sgml">
-<!ENTITY recovery-config SYSTEM "recovery-config.sgml">
 <!ENTITY runtime       SYSTEM "runtime.sgml">
 <!ENTITY config        SYSTEM "config.sgml">
 <!ENTITY user-manag    SYSTEM "user-manag.sgml">
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 490d710..692470b 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -14969,7 +14969,7 @@ postgres=# select pg_start_backup('label_goes_here');
     <function>pg_create_restore_point</> creates a named transaction log
     record that can be used as recovery target, and returns the corresponding
     transaction log location.  The given name can then be used with
-    <xref linkend="recovery-target-name"> to specify the point up to which
+    <xref linkend="guc-recovery-target-name"> to specify the point up to which
     recovery will proceed.  Avoid creating multiple restore points with the
     same name, since recovery will stop at the first one whose name matches
     the recovery target.
diff --git a/doc/src/sgml/high-availability.sgml b/doc/src/sgml/high-availability.sgml
index c8f6fa8..a2993f5 100644
--- a/doc/src/sgml/high-availability.sgml
+++ b/doc/src/sgml/high-availability.sgml
@@ -591,7 +591,7 @@ protocol to make nodes agree on a serializable transactional order.
    <para>
     In standby mode, the server continuously applies WAL received from the
     master server. The standby server can read WAL from a WAL archive
-    (see <xref linkend="restore-command">) or directly from the master
+    (see <xref linkend="guc-restore-command">) or directly from the master
     over a TCP connection (streaming replication). The standby server will
     also attempt to restore any WAL found in the standby cluster's
     <filename>pg_xlog</> directory. That typically happens after a server
@@ -658,8 +658,8 @@ protocol to make nodes agree on a serializable transactional order.
    <para>
     To set up the standby server, restore the base backup taken from primary
     server (see <xref linkend="backup-pitr-recovery">). Create a recovery
-    command file <filename>recovery.conf</> in the standby's cluster data
-    directory, and turn on <varname>standby_mode</>. Set
+    trigger file <filename>standby.enabled</> in the standby's cluster data
+    directory. Turn on <varname>standby_mode</> and set
     <varname>restore_command</> to a simple command to copy files from
     the WAL archive. If you plan to have multiple standby servers for high
     availability purposes, set <varname>recovery_target_timeline</> to
@@ -695,7 +695,7 @@ protocol to make nodes agree on a serializable transactional order.
 
    <para>
     If you're using a WAL archive, its size can be minimized using the <xref
-    linkend="archive-cleanup-command"> parameter to remove files that are no
+    linkend="guc-archive-cleanup-command"> parameter to remove files that are no
     longer required by the standby server.
     The <application>pg_archivecleanup</> utility is designed specifically to
     be used with <varname>archive_cleanup_command</> in typical single-standby
@@ -706,7 +706,7 @@ protocol to make nodes agree on a serializable transactional order.
    </para>
 
    <para>
-    A simple example of a <filename>recovery.conf</> is:
+    A simple example of standby settings is:
 <programlisting>
 standby_mode = 'on'
 primary_conninfo = 'host=192.168.1.50 port=5432 user=foo password=foopass'
@@ -763,8 +763,8 @@ archive_cleanup_command = 'pg_archivecleanup /path/to/archive %r'
     To use streaming replication, set up a file-based log-shipping standby
     server as described in <xref linkend="warm-standby">. The step that
     turns a file-based log-shipping standby into streaming replication
-    standby is setting <varname>primary_conninfo</> setting in the
-    <filename>recovery.conf</> file to point to the primary server. Set
+    standby is setting <varname>primary_conninfo</> to
+    point to the primary server. Set
     <xref linkend="guc-listen-addresses"> and authentication options
     (see <filename>pg_hba.conf</>) on the primary so that the standby server
     can connect to the <literal>replication</> pseudo-database on the primary
@@ -824,15 +824,14 @@ host    replication     foo             192.168.1.100/32        md5
     </para>
     <para>
      The host name and port number of the primary, connection user name,
-     and password are specified in the <filename>recovery.conf</> file.
+     and password are specified in <varname>primary_conninfo</>.
      The password can also be set in the <filename>~/.pgpass</> file on the
      standby (specify <literal>replication</> in the <replaceable>database</>
      field).
      For example, if the primary is running on host IP <literal>192.168.1.50</>,
      port <literal>5432</literal>, the account name for replication is
      <literal>foo</>, and the password is <literal>foopass</>, the administrator
-     can add the following line to the <filename>recovery.conf</> file on the
-     standby:
+     can set <varname>primary_conninfo</> on the standby like this:
 
 <programlisting>
 # The standby connects to the primary that is running on host 192.168.1.50
@@ -1212,8 +1211,8 @@ primary_conninfo = 'host=192.168.1.50 port=5432 user=foo password=foopass'
    <para>
     To trigger failover of a log-shipping standby server,
     run <command>pg_ctl promote</> or create a trigger
-    file with the file name and path specified by the <varname>trigger_file</>
-    setting in <filename>recovery.conf</>. If you're planning to use
+    file with the file name and path specified by the <varname>trigger_file</>.
+    If you're planning to use
     <command>pg_ctl promote</> to fail over, <varname>trigger_file</> is
     not required. If you're setting up the reporting servers that are
     only used to offload read-only queries from the primary, not for high
@@ -1258,8 +1257,7 @@ primary_conninfo = 'host=192.168.1.50 port=5432 user=foo password=foopass'
     The magic that makes the two loosely coupled servers work together is
     simply a <varname>restore_command</> used on the standby that,
     when asked for the next WAL file, waits for it to become available from
-    the primary. The <varname>restore_command</> is specified in the
-    <filename>recovery.conf</> file on the standby server. Normal recovery
+    the primary. Normal recovery
     processing would request a file from the WAL archive, reporting failure
     if the file was unavailable.  For standby processing it is normal for
     the next WAL file to be unavailable, so the standby must wait for
@@ -1346,8 +1344,14 @@ if (!triggered)
      </listitem>
      <listitem>
       <para>
+       Create a file called <filename>standby.enabled</> in the standby's
+       cluster data directory to trigger the recovery.
+      </para>
+     </listitem>
+     <listitem>
+      <para>
        Begin recovery on the standby server from the local WAL
-       archive, using a <filename>recovery.conf</> that specifies a
+       archive, specifying a
        <varname>restore_command</> that waits as described
        previously (see <xref linkend="backup-pitr-recovery">).
       </para>
@@ -1838,9 +1842,8 @@ if (!triggered)
    <title>Administrator's Overview</title>
 
    <para>
-    If <varname>hot_standby</> is turned <literal>on</> in
-    <filename>postgresql.conf</> and there is a <filename>recovery.conf</>
-    file present, the server will run in Hot Standby mode.
+    If <varname>hot_standby</> is turned <literal>on</> and there is a file
+    <filename>standby.enabled</> present, the server will run in Hot Standby mode.
     However, it may take some time for Hot Standby connections to be allowed,
     because the server will not accept connections until it has completed
     sufficient recovery to provide a consistent state against which queries
diff --git a/doc/src/sgml/pgarchivecleanup.sgml b/doc/src/sgml/pgarchivecleanup.sgml
index 932914b..2984da4 100644
--- a/doc/src/sgml/pgarchivecleanup.sgml
+++ b/doc/src/sgml/pgarchivecleanup.sgml
@@ -38,8 +38,8 @@
 
   <para>
    To configure a standby
-   server to use <application>pg_archivecleanup</>, put this into its
-   <filename>recovery.conf</filename> configuration file:
+   server to use <application>pg_archivecleanup</>, specify
+   <xref linkend="guc-archive-cleanup-command"> like this:
 <programlisting>
 archive_cleanup_command = 'pg_archivecleanup <replaceable>archivelocation</> %r'
 </programlisting>
@@ -47,7 +47,7 @@ archive_cleanup_command = 'pg_archivecleanup <replaceable>archivelocation</> %r'
    files should be removed.
   </para>
   <para>
-   When used within <xref linkend="archive-cleanup-command">, all WAL files
+   When used within <varname>archive_cleanup_command</>, all WAL files
    logically preceding the value of the <literal>%r</> argument will be removed
    from <replaceable>archivelocation</>. This minimizes the number of files
    that need to be retained, while preserving crash-restart capability.  Use of
diff --git a/doc/src/sgml/pgstandby.sgml b/doc/src/sgml/pgstandby.sgml
index ca2b5c0..15097ca 100644
--- a/doc/src/sgml/pgstandby.sgml
+++ b/doc/src/sgml/pgstandby.sgml
@@ -46,8 +46,8 @@
 
   <para>
    To configure a standby
-   server to use <application>pg_standby</>, put this into its
-   <filename>recovery.conf</filename> configuration file:
+   server to use <application>pg_standby</>, specify
+   <xref linkend="guc-restore-command"> like this:
 <programlisting>
 restore_command = 'pg_standby <replaceable>archiveDir</> %f %p %r'
 </programlisting>
diff --git a/doc/src/sgml/postgres.sgml b/doc/src/sgml/postgres.sgml
index 15e4ef6..26e8dc2 100644
--- a/doc/src/sgml/postgres.sgml
+++ b/doc/src/sgml/postgres.sgml
@@ -155,7 +155,6 @@
   &maintenance;
   &backup;
   &high-availability;
-  &recovery-config;
   &monitoring;
   &diskusage;
   &wal;
diff --git a/doc/src/sgml/recovery-config.sgml b/doc/src/sgml/recovery-config.sgml
deleted file mode 100644
index c0c543e..0000000
--- a/doc/src/sgml/recovery-config.sgml
+++ /dev/null
@@ -1,361 +0,0 @@
-<!-- doc/src/sgml/recovery-config.sgml -->
-
-<chapter id="recovery-config">
-  <title>Recovery Configuration</title>
-
-  <indexterm>
-   <primary>configuration</primary>
-   <secondary>of recovery</secondary>
-   <tertiary>of a standby server</tertiary>
-  </indexterm>
-
-   <para>
-    This chapter describes the settings available in the
-    <filename>recovery.conf</><indexterm><primary>recovery.conf</></>
-    file. They apply only for the duration of the
-    recovery.  They must be reset for any subsequent recovery you wish to
-    perform.  They cannot be changed once recovery has begun.
-   </para>
-
-   <para>
-     Settings in <filename>recovery.conf</> are specified in the format
-     <literal>name = 'value'</>. One parameter is specified per line.
-     Hash marks (<literal>#</literal>) designate the rest of the
-     line as a comment.  To embed a single quote in a parameter
-     value, write two quotes (<literal>''</>).
-   </para>
-
-   <para>
-    A sample file, <filename>share/recovery.conf.sample</>,
-    is provided in the installation's <filename>share/</> directory.
-   </para>
-
-  <sect1 id="archive-recovery-settings">
-
-    <title>Archive Recovery Settings</title>
-     <variablelist>
-
-     <varlistentry id="restore-command" xreflabel="restore_command">
-      <term><varname>restore_command</varname> (<type>string</type>)</term>
-      <indexterm>
-        <primary><varname>restore_command</> recovery parameter</primary>
-      </indexterm>
-      <listitem>
-       <para>
-        The shell command to execute to retrieve an archived segment of
-        the WAL file series. This parameter is required for archive recovery,
-        but optional for streaming replication.
-        Any <literal>%f</> in the string is
-        replaced by the name of the file to retrieve from the archive,
-        and any <literal>%p</> is replaced by the copy destination path name
-        on the server.
-        (The path name is relative to the current working directory,
-        i.e., the cluster's data directory.)
-        Any <literal>%r</> is replaced by the name of the file containing the
-        last valid restart point. That is the earliest file that must be kept
-        to allow a restore to be restartable, so this information can be used
-        to truncate the archive to just the minimum required to support
-        restarting from the current restore. <literal>%r</> is typically only
-        used by warm-standby configurations
-        (see <xref linkend="warm-standby">).
-        Write <literal>%%</> to embed an actual <literal>%</> character.
-       </para>
-
-       <para>
-        It is important for the command to return a zero exit status
-        only if it succeeds.  The command <emphasis>will</> be asked for file
-        names that are not present in the archive; it must return nonzero
-        when so asked.  Examples:
-<programlisting>
-restore_command = 'cp /mnt/server/archivedir/%f "%p"'
-restore_command = 'copy "C:\\server\\archivedir\\%f" "%p"'  # Windows
-</programlisting>
-       </para>
-      </listitem>
-     </varlistentry>
-
-     <varlistentry id="archive-cleanup-command" xreflabel="archive_cleanup_command">
-      <term><varname>archive_cleanup_command</varname> (<type>string</type>)</term>
-      <indexterm>
-        <primary><varname>archive_cleanup_command</> recovery parameter</primary>
-      </indexterm>
-      <listitem>
-       <para>
-        This optional parameter specifies a shell command that will be executed
-        at every restartpoint.  The purpose of
-        <varname>archive_cleanup_command</> is to provide a mechanism for
-        cleaning up old archived WAL files that are no longer needed by the
-        standby server.
-        Any <literal>%r</> is replaced by the name of the file containing the
-        last valid restart point.
-        That is the earliest file that must be <emphasis>kept</> to allow a
-        restore to be restartable, and so all files earlier than <literal>%r</>
-        may be safely removed.
-        This information can be used to truncate the archive to just the
-        minimum required to support restart from the current restore.
-        The <xref linkend="pgarchivecleanup"> module
-        is often used in <varname>archive_cleanup_command</> for
-        single-standby configurations, for example:
-<programlisting>archive_cleanup_command = 'pg_archivecleanup /mnt/server/archivedir %r'</programlisting>
-        Note however that if multiple standby servers are restoring from the
-        same archive directory, you will need to ensure that you do not delete
-        WAL files until they are no longer needed by any of the servers.
-        <varname>archive_cleanup_command</> would typically be used in a
-        warm-standby configuration (see <xref linkend="warm-standby">).
-        Write <literal>%%</> to embed an actual <literal>%</> character in the
-        command.
-       </para>
-       <para>
-        If the command returns a non-zero exit status then a WARNING log
-        message will be written.
-       </para>
-      </listitem>
-     </varlistentry>
-
-     <varlistentry id="recovery-end-command" xreflabel="recovery_end_command">
-      <term><varname>recovery_end_command</varname> (<type>string</type>)</term>
-      <indexterm>
-        <primary><varname>recovery_end_command</> recovery parameter</primary>
-      </indexterm>
-      <listitem>
-       <para>
-        This parameter specifies a shell command that will be executed once only
-        at the end of recovery. This parameter is optional. The purpose of the
-        <varname>recovery_end_command</> is to provide a mechanism for cleanup
-        following replication or recovery.
-        Any <literal>%r</> is replaced by the name of the file containing the
-        last valid restart point, like in <xref linkend="archive-cleanup-command">.
-       </para>
-       <para>
-        If the command returns a non-zero exit status then a WARNING log
-        message will be written and the database will proceed to start up
-        anyway.  An exception is that if the command was terminated by a
-        signal, the database will not proceed with startup.
-       </para>
-      </listitem>
-     </varlistentry>
-
-    </variablelist>
-
-  </sect1>
-
-  <sect1 id="recovery-target-settings">
-
-    <title>Recovery Target Settings</title>
-     <variablelist>
-
-     <varlistentry id="recovery-target-name" xreflabel="recovery_target_name">
-      <term><varname>recovery_target_name</varname>
-           (<type>string</type>)
-      </term>
-      <indexterm>
-        <primary><varname>recovery_target_name</> recovery parameter</primary>
-      </indexterm>
-      <listitem>
-       <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>
-
-     <varlistentry id="recovery-target-time" xreflabel="recovery_target_time">
-      <term><varname>recovery_target_time</varname>
-           (<type>timestamp</type>)
-      </term>
-      <indexterm>
-        <primary><varname>recovery_target_time</> recovery parameter</primary>
-      </indexterm>
-      <listitem>
-       <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>
-      </listitem>
-     </varlistentry>
-
-     <varlistentry id="recovery-target-xid" xreflabel="recovery_target_xid">
-      <term><varname>recovery_target_xid</varname> (<type>string</type>)</term>
-      <indexterm>
-        <primary><varname>recovery_target_xid</> recovery parameter</primary>
-      </indexterm>
-      <listitem>
-       <para>
-        This parameter specifies the transaction ID up to which recovery
-        will proceed. Keep in mind
-        that while transaction IDs are assigned sequentially at transaction
-        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>
-
-     <varlistentry id="recovery-target-inclusive"
-                   xreflabel="recovery_target_inclusive">
-      <term><varname>recovery_target_inclusive</varname>
-        (<type>boolean</type>)
-      </term>
-      <indexterm>
-        <primary><varname>recovery_target_inclusive</> recovery parameter</primary>
-      </indexterm>
-      <listitem>
-       <para>
-        Specifies whether we stop just after the specified recovery target
-        (<literal>true</literal>), or just before the recovery target
-        (<literal>false</literal>).
-        Applies to both <xref linkend="recovery-target-time">
-        and <xref linkend="recovery-target-xid">, whichever one is
-        specified for this recovery.  This indicates whether transactions
-        having exactly the target commit time or ID, respectively, will
-        be included in the recovery.  Default is <literal>true</>.
-       </para>
-      </listitem>
-     </varlistentry>
-
-     <varlistentry id="recovery-target-timeline"
-                   xreflabel="recovery_target_timeline">
-      <term><varname>recovery_target_timeline</varname>
-        (<type>string</type>)
-      </term>
-      <indexterm>
-        <primary><varname>recovery_target_timeline</> recovery parameter</primary>
-      </indexterm>
-      <listitem>
-       <para>
-        Specifies recovering into a particular timeline.  The default is
-        to recover along the same timeline that was current when the
-        base backup was taken. Setting this to <literal>latest</> recovers
-        to the latest timeline found in the archive, which is useful in
-        a standby server. Other than that you only need to set this parameter
-        in complex re-recovery situations, where you need to return to
-        a state that itself was reached after a point-in-time recovery.
-        See <xref linkend="backup-timelines"> for discussion.
-       </para>
-      </listitem>
-     </varlistentry>
-
-     <varlistentry id="pause-at-recovery-target"
-                   xreflabel="pause_at_recovery_target">
-      <term><varname>pause_at_recovery_target</varname>
-        (<type>boolean</type>)
-      </term>
-      <indexterm>
-        <primary><varname>pause_at_recovery_target</> recovery parameter</primary>
-      </indexterm>
-      <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
-        <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
-        recovery target settings to a later target and restart to
-        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.
-       </para>
-      </listitem>
-     </varlistentry>
-
-     </variablelist>
-   </sect1>
-
-  <sect1 id="standby-settings">
-
-    <title>Standby Server Settings</title>
-     <variablelist>
-
-       <varlistentry id="standby-mode" xreflabel="standby_mode">
-        <term><varname>standby_mode</varname> (<type>boolean</type>)</term>
-        <indexterm>
-          <primary><varname>standby_mode</> recovery parameter</primary>
-        </indexterm>
-        <listitem>
-         <para>
-          Specifies whether to start the <productname>PostgreSQL</> server as
-          a standby. If this parameter is <literal>on</>, the server will
-          not stop recovery when the end of archived WAL is reached, but
-          will keep trying to continue recovery by fetching new WAL segments
-          using <varname>restore_command</>
-          and/or by connecting to the primary server as specified by the
-          <varname>primary_conninfo</> setting.
-         </para>
-        </listitem>
-       </varlistentry>
-       <varlistentry id="primary-conninfo" xreflabel="primary_conninfo">
-        <term><varname>primary_conninfo</varname> (<type>string</type>)</term>
-        <indexterm>
-          <primary><varname>primary_conninfo</> recovery parameter</primary>
-        </indexterm>
-        <listitem>
-         <para>
-          Specifies a connection string to be used for the standby server
-          to connect with the primary. This string is in the format
-          described in <xref linkend="libpq-connstring">. If any option is
-          unspecified in this string, then the corresponding environment
-          variable (see <xref linkend="libpq-envars">) is checked. If the
-          environment variable is not set either, then
-          defaults are used.
-         </para>
-         <para>
-          The connection string should specify the host name (or address)
-          of the primary server, as well as the port number if it is not
-          the same as the standby server's default.
-          Also specify a user name corresponding to a suitably-privileged role
-          on the primary (see
-          <xref linkend="streaming-replication-authentication">).
-          A password needs to be provided too, if the primary demands password
-          authentication.  It can be provided in the
-          <varname>primary_conninfo</varname> string, or in a separate
-          <filename>~/.pgpass</> file on the standby server (use
-          <literal>replication</> as the database name).
-          Do not specify a database name in the
-          <varname>primary_conninfo</varname> string.
-         </para>
-         <para>
-          This setting has no effect if <varname>standby_mode</> is <literal>off</>.
-         </para>
-        </listitem>
-       </varlistentry>
-       <varlistentry id="trigger-file" xreflabel="trigger_file">
-        <term><varname>trigger_file</varname> (<type>string</type>)</term>
-        <indexterm>
-          <primary><varname>trigger_file</> recovery parameter</primary>
-        </indexterm>
-        <listitem>
-         <para>
-          Specifies a trigger file whose presence ends recovery in the
-          standby.  Even if this value is not set, you can still promote
-          the standby using <command>pg_ctl promote</>.
-          This setting has no effect if <varname>standby_mode</> is <literal>off</>.
-         </para>
-        </listitem>
-       </varlistentry>
-
-     </variablelist>
-   </sect1>
-
-</chapter>
diff --git a/doc/src/sgml/ref/pg_basebackup.sgml b/doc/src/sgml/ref/pg_basebackup.sgml
index 578541a..df8c34d 100644
--- a/doc/src/sgml/ref/pg_basebackup.sgml
+++ b/doc/src/sgml/ref/pg_basebackup.sgml
@@ -190,11 +190,11 @@ PostgreSQL documentation
 
      <varlistentry>
       <term><option>-R</option></term>
-      <term><option>--write-recovery-conf</option></term>
+      <term><option>--write-standby-enable</option></term>
       <listitem>
 
        <para>
-        Write a minimal recovery.conf in the output directory (or into
+        Write a minimal standby.enabled in the output directory (or into
         the base archive file when using tar format) to ease setting
         up a standby server.
        </para>
diff --git a/doc/src/sgml/release-9.1.sgml b/doc/src/sgml/release-9.1.sgml
index b524477..f10e02f 100644
--- a/doc/src/sgml/release-9.1.sgml
+++ b/doc/src/sgml/release-9.1.sgml
@@ -4279,7 +4279,7 @@
       <listitem>
        <para>
         Add <filename>recovery.conf</> setting <link
-        linkend="pause-at-recovery-target"><varname>pause_at_recovery_target</></link>
+        linkend="guc-pause-at-recovery-target"><varname>pause_at_recovery_target</></link>
         to pause recovery at target (Simon Riggs)
        </para>
 
@@ -4299,7 +4299,7 @@
        <para>
         These named restore points can be specified as recovery
         targets using the new <filename>recovery.conf</> setting
-        <link linkend="recovery-target-name"><varname>recovery_target_name</></link>.
+        <link linkend="guc-recovery-target-name"><varname>recovery_target_name</></link>.
        </para>
       </listitem>
 
@@ -4331,8 +4331,7 @@
 
       <listitem>
        <para>
-        Allow <link
-        linkend="recovery-config"><filename>recovery.conf</></link>
+        Allow <filename>recovery.conf</>
         to use the same quoting behavior as <filename>postgresql.conf</>
         (Dimitri Fontaine)
        </para>
diff --git a/doc/src/sgml/release.sgml b/doc/src/sgml/release.sgml
index 2515329..252bf13 100644
--- a/doc/src/sgml/release.sgml
+++ b/doc/src/sgml/release.sgml
@@ -5,8 +5,8 @@ Typical markup:
 
 &<>                             use & escapes
 PostgreSQL                      <productname>
-postgresql.conf, pg_hba.conf,
-        recovery.conf           <filename>
+postgresql.conf, pg_hba.conf
+        standby.enabled         <filename>
 [A-Z][A-Z_ ]+[A-Z_]             <command>, <literal>, <envar>
 [A-Za-z_][A-Za-z0-9_]+()        <function>
 -[-A-Za-z_]+                    <option>
diff --git a/src/backend/Makefile b/src/backend/Makefile
index 318cdbc..58d42c5 100644
--- a/src/backend/Makefile
+++ b/src/backend/Makefile
@@ -225,7 +225,6 @@ endif
 	$(INSTALL_DATA) $(srcdir)/libpq/pg_hba.conf.sample '$(DESTDIR)$(datadir)/pg_hba.conf.sample'
 	$(INSTALL_DATA) $(srcdir)/libpq/pg_ident.conf.sample '$(DESTDIR)$(datadir)/pg_ident.conf.sample'
 	$(INSTALL_DATA) $(srcdir)/utils/misc/postgresql.conf.sample '$(DESTDIR)$(datadir)/postgresql.conf.sample'
-	$(INSTALL_DATA) $(srcdir)/access/transam/recovery.conf.sample '$(DESTDIR)$(datadir)/recovery.conf.sample'
 
 install-bin: postgres $(POSTGRES_IMP) installdirs
 	$(INSTALL_PROGRAM) postgres$(X) '$(DESTDIR)$(bindir)/postgres$(X)'
@@ -282,8 +281,7 @@ endif
 	$(MAKE) -C tsearch uninstall-data
 	rm -f '$(DESTDIR)$(datadir)/pg_hba.conf.sample' \
 	      '$(DESTDIR)$(datadir)/pg_ident.conf.sample' \
-              '$(DESTDIR)$(datadir)/postgresql.conf.sample' \
-	      '$(DESTDIR)$(datadir)/recovery.conf.sample'
+              '$(DESTDIR)$(datadir)/postgresql.conf.sample'
 
 
 ##########################################################################
diff --git a/src/backend/access/transam/recovery.conf.sample b/src/backend/access/transam/recovery.conf.sample
deleted file mode 100644
index 5acfa57..0000000
--- a/src/backend/access/transam/recovery.conf.sample
+++ /dev/null
@@ -1,132 +0,0 @@
-# -------------------------------
-# PostgreSQL recovery config file
-# -------------------------------
-#
-# Edit this file to provide the parameters that PostgreSQL needs to
-# perform an archive recovery of a database, or to act as a replication
-# standby.
-#
-# If "recovery.conf" is present in the PostgreSQL data directory, it is
-# read on postmaster startup.  After successful recovery, it is renamed
-# to "recovery.done" to ensure that we do not accidentally re-enter
-# archive recovery or standby mode.
-#
-# This file consists of lines of the form:
-#
-#   name = value
-#
-# Comments are introduced with '#'.
-#
-# The complete list of option names and allowed values can be found
-# in the PostgreSQL documentation.
-#
-#---------------------------------------------------------------------------
-# ARCHIVE RECOVERY PARAMETERS
-#---------------------------------------------------------------------------
-#
-# restore_command
-#
-# specifies the shell command that is executed to copy log files
-# back from archival storage.  The command string may contain %f,
-# which is replaced by the name of the desired log file, and %p,
-# which is replaced by the absolute path to copy the log file to.
-#
-# This parameter is *required* for an archive recovery, but optional
-# for streaming replication.
-#
-# It is important that the command return nonzero exit status on failure.
-# The command *will* be asked for log files that are not present in the
-# archive; it must return nonzero when so asked.
-#
-# NOTE that the basename of %p will be different from %f; do not
-# expect them to be interchangeable.
-#
-#restore_command = ''		# e.g. 'cp /mnt/server/archivedir/%f %p'
-#
-#
-# archive_cleanup_command
-#
-# specifies an optional shell command to execute at every restartpoint.
-# This can be useful for cleaning up the archive of a standby server.
-#
-#archive_cleanup_command = ''
-#
-# recovery_end_command
-#
-# specifies an optional shell command to execute at completion of recovery.
-# This can be useful for cleaning up after the restore_command.
-#
-#recovery_end_command = ''
-#
-#---------------------------------------------------------------------------
-# RECOVERY TARGET PARAMETERS
-#---------------------------------------------------------------------------
-#
-# By default, recovery will rollforward to the end of the WAL log.
-# If you want to stop rollforward at a specific point, you
-# must set a recovery target.
-#
-# You may set a recovery target either by transactionId, by name,
-# or by timestamp. Recovery may either include or exclude the
-# transaction(s) with the recovery target value (ie, stop either
-# just after or just before the given target, respectively).
-#
-#
-#recovery_target_name = ''	# e.g. 'daily backup 2011-01-26'
-#
-#recovery_target_time = ''	# e.g. '2004-07-14 22:39:00 EST'
-#
-#recovery_target_xid = ''
-#
-#recovery_target_inclusive = true
-#
-#
-# If you want to recover into a timeline other than the "main line" shown in
-# pg_control, specify the timeline number here, or write 'latest' to get
-# the latest branch for which there's a history file.
-#
-#recovery_target_timeline = 'latest'
-#
-#
-# If pause_at_recovery_target is enabled, recovery will pause when
-# the recovery target is reached. The pause state will continue until
-# pg_xlog_replay_resume() is called. This setting has no effect if
-# hot standby is not enabled, or if no recovery target is set.
-#
-#pause_at_recovery_target = true
-#
-#---------------------------------------------------------------------------
-# STANDBY SERVER PARAMETERS
-#---------------------------------------------------------------------------
-#
-# standby_mode
-#
-# When standby_mode is enabled, the PostgreSQL server will work as a
-# standby. It will continuously wait for the additional XLOG records, using
-# restore_command and/or primary_conninfo.
-#
-#standby_mode = off
-#
-# primary_conninfo
-#
-# If set, the PostgreSQL server will try to connect to the primary using this
-# connection string and receive XLOG records continuously.
-#
-#primary_conninfo = ''		# e.g. 'host=localhost port=5432'
-#
-#
-# By default, a standby server keeps restoring XLOG records from the
-# primary indefinitely. If you want to stop the standby mode, finish recovery
-# and open the system in read/write mode, specify path to a trigger file.
-# The server will poll the trigger file path periodically and start as a
-# primary server when it's found.
-#
-#trigger_file = ''
-#
-#---------------------------------------------------------------------------
-# HOT STANDBY PARAMETERS
-#---------------------------------------------------------------------------
-#
-# Hot Standby related parameters are listed in postgresql.conf
-#
-#---------------------------------------------------------------------------
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 07c68ad..5a0b5fe 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -63,11 +63,12 @@
 extern bool bootstrap_data_checksums;
 
 /* File path names (all relative to $PGDATA) */
-#define RECOVERY_COMMAND_FILE	"recovery.conf"
-#define RECOVERY_COMMAND_DONE	"recovery.done"
-#define PROMOTE_SIGNAL_FILE "promote"
+#define RECOVERY_ENABLE_FILE	"standby.enabled"
+#define PROMOTE_SIGNAL_FILE	"promote"
 #define FAST_PROMOTE_SIGNAL_FILE "fast_promote"
 
+/* recovery.conf is not supported anymore */
+#define RECOVERY_COMMAND_FILE	"recovery.conf"
 
 /* User-settable parameters */
 int			CheckPointSegments = 3;
@@ -83,6 +84,23 @@ int			sync_method = DEFAULT_SYNC_METHOD;
 int			wal_level = WAL_LEVEL_MINIMAL;
 int			CommitDelay = 0;	/* precommit delay in microseconds */
 int			CommitSiblings = 5; /* # concurrent xacts needed to sleep */
+char	   *restore_command = NULL;
+char	   *archive_cleanup_command = NULL;
+char	   *recovery_end_command = NULL;
+bool		StandbyModeRequested = false;
+char	   *primary_conninfo = NULL;
+char	   *trigger_file = NULL;
+RecoveryTargetType	recovery_target = RECOVERY_TARGET_UNSET;
+TransactionId		recovery_target_xid = InvalidTransactionId;
+TimestampTz			recovery_target_time = 0;
+char	   *recovery_target_name = NULL;
+bool		recovery_target_inclusive = true;
+bool		pause_at_recovery_target = true;
+char	   *recovery_target_timeline_string = NULL;
+TimeLineID	recovery_target_timeline = 0;
+
+/* are we currently in standby mode? */
+bool StandbyMode = false;
 
 #ifdef WAL_DEBUG
 bool		XLOG_DEBUG = false;
@@ -206,29 +224,11 @@ bool InArchiveRecovery = false;
 /* Was the last xlog file restored from archive, or local? */
 static bool restoredFromArchive = false;
 
-/* options 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 bool recoveryPauseAtTarget = true;
-static TransactionId recoveryTargetXid;
-static TimestampTz recoveryTargetTime;
-static char *recoveryTargetName;
-
-/* options taken from recovery.conf for XLOG streaming */
-static bool StandbyModeRequested = false;
-static char *PrimaryConnInfo = NULL;
-static char *TriggerFile = NULL;
-
-/* are we currently in standby mode? */
-bool StandbyMode = false;
-
 /* whether request for fast promotion has been made yet */
 static bool fast_promote = false;
 
 /* if recoveryStopsHere returns true, it saves actual stop xid/time/name here */
+static RecoveryTargetType recoveryStopTarget;
 static TransactionId recoveryStopXid;
 static TimestampTz recoveryStopTime;
 static char recoveryStopName[MAXFNAMELEN];
@@ -437,12 +437,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.
 	 */
@@ -631,7 +625,7 @@ static bool InRedo = false;
 static bool bgwriterLaunched = false;
 
 
-static void readRecoveryCommandFile(void);
+static void CheckRecoveryReadyFile(void);
 static void exitArchiveRecovery(TimeLineID endTLI, XLogSegNo endLogSegNo);
 static bool recoveryStopsHere(XLogRecord *record, bool *includeThis);
 static void recoveryPausesHere(void);
@@ -3326,7 +3320,7 @@ ReadRecord(XLogReaderState *xlogreader, XLogRecPtr RecPtr, int emode,
 				ereport(DEBUG1,
 						(errmsg_internal("reached end of WAL in pg_xlog, entering archive recovery")));
 				InArchiveRecovery = true;
-				if (StandbyModeRequested)
+				if (ArchiveRecoveryRequested && StandbyModeRequested)
 					StandbyMode = true;
 
 				/* initialize minRecoveryPoint to this record */
@@ -4148,212 +4142,47 @@ 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.
- *
- * The file is parsed using the main configuration parser.
+ * Check to see if there is a recovery trigger file (standby.enabled).
+ * If so, validate recovery parameters and determine recovery target timeline.
  */
 static void
-readRecoveryCommandFile(void)
+CheckRecoveryReadyFile(void)
 {
-	FILE	   *fd;
-	TimeLineID	rtli = 0;
-	bool		rtliGiven = false;
-	ConfigVariable *item,
-			   *head = NULL,
-			   *tail = NULL;
-
-	fd = AllocateFile(RECOVERY_COMMAND_FILE, "r");
+	FILE *fd;
+
+	/* Check the presence of recovery.conf, it is not supported anymore */
+	if (AllocateFile(RECOVERY_COMMAND_FILE, "r") != NULL)
+		ereport(FATAL,
+				(errmsg("\"%s\" is not supported anymore as a recovery method",
+						RECOVERY_COMMAND_FILE),
+				 errdetail("Refer to appropriate documentation about migration methods")));
+
+	/* Check the presence of file standby.enabled, the file triggering recovery */
+	fd = AllocateFile(RECOVERY_ENABLE_FILE, "r");
 	if (fd == NULL)
 	{
 		if (errno == ENOENT)
 			return;				/* not there, so no archive recovery */
 		ereport(FATAL,
 				(errcode_for_file_access(),
-				 errmsg("could not open recovery command file \"%s\": %m",
-						RECOVERY_COMMAND_FILE)));
-	}
-
-	/*
-	 * Since we're asking ParseConfigFp() to report errors as FATAL, there's
-	 * no need to check the return value.
-	 */
-	(void) ParseConfigFp(fd, RECOVERY_COMMAND_FILE, 0, FATAL, &head, &tail);
-
-	FreeFile(fd);
-
-	for (item = head; item; item = item->next)
-	{
-		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, "pause_at_recovery_target") == 0)
-		{
-			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)));
-		}
-		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,
-							(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,
-				 (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)
-		{
-			/*
-			 * if recovery_target_xid or recovery_target_name specified, then
-			 * this overrides recovery_target_time
-			 */
-			if (recoveryTarget == RECOVERY_TARGET_XID ||
-				recoveryTarget == RECOVERY_TARGET_NAME)
-				continue;
-			recoveryTarget = RECOVERY_TARGET_TIME;
-
-			/*
-			 * 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)
-		{
-			/*
-			 * if recovery_target_xid specified, then this overrides
-			 * recovery_target_name
-			 */
-			if (recoveryTarget == RECOVERY_TARGET_XID)
-				continue;
-			recoveryTarget = RECOVERY_TARGET_NAME;
-
-			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)));
-
-			ereport(DEBUG2,
-					(errmsg_internal("recovery_target_name = '%s'",
-									 recoveryTargetName)));
-		}
-		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, "trigger_file") == 0)
-		{
-			TriggerFile = pstrdup(item->value);
-			ereport(DEBUG2,
-					(errmsg_internal("trigger_file = '%s'",
-									 TriggerFile)));
-		}
-		else
-			ereport(FATAL,
-					(errmsg("unrecognized recovery parameter \"%s\"",
-							item->name)));
+				 errmsg("could not open recovery file trigger \"%s\": %m",
+						RECOVERY_ENABLE_FILE)));
 	}
 
-	/*
-	 * Check for compulsory parameters
-	 */
+	/* Check for compulsory parameters */
 	if (StandbyModeRequested)
 	{
-		if (PrimaryConnInfo == NULL && recoveryRestoreCommand == NULL)
+		if (!restore_command[0] && !primary_conninfo[0])
 			ereport(WARNING,
-					(errmsg("recovery command file \"%s\" specified neither primary_conninfo nor restore_command",
-							RECOVERY_COMMAND_FILE),
+					(errmsg("Neither primary_conninfo nor restore_command specified"),
 					 errhint("The database server will regularly poll the pg_xlog subdirectory to check for files placed there.")));
 	}
 	else
 	{
-		if (recoveryRestoreCommand == NULL)
+		if (!restore_command[0])
 			ereport(FATAL,
-					(errmsg("recovery command file \"%s\" must specify restore_command when standby mode is not enabled",
-							RECOVERY_COMMAND_FILE)));
+					(errmsg("restore_command must be specified when "
+							"standby_mode is not enabled")));
 	}
 
 	/* Enable fetching from archive recovery area */
@@ -4365,16 +4194,17 @@ readRecoveryCommandFile(void)
 	 * command and set InArchiveRecovery, because we need to fetch timeline
 	 * history files from the archive.
 	 */
-	if (rtliGiven)
+	if (strcmp(recovery_target_timeline_string, "") != 0)
 	{
-		if (rtli)
+		if (recovery_target_timeline)
 		{
 			/* Timeline 1 does not have a history file, all else should */
-			if (rtli != 1 && !existsTimeLineHistory(rtli))
+			if (recovery_target_timeline != 1 &&
+				!existsTimeLineHistory(recovery_target_timeline))
 				ereport(FATAL,
 						(errmsg("recovery target timeline %u does not exist",
-								rtli)));
-			recoveryTargetTLI = rtli;
+								recovery_target_timeline)));
+			recoveryTargetTLI = recovery_target_timeline;
 			recoveryTargetIsLatest = false;
 		}
 		else
@@ -4384,8 +4214,6 @@ readRecoveryCommandFile(void)
 			recoveryTargetIsLatest = true;
 		}
 	}
-
-	FreeConfigVariables(head);
 }
 
 /*
@@ -4456,15 +4284,13 @@ exitArchiveRecovery(TimeLineID endTLI, XLogSegNo endLogSegNo)
 	unlink(recoveryPath);		/* ignore any error */
 
 	/*
-	 * Rename the config file out of the way, so that we don't accidentally
-	 * re-enter archive recovery mode in a subsequent crash.
+	 * Remove file that triggered the recovery
 	 */
-	unlink(RECOVERY_COMMAND_DONE);
-	if (rename(RECOVERY_COMMAND_FILE, RECOVERY_COMMAND_DONE) != 0)
+	if (unlink(RECOVERY_ENABLE_FILE) != 0)
 		ereport(FATAL,
 				(errcode_for_file_access(),
-				 errmsg("could not rename file \"%s\" to \"%s\": %m",
-						RECOVERY_COMMAND_FILE, RECOVERY_COMMAND_DONE)));
+				 errmsg("could not remove file \"%s\": %m",
+						RECOVERY_ENABLE_FILE)));
 
 	ereport(LOG,
 			(errmsg("archive recovery complete")));
@@ -4527,7 +4353,7 @@ recoveryStopsHere(XLogRecord *record, bool *includeThis)
 		return false;
 
 	/* Do we have a PITR target at all? */
-	if (recoveryTarget == RECOVERY_TARGET_UNSET)
+	if (recovery_target == RECOVERY_TARGET_UNSET)
 	{
 		/*
 		 * Save timestamp of latest transaction commit/abort if this is a
@@ -4538,7 +4364,7 @@ recoveryStopsHere(XLogRecord *record, bool *includeThis)
 		return false;
 	}
 
-	if (recoveryTarget == RECOVERY_TARGET_XID)
+	if (recovery_target == RECOVERY_TARGET_XID)
 	{
 		/*
 		 * There can be only one transaction end record with this exact
@@ -4549,17 +4375,17 @@ recoveryStopsHere(XLogRecord *record, bool *includeThis)
 		 * they complete. A higher numbered xid will complete before you about
 		 * 50% of the time...
 		 */
-		stopsHere = (record->xl_xid == recoveryTargetXid);
+		stopsHere = (record->xl_xid == recovery_target_xid);
 		if (stopsHere)
-			*includeThis = recoveryTargetInclusive;
+			*includeThis = recovery_target_inclusive;
 	}
-	else if (recoveryTarget == RECOVERY_TARGET_NAME)
+	else if (recovery_target == RECOVERY_TARGET_NAME)
 	{
 		/*
 		 * There can be many restore points that share the same name, so we
 		 * stop at the first one
 		 */
-		stopsHere = (strcmp(recordRPName, recoveryTargetName) == 0);
+		stopsHere = (strcmp(recordRPName, recovery_target_name) == 0);
 
 		/*
 		 * Ignore recoveryTargetInclusive because this is not a transaction
@@ -4574,16 +4400,17 @@ recoveryStopsHere(XLogRecord *record, bool *includeThis)
 		 * we stop after the last one, if we are inclusive, or stop at the
 		 * first one if we are exclusive
 		 */
-		if (recoveryTargetInclusive)
-			stopsHere = (recordXtime > recoveryTargetTime);
+		if (recovery_target_inclusive)
+			stopsHere = (recordXtime > recovery_target_time);
 		else
-			stopsHere = (recordXtime >= recoveryTargetTime);
+			stopsHere = (recordXtime >= recovery_target_time);
 		if (stopsHere)
 			*includeThis = false;
 	}
 
 	if (stopsHere)
 	{
+		recoveryStopTarget = recovery_target;
 		recoveryStopXid = record->xl_xid;
 		recoveryStopTime = recordXtime;
 		recoveryStopAfter = *includeThis;
@@ -4933,36 +4760,28 @@ 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 recovery trigger file, and if so set up state for offline
+	 * recovery.
 	 */
-	strncpy(XLogCtl->archiveCleanupCommand,
-			archiveCleanupCommand ? archiveCleanupCommand : "",
-			sizeof(XLogCtl->archiveCleanupCommand));
+	CheckRecoveryReadyFile();
 
 	if (ArchiveRecoveryRequested)
 	{
 		if (StandbyModeRequested)
 			ereport(LOG,
 					(errmsg("entering standby mode")));
-		else if (recoveryTarget == RECOVERY_TARGET_XID)
+		else if (recovery_target == RECOVERY_TARGET_XID)
 			ereport(LOG,
 					(errmsg("starting point-in-time recovery to XID %u",
-							recoveryTargetXid)));
-		else if (recoveryTarget == RECOVERY_TARGET_TIME)
+							recovery_target_xid)));
+		else if (recovery_target == RECOVERY_TARGET_TIME)
 			ereport(LOG,
 					(errmsg("starting point-in-time recovery to %s",
-							timestamptz_to_str(recoveryTargetTime))));
-		else if (recoveryTarget == RECOVERY_TARGET_NAME)
+							timestamptz_to_str(recovery_target_time))));
+		else if (recovery_target == RECOVERY_TARGET_NAME)
 			ereport(LOG,
 					(errmsg("starting point-in-time recovery to \"%s\"",
-							recoveryTargetName)));
+							recovery_target_name)));
 		else
 			ereport(LOG,
 					(errmsg("starting archive recovery")));
@@ -4988,7 +4807,7 @@ StartupXLOG(void)
 	 * Take ownership of the wakeup latch if we're going to sleep during
 	 * recovery.
 	 */
-	if (StandbyModeRequested)
+	if (ArchiveRecoveryRequested && StandbyModeRequested)
 		OwnLatch(&XLogCtl->recoveryWakeupLatch);
 
 	/* Set up XLOG reader facility */
@@ -5010,7 +4829,7 @@ StartupXLOG(void)
 		 * archive recovery directly.
 		 */
 		InArchiveRecovery = true;
-		if (StandbyModeRequested)
+		if (ArchiveRecoveryRequested && StandbyModeRequested)
 			StandbyMode = true;
 
 		/*
@@ -5076,7 +4895,7 @@ StartupXLOG(void)
 			 ControlFile->state == DB_SHUTDOWNED))
 		{
 			InArchiveRecovery = true;
-			if (StandbyModeRequested)
+			if (ArchiveRecoveryRequested && StandbyModeRequested)
 				StandbyMode = true;
 		}
 
@@ -5236,7 +5055,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 standby.enabled file,
 	 * then assume no recovery needed.
 	 */
 	if (checkPoint.redo < RecPtr)
@@ -5250,7 +5069,7 @@ StartupXLOG(void)
 		InRecovery = true;
 	else if (ArchiveRecoveryRequested)
 	{
-		/* force recovery due to presence of recovery.conf */
+		/* force recovery due to presence of standby.enabled */
 		InRecovery = true;
 	}
 
@@ -5569,7 +5388,7 @@ StartupXLOG(void)
 				 */
 				if (recoveryStopsHere(record, &recoveryApply))
 				{
-					if (recoveryPauseAtTarget)
+					if (pause_at_recovery_target)
 					{
 						SetRecoveryPause(true);
 						recoveryPausesHere();
@@ -5733,7 +5552,7 @@ StartupXLOG(void)
 	 * We don't need the latch anymore. It's not strictly necessary to disown
 	 * it, but let's do it for the sake of tidiness.
 	 */
-	if (StandbyModeRequested)
+	if (ArchiveRecoveryRequested && StandbyModeRequested)
 		DisownLatch(&XLogCtl->recoveryWakeupLatch);
 
 	/*
@@ -5823,17 +5642,17 @@ StartupXLOG(void)
 		 * Create a comment for the history file to explain why and where
 		 * timeline changed.
 		 */
-		if (recoveryTarget == RECOVERY_TARGET_XID)
+		if (recovery_target == RECOVERY_TARGET_XID)
 			snprintf(reason, sizeof(reason),
 					 "%s transaction %u",
 					 recoveryStopAfter ? "after" : "before",
 					 recoveryStopXid);
-		else if (recoveryTarget == RECOVERY_TARGET_TIME)
+		else if (recovery_target == RECOVERY_TARGET_TIME)
 			snprintf(reason, sizeof(reason),
 					 "%s %s\n",
 					 recoveryStopAfter ? "after" : "before",
 					 timestamptz_to_str(recoveryStopTime));
-		else if (recoveryTarget == RECOVERY_TARGET_NAME)
+		else if (recovery_target == RECOVERY_TARGET_NAME)
 			snprintf(reason, sizeof(reason),
 					 "at restore point \"%s\"",
 					 recoveryStopName);
@@ -5992,8 +5811,8 @@ StartupXLOG(void)
 		/*
 		 * And finally, execute the recovery_end_command, if any.
 		 */
-		if (recoveryEndCommand)
-			ExecuteRecoveryCommand(recoveryEndCommand,
+		if (recovery_end_command[0])
+			ExecuteRecoveryCommand(recovery_end_command,
 								   "recovery_end_command",
 								   true);
 	}
@@ -6861,7 +6680,7 @@ CreateCheckPoint(int flags)
 		XLogRecPtr	curInsert;
 
 		INSERT_RECPTR(curInsert, Insert, Insert->curridx);
-		if (curInsert == ControlFile->checkPoint + 
+		if (curInsert == ControlFile->checkPoint +
 			MAXALIGN(SizeOfXLogRecord + sizeof(CheckPoint)) &&
 			ControlFile->checkPoint == ControlFile->checkPointCopy.redo)
 		{
@@ -7509,8 +7328,8 @@ CreateRestartPoint(int flags)
 	/*
 	 * Finally, execute archive_cleanup_command, if any.
 	 */
-	if (XLogCtl->archiveCleanupCommand[0])
-		ExecuteRecoveryCommand(XLogCtl->archiveCleanupCommand,
+	if (archive_cleanup_command[0])
+		ExecuteRecoveryCommand(archive_cleanup_command,
 							   "archive_cleanup_command",
 							   false);
 
@@ -9325,7 +9144,7 @@ XLogPageRead(XLogReaderState *xlogreader, XLogRecPtr targetPagePtr, int reqLen,
 		 * Request a restartpoint if we've replayed too much xlog since the
 		 * last one.
 		 */
-		if (StandbyModeRequested && bgwriterLaunched)
+		if (ArchiveRecoveryRequested && StandbyModeRequested && bgwriterLaunched)
 		{
 			if (XLogCheckpointNeeded(readSegNo))
 			{
@@ -9541,7 +9360,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 (primary_conninfo[0])
 					{
 						XLogRecPtr ptr;
 						TimeLineID tli;
@@ -9562,7 +9381,7 @@ WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess,
 									 tli, curFileTLI);
 						}
 						curFileTLI = tli;
-						RequestXLogStreaming(curFileTLI, ptr, PrimaryConnInfo);
+						RequestXLogStreaming(curFileTLI, ptr);
 					}
 					/*
 					 * Move to XLOG_FROM_STREAM state in either case. We'll get
@@ -9880,14 +9699,14 @@ CheckForStandbyTrigger(void)
 		return true;
 	}
 
-	if (TriggerFile == NULL)
+	if (!trigger_file[0])
 		return false;
 
-	if (stat(TriggerFile, &stat_buf) == 0)
+	if (stat(trigger_file, &stat_buf) == 0)
 	{
 		ereport(LOG,
-				(errmsg("trigger file found: %s", TriggerFile)));
-		unlink(TriggerFile);
+				(errmsg("trigger file found: %s", trigger_file)));
+		unlink(trigger_file);
 		triggered = true;
 		return true;
 	}
diff --git a/src/backend/access/transam/xlogarchive.c b/src/backend/access/transam/xlogarchive.c
index 0c178c5..21e2eee 100644
--- a/src/backend/access/transam/xlogarchive.c
+++ b/src/backend/access/transam/xlogarchive.c
@@ -67,7 +67,7 @@ RestoreArchivedFile(char *path, const char *xlogfname,
 	TimeLineID	restartTli;
 
 	/* In standby mode, restore_command might not be supplied */
-	if (recoveryRestoreCommand == NULL)
+	if (restore_command == NULL)
 		goto not_available;
 
 	/*
@@ -150,7 +150,7 @@ RestoreArchivedFile(char *path, const char *xlogfname,
 	endp = xlogRestoreCmd + MAXPGPATH - 1;
 	*endp = '\0';
 
-	for (sp = recoveryRestoreCommand; *sp; sp++)
+	for (sp = restore_command; *sp; sp++)
 	{
 		if (*sp == '%')
 		{
diff --git a/src/backend/commands/extension.c b/src/backend/commands/extension.c
index 36df8bd..adea8a0 100644
--- a/src/backend/commands/extension.c
+++ b/src/backend/commands/extension.c
@@ -9,7 +9,7 @@
  * dependent objects can be associated with it.  An extension is created by
  * populating the pg_extension catalog from a "control" file.
  * The extension control file is parsed with the same parser we use for
- * postgresql.conf and recovery.conf.  An extension also has an installation
+ * postgresql.conf.  An extension also has an installation
  * script file, containing SQL commands to create the extension's objects.
  *
  * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index 911a66b..9f8d450 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -186,7 +186,6 @@ DisableWalRcvImmediateExit(void)
 void
 WalReceiverMain(void)
 {
-	char		conninfo[MAXCONNINFO];
 	XLogRecPtr	startpoint;
 	TimeLineID	startpointTLI;
 	TimeLineID	primaryTLI;
@@ -240,7 +239,6 @@ WalReceiverMain(void)
 	walrcv->walRcvState = WALRCV_STREAMING;
 
 	/* Fetch information required to start streaming */
-	strlcpy(conninfo, (char *) walrcv->conninfo, MAXCONNINFO);
 	startpoint = walrcv->receiveStart;
 	startpointTLI = walrcv->receiveStartTLI;
 
@@ -307,7 +305,7 @@ WalReceiverMain(void)
 
 	/* Establish the connection to the primary for XLOG streaming */
 	EnableWalRcvImmediateExit();
-	walrcv_connect(conninfo);
+	walrcv_connect(primary_conninfo);
 	DisableWalRcvImmediateExit();
 
 	first_stream = true;
@@ -405,8 +403,22 @@ WalReceiverMain(void)
 
 				if (got_SIGHUP)
 				{
+					char    *conninfo = pstrdup(primary_conninfo);
+
 					got_SIGHUP = false;
 					ProcessConfigFile(PGC_SIGHUP);
+
+					/*
+					 * If primary_conninfo has been changed while walreceiver is running,
+					 * shut down walreceiver so that new walreceiver is started and
+					 * it initiates replication with new primary_conninfo.
+					 */
+					if (strcmp(conninfo, primary_conninfo) != 0)
+						ereport(FATAL,
+								(errcode(ERRCODE_ADMIN_SHUTDOWN),
+								 errmsg("terminating walreceiver process because primary_conninfo was changed")));
+					pfree(conninfo);
+
 					XLogWalRcvSendHSFeedback(true);
 				}
 
diff --git a/src/backend/replication/walreceiverfuncs.c b/src/backend/replication/walreceiverfuncs.c
index d414808..d6a5e06 100644
--- a/src/backend/replication/walreceiverfuncs.c
+++ b/src/backend/replication/walreceiverfuncs.c
@@ -219,11 +219,10 @@ ShutdownWalRcv(void)
 /*
  * Request postmaster to start walreceiver.
  *
- * recptr indicates the position where streaming should begin, and conninfo
- * is a libpq connection string to use.
+ * recptr indicates the position where streaming should begin.
  */
 void
-RequestXLogStreaming(TimeLineID tli, XLogRecPtr recptr, const char *conninfo)
+RequestXLogStreaming(TimeLineID tli, XLogRecPtr recptr)
 {
 	/* use volatile pointer to prevent code rearrangement */
 	volatile WalRcvData *walrcv = WalRcv;
@@ -245,11 +244,6 @@ RequestXLogStreaming(TimeLineID tli, XLogRecPtr recptr, const char *conninfo)
 	Assert(walrcv->walRcvState == WALRCV_STOPPED ||
 		   walrcv->walRcvState == WALRCV_WAITING);
 
-	if (conninfo != NULL)
-		strlcpy((char *) walrcv->conninfo, conninfo, MAXCONNINFO);
-	else
-		walrcv->conninfo[0] = '\0';
-
 	if (walrcv->walRcvState == WALRCV_STOPPED)
 	{
 		launch = true;
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 22ba35f..c8cd004 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -30,6 +30,7 @@
 #include "access/transam.h"
 #include "access/twophase.h"
 #include "access/xact.h"
+#include "access/xlog_internal.h"
 #include "catalog/namespace.h"
 #include "commands/async.h"
 #include "commands/prepare.h"
@@ -197,6 +198,14 @@ static bool check_application_name(char **newval, void **extra, GucSource source
 static void assign_application_name(const char *newval, void *extra);
 static const char *show_unix_socket_permissions(void);
 static const char *show_log_file_mode(void);
+static bool check_recovery_target_xid(char **newval, void **extra, GucSource source);
+static void assign_recovery_target_xid(const char *newval, void *extra);
+static bool check_recovery_target_name(char **newval, void **extra, GucSource source);
+static void assign_recovery_target_name(const char *newval, void *extra);
+static bool check_recovery_target_time(char **newval, void **extra, GucSource source);
+static void assign_recovery_target_time(const char *newval, void *extra);
+static bool check_recovery_target_timeline(char **newval, void **extra, GucSource source);
+static void assign_recovery_target_timeline(const char *newval, void *extra);
 
 static char *config_enum_get_options(struct config_enum * record,
 						const char *prefix, const char *suffix,
@@ -469,6 +478,8 @@ static int	wal_block_size;
 static int	wal_segment_size;
 static bool integer_datetimes;
 static int	effective_io_concurrency;
+static char *recovery_target_xid_string;
+static char *recovery_target_time_string;
 
 /* should be static, but commands/variable.c needs to get at this */
 char	   *role_string;
@@ -549,6 +560,10 @@ const char *const config_group_names[] =
 	gettext_noop("Write-Ahead Log / Checkpoints"),
 	/* WAL_ARCHIVING */
 	gettext_noop("Write-Ahead Log / Archiving"),
+	/* WAL_ARCHIVE_RECOVERY */
+	gettext_noop("Write-Ahead Log / Archive Recovery"),
+	/* WAL_RECOVERY_TARGET */
+	gettext_noop("Write-Ahead Log / Recovery Target"),
 	/* REPLICATION */
 	gettext_noop("Replication"),
 	/* REPLICATION_SENDING */
@@ -1392,6 +1407,36 @@ static struct config_bool ConfigureNamesBool[] =
 	},
 
 	{
+		{"recovery_target_inclusive", PGC_SIGHUP, WAL_RECOVERY_TARGET,
+			gettext_noop("Sets whether to include or exclude transaction with recovery target."),
+			NULL
+		},
+		&recovery_target_inclusive,
+		true,
+		NULL, NULL, NULL
+	},
+
+	{
+		{"pause_at_recovery_target", PGC_SIGHUP, WAL_RECOVERY_TARGET,
+			gettext_noop("Sets whether recovery should pause when the recovery target is reached."),
+			NULL
+		},
+		&pause_at_recovery_target,
+		true,
+		NULL, NULL, NULL
+	},
+
+	{
+		{"standby_mode", PGC_POSTMASTER, REPLICATION_STANDBY,
+			gettext_noop("Sets whether to start the server as a standby."),
+			NULL
+		},
+		&StandbyModeRequested,
+		false,
+		NULL, NULL, NULL
+	},
+
+	{
 		{"hot_standby", PGC_POSTMASTER, REPLICATION_STANDBY,
 			gettext_noop("Allows connections and queries during recovery."),
 			NULL
@@ -2571,6 +2616,97 @@ static struct config_string ConfigureNamesString[] =
 	},
 
 	{
+		{"restore_command", PGC_SIGHUP, WAL_ARCHIVE_RECOVERY,
+			gettext_noop("Sets the shell command that will retrieve an archived WAL file."),
+			NULL
+		},
+		&restore_command,
+		"",
+		NULL, NULL, NULL
+	},
+
+	{
+		{"archive_cleanup_command", PGC_SIGHUP, WAL_ARCHIVE_RECOVERY,
+			gettext_noop("Sets the shell command that will be executed at every restartpoint."),
+			NULL
+		},
+		&archive_cleanup_command,
+		"",
+		NULL, NULL, NULL
+	},
+
+	{
+		{"recovery_end_command", PGC_SIGHUP, WAL_ARCHIVE_RECOVERY,
+			gettext_noop("Sets the shell command that will be executed once only at the end of recovery."),
+			NULL
+		},
+		&recovery_end_command,
+		"",
+		NULL, NULL, NULL
+	},
+
+	{
+		{"recovery_target_xid", PGC_SIGHUP, WAL_RECOVERY_TARGET,
+			gettext_noop("Sets the transaction ID up to which recovery will proceed."),
+			NULL
+		},
+		&recovery_target_xid_string,
+		"",
+		check_recovery_target_xid, assign_recovery_target_xid, NULL
+	},
+
+	{
+		{"recovery_target_name", PGC_SIGHUP, WAL_RECOVERY_TARGET,
+			gettext_noop("Sets the named restore point."),
+			NULL
+		},
+		&recovery_target_name,
+		"",
+		check_recovery_target_name, assign_recovery_target_name, NULL
+	},
+
+	{
+		{"recovery_target_time", PGC_SIGHUP, WAL_RECOVERY_TARGET,
+			gettext_noop("Sets the time stamp up to which recovery will proceed."),
+			NULL
+		},
+		&recovery_target_time_string,
+		"",
+		check_recovery_target_time, assign_recovery_target_time, NULL
+	},
+
+	{
+		{"recovery_target_timeline", PGC_POSTMASTER, WAL_RECOVERY_TARGET,
+			gettext_noop("Sets recoverying into a particular timeline."),
+			NULL
+		},
+		&recovery_target_timeline_string,
+		"",
+		check_recovery_target_timeline, assign_recovery_target_timeline, NULL
+	},
+
+	{
+		{"primary_conninfo", PGC_SIGHUP, REPLICATION_STANDBY,
+			gettext_noop("Sets the connection string to be used to connect with the primary."),
+			NULL,
+			GUC_SUPERUSER_ONLY
+		},
+		&primary_conninfo,
+		"",
+		NULL, NULL, NULL
+	},
+
+	{
+		{"trigger_file", PGC_SIGHUP, REPLICATION_STANDBY,
+			gettext_noop("Sets the trigger file whose presence ends recovery in the standby."),
+			NULL
+		},
+		&trigger_file,
+		"",
+		NULL, NULL, NULL
+	},
+
+	{
 		{"client_encoding", PGC_USERSET, CLIENT_CONN_LOCALE,
 			gettext_noop("Sets the client's character set encoding."),
 			NULL,
@@ -8797,4 +8933,158 @@ show_log_file_mode(void)
 	return buf;
 }
 
+static bool
+check_recovery_target_xid(char **newval, void **extra, GucSource source)
+{
+	TransactionId   xid;
+	TransactionId   *myextra;
+
+	if (strcmp(*newval, "") == 0)
+		xid = InvalidTransactionId;
+	else
+	{
+		errno = 0;
+		xid = (TransactionId) strtoul(*newval, NULL, 0);
+		if (errno == EINVAL || errno == ERANGE)
+		{
+			GUC_check_errdetail("recovery_target_xid is not a valid number: \"%s\"",
+								*newval);
+			return false;
+		}
+	}
+
+	myextra = (TransactionId *) guc_malloc(ERROR, sizeof(TransactionId));
+	*myextra = xid;
+	*extra = (void *) myextra;
+
+	return true;
+}
+
+static void
+assign_recovery_target_xid(const char *newval, void *extra)
+{
+	recovery_target_xid = *((TransactionId *) extra);
+
+	if (recovery_target_xid != InvalidTransactionId)
+		recovery_target = RECOVERY_TARGET_XID;
+	else if (recovery_target_name[0])
+		recovery_target = RECOVERY_TARGET_NAME;
+	else if (recovery_target_time != 0)
+		recovery_target = RECOVERY_TARGET_TIME;
+	else
+		recovery_target = RECOVERY_TARGET_UNSET;
+}
+
+static bool
+check_recovery_target_name(char **newval, void **extra, GucSource source)
+{
+	if (strlen(*newval) >= MAXFNAMELEN)
+	{
+		GUC_check_errdetail("\"recovery_target_name\" is too long (maximum %d characters)",
+							MAXFNAMELEN - 1);
+		return false;
+	}
+	return true;
+}
+
+static void
+assign_recovery_target_name(const char *newval, void *extra)
+{
+	if (recovery_target_xid != InvalidTransactionId)
+		recovery_target = RECOVERY_TARGET_XID;
+	else if (newval[0])
+		recovery_target = RECOVERY_TARGET_NAME;
+	else if (recovery_target_time != 0)
+		recovery_target = RECOVERY_TARGET_TIME;
+	else
+		recovery_target = RECOVERY_TARGET_UNSET;
+}
+
+static bool
+check_recovery_target_time(char **newval, void **extra, GucSource source)
+{
+	TimestampTz     time;
+	TimestampTz     *myextra;
+	MemoryContext oldcontext = CurrentMemoryContext;
+
+	PG_TRY();
+	{
+		time = (strcmp(*newval, "") == 0) ?
+			0 :
+			DatumGetTimestampTz(DirectFunctionCall3(timestamptz_in,
+													CStringGetDatum(*newval),
+													ObjectIdGetDatum(InvalidOid),
+													Int32GetDatum(-1)));
+	}
+	PG_CATCH();
+	{
+		ErrorData  *edata;
+
+		/* Save error info */
+		MemoryContextSwitchTo(oldcontext);
+		edata = CopyErrorData();
+		FlushErrorState();
+
+		/* Pass the error message */
+		GUC_check_errdetail("%s", edata->message);
+		FreeErrorData(edata);
+		return false;
+	}
+	PG_END_TRY();
+
+	myextra = (TimestampTz *) guc_malloc(ERROR, sizeof(TimestampTz));
+	*myextra = time;
+	*extra = (void *) myextra;
+
+	return true;
+}
+
+static void
+assign_recovery_target_time(const char *newval, void *extra)
+{
+	recovery_target_time = *((TimestampTz *) extra);
+
+	if (recovery_target_xid != InvalidTransactionId)
+		recovery_target = RECOVERY_TARGET_XID;
+	else if (recovery_target_name[0])
+		recovery_target = RECOVERY_TARGET_NAME;
+	else if (recovery_target_time != 0)
+		recovery_target = RECOVERY_TARGET_TIME;
+	else
+		recovery_target = RECOVERY_TARGET_UNSET;
+}
+
+static bool
+check_recovery_target_timeline(char **newval, void **extra, GucSource source)
+{
+	TimeLineID	tli = 0;
+	TimeLineID	*myextra;
+
+	if (strcmp(*newval, "") == 0 || strcmp(*newval, "latest") == 0)
+		tli = 0;
+	else
+	{
+		errno = 0;
+		tli = (TimeLineID) strtoul(*newval, NULL, 0);
+		if (errno == EINVAL || errno == ERANGE)
+		{
+			GUC_check_errdetail("recovery_target_timeline is not a valid number: \"%s\"",
+								*newval);
+			return false;
+		}
+	}
+
+	myextra = (TimeLineID *) guc_malloc(ERROR, sizeof(TimeLineID));
+	*myextra = tli;
+	*extra = (void *) myextra;
+
+	return true;
+}
+
+static void
+assign_recovery_target_timeline(const char *newval, void *extra)
+{
+	recovery_target_timeline = *((TimeLineID *) extra);
+}
+
 #include "guc-file.c"
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
index 307b456..d8e2616 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -198,6 +198,23 @@
 #archive_timeout = 0		# force a logfile segment switch after this
 				# number of seconds; 0 disables
 
+# - Archive Recovery -
+#restore_command = ''		# command to use to restore an archived logfile segment
+				# placeholders: %p = path of file to restore
+				#               %f = file name only
+				# e.g. 'cp /mnt/server/archivedir/%f %p'
+#archive_cleanup_command = ''	# command to execute at every restartpoint
+#recovery_end_command = ''	# command to execute at completion of recovery
+
+# - Recovery Target -
+#recovery_target_xid = ''
+#recovery_target_name = ''		# e.g. 'daily backup 2011-01-26'
+#recovery_target_time = ''		# e.g. '2004-07-14 22:39:00 EST'
+#recovery_target_timeline = ''		# timeline ID or 'latest'
+					# (change requires restart)
+#recovery_target_inclusive = on
+#pause_at_recovery_target = on		# Pause recovery once target is reached
+
 
 #------------------------------------------------------------------------------
 # REPLICATION
@@ -240,6 +257,11 @@
 #wal_receiver_timeout = 60s		# time that receiver waits for
 					# communication from master
 					# in milliseconds; 0 disables
+#standby_mode = off			# "on" starts the server as a standby
+					# (change requires restart)
+#primary_conninfo = ''			# connection string to connect to the master
+					# e.g. 'host=localhost port=5432'
+#trigger_file = ''			# trigger file to promote the standby
 
 
 #------------------------------------------------------------------------------
diff --git a/src/bin/pg_basebackup/pg_basebackup.c b/src/bin/pg_basebackup/pg_basebackup.c
index eacb592..9bd8a99 100644
--- a/src/bin/pg_basebackup/pg_basebackup.c
+++ b/src/bin/pg_basebackup/pg_basebackup.c
@@ -43,7 +43,7 @@ int			compresslevel = 0;
 bool		includewal = false;
 bool		streamwal = false;
 bool		fastcheckpoint = false;
-bool		writerecoveryconf = false;
+bool		writestandby = false;
 int			standby_message_timeout = 10 * 1000;		/* 10 sec = default */
 
 /* Progress counters */
@@ -68,9 +68,6 @@ static int	has_xlogendptr = 0;
 static volatile LONG has_xlogendptr = 0;
 #endif
 
-/* Contents of recovery.conf to be generated */
-static PQExpBuffer recoveryconfcontents = NULL;
-
 /* Function headers */
 static void usage(void);
 static void verify_dir_is_empty_or_create(char *dirname);
@@ -78,8 +75,7 @@ static void progress_report(int tablespacenum, const char *filename);
 
 static void ReceiveTarFile(PGconn *conn, PGresult *res, int rownum);
 static void ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum);
-static void GenerateRecoveryConf(PGconn *conn);
-static void WriteRecoveryConf(void);
+static void WriteStandbyEnabled(void);
 static void BaseBackup(void);
 
 static bool reached_end_position(XLogRecPtr segendpos, uint32 timeline,
@@ -110,8 +106,8 @@ usage(void)
 	printf(_("\nOptions controlling the output:\n"));
 	printf(_("  -D, --pgdata=DIRECTORY receive base backup into directory\n"));
 	printf(_("  -F, --format=p|t       output format (plain (default), tar)\n"));
-	printf(_("  -R, --write-recovery-conf\n"
-			 "                         write recovery.conf after backup\n"));
+	printf(_("  -R, --write-standby-enable\n"
+			 "                         write standby.enabled after backup\n"));
 	printf(_("  -x, --xlog             include required WAL files in backup (fetch mode)\n"));
 	printf(_("  -X, --xlog-method=fetch|stream\n"
 			 "                         include required WAL files with specified method\n"));
@@ -667,7 +663,7 @@ ReceiveTarFile(PGconn *conn, PGresult *res, int rownum)
 		{
 			/*
 			 * End of chunk. If requested, and this is the base tablespace,
-			 * write recovery.conf into the tarfile. When done, close the file
+			 * write standby.enabled into the tarfile. When done, close the file
 			 * (but not stdout).
 			 *
 			 * Also, write two completely empty blocks at the end of the tar
@@ -677,22 +673,16 @@ ReceiveTarFile(PGconn *conn, PGresult *res, int rownum)
 
 			MemSet(zerobuf, 0, sizeof(zerobuf));
 
-			if (basetablespace && writerecoveryconf)
+			if (basetablespace && writestandby)
 			{
 				char		header[512];
-				int			padding;
 
-				tarCreateHeader(header, "recovery.conf", NULL,
-								recoveryconfcontents->len,
+				tarCreateHeader(header, "standby.enabled", NULL,
+								0,
 								0600, 04000, 02000,
 								time(NULL));
 
-				padding = ((recoveryconfcontents->len + 511) & ~511) - recoveryconfcontents->len;
-
 				WRITE_TAR_DATA(header, sizeof(header));
-				WRITE_TAR_DATA(recoveryconfcontents->data, recoveryconfcontents->len);
-				if (padding)
-					WRITE_TAR_DATA(zerobuf, padding);
 			}
 
 			/* 2 * 512 bytes empty data at end of file */
@@ -733,11 +723,11 @@ ReceiveTarFile(PGconn *conn, PGresult *res, int rownum)
 			disconnect_and_exit(1);
 		}
 
-		if (!writerecoveryconf || !basetablespace)
+		if (!writestandby || !basetablespace)
 		{
 			/*
-			 * When not writing recovery.conf, or when not working on the base
-			 * tablespace, we never have to look for an existing recovery.conf
+			 * When not writing standby.enabled, or when not working on the base
+			 * tablespace, we never have to look for an existing standby.enabled
 			 * file in the stream.
 			 */
 			WRITE_TAR_DATA(copybuf, r);
@@ -745,7 +735,7 @@ ReceiveTarFile(PGconn *conn, PGresult *res, int rownum)
 		else
 		{
 			/*
-			 * Look for a recovery.conf in the existing tar stream. If it's
+			 * Look for a standby.enabled in the existing tar stream. If it's
 			 * there, we must skip it so we can later overwrite it with our
 			 * own version of the file.
 			 *
@@ -791,12 +781,12 @@ ReceiveTarFile(PGconn *conn, PGresult *res, int rownum)
 						 * We have the complete header structure in tarhdr,
 						 * look at the file metadata: - the subsequent file
 						 * contents have to be skipped if the filename is
-						 * recovery.conf - find out the size of the file
+						 * standby.enabled - find out the size of the file
 						 * padded to the next multiple of 512
 						 */
 						int			padding;
 
-						skip_file = (strcmp(&tarhdr[0], "recovery.conf") == 0);
+						skip_file = (strcmp(&tarhdr[0], "standby.enabled") == 0);
 
 						sscanf(&tarhdr[124], "%11o", (unsigned int *) &filesz);
 
@@ -1102,102 +1092,21 @@ ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum)
 	if (copybuf != NULL)
 		PQfreemem(copybuf);
 
-	if (basetablespace && writerecoveryconf)
-		WriteRecoveryConf();
+	if (basetablespace && writestandby)
+		WriteStandbyEnabled();
 }
 
-/*
- * Escape single quotes used in connection parameters
- */
-static char *
-escape_quotes(const char *src)
-{
-	char	   *result = escape_single_quotes_ascii(src);
-
-	if (!result)
-	{
-		fprintf(stderr, _("%s: out of memory\n"), progname);
-		exit(1);
-	}
-	return result;
-}
 
 /*
- * Create a recovery.conf file in memory using a PQExpBuffer
+ * Write a standby.enabled file into the directory specified in basedir.
  */
 static void
-GenerateRecoveryConf(PGconn *conn)
-{
-	PQconninfoOption *connOptions;
-	PQconninfoOption *option;
-
-	recoveryconfcontents = createPQExpBuffer();
-	if (!recoveryconfcontents)
-	{
-		fprintf(stderr, _("%s: out of memory\n"), progname);
-		disconnect_and_exit(1);
-	}
-
-	connOptions = PQconninfo(conn);
-	if (connOptions == NULL)
-	{
-		fprintf(stderr, _("%s: out of memory\n"), progname);
-		disconnect_and_exit(1);
-	}
-
-	appendPQExpBufferStr(recoveryconfcontents, "standby_mode = 'on'\n");
-	appendPQExpBufferStr(recoveryconfcontents, "primary_conninfo = '");
-
-	for (option = connOptions; option && option->keyword; option++)
-	{
-		char	   *escaped;
-
-		/*
-		 * Do not emit this setting if: - the setting is "replication",
-		 * "dbname" or "fallback_application_name", since these would be
-		 * overridden by the libpqwalreceiver module anyway. - not set or
-		 * empty.
-		 */
-		if (strcmp(option->keyword, "replication") == 0 ||
-			strcmp(option->keyword, "dbname") == 0 ||
-			strcmp(option->keyword, "fallback_application_name") == 0 ||
-			(option->val == NULL) ||
-			(option->val != NULL && option->val[0] == '\0'))
-			continue;
-
-		/*
-		 * Write "keyword='value'" pieces, the value string is escaped if
-		 * necessary and doubled single quotes around the value string.
-		 */
-		escaped = escape_quotes(option->val);
-
-		appendPQExpBuffer(recoveryconfcontents, "%s=''%s'' ", option->keyword, escaped);
-
-		free(escaped);
-	}
-
-	appendPQExpBufferStr(recoveryconfcontents, "'\n");
-	if (PQExpBufferBroken(recoveryconfcontents))
-	{
-		fprintf(stderr, _("%s: out of memory\n"), progname);
-		disconnect_and_exit(1);
-	}
-
-	PQconninfoFree(connOptions);
-}
-
-
-/*
- * Write a recovery.conf file into the directory specified in basedir,
- * with the contents already collected in memory.
- */
-static void
-WriteRecoveryConf(void)
+WriteStandbyEnabled(void)
 {
 	char		filename[MAXPGPATH];
 	FILE	   *cf;
 
-	sprintf(filename, "%s/recovery.conf", basedir);
+	sprintf(filename, "%s/standby.enabled", basedir);
 
 	cf = fopen(filename, "w");
 	if (cf == NULL)
@@ -1206,14 +1115,6 @@ WriteRecoveryConf(void)
 		disconnect_and_exit(1);
 	}
 
-	if (fwrite(recoveryconfcontents->data, recoveryconfcontents->len, 1, cf) != 1)
-	{
-		fprintf(stderr,
-				_("%s: could not write to file \"%s\": %s\n"),
-				progname, filename, strerror(errno));
-		disconnect_and_exit(1);
-	}
-
 	fclose(cf);
 }
 
@@ -1239,12 +1140,6 @@ BaseBackup(void)
 		exit(1);
 
 	/*
-	 * Build contents of recovery.conf if requested
-	 */
-	if (writerecoveryconf)
-		GenerateRecoveryConf(conn);
-
-	/*
 	 * Run IDENTIFY_SYSTEM so we can get the timeline
 	 */
 	res = PQexec(conn, "IDENTIFY_SYSTEM");
@@ -1512,9 +1407,6 @@ BaseBackup(void)
 #endif
 	}
 
-	/* Free the recovery.conf contents */
-	destroyPQExpBuffer(recoveryconfcontents);
-
 	/*
 	 * End of copy data. Final result is already checked inside the loop.
 	 */
@@ -1535,7 +1427,7 @@ main(int argc, char **argv)
 		{"pgdata", required_argument, NULL, 'D'},
 		{"format", required_argument, NULL, 'F'},
 		{"checkpoint", required_argument, NULL, 'c'},
-		{"write-recovery-conf", no_argument, NULL, 'R'},
+		{"write-standby-enable", no_argument, NULL, 'R'},
 		{"xlog", no_argument, NULL, 'x'},
 		{"xlog-method", required_argument, NULL, 'X'},
 		{"gzip", no_argument, NULL, 'z'},
@@ -1596,7 +1488,7 @@ main(int argc, char **argv)
 				}
 				break;
 			case 'R':
-				writerecoveryconf = true;
+				writestandby = true;
 				break;
 			case 'x':
 				if (includewal)
diff --git a/src/bin/pg_ctl/pg_ctl.c b/src/bin/pg_ctl/pg_ctl.c
index 537d173..c49c847 100644
--- a/src/bin/pg_ctl/pg_ctl.c
+++ b/src/bin/pg_ctl/pg_ctl.c
@@ -889,7 +889,7 @@ do_stop(void)
 		/*
 		 * If backup_label exists, an online backup is running. Warn the user
 		 * that smart shutdown will wait for it to finish. However, if
-		 * recovery.conf is also present, we're recovering from an online
+		 * standby.enabled is also present, we're recovering from an online
 		 * backup instead of performing one.
 		 */
 		if (shutdown_mode == SMART_MODE &&
@@ -977,7 +977,7 @@ do_restart(void)
 		/*
 		 * If backup_label exists, an online backup is running. Warn the user
 		 * that smart shutdown will wait for it to finish. However, if
-		 * recovery.conf is also present, we're recovering from an online
+		 * standby.enabled is also present, we're recovering from an online
 		 * backup instead of performing one.
 		 */
 		if (shutdown_mode == SMART_MODE &&
@@ -1088,7 +1088,7 @@ do_promote(void)
 		exit(1);
 	}
 
-	/* If recovery.conf doesn't exist, the server is not in standby mode */
+	/* If standby.enabled doesn't exist, the server is not in standby mode */
 	if (stat(recovery_file, &statbuf) != 0)
 	{
 		write_stderr(_("%s: cannot promote server; "
@@ -2244,7 +2244,7 @@ main(int argc, char **argv)
 		snprintf(postopts_file, MAXPGPATH, "%s/postmaster.opts", pg_data);
 		snprintf(pid_file, MAXPGPATH, "%s/postmaster.pid", pg_data);
 		snprintf(backup_file, MAXPGPATH, "%s/backup_label", pg_data);
-		snprintf(recovery_file, MAXPGPATH, "%s/recovery.conf", pg_data);
+		snprintf(recovery_file, MAXPGPATH, "%s/standby.enabled", pg_data);
 	}
 
 	switch (ctl_command)
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index f8f06c1..7e9ad4e 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -190,6 +190,20 @@ extern char *XLogArchiveCommand;
 extern bool EnableHotStandby;
 extern bool fullPageWrites;
 extern bool log_checkpoints;
+extern char *restore_command;
+extern char *archive_cleanup_command;
+extern char *recovery_end_command;
+extern bool	StandbyModeRequested;
+extern char *primary_conninfo;
+extern char *trigger_file;
+extern RecoveryTargetType recovery_target;
+extern TransactionId recovery_target_xid;
+extern TimestampTz recovery_target_time;
+extern char *recovery_target_name;
+extern bool recovery_target_inclusive;
+extern bool pause_at_recovery_target;
+extern char *recovery_target_timeline_string;
+extern TimeLineID recovery_target_timeline;
 
 /* WAL levels */
 typedef enum WalLevel
diff --git a/src/include/replication/walreceiver.h b/src/include/replication/walreceiver.h
index 72878f8..d51d86f 100644
--- a/src/include/replication/walreceiver.h
+++ b/src/include/replication/walreceiver.h
@@ -149,7 +149,7 @@ extern void WalRcvShmemInit(void);
 extern void ShutdownWalRcv(void);
 extern bool WalRcvStreaming(void);
 extern bool WalRcvRunning(void);
-extern void RequestXLogStreaming(TimeLineID tli, XLogRecPtr recptr, const char *conninfo);
+extern void RequestXLogStreaming(TimeLineID tli, XLogRecPtr recptr);
 extern XLogRecPtr GetWalRcvWriteRecPtr(XLogRecPtr *latestChunkStart, TimeLineID *receiveTLI);
 extern int	GetReplicationApplyDelay(void);
 extern int	GetReplicationTransferLatency(void);
diff --git a/src/include/utils/guc_tables.h b/src/include/utils/guc_tables.h
index 7360ce3..a2d3281 100644
--- a/src/include/utils/guc_tables.h
+++ b/src/include/utils/guc_tables.h
@@ -68,6 +68,8 @@ enum config_group
 	WAL_SETTINGS,
 	WAL_CHECKPOINTS,
 	WAL_ARCHIVING,
+	WAL_ARCHIVE_RECOVERY,
+	WAL_RECOVERY_TARGET,
 	REPLICATION,
 	REPLICATION_SENDING,
 	REPLICATION_MASTER,
#28Simon Riggs
simon@2ndQuadrant.com
In reply to: Michael Paquier (#27)
Re: Request for vote to move forward with recovery.conf overhaul

On 25 March 2013 04:08, Michael Paquier <michael.paquier@gmail.com> wrote:

Feedback is warmly welcome.

I'll look at this in the coming week.

--
Simon Riggs http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#29Michael Paquier
michael.paquier@gmail.com
In reply to: Simon Riggs (#28)
Re: Request for vote to move forward with recovery.conf overhaul

On Mon, Mar 25, 2013 at 1:14 PM, Simon Riggs <simon@2ndquadrant.com> wrote:

On 25 March 2013 04:08, Michael Paquier <michael.paquier@gmail.com> wrote:

Feedback is warmly welcome.

I'll look at this in the coming week.

Thanks.
--
Michael