Hi

I attached new version of this patch due merge conflict with pg_promote 
function.

regards, Sergei
diff --git a/contrib/pg_standby/pg_standby.c b/contrib/pg_standby/pg_standby.c
index ee1fbd7..946239c 100644
--- a/contrib/pg_standby/pg_standby.c
+++ b/contrib/pg_standby/pg_standby.c
@@ -611,7 +611,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 3fa5efd..780f40d 100644
--- a/doc/src/sgml/backup.sgml
+++ b/doc/src/sgml/backup.sgml
@@ -1220,7 +1220,7 @@ SELECT pg_stop_backup();
    </listitem>
    <listitem>
     <para>
-     Create a recovery command file <filename>recovery.conf</filename> in the cluster
+     Create a file <filename>recovery.signal</filename> in the cluster
      data directory (see <xref linkend="recovery-config"/>). You might
      also want to temporarily modify <filename>pg_hba.conf</filename> to prevent
      ordinary users from connecting until you are sure the recovery was successful.
@@ -1232,10 +1232,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</filename> to <filename>recovery.done</filename> (to prevent
-     accidentally re-entering recovery mode later) and then
-     commence normal database operations.
+     of the recovery process, the server will remove
+     <filename>recovery.signal</filename> (to prevent accidentally re-entering
+     recovery mode later) and then commence normal database operations.
     </para>
    </listitem>
    <listitem>
@@ -1249,12 +1248,8 @@ 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</filename> (normally
-    located in the installation's <filename>share/</filename> directory) as a
-    prototype.  The one thing that you absolutely must specify in
-    <filename>recovery.conf</filename> is the <varname>restore_command</varname>,
+    The key part of all this is to set up a recovery configuration.
+    The one thing that you absolutely must specify is the <varname>restore_command</varname>,
     which tells <productname>PostgreSQL</productname> how to retrieve archived
     WAL file segments.  Like the <varname>archive_command</varname>, this is
     a shell command string.  It can contain <literal>%f</literal>, which is
@@ -1316,7 +1311,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 <link linkend="recovery-target-settings">stopping point</link> in <filename>recovery.conf</filename>.  You can specify
+    required <link linkend="recovery-target-settings">stopping point</link>.  You can specify
     the stop point, known as the <quote>recovery target</quote>, 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
@@ -1414,8 +1409,8 @@ restore_command = 'cp /mnt/server/archivedir/%f %p'
     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</filename>.  You cannot recover into
-    timelines that branched off earlier than the base backup.
+    target timeline ID in <xref linkend="recovery-target-timeline"/>. 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 7554cba..4c79113 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -3203,11 +3203,11 @@ include_dir 'conf.d'
         <varname>application_name</varname> setting of the standby, as set in the
         standby's connection information.  In case of a physical replication
         standby, this should be set in the <varname>primary_conninfo</varname>
-        setting in <filename>recovery.conf</filename>; the default
-        is <literal>walreceiver</literal>.  For logical replication, this can
-        be set in the connection information of the subscription, and it
-        defaults to the subscription name.  For other replication stream
-        consumers, consult their documentation.
+        setting; the default is <literal>walreceiver</literal>.
+        For logical replication, this can be set in the connection
+        information of the subscription, and it defaults to the
+        subscription name.  For other replication stream consumers,
+        consult their documentation.
        </para>
        <para>
         This parameter specifies a list of standby servers using
diff --git a/doc/src/sgml/high-availability.sgml b/doc/src/sgml/high-availability.sgml
index faf8e71..17b5d72 100644
--- a/doc/src/sgml/high-availability.sgml
+++ b/doc/src/sgml/high-availability.sgml
@@ -686,10 +686,9 @@ 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</filename> in the standby's cluster data
-    directory, and turn on <varname>standby_mode</varname>. Set
-    <varname>restore_command</varname> to a simple command to copy files from
+    server (see <xref linkend="backup-pitr-recovery"/>). Create a file
+    <filename>standby.signal</filename> in the standby's cluster data
+    directory. Set <xref linkend="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</varname> to
     <literal>latest</literal>, to make the standby server follow the timeline change
@@ -699,7 +698,7 @@ protocol to make nodes agree on a serializable transactional order.
    <note>
      <para>
      Do not use pg_standby or similar tools with the built-in standby mode
-     described here. <varname>restore_command</varname> should return immediately
+     described here. <xref linkend="restore-command"/> should return immediately
      if the file does not exist; the server will retry the command again if
      necessary. See <xref linkend="log-shipping-alternative"/>
      for using tools like pg_standby.
@@ -708,11 +707,11 @@ protocol to make nodes agree on a serializable transactional order.
 
    <para>
      If you want to use streaming replication, fill in
-     <varname>primary_conninfo</varname> with a libpq connection string, including
+     <xref linkend="primary-conninfo"/> with a libpq connection string, including
      the host name (or IP address) and any additional details needed to
      connect to the primary server. If the primary needs a password for
      authentication, the password needs to be specified in
-     <varname>primary_conninfo</varname> as well.
+     <xref linkend="primary-conninfo"/> as well.
    </para>
 
    <para>
@@ -735,9 +734,8 @@ protocol to make nodes agree on a serializable transactional order.
    </para>
 
    <para>
-    A simple example of a <filename>recovery.conf</filename> is:
+    A simple example of configuration is:
 <programlisting>
-standby_mode = 'on'
 primary_conninfo = 'host=192.168.1.50 port=5432 user=foo password=foopass options=''-c wal_sender_timeout=5000'''
 restore_command = 'cp /path/to/archive/%f %p'
 archive_cleanup_command = 'pg_archivecleanup /path/to/archive %r'
@@ -793,8 +791,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</varname> setting in the
-    <filename>recovery.conf</filename> file to point to the primary server. Set
+    standby is setting <varname>primary_conninfo</varname> setting
+    to point to the primary server. Set
     <xref linkend="guc-listen-addresses"/> and authentication options
     (see <filename>pg_hba.conf</filename>) on the primary so that the standby server
     can connect to the <literal>replication</literal> pseudo-database on the primary
@@ -854,14 +852,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</filename> file.
+     and password are specified in the <xref linkend="primary-conninfo"/>.
      The password can also be set in the <filename>~/.pgpass</filename> file on the
      standby (specify <literal>replication</literal> in the <replaceable>database</replaceable>
      field).
      For example, if the primary is running on host IP <literal>192.168.1.50</literal>,
      port <literal>5432</literal>, the account name for replication is
      <literal>foo</literal>, and the password is <literal>foopass</literal>, the administrator
-     can add the following line to the <filename>recovery.conf</filename> file on the
+     can add the following line to the <filename>postgresql.conf</filename> file on the
      standby:
 
 <programlisting>
@@ -967,16 +965,14 @@ postgres=# SELECT * FROM pg_create_physical_replication_slot('node_a_slot');
  node_a_slot |
 
 postgres=# SELECT slot_name, slot_type, active FROM pg_replication_slots;
-  slot_name  | slot_type | active 
+  slot_name  | slot_type | active
 -------------+-----------+--------
  node_a_slot | physical  | f
 (1 row)
 </programlisting>
      To configure the standby to use this slot, <varname>primary_slot_name</varname>
-     should be configured in the standby's <filename>recovery.conf</filename>.
-     Here is a simple example:
+     should be configured on the standby. Here is a simple example:
 <programlisting>
-standby_mode = 'on'
 primary_conninfo = 'host=192.168.1.50 port=5432 user=foo password=foopass'
 primary_slot_name = 'node_a_slot'
 </programlisting>
@@ -1474,11 +1470,10 @@ synchronous_standby_names = 'ANY 2 (s1, s2, s3)'
     To trigger failover of a log-shipping standby server, run
     <command>pg_ctl promote</command>, call <function>pg_promote</function>,
     or create a trigger file with the file name and path specified by the
-    <varname>trigger_file</varname> setting in
-    <filename>recovery.conf</filename>. If you're planning to use
+    <varname>promote_trigger_file</varname>. If you're planning to use
     <command>pg_ctl promote</command> or to call
     <function>pg_promote</function> to fail over,
-    <varname>trigger_file</varname> is not required. If you're
+    <varname>promote_trigger_file</varname> 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 availability purposes, you don't
     need to promote it.
@@ -1491,11 +1486,8 @@ synchronous_standby_names = 'ANY 2 (s1, s2, s3)'
    <para>
     An alternative to the built-in standby mode described in the previous
     sections is to use a <varname>restore_command</varname> that polls the archive location.
-    This was the only option available in versions 8.4 and below. In this
-    setup, set <varname>standby_mode</varname> off, because you are implementing
-    the polling required for standby operation yourself. See the
-    <xref linkend="pgstandby"/> module for a reference
-    implementation of this.
+    This was the only option available in versions 8.4 and below. See the
+    <xref linkend="pgstandby"/> module for a reference implementation of this.
    </para>
 
    <para>
@@ -1522,14 +1514,13 @@ synchronous_standby_names = 'ANY 2 (s1, s2, s3)'
     The magic that makes the two loosely coupled servers work together is
     simply a <varname>restore_command</varname> 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</varname> is specified in the
-    <filename>recovery.conf</filename> file on the standby server. 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
-    it to appear. For files ending in 
-    <literal>.history</literal> there is no need to wait, and a non-zero return
-    code must be returned. A waiting <varname>restore_command</varname> can be
+    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 it to appear. For files ending in
+    <literal>.backup</literal> or <literal>.history</literal>
+    there is no need to wait, and a non-zero return code must be returned.
+    A waiting <varname>restore_command</varname> can be
     written as a custom script that loops after polling for the existence of
     the next WAL file. There must also be some way to trigger failover, which
     should interrupt the <varname>restore_command</varname>, break the loop and
@@ -1611,9 +1602,8 @@ if (!triggered)
      <listitem>
       <para>
        Begin recovery on the standby server from the local WAL
-       archive, using a <filename>recovery.conf</filename> that specifies a
-       <varname>restore_command</varname> that waits as described
-       previously (see <xref linkend="backup-pitr-recovery"/>).
+       archive, using <varname>restore_command</varname> that waits
+       as described previously (see <xref linkend="backup-pitr-recovery"/>).
       </para>
      </listitem>
     </orderedlist>
@@ -2108,7 +2098,7 @@ if (!triggered)
 
    <para>
     If <varname>hot_standby</varname> is <literal>on</literal> in <filename>postgresql.conf</filename>
-    (the default value) and there is a <filename>recovery.conf</filename>
+    (the default value) and there is a <filename>standby.signal</filename>
     file 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
diff --git a/doc/src/sgml/pgstandby.sgml b/doc/src/sgml/pgstandby.sgml
index 2cc58fe..d8aded4 100644
--- a/doc/src/sgml/pgstandby.sgml
+++ b/doc/src/sgml/pgstandby.sgml
@@ -47,7 +47,7 @@
   <para>
    To configure a standby
    server to use <application>pg_standby</application>, put this into its
-   <filename>recovery.conf</filename> configuration file:
+   <filename>postgresql.conf</filename> configuration file:
 <programlisting>
 restore_command = 'pg_standby <replaceable>archiveDir</replaceable> %f %p %r'
 </programlisting>
diff --git a/doc/src/sgml/recovery-config.sgml b/doc/src/sgml/recovery-config.sgml
index a2bdffd..cec277c 100644
--- a/doc/src/sgml/recovery-config.sgml
+++ b/doc/src/sgml/recovery-config.sgml
@@ -11,23 +11,44 @@
 
    <para>
     This chapter describes the settings available in the
-    <filename>recovery.conf</filename><indexterm><primary>recovery.conf</primary></indexterm>
-    file. They apply only for the duration of the
+    <filename>postgresql.conf</filename>
+    file that 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</filename> are specified in the format
-     <literal>name = 'value'</literal>. 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>''</literal>).
+    The database server can also be started <literal>in recovery</literal>, a term that covers
+    using the server as a standby or for executing a targeted recovery. Typically
+    standby mode would be used to provide high availability and/or read
+    scalability, whereas a targeted recovery is used to recover from data loss.
    </para>
 
    <para>
-    A sample file, <filename>share/recovery.conf.sample</filename>,
-    is provided in the installation's <filename>share/</filename> directory.
+     To start the server in standby mode create file
+    called <filename>standby.signal</filename><indexterm><primary>standby.signal</primary></indexterm>
+    in the data directory. The server will enter recovery and
+    will not stop recovery when the end of archived WAL is reached, but
+    will keep trying to continue recovery by connecting to the sending server as
+    specified by the <varname>primary_conninfo</varname> setting and/or by
+    fetching new WAL segments using <varname>restore_command</varname>
+    In this mode you may use parameters
+    in both <xref linkend="archive-recovery-settings" /> and
+    <xref linkend="standby-settings"/> sections. Parameters from
+    <xref linkend="recovery-target-settings"/> will not be used.
+   </para>
+
+   <para>
+    To start the server in targeted recovery create a file called
+    <filename>recovery.signal</filename><indexterm><primary>recovery.signal</primary></indexterm>
+    in the data directory.
+    If both <filename>standby.signal</filename> and <filename>recovery.signal</filename> files are
+    created, standby mode takes precedence. Targeted recovery mode will end when
+    end of archived WAL is reached, or when <varname>recovery_target</varname> is reached.
+    In this mode you may use parameters from both
+    <xref linkend="archive-recovery-settings"/> and
+    <xref linkend="recovery-target-settings"/> sections. Parameters from
+    <xref linkend="standby-settings"/> will not be used.
    </para>
 
   <sect1 id="archive-recovery-settings">
@@ -336,11 +357,11 @@ restore_command = 'copy "C:\\server\\archivedir\\%f" "%p"'  # Windows
         since the last checkpoint next time it is started).
        </para>
        <para>
-        Note that because <filename>recovery.conf</filename> will not be renamed when
-        <varname>recovery_target_action</varname> is set to <literal>shutdown</literal>,
+        Note that because <filename>recovery.signal</filename> will not be
+        removed when <varname>recovery_target_action</varname> is set to <literal>shutdown</literal>,
         any subsequent start will end with immediate shutdown unless the
-        configuration is changed or the <filename>recovery.conf</filename> file is
-        removed manually.
+        configuration is changed or the <filename>recovery.signal</filename>
+        file is removed manually.
        </para>
        <para>
         This setting has no effect if no recovery target is set.
@@ -358,24 +379,9 @@ restore_command = 'copy "C:\\server\\archivedir\\%f" "%p"'  # Windows
     <title>Standby Server Settings</title>
      <variablelist>
 
-       <varlistentry id="standby-mode" xreflabel="standby_mode">
-        <term><varname>standby_mode</varname> (<type>boolean</type>)
-        <indexterm>
-          <primary><varname>standby_mode</varname> recovery parameter</primary>
-        </indexterm>
-        </term>
-        <listitem>
-         <para>
-          Specifies whether to start the <productname>PostgreSQL</productname> server as
-          a standby. If this parameter is <literal>on</literal>, 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</varname>
-          and/or by connecting to the primary server as specified by the
-          <varname>primary_conninfo</varname> setting.
-         </para>
-        </listitem>
-       </varlistentry>
+       <para>
+        New values for those parameters are considered only at restart of the server
+       </para>
        <varlistentry id="primary-conninfo" xreflabel="primary_conninfo">
         <term><varname>primary_conninfo</varname> (<type>string</type>)
         <indexterm>
@@ -385,7 +391,7 @@ restore_command = 'copy "C:\\server\\archivedir\\%f" "%p"'  # Windows
         <listitem>
          <para>
           Specifies a connection string to be used for the standby server
-          to connect with the primary. This string is in the format
+          to connect with a sending server. 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
@@ -394,12 +400,12 @@ restore_command = 'copy "C:\\server\\archivedir\\%f" "%p"'  # Windows
          </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
+          of the sending 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
+          on the sending server (see
           <xref linkend="streaming-replication-authentication"/>).
-          A password needs to be provided too, if the primary demands password
+          A password needs to be provided too, if the sender demands password
           authentication.  It can be provided in the
           <varname>primary_conninfo</varname> string, or in a separate
           <filename>~/.pgpass</filename> file on the standby server (use
@@ -421,7 +427,7 @@ restore_command = 'copy "C:\\server\\archivedir\\%f" "%p"'  # Windows
         <listitem>
          <para>
           Optionally specifies an existing replication slot to be used when
-          connecting to the primary via streaming replication to control
+          connecting to the sending server via streaming replication to control
           resource removal on the upstream node
           (see <xref linkend="streaming-replication-slots"/>).
           This setting has no effect if <varname>primary_conninfo</varname> is not
@@ -429,10 +435,11 @@ restore_command = 'copy "C:\\server\\archivedir\\%f" "%p"'  # Windows
          </para>
         </listitem>
        </varlistentry>
-       <varlistentry id="trigger-file" xreflabel="trigger_file">
-        <term><varname>trigger_file</varname> (<type>string</type>)
+
+       <varlistentry id="promote-trigger-file" xreflabel="promote_trigger_file">
+        <term><varname>promote_trigger_file</varname> (<type>string</type>)
         <indexterm>
-          <primary><varname>trigger_file</varname> recovery parameter</primary>
+          <primary><varname>promote_trigger_file</varname> recovery parameter</primary>
         </indexterm>
         </term>
         <listitem>
@@ -441,7 +448,6 @@ restore_command = 'copy "C:\\server\\archivedir\\%f" "%p"'  # Windows
           standby.  Even if this value is not set, you can still promote
           the standby using <command>pg_ctl promote</command> or calling
           <function>pg_promote</function>.
-          This setting has no effect if <varname>standby_mode</varname> is <literal>off</literal>.
          </para>
         </listitem>
        </varlistentry>
@@ -455,7 +461,7 @@ restore_command = 'copy "C:\\server\\archivedir\\%f" "%p"'  # Windows
       <listitem>
        <para>
         By default, a standby server restores WAL records from the
-        primary as soon as possible. It may be useful to have a time-delayed
+        sending server as soon as possible. It may be useful to have a time-delayed
         copy of the data, offering opportunities to correct data loss errors.
         This parameter allows you to delay recovery by a fixed period of time,
         measured in milliseconds if no unit is specified.  For example, if
diff --git a/doc/src/sgml/ref/pg_basebackup.sgml b/doc/src/sgml/ref/pg_basebackup.sgml
index c9f6ce4..91932b1 100644
--- a/doc/src/sgml/ref/pg_basebackup.sgml
+++ b/doc/src/sgml/ref/pg_basebackup.sgml
@@ -214,10 +214,11 @@ PostgreSQL documentation
       <listitem>
 
        <para>
-        Write a minimal <filename>recovery.conf</filename> in the output
+        Create <filename>standby.signal</filename> and append connection settings
+        to <filename>postgresql.auto.conf</filename> in the output
         directory (or into the base archive file when using tar format) to
         ease setting up a standby server.
-        The <filename>recovery.conf</filename> file will record the connection
+        The <filename>postgresql.auto.conf</filename> file will record the connection
         settings and, if specified, the replication slot
         that <application>pg_basebackup</application> is using, so that the
         streaming replication will use the same settings later on.
@@ -470,7 +471,7 @@ PostgreSQL documentation
         replication slot.  If the base backup is intended to be used as a
         streaming replication standby using replication slots, it should then
         use the same replication slot name
-        in <filename>recovery.conf</filename>.  That way, it is ensured that
+        in <xref linkend="primary-slot-name"/>.  That way, it is ensured that
         the server does not remove any necessary WAL data in the time between
         the end of the base backup and the start of streaming replication.
        </para>
diff --git a/doc/src/sgml/ref/pg_rewind.sgml b/doc/src/sgml/ref/pg_rewind.sgml
index e2662bb..a1cc24e 100644
--- a/doc/src/sgml/ref/pg_rewind.sgml
+++ b/doc/src/sgml/ref/pg_rewind.sgml
@@ -69,7 +69,8 @@ PostgreSQL documentation
    target cluster ran for a long time after the divergence, the old WAL
    files might no longer be present. In that case, they can be manually
    copied from the WAL archive to the <filename>pg_wal</filename> directory, or
-   fetched on startup by configuring <filename>recovery.conf</filename>.  The use of
+   fetched on startup by configuring <xref linkend="primary-conninfo"/> or
+   <xref linkend="restore-command"/>.  The use of
    <application>pg_rewind</application> is not limited to failover, e.g.  a standby
    server can be promoted, run some write transactions, and then rewinded
    to become a standby again.
@@ -83,8 +84,9 @@ PostgreSQL documentation
    <application>pg_rewind</application> was run, and therefore could not be copied by the
    <application>pg_rewind</application> session, it must be made available when the
    target server is started. This can be done by creating a
-   <filename>recovery.conf</filename> file in the target data directory with a
-   suitable <varname>restore_command</varname>.
+   <filename>recovery.signal</filename> file in the target data directory
+   and configuring suitable <xref linkend="restore-command"/>
+   in <filename>postgresql.conf</filename>.
   </para>
 
   <para>
diff --git a/doc/src/sgml/ref/pgarchivecleanup.sgml b/doc/src/sgml/ref/pgarchivecleanup.sgml
index 4117a43..52674df 100644
--- a/doc/src/sgml/ref/pgarchivecleanup.sgml
+++ b/doc/src/sgml/ref/pgarchivecleanup.sgml
@@ -39,7 +39,7 @@
   <para>
    To configure a standby
    server to use <application>pg_archivecleanup</application>, put this into its
-   <filename>recovery.conf</filename> configuration file:
+   <filename>postgresql.conf</filename> configuration file:
 <programlisting>
 archive_cleanup_command = 'pg_archivecleanup <replaceable>archivelocation</replaceable> %r'
 </programlisting>
diff --git a/doc/src/sgml/ref/pgupgrade.sgml b/doc/src/sgml/ref/pgupgrade.sgml
index d51146d..51c044f 100644
--- a/doc/src/sgml/ref/pgupgrade.sgml
+++ b/doc/src/sgml/ref/pgupgrade.sgml
@@ -479,7 +479,7 @@ pg_upgrade.exe
       <para>
        Save any configuration files from the old standbys' configuration
        directories you need to keep, e.g.  <filename>postgresql.conf</filename>,
-       <literal>recovery.conf</literal>, because these will be overwritten or
+       <literal>pg_hba.conf</literal>, because these will be overwritten or
        removed in the next step.
       </para>
      </step>
diff --git a/doc/src/sgml/release.sgml b/doc/src/sgml/release.sgml
index c4e763a..4055adf 100644
--- a/doc/src/sgml/release.sgml
+++ b/doc/src/sgml/release.sgml
@@ -5,8 +5,7 @@ Typical markup:
 
 &<>                             use & escapes
 PostgreSQL                      <productname>
-postgresql.conf, pg_hba.conf,
-        recovery.conf           <filename>
+postgresql.conf, pg_hba.conf    <filename>
 [A-Z][A-Z_ ]+[A-Z_]             <command>, <literal>, <envar>, <acronym>
 [A-Za-z_][A-Za-z0-9_]+()        <function>
 \-\-?[A-Za-z_]+[-A-Za-z_]*      <option> (use backslashes to avoid SGML markup)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 62fc418..33d2386 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -78,7 +78,6 @@
 
 extern uint32 bootstrap_data_checksum_version;
 
-
 /* User-settable parameters */
 int			max_wal_size_mb = 1024; /* 1 GB */
 int			min_wal_size_mb = 80;	/* 80 MB */
@@ -161,6 +160,13 @@ const struct config_enum_entry archive_mode_options[] = {
 	{NULL, 0, false}
 };
 
+const struct config_enum_entry recovery_target_action_options[] = {
+	{"pause", RECOVERY_TARGET_ACTION_PAUSE, false},
+	{"promote", RECOVERY_TARGET_ACTION_PROMOTE, false},
+	{"shutdown", RECOVERY_TARGET_ACTION_SHUTDOWN, false},
+	{NULL, 0, false}
+};
+
 /*
  * Statistics for current checkpoint are collected in this global struct.
  * Because only the checkpointer or a stand-alone backend can perform
@@ -230,7 +236,7 @@ static int	LocalXLogInsertAllowed = -1;
 
 /*
  * When ArchiveRecoveryRequested is set, archive recovery was requested,
- * ie. recovery.conf file was present. When InArchiveRecovery is set, we are
+ * ie. signal files were present. When InArchiveRecovery is set, we are
  * currently recovering using offline XLOG archives. These variables are only
  * valid in the startup process.
  *
@@ -242,6 +248,9 @@ static int	LocalXLogInsertAllowed = -1;
 bool		ArchiveRecoveryRequested = false;
 bool		InArchiveRecovery = false;
 
+static bool standby_signal_file_found = false;
+static bool recovery_signal_file_found = false;
+
 /* Was the last xlog file restored from archive, or local? */
 static bool restoredFromArchive = false;
 
@@ -249,29 +258,32 @@ static bool restoredFromArchive = false;
 static char *replay_image_masked = NULL;
 static char *master_image_masked = NULL;
 
-/* options taken from recovery.conf for archive recovery */
+/* options formerly taken from recovery.conf for archive recovery */
 char	   *recoveryRestoreCommand = NULL;
-static char *recoveryEndCommand = NULL;
-static char *archiveCleanupCommand = NULL;
-static RecoveryTargetType recoveryTarget = RECOVERY_TARGET_UNSET;
-static bool recoveryTargetInclusive = true;
-static RecoveryTargetAction recoveryTargetAction = RECOVERY_TARGET_ACTION_PAUSE;
-static TransactionId recoveryTargetXid;
-static TimestampTz recoveryTargetTime;
-static char *recoveryTargetName;
-static XLogRecPtr recoveryTargetLSN;
-static int	recovery_min_apply_delay = 0;
-static TimestampTz recoveryDelayUntilTime;
-
-/* options taken from recovery.conf for XLOG streaming */
-static bool StandbyModeRequested = false;
-static char *PrimaryConnInfo = NULL;
-static char *PrimarySlotName = NULL;
-static char *TriggerFile = NULL;
+char	   *recoveryEndCommand = NULL;
+char	   *archiveCleanupCommand = NULL;
+RecoveryTargetType recoveryTarget = RECOVERY_TARGET_UNSET;
+bool		recoveryTargetInclusive = true;
+int			recoveryTargetAction = RECOVERY_TARGET_ACTION_PAUSE;
+TransactionId recoveryTargetXid;
+TimestampTz recoveryTargetTime;
+char	   *recoveryTargetName;
+XLogRecPtr	recoveryTargetLSN;
+int			recovery_min_apply_delay = 0;
+TimestampTz recoveryDelayUntilTime;
+
+/* options formerly taken from recovery.conf for XLOG streaming */
+bool		StandbyModeRequested = false;
+char	   *PrimaryConnInfo = NULL;
+char	   *PrimarySlotName = NULL;
 
 /* are we currently in standby mode? */
 bool		StandbyMode = false;
 
+char	   *PromoteTriggerFile = NULL;
+char		RecoverySignalFile[MAXPGPATH];
+char		StandbySignalFile[MAXPGPATH];
+
 /* whether request for fast promotion has been made yet */
 static bool fast_promote = false;
 
@@ -293,7 +305,11 @@ static bool recoveryStopAfter;
  * the currently-scanned WAL record was generated).  We also need these
  * timeline values:
  *
- * recoveryTargetTLI: the desired timeline that we want to end in.
+ * recoveryTargetTimeLineGoal: what the user requested, if any
+ *
+ * recoveryTargetTLIRequested: numeric value of requested timeline, if constant
+ *
+ * recoveryTargetTLI: the currently understood target timeline; changes
  *
  * recoveryTargetIsLatest: was the requested target timeline 'latest'?
  *
@@ -309,7 +325,9 @@ static bool recoveryStopAfter;
  * file was created.)  During a sequential scan we do not allow this value
  * to decrease.
  */
-static TimeLineID recoveryTargetTLI;
+RecoveryTargetTimeLineGoal recoveryTargetTimeLineGoal = RECOVERY_TARGET_TIMELINE_CONTROLFILE;
+TimeLineID	recoveryTargetTLIRequested = 0;
+TimeLineID	recoveryTargetTLI = 0;
 static bool recoveryTargetIsLatest = false;
 static List *expectedTLEs;
 static TimeLineID curFileTLI;
@@ -625,12 +643,6 @@ typedef struct XLogCtlData
 	TimeLineID	PrevTimeLineID;
 
 	/*
-	 * archiveCleanupCommand is read from recovery.conf but needs to be in
-	 * shared memory so that the checkpointer process can access it.
-	 */
-	char		archiveCleanupCommand[MAXPGPATH];
-
-	/*
 	 * SharedRecoveryInProgress indicates if we're still in crash or archive
 	 * recovery.  Protected by info_lck.
 	 */
@@ -846,7 +858,7 @@ static bool holdingAllLocks = false;
 static MemoryContext walDebugCxt = NULL;
 #endif
 
-static void readRecoveryCommandFile(void);
+static void readRecoverySignalFile(void);
 static void exitArchiveRecovery(TimeLineID endTLI, XLogRecPtr endOfLog);
 static bool recoveryStopsBefore(XLogReaderState *record);
 static bool recoveryStopsAfter(XLogReaderState *record);
@@ -5300,264 +5312,200 @@ 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.
+ * throw an ERROR since as of PG12.0 we no longer recognize that.
  *
- * The file is parsed using the main configuration parser.
+ * See if there are any recovery signal files and if so, set state for
+ * recovery.
  */
 static void
-readRecoveryCommandFile(void)
+readRecoverySignalFile(void)
 {
-	FILE	   *fd;
-	TimeLineID	rtli = 0;
-	bool		rtliGiven = false;
-	ConfigVariable *item,
-			   *head = NULL,
-			   *tail = NULL;
-	bool		recoveryTargetActionSet = false;
+	struct stat stat_buf;
 
+	if (IsBootstrapProcessingMode())
+		return;
 
-	fd = AllocateFile(RECOVERY_COMMAND_FILE, "r");
-	if (fd == NULL)
-	{
-		if (errno == ENOENT)
-			return;				/* not there, so no archive recovery */
+	/*
+	 * Set paths for named signal files
+	 */
+	snprintf(StandbySignalFile, MAXPGPATH, "%s", STANDBY_SIGNAL_FILE);
+	snprintf(RecoverySignalFile, MAXPGPATH, "%s", RECOVERY_SIGNAL_FILE);
+
+	/*
+	 * Check for old recovery API file: recovery.conf
+	 */
+	if (stat(RECOVERY_COMMAND_FILE, &stat_buf) == 0)
 		ereport(FATAL,
 				(errcode_for_file_access(),
-				 errmsg("could not open recovery command file \"%s\": %m",
+				 errmsg("using recovery command file \"%s\" is not supported",
 						RECOVERY_COMMAND_FILE)));
-	}
 
 	/*
-	 * Since we're asking ParseConfigFp() to report errors as FATAL, there's
-	 * no need to check the return value.
+	 * Remove unused .done file, if present. Ignore if absent.
 	 */
-	(void) ParseConfigFp(fd, RECOVERY_COMMAND_FILE, 0, FATAL, &head, &tail);
+	unlink(RECOVERY_COMMAND_DONE);
 
-	FreeFile(fd);
+	/*
+	 * Check for recovery signal files and if found, fsync them since they
+	 * represent server state information.
+	 *
+	 * If present, standby signal file takes precedence. If neither is present
+	 * then we won't enter archive recovery.
+	 */
+	if (stat(StandbySignalFile, &stat_buf) == 0)
+	{
+		int			fd;
 
-	for (item = head; item; item = item->next)
+		fd = BasicOpenFilePerm(StandbySignalFile, O_RDWR | PG_BINARY | get_sync_bit(sync_method),
+							   S_IRUSR | S_IWUSR);
+		pg_fsync(fd);
+		close(fd);
+		standby_signal_file_found = true;
+	}
+	else if (stat(RecoverySignalFile, &stat_buf) == 0)
 	{
-		if (strcmp(item->name, "restore_command") == 0)
-		{
-			recoveryRestoreCommand = pstrdup(item->value);
-			ereport(DEBUG2,
-					(errmsg_internal("restore_command = '%s'",
-									 recoveryRestoreCommand)));
-		}
-		else if (strcmp(item->name, "recovery_end_command") == 0)
-		{
-			recoveryEndCommand = pstrdup(item->value);
-			ereport(DEBUG2,
-					(errmsg_internal("recovery_end_command = '%s'",
-									 recoveryEndCommand)));
-		}
-		else if (strcmp(item->name, "archive_cleanup_command") == 0)
-		{
-			archiveCleanupCommand = pstrdup(item->value);
-			ereport(DEBUG2,
-					(errmsg_internal("archive_cleanup_command = '%s'",
-									 archiveCleanupCommand)));
-		}
-		else if (strcmp(item->name, "recovery_target_action") == 0)
-		{
-			if (strcmp(item->value, "pause") == 0)
-				recoveryTargetAction = RECOVERY_TARGET_ACTION_PAUSE;
-			else if (strcmp(item->value, "promote") == 0)
-				recoveryTargetAction = RECOVERY_TARGET_ACTION_PROMOTE;
-			else if (strcmp(item->value, "shutdown") == 0)
-				recoveryTargetAction = RECOVERY_TARGET_ACTION_SHUTDOWN;
-			else
-				ereport(ERROR,
-						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-						 errmsg("invalid value for recovery parameter \"%s\": \"%s\"",
-								"recovery_target_action",
-								item->value),
-						 errhint("Valid values are \"pause\", \"promote\", and \"shutdown\".")));
+		int			fd;
 
-			ereport(DEBUG2,
-					(errmsg_internal("recovery_target_action = '%s'",
-									 item->value)));
+		fd = BasicOpenFilePerm(RecoverySignalFile, O_RDWR | PG_BINARY | get_sync_bit(sync_method),
+							   S_IRUSR | S_IWUSR);
+		pg_fsync(fd);
+		close(fd);
+		recovery_signal_file_found = true;
+	}
 
-			recoveryTargetActionSet = true;
-		}
-		else if (strcmp(item->name, "recovery_target_timeline") == 0)
-		{
-			rtliGiven = true;
-			if (strcmp(item->value, "latest") == 0)
-				rtli = 0;
-			else
-			{
-				errno = 0;
-				rtli = (TimeLineID) strtoul(item->value, NULL, 0);
-				if (errno == EINVAL || errno == ERANGE)
-					ereport(FATAL,
-							(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-							 errmsg("recovery_target_timeline is not a valid number: \"%s\"",
-									item->value)));
-			}
-			if (rtli)
-				ereport(DEBUG2,
-						(errmsg_internal("recovery_target_timeline = %u", rtli)));
-			else
-				ereport(DEBUG2,
-						(errmsg_internal("recovery_target_timeline = latest")));
-		}
-		else if (strcmp(item->name, "recovery_target_xid") == 0)
-		{
-			errno = 0;
-			recoveryTargetXid = (TransactionId) strtoul(item->value, NULL, 0);
-			if (errno == EINVAL || errno == ERANGE)
-				ereport(FATAL,
-						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-						 errmsg("recovery_target_xid is not a valid number: \"%s\"",
-								item->value)));
-			ereport(DEBUG2,
+	StandbyModeRequested = false;
+	ArchiveRecoveryRequested = false;
+	if (standby_signal_file_found)
+	{
+		StandbyModeRequested = true;
+		ArchiveRecoveryRequested = true;
+	}
+	else if (recovery_signal_file_found)
+	{
+		StandbyModeRequested = false;
+		ArchiveRecoveryRequested = true;
+	}
+	else
+		return;
+
+	/*
+	 * We don't support standby_mode in standalone backends; that requires
+	 * other processes such as the WAL receiver to be alive.
+	 */
+	if (StandbyModeRequested && !IsUnderPostmaster)
+		ereport(FATAL,
+				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+				 errmsg("standby mode is not supported by single-user servers")));
+
+	logRecoveryParameters();
+	validateRecoveryParameters();
+}
+
+void
+logRecoveryParameters(void)
+{
+	int			normal_log_level = DEBUG2;
+
+	/*
+	 * Log messages for recovery parameters at server start
+	 */
+	ereport(normal_log_level,
+			(errmsg_internal("standby_mode = '%s'", (StandbyModeRequested ? "on" : "off"))));
+
+	if (recoveryRestoreCommand != NULL)
+		ereport(normal_log_level,
+				(errmsg_internal("restore_command = '%s'", recoveryRestoreCommand)));
+
+	if (recoveryEndCommand != NULL)
+		ereport(normal_log_level,
+				(errmsg_internal("recovery_end_command = '%s'", recoveryEndCommand)));
+
+	if (archiveCleanupCommand != NULL)
+		ereport(normal_log_level,
+				(errmsg_internal("archive_cleanup_command = '%s'", archiveCleanupCommand)));
+
+	if (PrimaryConnInfo != NULL)
+		ereport(normal_log_level,
+				(errmsg_internal("primary_conninfo = '%s'", PrimaryConnInfo)));
+
+	if (PrimarySlotName != NULL)
+		ereport(normal_log_level,
+				(errmsg_internal("primary_slot_name = '%s'", PrimarySlotName)));
+
+	if (recovery_min_apply_delay > 0)
+		ereport(normal_log_level,
+				(errmsg_internal("recovery_min_apply_delay = '%u'", recovery_min_apply_delay)));
+
+	switch (recoveryTarget)
+	{
+		case RECOVERY_TARGET_UNSET:
+			/* no recovery target was requested */
+			break;
+		case RECOVERY_TARGET_XID:
+			ereport(normal_log_level,
 					(errmsg_internal("recovery_target_xid = %u",
 									 recoveryTargetXid)));
-			recoveryTarget = RECOVERY_TARGET_XID;
-		}
-		else if (strcmp(item->name, "recovery_target_time") == 0)
-		{
-			recoveryTarget = RECOVERY_TARGET_TIME;
-
-			if (strcmp(item->value, "epoch") == 0 ||
-				strcmp(item->value, "infinity") == 0 ||
-				strcmp(item->value, "-infinity") == 0 ||
-				strcmp(item->value, "now") == 0 ||
-				strcmp(item->value, "today") == 0 ||
-				strcmp(item->value, "tomorrow") == 0 ||
-				strcmp(item->value, "yesterday") == 0)
-				ereport(FATAL,
-						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-						 errmsg("recovery_target_time is not a valid timestamp: \"%s\"",
-								item->value)));
-
-			/*
-			 * 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,
+			break;
+		case RECOVERY_TARGET_TIME:
+			ereport(normal_log_level,
 					(errmsg_internal("recovery_target_time = '%s'",
 									 timestamptz_to_str(recoveryTargetTime))));
-		}
-		else if (strcmp(item->name, "recovery_target_name") == 0)
-		{
-			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,
+			break;
+		case RECOVERY_TARGET_NAME:
+			ereport(normal_log_level,
 					(errmsg_internal("recovery_target_name = '%s'",
 									 recoveryTargetName)));
-		}
-		else if (strcmp(item->name, "recovery_target_lsn") == 0)
-		{
-			recoveryTarget = RECOVERY_TARGET_LSN;
-
-			/*
-			 * Convert the LSN string given by the user to XLogRecPtr form.
-			 */
-			recoveryTargetLSN =
-				DatumGetLSN(DirectFunctionCall3(pg_lsn_in,
-												CStringGetDatum(item->value),
-												ObjectIdGetDatum(InvalidOid),
-												Int32GetDatum(-1)));
-			ereport(DEBUG2,
+			break;
+		case RECOVERY_TARGET_LSN:
+			ereport(normal_log_level,
 					(errmsg_internal("recovery_target_lsn = '%X/%X'",
 									 (uint32) (recoveryTargetLSN >> 32),
 									 (uint32) recoveryTargetLSN)));
-		}
-		else if (strcmp(item->name, "recovery_target") == 0)
-		{
-			if (strcmp(item->value, "immediate") == 0)
-				recoveryTarget = RECOVERY_TARGET_IMMEDIATE;
-			else
-				ereport(ERROR,
-						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-						 errmsg("invalid value for recovery parameter \"%s\": \"%s\"",
-								"recovery_target",
-								item->value),
-						 errhint("The only allowed value is \"immediate\".")));
-			ereport(DEBUG2,
+			break;
+		case RECOVERY_TARGET_IMMEDIATE:
+			ereport(normal_log_level,
 					(errmsg_internal("recovery_target = '%s'",
-									 item->value)));
-		}
-		else if (strcmp(item->name, "recovery_target_inclusive") == 0)
-		{
-			/*
-			 * does nothing if a recovery_target is not also set
-			 */
-			if (!parse_bool(item->value, &recoveryTargetInclusive))
-				ereport(ERROR,
-						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-						 errmsg("parameter \"%s\" requires a Boolean value",
-								"recovery_target_inclusive")));
-			ereport(DEBUG2,
-					(errmsg_internal("recovery_target_inclusive = %s",
-									 item->value)));
-		}
-		else if (strcmp(item->name, "standby_mode") == 0)
-		{
-			if (!parse_bool(item->value, &StandbyModeRequested))
-				ereport(ERROR,
-						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-						 errmsg("parameter \"%s\" requires a Boolean value",
-								"standby_mode")));
-			ereport(DEBUG2,
-					(errmsg_internal("standby_mode = '%s'", item->value)));
-		}
-		else if (strcmp(item->name, "primary_conninfo") == 0)
-		{
-			PrimaryConnInfo = pstrdup(item->value);
-			ereport(DEBUG2,
-					(errmsg_internal("primary_conninfo = '%s'",
-									 PrimaryConnInfo)));
-		}
-		else if (strcmp(item->name, "primary_slot_name") == 0)
-		{
-			ReplicationSlotValidateName(item->value, ERROR);
-			PrimarySlotName = pstrdup(item->value);
-			ereport(DEBUG2,
-					(errmsg_internal("primary_slot_name = '%s'",
-									 PrimarySlotName)));
-		}
-		else if (strcmp(item->name, "trigger_file") == 0)
-		{
-			TriggerFile = pstrdup(item->value);
-			ereport(DEBUG2,
-					(errmsg_internal("trigger_file = '%s'",
-									 TriggerFile)));
-		}
-		else if (strcmp(item->name, "recovery_min_apply_delay") == 0)
-		{
-			const char *hintmsg;
+									 "immediate")));
+			break;
+	}
 
-			if (!parse_int(item->value, &recovery_min_apply_delay, GUC_UNIT_MS,
-						   &hintmsg))
-				ereport(ERROR,
-						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-						 errmsg("parameter \"%s\" requires a temporal value",
-								"recovery_min_apply_delay"),
-						 hintmsg ? errhint("%s", _(hintmsg)) : 0));
-			ereport(DEBUG2,
-					(errmsg_internal("recovery_min_apply_delay = '%s'", item->value)));
+	/*
+	 * Check details for recovery target, if any
+	 */
+	if (recoveryTarget > RECOVERY_TARGET_UNSET)
+	{
+		ereport(normal_log_level,
+				(errmsg_internal("recovery_target_inclusive = '%s'", (recoveryTargetInclusive ? "on " : "off"))));
+
+		switch (recoveryTargetTimeLineGoal)
+		{
+			case RECOVERY_TARGET_TIMELINE_CONTROLFILE:
+				ereport(normal_log_level,
+						(errmsg_internal("recovery_target_timeline = '%u' (from controlfile)",
+										 recoveryTargetTLI)));
+				break;
+			case RECOVERY_TARGET_TIMELINE_LATEST:
+				ereport(normal_log_level,
+						(errmsg_internal("recovery_target_timeline = 'latest'")));
+				break;
+			case RECOVERY_TARGET_TIMELINE_NUMERIC:
+				ereport(normal_log_level,
+						(errmsg_internal("recovery_target_timeline = '%u'",
+										 recoveryTargetTLIRequested)));
+				break;
 		}
-		else
-			ereport(FATAL,
-					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-					 errmsg("unrecognized recovery parameter \"%s\"",
-							item->name)));
 	}
 
+	ereport(normal_log_level,
+			(errmsg_internal("recovery_target_action = '%s'", RecoveryTargetActionText(recoveryTargetAction))));
+}
+
+void
+validateRecoveryParameters(void)
+{
+	if (!ArchiveRecoveryRequested)
+		return;
+
 	/*
 	 * Check for compulsory parameters
 	 */
@@ -5565,8 +5513,7 @@ readRecoveryCommandFile(void)
 	{
 		if (PrimaryConnInfo == NULL && recoveryRestoreCommand == NULL)
 			ereport(WARNING,
-					(errmsg("recovery command file \"%s\" specified neither primary_conninfo nor restore_command",
-							RECOVERY_COMMAND_FILE),
+					(errmsg("specified neither primary_conninfo nor restore_command"),
 					 errhint("The database server will regularly poll the pg_wal subdirectory to check for files placed there.")));
 	}
 	else
@@ -5574,8 +5521,7 @@ readRecoveryCommandFile(void)
 		if (recoveryRestoreCommand == NULL)
 			ereport(FATAL,
 					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-					 errmsg("recovery command file \"%s\" must specify restore_command when standby mode is not enabled",
-							RECOVERY_COMMAND_FILE)));
+					 errmsg("must specify restore_command when standby mode is not enabled")));
 	}
 
 	/*
@@ -5584,50 +5530,49 @@ readRecoveryCommandFile(void)
 	 * hot_standby = off, which was surprising behaviour.
 	 */
 	if (recoveryTargetAction == RECOVERY_TARGET_ACTION_PAUSE &&
-		recoveryTargetActionSet &&
 		!EnableHotStandby)
 		recoveryTargetAction = RECOVERY_TARGET_ACTION_SHUTDOWN;
 
 	/*
-	 * We don't support standby_mode in standalone backends; that requires
-	 * other processes such as the WAL receiver to be alive.
-	 */
-	if (StandbyModeRequested && !IsUnderPostmaster)
-		ereport(FATAL,
-				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-				 errmsg("standby mode is not supported by single-user servers")));
-
-	/* Enable fetching from archive recovery area */
-	ArchiveRecoveryRequested = true;
-
-	/*
 	 * If user specified recovery_target_timeline, validate it or compute the
 	 * "latest" value.  We can't do this until after we've gotten the restore
 	 * command and set InArchiveRecovery, because we need to fetch timeline
 	 * history files from the archive.
 	 */
-	if (rtliGiven)
+	if (recoveryTargetTimeLineGoal == RECOVERY_TARGET_TIMELINE_NUMERIC)
 	{
-		if (rtli)
-		{
-			/* Timeline 1 does not have a history file, all else should */
-			if (rtli != 1 && !existsTimeLineHistory(rtli))
-				ereport(FATAL,
-						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-						 errmsg("recovery target timeline %u does not exist",
-								rtli)));
-			recoveryTargetTLI = rtli;
-			recoveryTargetIsLatest = false;
-		}
-		else
-		{
-			/* We start the "latest" search from pg_control's timeline */
-			recoveryTargetTLI = findNewestTimeLine(recoveryTargetTLI);
-			recoveryTargetIsLatest = true;
-		}
-	}
+		TimeLineID	rtli = recoveryTargetTLIRequested;
+
+		/* Timeline 1 does not have a history file, all else should */
+		if (rtli != 1 && !existsTimeLineHistory(rtli))
+			ereport(FATAL,
+					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+					 errmsg("recovery target timeline %u does not exist",
+							rtli)));
+		recoveryTargetTLI = rtli;
 
-	FreeConfigVariables(head);
+		/*
+		 * The user has requested a specific tli. This might be the latest
+		 * timeline but we don't know that; the point here is that we do not
+		 * allow the recoveryTargetTLI to follow any changes.
+		 */
+		recoveryTargetIsLatest = false;
+	}
+	else if (recoveryTargetTimeLineGoal == RECOVERY_TARGET_TIMELINE_LATEST)
+	{
+		/* We start the "latest" search from pg_control's timeline */
+		recoveryTargetTLI = findNewestTimeLine(recoveryTargetTLI);
+		recoveryTargetIsLatest = true;
+	}
+	else
+	{
+		/*
+		 * else we just use the recoveryTargetTLI as already read from
+		 * ControlFile
+		 */
+		Assert(recoveryTargetTimeLineGoal == RECOVERY_TARGET_TIMELINE_CONTROLFILE);
+		recoveryTargetIsLatest = false;
+	}
 }
 
 /*
@@ -5728,11 +5673,22 @@ exitArchiveRecovery(TimeLineID endTLI, XLogRecPtr endOfLog)
 	unlink(recoveryPath);		/* ignore any error */
 
 	/*
-	 * Rename the config file out of the way, so that we don't accidentally
+	 * Remove the signal files out of the way, so that we don't accidentally
 	 * re-enter archive recovery mode in a subsequent crash.
 	 */
-	unlink(RECOVERY_COMMAND_DONE);
-	durable_rename(RECOVERY_COMMAND_FILE, RECOVERY_COMMAND_DONE, FATAL);
+	if (standby_signal_file_found &&
+		durable_unlink(StandbySignalFile, FATAL) != 0)
+		ereport(FATAL,
+				(errcode_for_file_access(),
+				 errmsg("could not remove file \"%s\": %m",
+						StandbySignalFile)));
+
+	if (recovery_signal_file_found &&
+		durable_unlink(RecoverySignalFile, FATAL) != 0)
+		ereport(FATAL,
+				(errcode_for_file_access(),
+				 errmsg("could not remove file \"%s\": %m",
+						RecoverySignalFile)));
 
 	ereport(LOG,
 			(errmsg("archive recovery complete")));
@@ -6475,18 +6431,9 @@ StartupXLOG(void)
 		recoveryTargetTLI = ControlFile->checkPointCopy.ThisTimeLineID;
 
 	/*
-	 * Check for recovery control file, and if so set up state for offline
-	 * recovery
-	 */
-	readRecoveryCommandFile();
-
-	/*
-	 * Save archive_cleanup_command in shared memory so that other processes
-	 * can see it.
+	 * Check for signal files, and if so set up state for offline recovery
 	 */
-	strlcpy(XLogCtl->archiveCleanupCommand,
-			archiveCleanupCommand ? archiveCleanupCommand : "",
-			sizeof(XLogCtl->archiveCleanupCommand));
+	readRecoverySignalFile();
 
 	if (ArchiveRecoveryRequested)
 	{
@@ -6666,7 +6613,8 @@ StartupXLOG(void)
 		 * This can happen for example if a base backup is taken from a
 		 * running server using an atomic filesystem snapshot, without calling
 		 * pg_start/stop_backup. Or if you just kill a running master server
-		 * and put it into archive recovery by creating a recovery.conf file.
+		 * and put it into archive recovery by creating a recovery signal
+		 * file.
 		 *
 		 * Our strategy in that case is to perform crash recovery first,
 		 * replaying all the WAL present in pg_wal, and only enter archive
@@ -6892,7 +6840,7 @@ StartupXLOG(void)
 
 	/*
 	 * Check whether we need to force recovery from WAL.  If it appears to
-	 * have been a clean shutdown and we did not have a recovery.conf file,
+	 * have been a clean shutdown and we did not have a recovery signal file,
 	 * then assume no recovery needed.
 	 */
 	if (checkPoint.redo < RecPtr)
@@ -6906,7 +6854,7 @@ StartupXLOG(void)
 		InRecovery = true;
 	else if (ArchiveRecoveryRequested)
 	{
-		/* force recovery due to presence of recovery.conf */
+		/* force recovery due to presence of recovery signal file */
 		InRecovery = true;
 	}
 
@@ -7427,7 +7375,6 @@ StartupXLOG(void)
 			/*
 			 * end of main redo apply loop
 			 */
-
 			if (reachedStopPoint)
 			{
 				if (!reachedConsistency)
@@ -9499,8 +9446,8 @@ CreateRestartPoint(int flags)
 	/*
 	 * Finally, execute archive_cleanup_command, if any.
 	 */
-	if (XLogCtl->archiveCleanupCommand[0])
-		ExecuteRecoveryCommand(XLogCtl->archiveCleanupCommand,
+	if (archiveCleanupCommand)
+		ExecuteRecoveryCommand(archiveCleanupCommand,
 							   "archive_cleanup_command",
 							   false);
 
@@ -12022,7 +11969,7 @@ WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess,
 					 * that when we later jump backwards to start redo at
 					 * RedoStartLSN, we will have the logs streamed already.
 					 */
-					if (PrimaryConnInfo)
+					if (PrimaryConnInfo && strcmp(PrimaryConnInfo, "") != 0)
 					{
 						XLogRecPtr	ptr;
 						TimeLineID	tli;
@@ -12391,14 +12338,14 @@ CheckForStandbyTrigger(void)
 		return true;
 	}
 
-	if (TriggerFile == NULL)
+	if (PromoteTriggerFile == NULL)
 		return false;
 
-	if (stat(TriggerFile, &stat_buf) == 0)
+	if (stat(PromoteTriggerFile, &stat_buf) == 0)
 	{
 		ereport(LOG,
-				(errmsg("trigger file found: %s", TriggerFile)));
-		unlink(TriggerFile);
+				(errmsg("promote trigger file found: %s", PromoteTriggerFile)));
+		unlink(PromoteTriggerFile);
 		triggered = true;
 		fast_promote = true;
 		return true;
@@ -12406,8 +12353,8 @@ CheckForStandbyTrigger(void)
 	else if (errno != ENOENT)
 		ereport(ERROR,
 				(errcode_for_file_access(),
-				 errmsg("could not stat trigger file \"%s\": %m",
-						TriggerFile)));
+				 errmsg("could not stat promote trigger file \"%s\": %m",
+						PromoteTriggerFile)));
 
 	return false;
 }
diff --git a/src/backend/access/transam/xlogarchive.c b/src/backend/access/transam/xlogarchive.c
index d403171..57d3025 100644
--- a/src/backend/access/transam/xlogarchive.c
+++ b/src/backend/access/transam/xlogarchive.c
@@ -410,7 +410,7 @@ ExecuteRecoveryCommand(const char *command, const char *commandName, bool failOn
 
 		ereport((signaled && failOnSignal) ? FATAL : WARNING,
 		/*------
-		   translator: First %s represents a recovery.conf parameter name like
+		   translator: First %s represents a postgresql.conf parameter name like
 		  "recovery_end_command", the 2nd is the value of that parameter, the
 		  third an already translated error message. */
 				(errmsg("%s \"%s\": %s", commandName,
diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c
index a31adcc..67c4e6e 100644
--- a/src/backend/access/transam/xlogfuncs.c
+++ b/src/backend/access/transam/xlogfuncs.c
@@ -324,10 +324,11 @@ pg_create_restore_point(PG_FUNCTION_ARGS)
 
 	restore_name_str = text_to_cstring(restore_name);
 
-	if (strlen(restore_name_str) >= MAXFNAMELEN)
+	if (strlen(restore_name_str) >= MAXRESTOREPOINTNAMELEN)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-				 errmsg("value too long for restore point (maximum %d characters)", MAXFNAMELEN - 1)));
+				 errmsg("value too long for restore point (maximum %d characters)",
+						MAXRESTOREPOINTNAMELEN - 1)));
 
 	restorepoint = XLogRestorePoint(restore_name_str);
 
diff --git a/src/backend/commands/extension.c b/src/backend/commands/extension.c
index 2d761a5..bb554ab 100644
--- a/src/backend/commands/extension.c
+++ b/src/backend/commands/extension.c
@@ -9,8 +9,8 @@
  * 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
- * script file, containing SQL commands to create the extension's objects.
+ * postgresql.conf.  An extension also has an installation script file,
+ * containing SQL commands to create the extension's objects.
  *
  * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
diff --git a/src/backend/postmaster/startup.c b/src/backend/postmaster/startup.c
index 2926211..28c3225 100644
--- a/src/backend/postmaster/startup.c
+++ b/src/backend/postmaster/startup.c
@@ -148,6 +148,7 @@ HandleStartupProcInterrupts(void)
 	{
 		got_SIGHUP = false;
 		ProcessConfigFile(PGC_SIGHUP);
+		validateRecoveryParameters();
 	}
 
 	/*
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 2317e8b..7988382 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -32,6 +32,7 @@
 #include "access/transam.h"
 #include "access/twophase.h"
 #include "access/xact.h"
+#include "access/xlog.h"
 #include "access/xlog_internal.h"
 #include "catalog/namespace.h"
 #include "catalog/pg_authid.h"
@@ -84,6 +85,7 @@
 #include "utils/float.h"
 #include "utils/memutils.h"
 #include "utils/pg_locale.h"
+#include "utils/pg_lsn.h"
 #include "utils/plancache.h"
 #include "utils/portal.h"
 #include "utils/ps_status.h"
@@ -195,6 +197,19 @@ static bool check_cluster_name(char **newval, void **extra, GucSource source);
 static const char *show_unix_socket_permissions(void);
 static const char *show_log_file_mode(void);
 static const char *show_data_directory_mode(void);
+static bool check_recovery_target_timeline(char **newval, void **extra, GucSource source);
+static void assign_recovery_target_timeline(const char *newval, void *extra);
+static bool check_primary_slot_name(char **newval, void **extra, GucSource source);
+static bool check_recovery_target(char **newval, void **extra, GucSource source);
+static void assign_recovery_target(const char *newval, void *extra);
+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_time(char **newval, void **extra, GucSource source);
+static void assign_recovery_target_time(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_lsn(char **newval, void **extra, GucSource source);
+static void assign_recovery_target_lsn(const char *newval, void *extra);
 
 /* Private functions in guc-file.l that need to be called from guc.c */
 static ConfigVariable *ProcessConfigFileInternal(GucContext context,
@@ -434,6 +449,7 @@ static const struct config_enum_entry password_encryption_options[] = {
  */
 extern const struct config_enum_entry wal_level_options[];
 extern const struct config_enum_entry archive_mode_options[];
+extern const struct config_enum_entry recovery_target_action_options[];
 extern const struct config_enum_entry sync_method_options[];
 extern const struct config_enum_entry dynamic_shared_memory_options[];
 
@@ -526,6 +542,13 @@ static int	wal_block_size;
 static bool data_checksums;
 static bool integer_datetimes;
 static bool assert_enabled;
+static char *recovery_target_timeline_string;
+static char *recovery_target_string;
+static char *recovery_target_xid_string;
+static char *recovery_target_time_string;
+static char *recovery_target_name_string;
+static char *recovery_target_lsn_string;
+
 
 /* should be static, but commands/variable.c needs to get at this */
 char	   *role_string;
@@ -609,6 +632,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 */
@@ -1640,6 +1667,16 @@ static struct config_bool ConfigureNamesBool[] =
 	},
 
 	{
+		{"recovery_target_inclusive", PGC_POSTMASTER, WAL_RECOVERY_TARGET,
+			gettext_noop("Sets whether to include or exclude transaction with recovery target."),
+			NULL
+		},
+		&recoveryTargetInclusive,
+		true,
+		NULL, NULL, NULL
+	},
+
+	{
 		{"hot_standby", PGC_POSTMASTER, REPLICATION_STANDBY,
 			gettext_noop("Allows connections and queries during recovery."),
 			NULL
@@ -1967,8 +2004,19 @@ static struct config_int ConfigureNamesInt[] =
 	},
 
 	{
+		{"recovery_min_apply_delay", PGC_POSTMASTER, REPLICATION_STANDBY,
+			gettext_noop("Sets the minimum delay to apply changes during recovery."),
+			NULL,
+			GUC_UNIT_MS
+		},
+		&recovery_min_apply_delay,
+		0, 0, INT_MAX,
+		NULL, NULL, NULL
+	},
+
+	{
 		{"wal_receiver_status_interval", PGC_SIGHUP, REPLICATION_STANDBY,
-			gettext_noop("Sets the maximum interval between WAL receiver status reports to the primary."),
+			gettext_noop("Sets the maximum interval between WAL receiver status reports to the sending server."),
 			NULL,
 			GUC_UNIT_S
 		},
@@ -1979,7 +2027,7 @@ static struct config_int ConfigureNamesInt[] =
 
 	{
 		{"wal_receiver_timeout", PGC_SIGHUP, REPLICATION_STANDBY,
-			gettext_noop("Sets the maximum wait time to receive data from the primary."),
+			gettext_noop("Sets the maximum wait time to receive data from the sending server."),
 			NULL,
 			GUC_UNIT_MS
 		},
@@ -3286,6 +3334,123 @@ static struct config_string ConfigureNamesString[] =
 	},
 
 	{
+		{"restore_command", PGC_POSTMASTER, WAL_ARCHIVE_RECOVERY,
+			gettext_noop("Sets the shell command that will retrieve an archived WAL file."),
+			NULL
+		},
+		&recoveryRestoreCommand,
+		NULL,
+		NULL, NULL, NULL
+	},
+
+	{
+		{"archive_cleanup_command", PGC_POSTMASTER, WAL_ARCHIVE_RECOVERY,
+			gettext_noop("Sets the shell command that will be executed at every restartpoint."),
+			NULL
+		},
+		&archiveCleanupCommand,
+		NULL,
+		NULL, NULL, NULL
+	},
+
+	{
+		{"recovery_end_command", PGC_POSTMASTER, WAL_ARCHIVE_RECOVERY,
+			gettext_noop("Sets the shell command that will be executed once only at the end of recovery."),
+			NULL
+		},
+		&recoveryEndCommand,
+		NULL,
+		NULL, NULL, NULL
+	},
+
+	{
+		{"recovery_target_timeline", PGC_POSTMASTER, WAL_RECOVERY_TARGET,
+			gettext_noop("Sets recovering into a particular timeline."),
+			NULL
+		},
+		&recovery_target_timeline_string,
+		"",
+		check_recovery_target_timeline, assign_recovery_target_timeline, NULL
+	},
+
+	{
+		{"recovery_target", PGC_POSTMASTER, WAL_RECOVERY_TARGET,
+			gettext_noop("Sets recovery should end as soon as a consistent state is reached"),
+			NULL
+		},
+		&recovery_target_string,
+		"",
+		check_recovery_target, assign_recovery_target, NULL
+	},
+	{
+		{"recovery_target_xid", PGC_POSTMASTER, 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_time", PGC_POSTMASTER, 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_name", PGC_POSTMASTER, WAL_RECOVERY_TARGET,
+			gettext_noop("Sets the named restore point up to which recovery will proceed"),
+			NULL
+		},
+		&recovery_target_name_string,
+		"",
+		check_recovery_target_name, assign_recovery_target_name, NULL
+	},
+	{
+		{"recovery_target_lsn", PGC_POSTMASTER, WAL_RECOVERY_TARGET,
+			gettext_noop("Sets the LSN of the write-ahead log location up to which recovery will proceed"),
+			NULL
+		},
+		&recovery_target_lsn_string,
+		"",
+		check_recovery_target_lsn, assign_recovery_target_lsn, NULL
+	},
+
+	{
+		{"promote_trigger_file", PGC_POSTMASTER, REPLICATION_STANDBY,
+			gettext_noop("Specifies a filename whose presence ends recovery in the standby"),
+			NULL
+		},
+		&PromoteTriggerFile,
+		NULL,
+		NULL, NULL, NULL
+	},
+
+	{
+		{"primary_conninfo", PGC_POSTMASTER, REPLICATION_STANDBY,
+			gettext_noop("Sets the connection string to be used to connect with the sending server."),
+			NULL,
+			GUC_SUPERUSER_ONLY
+		},
+		&PrimaryConnInfo,
+		NULL,
+		NULL, NULL, NULL
+	},
+
+	{
+		{"primary_slot_name", PGC_POSTMASTER, REPLICATION_STANDBY,
+			gettext_noop("Sets the name of the replication slot to use on the sending server."),
+			NULL
+		},
+		&PrimarySlotName,
+		NULL,
+		check_primary_slot_name, NULL, NULL
+	},
+
+	{
 		{"client_encoding", PGC_USERSET, CLIENT_CONN_LOCALE,
 			gettext_noop("Sets the client's character set encoding."),
 			NULL,
@@ -4066,6 +4231,16 @@ static struct config_enum ConfigureNamesEnum[] =
 	},
 
 	{
+		{"recovery_target_action", PGC_POSTMASTER, WAL_RECOVERY_TARGET,
+			gettext_noop("Sets the action to perform upon reaching the recovery target."),
+			NULL
+		},
+		&recoveryTargetAction,
+		RECOVERY_TARGET_ACTION_PAUSE, recovery_target_action_options,
+		NULL, NULL, NULL
+	},
+
+	{
 		{"trace_recovery_messages", PGC_SIGHUP, DEVELOPER_OPTIONS,
 			gettext_noop("Enables logging of recovery-related debugging information."),
 			gettext_noop("Each level includes all the levels that follow it. The later"
@@ -10808,4 +10983,261 @@ show_data_directory_mode(void)
 	return buf;
 }
 
+static bool
+check_recovery_target_timeline(char **newval, void **extra, GucSource source)
+{
+	RecoveryTargetTimeLineGoal rttg = RECOVERY_TARGET_TIMELINE_CONTROLFILE;
+	RecoveryTargetTimeLineGoal *myextra;
+
+	if (strcmp(*newval, "latest") == 0)
+		rttg = RECOVERY_TARGET_TIMELINE_LATEST;
+	else if (strcmp(*newval, "controlfile") == 0 || strcmp(*newval, "") == 0)
+		rttg = RECOVERY_TARGET_TIMELINE_CONTROLFILE;
+	else
+	{
+		const char *hintmsg;
+
+		if (!parse_int(*newval, NULL, 0, &hintmsg))
+		{
+			GUC_check_errdetail("recovery_target_timeline is not a valid number");
+			if (hintmsg)
+				GUC_check_errhint("%s", hintmsg);
+			return false;
+		}
+		rttg = RECOVERY_TARGET_TIMELINE_NUMERIC;
+	}
+
+	myextra = (TimeLineID *) guc_malloc(ERROR, sizeof(TimeLineID));
+	*myextra = rttg;
+	*extra = (void *) myextra;
+
+	return true;
+}
+
+static void
+assign_recovery_target_timeline(const char *newval, void *extra)
+{
+	recoveryTargetTimeLineGoal = *((TimeLineID *) extra);
+	if (recoveryTargetTimeLineGoal == RECOVERY_TARGET_TIMELINE_NUMERIC)
+		recoveryTargetTLIRequested = (TimeLineID) strtoul(newval, NULL, 0);
+	else
+		recoveryTargetTLIRequested = 0;
+}
+
+static bool
+check_primary_slot_name(char **newval, void **extra, GucSource source)
+{
+	if (*newval && strcmp(*newval, "") != 0 &&
+		!ReplicationSlotValidateName(*newval, WARNING))
+	{
+		GUC_check_errdetail("primary_slot_name is not valid: \"%s\"", *newval);
+		return false;
+	}
+
+	return true;
+}
+
+static bool
+check_recovery_target(char **newval, void **extra, GucSource source)
+{
+	if (strcmp(*newval, "immediate") != 0 && strcmp(*newval, "") != 0)
+	{
+		GUC_check_errdetail("The only allowed value is \"immediate\".");
+		return false;
+	}
+	return true;
+}
+
+static void
+assign_recovery_target(const char *newval, void *extra)
+{
+	if (newval && strcmp(newval, "") != 0)
+		recoveryTarget = RECOVERY_TARGET_IMMEDIATE;
+	else
+
+		/*
+		 * reset recoveryTarget to RECOVERY_TARGET_UNSET to proper handle if
+		 * user set multiple recovery_target with blank value on last
+		 */
+		recoveryTarget = RECOVERY_TARGET_UNSET;
+}
+
+static bool
+check_recovery_target_xid(char **newval, void **extra, GucSource source)
+{
+	if (strcmp(*newval, "") != 0)
+	{
+		TransactionId xid;
+		TransactionId *myextra;
+
+		errno = 0;
+		xid = (TransactionId) strtoul(*newval, NULL, 0);
+		if (errno == EINVAL || errno == ERANGE)
+		{
+			GUC_check_errdetail("%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)
+{
+	if (newval && strcmp(newval, "") != 0)
+	{
+		recoveryTarget = RECOVERY_TARGET_XID;
+		recoveryTargetXid = *((TransactionId *) extra);
+	}
+	else
+		recoveryTarget = RECOVERY_TARGET_UNSET;
+}
+
+static bool
+check_recovery_target_time(char **newval, void **extra, GucSource source)
+{
+	if (strcmp(*newval, "") != 0)
+	{
+		TimestampTz time;
+		TimestampTz *myextra;
+		MemoryContext oldcontext = CurrentMemoryContext;
+
+		/* reject some special values */
+		if (strcmp(*newval, "epoch") == 0 ||
+			strcmp(*newval, "infinity") == 0 ||
+			strcmp(*newval, "-infinity") == 0 ||
+			strcmp(*newval, "now") == 0 ||
+			strcmp(*newval, "today") == 0 ||
+			strcmp(*newval, "tomorrow") == 0 ||
+			strcmp(*newval, "yesterday") == 0)
+		{
+			return false;
+		}
+
+		PG_TRY();
+		{
+			time = 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)
+{
+	if (newval && strcmp(newval, "") != 0)
+	{
+		recoveryTarget = RECOVERY_TARGET_TIME;
+		recoveryTargetTime = *((TimestampTz *) extra);
+	}
+	else
+		recoveryTarget = RECOVERY_TARGET_UNSET;
+}
+
+static bool
+check_recovery_target_name(char **newval, void **extra, GucSource source)
+{
+	/* Use the value of newval directly */
+	if (strlen(*newval) > MAXRESTOREPOINTNAMELEN)
+	{
+		GUC_check_errdetail("recovery_target_name is too long (maximum %d characters)",
+							MAXRESTOREPOINTNAMELEN);
+		return false;
+	}
+	return true;
+}
+
+static void
+assign_recovery_target_name(const char *newval, void *extra)
+{
+	if (newval && strcmp(newval, "") != 0)
+	{
+		recoveryTarget = RECOVERY_TARGET_NAME;
+		recoveryTargetName = (char *) newval;
+	}
+	else
+		recoveryTarget = RECOVERY_TARGET_UNSET;
+}
+
+static bool
+check_recovery_target_lsn(char **newval, void **extra, GucSource source)
+{
+	if (strcmp(*newval, "") != 0)
+	{
+		XLogRecPtr	lsn;
+		XLogRecPtr *myextra;
+		MemoryContext oldcontext = CurrentMemoryContext;
+
+		/*
+		 * Convert the LSN string given by the user to XLogRecPtr form.
+		 */
+		PG_TRY();
+		{
+			lsn = DatumGetLSN(DirectFunctionCall3(pg_lsn_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 = (XLogRecPtr *) guc_malloc(ERROR, sizeof(XLogRecPtr));
+		*myextra = lsn;
+		*extra = (void *) myextra;
+	}
+	return true;
+}
+
+static void
+assign_recovery_target_lsn(const char *newval, void *extra)
+{
+	if (newval && strcmp(newval, "") != 0)
+	{
+		recoveryTarget = RECOVERY_TARGET_LSN;
+		recoveryTargetLSN = *((XLogRecPtr *) extra);
+	}
+	else
+		recoveryTarget = RECOVERY_TARGET_UNSET;
+}
+
 #include "guc-file.c"
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
index 4e61bc6..148d816 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -226,6 +226,32 @@
 #archive_timeout = 0		# force a logfile segment switch after this
 				# number of seconds; 0 disables
 
+# - Archive Recovery -
+# These are only used in recovery mode
+
+#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 -
+
+# Set these only when performing a targeted recovery
+
+#recovery_target='' # 'immediate' to end recovery as soon as a consistent state is reached
+#recovery_target_name='' # the named restore point to which recovery will proceed
+#recovery_target_time='' # the time stamp up to which recovery will proceed
+#recovery_target_xid=''  # the transaction ID up to which recovery will proceed
+#recovery_target_lsn=''  # the LSN of the write-ahead log location up to which recovery will proceed
+#recovery_target_inclusive = on # Specifies whether to stop:
+								# just after the specified recovery target (true)
+								# just before the recovery target (false)
+#recovery_target_timeline = ''	# unset means read from controlfile (default),
+				# or set to 'latest' or timeline ID
+#recovery_target_action = '' 	# 'pause', 'promote', 'shutdown'
+
 
 #------------------------------------------------------------------------------
 # REPLICATION
@@ -259,6 +285,9 @@
 
 # These settings are ignored on a master server.
 
+#primary_conninfo = ''			# connection string on sending server
+#primary_slot_name = ''			# connection slot on sending server
+#promote_trigger_file = ''		# filename whose presence ends recovery
 #hot_standby = on			# "off" disallows queries during recovery
 					# (change requires restart)
 #max_standby_archive_delay = 30s	# max delay before canceling queries
diff --git a/src/bin/pg_archivecleanup/pg_archivecleanup.c b/src/bin/pg_archivecleanup/pg_archivecleanup.c
index d017f57..8648137 100644
--- a/src/bin/pg_archivecleanup/pg_archivecleanup.c
+++ b/src/bin/pg_archivecleanup/pg_archivecleanup.c
@@ -269,7 +269,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 recovery:\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/src/bin/pg_basebackup/pg_basebackup.c b/src/bin/pg_basebackup/pg_basebackup.c
index d6fef38..29181e2 100644
--- a/src/bin/pg_basebackup/pg_basebackup.c
+++ b/src/bin/pg_basebackup/pg_basebackup.c
@@ -131,9 +131,12 @@ static int	has_xlogendptr = 0;
 static volatile LONG has_xlogendptr = 0;
 #endif
 
-/* Contents of recovery.conf to be generated */
+/* Contents of configuration file to be generated */
 static PQExpBuffer recoveryconfcontents = NULL;
 
+#define PG_AUTOCONF_FILENAME		"postgresql.auto.conf"
+#define STANDBY_SIGNAL_FILE 		"standby.signal"
+
 /* Function headers */
 static void usage(void);
 static void disconnect_and_exit(int code) pg_attribute_noreturn();
@@ -346,7 +349,8 @@ usage(void)
 	printf(_("  -r, --max-rate=RATE    maximum transfer rate to transfer data directory\n"
 			 "                         (in kB/s, or use suffix \"k\" or \"M\")\n"));
 	printf(_("  -R, --write-recovery-conf\n"
-			 "                         write recovery.conf for replication\n"));
+			 "                         append replication config to " PG_AUTOCONF_FILENAME "\n"
+			 "                         and place " STANDBY_SIGNAL_FILE " file\n"));
 	printf(_("  -T, --tablespace-mapping=OLDDIR=NEWDIR\n"
 			 "                         relocate tablespace in OLDDIR to NEWDIR\n"));
 	printf(_("      --waldir=WALDIR    location for the write-ahead log directory\n"));
@@ -974,6 +978,9 @@ ReceiveTarFile(PGconn *conn, PGresult *res, int rownum)
 	bool		basetablespace = PQgetisnull(res, rownum, 0);
 	bool		in_tarhdr = true;
 	bool		skip_file = false;
+	bool		is_postgresql_auto_conf = false;
+	bool		found_postgresql_auto_conf = false;
+	int			file_padding_len = 0;
 	size_t		tarhdrsz = 0;
 	pgoff_t		filesz = 0;
 
@@ -1113,8 +1120,8 @@ 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
-			 * (but not stdout).
+			 * write configuration file into the tarfile. When done, close the
+			 * file (but not stdout).
 			 *
 			 * Also, write two completely empty blocks at the end of the tar
 			 * file, as required by some tar programs.
@@ -1126,19 +1133,31 @@ ReceiveTarFile(PGconn *conn, PGresult *res, int rownum)
 			if (basetablespace && writerecoveryconf)
 			{
 				char		header[512];
-				int			padding;
 
-				tarCreateHeader(header, "recovery.conf", NULL,
-								recoveryconfcontents->len,
-								pg_file_create_mode, 04000, 02000,
-								time(NULL));
+				if (!found_postgresql_auto_conf)
+				{
+					int			padding;
 
-				padding = ((recoveryconfcontents->len + 511) & ~511) - recoveryconfcontents->len;
+					tarCreateHeader(header, PG_AUTOCONF_FILENAME, NULL,
+									recoveryconfcontents->len,
+									pg_file_create_mode, 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);
+				}
+
+				tarCreateHeader(header, STANDBY_SIGNAL_FILE, NULL,
+								0,	/* zero-length file */
+								0600, 04000, 02000,
+								time(NULL));
 
 				WRITE_TAR_DATA(header, sizeof(header));
-				WRITE_TAR_DATA(recoveryconfcontents->data, recoveryconfcontents->len);
-				if (padding)
-					WRITE_TAR_DATA(zerobuf, padding);
+				WRITE_TAR_DATA(zerobuf, 511);
 			}
 
 			/* 2 * 512 bytes empty data at end of file */
@@ -1182,8 +1201,8 @@ ReceiveTarFile(PGconn *conn, PGresult *res, int rownum)
 		if (!writerecoveryconf || !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 config file, or when not working on the base
+			 * tablespace, we never have to look for an existing configuration
 			 * file in the stream.
 			 */
 			WRITE_TAR_DATA(copybuf, r);
@@ -1191,7 +1210,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 config file 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.
 			 *
@@ -1235,29 +1254,46 @@ 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
-						 * padded to the next multiple of 512
+						 * look at the file metadata: we may want append
+						 * recovery info into PG_AUTOCONF_FILENAME and skip
+						 * standby signal file In both cases we must calculate
+						 * tar padding
 						 */
-						int			padding;
-
-						skip_file = (strcmp(&tarhdr[0], "recovery.conf") == 0);
+						skip_file = (strcmp(&tarhdr[0], STANDBY_SIGNAL_FILE) == 0);
+						is_postgresql_auto_conf = (strcmp(&tarhdr[0], PG_AUTOCONF_FILENAME) == 0);
 
 						filesz = read_tar_number(&tarhdr[124], 12);
+						file_padding_len = ((filesz + 511) & ~511) - filesz;
 
-						padding = ((filesz + 511) & ~511) - filesz;
-						filesz += padding;
+						if (is_postgresql_auto_conf && writerecoveryconf)
+						{
+							/* replace tar header */
+							char		header[512];
+
+							tarCreateHeader(header, PG_AUTOCONF_FILENAME, NULL,
+											filesz + recoveryconfcontents->len,
+											pg_file_create_mode, 04000, 02000,
+											time(NULL));
+
+							WRITE_TAR_DATA(header, sizeof(header));
+						}
+						else
+						{
+							/* copy stream with padding */
+							filesz += file_padding_len;
+
+							if (!skip_file)
+							{
+								/*
+								 * If we're not skipping the file, write the
+								 * tar header unmodified.
+								 */
+								WRITE_TAR_DATA(tarhdr, 512);
+							}
+						}
 
 						/* Next part is the file, not the header */
 						in_tarhdr = false;
-
-						/*
-						 * If we're not skipping the file, write the tar
-						 * header unmodified.
-						 */
-						if (!skip_file)
-							WRITE_TAR_DATA(tarhdr, 512);
 					}
 				}
 				else
@@ -1281,6 +1317,32 @@ ReceiveTarFile(PGconn *conn, PGresult *res, int rownum)
 						pos += bytes2write;
 						filesz -= bytes2write;
 					}
+					else if (is_postgresql_auto_conf && writerecoveryconf)
+					{
+						/* append recovery conf to PG_AUTOCONF_FILENAME */
+						int			padding;
+						int			tailsize;
+
+						tailsize = (512 - file_padding_len) + recoveryconfcontents->len;
+						padding = ((tailsize + 511) & ~511) - tailsize;
+
+						WRITE_TAR_DATA(recoveryconfcontents->data, recoveryconfcontents->len);
+
+						if (padding)
+						{
+							char		zerobuf[512];
+
+							MemSet(zerobuf, 0, sizeof(zerobuf));
+							WRITE_TAR_DATA(zerobuf, padding);
+						}
+
+						/* skip original file padding */
+						is_postgresql_auto_conf = false;
+						skip_file = true;
+						filesz += file_padding_len;
+
+						found_postgresql_auto_conf = true;
+					}
 					else
 					{
 						/*
@@ -1289,6 +1351,7 @@ ReceiveTarFile(PGconn *conn, PGresult *res, int rownum)
 						 */
 						in_tarhdr = true;
 						skip_file = false;
+						is_postgresql_auto_conf = false;
 						tarhdrsz = 0;
 						filesz = 0;
 					}
@@ -1614,7 +1677,7 @@ escape_quotes(const char *src)
 }
 
 /*
- * Create a recovery.conf file in memory using a PQExpBuffer
+ * Create a configuration file in memory using a PQExpBuffer
  */
 static void
 GenerateRecoveryConf(PGconn *conn)
@@ -1638,8 +1701,6 @@ GenerateRecoveryConf(PGconn *conn)
 		disconnect_and_exit(1);
 	}
 
-	appendPQExpBufferStr(recoveryconfcontents, "standby_mode = 'on'\n");
-
 	initPQExpBuffer(&conninfo_buf);
 	for (option = connOptions; option && option->keyword; option++)
 	{
@@ -1698,8 +1759,9 @@ GenerateRecoveryConf(PGconn *conn)
 
 
 /*
- * Write a recovery.conf file into the directory specified in basedir,
+ * Write the configuration file into the directory specified in basedir,
  * with the contents already collected in memory.
+ * Then write the signal file into the basedir also.
  */
 static void
 WriteRecoveryConf(void)
@@ -1707,9 +1769,9 @@ WriteRecoveryConf(void)
 	char		filename[MAXPGPATH];
 	FILE	   *cf;
 
-	sprintf(filename, "%s/recovery.conf", basedir);
+	snprintf(filename, MAXPGPATH, "%s/%s", basedir, PG_AUTOCONF_FILENAME);
 
-	cf = fopen(filename, "w");
+	cf = fopen(filename, "a");
 	if (cf == NULL)
 	{
 		fprintf(stderr, _("%s: could not create file \"%s\": %s\n"), progname, filename, strerror(errno));
@@ -1725,6 +1787,16 @@ WriteRecoveryConf(void)
 	}
 
 	fclose(cf);
+
+	snprintf(filename, MAXPGPATH, "%s/%s", basedir, STANDBY_SIGNAL_FILE);
+	cf = fopen(filename, "w");
+	if (cf == NULL)
+	{
+		fprintf(stderr, _("%s: could not create file \"%s\": %s\n"), progname, filename, strerror(errno));
+		disconnect_and_exit(1);
+	}
+
+	fclose(cf);
 }
 
 
@@ -1780,7 +1852,7 @@ BaseBackup(void)
 	}
 
 	/*
-	 * Build contents of recovery.conf if requested
+	 * Build contents of configuration file if requested
 	 */
 	if (writerecoveryconf)
 		GenerateRecoveryConf(conn);
@@ -2094,7 +2166,7 @@ BaseBackup(void)
 #endif
 	}
 
-	/* Free the recovery.conf contents */
+	/* Free the configuration file contents */
 	destroyPQExpBuffer(recoveryconfcontents);
 
 	/*
diff --git a/src/bin/pg_basebackup/t/010_pg_basebackup.pl b/src/bin/pg_basebackup/t/010_pg_basebackup.pl
index 2211d90..b73c1ef 100644
--- a/src/bin/pg_basebackup/t/010_pg_basebackup.pl
+++ b/src/bin/pg_basebackup/t/010_pg_basebackup.pl
@@ -358,19 +358,16 @@ SKIP:
 
 $node->command_ok([ 'pg_basebackup', '-D', "$tempdir/backupR", '-R' ],
 	'pg_basebackup -R runs');
-ok(-f "$tempdir/backupR/recovery.conf", 'recovery.conf was created');
-my $recovery_conf = slurp_file "$tempdir/backupR/recovery.conf";
+ok(-f "$tempdir/backupR/postgresql.auto.conf", 'postgresql.auto.conf present');
+ok(-f "$tempdir/backupR/standby.signal", 'standby mode is configured');
+my $recovery_conf = slurp_file "$tempdir/backupR/postgresql.auto.conf";
 rmtree("$tempdir/backupR");
 
 my $port = $node->port;
 like(
 	$recovery_conf,
-	qr/^standby_mode = 'on'\n/m,
-	'recovery.conf sets standby_mode');
-like(
-	$recovery_conf,
 	qr/^primary_conninfo = '.*port=$port.*'\n/m,
-	'recovery.conf sets primary_conninfo');
+	'postgresql.auto.conf sets primary_conninfo');
 
 $node->command_ok(
 	[ 'pg_basebackup', '-D', "$tempdir/backupxd" ],
@@ -478,9 +475,9 @@ $node->command_ok(
 	],
 	'pg_basebackup with replication slot and -R runs');
 like(
-	slurp_file("$tempdir/backupxs_sl_R/recovery.conf"),
+	slurp_file("$tempdir/backupxs_sl_R/postgresql.auto.conf"),
 	qr/^primary_slot_name = 'slot1'\n/m,
-	'recovery.conf sets primary_slot_name');
+	'recovery conf file sets primary_slot_name');
 
 my $checksum = $node->safe_psql('postgres', 'SHOW data_checksums;');
 is($checksum, 'on', 'checksums are enabled');
diff --git a/src/bin/pg_ctl/pg_ctl.c b/src/bin/pg_ctl/pg_ctl.c
index 1d0b056..adc04cc 100644
--- a/src/bin/pg_ctl/pg_ctl.c
+++ b/src/bin/pg_ctl/pg_ctl.c
@@ -1115,7 +1115,7 @@ do_promote(void)
 	 * checkpoint is still possible by writing a file called
 	 * "fallback_promote" instead of "promote"
 	 */
-	snprintf(promote_file, MAXPGPATH, "%s/promote", pg_data);
+	snprintf(promote_file, MAXPGPATH, "%s/promote.signal", pg_data);
 
 	if ((prmfile = fopen(promote_file, "w")) == NULL)
 	{
diff --git a/src/bin/pg_rewind/RewindTest.pm b/src/bin/pg_rewind/RewindTest.pm
index 1dce56d..6279872 100644
--- a/src/bin/pg_rewind/RewindTest.pm
+++ b/src/bin/pg_rewind/RewindTest.pm
@@ -159,12 +159,13 @@ sub create_standby
 	my $connstr_master = $node_master->connstr();
 
 	$node_standby->append_conf(
-		"recovery.conf", qq(
+		"postgresql.conf", qq(
 primary_conninfo='$connstr_master application_name=rewind_standby'
-standby_mode=on
 recovery_target_timeline='latest'
 ));
 
+	$node_standby->request_standby_mode();
+
 	# Start standby
 	$node_standby->start;
 
@@ -270,12 +271,13 @@ sub run_pg_rewind
 	# Plug-in rewound node to the now-promoted standby node
 	my $port_standby = $node_standby->port;
 	$node_master->append_conf(
-		'recovery.conf', qq(
+		'postgresql.conf', qq(
 primary_conninfo='port=$port_standby'
-standby_mode=on
 recovery_target_timeline='latest'
 ));
 
+	$node_master->request_standby_mode();
+
 	# Restart the master to check that rewind went correctly
 	$node_master->start;
 
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index e01d12e..6eaf21c 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -87,6 +87,33 @@ typedef enum
 	RECOVERY_TARGET_IMMEDIATE
 } RecoveryTargetType;
 
+/*
+ * Recovery target action.
+ */
+typedef enum
+{
+	RECOVERY_TARGET_ACTION_PAUSE,
+	RECOVERY_TARGET_ACTION_PROMOTE,
+	RECOVERY_TARGET_ACTION_SHUTDOWN
+} RecoveryTargetAction;
+
+#define RecoveryTargetActionText(t) ( \
+	t == RECOVERY_TARGET_ACTION_PAUSE   ? "pause" : ( \
+	t == RECOVERY_TARGET_ACTION_PROMOTE ? "promote" : ( \
+						"shutdown" )))
+/*
+ * Recovery target TimeLine goal
+ */
+typedef enum
+{
+	RECOVERY_TARGET_TIMELINE_CONTROLFILE,
+	RECOVERY_TARGET_TIMELINE_LATEST,
+	RECOVERY_TARGET_TIMELINE_NUMERIC
+}			RecoveryTargetTimeLineGoal;
+
+/* Max length of named restore points */
+#define MAXRESTOREPOINTNAMELEN 64
+
 extern XLogRecPtr ProcLastRecPtr;
 extern XLogRecPtr XactLastRecEnd;
 extern PGDLLIMPORT XLogRecPtr XactLastCommitEnd;
@@ -112,6 +139,35 @@ extern bool log_checkpoints;
 
 extern int	CheckPointSegments;
 
+/* options previously taken from recovery.conf for archive recovery */
+extern char *recoveryRestoreCommand;
+extern char *recoveryEndCommand;
+extern char *archiveCleanupCommand;
+extern char *recoveryTargetTypeString;
+extern RecoveryTargetType recoveryTarget;
+extern char *recoveryTargetValue;
+extern bool recoveryTargetInclusive;
+extern int	recoveryTargetAction;
+extern TransactionId recoveryTargetXid;
+extern TimestampTz recoveryTargetTime;
+extern char *recoveryTargetName;
+extern XLogRecPtr recoveryTargetLSN;
+extern int	recovery_min_apply_delay;
+
+/* option set locally in Startup process only when signal files exist */
+extern bool StandbyModeRequested;
+extern bool StandbyMode;
+
+/* options for WALreceiver.c */
+extern char *PrimaryConnInfo;
+extern char *PrimarySlotName;
+
+extern char *PromoteTriggerFile;
+
+extern RecoveryTargetTimeLineGoal recoveryTargetTimeLineGoal;
+extern TimeLineID recoveryTargetTLIRequested;
+extern TimeLineID recoveryTargetTLI;
+
 /* Archive modes */
 typedef enum ArchiveMode
 {
@@ -240,6 +296,8 @@ extern const char *xlog_identify(uint8 info);
 
 extern void issue_xlog_fsync(int fd, XLogSegNo segno);
 
+extern void logRecoveryParameters(void);
+extern void validateRecoveryParameters(void);
 extern bool RecoveryInProgress(void);
 extern bool HotStandbyActive(void);
 extern bool HotStandbyActiveInReplay(void);
@@ -327,8 +385,12 @@ extern SessionBackupState get_backup_status(void);
 #define TABLESPACE_MAP			"tablespace_map"
 #define TABLESPACE_MAP_OLD		"tablespace_map.old"
 
+/* files to signal entering to recovery or standby mode */
+#define RECOVERY_SIGNAL_FILE	"recovery.signal"
+#define STANDBY_SIGNAL_FILE		"standby.signal"
+
 /* files to signal promotion to primary */
-#define PROMOTE_SIGNAL_FILE		"promote"
-#define FALLBACK_PROMOTE_SIGNAL_FILE  "fallback_promote"
+#define PROMOTE_SIGNAL_FILE		"promote.signal"
+#define FALLBACK_PROMOTE_SIGNAL_FILE  "fallback_promote.signal"
 
 #endif							/* XLOG_H */
diff --git a/src/include/access/xlog_internal.h b/src/include/access/xlog_internal.h
index 30610b3..fb12a7e 100644
--- a/src/include/access/xlog_internal.h
+++ b/src/include/access/xlog_internal.h
@@ -260,16 +260,6 @@ typedef struct XLogRecData
 } XLogRecData;
 
 /*
- * Recovery target action.
- */
-typedef enum
-{
-	RECOVERY_TARGET_ACTION_PAUSE,
-	RECOVERY_TARGET_ACTION_PROMOTE,
-	RECOVERY_TARGET_ACTION_SHUTDOWN
-} RecoveryTargetAction;
-
-/*
  * Method table for resource managers.
  *
  * This struct must be kept in sync with the PG_RMGR definition in
diff --git a/src/include/utils/guc_tables.h b/src/include/utils/guc_tables.h
index 668d9ef..6f9fdb6 100644
--- a/src/include/utils/guc_tables.h
+++ b/src/include/utils/guc_tables.h
@@ -69,6 +69,8 @@ enum config_group
 	WAL_SETTINGS,
 	WAL_CHECKPOINTS,
 	WAL_ARCHIVING,
+	WAL_ARCHIVE_RECOVERY,
+	WAL_RECOVERY_TARGET,
 	REPLICATION,
 	REPLICATION_SENDING,
 	REPLICATION_MASTER,
diff --git a/src/port/quotes.c b/src/port/quotes.c
index 29770c7..0f9ab68 100644
--- a/src/port/quotes.c
+++ b/src/port/quotes.c
@@ -19,7 +19,7 @@
  * Escape (by doubling) any single quotes or backslashes in given string
  *
  * Note: this is used to process postgresql.conf entries and to quote
- * string literals in pg_basebackup for creating recovery.conf.
+ * string literals in pg_basebackup for creating recovery config.
  * Since postgresql.conf strings are defined to treat backslashes as escapes,
  * we have to double backslashes here.
  *
diff --git a/src/test/perl/PostgresNode.pm b/src/test/perl/PostgresNode.pm
index efdebc3..0450990 100644
--- a/src/test/perl/PostgresNode.pm
+++ b/src/test/perl/PostgresNode.pm
@@ -635,8 +635,6 @@ of a backup previously created on that node with $node->backup.
 
 Does not start the node after initializing it.
 
-A recovery.conf is not created.
-
 Streaming replication can be enabled on this node by passing the keyword
 parameter has_streaming => 1. This is disabled by default.
 
@@ -831,13 +829,14 @@ sub enable_streaming
 	my ($self, $root_node) = @_;
 	my $root_connstr = $root_node->connstr;
 	my $name         = $self->name;
+	my $pgdata  	 = $self->data_dir;
 
 	print "### Enabling streaming replication for node \"$name\"\n";
 	$self->append_conf(
-		'recovery.conf', qq(
+		'postgresql.conf', qq(
 primary_conninfo='$root_connstr application_name=$name'
-standby_mode=on
 ));
+	$self->request_standby_mode();
 	return;
 }
 
@@ -863,10 +862,25 @@ sub enable_restoring
 	  : qq{cp "$path/%f" "%p"};
 
 	$self->append_conf(
-		'recovery.conf', qq(
+		'postgresql.conf', qq(
 restore_command = '$copy_command'
-standby_mode = on
 ));
+	$self->request_standby_mode();
+	return;
+}
+
+# routine to place standby.signal file
+sub request_standby_mode
+{
+	my ($self) = @_;
+	my $signalfile = $self->data_dir . "/standby.signal";
+
+	open my $standbysignal, ">>$signalfile";
+	print $standbysignal "\n# Allow replication (set up by PostgresNode.pm)\n";
+	close $standbysignal;
+
+	chmod($self->group_access() ? 0640 : 0600, $signalfile)
+	  or die("unable to set permissions for $signalfile");
 	return;
 }
 
diff --git a/src/test/recovery/t/001_stream_rep.pl b/src/test/recovery/t/001_stream_rep.pl
index 8dff5fc..beb4555 100644
--- a/src/test/recovery/t/001_stream_rep.pl
+++ b/src/test/recovery/t/001_stream_rep.pl
@@ -131,7 +131,7 @@ is( $node_master->psql(
 		qq[SELECT pg_create_physical_replication_slot('$slotname_1');]),
 	0,
 	'physical slot created on master');
-$node_standby_1->append_conf('recovery.conf',
+$node_standby_1->append_conf('postgresql.conf',
 	"primary_slot_name = $slotname_1");
 $node_standby_1->append_conf('postgresql.conf',
 	"wal_receiver_status_interval = 1");
@@ -142,7 +142,7 @@ is( $node_standby_1->psql(
 		qq[SELECT pg_create_physical_replication_slot('$slotname_2');]),
 	0,
 	'physical slot created on intermediate replica');
-$node_standby_2->append_conf('recovery.conf',
+$node_standby_2->append_conf('postgresql.conf',
 	"primary_slot_name = $slotname_2");
 $node_standby_2->append_conf('postgresql.conf',
 	"wal_receiver_status_interval = 1");
diff --git a/src/test/recovery/t/003_recovery_targets.pl b/src/test/recovery/t/003_recovery_targets.pl
index e867479..f6f2e8b 100644
--- a/src/test/recovery/t/003_recovery_targets.pl
+++ b/src/test/recovery/t/003_recovery_targets.pl
@@ -23,7 +23,7 @@ sub test_recovery_standby
 
 	foreach my $param_item (@$recovery_params)
 	{
-		$node_standby->append_conf('recovery.conf', qq($param_item));
+		$node_standby->append_conf('postgresql.conf', qq($param_item));
 	}
 
 	$node_standby->start;
diff --git a/src/test/recovery/t/004_timeline_switch.pl b/src/test/recovery/t/004_timeline_switch.pl
index a7ccb7b..79cbffb 100644
--- a/src/test/recovery/t/004_timeline_switch.pl
+++ b/src/test/recovery/t/004_timeline_switch.pl
@@ -47,12 +47,10 @@ $node_standby_1->psql('postgres', "SELECT pg_promote(wait_seconds => 300)",
 is($psql_out, 't', "promotion of standby with pg_promote");
 
 # Switch standby 2 to replay from standby 1
-rmtree($node_standby_2->data_dir . '/recovery.conf');
 my $connstr_1 = $node_standby_1->connstr;
 $node_standby_2->append_conf(
-	'recovery.conf', qq(
+	'postgresql.conf', qq(
 primary_conninfo='$connstr_1 application_name=@{[$node_standby_2->name]}'
-standby_mode=on
 recovery_target_timeline='latest'
 ));
 $node_standby_2->restart;
diff --git a/src/test/recovery/t/005_replay_delay.pl b/src/test/recovery/t/005_replay_delay.pl
index 8909c45..6c85c92 100644
--- a/src/test/recovery/t/005_replay_delay.pl
+++ b/src/test/recovery/t/005_replay_delay.pl
@@ -25,7 +25,7 @@ my $delay        = 3;
 $node_standby->init_from_backup($node_master, $backup_name,
 	has_streaming => 1);
 $node_standby->append_conf(
-	'recovery.conf', qq(
+	'postgresql.conf', qq(
 recovery_min_apply_delay = '${delay}s'
 ));
 $node_standby->start;
diff --git a/src/test/recovery/t/009_twophase.pl b/src/test/recovery/t/009_twophase.pl
index 9ea3bd6..dac2d4e 100644
--- a/src/test/recovery/t/009_twophase.pl
+++ b/src/test/recovery/t/009_twophase.pl
@@ -230,7 +230,7 @@ is($psql_rc, '0', "Restore of prepared transaction on promoted standby");
 # restart old master as new standby
 $cur_standby->enable_streaming($cur_master);
 $cur_standby->append_conf(
-	'recovery.conf', qq(
+	'postgresql.conf', qq(
 recovery_target_timeline='latest'
 ));
 $cur_standby->start;
@@ -268,7 +268,7 @@ is($psql_out, '1',
 # restart old master as new standby
 $cur_standby->enable_streaming($cur_master);
 $cur_standby->append_conf(
-	'recovery.conf', qq(
+	'postgresql.conf', qq(
 recovery_target_timeline='latest'
 ));
 $cur_standby->start;
@@ -308,7 +308,7 @@ is($psql_out, '1',
 # restart old master as new standby
 $cur_standby->enable_streaming($cur_master);
 $cur_standby->append_conf(
-	'recovery.conf', qq(
+	'postgresql.conf', qq(
 recovery_target_timeline='latest'
 ));
 $cur_standby->start;
diff --git a/src/test/recovery/t/010_logical_decoding_timelines.pl b/src/test/recovery/t/010_logical_decoding_timelines.pl
index a76eea8..4fbd386 100644
--- a/src/test/recovery/t/010_logical_decoding_timelines.pl
+++ b/src/test/recovery/t/010_logical_decoding_timelines.pl
@@ -76,7 +76,7 @@ $node_replica->init_from_backup(
 	$node_master, $backup_name,
 	has_streaming => 1,
 	has_restoring => 1);
-$node_replica->append_conf('recovery.conf',
+$node_replica->append_conf('postgresql.conf',
 	q[primary_slot_name = 'phys_slot']);
 
 $node_replica->start;
diff --git a/src/test/recovery/t/012_subtransactions.pl b/src/test/recovery/t/012_subtransactions.pl
index efc23d0..e26cc9c 100644
--- a/src/test/recovery/t/012_subtransactions.pl
+++ b/src/test/recovery/t/012_subtransactions.pl
@@ -120,7 +120,7 @@ is($psql_out, '8128', "Visible");
 ($node_master, $node_standby) = ($node_standby, $node_master);
 $node_standby->enable_streaming($node_master);
 $node_standby->append_conf(
-	'recovery.conf', qq(
+	'postgresql.conf', qq(
 recovery_target_timeline='latest'
 ));
 $node_standby->start;
@@ -171,7 +171,7 @@ is($psql_out, '-1', "Not visible");
 ($node_master, $node_standby) = ($node_standby, $node_master);
 $node_standby->enable_streaming($node_master);
 $node_standby->append_conf(
-	'recovery.conf', qq(
+	'postgresql.conf', qq(
 recovery_target_timeline='latest'
 ));
 $node_standby->start;
@@ -212,7 +212,7 @@ is($psql_out, '-1', "Not visible");
 ($node_master, $node_standby) = ($node_standby, $node_master);
 $node_standby->enable_streaming($node_master);
 $node_standby->append_conf(
-	'recovery.conf', qq(
+	'postgresql.conf', qq(
 recovery_target_timeline='latest'
 ));
 $node_standby->start;

Reply via email to