Changing recovery.conf parameters into GUCs

Started by Simon Riggsalmost 13 years ago19 messages
#1Simon Riggs
simon@2ndQuadrant.com
1 attachment(s)

What we want to do is make recovery parameters into GUCs, allowing
them to be reset by SIGHUP and also to allow all users to see the
parameters in use, from any session.

The existing mechanism for recovery is that
1. we put parameters in a file called recovery.conf
2. we use the existence of a recovery.conf file to trigger archive
recovery/replication

I also wish to see backwards compatibility maintained, so am proposing
the following:

a) recovery parameters are made into GUCs (for which we have a patch
from Fujii)
b) all processes automatically read recovery.conf as the last step in
reading configuration files, if it exists, even if data_directory
parameter is in use (attached patch)
c) we trigger archive recovery by the presence of either
recovery.conf or recovery.trigger in the data directory. At the end,
we rename to recovery.done just as we do now. This means that any
parameters put into recovery.conf will not be re-read when we SIGHUP
after end of recovery. Note that recovery.trigger will NOT be read for
parameters and is assumed to be zero-length.
(minor patch required)

This allows these use cases

1. Existing users create $PGDATA/recovery.conf and everything works as
before. No servers crash, because the HA instructions in the wiki
still work. Users can now see the parameters in pg_settings and we can
use SIGHUP without restarting server. Same stuff, new benefits.

2. New users wish to move their existing recovery.conf file to the
config directory. Same file contents, same file name (if desired),
same behaviour, just more convenient location for config management
tools. Recovery is triggered by recovery.trigger in $PGDATA. Trigger
and configuration are now separate, if desired.

3. Split mode. We can put things like trigger_file into the
postgresql.conf directory and also put other parameters (for example
PITR settings) into recovery.conf. Where multiple tools are in use, we
support both APIs.

Specific details...

* primary_conninfo, trigger_file and standby_mode are added to
postgresql.conf.sample
* all ex-recovery.conf parameters are SIGHUP, so no errors if
recovery.conf has changed to .done

If desired, this behaviour could be enabled by a parameter called
recovery_conf_enabled = on (default). When set to off, this would
throw an error if recovery.conf exists. (I don't see a need for this)

The patch to implement this is very small (attached). This works
standalone, but obviously barfs at the actual parameter parsing stage.
Just in case it wasn't clear, this patch is intended to go with the
parts of Fujji's patch that relate to GUC changes.

If we agree, I will merge and re-post before commit.

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

Attachments:

read_recovery.conf_from_data_directory.v1.patchapplication/octet-stream; name=read_recovery.conf_from_data_directory.v1.patchDownload
diff --git a/src/backend/utils/misc/guc-file.l b/src/backend/utils/misc/guc-file.l
index d3565a5..0e15562 100644
--- a/src/backend/utils/misc/guc-file.l
+++ b/src/backend/utils/misc/guc-file.l
@@ -137,7 +137,7 @@ ProcessConfigFile(GucContext context)
 	/* Parse the file into a list of option names and values */
 	head = tail = NULL;
 
-	if (!ParseConfigFile(ConfigFileName, NULL, true, 0, elevel, &head, &tail))
+	if (!ParseConfigFile(ConfigFileName, NULL, true, true, 0, elevel, &head, &tail))
 	{
 		/* Syntax error(s) detected in the file, so bail out */
 		error = true;
@@ -145,6 +145,40 @@ ProcessConfigFile(GucContext context)
 	}
 
 	/*
+	 * If DataDir is now set, search for a recovery.conf file so we can
+	 * read any parameters from that as well. If DataDir isn't set by now,
+	 * we can ignore it, since it will error out at next level up.
+	 *
+	 * This step is the same as saying "include_if_exists recovery.conf"
+	 * as the last line of the postgresql.conf
+	 *
+	 * recovery.conf is renamed to recovery.done at the end of recovery.
+	 * Note that this means the contents of recovery.conf will not be
+	 * reread when we SIGHUP after the end of recovery, so that all
+	 * recovery parameters will end up at their boot values.
+	 *
+	 * Note also that this means that we use the setting of data_directory
+	 * as it exists now for the purposes of reading recovery.conf.
+	 * Some will note that setting data_directory inside recovery.conf
+	 * could change the final value of that. If anybody thinks that is
+	 * even remotely likely, we can put specific trap against that occurring
+	 * easily enough.
+	 */
+#define RECOVERY_COMMAND_FILE "recovery.conf"
+	if (DataDir)
+	{
+		char   RecoveryConfFileName[MAXPGPATH];
+
+		snprintf(RecoveryConfFileName, MAXPGPATH, "%s/%s", DataDir, RECOVERY_COMMAND_FILE);
+		if (!ParseConfigFile(RecoveryConfFileName, NULL, false, false, 0, elevel, &head, &tail))
+		{
+			/* Syntax error(s) detected in the file, so bail out */
+			error = true;
+			goto cleanup_list;
+		}
+	}
+
+	/*
 	 * Mark all extant GUC variables as not present in the config file.
 	 * We need this so that we can tell below which ones have been removed
 	 * from the file since we last processed it.
@@ -404,7 +438,8 @@ AbsoluteConfigLocation(const char *location, const char *calling_file)
  * and absolute-ifying the path name if necessary.
  */
 bool
-ParseConfigFile(const char *config_file, const char *calling_file, bool strict,
+ParseConfigFile(const char *config_file, const char *calling_file,
+				bool strict, bool log,
 				int depth, int elevel,
 				ConfigVariable **head_p,
 				ConfigVariable **tail_p)
@@ -439,7 +474,8 @@ ParseConfigFile(const char *config_file, const char *calling_file, bool strict,
 			return false;
 		}
 
-		ereport(LOG,
+		if (log)
+			ereport(LOG,
 				(errmsg("skipping missing configuration file \"%s\"",
 						config_file)));
 		return OK;
@@ -592,7 +628,7 @@ ParseConfigFp(FILE *fp, const char *config_file, int depth, int elevel,
 			 * An include_if_exists directive isn't a variable and should be
 			 * processed immediately.
 			 */
-			if (!ParseConfigFile(opt_value, config_file, false,
+			if (!ParseConfigFile(opt_value, config_file, false, true,
 								 depth + 1, elevel,
 								 head_p, tail_p))
 				OK = false;
@@ -606,7 +642,7 @@ ParseConfigFp(FILE *fp, const char *config_file, int depth, int elevel,
 			 * An include directive isn't a variable and should be processed
 			 * immediately.
 			 */
-			if (!ParseConfigFile(opt_value, config_file, true,
+			if (!ParseConfigFile(opt_value, config_file, true, true,
 								 depth + 1, elevel,
 								 head_p, tail_p))
 				OK = false;
@@ -614,6 +650,10 @@ ParseConfigFp(FILE *fp, const char *config_file, int depth, int elevel,
 			pfree(opt_name);
 			pfree(opt_value);
 		}
+		else if (guc_name_compare(opt_name, "data_directory") == 0)
+		{
+			SetDataDir(opt_value);
+		}
 		else
 		{
 			/* ordinary variable, append to list */
@@ -779,7 +819,7 @@ ParseConfigDirectory(const char *includedir,
 		qsort(filenames, num_filenames, sizeof(char *), pg_qsort_strcmp);
 		for (i = 0; i < num_filenames; i++)
 		{
-			if (!ParseConfigFile(filenames[i], NULL, true,
+			if (!ParseConfigFile(filenames[i], NULL, true, true,
 								 depth, elevel, head_p, tail_p))
 			{
 				status = false;
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index f9fb264..96f6727 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -4120,6 +4120,13 @@ SelectConfigFiles(const char *userDoption, const char *progname)
 		configdir = make_absolute_path(getenv("PGDATA"));
 
 	/*
+	 * Set our initial value of DataDir from the configdir.
+	 * This may be overidden later if data_directory parameter is set.
+	 */
+	if (configdir)
+		SetDataDir(configdir);
+
+	/*
 	 * Find the configuration file: if config_file was specified on the
 	 * command line, use it, else use configdir/postgresql.conf.  In any case
 	 * ensure the result is an absolute path, so that it will be interpreted
@@ -4165,15 +4172,8 @@ SelectConfigFiles(const char *userDoption, const char *progname)
 	/*
 	 * If the data_directory GUC variable has been set, use that as DataDir;
 	 * otherwise use configdir if set; else punt.
-	 *
-	 * Note: SetDataDir will copy and absolute-ize its argument, so we don't
-	 * have to.
 	 */
-	if (data_directory)
-		SetDataDir(data_directory);
-	else if (configdir)
-		SetDataDir(configdir);
-	else
+	if (!DataDir)
 	{
 		write_stderr("%s does not know where to find the database system data.\n"
 					 "This can be specified as \"data_directory\" in \"%s\", "
diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h
index 42428cb..16130e2 100644
--- a/src/include/utils/guc.h
+++ b/src/include/utils/guc.h
@@ -112,7 +112,7 @@ typedef struct ConfigVariable
 } ConfigVariable;
 
 extern bool ParseConfigFile(const char *config_file, const char *calling_file,
-				bool strict, int depth, int elevel,
+				bool strict, bool log, int depth, int elevel,
 				ConfigVariable **head_p, ConfigVariable **tail_p);
 extern bool ParseConfigFp(FILE *fp, const char *config_file,
 			  int depth, int elevel,
#2Michael Paquier
michael.paquier@gmail.com
In reply to: Simon Riggs (#1)
Re: Changing recovery.conf parameters into GUCs

Hi,

The main argument on which this proposal is based on is to keep
backward-compatibility.
This has been discussed before many times and the position of each people
is well-known,
so I am not going back to that...

So, based on *only* what I see in this thread...

On Fri, Mar 29, 2013 at 12:48 AM, Simon Riggs <simon@2ndquadrant.com> wrote:

What we want to do is make recovery parameters into GUCs, allowing
them to be reset by SIGHUP and also to allow all users to see the
parameters in use, from any session.

The existing mechanism for recovery is that
1. we put parameters in a file called recovery.conf
2. we use the existence of a recovery.conf file to trigger archive
recovery/replication

I also wish to see backwards compatibility maintained, so am proposing
the following:

a) recovery parameters are made into GUCs (for which we have a patch
from Fujii)

b) all processes automatically read recovery.conf as the last step in

reading configuration files, if it exists, even if data_directory
parameter is in use (attached patch)
c) we trigger archive recovery by the presence of either
recovery.conf or recovery.trigger in the data directory. At the end,
we rename to recovery.done just as we do now. This means that any
parameters put into recovery.conf will not be re-read when we SIGHUP
after end of recovery. Note that recovery.trigger will NOT be read for
parameters and is assumed to be zero-length.
(minor patch required)

This allows these use cases

1. Existing users create $PGDATA/recovery.conf and everything works as
before. No servers crash, because the HA instructions in the wiki
still work. Users can now see the parameters in pg_settings and we can
use SIGHUP without restarting server. Same stuff, new benefits.

Forcing hardcoding of "include_if_exists recovery.conf" at the bottom of
postgresql.conf
is not a good thing for the user as it makes postgresql.conf processing
more opaque and
complicates parameter reloading. IMO, simplicity and transparency of
operations are
important when processing parameters.

2. New users wish to move their existing recovery.conf file to the

config directory. Same file contents, same file name (if desired),
same behaviour, just more convenient location for config management
tools. Recovery is triggered by recovery.trigger in $PGDATA. Trigger
and configuration are now separate, if desired.

So, people could be able to also define a recovery.trigger file? What about
the case where both recovery.conf and recovery.trigger are found in the
base folder?
Priority needs to be given to one way of processing or the other. Is it
really our goal
to confuse the user with internal priority mechanisms at least for GUC
handling?

3. Split mode. We can put things like trigger_file into the

postgresql.conf directory and also put other parameters (for example
PITR settings) into recovery.conf. Where multiple tools are in use, we
support both APIs.

Specific details...

* primary_conninfo, trigger_file and standby_mode are added to
postgresql.conf.sample

Not adding all the recovery_target_* parameters would confuse the user.
With this proposal it is actually possible to define a recovery target
inside
postgresql.conf even if the parameter is not plainly written in
postgresql.conf.sample.

* all ex-recovery.conf parameters are SIGHUP, so no errors if
recovery.conf has changed to .done

Drop of recovery.trigger at the same time? And what about the case
where both files are specified, that the server can only remove one of the
trigger files, and is then restarted with only 1 trigger file present?

If desired, this behaviour could be enabled by a parameter called

recovery_conf_enabled = on (default). When set to off, this would
throw an error if recovery.conf exists. (I don't see a need for this)

Me neither, the less GUCs the better.

The patch to implement this is very small (attached). This works
standalone, but obviously barfs at the actual parameter parsing stage.
Just in case it wasn't clear, this patch is intended to go with the
parts of Fujji's patch that relate to GUC changes.

If we agree, I will merge and re-post before commit.

If an agreement is reached based on this proposal, I highly recommend that
you use one of the latest updated version I sent. Fujii's version had some
bugs, one of them being that as standbyModeRequested can be set to true if
specified in postgresql.conf, a portion of the code using in xlog.c can be
triggered even if ArchiveRecoveryRequested is not set to true. I also added
fixes related to documentation.

Comments from others are welcome.
--
Michael

#3Simon Riggs
simon@2ndQuadrant.com
In reply to: Michael Paquier (#2)
Re: Changing recovery.conf parameters into GUCs

On 29 March 2013 01:17, Michael Paquier <michael.paquier@gmail.com> wrote:

The main argument on which this proposal is based on is to keep
backward-compatibility.

The main objective is to get recovery parameters as GUCs, as I said....

On Fri, Mar 29, 2013 at 12:48 AM, Simon Riggs <simon@2ndquadrant.com> wrote:

What we want to do is make recovery parameters into GUCs, allowing
them to be reset by SIGHUP and also to allow all users to see the
parameters in use, from any session.

From the user's perspective, we are making no changes. All recovery
parameters will work exactly the same as they always did, just now we
get to see their values more easily and we can potentially place them
in a different file if we wish. The user will have no idea that we
plan to do some internal refactoring of how we process the parameters.
So IMHO simplicity means continuing to work the way it always did
work. We simply announce "PostgreSQL now supports configuration
directories. All parameters, including recovery parameters, can be
placed in any configuration file, or in $PGDATA/recovery.conf, as
before".

We introduced "pg_ctl promote" with a new API without removing
existing ones, and some people are still in favour of keeping both
APIs. Doing the same thing here makes sense and reduces conceptual
change.

Early discussions had difficulties because of the lack of config
directories, include_if_exists and this patch. We now have the
technical capability to meet every request. Circumstances have changed
and outcomes may change also.

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

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

#4Michael Paquier
michael.paquier@gmail.com
In reply to: Simon Riggs (#3)
Re: Changing recovery.conf parameters into GUCs

On Fri, Mar 29, 2013 at 9:59 PM, Simon Riggs <simon@2ndquadrant.com> wrote:

On 29 March 2013 01:17, Michael Paquier <michael.paquier@gmail.com> wrote:

On Fri, Mar 29, 2013 at 12:48 AM, Simon Riggs <simon@2ndquadrant.com>

wrote:
Early discussions had difficulties because of the lack of config
directories, include_if_exists and this patch. We now have the
technical capability to meet every request. Circumstances have changed
and outcomes may change also.

Thanks for the clarifications. The following questions are still unanswered:
1) If recovery.trigger and recovery.conf are specified. To which one the
priority is given?
2) If both recovery.trigger and recovery.conf are used, let's imagine that
the server removes recovery.trigger but fails in renaming recovery.conf but
a reason or another. Isn't there a risk of inconsistency if both triggering
methods are used at the same time?
3) Forcing a harcode of include_is_exists = 'recovery.conf' at the bottom
of postgresql.conf doesn't look like a hack?
4) Based on your proposal, are all the parameters included in
postgresql.conf.sample or not? Or only primary_conninfo, trigger_file and
standby_mode?
--
Michael

#5Simon Riggs
simon@2ndQuadrant.com
In reply to: Michael Paquier (#4)
Re: Changing recovery.conf parameters into GUCs

On 29 March 2013 13:24, Michael Paquier <michael.paquier@gmail.com> wrote:

On Fri, Mar 29, 2013 at 9:59 PM, Simon Riggs <simon@2ndquadrant.com> wrote:

On 29 March 2013 01:17, Michael Paquier <michael.paquier@gmail.com> wrote:

On Fri, Mar 29, 2013 at 12:48 AM, Simon Riggs <simon@2ndquadrant.com>
wrote:

Early discussions had difficulties because of the lack of config
directories, include_if_exists and this patch. We now have the
technical capability to meet every request. Circumstances have changed
and outcomes may change also.

Thanks for the clarifications. The following questions are still unanswered:

Minor points only. We can implement this differently if you have
alternate proposals.

1) If recovery.trigger and recovery.conf are specified. To which one the
priority is given?

Neither. No priority is required. If either is present we are triggered.

2) If both recovery.trigger and recovery.conf are used, let's imagine that
the server removes recovery.trigger but fails in renaming recovery.conf but
a reason or another. Isn't there a risk of inconsistency if both triggering
methods are used at the same time?

No. If writes to the filesystem fail, you have much bigger problems.

3) Forcing a harcode of include_is_exists = 'recovery.conf' at the bottom of
postgresql.conf doesn't look like a hack?

Well, that's just an emotive term to describe something you don't
like. There are no significant downsides, just a few lines of code,
like we have in many places for various purposes, such as the support
of multiple APIs for triggering standbys.

4) Based on your proposal, are all the parameters included in
postgresql.conf.sample or not? Or only primary_conninfo, trigger_file and
standby_mode?

Other values are specific to particular situations (e.g. PITR) and if
set in the wrong context could easily break replication. We could add
them if people wish it, but it would be commented out with a clear
"don't touch these" message, so it seems more sensible to avoid them
IMHO.

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

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

#6Bruce Momjian
bruce@momjian.us
In reply to: Simon Riggs (#5)
Re: Changing recovery.conf parameters into GUCs

On Fri, Mar 29, 2013 at 01:56:50PM +0000, Simon Riggs wrote:

On 29 March 2013 13:24, Michael Paquier <michael.paquier@gmail.com> wrote:

On Fri, Mar 29, 2013 at 9:59 PM, Simon Riggs <simon@2ndquadrant.com> wrote:

On 29 March 2013 01:17, Michael Paquier <michael.paquier@gmail.com> wrote:

On Fri, Mar 29, 2013 at 12:48 AM, Simon Riggs <simon@2ndquadrant.com>
wrote:

Early discussions had difficulties because of the lack of config
directories, include_if_exists and this patch. We now have the
technical capability to meet every request. Circumstances have changed
and outcomes may change also.

Thanks for the clarifications. The following questions are still unanswered:

Minor points only. We can implement this differently if you have
alternate proposals.

Seems we are doing design on this long after the final 9.3 commit fest
should have closed. I think we need to punt this to 9.4.

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

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

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

#7Simon Riggs
simon@2ndQuadrant.com
In reply to: Michael Paquier (#2)
Re: Changing recovery.conf parameters into GUCs

On 29 March 2013 01:17, Michael Paquier <michael.paquier@gmail.com> wrote:

I highly recommend that
you use one of the latest updated version I sent. Fujii's version had some
bugs, one of them being that as standbyModeRequested can be set to true if
specified in postgresql.conf, a portion of the code using in xlog.c can be
triggered even if ArchiveRecoveryRequested is not set to true. I also added
fixes related to documentation.

Yes, that is what I meant by "Fujii's patch". He would still be
credited first, having done the main part of the work. I'll call it
Michael's updated version to avoid any further confusion.

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

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

#8Josh Berkus
josh@agliodbs.com
In reply to: Simon Riggs (#3)
Re: Changing recovery.conf parameters into GUCs

Simon, All,

The new approach seems fine to me; I haven't looked at the code. If Tom
doesn't feel like it's overly complicated, then this seems like a good
compromise.

The desire to move recovery.conf/trigger to a different directory is
definitely wanted by our Debian contingent. Right now, the fact that
Debian has all .confs in /etc/, but that it doesn't work to relocate
recovery.conf, is a constant source of irritation.

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

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

#9Tom Lane
tgl@sss.pgh.pa.us
In reply to: Josh Berkus (#8)
Re: Changing recovery.conf parameters into GUCs

Josh Berkus <josh@agliodbs.com> writes:

The desire to move recovery.conf/trigger to a different directory is
definitely wanted by our Debian contingent. Right now, the fact that
Debian has all .confs in /etc/, but that it doesn't work to relocate
recovery.conf, is a constant source of irritation.

It seems like this is confusing two different problems.

If we get rid of recovery.conf per se in favor of folding the settings
into GUCs in the regular config file, then the first aspect of the issue
goes away, no? The second aspect is where to put the trigger file, and
I'm not at all convinced that anybody would want the trigger file to be
in the same place they put external config files, mainly because the
trigger has to be in a server-writable directory.

regards, tom lane

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

#10Robert Haas
robertmhaas@gmail.com
In reply to: Simon Riggs (#1)
Re: Changing recovery.conf parameters into GUCs

On Thu, Mar 28, 2013 at 11:48 AM, Simon Riggs <simon@2ndquadrant.com> wrote:

What we want to do is make recovery parameters into GUCs, allowing
them to be reset by SIGHUP and also to allow all users to see the
parameters in use, from any session.

The existing mechanism for recovery is that
1. we put parameters in a file called recovery.conf
2. we use the existence of a recovery.conf file to trigger archive
recovery/replication

I also wish to see backwards compatibility maintained, so am proposing
the following:

a) recovery parameters are made into GUCs (for which we have a patch
from Fujii)
b) all processes automatically read recovery.conf as the last step in
reading configuration files, if it exists, even if data_directory
parameter is in use (attached patch)
c) we trigger archive recovery by the presence of either
recovery.conf or recovery.trigger in the data directory. At the end,
we rename to recovery.done just as we do now. This means that any
parameters put into recovery.conf will not be re-read when we SIGHUP
after end of recovery. Note that recovery.trigger will NOT be read for
parameters and is assumed to be zero-length.
(minor patch required)

I still prefer Greg Smith's proposal.

/messages/by-id/4EE91248.8010505@2ndQuadrant.com

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

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

#11Josh Berkus
josh@agliodbs.com
In reply to: Robert Haas (#10)
Re: Changing recovery.conf parameters into GUCs

Robert, Simon, All,

On 04/01/2013 04:51 AM, Robert Haas wrote:> On Thu, Mar 28, 2013 at
11:48 AM, Simon Riggs <simon@2ndquadrant.com> wrote:

a) recovery parameters are made into GUCs (for which we have a patch
from Fujii)
b) all processes automatically read recovery.conf as the last step in
reading configuration files, if it exists, even if data_directory
parameter is in use (attached patch)
c) we trigger archive recovery by the presence of either
recovery.conf or recovery.trigger in the data directory. At the end,
we rename to recovery.done just as we do now. This means that any
parameters put into recovery.conf will not be re-read when we SIGHUP
after end of recovery. Note that recovery.trigger will NOT be read for
parameters and is assumed to be zero-length.
(minor patch required)

I still prefer Greg Smith's proposal.

/messages/by-id/4EE91248.8010505@2ndQuadrant.com

So, this seems to still be stalled. Is there a way forward on this
which won't cause us to wait *another* version before we have working
replication GUCs?

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

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

#12Michael Paquier
michael.paquier@gmail.com
In reply to: Josh Berkus (#11)
Re: Changing recovery.conf parameters into GUCs

On Sat, Jul 6, 2013 at 3:49 AM, Josh Berkus <josh@agliodbs.com> wrote:

Robert, Simon, All,

On 04/01/2013 04:51 AM, Robert Haas wrote:> On Thu, Mar 28, 2013 at
11:48 AM, Simon Riggs <simon@2ndquadrant.com> wrote:

a) recovery parameters are made into GUCs (for which we have a patch
from Fujii)
b) all processes automatically read recovery.conf as the last step in
reading configuration files, if it exists, even if data_directory
parameter is in use (attached patch)
c) we trigger archive recovery by the presence of either
recovery.conf or recovery.trigger in the data directory. At the end,
we rename to recovery.done just as we do now. This means that any
parameters put into recovery.conf will not be re-read when we SIGHUP
after end of recovery. Note that recovery.trigger will NOT be read for
parameters and is assumed to be zero-length.
(minor patch required)

I still prefer Greg Smith's proposal.

/messages/by-id/4EE91248.8010505@2ndQuadrant.com

So, this seems to still be stalled. Is there a way forward on this
which won't cause us to wait *another* version before we have working
replication GUCs?

Yeah, it would be good to revive this thread now, which is the
beginning of the development cycle. As of now, just to recall
everybody, an agreement on this patch still needs to be found... Simon
is concerned with backward compatibility. Greg presented a nice spec
some time ago (Robert and I liked it) which would break backward
compatibility but allow to begin with a fresh infrastructure.
--
Michael

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

#13Josh Berkus
josh@agliodbs.com
In reply to: Simon Riggs (#1)
Re: Changing recovery.conf parameters into GUCs

On 07/05/2013 10:09 PM, Michael Paquier wrote:

Yeah, it would be good to revive this thread now, which is the
beginning of the development cycle. As of now, just to recall
everybody, an agreement on this patch still needs to be found... Simon
is concerned with backward compatibility. Greg presented a nice spec
some time ago (Robert and I liked it) which would break backward
compatibility but allow to begin with a fresh infrastructure.

As folks know, I favor Smith's approach. However, as far as I can find,
GSmith never posted a patch for his version.

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

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

#14Michael Paquier
michael.paquier@gmail.com
In reply to: Josh Berkus (#13)
Re: Changing recovery.conf parameters into GUCs

On 2013/07/09, at 4:09, Josh Berkus <josh@agliodbs.com> wrote:

On 07/05/2013 10:09 PM, Michael Paquier wrote:

Yeah, it would be good to revive this thread now, which is the
beginning of the development cycle. As of now, just to recall
everybody, an agreement on this patch still needs to be found... Simon
is concerned with backward compatibility. Greg presented a nice spec
some time ago (Robert and I liked it) which would break backward
compatibility but allow to begin with a fresh infrastructure.

As folks know, I favor Smith's approach. However, as far as I can find,
GSmith never posted a patch for his version.

Actually I did.
/messages/by-id/CAB7nPqR+fpopEDMoecK+AfZB5a8kUUvxpU=1a2JiX5d9s=0s6Q@mail.gmail.com
--
Michael
(Sent from my mobile phone)

#15Simon Riggs
simon@2ndQuadrant.com
In reply to: Josh Berkus (#11)
Re: Changing recovery.conf parameters into GUCs

On 5 July 2013 19:49, Josh Berkus <josh@agliodbs.com> wrote:

Robert, Simon, All,

On 04/01/2013 04:51 AM, Robert Haas wrote:> On Thu, Mar 28, 2013 at
11:48 AM, Simon Riggs <simon@2ndquadrant.com> wrote:

a) recovery parameters are made into GUCs (for which we have a patch
from Fujii)
b) all processes automatically read recovery.conf as the last step in
reading configuration files, if it exists, even if data_directory
parameter is in use (attached patch)
c) we trigger archive recovery by the presence of either
recovery.conf or recovery.trigger in the data directory. At the end,
we rename to recovery.done just as we do now. This means that any
parameters put into recovery.conf will not be re-read when we SIGHUP
after end of recovery. Note that recovery.trigger will NOT be read for
parameters and is assumed to be zero-length.
(minor patch required)

I still prefer Greg Smith's proposal.

/messages/by-id/4EE91248.8010505@2ndQuadrant.com

So, this seems to still be stalled. Is there a way forward on this
which won't cause us to wait *another* version before we have working
replication GUCs?

This needs to be broken down rather than just say "I like Greg's
proposal", or I have written a patch. Writing the patch is not the/an
issue.

Greg's points were these (I have numbered them and named/characterised them)

1. MOVE SETTINGS
All settings move into the postgresql.conf.

Comment: AFAIK, all agree this.

2. RELOCATE RECOVERY PARAMETER FILE(s)
As of 9.2, relocating the postgresql.conf means there are no user
writable files needed in the data directory.

Comment: AFAIK, all except Heikki wanted this. He has very strong
objections to my commit that would have allowed relocating
recovery.conf outside of the data directory. By which he means both
the concepts of triggerring replication and of specifying parameters.
Changes in 9.3 specifically write files to the data directory that
expect this.

3. SEPARATE TRIGGER FILE
Creating a standby.enabled file in the directory that houses the
postgresql.conf (same logic as "include" uses to locate things) puts the
system into recovery mode. That feature needs to save some state, and
making those decisions based on existence of a file is already a thing
we do. Rather than emulating the rename to recovery.done that happens
now, the server can just delete it, to keep from incorrectly returning
to a state it's exited. A UI along the lines of the promote one,
allowing "pg_ctl standby", should fall out of here. I think this is
enough that people who just want to use replication features need never
hear about this file at all, at least during the important to simplify
first run through.

Comment: AFAIK, all except Heikki are OK with this.

4. DISALLOW PREVIOUS API
If startup finds a recovery.conf file where it used to live at,
abort--someone is expecting the old behavior. Hint to RTFM or include a
short migration guide right on the spot. That can have a nice section
about how you might use the various postgresql.conf include* features if
they want to continue managing those files separately. Example: rename
it as replication.conf and use include_if_exists if you want to be able
to rename it to recovery.done like before. Or drop it into a conf.d
directory where the rename will make it then skipped.

Comment: I am against this. Tool vendors are not the problem here.
There is no good reason to just break everybody's scripts with no
warning of future deprecataion and an alternate API, especially since
we now allow multiple parameter files.

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

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

#16Josh Berkus
josh@agliodbs.com
In reply to: Simon Riggs (#1)
Re: Changing recovery.conf parameters into GUCs

On 07/08/2013 11:43 PM, Simon Riggs wrote:

This needs to be broken down rather than just say "I like Greg's
proposal", or I have written a patch. Writing the patch is not the/an
issue.

Greg's points were these (I have numbered them and named/characterised them)

Thanks for the nice summary! Makes it easy for the rest of us to address.

1. MOVE SETTINGS
All settings move into the postgresql.conf.

Comment: AFAIK, all agree this.

Good to go then.

2. RELOCATE RECOVERY PARAMETER FILE(s)
As of 9.2, relocating the postgresql.conf means there are no user
writable files needed in the data directory.

Comment: AFAIK, all except Heikki wanted this. He has very strong
objections to my commit that would have allowed relocating
recovery.conf outside of the data directory. By which he means both
the concepts of triggerring replication and of specifying parameters.
Changes in 9.3 specifically write files to the data directory that
expect this.

Yeah, I didn't understand why this was shot down either.

Heikki?

3. SEPARATE TRIGGER FILE
Creating a standby.enabled file in the directory that houses the
postgresql.conf (same logic as "include" uses to locate things) puts the
system into recovery mode. That feature needs to save some state, and
making those decisions based on existence of a file is already a thing
we do. Rather than emulating the rename to recovery.done that happens
now, the server can just delete it, to keep from incorrectly returning
to a state it's exited. A UI along the lines of the promote one,
allowing "pg_ctl standby", should fall out of here. I think this is
enough that people who just want to use replication features need never
hear about this file at all, at least during the important to simplify
first run through.

Comment: AFAIK, all except Heikki are OK with this.

One bit of complexity I'd like to see go away is that we have two
trigger files: one to put a server into replication, and one to promote
it. The promotion trigger file is a legacy of warm standby, I believe.
Maybe, now that we have pg_ctl promote available, we can eliminate the
promotion trigger?

Also, previously, deleting the recovery.conf file did not cause the
server to be promoted AFAIK. Is that something we should change if
we're going to keep a trigger file to start replication?

Also, I'm not keen on the idea that the start-replication trigger file
will still be *required*. I really want to be able to manage my setup
entirely through configuration/pg_ctl directives and not be forced to
use a trigger file.

4. DISALLOW PREVIOUS API
If startup finds a recovery.conf file where it used to live at,
abort--someone is expecting the old behavior. Hint to RTFM or include a
short migration guide right on the spot. That can have a nice section
about how you might use the various postgresql.conf include* features if
they want to continue managing those files separately. Example: rename
it as replication.conf and use include_if_exists if you want to be able
to rename it to recovery.done like before. Or drop it into a conf.d
directory where the rename will make it then skipped.

Comment: I am against this. Tool vendors are not the problem here.
There is no good reason to just break everybody's scripts with no
warning of future deprecataion and an alternate API, especially since
we now allow multiple parameter files.

Well, the issue is not so much the presence of a recovery.conf file full
of config variables ... which as you point out is now effectively
supported ... but the use of that as a trigger file. So I think the
two points you make here are flipped.

Personally, I don't care if we support the old recovery.conf-trigger
behavior as long as I'm not forced to use it. The main objection to
supporting both was code complexity, I believe.

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

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

#17Heikki Linnakangas
hlinnakangas@vmware.com
In reply to: Josh Berkus (#16)
Re: Changing recovery.conf parameters into GUCs

On 10.07.2013 02:54, Josh Berkus wrote:

On 07/08/2013 11:43 PM, Simon Riggs wrote:

1. MOVE SETTINGS
All settings move into the postgresql.conf.

Comment: AFAIK, all agree this.

Good to go then.

+1.

2. RELOCATE RECOVERY PARAMETER FILE(s)
As of 9.2, relocating the postgresql.conf means there are no user
writable files needed in the data directory.

Comment: AFAIK, all except Heikki wanted this. He has very strong
objections to my commit that would have allowed relocating
recovery.conf outside of the data directory. By which he means both
the concepts of triggerring replication and of specifying parameters.
Changes in 9.3 specifically write files to the data directory that
expect this.

Yeah, I didn't understand why this was shot down either.

Heikki?

Does this refer to this:

/messages/by-id/5152F778.2070205@vmware.com

? I listed some objections and suggestions there. Probably the biggest
issue back then, however, was that it was committed so late in the
release cycle. In any case, relocating the config/trigger file has
nothing to do with turning recovery.conf parameters into GUCs, so let's
not confuse this patch with that goal.

3. SEPARATE TRIGGER FILE
Creating a standby.enabled file in the directory that houses the
postgresql.conf (same logic as "include" uses to locate things) puts the
system into recovery mode. That feature needs to save some state, and
making those decisions based on existence of a file is already a thing
we do. Rather than emulating the rename to recovery.done that happens
now, the server can just delete it, to keep from incorrectly returning
to a state it's exited. A UI along the lines of the promote one,
allowing "pg_ctl standby", should fall out of here. I think this is
enough that people who just want to use replication features need never
hear about this file at all, at least during the important to simplify
first run through.

Comment: AFAIK, all except Heikki are OK with this.

Sorry, I don't quite understand what this is about. Can you point me to
the previous discussion on this?

"pg_ctl standby" sounds handy. It's not very useful without something
like pg_rewind or some other mechanism to do a clean failover, though.
Have to make sure that we have enough safeguards in place that you can't
shoot yourself in the foot with that, though; if you turn a master
server into a standby with that, must make sure that you can't corrupt
the database if you point that standby to another standby.

But I don't see how that's related to changing recovery.conf parameters
into gucs.

One bit of complexity I'd like to see go away is that we have two
trigger files: one to put a server into replication, and one to promote
it. The promotion trigger file is a legacy of warm standby, I believe.
Maybe, now that we have pg_ctl promote available, we can eliminate the
promotion trigger?

No, see /messages/by-id/5112A54B.8090500@vmware.com.

Also, previously, deleting the recovery.conf file did not cause the
server to be promoted AFAIK. Is that something we should change if
we're going to keep a trigger file to start replication?

Deleting recovery.conf file (and restarting) takes the server out of
standby mode, but in an unsafe way. Yeah, would be nice to do something
about that.

4. DISALLOW PREVIOUS API
If startup finds a recovery.conf file where it used to live at,
abort--someone is expecting the old behavior. Hint to RTFM or include a
short migration guide right on the spot. That can have a nice section
about how you might use the various postgresql.conf include* features if
they want to continue managing those files separately. Example: rename
it as replication.conf and use include_if_exists if you want to be able
to rename it to recovery.done like before. Or drop it into a conf.d
directory where the rename will make it then skipped.

Comment: I am against this. Tool vendors are not the problem here.
There is no good reason to just break everybody's scripts with no
warning of future deprecataion and an alternate API, especially since
we now allow multiple parameter files.

Well, the issue is not so much the presence of a recovery.conf file full
of config variables ... which as you point out is now effectively
supported ... but the use of that as a trigger file. So I think the
two points you make here are flipped.

Personally, I don't care if we support the old recovery.conf-trigger
behavior as long as I'm not forced to use it. The main objection to
supporting both was code complexity, I believe.

I'm also undecided on this one. If we can figure out a good way forward
that keeps backwards-compatibility, good. But it's not worth very much
to me - if we can get a better interface overall by dropping
backwards-compatibility, then let's drop it.

- Heikki

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

#18Greg Smith
greg@2ndQuadrant.com
In reply to: Heikki Linnakangas (#17)
Re: Changing recovery.conf parameters into GUCs

On 7/10/13 9:39 AM, Heikki Linnakangas wrote:

On 10.07.2013 02:54, Josh Berkus wrote:

One bit of complexity I'd like to see go away is that we have two
trigger files: one to put a server into replication, and one to promote
it. The promotion trigger file is a legacy of warm standby, I believe.
Maybe, now that we have pg_ctl promote available, we can eliminate the
promotion trigger?

No, see /messages/by-id/5112A54B.8090500@vmware.com.

Right, you had some good points in there. STONITH is so hard already,
we need to be careful about eliminating options there.

All the summaries added here have actually managed to revive this one
usefully early in the release cycle! Well done. I just tried to apply
Michael's 20130325_recovery_guc_v3.patch and the bit rot isn't that bad
either. 5 rejection files, nothing big in them.

The only overlap between the recovery.conf GUC work and refactoring the
trigger file is that the trigger file is referenced in there, and we
really need to point it somewhere to be most useful.

Personally, I don't care if we support the old recovery.conf-trigger
behavior as long as I'm not forced to use it.

If you accept Heikki's argument for why the file can't go away
altogether, and it's pretty reasonable, I think two changes reach a
point where everyone can live with this:

-We need a useful default filename for trigger_file to point at.
-"pg_ctl failover" creates that file.

As for the location to default to, the pg_standby docs suggest
/tmp/pgsql.trigger.5432 while the "Binary Replication Tutorial" on the
wiki uses a RedHat directory layout $PGDATA/failover

The main reason I've preferred something in the data directory is that
triggering a standby is too catastrophic for me to be comfortable
putting it in /tmp. Any random hooligan with a shell account can
trigger a standby and break its replication. Putting the unix socket
into /tmp only works because the server creates the file as part of
startup. Here that's not possible, because creating the trigger is the
signalling mechanism.

I don't think there needs to be a CLI interface for putting the
alternate possible text into the trigger--that you can ask for 'fast'
startup. It's nice to have available as an expert, but it's fine for
that to be harder to do.

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

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

#19Michael Paquier
michael.paquier@gmail.com
In reply to: Greg Smith (#18)
1 attachment(s)
Re: Changing recovery.conf parameters into GUCs

On Mon, Jul 15, 2013 at 9:09 AM, Greg Smith <greg@2ndquadrant.com> wrote:

All the summaries added here have actually managed to revive this one
usefully early in the release cycle! Well done. I just tried to apply
Michael's 20130325_recovery_guc_v3.patch and the bit rot isn't that bad
either. 5 rejection files, nothing big in them.

Not sure if it will help, but I have in one of my dev branches a
version of this patch in sync with master branch... Please see
attached... At least it will avoid to have to realign the code of v3.
--
Michael

Attachments:

20130714_recovery_guc_v4.patchapplication/octet-stream; name=20130714_recovery_guc_v4.patchDownload
diff --git a/contrib/pg_archivecleanup/pg_archivecleanup.c b/contrib/pg_archivecleanup/pg_archivecleanup.c
index f12331a..339e805 100644
--- a/contrib/pg_archivecleanup/pg_archivecleanup.c
+++ b/contrib/pg_archivecleanup/pg_archivecleanup.c
@@ -255,7 +255,7 @@ usage(void)
 	printf("  -x EXT         clean up files if they have this extension\n");
 	printf("  -?, --help     show this help, then exit\n");
 	printf("\n"
-		   "For use as archive_cleanup_command in recovery.conf when standby_mode = on:\n"
+		   "For use as archive_cleanup_command in postgresql.conf when standby_mode = on:\n"
 		   "  archive_cleanup_command = 'pg_archivecleanup [OPTION]... ARCHIVELOCATION %%r'\n"
 		   "e.g.\n"
 		   "  archive_cleanup_command = 'pg_archivecleanup /mnt/server/archiverdir %%r'\n");
diff --git a/contrib/pg_standby/pg_standby.c b/contrib/pg_standby/pg_standby.c
index a3f40fb..b3a280e 100644
--- a/contrib/pg_standby/pg_standby.c
+++ b/contrib/pg_standby/pg_standby.c
@@ -531,7 +531,7 @@ usage(void)
 	printf("  -w MAXWAITTIME     max seconds to wait for a file (0=no limit) (default=0)\n");
 	printf("  -?, --help         show this help, then exit\n");
 	printf("\n"
-		   "Main intended use as restore_command in recovery.conf:\n"
+		   "Main intended use as restore_command in postgresql.conf:\n"
 		   "  restore_command = 'pg_standby [OPTION]... ARCHIVELOCATION %%f %%p %%r'\n"
 		   "e.g.\n"
 	"  restore_command = 'pg_standby /mnt/server/archiverdir %%f %%p %%r'\n");
diff --git a/doc/src/sgml/backup.sgml b/doc/src/sgml/backup.sgml
index ccb76d8..7c8219d 100644
--- a/doc/src/sgml/backup.sgml
+++ b/doc/src/sgml/backup.sgml
@@ -1023,10 +1023,17 @@ SELECT pg_stop_backup();
    </listitem>
    <listitem>
     <para>
-     Create a recovery command file <filename>recovery.conf</> in the cluster
-     data directory (see <xref linkend="recovery-config">). You might
-     also want to temporarily modify <filename>pg_hba.conf</> to prevent
-     ordinary users from connecting until you are sure the recovery was successful.
+     Set up recovery parameters in <filename>postgresql.conf</> (see
+     <xref linkend="runtime-config-wal-archive-recovery"> and
+     <xref linkend="runtime-config-wal-recovery-target">).
+    </para>
+   </listitem>
+   <listitem>
+    <para>
+     Create a file called <filename>standby.enabled</> in the cluster data
+     directory. You might also want to temporarily modify <filename>pg_hba.conf</>
+     to prevent ordinary users from connecting until you are sure the recovery
+     was successful.
     </para>
    </listitem>
    <listitem>
@@ -1035,10 +1042,9 @@ SELECT pg_stop_backup();
      proceed to read through the archived WAL files it needs.  Should the
      recovery be terminated because of an external error, the server can
      simply be restarted and it will continue recovery.  Upon completion
-     of the recovery process, the server will rename
-     <filename>recovery.conf</> to <filename>recovery.done</> (to prevent
-     accidentally re-entering recovery mode later) and then
-     commence normal database operations.
+     of the recovery process, the server will delete
+     <filename>standby.enabled</> (to prevent accidentally re-entering
+     recovery mode later) and then commence normal database operations.
     </para>
    </listitem>
    <listitem>
@@ -1052,12 +1058,11 @@ SELECT pg_stop_backup();
    </para>
 
    <para>
-    The key part of all this is to set up a recovery configuration file that
-    describes how you want to recover and how far the recovery should
-    run.  You can use <filename>recovery.conf.sample</> (normally
-    located in the installation's <filename>share/</> directory) as a
-    prototype.  The one thing that you absolutely must specify in
-    <filename>recovery.conf</> is the <varname>restore_command</>,
+    The key part of all this is to set up recovery parameters that
+    specify how you want to recover and how far the recovery should
+    run. The one thing that you absolutely must specify in
+    <filename>postgresql.conf</> to recover from the backup is
+    the <varname>restore_command</>,
     which tells <productname>PostgreSQL</> how to retrieve archived
     WAL file segments.  Like the <varname>archive_command</>, this is
     a shell command string.  It can contain <literal>%f</>, which is
@@ -1111,7 +1116,7 @@ restore_command = 'cp /mnt/server/archivedir/%f %p'
    <para>
     If you want to recover to some previous point in time (say, right before
     the junior DBA dropped your main transaction table), just specify the
-    required stopping point in <filename>recovery.conf</>.  You can specify
+    required stopping point in <filename>postgresql.conf</>.  You can specify
     the stop point, known as the <quote>recovery target</>, either by
     date/time, named restore point or by completion of a specific transaction
     ID.  As of this writing only the date/time and named restore point options
@@ -1208,8 +1213,9 @@ restore_command = 'cp /mnt/server/archivedir/%f %p'
     The default behavior of recovery is to recover along the same timeline
     that was current when the base backup was taken.  If you wish to recover
     into some child timeline (that is, you want to return to some state that
-    was itself generated after a recovery attempt), you need to specify the
-    target timeline ID in <filename>recovery.conf</>.  You cannot recover into
+    was itself generated after a recovery attempt), you need to set
+    <xref linkend="guc-recovery-target-timeline"> to the
+    target timeline ID in <filename>postgresql.conf</>.  You cannot recover into
     timelines that branched off earlier than the base backup.
    </para>
   </sect2>
diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index 23ebc11..a436db5 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -2125,6 +2125,312 @@ include 'filename'
 
      </variablelist>
     </sect2>
+   </sect1>
+
+   <sect1 id="runtime-config-recovery">
+    <title>Recovery</title>
+
+    <sect2 id="runtime-config-wal-archive-recovery">
+     <title>Archive Recovery</title>
+
+     <para>
+      These settings control the behavior of server when put in recovery by
+      creating a recovery trigger file <filename>standby.enabled</> in data
+      folder. Those parameters are not used if server is not in recovery.
+     </para>
+
+     <variablelist>
+      <varlistentry id="guc-restore-command" xreflabel="restore_command">
+       <term><varname>restore_command</varname> (<type>string</type>)</term>
+       <indexterm>
+        <primary><varname>restore_command</> configuration parameter</primary>
+       </indexterm>
+       <listitem>
+        <para>
+         The shell command to execute to retrieve an archived segment of
+         the WAL file series. This parameter is required for archive recovery,
+         but optional for streaming replication.
+         Any <literal>%f</> in the string is
+         replaced by the name of the file to retrieve from the archive,
+         and any <literal>%p</> is replaced by the copy destination path name
+         on the server.
+         (The path name is relative to the current working directory,
+         i.e., the cluster's data directory.)
+         Any <literal>%r</> is replaced by the name of the file containing the
+         last valid restart point. That is the earliest file that must be kept
+         to allow a restore to be restartable, so this information can be used
+         to truncate the archive to just the minimum required to support
+         restarting from the current restore. <literal>%r</> is typically only
+         used by warm-standby configurations
+         (see <xref linkend="warm-standby">).
+         Write <literal>%%</> to embed an actual <literal>%</> character.
+        </para>
+        <para>
+         It is important for the command to return a zero exit status
+         only if it succeeds.  The command <emphasis>will</> be asked for file
+         names that are not present in the archive; it must return nonzero
+         when so asked.  Examples:
+<programlisting>
+restore_command = 'cp /mnt/server/archivedir/%f "%p"'
+restore_command = 'copy "C:\\server\\archivedir\\%f" "%p"'  # Windows
+</programlisting>
+        </para>
+        <para>
+         This parameter can only be set in the <filename>postgresql.conf</>
+         file or on the server command line. It only has effect during archive
+         recovery or in standby mode.
+        </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry id="guc-archive-cleanup-command" xreflabel="archive_cleanup_command">
+       <term><varname>archive_cleanup_command</varname> (<type>string</type>)</term>
+       <indexterm>
+         <primary><varname>archive_cleanup_command</> configuration parameter</primary>
+       </indexterm>
+       <listitem>
+        <para>
+         The shell command that will be executed at every restartpoint.
+         The purpose of <varname>archive_cleanup_command</> is to
+         provide a mechanism for cleaning up old archived WAL files that
+         are no longer needed by the standby server.
+         Any <literal>%r</> is replaced by the name of the file containing the
+         last valid restart point.
+         That is the earliest file that must be <emphasis>kept</> to allow a
+         restore to be restartable, and so all files earlier than <literal>%r</>
+         may be safely removed.
+         This information can be used to truncate the archive to just the
+         minimum required to support restart from the current restore.
+         The <xref linkend="pgarchivecleanup"> module
+         is often used in <varname>archive_cleanup_command</> for
+         single-standby configurations, for example:
+<programlisting>archive_cleanup_command = 'pg_archivecleanup /mnt/server/archivedir %r'</programlisting>
+         Note however that if multiple standby servers are restoring from the
+         same archive directory, you will need to ensure that you do not delete
+         WAL files until they are no longer needed by any of the servers.
+         <varname>archive_cleanup_command</> would typically be used in a
+         warm-standby configuration (see <xref linkend="warm-standby">).
+         Write <literal>%%</> to embed an actual <literal>%</> character in the
+         command.
+        </para>
+        <para>
+         If the command returns a non-zero exit status then a WARNING log
+         message will be written.
+        </para>
+        <para>
+         This parameter can only be set in the <filename>postgresql.conf</>
+         file or on the server command line. It only has effect during archive
+         recovery or in standby mode.
+        </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry id="guc-recovery-end-command" xreflabel="recovery_end_command">
+       <term><varname>recovery_end_command</varname> (<type>string</type>)</term>
+       <indexterm>
+         <primary><varname>recovery_end_command</> configuration parameter</primary>
+       </indexterm>
+       <listitem>
+        <para>
+         The shell command that will be executed once only
+         at the end of recovery. This parameter is optional. The purpose of the
+         <varname>recovery_end_command</> is to provide a mechanism for cleanup
+         following replication or recovery.
+         Any <literal>%r</> is replaced by the name of the file containing the
+         last valid restart point, like in <varname>archive_cleanup_command</>.
+        </para>
+        <para>
+         If the command returns a non-zero exit status then a WARNING log
+         message will be written and the database will proceed to start up
+         anyway.  An exception is that if the command was terminated by a
+         signal, the database will not proceed with startup.
+        </para>
+        <para>
+         This parameter can only be set in the <filename>postgresql.conf</>
+         file or on the server command line. It only has effect during archive
+         recovery or in standby mode.
+        </para>
+       </listitem>
+      </varlistentry>
+     </variablelist>
+    </sect2>
+
+    <sect2 id="runtime-config-wal-recovery-target">
+     <title>Recovery Target</title>
+
+     <variablelist>
+      <varlistentry id="guc-recovery-target-name" xreflabel="recovery_target_name">
+       <term><varname>recovery_target_name</varname> (<type>string</type>)</term>
+       <indexterm>
+        <primary><varname>recovery_target_name</> configuration parameter</primary>
+       </indexterm>
+       <listitem>
+        <para>
+         Specifies the named restore point, created with
+         <function>pg_create_restore_point()</> to which recovery will proceed.
+         At most one of <varname>recovery_target_name</>,
+         <varname>recovery_target_time</> or
+         <varname>recovery_target_xid</> can be specified.  The default
+         value is an empty string, which will recover to the end of the WAL log.
+        </para>
+        <para>
+         This parameter can only be set in the <filename>postgresql.conf</>
+         file or on the server command line. It only has effect during archive
+         recovery or in standby mode.
+        </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry id="guc-recovery-target-time" xreflabel="recovery_target_time">
+       <term><varname>recovery_target_time</varname> (<type>string</type>)</term>
+       <indexterm>
+        <primary><varname>recovery_target_time</> configuration parameter</primary>
+       </indexterm>
+       <listitem>
+        <para>
+         Specifies the time stamp up to which recovery will proceed.
+         This parameter must be specified in the date/time format
+         (see <xref linkend="datatype-datetime-input"> for details).
+         At most one of <varname>recovery_target_time</>,
+         <varname>recovery_target_name</> or
+         <varname>recovery_target_xid</> can be specified.
+         The default value is an empty string, which will recover to
+         the end of the WAL log. The precise stopping point is also
+         influenced by <varname>recovery_target_inclusive</>.
+        </para>
+        <para>
+         This parameter can only be set in the <filename>postgresql.conf</>
+         file or on the server command line. It only has effect during archive
+         recovery or in standby mode.
+        </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry id="guc-recovery-target-xid" xreflabel="recovery_target_xid">
+       <term><varname>recovery_target_xid</varname> (<type>string</type>)</term>
+       <indexterm>
+        <primary><varname>recovery_target_xid</> configuration parameter</primary>
+       </indexterm>
+       <listitem>
+        <para>
+         Specifies the transaction ID up to which recovery will proceed.
+         Keep in mind that while transaction IDs are assigned sequentially
+         at transaction start, transactions can complete in a different
+         numeric order. The transactions that will be recovered are
+         those that committed before (and optionally including)
+         the specified one. At most one of <varname>recovery_target_xid</>,
+         <varname>recovery_target_name</> or
+         <varname>recovery_target_time</> can be specified.
+         The default value is an empty string, which will recover to the end of
+         the WAL log. The precise stopping point is also influenced by
+         <varname>recovery_target_inclusive</>.
+        </para>
+        <para>
+         This parameter can only be set in the <filename>postgresql.conf</>
+         file or on the server command line. It only has effect during archive
+         recovery or in standby mode.
+        </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry id="guc-recovery-target-inclusive" xreflabel="recovery_target_inclusive">
+       <term><varname>recovery_target_inclusive</varname> (<type>boolean</type>)</term>
+       <indexterm>
+        <primary><varname>recovery_target_inclusive</> configuration parameter</primary>
+       </indexterm>
+       <listitem>
+        <para>
+         Specifies whether we stop just after the specified recovery target
+         (<literal>on</>), or just before the recovery target (<literal>off</>).
+         Applies to both <varname>recovery_target_time</>
+         and <varname>recovery_target_xid</>, whichever one is
+         specified for this recovery.  This indicates whether transactions
+         having exactly the target commit time or ID, respectively, will
+         be included in the recovery.  Default is <literal>on</>.
+        </para>
+        <para>
+         This parameter can only be set in the <filename>postgresql.conf</>
+         file or on the server command line. It only has effect during archive
+         recovery or in standby mode.
+        </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry id="guc-recovery-target-timeline" xreflabel="recovery_target_timeline">
+       <term><varname>recovery_target_timeline</varname> (<type>string</type>)</term>
+       <indexterm>
+        <primary><varname>recovery_target_timeline</> configuration parameter</primary>
+       </indexterm>
+       <listitem>
+        <para>
+         Specifies recovering into a particular timeline.  The default value is
+         an empty string, which will recover along the same timeline that was
+         current when the base backup was taken. Setting this to
+         <literal>latest</> recovers to the latest timeline found in the archive,
+         which is useful in a standby server. Other than that you only need to
+         set this parameter in complex re-recovery situations, where you need
+         to return to a state that itself was reached after a point-in-time
+         recovery. See <xref linkend="backup-timelines"> for discussion.
+        </para>
+        <para>
+         This parameter can only be set at server start. It only has effect
+         during archive recovery or in standby mode.
+        </para>
+       </listitem>
+      </varlistentry>
+
+      <varlistentry id="guc-pause-at-recovery-target" xreflabel="pause_at_recovery_target">
+       <term><varname>pause_at_recovery_target</varname> (<type>boolean</type>)</term>
+       <indexterm>
+        <primary><varname>pause_at_recovery_target</> configuration parameter</primary>
+       </indexterm>
+       <listitem>
+        <para>
+         Specifies whether recovery should pause when the recovery target
+         is reached. The default is <literal>on</>.
+         This is intended to allow queries to be executed against the
+         database to check if this recovery target is the most desirable
+         point for recovery. The paused state can be resumed by using
+         <function>pg_xlog_replay_resume()</> (See
+         <xref linkend="functions-recovery-control-table">), which then
+         causes recovery to end. If this recovery target is not the
+         desired stopping point, then shutdown the server, change the
+         recovery target settings to a later target and restart to
+         continue recovery.
+        </para>
+        <para>
+         This parameter can only be set in the <filename>postgresql.conf</>
+         file or on the server command line. It only has effect during archive
+         recovery or in standby mode if recovery target is set.
+        </para>
+       </listitem>
+      </varlistentry>
+     </variablelist>
+     </sect2>
+
+    <sect2 id="runtime-config-">
+     <title>Migration from recovery.conf</title>
+
+     <para>
+      Prior <productname>PostgreSQL</> 9.2, all the recovery parameters had
+      to be specified in a configuration file called <filename>recovery.conf</>
+      located at the root of data folder of server. Servers running
+      <productname>PostgreSQL</> 9.3 and above return an error if
+      <filename>recovery.conf</> is found in data folder.
+     </para>
+
+     <para>
+      <filename>postgresql.conf</> provides two parameters allowing the
+      inclusion of external configuration files by either setting
+      <literal>include_if_exists</> to include a given file or <literal>include_dir</>
+      to include a directory containing a set of files configuration files.
+      In order to migrate an existing <filename>recovery.conf</> used with
+      a server whose version is lower than 9.2, set one of those parameters to
+      include it correctly. It is also necessary to rename <filename>recovery.conf</>
+      to a new name if the file included is located at root of data folder.
+     </para>
+
+    </sect2>
 
    </sect1>
 
@@ -2345,6 +2651,93 @@ include 'filename'
 
     <variablelist>
 
+     <varlistentry id="guc-standby-mode" xreflabel="standby_mode">
+      <term><varname>standby_mode</varname> (<type>boolean</type>)</term>
+      <indexterm>
+       <primary><varname>standby_mode</> configuration parameter</primary>
+      </indexterm>
+      <listitem>
+       <para>
+        Specifies whether to start the <productname>PostgreSQL</> server as
+        a standby when the file called <filename>standby.enabled</> exists.
+        The default value is <literal>off</>.
+        If this parameter is <literal>on</>, the server will not
+        stop recovery when the end of archived WAL is reached,
+        but will keep trying to continue recovery by fetching new WAL segments
+        using <varname>restore_command</> and/or by connecting to
+        the primary server as specified by the <varname>primary_conninfo</>
+        setting.
+       </para>
+       <para>
+        This parameter can only be set at server start. It only has effect
+        if file <filename>standby.enabled</> exists.
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry id="guc-primary-conninfo" xreflabel="primary_conninfo">
+      <term><varname>primary_conninfo</varname> (<type>string</type>)</term>
+      <indexterm>
+        <primary><varname>primary_conninfo</> configuration parameter</primary>
+      </indexterm>
+      <listitem>
+       <para>
+        Specifies a connection string to be used for the standby server
+        to connect with the primary. This string is in the format
+        accepted by the libpq <function>PQconnectdb</function> function,
+        described in <xref linkend="libpq-connect">. If any option is
+        unspecified in this string, then the corresponding environment
+        variable (see <xref linkend="libpq-envars">) is checked. If the
+        environment variable is not set either, then defaults are used.
+        If this parameter is an empty string (the default), no attempt is
+        made to connect to the master.
+       </para>
+       <para>
+        The connection string should specify the host name (or address)
+        of the primary server, as well as the port number if it is not
+        the same as the standby server's default.
+        Also specify a user name corresponding to a role that has the
+        <literal>REPLICATION</> and <literal>LOGIN</> privileges on the
+        primary (see
+        <xref linkend="streaming-replication-authentication">).
+        A password needs to be provided too, if the primary demands password
+        authentication.  It can be provided in the
+        <varname>primary_conninfo</varname> string, or in a separate
+        <filename>~/.pgpass</> file on the standby server (use
+        <literal>replication</> as the database name).
+        Do not specify a database name in the
+        <varname>primary_conninfo</varname> string.
+       </para>
+       <para>
+        This parameter can only be set in the <filename>postgresql.conf</>
+        file or on the server command line. It only has effect in standby mode.
+       </para>
+       <para>
+        If this parameter is changed while replication is in progress,
+        the standby terminates replication, and then tries to restart
+        replication with new setting.
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry id="guc-trigger-file" xreflabel="trigger_file">
+      <term><varname>trigger_file</varname> (<type>string</type>)</term>
+      <indexterm>
+        <primary><varname>trigger_file</> configuration parameter</primary>
+      </indexterm>
+      <listitem>
+       <para>
+        Specifies a trigger file whose presence ends recovery in the
+        standby.  Even if this value is not set, you can still promote
+        the standby using <command>pg_ctl promote</>.
+       </para>
+       <para>
+        This parameter can only be set in the <filename>postgresql.conf</>
+        file or on the server command line. It only has effect in standby mode.
+       </para>
+      </listitem>
+    </varlistentry>
+
      <varlistentry id="guc-hot-standby" xreflabel="hot_standby">
       <term><varname>hot_standby</varname> (<type>boolean</type>)</term>
       <indexterm>
diff --git a/doc/src/sgml/filelist.sgml b/doc/src/sgml/filelist.sgml
index 914090d..7248570 100644
--- a/doc/src/sgml/filelist.sgml
+++ b/doc/src/sgml/filelist.sgml
@@ -43,7 +43,6 @@
 <!ENTITY manage-ag     SYSTEM "manage-ag.sgml">
 <!ENTITY monitoring    SYSTEM "monitoring.sgml">
 <!ENTITY regress       SYSTEM "regress.sgml">
-<!ENTITY recovery-config SYSTEM "recovery-config.sgml">
 <!ENTITY runtime       SYSTEM "runtime.sgml">
 <!ENTITY config        SYSTEM "config.sgml">
 <!ENTITY user-manag    SYSTEM "user-manag.sgml">
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 5765ddf..febc0e5 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -15233,7 +15233,7 @@ postgres=# select pg_start_backup('label_goes_here');
     <function>pg_create_restore_point</> creates a named transaction log
     record that can be used as recovery target, and returns the corresponding
     transaction log location.  The given name can then be used with
-    <xref linkend="recovery-target-name"> to specify the point up to which
+    <xref linkend="guc-recovery-target-name"> to specify the point up to which
     recovery will proceed.  Avoid creating multiple restore points with the
     same name, since recovery will stop at the first one whose name matches
     the recovery target.
diff --git a/doc/src/sgml/high-availability.sgml b/doc/src/sgml/high-availability.sgml
index c8f6fa8..a2993f5 100644
--- a/doc/src/sgml/high-availability.sgml
+++ b/doc/src/sgml/high-availability.sgml
@@ -591,7 +591,7 @@ protocol to make nodes agree on a serializable transactional order.
    <para>
     In standby mode, the server continuously applies WAL received from the
     master server. The standby server can read WAL from a WAL archive
-    (see <xref linkend="restore-command">) or directly from the master
+    (see <xref linkend="guc-restore-command">) or directly from the master
     over a TCP connection (streaming replication). The standby server will
     also attempt to restore any WAL found in the standby cluster's
     <filename>pg_xlog</> directory. That typically happens after a server
@@ -658,8 +658,8 @@ protocol to make nodes agree on a serializable transactional order.
    <para>
     To set up the standby server, restore the base backup taken from primary
     server (see <xref linkend="backup-pitr-recovery">). Create a recovery
-    command file <filename>recovery.conf</> in the standby's cluster data
-    directory, and turn on <varname>standby_mode</>. Set
+    trigger file <filename>standby.enabled</> in the standby's cluster data
+    directory. Turn on <varname>standby_mode</> and set
     <varname>restore_command</> to a simple command to copy files from
     the WAL archive. If you plan to have multiple standby servers for high
     availability purposes, set <varname>recovery_target_timeline</> to
@@ -695,7 +695,7 @@ protocol to make nodes agree on a serializable transactional order.
 
    <para>
     If you're using a WAL archive, its size can be minimized using the <xref
-    linkend="archive-cleanup-command"> parameter to remove files that are no
+    linkend="guc-archive-cleanup-command"> parameter to remove files that are no
     longer required by the standby server.
     The <application>pg_archivecleanup</> utility is designed specifically to
     be used with <varname>archive_cleanup_command</> in typical single-standby
@@ -706,7 +706,7 @@ protocol to make nodes agree on a serializable transactional order.
    </para>
 
    <para>
-    A simple example of a <filename>recovery.conf</> is:
+    A simple example of standby settings is:
 <programlisting>
 standby_mode = 'on'
 primary_conninfo = 'host=192.168.1.50 port=5432 user=foo password=foopass'
@@ -763,8 +763,8 @@ archive_cleanup_command = 'pg_archivecleanup /path/to/archive %r'
     To use streaming replication, set up a file-based log-shipping standby
     server as described in <xref linkend="warm-standby">. The step that
     turns a file-based log-shipping standby into streaming replication
-    standby is setting <varname>primary_conninfo</> setting in the
-    <filename>recovery.conf</> file to point to the primary server. Set
+    standby is setting <varname>primary_conninfo</> to
+    point to the primary server. Set
     <xref linkend="guc-listen-addresses"> and authentication options
     (see <filename>pg_hba.conf</>) on the primary so that the standby server
     can connect to the <literal>replication</> pseudo-database on the primary
@@ -824,15 +824,14 @@ host    replication     foo             192.168.1.100/32        md5
     </para>
     <para>
      The host name and port number of the primary, connection user name,
-     and password are specified in the <filename>recovery.conf</> file.
+     and password are specified in <varname>primary_conninfo</>.
      The password can also be set in the <filename>~/.pgpass</> file on the
      standby (specify <literal>replication</> in the <replaceable>database</>
      field).
      For example, if the primary is running on host IP <literal>192.168.1.50</>,
      port <literal>5432</literal>, the account name for replication is
      <literal>foo</>, and the password is <literal>foopass</>, the administrator
-     can add the following line to the <filename>recovery.conf</> file on the
-     standby:
+     can set <varname>primary_conninfo</> on the standby like this:
 
 <programlisting>
 # The standby connects to the primary that is running on host 192.168.1.50
@@ -1212,8 +1211,8 @@ primary_conninfo = 'host=192.168.1.50 port=5432 user=foo password=foopass'
    <para>
     To trigger failover of a log-shipping standby server,
     run <command>pg_ctl promote</> or create a trigger
-    file with the file name and path specified by the <varname>trigger_file</>
-    setting in <filename>recovery.conf</>. If you're planning to use
+    file with the file name and path specified by the <varname>trigger_file</>.
+    If you're planning to use
     <command>pg_ctl promote</> to fail over, <varname>trigger_file</> is
     not required. If you're setting up the reporting servers that are
     only used to offload read-only queries from the primary, not for high
@@ -1258,8 +1257,7 @@ primary_conninfo = 'host=192.168.1.50 port=5432 user=foo password=foopass'
     The magic that makes the two loosely coupled servers work together is
     simply a <varname>restore_command</> used on the standby that,
     when asked for the next WAL file, waits for it to become available from
-    the primary. The <varname>restore_command</> is specified in the
-    <filename>recovery.conf</> file on the standby server. Normal recovery
+    the primary. Normal recovery
     processing would request a file from the WAL archive, reporting failure
     if the file was unavailable.  For standby processing it is normal for
     the next WAL file to be unavailable, so the standby must wait for
@@ -1346,8 +1344,14 @@ if (!triggered)
      </listitem>
      <listitem>
       <para>
+       Create a file called <filename>standby.enabled</> in the standby's
+       cluster data directory to trigger the recovery.
+      </para>
+     </listitem>
+     <listitem>
+      <para>
        Begin recovery on the standby server from the local WAL
-       archive, using a <filename>recovery.conf</> that specifies a
+       archive, specifying a
        <varname>restore_command</> that waits as described
        previously (see <xref linkend="backup-pitr-recovery">).
       </para>
@@ -1838,9 +1842,8 @@ if (!triggered)
    <title>Administrator's Overview</title>
 
    <para>
-    If <varname>hot_standby</> is turned <literal>on</> in
-    <filename>postgresql.conf</> and there is a <filename>recovery.conf</>
-    file present, the server will run in Hot Standby mode.
+    If <varname>hot_standby</> is turned <literal>on</> and there is a file
+    <filename>standby.enabled</> present, the server will run in Hot Standby mode.
     However, it may take some time for Hot Standby connections to be allowed,
     because the server will not accept connections until it has completed
     sufficient recovery to provide a consistent state against which queries
diff --git a/doc/src/sgml/pgarchivecleanup.sgml b/doc/src/sgml/pgarchivecleanup.sgml
index 932914b..2984da4 100644
--- a/doc/src/sgml/pgarchivecleanup.sgml
+++ b/doc/src/sgml/pgarchivecleanup.sgml
@@ -38,8 +38,8 @@
 
   <para>
    To configure a standby
-   server to use <application>pg_archivecleanup</>, put this into its
-   <filename>recovery.conf</filename> configuration file:
+   server to use <application>pg_archivecleanup</>, specify
+   <xref linkend="guc-archive-cleanup-command"> like this:
 <programlisting>
 archive_cleanup_command = 'pg_archivecleanup <replaceable>archivelocation</> %r'
 </programlisting>
@@ -47,7 +47,7 @@ archive_cleanup_command = 'pg_archivecleanup <replaceable>archivelocation</> %r'
    files should be removed.
   </para>
   <para>
-   When used within <xref linkend="archive-cleanup-command">, all WAL files
+   When used within <varname>archive_cleanup_command</>, all WAL files
    logically preceding the value of the <literal>%r</> argument will be removed
    from <replaceable>archivelocation</>. This minimizes the number of files
    that need to be retained, while preserving crash-restart capability.  Use of
diff --git a/doc/src/sgml/pgstandby.sgml b/doc/src/sgml/pgstandby.sgml
index ca2b5c0..15097ca 100644
--- a/doc/src/sgml/pgstandby.sgml
+++ b/doc/src/sgml/pgstandby.sgml
@@ -46,8 +46,8 @@
 
   <para>
    To configure a standby
-   server to use <application>pg_standby</>, put this into its
-   <filename>recovery.conf</filename> configuration file:
+   server to use <application>pg_standby</>, specify
+   <xref linkend="guc-restore-command"> like this:
 <programlisting>
 restore_command = 'pg_standby <replaceable>archiveDir</> %f %p %r'
 </programlisting>
diff --git a/doc/src/sgml/postgres.sgml b/doc/src/sgml/postgres.sgml
index 15e4ef6..26e8dc2 100644
--- a/doc/src/sgml/postgres.sgml
+++ b/doc/src/sgml/postgres.sgml
@@ -155,7 +155,6 @@
   &maintenance;
   &backup;
   &high-availability;
-  &recovery-config;
   &monitoring;
   &diskusage;
   &wal;
diff --git a/doc/src/sgml/recovery-config.sgml b/doc/src/sgml/recovery-config.sgml
deleted file mode 100644
index c0c543e..0000000
--- a/doc/src/sgml/recovery-config.sgml
+++ /dev/null
@@ -1,361 +0,0 @@
-<!-- doc/src/sgml/recovery-config.sgml -->
-
-<chapter id="recovery-config">
-  <title>Recovery Configuration</title>
-
-  <indexterm>
-   <primary>configuration</primary>
-   <secondary>of recovery</secondary>
-   <tertiary>of a standby server</tertiary>
-  </indexterm>
-
-   <para>
-    This chapter describes the settings available in the
-    <filename>recovery.conf</><indexterm><primary>recovery.conf</></>
-    file. They apply only for the duration of the
-    recovery.  They must be reset for any subsequent recovery you wish to
-    perform.  They cannot be changed once recovery has begun.
-   </para>
-
-   <para>
-     Settings in <filename>recovery.conf</> are specified in the format
-     <literal>name = 'value'</>. One parameter is specified per line.
-     Hash marks (<literal>#</literal>) designate the rest of the
-     line as a comment.  To embed a single quote in a parameter
-     value, write two quotes (<literal>''</>).
-   </para>
-
-   <para>
-    A sample file, <filename>share/recovery.conf.sample</>,
-    is provided in the installation's <filename>share/</> directory.
-   </para>
-
-  <sect1 id="archive-recovery-settings">
-
-    <title>Archive Recovery Settings</title>
-     <variablelist>
-
-     <varlistentry id="restore-command" xreflabel="restore_command">
-      <term><varname>restore_command</varname> (<type>string</type>)</term>
-      <indexterm>
-        <primary><varname>restore_command</> recovery parameter</primary>
-      </indexterm>
-      <listitem>
-       <para>
-        The shell command to execute to retrieve an archived segment of
-        the WAL file series. This parameter is required for archive recovery,
-        but optional for streaming replication.
-        Any <literal>%f</> in the string is
-        replaced by the name of the file to retrieve from the archive,
-        and any <literal>%p</> is replaced by the copy destination path name
-        on the server.
-        (The path name is relative to the current working directory,
-        i.e., the cluster's data directory.)
-        Any <literal>%r</> is replaced by the name of the file containing the
-        last valid restart point. That is the earliest file that must be kept
-        to allow a restore to be restartable, so this information can be used
-        to truncate the archive to just the minimum required to support
-        restarting from the current restore. <literal>%r</> is typically only
-        used by warm-standby configurations
-        (see <xref linkend="warm-standby">).
-        Write <literal>%%</> to embed an actual <literal>%</> character.
-       </para>
-
-       <para>
-        It is important for the command to return a zero exit status
-        only if it succeeds.  The command <emphasis>will</> be asked for file
-        names that are not present in the archive; it must return nonzero
-        when so asked.  Examples:
-<programlisting>
-restore_command = 'cp /mnt/server/archivedir/%f "%p"'
-restore_command = 'copy "C:\\server\\archivedir\\%f" "%p"'  # Windows
-</programlisting>
-       </para>
-      </listitem>
-     </varlistentry>
-
-     <varlistentry id="archive-cleanup-command" xreflabel="archive_cleanup_command">
-      <term><varname>archive_cleanup_command</varname> (<type>string</type>)</term>
-      <indexterm>
-        <primary><varname>archive_cleanup_command</> recovery parameter</primary>
-      </indexterm>
-      <listitem>
-       <para>
-        This optional parameter specifies a shell command that will be executed
-        at every restartpoint.  The purpose of
-        <varname>archive_cleanup_command</> is to provide a mechanism for
-        cleaning up old archived WAL files that are no longer needed by the
-        standby server.
-        Any <literal>%r</> is replaced by the name of the file containing the
-        last valid restart point.
-        That is the earliest file that must be <emphasis>kept</> to allow a
-        restore to be restartable, and so all files earlier than <literal>%r</>
-        may be safely removed.
-        This information can be used to truncate the archive to just the
-        minimum required to support restart from the current restore.
-        The <xref linkend="pgarchivecleanup"> module
-        is often used in <varname>archive_cleanup_command</> for
-        single-standby configurations, for example:
-<programlisting>archive_cleanup_command = 'pg_archivecleanup /mnt/server/archivedir %r'</programlisting>
-        Note however that if multiple standby servers are restoring from the
-        same archive directory, you will need to ensure that you do not delete
-        WAL files until they are no longer needed by any of the servers.
-        <varname>archive_cleanup_command</> would typically be used in a
-        warm-standby configuration (see <xref linkend="warm-standby">).
-        Write <literal>%%</> to embed an actual <literal>%</> character in the
-        command.
-       </para>
-       <para>
-        If the command returns a non-zero exit status then a WARNING log
-        message will be written.
-       </para>
-      </listitem>
-     </varlistentry>
-
-     <varlistentry id="recovery-end-command" xreflabel="recovery_end_command">
-      <term><varname>recovery_end_command</varname> (<type>string</type>)</term>
-      <indexterm>
-        <primary><varname>recovery_end_command</> recovery parameter</primary>
-      </indexterm>
-      <listitem>
-       <para>
-        This parameter specifies a shell command that will be executed once only
-        at the end of recovery. This parameter is optional. The purpose of the
-        <varname>recovery_end_command</> is to provide a mechanism for cleanup
-        following replication or recovery.
-        Any <literal>%r</> is replaced by the name of the file containing the
-        last valid restart point, like in <xref linkend="archive-cleanup-command">.
-       </para>
-       <para>
-        If the command returns a non-zero exit status then a WARNING log
-        message will be written and the database will proceed to start up
-        anyway.  An exception is that if the command was terminated by a
-        signal, the database will not proceed with startup.
-       </para>
-      </listitem>
-     </varlistentry>
-
-    </variablelist>
-
-  </sect1>
-
-  <sect1 id="recovery-target-settings">
-
-    <title>Recovery Target Settings</title>
-     <variablelist>
-
-     <varlistentry id="recovery-target-name" xreflabel="recovery_target_name">
-      <term><varname>recovery_target_name</varname>
-           (<type>string</type>)
-      </term>
-      <indexterm>
-        <primary><varname>recovery_target_name</> recovery parameter</primary>
-      </indexterm>
-      <listitem>
-       <para>
-        This parameter specifies the named restore point, created with
-        <function>pg_create_restore_point()</> to which recovery will proceed.
-        At most one of <varname>recovery_target_name</>,
-        <xref linkend="recovery-target-time"> or
-        <xref linkend="recovery-target-xid"> can be specified.  The default is to
-        recover to the end of the WAL log.
-       </para>
-      </listitem>
-     </varlistentry>
-
-     <varlistentry id="recovery-target-time" xreflabel="recovery_target_time">
-      <term><varname>recovery_target_time</varname>
-           (<type>timestamp</type>)
-      </term>
-      <indexterm>
-        <primary><varname>recovery_target_time</> recovery parameter</primary>
-      </indexterm>
-      <listitem>
-       <para>
-        This parameter specifies the time stamp up to which recovery
-        will proceed.
-        At most one of <varname>recovery_target_time</>,
-        <xref linkend="recovery-target-name"> or
-        <xref linkend="recovery-target-xid"> can be specified.
-        The default is to recover to the end of the WAL log.
-        The precise stopping point is also influenced by
-        <xref linkend="recovery-target-inclusive">.
-       </para>
-      </listitem>
-     </varlistentry>
-
-     <varlistentry id="recovery-target-xid" xreflabel="recovery_target_xid">
-      <term><varname>recovery_target_xid</varname> (<type>string</type>)</term>
-      <indexterm>
-        <primary><varname>recovery_target_xid</> recovery parameter</primary>
-      </indexterm>
-      <listitem>
-       <para>
-        This parameter specifies the transaction ID up to which recovery
-        will proceed. Keep in mind
-        that while transaction IDs are assigned sequentially at transaction
-        start, transactions can complete in a different numeric order.
-        The transactions that will be recovered are those that committed
-        before (and optionally including) the specified one.
-        At most one of <varname>recovery_target_xid</>,
-        <xref linkend="recovery-target-name"> or
-        <xref linkend="recovery-target-time"> can be specified.
-        The default is to recover to the end of the WAL log.
-        The precise stopping point is also influenced by
-        <xref linkend="recovery-target-inclusive">.
-       </para>
-      </listitem>
-     </varlistentry>
-
-     <varlistentry id="recovery-target-inclusive"
-                   xreflabel="recovery_target_inclusive">
-      <term><varname>recovery_target_inclusive</varname>
-        (<type>boolean</type>)
-      </term>
-      <indexterm>
-        <primary><varname>recovery_target_inclusive</> recovery parameter</primary>
-      </indexterm>
-      <listitem>
-       <para>
-        Specifies whether we stop just after the specified recovery target
-        (<literal>true</literal>), or just before the recovery target
-        (<literal>false</literal>).
-        Applies to both <xref linkend="recovery-target-time">
-        and <xref linkend="recovery-target-xid">, whichever one is
-        specified for this recovery.  This indicates whether transactions
-        having exactly the target commit time or ID, respectively, will
-        be included in the recovery.  Default is <literal>true</>.
-       </para>
-      </listitem>
-     </varlistentry>
-
-     <varlistentry id="recovery-target-timeline"
-                   xreflabel="recovery_target_timeline">
-      <term><varname>recovery_target_timeline</varname>
-        (<type>string</type>)
-      </term>
-      <indexterm>
-        <primary><varname>recovery_target_timeline</> recovery parameter</primary>
-      </indexterm>
-      <listitem>
-       <para>
-        Specifies recovering into a particular timeline.  The default is
-        to recover along the same timeline that was current when the
-        base backup was taken. Setting this to <literal>latest</> recovers
-        to the latest timeline found in the archive, which is useful in
-        a standby server. Other than that you only need to set this parameter
-        in complex re-recovery situations, where you need to return to
-        a state that itself was reached after a point-in-time recovery.
-        See <xref linkend="backup-timelines"> for discussion.
-       </para>
-      </listitem>
-     </varlistentry>
-
-     <varlistentry id="pause-at-recovery-target"
-                   xreflabel="pause_at_recovery_target">
-      <term><varname>pause_at_recovery_target</varname>
-        (<type>boolean</type>)
-      </term>
-      <indexterm>
-        <primary><varname>pause_at_recovery_target</> recovery parameter</primary>
-      </indexterm>
-      <listitem>
-       <para>
-        Specifies whether recovery should pause when the recovery target
-        is reached. The default is true.
-        This is intended to allow queries to be executed against the
-        database to check if this recovery target is the most desirable
-        point for recovery. The paused state can be resumed by using
-        <function>pg_xlog_replay_resume()</> (See
-        <xref linkend="functions-recovery-control-table">), which then
-        causes recovery to end. If this recovery target is not the
-        desired stopping point, then shutdown the server, change the
-        recovery target settings to a later target and restart to
-        continue recovery.
-       </para>
-       <para>
-        This setting has no effect if <xref linkend="guc-hot-standby"> is not
-        enabled, or if no recovery target is set.
-       </para>
-      </listitem>
-     </varlistentry>
-
-     </variablelist>
-   </sect1>
-
-  <sect1 id="standby-settings">
-
-    <title>Standby Server Settings</title>
-     <variablelist>
-
-       <varlistentry id="standby-mode" xreflabel="standby_mode">
-        <term><varname>standby_mode</varname> (<type>boolean</type>)</term>
-        <indexterm>
-          <primary><varname>standby_mode</> recovery parameter</primary>
-        </indexterm>
-        <listitem>
-         <para>
-          Specifies whether to start the <productname>PostgreSQL</> server as
-          a standby. If this parameter is <literal>on</>, the server will
-          not stop recovery when the end of archived WAL is reached, but
-          will keep trying to continue recovery by fetching new WAL segments
-          using <varname>restore_command</>
-          and/or by connecting to the primary server as specified by the
-          <varname>primary_conninfo</> setting.
-         </para>
-        </listitem>
-       </varlistentry>
-       <varlistentry id="primary-conninfo" xreflabel="primary_conninfo">
-        <term><varname>primary_conninfo</varname> (<type>string</type>)</term>
-        <indexterm>
-          <primary><varname>primary_conninfo</> recovery parameter</primary>
-        </indexterm>
-        <listitem>
-         <para>
-          Specifies a connection string to be used for the standby server
-          to connect with the primary. This string is in the format
-          described in <xref linkend="libpq-connstring">. If any option is
-          unspecified in this string, then the corresponding environment
-          variable (see <xref linkend="libpq-envars">) is checked. If the
-          environment variable is not set either, then
-          defaults are used.
-         </para>
-         <para>
-          The connection string should specify the host name (or address)
-          of the primary server, as well as the port number if it is not
-          the same as the standby server's default.
-          Also specify a user name corresponding to a suitably-privileged role
-          on the primary (see
-          <xref linkend="streaming-replication-authentication">).
-          A password needs to be provided too, if the primary demands password
-          authentication.  It can be provided in the
-          <varname>primary_conninfo</varname> string, or in a separate
-          <filename>~/.pgpass</> file on the standby server (use
-          <literal>replication</> as the database name).
-          Do not specify a database name in the
-          <varname>primary_conninfo</varname> string.
-         </para>
-         <para>
-          This setting has no effect if <varname>standby_mode</> is <literal>off</>.
-         </para>
-        </listitem>
-       </varlistentry>
-       <varlistentry id="trigger-file" xreflabel="trigger_file">
-        <term><varname>trigger_file</varname> (<type>string</type>)</term>
-        <indexterm>
-          <primary><varname>trigger_file</> recovery parameter</primary>
-        </indexterm>
-        <listitem>
-         <para>
-          Specifies a trigger file whose presence ends recovery in the
-          standby.  Even if this value is not set, you can still promote
-          the standby using <command>pg_ctl promote</>.
-          This setting has no effect if <varname>standby_mode</> is <literal>off</>.
-         </para>
-        </listitem>
-       </varlistentry>
-
-     </variablelist>
-   </sect1>
-
-</chapter>
diff --git a/doc/src/sgml/ref/pg_basebackup.sgml b/doc/src/sgml/ref/pg_basebackup.sgml
index eb0c1d6..c6e49aa 100644
--- a/doc/src/sgml/ref/pg_basebackup.sgml
+++ b/doc/src/sgml/ref/pg_basebackup.sgml
@@ -190,13 +190,13 @@ PostgreSQL documentation
 
      <varlistentry>
       <term><option>-R</option></term>
-      <term><option>--write-recovery-conf</option></term>
+      <term><option>--write-standby-enable</option></term>
       <listitem>
 
        <para>
-        Write a minimal <filename>recovery.conf</filename> in the output directory (or into
-        the base archive file when using tar format) to ease setting
-        up a standby server.
+        Write a minimal <filename>standby.enabled</filename> in the output
+        directory (or into the base archive file when using tar format)
+        to ease setting up a standby server.
        </para>
 
       </listitem>
diff --git a/doc/src/sgml/release-9.1.sgml b/doc/src/sgml/release-9.1.sgml
index 0af7f38..dae79da 100644
--- a/doc/src/sgml/release-9.1.sgml
+++ b/doc/src/sgml/release-9.1.sgml
@@ -4613,7 +4613,7 @@
       <listitem>
        <para>
         Add <filename>recovery.conf</> setting <link
-        linkend="pause-at-recovery-target"><varname>pause_at_recovery_target</></link>
+        linkend="guc-pause-at-recovery-target"><varname>pause_at_recovery_target</></link>
         to pause recovery at target (Simon Riggs)
        </para>
 
@@ -4633,7 +4633,7 @@
        <para>
         These named restore points can be specified as recovery
         targets using the new <filename>recovery.conf</> setting
-        <link linkend="recovery-target-name"><varname>recovery_target_name</></link>.
+        <link linkend="guc-recovery-target-name"><varname>recovery_target_name</></link>.
        </para>
       </listitem>
 
@@ -4665,8 +4665,7 @@
 
       <listitem>
        <para>
-        Allow <link
-        linkend="recovery-config"><filename>recovery.conf</></link>
+        Allow <filename>recovery.conf</>
         to use the same quoting behavior as <filename>postgresql.conf</>
         (Dimitri Fontaine)
        </para>
diff --git a/doc/src/sgml/release.sgml b/doc/src/sgml/release.sgml
index 0980c6e..ab7f548 100644
--- a/doc/src/sgml/release.sgml
+++ b/doc/src/sgml/release.sgml
@@ -5,8 +5,8 @@ Typical markup:
 
 &<>                             use & escapes
 PostgreSQL                      <productname>
-postgresql.conf, pg_hba.conf,
-        recovery.conf           <filename>
+postgresql.conf, pg_hba.conf
+        standby.enabled         <filename>
 [A-Z][A-Z_ ]+[A-Z_]             <command>, <literal>, <envar>, <acronym>
 [A-Za-z_][A-Za-z0-9_]+()        <function>
 -[-A-Za-z_]+                    <option>
diff --git a/src/backend/Makefile b/src/backend/Makefile
index 318cdbc..58d42c5 100644
--- a/src/backend/Makefile
+++ b/src/backend/Makefile
@@ -225,7 +225,6 @@ endif
 	$(INSTALL_DATA) $(srcdir)/libpq/pg_hba.conf.sample '$(DESTDIR)$(datadir)/pg_hba.conf.sample'
 	$(INSTALL_DATA) $(srcdir)/libpq/pg_ident.conf.sample '$(DESTDIR)$(datadir)/pg_ident.conf.sample'
 	$(INSTALL_DATA) $(srcdir)/utils/misc/postgresql.conf.sample '$(DESTDIR)$(datadir)/postgresql.conf.sample'
-	$(INSTALL_DATA) $(srcdir)/access/transam/recovery.conf.sample '$(DESTDIR)$(datadir)/recovery.conf.sample'
 
 install-bin: postgres $(POSTGRES_IMP) installdirs
 	$(INSTALL_PROGRAM) postgres$(X) '$(DESTDIR)$(bindir)/postgres$(X)'
@@ -282,8 +281,7 @@ endif
 	$(MAKE) -C tsearch uninstall-data
 	rm -f '$(DESTDIR)$(datadir)/pg_hba.conf.sample' \
 	      '$(DESTDIR)$(datadir)/pg_ident.conf.sample' \
-              '$(DESTDIR)$(datadir)/postgresql.conf.sample' \
-	      '$(DESTDIR)$(datadir)/recovery.conf.sample'
+              '$(DESTDIR)$(datadir)/postgresql.conf.sample'
 
 
 ##########################################################################
diff --git a/src/backend/access/transam/recovery.conf.sample b/src/backend/access/transam/recovery.conf.sample
deleted file mode 100644
index 5acfa57..0000000
--- a/src/backend/access/transam/recovery.conf.sample
+++ /dev/null
@@ -1,132 +0,0 @@
-# -------------------------------
-# PostgreSQL recovery config file
-# -------------------------------
-#
-# Edit this file to provide the parameters that PostgreSQL needs to
-# perform an archive recovery of a database, or to act as a replication
-# standby.
-#
-# If "recovery.conf" is present in the PostgreSQL data directory, it is
-# read on postmaster startup.  After successful recovery, it is renamed
-# to "recovery.done" to ensure that we do not accidentally re-enter
-# archive recovery or standby mode.
-#
-# This file consists of lines of the form:
-#
-#   name = value
-#
-# Comments are introduced with '#'.
-#
-# The complete list of option names and allowed values can be found
-# in the PostgreSQL documentation.
-#
-#---------------------------------------------------------------------------
-# ARCHIVE RECOVERY PARAMETERS
-#---------------------------------------------------------------------------
-#
-# restore_command
-#
-# specifies the shell command that is executed to copy log files
-# back from archival storage.  The command string may contain %f,
-# which is replaced by the name of the desired log file, and %p,
-# which is replaced by the absolute path to copy the log file to.
-#
-# This parameter is *required* for an archive recovery, but optional
-# for streaming replication.
-#
-# It is important that the command return nonzero exit status on failure.
-# The command *will* be asked for log files that are not present in the
-# archive; it must return nonzero when so asked.
-#
-# NOTE that the basename of %p will be different from %f; do not
-# expect them to be interchangeable.
-#
-#restore_command = ''		# e.g. 'cp /mnt/server/archivedir/%f %p'
-#
-#
-# archive_cleanup_command
-#
-# specifies an optional shell command to execute at every restartpoint.
-# This can be useful for cleaning up the archive of a standby server.
-#
-#archive_cleanup_command = ''
-#
-# recovery_end_command
-#
-# specifies an optional shell command to execute at completion of recovery.
-# This can be useful for cleaning up after the restore_command.
-#
-#recovery_end_command = ''
-#
-#---------------------------------------------------------------------------
-# RECOVERY TARGET PARAMETERS
-#---------------------------------------------------------------------------
-#
-# By default, recovery will rollforward to the end of the WAL log.
-# If you want to stop rollforward at a specific point, you
-# must set a recovery target.
-#
-# You may set a recovery target either by transactionId, by name,
-# or by timestamp. Recovery may either include or exclude the
-# transaction(s) with the recovery target value (ie, stop either
-# just after or just before the given target, respectively).
-#
-#
-#recovery_target_name = ''	# e.g. 'daily backup 2011-01-26'
-#
-#recovery_target_time = ''	# e.g. '2004-07-14 22:39:00 EST'
-#
-#recovery_target_xid = ''
-#
-#recovery_target_inclusive = true
-#
-#
-# If you want to recover into a timeline other than the "main line" shown in
-# pg_control, specify the timeline number here, or write 'latest' to get
-# the latest branch for which there's a history file.
-#
-#recovery_target_timeline = 'latest'
-#
-#
-# If pause_at_recovery_target is enabled, recovery will pause when
-# the recovery target is reached. The pause state will continue until
-# pg_xlog_replay_resume() is called. This setting has no effect if
-# hot standby is not enabled, or if no recovery target is set.
-#
-#pause_at_recovery_target = true
-#
-#---------------------------------------------------------------------------
-# STANDBY SERVER PARAMETERS
-#---------------------------------------------------------------------------
-#
-# standby_mode
-#
-# When standby_mode is enabled, the PostgreSQL server will work as a
-# standby. It will continuously wait for the additional XLOG records, using
-# restore_command and/or primary_conninfo.
-#
-#standby_mode = off
-#
-# primary_conninfo
-#
-# If set, the PostgreSQL server will try to connect to the primary using this
-# connection string and receive XLOG records continuously.
-#
-#primary_conninfo = ''		# e.g. 'host=localhost port=5432'
-#
-#
-# By default, a standby server keeps restoring XLOG records from the
-# primary indefinitely. If you want to stop the standby mode, finish recovery
-# and open the system in read/write mode, specify path to a trigger file.
-# The server will poll the trigger file path periodically and start as a
-# primary server when it's found.
-#
-#trigger_file = ''
-#
-#---------------------------------------------------------------------------
-# HOT STANDBY PARAMETERS
-#---------------------------------------------------------------------------
-#
-# Hot Standby related parameters are listed in postgresql.conf
-#
-#---------------------------------------------------------------------------
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index c9e3a7a..aed8128 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -64,11 +64,12 @@
 extern uint32 bootstrap_data_checksum_version;
 
 /* File path names (all relative to $PGDATA) */
-#define RECOVERY_COMMAND_FILE	"recovery.conf"
-#define RECOVERY_COMMAND_DONE	"recovery.done"
-#define PROMOTE_SIGNAL_FILE "promote"
+#define RECOVERY_ENABLE_FILE	"standby.enabled"
+#define PROMOTE_SIGNAL_FILE	"promote"
 #define FAST_PROMOTE_SIGNAL_FILE "fast_promote"
 
+/* recovery.conf is not supported anymore */
+#define RECOVERY_COMMAND_FILE	"recovery.conf"
 
 /* User-settable parameters */
 int			CheckPointSegments = 3;
@@ -84,8 +85,25 @@ int			sync_method = DEFAULT_SYNC_METHOD;
 int			wal_level = WAL_LEVEL_MINIMAL;
 int			CommitDelay = 0;	/* precommit delay in microseconds */
 int			CommitSiblings = 5; /* # concurrent xacts needed to sleep */
+char	   *restore_command = NULL;
+char	   *archive_cleanup_command = NULL;
+char	   *recovery_end_command = NULL;
+bool		StandbyModeRequested = false;
+char	   *primary_conninfo = NULL;
+char	   *trigger_file = NULL;
+RecoveryTargetType	recovery_target = RECOVERY_TARGET_UNSET;
+TransactionId		recovery_target_xid = InvalidTransactionId;
+TimestampTz			recovery_target_time = 0;
+char	   *recovery_target_name = NULL;
+bool		recovery_target_inclusive = true;
+bool		pause_at_recovery_target = true;
+char	   *recovery_target_timeline_string = NULL;
+TimeLineID	recovery_target_timeline = 0;
 int			num_xloginsert_slots = 8;
 
+/* are we currently in standby mode? */
+bool StandbyMode = false;
+
 #ifdef WAL_DEBUG
 bool		XLOG_DEBUG = false;
 #endif
@@ -208,25 +226,6 @@ bool		InArchiveRecovery = false;
 /* Was the last xlog file restored from archive, or local? */
 static bool restoredFromArchive = false;
 
-/* options taken from recovery.conf for archive recovery */
-char	   *recoveryRestoreCommand = NULL;
-static char *recoveryEndCommand = NULL;
-static char *archiveCleanupCommand = NULL;
-static RecoveryTargetType recoveryTarget = RECOVERY_TARGET_UNSET;
-static bool recoveryTargetInclusive = true;
-static bool recoveryPauseAtTarget = true;
-static TransactionId recoveryTargetXid;
-static TimestampTz recoveryTargetTime;
-static char *recoveryTargetName;
-
-/* options taken from recovery.conf for XLOG streaming */
-static bool StandbyModeRequested = false;
-static char *PrimaryConnInfo = NULL;
-static char *TriggerFile = NULL;
-
-/* are we currently in standby mode? */
-bool		StandbyMode = false;
-
 /* whether request for fast promotion has been made yet */
 static bool fast_promote = false;
 
@@ -525,12 +524,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.
 	 */
@@ -732,7 +725,7 @@ static bool bgwriterLaunched = false;
 static int	MySlotNo = 0;
 static bool holdingAllSlots = false;
 
-static void readRecoveryCommandFile(void);
+static void CheckRecoveryReadyFile(void);
 static void exitArchiveRecovery(TimeLineID endTLI, XLogSegNo endLogSegNo);
 static bool recoveryStopsHere(XLogRecord *record, bool *includeThis);
 static void recoveryPausesHere(void);
@@ -4467,7 +4460,7 @@ ReadRecord(XLogReaderState *xlogreader, XLogRecPtr RecPtr, int emode,
 				ereport(DEBUG1,
 						(errmsg_internal("reached end of WAL in pg_xlog, entering archive recovery")));
 				InArchiveRecovery = true;
-				if (StandbyModeRequested)
+				if (ArchiveRecoveryRequested && StandbyModeRequested)
 					StandbyMode = true;
 
 				/* initialize minRecoveryPoint to this record */
@@ -5315,212 +5308,47 @@ str_time(pg_time_t tnow)
 }
 
 /*
- * See if there is a recovery command file (recovery.conf), and if so
- * read in parameters for archive recovery and XLOG streaming.
- *
- * The file is parsed using the main configuration parser.
+ * Check to see if there is a recovery trigger file (standby.enabled).
+ * If so, validate recovery parameters and determine recovery target timeline.
  */
 static void
-readRecoveryCommandFile(void)
+CheckRecoveryReadyFile(void)
 {
-	FILE	   *fd;
-	TimeLineID	rtli = 0;
-	bool		rtliGiven = false;
-	ConfigVariable *item,
-			   *head = NULL,
-			   *tail = NULL;
+	FILE *fd;
+
+	/* Check the presence of recovery.conf, it is not supported anymore */
+	if (AllocateFile(RECOVERY_COMMAND_FILE, "r") != NULL)
+		ereport(FATAL,
+				(errmsg("\"%s\" is not supported anymore as a recovery method",
+						RECOVERY_COMMAND_FILE),
+				 errdetail("Refer to appropriate documentation about migration methods")));
 
-	fd = AllocateFile(RECOVERY_COMMAND_FILE, "r");
+	/* Check the presence of file standby.enabled, the file triggering recovery */
+	fd = AllocateFile(RECOVERY_ENABLE_FILE, "r");
 	if (fd == NULL)
 	{
 		if (errno == ENOENT)
 			return;				/* not there, so no archive recovery */
 		ereport(FATAL,
 				(errcode_for_file_access(),
-				 errmsg("could not open recovery command file \"%s\": %m",
-						RECOVERY_COMMAND_FILE)));
-	}
-
-	/*
-	 * Since we're asking ParseConfigFp() to report errors as FATAL, there's
-	 * no need to check the return value.
-	 */
-	(void) ParseConfigFp(fd, RECOVERY_COMMAND_FILE, 0, FATAL, &head, &tail);
-
-	FreeFile(fd);
-
-	for (item = head; item; item = item->next)
-	{
-		if (strcmp(item->name, "restore_command") == 0)
-		{
-			recoveryRestoreCommand = pstrdup(item->value);
-			ereport(DEBUG2,
-					(errmsg_internal("restore_command = '%s'",
-									 recoveryRestoreCommand)));
-		}
-		else if (strcmp(item->name, "recovery_end_command") == 0)
-		{
-			recoveryEndCommand = pstrdup(item->value);
-			ereport(DEBUG2,
-					(errmsg_internal("recovery_end_command = '%s'",
-									 recoveryEndCommand)));
-		}
-		else if (strcmp(item->name, "archive_cleanup_command") == 0)
-		{
-			archiveCleanupCommand = pstrdup(item->value);
-			ereport(DEBUG2,
-					(errmsg_internal("archive_cleanup_command = '%s'",
-									 archiveCleanupCommand)));
-		}
-		else if (strcmp(item->name, "pause_at_recovery_target") == 0)
-		{
-			if (!parse_bool(item->value, &recoveryPauseAtTarget))
-				ereport(ERROR,
-						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-						 errmsg("parameter \"%s\" requires a Boolean value", "pause_at_recovery_target")));
-			ereport(DEBUG2,
-					(errmsg_internal("pause_at_recovery_target = '%s'",
-									 item->value)));
-		}
-		else if (strcmp(item->name, "recovery_target_timeline") == 0)
-		{
-			rtliGiven = true;
-			if (strcmp(item->value, "latest") == 0)
-				rtli = 0;
-			else
-			{
-				errno = 0;
-				rtli = (TimeLineID) strtoul(item->value, NULL, 0);
-				if (errno == EINVAL || errno == ERANGE)
-					ereport(FATAL,
-							(errmsg("recovery_target_timeline is not a valid number: \"%s\"",
-									item->value)));
-			}
-			if (rtli)
-				ereport(DEBUG2,
-				   (errmsg_internal("recovery_target_timeline = %u", rtli)));
-			else
-				ereport(DEBUG2,
-					 (errmsg_internal("recovery_target_timeline = latest")));
-		}
-		else if (strcmp(item->name, "recovery_target_xid") == 0)
-		{
-			errno = 0;
-			recoveryTargetXid = (TransactionId) strtoul(item->value, NULL, 0);
-			if (errno == EINVAL || errno == ERANGE)
-				ereport(FATAL,
-				 (errmsg("recovery_target_xid is not a valid number: \"%s\"",
-						 item->value)));
-			ereport(DEBUG2,
-					(errmsg_internal("recovery_target_xid = %u",
-									 recoveryTargetXid)));
-			recoveryTarget = RECOVERY_TARGET_XID;
-		}
-		else if (strcmp(item->name, "recovery_target_time") == 0)
-		{
-			/*
-			 * if recovery_target_xid or recovery_target_name specified, then
-			 * this overrides recovery_target_time
-			 */
-			if (recoveryTarget == RECOVERY_TARGET_XID ||
-				recoveryTarget == RECOVERY_TARGET_NAME)
-				continue;
-			recoveryTarget = RECOVERY_TARGET_TIME;
-
-			/*
-			 * Convert the time string given by the user to TimestampTz form.
-			 */
-			recoveryTargetTime =
-				DatumGetTimestampTz(DirectFunctionCall3(timestamptz_in,
-												CStringGetDatum(item->value),
-												ObjectIdGetDatum(InvalidOid),
-														Int32GetDatum(-1)));
-			ereport(DEBUG2,
-					(errmsg_internal("recovery_target_time = '%s'",
-								   timestamptz_to_str(recoveryTargetTime))));
-		}
-		else if (strcmp(item->name, "recovery_target_name") == 0)
-		{
-			/*
-			 * if recovery_target_xid specified, then this overrides
-			 * recovery_target_name
-			 */
-			if (recoveryTarget == RECOVERY_TARGET_XID)
-				continue;
-			recoveryTarget = RECOVERY_TARGET_NAME;
-
-			recoveryTargetName = pstrdup(item->value);
-			if (strlen(recoveryTargetName) >= MAXFNAMELEN)
-				ereport(FATAL,
-						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-						 errmsg("recovery_target_name is too long (maximum %d characters)",
-								MAXFNAMELEN - 1)));
-
-			ereport(DEBUG2,
-					(errmsg_internal("recovery_target_name = '%s'",
-									 recoveryTargetName)));
-		}
-		else if (strcmp(item->name, "recovery_target_inclusive") == 0)
-		{
-			/*
-			 * does nothing if a recovery_target is not also set
-			 */
-			if (!parse_bool(item->value, &recoveryTargetInclusive))
-				ereport(ERROR,
-						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-						 errmsg("parameter \"%s\" requires a Boolean value",
-								"recovery_target_inclusive")));
-			ereport(DEBUG2,
-					(errmsg_internal("recovery_target_inclusive = %s",
-									 item->value)));
-		}
-		else if (strcmp(item->name, "standby_mode") == 0)
-		{
-			if (!parse_bool(item->value, &StandbyModeRequested))
-				ereport(ERROR,
-						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-						 errmsg("parameter \"%s\" requires a Boolean value",
-								"standby_mode")));
-			ereport(DEBUG2,
-					(errmsg_internal("standby_mode = '%s'", item->value)));
-		}
-		else if (strcmp(item->name, "primary_conninfo") == 0)
-		{
-			PrimaryConnInfo = pstrdup(item->value);
-			ereport(DEBUG2,
-					(errmsg_internal("primary_conninfo = '%s'",
-									 PrimaryConnInfo)));
-		}
-		else if (strcmp(item->name, "trigger_file") == 0)
-		{
-			TriggerFile = pstrdup(item->value);
-			ereport(DEBUG2,
-					(errmsg_internal("trigger_file = '%s'",
-									 TriggerFile)));
-		}
-		else
-			ereport(FATAL,
-					(errmsg("unrecognized recovery parameter \"%s\"",
-							item->name)));
+				 errmsg("could not open recovery file trigger \"%s\": %m",
+						RECOVERY_ENABLE_FILE)));
 	}
 
-	/*
-	 * Check for compulsory parameters
-	 */
+	/* Check for compulsory parameters */
 	if (StandbyModeRequested)
 	{
-		if (PrimaryConnInfo == NULL && recoveryRestoreCommand == NULL)
+		if (!restore_command[0] && !primary_conninfo[0])
 			ereport(WARNING,
-					(errmsg("recovery command file \"%s\" specified neither primary_conninfo nor restore_command",
-							RECOVERY_COMMAND_FILE),
+					(errmsg("Neither primary_conninfo nor restore_command specified"),
 					 errhint("The database server will regularly poll the pg_xlog subdirectory to check for files placed there.")));
 	}
 	else
 	{
-		if (recoveryRestoreCommand == NULL)
+		if (!restore_command[0])
 			ereport(FATAL,
-					(errmsg("recovery command file \"%s\" must specify restore_command when standby mode is not enabled",
-							RECOVERY_COMMAND_FILE)));
+					(errmsg("restore_command must be specified when "
+							"standby_mode is not enabled")));
 	}
 
 	/* Enable fetching from archive recovery area */
@@ -5532,16 +5360,17 @@ readRecoveryCommandFile(void)
 	 * command and set InArchiveRecovery, because we need to fetch timeline
 	 * history files from the archive.
 	 */
-	if (rtliGiven)
+	if (strcmp(recovery_target_timeline_string, "") != 0)
 	{
-		if (rtli)
+		if (recovery_target_timeline)
 		{
 			/* Timeline 1 does not have a history file, all else should */
-			if (rtli != 1 && !existsTimeLineHistory(rtli))
+			if (recovery_target_timeline != 1 &&
+				!existsTimeLineHistory(recovery_target_timeline))
 				ereport(FATAL,
 						(errmsg("recovery target timeline %u does not exist",
-								rtli)));
-			recoveryTargetTLI = rtli;
+								recovery_target_timeline)));
+			recoveryTargetTLI = recovery_target_timeline;
 			recoveryTargetIsLatest = false;
 		}
 		else
@@ -5551,8 +5380,6 @@ readRecoveryCommandFile(void)
 			recoveryTargetIsLatest = true;
 		}
 	}
-
-	FreeConfigVariables(head);
 }
 
 /*
@@ -5623,15 +5450,13 @@ exitArchiveRecovery(TimeLineID endTLI, XLogSegNo endLogSegNo)
 	unlink(recoveryPath);		/* ignore any error */
 
 	/*
-	 * Rename the config file out of the way, so that we don't accidentally
-	 * re-enter archive recovery mode in a subsequent crash.
+	 * Remove file that triggered the recovery
 	 */
-	unlink(RECOVERY_COMMAND_DONE);
-	if (rename(RECOVERY_COMMAND_FILE, RECOVERY_COMMAND_DONE) != 0)
+	if (unlink(RECOVERY_ENABLE_FILE) != 0)
 		ereport(FATAL,
 				(errcode_for_file_access(),
-				 errmsg("could not rename file \"%s\" to \"%s\": %m",
-						RECOVERY_COMMAND_FILE, RECOVERY_COMMAND_DONE)));
+				 errmsg("could not remove file \"%s\": %m",
+						RECOVERY_ENABLE_FILE)));
 
 	ereport(LOG,
 			(errmsg("archive recovery complete")));
@@ -5694,7 +5519,7 @@ recoveryStopsHere(XLogRecord *record, bool *includeThis)
 		return false;
 
 	/* Do we have a PITR target at all? */
-	if (recoveryTarget == RECOVERY_TARGET_UNSET)
+	if (recovery_target == RECOVERY_TARGET_UNSET)
 	{
 		/*
 		 * Save timestamp of latest transaction commit/abort if this is a
@@ -5705,7 +5530,7 @@ recoveryStopsHere(XLogRecord *record, bool *includeThis)
 		return false;
 	}
 
-	if (recoveryTarget == RECOVERY_TARGET_XID)
+	if (recovery_target == RECOVERY_TARGET_XID)
 	{
 		/*
 		 * There can be only one transaction end record with this exact
@@ -5716,17 +5541,17 @@ recoveryStopsHere(XLogRecord *record, bool *includeThis)
 		 * they complete. A higher numbered xid will complete before you about
 		 * 50% of the time...
 		 */
-		stopsHere = (record->xl_xid == recoveryTargetXid);
+		stopsHere = (record->xl_xid == recovery_target_xid);
 		if (stopsHere)
-			*includeThis = recoveryTargetInclusive;
+			*includeThis = recovery_target_inclusive;
 	}
-	else if (recoveryTarget == RECOVERY_TARGET_NAME)
+	else if (recovery_target == RECOVERY_TARGET_NAME)
 	{
 		/*
 		 * There can be many restore points that share the same name, so we
 		 * stop at the first one
 		 */
-		stopsHere = (strcmp(recordRPName, recoveryTargetName) == 0);
+		stopsHere = (strcmp(recordRPName, recovery_target_name) == 0);
 
 		/*
 		 * Ignore recoveryTargetInclusive because this is not a transaction
@@ -5741,10 +5566,10 @@ recoveryStopsHere(XLogRecord *record, bool *includeThis)
 		 * we stop after the last one, if we are inclusive, or stop at the
 		 * first one if we are exclusive
 		 */
-		if (recoveryTargetInclusive)
-			stopsHere = (recordXtime > recoveryTargetTime);
+		if (recovery_target_inclusive)
+			stopsHere = (recordXtime > recovery_target_time);
 		else
-			stopsHere = (recordXtime >= recoveryTargetTime);
+			stopsHere = (recordXtime >= recovery_target_time);
 		if (stopsHere)
 			*includeThis = false;
 	}
@@ -6111,36 +5936,28 @@ StartupXLOG(void)
 		recoveryTargetTLI = ControlFile->checkPointCopy.ThisTimeLineID;
 
 	/*
-	 * Check for recovery control file, and if so set up state for offline
-	 * recovery
-	 */
-	readRecoveryCommandFile();
-
-	/*
-	 * Save archive_cleanup_command in shared memory so that other processes
-	 * can see it.
+	 * Check for recovery trigger file, and if so set up state for offline
+	 * recovery.
 	 */
-	strncpy(XLogCtl->archiveCleanupCommand,
-			archiveCleanupCommand ? archiveCleanupCommand : "",
-			sizeof(XLogCtl->archiveCleanupCommand));
+	CheckRecoveryReadyFile();
 
 	if (ArchiveRecoveryRequested)
 	{
 		if (StandbyModeRequested)
 			ereport(LOG,
 					(errmsg("entering standby mode")));
-		else if (recoveryTarget == RECOVERY_TARGET_XID)
+		else if (recovery_target == RECOVERY_TARGET_XID)
 			ereport(LOG,
 					(errmsg("starting point-in-time recovery to XID %u",
-							recoveryTargetXid)));
-		else if (recoveryTarget == RECOVERY_TARGET_TIME)
+							recovery_target_xid)));
+		else if (recovery_target == RECOVERY_TARGET_TIME)
 			ereport(LOG,
 					(errmsg("starting point-in-time recovery to %s",
-							timestamptz_to_str(recoveryTargetTime))));
-		else if (recoveryTarget == RECOVERY_TARGET_NAME)
+							timestamptz_to_str(recovery_target_time))));
+		else if (recovery_target == RECOVERY_TARGET_NAME)
 			ereport(LOG,
 					(errmsg("starting point-in-time recovery to \"%s\"",
-							recoveryTargetName)));
+							recovery_target_name)));
 		else
 			ereport(LOG,
 					(errmsg("starting archive recovery")));
@@ -6150,7 +5967,7 @@ StartupXLOG(void)
 	 * Take ownership of the wakeup latch if we're going to sleep during
 	 * recovery.
 	 */
-	if (StandbyModeRequested)
+	if (ArchiveRecoveryRequested && StandbyModeRequested)
 		OwnLatch(&XLogCtl->recoveryWakeupLatch);
 
 	/* Set up XLOG reader facility */
@@ -6172,7 +5989,7 @@ StartupXLOG(void)
 		 * archive recovery directly.
 		 */
 		InArchiveRecovery = true;
-		if (StandbyModeRequested)
+		if (ArchiveRecoveryRequested && StandbyModeRequested)
 			StandbyMode = true;
 
 		/*
@@ -6238,7 +6055,7 @@ StartupXLOG(void)
 			 ControlFile->state == DB_SHUTDOWNED))
 		{
 			InArchiveRecovery = true;
-			if (StandbyModeRequested)
+			if (ArchiveRecoveryRequested && StandbyModeRequested)
 				StandbyMode = true;
 		}
 
@@ -6399,7 +6216,7 @@ StartupXLOG(void)
 
 	/*
 	 * Check whether we need to force recovery from WAL.  If it appears to
-	 * have been a clean shutdown and we did not have a recovery.conf file,
+	 * have been a clean shutdown and we did not have a standby.enabled file,
 	 * then assume no recovery needed.
 	 */
 	if (checkPoint.redo < RecPtr)
@@ -6413,7 +6230,7 @@ StartupXLOG(void)
 		InRecovery = true;
 	else if (ArchiveRecoveryRequested)
 	{
-		/* force recovery due to presence of recovery.conf */
+		/* force recovery due to presence of standby.enabled */
 		InRecovery = true;
 	}
 
@@ -6736,7 +6553,7 @@ StartupXLOG(void)
 				 */
 				if (recoveryStopsHere(record, &recoveryApply))
 				{
-					if (recoveryPauseAtTarget)
+					if (pause_at_recovery_target)
 					{
 						SetRecoveryPause(true);
 						recoveryPausesHere();
@@ -6900,7 +6717,7 @@ StartupXLOG(void)
 	 * We don't need the latch anymore. It's not strictly necessary to disown
 	 * it, but let's do it for the sake of tidiness.
 	 */
-	if (StandbyModeRequested)
+	if (ArchiveRecoveryRequested && StandbyModeRequested)
 		DisownLatch(&XLogCtl->recoveryWakeupLatch);
 
 	/*
@@ -6990,17 +6807,17 @@ StartupXLOG(void)
 		 * Create a comment for the history file to explain why and where
 		 * timeline changed.
 		 */
-		if (recoveryTarget == RECOVERY_TARGET_XID)
+		if (recovery_target == RECOVERY_TARGET_XID)
 			snprintf(reason, sizeof(reason),
 					 "%s transaction %u",
 					 recoveryStopAfter ? "after" : "before",
 					 recoveryStopXid);
-		else if (recoveryTarget == RECOVERY_TARGET_TIME)
+		else if (recovery_target == RECOVERY_TARGET_TIME)
 			snprintf(reason, sizeof(reason),
 					 "%s %s\n",
 					 recoveryStopAfter ? "after" : "before",
 					 timestamptz_to_str(recoveryStopTime));
-		else if (recoveryTarget == RECOVERY_TARGET_NAME)
+		else if (recovery_target == RECOVERY_TARGET_NAME)
 			snprintf(reason, sizeof(reason),
 					 "at restore point \"%s\"",
 					 recoveryStopName);
@@ -7168,8 +6985,8 @@ StartupXLOG(void)
 		/*
 		 * And finally, execute the recovery_end_command, if any.
 		 */
-		if (recoveryEndCommand)
-			ExecuteRecoveryCommand(recoveryEndCommand,
+		if (recovery_end_command[0])
+			ExecuteRecoveryCommand(recovery_end_command,
 								   "recovery_end_command",
 								   true);
 	}
@@ -8712,8 +8529,8 @@ CreateRestartPoint(int flags)
 	/*
 	 * Finally, execute archive_cleanup_command, if any.
 	 */
-	if (XLogCtl->archiveCleanupCommand[0])
-		ExecuteRecoveryCommand(XLogCtl->archiveCleanupCommand,
+	if (archive_cleanup_command[0])
+		ExecuteRecoveryCommand(archive_cleanup_command,
 							   "archive_cleanup_command",
 							   false);
 
@@ -10572,7 +10389,7 @@ XLogPageRead(XLogReaderState *xlogreader, XLogRecPtr targetPagePtr, int reqLen,
 		 * Request a restartpoint if we've replayed too much xlog since the
 		 * last one.
 		 */
-		if (StandbyModeRequested && bgwriterLaunched)
+		if (ArchiveRecoveryRequested && StandbyModeRequested && bgwriterLaunched)
 		{
 			if (XLogCheckpointNeeded(readSegNo))
 			{
@@ -10789,7 +10606,7 @@ WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess,
 					 * that when we later jump backwards to start redo at
 					 * RedoStartLSN, we will have the logs streamed already.
 					 */
-					if (PrimaryConnInfo)
+					if (primary_conninfo[0])
 					{
 						XLogRecPtr	ptr;
 						TimeLineID	tli;
@@ -10810,7 +10627,7 @@ WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess,
 									 tli, curFileTLI);
 						}
 						curFileTLI = tli;
-						RequestXLogStreaming(tli, ptr, PrimaryConnInfo);
+						RequestXLogStreaming(tli, ptr, primary_conninfo);
 						receivedUpto = 0;
 					}
 
@@ -11124,14 +10941,14 @@ CheckForStandbyTrigger(void)
 		return true;
 	}
 
-	if (TriggerFile == NULL)
+	if (!trigger_file[0])
 		return false;
 
-	if (stat(TriggerFile, &stat_buf) == 0)
+	if (stat(trigger_file, &stat_buf) == 0)
 	{
 		ereport(LOG,
-				(errmsg("trigger file found: %s", TriggerFile)));
-		unlink(TriggerFile);
+				(errmsg("trigger file found: %s", trigger_file)));
+		unlink(trigger_file);
 		triggered = true;
 		fast_promote = true;
 		return true;
diff --git a/src/backend/access/transam/xlogarchive.c b/src/backend/access/transam/xlogarchive.c
index 342975c..3a73b69 100644
--- a/src/backend/access/transam/xlogarchive.c
+++ b/src/backend/access/transam/xlogarchive.c
@@ -67,7 +67,7 @@ RestoreArchivedFile(char *path, const char *xlogfname,
 	TimeLineID	restartTli;
 
 	/* In standby mode, restore_command might not be supplied */
-	if (recoveryRestoreCommand == NULL)
+	if (restore_command == NULL)
 		goto not_available;
 
 	/*
@@ -150,7 +150,7 @@ RestoreArchivedFile(char *path, const char *xlogfname,
 	endp = xlogRestoreCmd + MAXPGPATH - 1;
 	*endp = '\0';
 
-	for (sp = recoveryRestoreCommand; *sp; sp++)
+	for (sp = restore_command; *sp; sp++)
 	{
 		if (*sp == '%')
 		{
diff --git a/src/backend/commands/extension.c b/src/backend/commands/extension.c
index 798c92a..29722a5 100644
--- a/src/backend/commands/extension.c
+++ b/src/backend/commands/extension.c
@@ -9,7 +9,7 @@
  * dependent objects can be associated with it.  An extension is created by
  * populating the pg_extension catalog from a "control" file.
  * The extension control file is parsed with the same parser we use for
- * postgresql.conf and recovery.conf.  An extension also has an installation
+ * postgresql.conf.  An extension also has an installation
  * script file, containing SQL commands to create the extension's objects.
  *
  * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 2b753f8..6a72125 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -30,6 +30,7 @@
 #include "access/transam.h"
 #include "access/twophase.h"
 #include "access/xact.h"
+#include "access/xlog_internal.h"
 #include "catalog/namespace.h"
 #include "commands/async.h"
 #include "commands/prepare.h"
@@ -199,6 +200,14 @@ static bool check_application_name(char **newval, void **extra, GucSource source
 static void assign_application_name(const char *newval, void *extra);
 static const char *show_unix_socket_permissions(void);
 static const char *show_log_file_mode(void);
+static bool check_recovery_target_xid(char **newval, void **extra, GucSource source);
+static void assign_recovery_target_xid(const char *newval, void *extra);
+static bool check_recovery_target_name(char **newval, void **extra, GucSource source);
+static void assign_recovery_target_name(const char *newval, void *extra);
+static bool check_recovery_target_time(char **newval, void **extra, GucSource source);
+static void assign_recovery_target_time(const char *newval, void *extra);
+static bool check_recovery_target_timeline(char **newval, void **extra, GucSource source);
+static void assign_recovery_target_timeline(const char *newval, void *extra);
 
 static char *config_enum_get_options(struct config_enum * record,
 						const char *prefix, const char *suffix,
@@ -471,6 +480,8 @@ static int	wal_block_size;
 static int	wal_segment_size;
 static bool integer_datetimes;
 static int	effective_io_concurrency;
+static char *recovery_target_xid_string;
+static char *recovery_target_time_string;
 
 /* should be static, but commands/variable.c needs to get at this */
 char	   *role_string;
@@ -551,6 +562,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 */
@@ -1396,6 +1411,36 @@ static struct config_bool ConfigureNamesBool[] =
 	},
 
 	{
+		{"recovery_target_inclusive", PGC_SIGHUP, WAL_RECOVERY_TARGET,
+			gettext_noop("Sets whether to include or exclude transaction with recovery target."),
+			NULL
+		},
+		&recovery_target_inclusive,
+		true,
+		NULL, NULL, NULL
+	},
+
+	{
+		{"pause_at_recovery_target", PGC_SIGHUP, WAL_RECOVERY_TARGET,
+			gettext_noop("Sets whether recovery should pause when the recovery target is reached."),
+			NULL
+		},
+		&pause_at_recovery_target,
+		true,
+		NULL, NULL, NULL
+	},
+
+	{
+		{"standby_mode", PGC_POSTMASTER, REPLICATION_STANDBY,
+			gettext_noop("Sets whether to start the server as a standby."),
+			NULL
+		},
+		&StandbyModeRequested,
+		false,
+		NULL, NULL, NULL
+	},
+
+	{
 		{"hot_standby", PGC_POSTMASTER, REPLICATION_STANDBY,
 			gettext_noop("Allows connections and queries during recovery."),
 			NULL
@@ -2588,7 +2633,7 @@ static struct config_real ConfigureNamesReal[] =
 static struct config_string ConfigureNamesString[] =
 {
 	{
-		{"archive_command", PGC_SIGHUP, WAL_ARCHIVING,
+		{"archive_command", PGC_POSTMASTER, WAL_ARCHIVING,
 			gettext_noop("Sets the shell command that will be called to archive a WAL file."),
 			NULL
 		},
@@ -2598,6 +2643,97 @@ 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
+		},
+		&restore_command,
+		"",
+		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
+		},
+		&archive_cleanup_command,
+		"",
+		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
+		},
+		&recovery_end_command,
+		"",
+		NULL, NULL, 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_name", PGC_POSTMASTER, WAL_RECOVERY_TARGET,
+			gettext_noop("Sets the named restore point."),
+			NULL
+		},
+		&recovery_target_name,
+		"",
+		check_recovery_target_name, assign_recovery_target_name, NULL
+	},
+
+	{
+		{"recovery_target_time", PGC_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_timeline", PGC_POSTMASTER, WAL_RECOVERY_TARGET,
+			gettext_noop("Sets recoverying into a particular timeline."),
+			NULL
+		},
+		&recovery_target_timeline_string,
+		"",
+		check_recovery_target_timeline, assign_recovery_target_timeline, NULL
+	},
+
+	{
+		{"primary_conninfo", PGC_POSTMASTER, REPLICATION_STANDBY,
+			gettext_noop("Sets the connection string to be used to connect with the primary."),
+			NULL,
+			GUC_SUPERUSER_ONLY
+		},
+		&primary_conninfo,
+		"",
+		NULL, NULL, NULL
+	},
+
+	{
+		{"trigger_file", PGC_POSTMASTER, REPLICATION_STANDBY,
+			gettext_noop("Sets the trigger file whose presence ends recovery in the standby."),
+			NULL
+		},
+		&trigger_file,
+		"",
+		NULL, NULL, NULL
+	},
+
+	{
 		{"client_encoding", PGC_USERSET, CLIENT_CONN_LOCALE,
 			gettext_noop("Sets the client's character set encoding."),
 			NULL,
@@ -8863,4 +8999,158 @@ show_log_file_mode(void)
 	return buf;
 }
 
+static bool
+check_recovery_target_xid(char **newval, void **extra, GucSource source)
+{
+	TransactionId   xid;
+	TransactionId   *myextra;
+
+	if (strcmp(*newval, "") == 0)
+		xid = InvalidTransactionId;
+	else
+	{
+		errno = 0;
+		xid = (TransactionId) strtoul(*newval, NULL, 0);
+		if (errno == EINVAL || errno == ERANGE)
+		{
+			GUC_check_errdetail("recovery_target_xid is not a valid number: \"%s\"",
+								*newval);
+			return false;
+		}
+	}
+
+	myextra = (TransactionId *) guc_malloc(ERROR, sizeof(TransactionId));
+	*myextra = xid;
+	*extra = (void *) myextra;
+
+	return true;
+}
+
+static void
+assign_recovery_target_xid(const char *newval, void *extra)
+{
+	recovery_target_xid = *((TransactionId *) extra);
+
+	if (recovery_target_xid != InvalidTransactionId)
+		recovery_target = RECOVERY_TARGET_XID;
+	else if (recovery_target_name[0])
+		recovery_target = RECOVERY_TARGET_NAME;
+	else if (recovery_target_time != 0)
+		recovery_target = RECOVERY_TARGET_TIME;
+	else
+		recovery_target = RECOVERY_TARGET_UNSET;
+}
+
+static bool
+check_recovery_target_name(char **newval, void **extra, GucSource source)
+{
+	if (strlen(*newval) >= MAXFNAMELEN)
+	{
+		GUC_check_errdetail("\"recovery_target_name\" is too long (maximum %d characters)",
+							MAXFNAMELEN - 1);
+		return false;
+	}
+	return true;
+}
+
+static void
+assign_recovery_target_name(const char *newval, void *extra)
+{
+	if (recovery_target_xid != InvalidTransactionId)
+		recovery_target = RECOVERY_TARGET_XID;
+	else if (newval[0])
+		recovery_target = RECOVERY_TARGET_NAME;
+	else if (recovery_target_time != 0)
+		recovery_target = RECOVERY_TARGET_TIME;
+	else
+		recovery_target = RECOVERY_TARGET_UNSET;
+}
+
+static bool
+check_recovery_target_time(char **newval, void **extra, GucSource source)
+{
+	TimestampTz     time;
+	TimestampTz     *myextra;
+	MemoryContext oldcontext = CurrentMemoryContext;
+
+	PG_TRY();
+	{
+		time = (strcmp(*newval, "") == 0) ?
+			0 :
+			DatumGetTimestampTz(DirectFunctionCall3(timestamptz_in,
+													CStringGetDatum(*newval),
+													ObjectIdGetDatum(InvalidOid),
+													Int32GetDatum(-1)));
+	}
+	PG_CATCH();
+	{
+		ErrorData  *edata;
+
+		/* Save error info */
+		MemoryContextSwitchTo(oldcontext);
+		edata = CopyErrorData();
+		FlushErrorState();
+
+		/* Pass the error message */
+		GUC_check_errdetail("%s", edata->message);
+		FreeErrorData(edata);
+		return false;
+	}
+	PG_END_TRY();
+
+	myextra = (TimestampTz *) guc_malloc(ERROR, sizeof(TimestampTz));
+	*myextra = time;
+	*extra = (void *) myextra;
+
+	return true;
+}
+
+static void
+assign_recovery_target_time(const char *newval, void *extra)
+{
+	recovery_target_time = *((TimestampTz *) extra);
+
+	if (recovery_target_xid != InvalidTransactionId)
+		recovery_target = RECOVERY_TARGET_XID;
+	else if (recovery_target_name[0])
+		recovery_target = RECOVERY_TARGET_NAME;
+	else if (recovery_target_time != 0)
+		recovery_target = RECOVERY_TARGET_TIME;
+	else
+		recovery_target = RECOVERY_TARGET_UNSET;
+}
+
+static bool
+check_recovery_target_timeline(char **newval, void **extra, GucSource source)
+{
+	TimeLineID	tli = 0;
+	TimeLineID	*myextra;
+
+	if (strcmp(*newval, "") == 0 || strcmp(*newval, "latest") == 0)
+		tli = 0;
+	else
+	{
+		errno = 0;
+		tli = (TimeLineID) strtoul(*newval, NULL, 0);
+		if (errno == EINVAL || errno == ERANGE)
+		{
+			GUC_check_errdetail("recovery_target_timeline is not a valid number: \"%s\"",
+								*newval);
+			return false;
+		}
+	}
+
+	myextra = (TimeLineID *) guc_malloc(ERROR, sizeof(TimeLineID));
+	*myextra = tli;
+	*extra = (void *) myextra;
+
+	return true;
+}
+
+static void
+assign_recovery_target_timeline(const char *newval, void *extra)
+{
+	recovery_target_timeline = *((TimeLineID *) extra);
+}
+
 #include "guc-file.c"
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
index d69a02b..3c234ef 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -199,6 +199,23 @@
 #archive_timeout = 0		# force a logfile segment switch after this
 				# number of seconds; 0 disables
 
+# - Archive Recovery -
+#restore_command = ''		# command to use to restore an archived logfile segment
+				# placeholders: %p = path of file to restore
+				#               %f = file name only
+				# e.g. 'cp /mnt/server/archivedir/%f %p'
+#archive_cleanup_command = ''	# command to execute at every restartpoint
+#recovery_end_command = ''	# command to execute at completion of recovery
+
+# - Recovery Target -
+#recovery_target_xid = ''
+#recovery_target_name = ''		# e.g. 'daily backup 2011-01-26'
+#recovery_target_time = ''		# e.g. '2004-07-14 22:39:00 EST'
+#recovery_target_timeline = ''		# timeline ID or 'latest'
+					# (change requires restart)
+#recovery_target_inclusive = on
+#pause_at_recovery_target = on		# Pause recovery once target is reached
+
 
 #------------------------------------------------------------------------------
 # REPLICATION
@@ -241,6 +258,11 @@
 #wal_receiver_timeout = 60s		# time that receiver waits for
 					# communication from master
 					# in milliseconds; 0 disables
+#standby_mode = off			# "on" starts the server as a standby
+					# (change requires restart)
+#primary_conninfo = ''			# connection string to connect to the master
+					# e.g. 'host=localhost port=5432'
+#trigger_file = ''			# trigger file to promote the standby
 
 
 #------------------------------------------------------------------------------
diff --git a/src/bin/pg_basebackup/pg_basebackup.c b/src/bin/pg_basebackup/pg_basebackup.c
index 56657a4..c56c5dc 100644
--- a/src/bin/pg_basebackup/pg_basebackup.c
+++ b/src/bin/pg_basebackup/pg_basebackup.c
@@ -43,7 +43,7 @@ int			compresslevel = 0;
 bool		includewal = false;
 bool		streamwal = false;
 bool		fastcheckpoint = false;
-bool		writerecoveryconf = false;
+bool		writestandby = false;
 int			standby_message_timeout = 10 * 1000;		/* 10 sec = default */
 
 /* Progress counters */
@@ -68,9 +68,6 @@ static int	has_xlogendptr = 0;
 static volatile LONG has_xlogendptr = 0;
 #endif
 
-/* Contents of recovery.conf to be generated */
-static PQExpBuffer recoveryconfcontents = NULL;
-
 /* Function headers */
 static void usage(void);
 static void verify_dir_is_empty_or_create(char *dirname);
@@ -78,8 +75,7 @@ static void progress_report(int tablespacenum, const char *filename);
 
 static void ReceiveTarFile(PGconn *conn, PGresult *res, int rownum);
 static void ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum);
-static void GenerateRecoveryConf(PGconn *conn);
-static void WriteRecoveryConf(void);
+static void WriteStandbyEnabled(void);
 static void BaseBackup(void);
 
 static bool reached_end_position(XLogRecPtr segendpos, uint32 timeline,
@@ -110,8 +106,8 @@ usage(void)
 	printf(_("\nOptions controlling the output:\n"));
 	printf(_("  -D, --pgdata=DIRECTORY receive base backup into directory\n"));
 	printf(_("  -F, --format=p|t       output format (plain (default), tar)\n"));
-	printf(_("  -R, --write-recovery-conf\n"
-			 "                         write recovery.conf after backup\n"));
+	printf(_("  -R, --write-standby-enable\n"
+			 "                         write standby.enabled after backup\n"));
 	printf(_("  -x, --xlog             include required WAL files in backup (fetch mode)\n"));
 	printf(_("  -X, --xlog-method=fetch|stream\n"
 			 "                         include required WAL files with specified method\n"));
@@ -667,7 +663,7 @@ ReceiveTarFile(PGconn *conn, PGresult *res, int rownum)
 		{
 			/*
 			 * End of chunk. If requested, and this is the base tablespace,
-			 * write recovery.conf into the tarfile. When done, close the file
+			 * write standby.enabled into the tarfile. When done, close the file
 			 * (but not stdout).
 			 *
 			 * Also, write two completely empty blocks at the end of the tar
@@ -677,22 +673,16 @@ ReceiveTarFile(PGconn *conn, PGresult *res, int rownum)
 
 			MemSet(zerobuf, 0, sizeof(zerobuf));
 
-			if (basetablespace && writerecoveryconf)
+			if (basetablespace && writestandby)
 			{
 				char		header[512];
-				int			padding;
 
-				tarCreateHeader(header, "recovery.conf", NULL,
-								recoveryconfcontents->len,
+				tarCreateHeader(header, "standby.enabled", NULL,
+								0,
 								0600, 04000, 02000,
 								time(NULL));
 
-				padding = ((recoveryconfcontents->len + 511) & ~511) - recoveryconfcontents->len;
-
 				WRITE_TAR_DATA(header, sizeof(header));
-				WRITE_TAR_DATA(recoveryconfcontents->data, recoveryconfcontents->len);
-				if (padding)
-					WRITE_TAR_DATA(zerobuf, padding);
 			}
 
 			/* 2 * 512 bytes empty data at end of file */
@@ -733,11 +723,11 @@ ReceiveTarFile(PGconn *conn, PGresult *res, int rownum)
 			disconnect_and_exit(1);
 		}
 
-		if (!writerecoveryconf || !basetablespace)
+		if (!writestandby || !basetablespace)
 		{
 			/*
-			 * When not writing recovery.conf, or when not working on the base
-			 * tablespace, we never have to look for an existing recovery.conf
+			 * When not writing standby.enabled, or when not working on the base
+			 * tablespace, we never have to look for an existing standby.enabled
 			 * file in the stream.
 			 */
 			WRITE_TAR_DATA(copybuf, r);
@@ -745,7 +735,7 @@ ReceiveTarFile(PGconn *conn, PGresult *res, int rownum)
 		else
 		{
 			/*
-			 * Look for a recovery.conf in the existing tar stream. If it's
+			 * Look for a standby.enabled in the existing tar stream. If it's
 			 * there, we must skip it so we can later overwrite it with our
 			 * own version of the file.
 			 *
@@ -791,12 +781,12 @@ ReceiveTarFile(PGconn *conn, PGresult *res, int rownum)
 						 * We have the complete header structure in tarhdr,
 						 * look at the file metadata: - the subsequent file
 						 * contents have to be skipped if the filename is
-						 * recovery.conf - find out the size of the file
+						 * standby.enabled - find out the size of the file
 						 * padded to the next multiple of 512
 						 */
 						int			padding;
 
-						skip_file = (strcmp(&tarhdr[0], "recovery.conf") == 0);
+						skip_file = (strcmp(&tarhdr[0], "standby.enabled") == 0);
 
 						sscanf(&tarhdr[124], "%11o", (unsigned int *) &filesz);
 
@@ -1102,10 +1092,11 @@ ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum)
 	if (copybuf != NULL)
 		PQfreemem(copybuf);
 
-	if (basetablespace && writerecoveryconf)
-		WriteRecoveryConf();
+	if (basetablespace && writestandby)
+		WriteStandbyEnabled();
 }
 
+
 /*
  * Escape a parameter value so that it can be used as part of a libpq
  * connection string, e.g. in:
@@ -1186,95 +1177,17 @@ escape_quotes(const char *src)
 	return result;
 }
 
-/*
- * Create a recovery.conf file in memory using a PQExpBuffer
- */
-static void
-GenerateRecoveryConf(PGconn *conn)
-{
-	PQconninfoOption *connOptions;
-	PQconninfoOption *option;
-	PQExpBufferData conninfo_buf;
-	char	   *escaped;
-
-	recoveryconfcontents = createPQExpBuffer();
-	if (!recoveryconfcontents)
-	{
-		fprintf(stderr, _("%s: out of memory\n"), progname);
-		disconnect_and_exit(1);
-	}
-
-	connOptions = PQconninfo(conn);
-	if (connOptions == NULL)
-	{
-		fprintf(stderr, _("%s: out of memory\n"), progname);
-		disconnect_and_exit(1);
-	}
-
-	appendPQExpBufferStr(recoveryconfcontents, "standby_mode = 'on'\n");
-
-	initPQExpBuffer(&conninfo_buf);
-	for (option = connOptions; option && option->keyword; option++)
-	{
-		/*
-		 * Do not emit this setting if: - the setting is "replication",
-		 * "dbname" or "fallback_application_name", since these would be
-		 * overridden by the libpqwalreceiver module anyway. - not set or
-		 * empty.
-		 */
-		if (strcmp(option->keyword, "replication") == 0 ||
-			strcmp(option->keyword, "dbname") == 0 ||
-			strcmp(option->keyword, "fallback_application_name") == 0 ||
-			(option->val == NULL) ||
-			(option->val != NULL && option->val[0] == '\0'))
-			continue;
-
-		/* Separate key-value pairs with spaces */
-		if (conninfo_buf.len != 0)
-			appendPQExpBufferStr(&conninfo_buf, " ");
-
-		/*
-		 * Write "keyword=value" pieces, the value string is escaped and/or
-		 * quoted if necessary.
-		 */
-		escaped = escapeConnectionParameter(option->val);
-		appendPQExpBuffer(&conninfo_buf, "%s=%s", option->keyword, escaped);
-		free(escaped);
-	}
-
-	/*
-	 * Escape the connection string, so that it can be put in the config file.
-	 * Note that this is different from the escaping of individual connection
-	 * options above!
-	 */
-	escaped = escape_quotes(conninfo_buf.data);
-	appendPQExpBuffer(recoveryconfcontents, "primary_conninfo = '%s'\n", escaped);
-	free(escaped);
-
-	if (PQExpBufferBroken(recoveryconfcontents) ||
-		PQExpBufferDataBroken(conninfo_buf))
-	{
-		fprintf(stderr, _("%s: out of memory\n"), progname);
-		disconnect_and_exit(1);
-	}
-
-	termPQExpBuffer(&conninfo_buf);
-
-	PQconninfoFree(connOptions);
-}
-
 
 /*
- * Write a recovery.conf file into the directory specified in basedir,
- * with the contents already collected in memory.
+ * Write a standby.enabled file into the directory specified in basedir.
  */
 static void
-WriteRecoveryConf(void)
+WriteStandbyEnabled(void)
 {
 	char		filename[MAXPGPATH];
 	FILE	   *cf;
 
-	sprintf(filename, "%s/recovery.conf", basedir);
+	sprintf(filename, "%s/standby.enabled", basedir);
 
 	cf = fopen(filename, "w");
 	if (cf == NULL)
@@ -1283,14 +1196,6 @@ WriteRecoveryConf(void)
 		disconnect_and_exit(1);
 	}
 
-	if (fwrite(recoveryconfcontents->data, recoveryconfcontents->len, 1, cf) != 1)
-	{
-		fprintf(stderr,
-				_("%s: could not write to file \"%s\": %s\n"),
-				progname, filename, strerror(errno));
-		disconnect_and_exit(1);
-	}
-
 	fclose(cf);
 }
 
@@ -1346,12 +1251,6 @@ BaseBackup(void)
 	}
 
 	/*
-	 * Build contents of recovery.conf if requested
-	 */
-	if (writerecoveryconf)
-		GenerateRecoveryConf(conn);
-
-	/*
 	 * Run IDENTIFY_SYSTEM so we can get the timeline
 	 */
 	res = PQexec(conn, "IDENTIFY_SYSTEM");
@@ -1628,9 +1527,6 @@ BaseBackup(void)
 #endif
 	}
 
-	/* Free the recovery.conf contents */
-	destroyPQExpBuffer(recoveryconfcontents);
-
 	/*
 	 * End of copy data. Final result is already checked inside the loop.
 	 */
@@ -1651,7 +1547,7 @@ main(int argc, char **argv)
 		{"pgdata", required_argument, NULL, 'D'},
 		{"format", required_argument, NULL, 'F'},
 		{"checkpoint", required_argument, NULL, 'c'},
-		{"write-recovery-conf", no_argument, NULL, 'R'},
+		{"write-standby-enable", no_argument, NULL, 'R'},
 		{"xlog", no_argument, NULL, 'x'},
 		{"xlog-method", required_argument, NULL, 'X'},
 		{"gzip", no_argument, NULL, 'z'},
@@ -1712,7 +1608,7 @@ main(int argc, char **argv)
 				}
 				break;
 			case 'R':
-				writerecoveryconf = true;
+				writestandby = true;
 				break;
 			case 'x':
 				if (includewal)
diff --git a/src/bin/pg_ctl/pg_ctl.c b/src/bin/pg_ctl/pg_ctl.c
index ff3e359..02b0809 100644
--- a/src/bin/pg_ctl/pg_ctl.c
+++ b/src/bin/pg_ctl/pg_ctl.c
@@ -890,7 +890,7 @@ do_stop(void)
 		/*
 		 * If backup_label exists, an online backup is running. Warn the user
 		 * that smart shutdown will wait for it to finish. However, if
-		 * recovery.conf is also present, we're recovering from an online
+		 * standby.enabled is also present, we're recovering from an online
 		 * backup instead of performing one.
 		 */
 		if (shutdown_mode == SMART_MODE &&
@@ -978,7 +978,7 @@ do_restart(void)
 		/*
 		 * If backup_label exists, an online backup is running. Warn the user
 		 * that smart shutdown will wait for it to finish. However, if
-		 * recovery.conf is also present, we're recovering from an online
+		 * standby.enabled is also present, we're recovering from an online
 		 * backup instead of performing one.
 		 */
 		if (shutdown_mode == SMART_MODE &&
@@ -1089,7 +1089,7 @@ do_promote(void)
 		exit(1);
 	}
 
-	/* If recovery.conf doesn't exist, the server is not in standby mode */
+	/* If standby.enabled doesn't exist, the server is not in standby mode */
 	if (stat(recovery_file, &statbuf) != 0)
 	{
 		write_stderr(_("%s: cannot promote server; "
@@ -2238,7 +2238,7 @@ main(int argc, char **argv)
 		snprintf(postopts_file, MAXPGPATH, "%s/postmaster.opts", pg_data);
 		snprintf(pid_file, MAXPGPATH, "%s/postmaster.pid", pg_data);
 		snprintf(backup_file, MAXPGPATH, "%s/backup_label", pg_data);
-		snprintf(recovery_file, MAXPGPATH, "%s/recovery.conf", pg_data);
+		snprintf(recovery_file, MAXPGPATH, "%s/standby.enabled", pg_data);
 	}
 
 	switch (ctl_command)
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index 002862c..a5794e1 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -190,6 +190,20 @@ extern char *XLogArchiveCommand;
 extern bool EnableHotStandby;
 extern bool fullPageWrites;
 extern bool log_checkpoints;
+extern char *restore_command;
+extern char *archive_cleanup_command;
+extern char *recovery_end_command;
+extern bool	StandbyModeRequested;
+extern char *primary_conninfo;
+extern char *trigger_file;
+extern RecoveryTargetType recovery_target;
+extern TransactionId recovery_target_xid;
+extern TimestampTz recovery_target_time;
+extern char *recovery_target_name;
+extern bool recovery_target_inclusive;
+extern bool pause_at_recovery_target;
+extern char *recovery_target_timeline_string;
+extern TimeLineID recovery_target_timeline;
 extern int	num_xloginsert_slots;
 
 /* WAL levels */
diff --git a/src/include/utils/guc_tables.h b/src/include/utils/guc_tables.h
index 4f1f6e0..f280775 100644
--- a/src/include/utils/guc_tables.h
+++ b/src/include/utils/guc_tables.h
@@ -68,6 +68,8 @@ enum config_group
 	WAL_SETTINGS,
 	WAL_CHECKPOINTS,
 	WAL_ARCHIVING,
+	WAL_ARCHIVE_RECOVERY,
+	WAL_RECOVERY_TARGET,
 	REPLICATION,
 	REPLICATION_SENDING,
 	REPLICATION_MASTER,