Turning recovery.conf into GUCs
Hi everyone,
Seems that the latest patch in this series is:
/messages/by-id/CAB7nPqRLWLH1b0YsvqYF-zOFjrv4FRiurQ6yqcP3wjBp=TJOLg@mail.gmail.com
= Applying =
Reading the threads it seems there is consensus in this happening, so
let's move in that direction.
The patch applies almost cleanly except for a minor change in xlog.c
= Building =
In pg_basebackup we have now 2 unused functions:
escapeConnectionParameter and escape_quotes. the only use of these
functions was when that tool created the recovery.conf file so they
aren't needed anymore.
= Functionality =
I have been testing functionality and it looks good so far, i still
need to test a few things but i don't expect anything bad.
I have 2 complaints though:
1) the file to trigger recovery is now called standby.enabled. I know
this is because we use the file to also make the node a standby.
Now, reality is that the file doesn't make the node a standby but the
combination of this file (which starts recovery) + standby_mode=on.
so, i agree with the suggestion of naming the file: recovery.trigger
2) This patch removes the dual existence of recovery.conf: as a state
file and as a configuration file
- the former is accomplished by changing the name of the file that
triggers recovery (from recovery.conf to standby.enabled)
- the latter is done by moving all parameters to postgresql.conf and
*not reading* recovery.conf anymore
so, after applying this patch postgres don't use recovery.conf for
anything... except for complaining.
it's completely fair to say we are no longer using that file and
ignoring its existence, but why we should care if users want to use a
file with that name for inclusion in postgresql.conf or where they put
that hypotetic file?
after this patch, recovery.conf will have no special meaning anymore
so let's the user put it whatever files he wants, wherever he wants.
if we really want to warn the user, use WARNING instead of FATAL
= Code & functionality =
why did you changed the context in which we can set archive_command?
please, let it as a SIGHUP parameter
- {"archive_command", PGC_SIGHUP, WAL_ARCHIVING,
+ {"archive_command", PGC_POSTMASTER, WAL_ARCHIVING,
All parameters moved from recovery.conf has been marked as
PGC_POSTMASTER, but most of them are clearly PGC_SIGHUP candidates
+ {"restore_command", PGC_POSTMASTER, WAL_ARCHIVE_RECOVERY,
+ {"archive_cleanup_command", PGC_POSTMASTER, WAL_ARCHIVE_RECOVERY,
+ {"recovery_end_command", PGC_POSTMASTER, WAL_ARCHIVE_RECOVERY,
+ {"recovery_target_xid", PGC_POSTMASTER, WAL_RECOVERY_TARGET,
+ {"recovery_target_name", PGC_POSTMASTER, WAL_RECOVERY_TARGET,
+ {"recovery_target_time", PGC_POSTMASTER, WAL_RECOVERY_TARGET,
+ {"trigger_file", PGC_POSTMASTER, REPLICATION_STANDBY,
Not sure about these ones
+ {"recovery_target_timeline", PGC_POSTMASTER, WAL_RECOVERY_TARGET,
+ {"primary_conninfo", PGC_POSTMASTER, REPLICATION_STANDBY,
This is the only one i agree, should be PGC_POSTMASTER only
+ {"standby_mode", PGC_POSTMASTER, REPLICATION_STANDBY,
--
Jaime Casanova www.2ndQuadrant.com
Professional PostgreSQL: Soporte 24x7 y capacitación
Phone: +593 4 5107566 Cell: +593 987171157
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Jaime,
= Building =
In pg_basebackup we have now 2 unused functions:
escapeConnectionParameter and escape_quotes. the only use of these
functions was when that tool created the recovery.conf file so they
aren't needed anymore.
Except that we'll want 9.4's -R to do something, probably create a file
called conf.d/replication.conf. Mind you, it won't need the same wonky
quoting stuff.
1) the file to trigger recovery is now called standby.enabled. I know
this is because we use the file to also make the node a standby.
Now, reality is that the file doesn't make the node a standby but the
combination of this file (which starts recovery) + standby_mode=on.
so, i agree with the suggestion of naming the file: recovery.trigger2) This patch removes the dual existence of recovery.conf: as a state
file and as a configuration file- the former is accomplished by changing the name of the file that
triggers recovery (from recovery.conf to standby.enabled)
- the latter is done by moving all parameters to postgresql.conf and
*not reading* recovery.conf anymoreso, after applying this patch postgres don't use recovery.conf for
anything... except for complaining.
it's completely fair to say we are no longer using that file and
ignoring its existence, but why we should care if users want to use a
file with that name for inclusion in postgresql.conf or where they put
that hypotetic file?
So this is a bit of a catch-22. If we allow the user to use a file
named "recovery.conf" in $PGDATA, then the user may be unaware that the
*meaning* of the file has changed, which can result in unplanned
promotion of replicas after upgrade.
*on the other hand*, if we prevent creation of a configuration file
named "recovery.conf", then we block efforts to write
backwards-compatible management utilities.
AFAIK, there is no good solution for this, which is why it's taken so
long for us to resolve the general issue. Given that, I think it's
better to go for the breakage and all the warnings. If a user wants a
file called recovery.conf, put it in the conf.d directory.
I don't remember, though: how does this patch handle PITR recovery?
= Code & functionality =
+ {"restore_command", PGC_POSTMASTER, WAL_ARCHIVE_RECOVERY, + {"archive_cleanup_command", PGC_POSTMASTER, WAL_ARCHIVE_RECOVERY, + {"recovery_end_command", PGC_POSTMASTER, WAL_ARCHIVE_RECOVERY, + {"recovery_target_xid", PGC_POSTMASTER, WAL_RECOVERY_TARGET, + {"recovery_target_name", PGC_POSTMASTER, WAL_RECOVERY_TARGET, + {"recovery_target_time", PGC_POSTMASTER, WAL_RECOVERY_TARGET, + {"trigger_file", PGC_POSTMASTER, REPLICATION_STANDBY,Not sure about these ones
+ {"recovery_target_timeline", PGC_POSTMASTER, WAL_RECOVERY_TARGET, + {"primary_conninfo", PGC_POSTMASTER, REPLICATION_STANDBY,
It would be really nice to change these on the fly; it would help a lot
of issues with minor changes to replication config. I can understand,
though, that the replication code might not be prepared for that.
--
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
Import Notes
Reply to msg id not found: WM1d6117a19ee50d69cc6fa02a24805d341b69bae88bb96c42f0ab67495495e41eb6816369d45c86f44a56c710a383b24c@asav-3.01.com
On Wed, Oct 16, 2013 at 1:34 PM, Josh Berkus <josh@agliodbs.com> wrote:
Jaime,
= Building =
In pg_basebackup we have now 2 unused functions:
escapeConnectionParameter and escape_quotes. the only use of these
functions was when that tool created the recovery.conf file so they
aren't needed anymore.Except that we'll want 9.4's -R to do something, probably create a file
called conf.d/replication.conf. Mind you, it won't need the same wonky
quoting stuff.
Currently the patch uses -R to create the recovery trigger file
1) the file to trigger recovery is now called standby.enabled. I know
this is because we use the file to also make the node a standby.
Now, reality is that the file doesn't make the node a standby but the
combination of this file (which starts recovery) + standby_mode=on.
so, i agree with the suggestion of naming the file: recovery.trigger2) This patch removes the dual existence of recovery.conf: as a state
file and as a configuration file- the former is accomplished by changing the name of the file that
triggers recovery (from recovery.conf to standby.enabled)
- the latter is done by moving all parameters to postgresql.conf and
*not reading* recovery.conf anymoreso, after applying this patch postgres don't use recovery.conf for
anything... except for complaining.
it's completely fair to say we are no longer using that file and
ignoring its existence, but why we should care if users want to use a
file with that name for inclusion in postgresql.conf or where they put
that hypotetic file?So this is a bit of a catch-22. If we allow the user to use a file
named "recovery.conf" in $PGDATA, then the user may be unaware that the
*meaning* of the file has changed, which can result in unplanned
promotion of replicas after upgrade.
well, after upgrade you should do checks. and even if it happens,
after it happens once people will be aware of the change.
now, some suggestions were made to avoid the problem. 1) read the file
if exists last in the process of postgresql.conf, 2) add a GUC
indicating if it should read it and include it (not using it as a
trigger file). another one, 3) include in this release an
include_if_exists directive and give a warning if it sees the file
then include it, on next release remove the include_if_exists (at
least that way people will be warned before breaking compatibility)
please, keep in mind none of these suggestions include make the
recovery.conf file act as a trigger for recovery
*on the other hand*, if we prevent creation of a configuration file
named "recovery.conf", then we block efforts to write
backwards-compatible management utilities.
and all tools and procedures that currently exists.
AFAIK, there is no good solution for this, which is why it's taken so
long for us to resolve the general issue. Given that, I think it's
better to go for the breakage and all the warnings. If a user wants a
file called recovery.conf, put it in the conf.d directory.
well, there should be good solutions... maybe we haven't thought them yet.
anyway, we can't postpone the decision forever. we need to make a
decision and stick with it otherwise this patch will be stalled N
releases for no good reason
I don't remember, though: how does this patch handle PITR recovery?
exactly as it is now, if it sees the recovery trigger file, then it
starts ArchiveRecovery and after it finish delete the file (the only
difference) and increment the timeline
= Code & functionality =
+ {"restore_command", PGC_POSTMASTER, WAL_ARCHIVE_RECOVERY, + {"archive_cleanup_command", PGC_POSTMASTER, WAL_ARCHIVE_RECOVERY, + {"recovery_end_command", PGC_POSTMASTER, WAL_ARCHIVE_RECOVERY, + {"recovery_target_xid", PGC_POSTMASTER, WAL_RECOVERY_TARGET, + {"recovery_target_name", PGC_POSTMASTER, WAL_RECOVERY_TARGET, + {"recovery_target_time", PGC_POSTMASTER, WAL_RECOVERY_TARGET, + {"trigger_file", PGC_POSTMASTER, REPLICATION_STANDBY,Not sure about these ones
+ {"recovery_target_timeline", PGC_POSTMASTER, WAL_RECOVERY_TARGET, + {"primary_conninfo", PGC_POSTMASTER, REPLICATION_STANDBY,It would be really nice to change these on the fly; it would help a lot
of issues with minor changes to replication config. I can understand,
though, that the replication code might not be prepared for that.
well, archive_command can be changed right now with a SIGHUP so at
least that one shouldn't change... and i don't think most of these are
too different. even if we are not sure we can do this now and change
them as SIGHUP later
--
Jaime Casanova www.2ndQuadrant.com
Professional PostgreSQL: Soporte 24x7 y capacitación
Phone: +593 4 5107566 Cell: +593 987171157
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Fri, Oct 18, 2013 at 1:13 PM, Jaime Casanova <jaime@2ndquadrant.com> wrote:
= Code & functionality =
+ {"restore_command", PGC_POSTMASTER, WAL_ARCHIVE_RECOVERY, + {"archive_cleanup_command", PGC_POSTMASTER, WAL_ARCHIVE_RECOVERY, + {"recovery_end_command", PGC_POSTMASTER, WAL_ARCHIVE_RECOVERY, + {"recovery_target_xid", PGC_POSTMASTER, WAL_RECOVERY_TARGET, + {"recovery_target_name", PGC_POSTMASTER, WAL_RECOVERY_TARGET, + {"recovery_target_time", PGC_POSTMASTER, WAL_RECOVERY_TARGET, + {"trigger_file", PGC_POSTMASTER, REPLICATION_STANDBY,Not sure about these ones
+ {"recovery_target_timeline", PGC_POSTMASTER, WAL_RECOVERY_TARGET, + {"primary_conninfo", PGC_POSTMASTER, REPLICATION_STANDBY,It would be really nice to change these on the fly; it would help a lot
of issues with minor changes to replication config. I can understand,
though, that the replication code might not be prepared for that.well, archive_command can be changed right now with a SIGHUP so at
least that one shouldn't change... and i don't think most of these are
too different. even if we are not sure we can do this now and change
them as SIGHUP later
Changing those parameters don't really matter as long as the node is
not performing a recovery IMO, but I'd rather see a careful approach
here and let all those parameters as PGC_POSTMASTER for now to avoid
any surprises. Perhaps a second patch on top of this one could be the
addition of context name like SIGHUP_RECOVERY, aka just allow those
parameters to be updated with SIGHUP as long as the node is not in
recovery.
--
Michael
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Jaime,
Except that we'll want 9.4's -R to do something, probably create a file
called conf.d/replication.conf. Mind you, it won't need the same wonky
quoting stuff.Currently the patch uses -R to create the recovery trigger file
Right, I'm saying that we'll want to do better than that for release,
but that's dependant on committing the conf directory patch.
Note that this change makes committing the conf.d patch extra-important;
it's going to be a LOT easier to upgrade tools for 9.4 if we have that.
well, after upgrade you should do checks. and even if it happens,
after it happens once people will be aware of the change.
now, some suggestions were made to avoid the problem. 1) read the file
if exists last in the process of postgresql.conf, 2) add a GUC
indicating if it should read it and include it (not using it as a
trigger file). another one, 3) include in this release an
include_if_exists directive and give a warning if it sees the file
then include it, on next release remove the include_if_exists (at
least that way people will be warned before breaking compatibility)
I think all of these suggestions just make our code more complicated
without improving the upgrade situation.
The reason given (and I think it's pretty good) for erroring on
recovery.conf is that we don't want people to accidentally take a server
out of replication because they didn't check which version of PostgreSQL
they are on.
*on the other hand*, if we prevent creation of a configuration file
named "recovery.conf", then we block efforts to write
backwards-compatible management utilities.and all tools and procedures that currently exists.
Right. However, exploring your suggestions above, none of those
workarounds prevent breakage. And in some cases, they make the breakage
less obvious than the current patch does. If repmgr 1.2 / OmniPITR 1.2
won't work correctly with 9.4, then we want those tools to break at
upgrade time, not later when the user is trying to fail over.
For that matter, 9.4 is a very good time (relatively speaking) to break
replication tools because the new logical replication is going to cause
everyone to rev their tools anyway.
This kind of breakage alone might end up being a good reason to call the
next version 10.0.
well, there should be good solutions... maybe we haven't thought them yet.
anyway, we can't postpone the decision forever. we need to make a
decision and stick with it otherwise this patch will be stalled N
releases for no good reason
I think if there were a good solution, sometime in the last 1.5 years
someone would have suggested it. Gods know Simon has tried.
exactly as it is now, if it sees the recovery trigger file, then it
starts ArchiveRecovery and after it finish delete the file (the only
difference) and increment the timeline
OK, so if I'm doing a PITR recovery, I just put the recovery variables
into postgresql.conf, then?
--
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
Import Notes
Reply to msg id not found: WM8033be71c56714a007f8f2fcb59a5d025dcf246c7403e2ac59d34464da67589f36bfd2870288afa11642b191037b2772@asav-3.01.com
On Fri, Oct 18, 2013 at 11:32 AM, Josh Berkus <josh@agliodbs.com> wrote:
exactly as it is now, if it sees the recovery trigger file, then it
starts ArchiveRecovery and after it finish delete the file (the only
difference) and increment the timelineOK, so if I'm doing a PITR recovery, I just put the recovery variables
into postgresql.conf, then?
create a recovery trigger file (called standby.enabled in current
patch) in $PGDATA and start the server
--
Jaime Casanova www.2ndQuadrant.com
Professional PostgreSQL: Soporte 24x7 y capacitación
Phone: +593 4 5107566 Cell: +593 987171157
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 2013-10-18 09:32:15 -0700, Josh Berkus wrote:
For that matter, 9.4 is a very good time (relatively speaking) to break
replication tools because the new logical replication is going to cause
everyone to rev their tools anyway.
We're hopefully getting changeset extraction in, but there's little
chance of a full blown replication solution making it in in 9.4...
Greetings,
Andres Freund
--
Andres Freund 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
On 10/18/2013 12:29 PM, Andres Freund wrote:
On 2013-10-18 09:32:15 -0700, Josh Berkus wrote:
For that matter, 9.4 is a very good time (relatively speaking) to break
replication tools because the new logical replication is going to cause
everyone to rev their tools anyway.We're hopefully getting changeset extraction in, but there's little
chance of a full blown replication solution making it in in 9.4...
I thought changeset extraction was the only thing going into core? What
else do we need?
--
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
Import Notes
Reply to msg id not found: WMee6354fc71cb8dacd10ed359e39a31e8a2a7ad053f4bef00713ac76c8cf4ff121c8eedcf468373154bcb4ef8b4a2dcf3@asav-1.01.com
On 2013-10-18 13:16:52 -0700, Josh Berkus wrote:
On 10/18/2013 12:29 PM, Andres Freund wrote:
On 2013-10-18 09:32:15 -0700, Josh Berkus wrote:
For that matter, 9.4 is a very good time (relatively speaking) to break
replication tools because the new logical replication is going to cause
everyone to rev their tools anyway.We're hopefully getting changeset extraction in, but there's little
chance of a full blown replication solution making it in in 9.4...I thought changeset extraction was the only thing going into core? What
else do we need?
Well, I personally want more in core mid/long term, but anyway.
Without released, proven and stable logical in-core replication
technology using this, I don't see why repmgr or something related would
need/want to change?
Greetings,
Andres Freund
--
Andres Freund 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
On 10/18/2013 01:35 PM, Andres Freund wrote:
On 2013-10-18 13:16:52 -0700, Josh Berkus wrote:
I thought changeset extraction was the only thing going into core? What
else do we need?Well, I personally want more in core mid/long term, but anyway.
I've lost track of the plan, then.
Hmmm ... we need replication of DDL commands, no?
Without released, proven and stable logical in-core replication
technology using this, I don't see why repmgr or something related would
need/want to change?
Repmgr is designed to manage binary replication, not perform it.
What will likely change first is Slony and Bucardo, who have a strong
interest in dumping triggers and queues. A contrib module which did the
simplest implementation -- that is, whole-database M-S replication --
would also be a good idea, especially since it would provide an example
of how to build your own.
But I'd be wary of going beyond that in core, because you very quickly
get into the territory of trying to satisfy multiple exclusive
use-cases. Let's focus on providing a really good API which enables
people to build their own tools.
--
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
Import Notes
Reply to msg id not found: WMe1ac95375abf2ef2cf8d193f7c01ac36ef7e42805eb8fc99ff07dde6a08b91f659c740085cd72bd52bc152f04ca22106@asav-3.01.com
On 2013-10-18 14:16:04 -0700, Josh Berkus wrote:
On 10/18/2013 01:35 PM, Andres Freund wrote:
On 2013-10-18 13:16:52 -0700, Josh Berkus wrote:
I thought changeset extraction was the only thing going into core? What
else do we need?Well, I personally want more in core mid/long term, but anyway.
I've lost track of the plan, then.
Hmmm ... we need replication of DDL commands, no?
Without released, proven and stable logical in-core replication
technology using this, I don't see why repmgr or something related would
need/want to change?Repmgr is designed to manage binary replication, not perform it.
Obviously.
What will likely change first is Slony and Bucardo, who have a strong
interest in dumping triggers and queues.
But I don't understand what that has to do with recovery.conf and
breakage around it.
A contrib module which did the
simplest implementation -- that is, whole-database M-S replication --
would also be a good idea, especially since it would provide an example
of how to build your own.But I'd be wary of going beyond that in core, because you very quickly
get into the territory of trying to satisfy multiple exclusive
use-cases. Let's focus on providing a really good API which enables
people to build their own tools.
We'll see. I am certain we'll have many discussions about the bits and
pieces you need to build a great replication solution (of which we imo
don't have any yet).
Greetings,
Andres Freund
--
Andres Freund 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
On Fri, Oct 18, 2013 at 11:32 AM, Josh Berkus <josh@agliodbs.com> wrote:
Jaime,
well, after upgrade you should do checks. and even if it happens,
after it happens once people will be aware of the change.
now, some suggestions were made to avoid the problem. 1) read the file
if exists last in the process of postgresql.conf, 2) add a GUC
indicating if it should read it and include it (not using it as a
trigger file). another one, 3) include in this release an
include_if_exists directive and give a warning if it sees the file
then include it, on next release remove the include_if_exists (at
least that way people will be warned before breaking compatibility)I think all of these suggestions just make our code more complicated
without improving the upgrade situation.
well #3 just add a line in postgresql.conf (an include_if_exists) and
current patch gives an error in case it finds the file (i'm suggesting
to make it a warning instead).
how does that makes our code more complicated?
The reason given (and I think it's pretty good) for erroring on
recovery.conf is that we don't want people to accidentally take a server
out of replication because they didn't check which version of PostgreSQL
they are on.
well, people will go out of replication also if they forgot the
recovery trigger file
even if they set the variables in postgresql.conf
it happens two me twice today ;)
--
Jaime Casanova www.2ndQuadrant.com
Professional PostgreSQL: Soporte 24x7 y capacitación
Phone: +593 4 5107566 Cell: +593 987171157
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 10/18/2013 02:58 PM, Jaime Casanova wrote:
well #3 just add a line in postgresql.conf (an include_if_exists) and
current patch gives an error in case it finds the file (i'm suggesting
to make it a warning instead).
how does that makes our code more complicated?
Well, that's a couple extra lines only, I know. However, it doesn't
actually help with the breakage any, since recovery.conf *still* won't
work as a trigger file.
The only thing which would prevent breakage (proposed by Simon, I think)
is having recovery.conf have an include_if_exists, AND have
recovery.conf be an 'alternate' name for replication.trigger. However,
even this would break, and in IMHO ways which would tend to happen at
failover time rather than upgrade time.
To put it clearly: if we're going to have breakage, I want it to be at
upgrade time, when the database is *already down*, and not at failover
time or some other time when downtime is not planned.
well, people will go out of replication also if they forgot the
recovery trigger file
even if they set the variables in postgresql.confit happens two me twice today ;)
Right. What I'd like to avoid is having folks try to use, for example,
repmgr 1.2 with PostgreSQL 9.4 and have their replication break and them
not notice for a couple hours of operation. I'd rather have PostgreSQL
9.4 refuse to come up, so that they know *immediately* that something is
wrong.
--
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
Import Notes
Reply to msg id not found: WMaabe7c5df24e611511b96f564c5acfafe32386b2486b627ba9c499a6e4ec20c3f57dd97571c805906952b124006b94cd@asav-2.01.com
On 10/18/2013 02:36 PM, Andres Freund wrote:
What will likely change first is Slony and Bucardo, who have a strong
interest in dumping triggers and queues.But I don't understand what that has to do with recovery.conf and
breakage around it.
The simple thinking is this: if we announce and promote new replication,
then our users who do upgrade are going to expect to upgrade their
replication tools at the same time, even if they're not using the new
replication. That is people will look for a repmgr 2.0 / OmniPITR 1.5
and update to it.
Now, as a tool author, I know that supporting both models is going to be
annoying. But necessary.
And, as I said before, we need to do the GUC merger in the same release
we introduce configuration directory (or after it).
--
Josh Berkus
PostgreSQL Experts Inc.
http://pgexperts.com
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Import Notes
Reply to msg id not found: WM8eee63df1f6b49c1ea26b676c5d39c1bfbde6c6c9003fbae5ab4f0e150c91158588f1a5ba4a96e271822c4a0997a5fe8@asav-2.01.com
On Mon, Oct 21, 2013 at 11:53 AM, Josh Berkus <josh@agliodbs.com> wrote:
On 10/18/2013 02:36 PM, Andres Freund wrote:
What will likely change first is Slony and Bucardo, who have a strong
interest in dumping triggers and queues.But I don't understand what that has to do with recovery.conf and
breakage around it.The simple thinking is this: if we announce and promote new replication,
then our users who do upgrade are going to expect to upgrade their
replication tools at the same time, even if they're not using the new
replication. That is people will look for a repmgr 2.0 / OmniPITR 1.5
and update to it.Now, as a tool author, I know that supporting both models is going to be
annoying. But necessary.
AFAIU, even if we get in all about logical replication today that
won't affect tools that manage binary replication.
And, as I said before, we need to do the GUC merger in the same release
we introduce configuration directory (or after it).
you mean the ALTER SYSTEM syntax? anyway, why that restriction?
--
Jaime Casanova www.2ndQuadrant.com
Professional PostgreSQL: Soporte 24x7 y capacitación
Phone: +593 4 5107566 Cell: +593 987171157
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Jaime,
And, as I said before, we need to do the GUC merger in the same release
we introduce configuration directory (or after it).you mean the ALTER SYSTEM syntax? anyway, why that restriction?
No, I'm referring to the proposal to have an automatically created and
included conf.d directory for extra configuration files.
--
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
Import Notes
Reply to msg id not found: WM3b49b90b61cc20f662e940ac24c4ec97d4ad1ecb65ad7b1b175ae056be5417699e5d8bbf680d590c815e8d2bc080b391@asav-2.01.com
On Mon, Oct 21, 2013 at 2:57 PM, Josh Berkus <josh@agliodbs.com> wrote:
Jaime,
And, as I said before, we need to do the GUC merger in the same release
we introduce configuration directory (or after it).you mean the ALTER SYSTEM syntax? anyway, why that restriction?
No, I'm referring to the proposal to have an automatically created and
included conf.d directory for extra configuration files.
9.3 has include_dir and postgresql.conf has this setted:
"""
#include_dir = 'conf.d' # include files ending in '.conf' from
# directory 'conf.d'
"""
anything before this should be up to the packagers, no?
or, do you mean something else?
--
Jaime Casanova www.2ndQuadrant.com
Professional PostgreSQL: Soporte 24x7 y capacitación
Phone: +593 4 5107566 Cell: +593 987171157
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
9.3 has include_dir and postgresql.conf has this setted:
"""
#include_dir = 'conf.d' # include files ending in '.conf' from
# directory 'conf.d'
"""anything before this should be up to the packagers, no?
or, do you mean something else?
Well, I was just pointing out that it would make things *much* easier
for tool authors if conf.d were enabled by default, instead of disabled
by default. Then they could change tools to write a "recovery.conf"
file to conf.d.
--
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
Import Notes
Reply to msg id not found: WM2eef57bf14271a28b7764a48733ac1bb0352229c58adbbcfc444bf3b2d39b5c4e9068a10e3f688295481db2314a812ff@asav-3.01.com
On Mon, Oct 21, 2013 at 3:57 PM, Josh Berkus <josh@agliodbs.com> wrote:
9.3 has include_dir and postgresql.conf has this setted:
"""
#include_dir = 'conf.d' # include files ending in '.conf' from
# directory 'conf.d'
"""anything before this should be up to the packagers, no?
or, do you mean something else?
Well, I was just pointing out that it would make things *much* easier
for tool authors if conf.d were enabled by default, instead of disabled
by default. Then they could change tools to write a "recovery.conf"
file to conf.d.
I agree, it would be much easier, but that is not relevant to this patch.
I have rebased Michael Paquier's patch and did a few changes:
* changed standby.enabled filename to recovery.trigger
* make archive_command a SIGHUP parameter again
* make restore_command a SIGHUP parameter
* rename restore_command variable to XLogRestoreCommand to match
XLogArchiveCommand
we can also make primary_conninfo a SIGHUP parameter, of course the
DBA will need to force a reconection after that.
after this is done we can look at the other recovery parameters.
--
Jaime Casanova www.2ndQuadrant.com
Professional PostgreSQL: Soporte 24x7 y capacitación
Phone: +593 4 5107566 Cell: +593 987171157
Attachments:
recovery_guc_v5.patchtext/x-patch; charset=US-ASCII; name=recovery_guc_v5.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 059c820..907346e 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 1712974..6bad86f 100644
--- a/doc/src/sgml/backup.sgml
+++ b/doc/src/sgml/backup.sgml
@@ -1028,10 +1028,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>recovery.trigger</> in the cluster data
+ directory. You might also want to temporarily modify <filename>pg_hba.conf</>
+ to prevent ordinary users from connecting until you are sure the recovery
+ was successful.
</para>
</listitem>
<listitem>
@@ -1040,10 +1047,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>recovery.trigger</> (to prevent accidentally re-entering
+ recovery mode later) and then commence normal database operations.
</para>
</listitem>
<listitem>
@@ -1057,12 +1063,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
@@ -1116,7 +1121,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
@@ -1213,8 +1218,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 77a9303..07103e7 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -2151,6 +2151,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>recovery.trigger</> 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>
@@ -2371,6 +2677,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>recovery.trigger</> exists.
+ The default value is <literal>off</>.
+ If this parameter is <literal>on</>, the server will not
+ stop recovery when the end of archived WAL is reached,
+ but will keep trying to continue recovery by fetching new WAL segments
+ using <varname>restore_command</> and/or by connecting to
+ the primary server as specified by the <varname>primary_conninfo</>
+ setting.
+ </para>
+ <para>
+ This parameter can only be set at server start. It only has effect
+ if file <filename>recovery.trigger</> exists.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="guc-primary-conninfo" xreflabel="primary_conninfo">
+ <term><varname>primary_conninfo</varname> (<type>string</type>)</term>
+ <indexterm>
+ <primary><varname>primary_conninfo</> configuration parameter</primary>
+ </indexterm>
+ <listitem>
+ <para>
+ Specifies a connection string to be used for the standby server
+ to connect with the primary. This string is in the format
+ accepted by the libpq <function>PQconnectdb</function> function,
+ described in <xref linkend="libpq-connect">. If any option is
+ unspecified in this string, then the corresponding environment
+ variable (see <xref linkend="libpq-envars">) is checked. If the
+ environment variable is not set either, then defaults are used.
+ If this parameter is an empty string (the default), no attempt is
+ made to connect to the master.
+ </para>
+ <para>
+ The connection string should specify the host name (or address)
+ of the primary server, as well as the port number if it is not
+ the same as the standby server's default.
+ Also specify a user name corresponding to a role that has the
+ <literal>REPLICATION</> and <literal>LOGIN</> privileges on the
+ primary (see
+ <xref linkend="streaming-replication-authentication">).
+ A password needs to be provided too, if the primary demands password
+ authentication. It can be provided in the
+ <varname>primary_conninfo</varname> string, or in a separate
+ <filename>~/.pgpass</> file on the standby server (use
+ <literal>replication</> as the database name).
+ Do not specify a database name in the
+ <varname>primary_conninfo</varname> string.
+ </para>
+ <para>
+ This parameter can only be set in the <filename>postgresql.conf</>
+ file or on the server command line. It only has effect in standby mode.
+ </para>
+ <para>
+ If this parameter is changed while replication is in progress,
+ the standby terminates replication, and then tries to restart
+ replication with new setting.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="guc-trigger-file" xreflabel="trigger_file">
+ <term><varname>trigger_file</varname> (<type>string</type>)</term>
+ <indexterm>
+ <primary><varname>trigger_file</> configuration parameter</primary>
+ </indexterm>
+ <listitem>
+ <para>
+ Specifies a trigger file whose presence ends recovery in the
+ standby. Even if this value is not set, you can still promote
+ the standby using <command>pg_ctl promote</>.
+ </para>
+ <para>
+ This parameter can only be set in the <filename>postgresql.conf</>
+ file or on the server command line. It only has effect in standby mode.
+ </para>
+ </listitem>
+ </varlistentry>
+
<varlistentry id="guc-hot-standby" xreflabel="hot_standby">
<term><varname>hot_standby</varname> (<type>boolean</type>)</term>
<indexterm>
diff --git a/doc/src/sgml/filelist.sgml b/doc/src/sgml/filelist.sgml
index d1b7dc6..7a59c51 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 89f08af..544c4a6 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -15438,7 +15438,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..8b02016 100644
--- a/doc/src/sgml/high-availability.sgml
+++ b/doc/src/sgml/high-availability.sgml
@@ -591,7 +591,7 @@ protocol to make nodes agree on a serializable transactional order.
<para>
In standby mode, the server continuously applies WAL received from the
master server. The standby server can read WAL from a WAL archive
- (see <xref linkend="restore-command">) or directly from the master
+ (see <xref linkend="guc-restore-command">) or directly from the master
over a TCP connection (streaming replication). The standby server will
also attempt to restore any WAL found in the standby cluster's
<filename>pg_xlog</> directory. That typically happens after a server
@@ -658,8 +658,8 @@ protocol to make nodes agree on a serializable transactional order.
<para>
To set up the standby server, restore the base backup taken from primary
server (see <xref linkend="backup-pitr-recovery">). Create a recovery
- command file <filename>recovery.conf</> in the standby's cluster data
- directory, and turn on <varname>standby_mode</>. Set
+ trigger file <filename>recovery.trigger</> in the standby's cluster data
+ directory. Turn on <varname>standby_mode</> and set
<varname>restore_command</> to a simple command to copy files from
the WAL archive. If you plan to have multiple standby servers for high
availability purposes, set <varname>recovery_target_timeline</> to
@@ -695,7 +695,7 @@ protocol to make nodes agree on a serializable transactional order.
<para>
If you're using a WAL archive, its size can be minimized using the <xref
- linkend="archive-cleanup-command"> parameter to remove files that are no
+ linkend="guc-archive-cleanup-command"> parameter to remove files that are no
longer required by the standby server.
The <application>pg_archivecleanup</> utility is designed specifically to
be used with <varname>archive_cleanup_command</> in typical single-standby
@@ -706,7 +706,7 @@ protocol to make nodes agree on a serializable transactional order.
</para>
<para>
- A simple example of a <filename>recovery.conf</> is:
+ A simple example of standby settings is:
<programlisting>
standby_mode = 'on'
primary_conninfo = 'host=192.168.1.50 port=5432 user=foo password=foopass'
@@ -763,8 +763,8 @@ archive_cleanup_command = 'pg_archivecleanup /path/to/archive %r'
To use streaming replication, set up a file-based log-shipping standby
server as described in <xref linkend="warm-standby">. The step that
turns a file-based log-shipping standby into streaming replication
- standby is setting <varname>primary_conninfo</> setting in the
- <filename>recovery.conf</> file to point to the primary server. Set
+ standby is setting <varname>primary_conninfo</> to
+ point to the primary server. Set
<xref linkend="guc-listen-addresses"> and authentication options
(see <filename>pg_hba.conf</>) on the primary so that the standby server
can connect to the <literal>replication</> pseudo-database on the primary
@@ -824,15 +824,14 @@ host replication foo 192.168.1.100/32 md5
</para>
<para>
The host name and port number of the primary, connection user name,
- and password are specified in the <filename>recovery.conf</> file.
+ and password are specified in <varname>primary_conninfo</>.
The password can also be set in the <filename>~/.pgpass</> file on the
standby (specify <literal>replication</> in the <replaceable>database</>
field).
For example, if the primary is running on host IP <literal>192.168.1.50</>,
port <literal>5432</literal>, the account name for replication is
<literal>foo</>, and the password is <literal>foopass</>, the administrator
- can add the following line to the <filename>recovery.conf</> file on the
- standby:
+ can set <varname>primary_conninfo</> on the standby like this:
<programlisting>
# The standby connects to the primary that is running on host 192.168.1.50
@@ -1212,8 +1211,8 @@ primary_conninfo = 'host=192.168.1.50 port=5432 user=foo password=foopass'
<para>
To trigger failover of a log-shipping standby server,
run <command>pg_ctl promote</> or create a trigger
- file with the file name and path specified by the <varname>trigger_file</>
- setting in <filename>recovery.conf</>. If you're planning to use
+ file with the file name and path specified by the <varname>trigger_file</>.
+ If you're planning to use
<command>pg_ctl promote</> to fail over, <varname>trigger_file</> is
not required. If you're setting up the reporting servers that are
only used to offload read-only queries from the primary, not for high
@@ -1258,8 +1257,7 @@ primary_conninfo = 'host=192.168.1.50 port=5432 user=foo password=foopass'
The magic that makes the two loosely coupled servers work together is
simply a <varname>restore_command</> used on the standby that,
when asked for the next WAL file, waits for it to become available from
- the primary. The <varname>restore_command</> is specified in the
- <filename>recovery.conf</> file on the standby server. Normal recovery
+ the primary. Normal recovery
processing would request a file from the WAL archive, reporting failure
if the file was unavailable. For standby processing it is normal for
the next WAL file to be unavailable, so the standby must wait for
@@ -1346,8 +1344,14 @@ if (!triggered)
</listitem>
<listitem>
<para>
+ Create a file called <filename>recovery.trigger</> 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>recovery.trigger</> present, the server will run in Hot Standby mode.
However, it may take some time for Hot Standby connections to be allowed,
because the server will not accept connections until it has completed
sufficient recovery to provide a consistent state against which queries
diff --git a/doc/src/sgml/pgarchivecleanup.sgml b/doc/src/sgml/pgarchivecleanup.sgml
index 932914b..2984da4 100644
--- a/doc/src/sgml/pgarchivecleanup.sgml
+++ b/doc/src/sgml/pgarchivecleanup.sgml
@@ -38,8 +38,8 @@
<para>
To configure a standby
- server to use <application>pg_archivecleanup</>, put this into its
- <filename>recovery.conf</filename> configuration file:
+ server to use <application>pg_archivecleanup</>, specify
+ <xref linkend="guc-archive-cleanup-command"> like this:
<programlisting>
archive_cleanup_command = 'pg_archivecleanup <replaceable>archivelocation</> %r'
</programlisting>
@@ -47,7 +47,7 @@ archive_cleanup_command = 'pg_archivecleanup <replaceable>archivelocation</> %r'
files should be removed.
</para>
<para>
- When used within <xref linkend="archive-cleanup-command">, all WAL files
+ When used within <varname>archive_cleanup_command</>, all WAL files
logically preceding the value of the <literal>%r</> argument will be removed
from <replaceable>archivelocation</>. This minimizes the number of files
that need to be retained, while preserving crash-restart capability. Use of
diff --git a/doc/src/sgml/pgstandby.sgml b/doc/src/sgml/pgstandby.sgml
index ca2b5c0..15097ca 100644
--- a/doc/src/sgml/pgstandby.sgml
+++ b/doc/src/sgml/pgstandby.sgml
@@ -46,8 +46,8 @@
<para>
To configure a standby
- server to use <application>pg_standby</>, put this into its
- <filename>recovery.conf</filename> configuration file:
+ server to use <application>pg_standby</>, specify
+ <xref linkend="guc-restore-command"> like this:
<programlisting>
restore_command = 'pg_standby <replaceable>archiveDir</> %f %p %r'
</programlisting>
diff --git a/doc/src/sgml/postgres.sgml b/doc/src/sgml/postgres.sgml
index 522316c..b2e089b 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..31de46e 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>recovery.trigger</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 051ab69..8d137f0 100644
--- a/doc/src/sgml/release-9.1.sgml
+++ b/doc/src/sgml/release-9.1.sgml
@@ -4939,7 +4939,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>
@@ -4959,7 +4959,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>
@@ -4991,8 +4991,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..68f1ce9 100644
--- a/doc/src/sgml/release.sgml
+++ b/doc/src/sgml/release.sgml
@@ -5,8 +5,8 @@ Typical markup:
&<> use & escapes
PostgreSQL <productname>
-postgresql.conf, pg_hba.conf,
- recovery.conf <filename>
+postgresql.conf, pg_hba.conf
+ recovery.trigger <filename>
[A-Z][A-Z_ ]+[A-Z_] <command>, <literal>, <envar>, <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 a95149b..75be1b2 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 RECOVERY_ENABLE_FILE "recovery.trigger"
#define PROMOTE_SIGNAL_FILE "promote"
#define FALLBACK_PROMOTE_SIGNAL_FILE "fallback_promote"
+/* recovery.conf is not supported anymore */
+#define RECOVERY_COMMAND_FILE "recovery.conf"
/* User-settable parameters */
int CheckPointSegments = 3;
@@ -77,6 +78,7 @@ int XLOGbuffers = -1;
int XLogArchiveTimeout = 0;
bool XLogArchiveMode = false;
char *XLogArchiveCommand = NULL;
+char *XLogRestoreCommand = NULL;
bool EnableHotStandby = false;
bool fullPageWrites = true;
bool log_checkpoints = false;
@@ -84,8 +86,24 @@ 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 *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.
*/
@@ -726,7 +719,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);
@@ -4439,7 +4432,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 */
@@ -5291,212 +5284,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 (recovery.trigger).
+ * If so, validate recovery parameters and determine recovery target timeline.
*/
static void
-readRecoveryCommandFile(void)
+CheckRecoveryReadyFile(void)
{
- FILE *fd;
- TimeLineID rtli = 0;
- bool rtliGiven = false;
- ConfigVariable *item,
- *head = NULL,
- *tail = NULL;
-
- fd = AllocateFile(RECOVERY_COMMAND_FILE, "r");
+ FILE *fd;
+
+ /* Check the presence of recovery.conf, it is not supported anymore */
+ if (AllocateFile(RECOVERY_COMMAND_FILE, "r") != NULL)
+ ereport(FATAL,
+ (errmsg("\"%s\" is not supported anymore as a recovery method",
+ RECOVERY_COMMAND_FILE),
+ errdetail("Refer to appropriate documentation about migration methods")));
+
+ /* Check the presence of file recovery.trigger, 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 (!XLogRestoreCommand[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 (!XLogRestoreCommand[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 */
@@ -5508,16 +5336,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
@@ -5527,8 +5356,6 @@ readRecoveryCommandFile(void)
recoveryTargetIsLatest = true;
}
}
-
- FreeConfigVariables(head);
}
/*
@@ -5599,15 +5426,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")));
@@ -5670,7 +5495,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
@@ -5681,7 +5506,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
@@ -5692,17 +5517,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
@@ -5717,10 +5542,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;
}
@@ -6085,36 +5910,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")));
@@ -6124,7 +5941,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 */
@@ -6146,7 +5963,7 @@ StartupXLOG(void)
* archive recovery directly.
*/
InArchiveRecovery = true;
- if (StandbyModeRequested)
+ if (ArchiveRecoveryRequested && StandbyModeRequested)
StandbyMode = true;
/*
@@ -6212,7 +6029,7 @@ StartupXLOG(void)
ControlFile->state == DB_SHUTDOWNED))
{
InArchiveRecovery = true;
- if (StandbyModeRequested)
+ if (ArchiveRecoveryRequested && StandbyModeRequested)
StandbyMode = true;
}
@@ -6373,7 +6190,7 @@ StartupXLOG(void)
/*
* Check whether we need to force recovery from WAL. If it appears to
- * have been a clean shutdown and we did not have a recovery.conf file,
+ * have been a clean shutdown and we did not have a recovery.trigger file,
* then assume no recovery needed.
*/
if (checkPoint.redo < RecPtr)
@@ -6387,7 +6204,7 @@ StartupXLOG(void)
InRecovery = true;
else if (ArchiveRecoveryRequested)
{
- /* force recovery due to presence of recovery.conf */
+ /* force recovery due to presence of recovery.trigger */
InRecovery = true;
}
@@ -6710,7 +6527,7 @@ StartupXLOG(void)
*/
if (recoveryStopsHere(record, &recoveryApply))
{
- if (recoveryPauseAtTarget)
+ if (pause_at_recovery_target)
{
SetRecoveryPause(true);
recoveryPausesHere();
@@ -6874,7 +6691,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);
/*
@@ -6964,17 +6781,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);
@@ -7145,8 +6962,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);
}
@@ -8689,8 +8506,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);
@@ -10549,7 +10366,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))
{
@@ -10766,7 +10583,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;
@@ -10787,7 +10604,7 @@ WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess,
tli, curFileTLI);
}
curFileTLI = tli;
- RequestXLogStreaming(tli, ptr, PrimaryConnInfo);
+ RequestXLogStreaming(tli, ptr, primary_conninfo);
receivedUpto = 0;
}
@@ -11102,14 +10919,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..3e779b9 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 (XLogRestoreCommand == 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 = XLogRestoreCommand; *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 54d8078..67f5c8e 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 bool data_checksums;
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
@@ -2609,6 +2654,97 @@ static struct config_string ConfigureNamesString[] =
},
{
+ {"restore_command", PGC_SIGHUP, WAL_ARCHIVE_RECOVERY,
+ gettext_noop("Sets the shell command that will retrieve an archived WAL file."),
+ NULL
+ },
+ &XLogRestoreCommand,
+ "",
+ 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,
@@ -8896,4 +9032,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 34a2d05..d7df4f3 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -206,6 +206,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
@@ -248,6 +265,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 a1e12a8..ec3d98b 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 recovery.trigger 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 recovery.trigger 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, "recovery.trigger", 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 recovery.trigger, or when not working on the base
+ * tablespace, we never have to look for an existing recovery.trigger
* 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 recovery.trigger 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
+ * recovery.trigger - 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], "recovery.trigger") == 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 recovery.trigger 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/recovery.trigger", 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 8399cdd..e10a4ad 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
+ * recovery.trigger 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
+ * recovery.trigger 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 recovery.trigger doesn't exist, the server is not in standby mode */
if (stat(recovery_file, &statbuf) != 0)
{
write_stderr(_("%s: cannot promote server; "
@@ -2229,7 +2229,7 @@ main(int argc, char **argv)
snprintf(postopts_file, MAXPGPATH, "%s/postmaster.opts", pg_data);
snprintf(pid_file, MAXPGPATH, "%s/postmaster.pid", pg_data);
snprintf(backup_file, MAXPGPATH, "%s/backup_label", pg_data);
- snprintf(recovery_file, MAXPGPATH, "%s/recovery.conf", pg_data);
+ snprintf(recovery_file, MAXPGPATH, "%s/recovery.trigger", pg_data);
}
switch (ctl_command)
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index 002862c..9bb286c 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -187,9 +187,23 @@ extern int XLOGbuffers;
extern int XLogArchiveTimeout;
extern bool XLogArchiveMode;
extern char *XLogArchiveCommand;
+extern char *XLogRestoreCommand;
extern bool EnableHotStandby;
extern bool fullPageWrites;
extern bool log_checkpoints;
+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,
On 11/13/13, 12:17 AM, Jaime Casanova wrote:
I have rebased Michael Paquier's patch and did a few changes:
* changed standby.enabled filename to recovery.trigger
* make archive_command a SIGHUP parameter again
* make restore_command a SIGHUP parameter
* rename restore_command variable to XLogRestoreCommand to match
XLogArchiveCommand
Please check for compiler warnings in pg_basebackup:
pg_basebackup.c:1109:1: warning: �escapeConnectionParameter� defined but not used [-Wunused-function]
pg_basebackup.c:1168:1: warning: �escape_quotes� defined but not used [-Wunused-function]
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Fri, Nov 15, 2013 at 9:28 AM, Peter Eisentraut <peter_e@gmx.net> wrote:
On 11/13/13, 12:17 AM, Jaime Casanova wrote:
I have rebased Michael Paquier's patch and did a few changes:
* changed standby.enabled filename to recovery.trigger
* make archive_command a SIGHUP parameter again
* make restore_command a SIGHUP parameter
* rename restore_command variable to XLogRestoreCommand to match
XLogArchiveCommandPlease check for compiler warnings in pg_basebackup:
pg_basebackup.c:1109:1: warning: ‘escapeConnectionParameter’ defined but not used [-Wunused-function]
pg_basebackup.c:1168:1: warning: ‘escape_quotes’ defined but not used [-Wunused-function]
those are functions that are no longer used but Josh considered they
could become useful before release.
i can put them inside #ifdef _NOT_USED_ decorations or just remove
them now and if/when we find some use for them re add them
--
Jaime Casanova www.2ndQuadrant.com
Professional PostgreSQL: Soporte 24x7 y capacitación
Phone: +593 4 5107566 Cell: +593 987171157
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Fri, Nov 15, 2013 at 11:38 PM, Jaime Casanova <jaime@2ndquadrant.com> wrote:
those are functions that are no longer used but Josh considered they
could become useful before release.
i can put them inside #ifdef _NOT_USED_ decorations or just remove
them now and if/when we find some use for them re add them
Why not simply removing them? They will be kept in the git history either way.
--
Michael
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 11/15/2013 06:38 AM, Jaime Casanova wrote:
Please check for compiler warnings in pg_basebackup:
pg_basebackup.c:1109:1: warning: ‘escapeConnectionParameter’ defined but not used [-Wunused-function]
pg_basebackup.c:1168:1: warning: ‘escape_quotes’ defined but not used [-Wunused-function]those are functions that are no longer used but Josh considered they
could become useful before release.
i can put them inside #ifdef _NOT_USED_ decorations or just remove
them now and if/when we find some use for them re add them
Wait, which Josh? Not me ...
--
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
Import Notes
Reply to msg id not found: WM0708045e0cd4e30b58b63ca4500b439a99ff022446374e466fb2e2ff59e40caa786f790e10813a5f5ce879c3552aa422@asav-3.01.com
On Fri, Nov 15, 2013 at 4:11 PM, Josh Berkus <josh@agliodbs.com> wrote:
On 11/15/2013 06:38 AM, Jaime Casanova wrote:
Please check for compiler warnings in pg_basebackup:
pg_basebackup.c:1109:1: warning: ‘escapeConnectionParameter’ defined but not used [-Wunused-function]
pg_basebackup.c:1168:1: warning: ‘escape_quotes’ defined but not used [-Wunused-function]those are functions that are no longer used but Josh considered they
could become useful before release.
i can put them inside #ifdef _NOT_USED_ decorations or just remove
them now and if/when we find some use for them re add themWait, which Josh? Not me ...
sorry, i clearly misunderstood you. attached a rebased patch with
those functions removed.
--
Jaime Casanova www.2ndQuadrant.com
Professional PostgreSQL: Soporte 24x7 y capacitación
Phone: +593 4 5107566 Cell: +593 987171157
Attachments:
recovery_guc_v5.1.patchtext/x-patch; charset=US-ASCII; name=recovery_guc_v5.1.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 059c820..907346e 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 1712974..6bad86f 100644
--- a/doc/src/sgml/backup.sgml
+++ b/doc/src/sgml/backup.sgml
@@ -1028,10 +1028,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>recovery.trigger</> in the cluster data
+ directory. You might also want to temporarily modify <filename>pg_hba.conf</>
+ to prevent ordinary users from connecting until you are sure the recovery
+ was successful.
</para>
</listitem>
<listitem>
@@ -1040,10 +1047,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>recovery.trigger</> (to prevent accidentally re-entering
+ recovery mode later) and then commence normal database operations.
</para>
</listitem>
<listitem>
@@ -1057,12 +1063,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
@@ -1116,7 +1121,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
@@ -1213,8 +1218,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 77a9303..07103e7 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -2151,6 +2151,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>recovery.trigger</> 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>
@@ -2371,6 +2677,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>recovery.trigger</> exists.
+ The default value is <literal>off</>.
+ If this parameter is <literal>on</>, the server will not
+ stop recovery when the end of archived WAL is reached,
+ but will keep trying to continue recovery by fetching new WAL segments
+ using <varname>restore_command</> and/or by connecting to
+ the primary server as specified by the <varname>primary_conninfo</>
+ setting.
+ </para>
+ <para>
+ This parameter can only be set at server start. It only has effect
+ if file <filename>recovery.trigger</> exists.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="guc-primary-conninfo" xreflabel="primary_conninfo">
+ <term><varname>primary_conninfo</varname> (<type>string</type>)</term>
+ <indexterm>
+ <primary><varname>primary_conninfo</> configuration parameter</primary>
+ </indexterm>
+ <listitem>
+ <para>
+ Specifies a connection string to be used for the standby server
+ to connect with the primary. This string is in the format
+ accepted by the libpq <function>PQconnectdb</function> function,
+ described in <xref linkend="libpq-connect">. If any option is
+ unspecified in this string, then the corresponding environment
+ variable (see <xref linkend="libpq-envars">) is checked. If the
+ environment variable is not set either, then defaults are used.
+ If this parameter is an empty string (the default), no attempt is
+ made to connect to the master.
+ </para>
+ <para>
+ The connection string should specify the host name (or address)
+ of the primary server, as well as the port number if it is not
+ the same as the standby server's default.
+ Also specify a user name corresponding to a role that has the
+ <literal>REPLICATION</> and <literal>LOGIN</> privileges on the
+ primary (see
+ <xref linkend="streaming-replication-authentication">).
+ A password needs to be provided too, if the primary demands password
+ authentication. It can be provided in the
+ <varname>primary_conninfo</varname> string, or in a separate
+ <filename>~/.pgpass</> file on the standby server (use
+ <literal>replication</> as the database name).
+ Do not specify a database name in the
+ <varname>primary_conninfo</varname> string.
+ </para>
+ <para>
+ This parameter can only be set in the <filename>postgresql.conf</>
+ file or on the server command line. It only has effect in standby mode.
+ </para>
+ <para>
+ If this parameter is changed while replication is in progress,
+ the standby terminates replication, and then tries to restart
+ replication with new setting.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="guc-trigger-file" xreflabel="trigger_file">
+ <term><varname>trigger_file</varname> (<type>string</type>)</term>
+ <indexterm>
+ <primary><varname>trigger_file</> configuration parameter</primary>
+ </indexterm>
+ <listitem>
+ <para>
+ Specifies a trigger file whose presence ends recovery in the
+ standby. Even if this value is not set, you can still promote
+ the standby using <command>pg_ctl promote</>.
+ </para>
+ <para>
+ This parameter can only be set in the <filename>postgresql.conf</>
+ file or on the server command line. It only has effect in standby mode.
+ </para>
+ </listitem>
+ </varlistentry>
+
<varlistentry id="guc-hot-standby" xreflabel="hot_standby">
<term><varname>hot_standby</varname> (<type>boolean</type>)</term>
<indexterm>
diff --git a/doc/src/sgml/filelist.sgml b/doc/src/sgml/filelist.sgml
index d1b7dc6..7a59c51 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 89f08af..544c4a6 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -15438,7 +15438,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..8b02016 100644
--- a/doc/src/sgml/high-availability.sgml
+++ b/doc/src/sgml/high-availability.sgml
@@ -591,7 +591,7 @@ protocol to make nodes agree on a serializable transactional order.
<para>
In standby mode, the server continuously applies WAL received from the
master server. The standby server can read WAL from a WAL archive
- (see <xref linkend="restore-command">) or directly from the master
+ (see <xref linkend="guc-restore-command">) or directly from the master
over a TCP connection (streaming replication). The standby server will
also attempt to restore any WAL found in the standby cluster's
<filename>pg_xlog</> directory. That typically happens after a server
@@ -658,8 +658,8 @@ protocol to make nodes agree on a serializable transactional order.
<para>
To set up the standby server, restore the base backup taken from primary
server (see <xref linkend="backup-pitr-recovery">). Create a recovery
- command file <filename>recovery.conf</> in the standby's cluster data
- directory, and turn on <varname>standby_mode</>. Set
+ trigger file <filename>recovery.trigger</> in the standby's cluster data
+ directory. Turn on <varname>standby_mode</> and set
<varname>restore_command</> to a simple command to copy files from
the WAL archive. If you plan to have multiple standby servers for high
availability purposes, set <varname>recovery_target_timeline</> to
@@ -695,7 +695,7 @@ protocol to make nodes agree on a serializable transactional order.
<para>
If you're using a WAL archive, its size can be minimized using the <xref
- linkend="archive-cleanup-command"> parameter to remove files that are no
+ linkend="guc-archive-cleanup-command"> parameter to remove files that are no
longer required by the standby server.
The <application>pg_archivecleanup</> utility is designed specifically to
be used with <varname>archive_cleanup_command</> in typical single-standby
@@ -706,7 +706,7 @@ protocol to make nodes agree on a serializable transactional order.
</para>
<para>
- A simple example of a <filename>recovery.conf</> is:
+ A simple example of standby settings is:
<programlisting>
standby_mode = 'on'
primary_conninfo = 'host=192.168.1.50 port=5432 user=foo password=foopass'
@@ -763,8 +763,8 @@ archive_cleanup_command = 'pg_archivecleanup /path/to/archive %r'
To use streaming replication, set up a file-based log-shipping standby
server as described in <xref linkend="warm-standby">. The step that
turns a file-based log-shipping standby into streaming replication
- standby is setting <varname>primary_conninfo</> setting in the
- <filename>recovery.conf</> file to point to the primary server. Set
+ standby is setting <varname>primary_conninfo</> to
+ point to the primary server. Set
<xref linkend="guc-listen-addresses"> and authentication options
(see <filename>pg_hba.conf</>) on the primary so that the standby server
can connect to the <literal>replication</> pseudo-database on the primary
@@ -824,15 +824,14 @@ host replication foo 192.168.1.100/32 md5
</para>
<para>
The host name and port number of the primary, connection user name,
- and password are specified in the <filename>recovery.conf</> file.
+ and password are specified in <varname>primary_conninfo</>.
The password can also be set in the <filename>~/.pgpass</> file on the
standby (specify <literal>replication</> in the <replaceable>database</>
field).
For example, if the primary is running on host IP <literal>192.168.1.50</>,
port <literal>5432</literal>, the account name for replication is
<literal>foo</>, and the password is <literal>foopass</>, the administrator
- can add the following line to the <filename>recovery.conf</> file on the
- standby:
+ can set <varname>primary_conninfo</> on the standby like this:
<programlisting>
# The standby connects to the primary that is running on host 192.168.1.50
@@ -1212,8 +1211,8 @@ primary_conninfo = 'host=192.168.1.50 port=5432 user=foo password=foopass'
<para>
To trigger failover of a log-shipping standby server,
run <command>pg_ctl promote</> or create a trigger
- file with the file name and path specified by the <varname>trigger_file</>
- setting in <filename>recovery.conf</>. If you're planning to use
+ file with the file name and path specified by the <varname>trigger_file</>.
+ If you're planning to use
<command>pg_ctl promote</> to fail over, <varname>trigger_file</> is
not required. If you're setting up the reporting servers that are
only used to offload read-only queries from the primary, not for high
@@ -1258,8 +1257,7 @@ primary_conninfo = 'host=192.168.1.50 port=5432 user=foo password=foopass'
The magic that makes the two loosely coupled servers work together is
simply a <varname>restore_command</> used on the standby that,
when asked for the next WAL file, waits for it to become available from
- the primary. The <varname>restore_command</> is specified in the
- <filename>recovery.conf</> file on the standby server. Normal recovery
+ the primary. Normal recovery
processing would request a file from the WAL archive, reporting failure
if the file was unavailable. For standby processing it is normal for
the next WAL file to be unavailable, so the standby must wait for
@@ -1346,8 +1344,14 @@ if (!triggered)
</listitem>
<listitem>
<para>
+ Create a file called <filename>recovery.trigger</> 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>recovery.trigger</> present, the server will run in Hot Standby mode.
However, it may take some time for Hot Standby connections to be allowed,
because the server will not accept connections until it has completed
sufficient recovery to provide a consistent state against which queries
diff --git a/doc/src/sgml/pgarchivecleanup.sgml b/doc/src/sgml/pgarchivecleanup.sgml
index 932914b..2984da4 100644
--- a/doc/src/sgml/pgarchivecleanup.sgml
+++ b/doc/src/sgml/pgarchivecleanup.sgml
@@ -38,8 +38,8 @@
<para>
To configure a standby
- server to use <application>pg_archivecleanup</>, put this into its
- <filename>recovery.conf</filename> configuration file:
+ server to use <application>pg_archivecleanup</>, specify
+ <xref linkend="guc-archive-cleanup-command"> like this:
<programlisting>
archive_cleanup_command = 'pg_archivecleanup <replaceable>archivelocation</> %r'
</programlisting>
@@ -47,7 +47,7 @@ archive_cleanup_command = 'pg_archivecleanup <replaceable>archivelocation</> %r'
files should be removed.
</para>
<para>
- When used within <xref linkend="archive-cleanup-command">, all WAL files
+ When used within <varname>archive_cleanup_command</>, all WAL files
logically preceding the value of the <literal>%r</> argument will be removed
from <replaceable>archivelocation</>. This minimizes the number of files
that need to be retained, while preserving crash-restart capability. Use of
diff --git a/doc/src/sgml/pgstandby.sgml b/doc/src/sgml/pgstandby.sgml
index ca2b5c0..15097ca 100644
--- a/doc/src/sgml/pgstandby.sgml
+++ b/doc/src/sgml/pgstandby.sgml
@@ -46,8 +46,8 @@
<para>
To configure a standby
- server to use <application>pg_standby</>, put this into its
- <filename>recovery.conf</filename> configuration file:
+ server to use <application>pg_standby</>, specify
+ <xref linkend="guc-restore-command"> like this:
<programlisting>
restore_command = 'pg_standby <replaceable>archiveDir</> %f %p %r'
</programlisting>
diff --git a/doc/src/sgml/postgres.sgml b/doc/src/sgml/postgres.sgml
index 522316c..b2e089b 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..31de46e 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>recovery.trigger</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 051ab69..8d137f0 100644
--- a/doc/src/sgml/release-9.1.sgml
+++ b/doc/src/sgml/release-9.1.sgml
@@ -4939,7 +4939,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>
@@ -4959,7 +4959,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>
@@ -4991,8 +4991,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..68f1ce9 100644
--- a/doc/src/sgml/release.sgml
+++ b/doc/src/sgml/release.sgml
@@ -5,8 +5,8 @@ Typical markup:
&<> use & escapes
PostgreSQL <productname>
-postgresql.conf, pg_hba.conf,
- recovery.conf <filename>
+postgresql.conf, pg_hba.conf
+ recovery.trigger <filename>
[A-Z][A-Z_ ]+[A-Z_] <command>, <literal>, <envar>, <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 a95149b..75be1b2 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 RECOVERY_ENABLE_FILE "recovery.trigger"
#define PROMOTE_SIGNAL_FILE "promote"
#define FALLBACK_PROMOTE_SIGNAL_FILE "fallback_promote"
+/* recovery.conf is not supported anymore */
+#define RECOVERY_COMMAND_FILE "recovery.conf"
/* User-settable parameters */
int CheckPointSegments = 3;
@@ -77,6 +78,7 @@ int XLOGbuffers = -1;
int XLogArchiveTimeout = 0;
bool XLogArchiveMode = false;
char *XLogArchiveCommand = NULL;
+char *XLogRestoreCommand = NULL;
bool EnableHotStandby = false;
bool fullPageWrites = true;
bool log_checkpoints = false;
@@ -84,8 +86,24 @@ 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 *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.
*/
@@ -726,7 +719,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);
@@ -4439,7 +4432,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 */
@@ -5291,212 +5284,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 (recovery.trigger).
+ * If so, validate recovery parameters and determine recovery target timeline.
*/
static void
-readRecoveryCommandFile(void)
+CheckRecoveryReadyFile(void)
{
- FILE *fd;
- TimeLineID rtli = 0;
- bool rtliGiven = false;
- ConfigVariable *item,
- *head = NULL,
- *tail = NULL;
-
- fd = AllocateFile(RECOVERY_COMMAND_FILE, "r");
+ FILE *fd;
+
+ /* Check the presence of recovery.conf, it is not supported anymore */
+ if (AllocateFile(RECOVERY_COMMAND_FILE, "r") != NULL)
+ ereport(FATAL,
+ (errmsg("\"%s\" is not supported anymore as a recovery method",
+ RECOVERY_COMMAND_FILE),
+ errdetail("Refer to appropriate documentation about migration methods")));
+
+ /* Check the presence of file recovery.trigger, 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 (!XLogRestoreCommand[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 (!XLogRestoreCommand[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 */
@@ -5508,16 +5336,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
@@ -5527,8 +5356,6 @@ readRecoveryCommandFile(void)
recoveryTargetIsLatest = true;
}
}
-
- FreeConfigVariables(head);
}
/*
@@ -5599,15 +5426,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")));
@@ -5670,7 +5495,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
@@ -5681,7 +5506,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
@@ -5692,17 +5517,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
@@ -5717,10 +5542,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;
}
@@ -6085,36 +5910,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")));
@@ -6124,7 +5941,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 */
@@ -6146,7 +5963,7 @@ StartupXLOG(void)
* archive recovery directly.
*/
InArchiveRecovery = true;
- if (StandbyModeRequested)
+ if (ArchiveRecoveryRequested && StandbyModeRequested)
StandbyMode = true;
/*
@@ -6212,7 +6029,7 @@ StartupXLOG(void)
ControlFile->state == DB_SHUTDOWNED))
{
InArchiveRecovery = true;
- if (StandbyModeRequested)
+ if (ArchiveRecoveryRequested && StandbyModeRequested)
StandbyMode = true;
}
@@ -6373,7 +6190,7 @@ StartupXLOG(void)
/*
* Check whether we need to force recovery from WAL. If it appears to
- * have been a clean shutdown and we did not have a recovery.conf file,
+ * have been a clean shutdown and we did not have a recovery.trigger file,
* then assume no recovery needed.
*/
if (checkPoint.redo < RecPtr)
@@ -6387,7 +6204,7 @@ StartupXLOG(void)
InRecovery = true;
else if (ArchiveRecoveryRequested)
{
- /* force recovery due to presence of recovery.conf */
+ /* force recovery due to presence of recovery.trigger */
InRecovery = true;
}
@@ -6710,7 +6527,7 @@ StartupXLOG(void)
*/
if (recoveryStopsHere(record, &recoveryApply))
{
- if (recoveryPauseAtTarget)
+ if (pause_at_recovery_target)
{
SetRecoveryPause(true);
recoveryPausesHere();
@@ -6874,7 +6691,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);
/*
@@ -6964,17 +6781,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);
@@ -7145,8 +6962,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);
}
@@ -8689,8 +8506,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);
@@ -10549,7 +10366,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))
{
@@ -10766,7 +10583,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;
@@ -10787,7 +10604,7 @@ WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess,
tli, curFileTLI);
}
curFileTLI = tli;
- RequestXLogStreaming(tli, ptr, PrimaryConnInfo);
+ RequestXLogStreaming(tli, ptr, primary_conninfo);
receivedUpto = 0;
}
@@ -11102,14 +10919,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..3e779b9 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 (XLogRestoreCommand == 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 = XLogRestoreCommand; *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 54d8078..67f5c8e 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 bool data_checksums;
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
@@ -2609,6 +2654,97 @@ static struct config_string ConfigureNamesString[] =
},
{
+ {"restore_command", PGC_SIGHUP, WAL_ARCHIVE_RECOVERY,
+ gettext_noop("Sets the shell command that will retrieve an archived WAL file."),
+ NULL
+ },
+ &XLogRestoreCommand,
+ "",
+ 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,
@@ -8896,4 +9032,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 34a2d05..d7df4f3 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -206,6 +206,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
@@ -248,6 +265,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 a1e12a8..72e3c21 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 recovery.trigger 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 recovery.trigger 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, "recovery.trigger", 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 recovery.trigger, or when not working on the base
+ * tablespace, we never have to look for an existing recovery.trigger
* 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 recovery.trigger 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
+ * recovery.trigger - 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], "recovery.trigger") == 0);
sscanf(&tarhdr[124], "%11o", (unsigned int *) &filesz);
@@ -1102,179 +1092,21 @@ ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum)
if (copybuf != NULL)
PQfreemem(copybuf);
- if (basetablespace && writerecoveryconf)
- WriteRecoveryConf();
-}
-
-/*
- * Escape a parameter value so that it can be used as part of a libpq
- * connection string, e.g. in:
- *
- * application_name=<value>
- *
- * The returned string is malloc'd. Return NULL on out-of-memory.
- */
-static char *
-escapeConnectionParameter(const char *src)
-{
- bool need_quotes = false;
- bool need_escaping = false;
- const char *p;
- char *dstbuf;
- char *dst;
-
- /*
- * First check if quoting is needed. Any quote (') or backslash (\)
- * characters need to be escaped. Parameters are separated by whitespace,
- * so any string containing whitespace characters need to be quoted. An
- * empty string is represented by ''.
- */
- if (strchr(src, '\'') != NULL || strchr(src, '\\') != NULL)
- need_escaping = true;
-
- for (p = src; *p; p++)
- {
- if (isspace((unsigned char) *p))
- {
- need_quotes = true;
- break;
- }
- }
-
- if (*src == '\0')
- return pg_strdup("''");
-
- if (!need_quotes && !need_escaping)
- return pg_strdup(src); /* no quoting or escaping needed */
-
- /*
- * Allocate a buffer large enough for the worst case that all the source
- * characters need to be escaped, plus quotes.
- */
- dstbuf = pg_malloc(strlen(src) * 2 + 2 + 1);
-
- dst = dstbuf;
- if (need_quotes)
- *(dst++) = '\'';
- for (; *src; src++)
- {
- if (*src == '\'' || *src == '\\')
- *(dst++) = '\\';
- *(dst++) = *src;
- }
- if (need_quotes)
- *(dst++) = '\'';
- *dst = '\0';
-
- return dstbuf;
-}
-
-/*
- * Escape a string so that it can be used as a value in a key-value pair
- * a configuration file.
- */
-static char *
-escape_quotes(const char *src)
-{
- char *result = escape_single_quotes_ascii(src);
-
- if (!result)
- {
- fprintf(stderr, _("%s: out of memory\n"), progname);
- exit(1);
- }
- return result;
-}
-
-/*
- * Create a recovery.conf file in memory using a PQExpBuffer
- */
-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);
+ if (basetablespace && writestandby)
+ WriteStandbyEnabled();
}
/*
- * Write a recovery.conf file into the directory specified in basedir,
- * with the contents already collected in memory.
+ * Write a recovery.trigger 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/recovery.trigger", basedir);
cf = fopen(filename, "w");
if (cf == NULL)
@@ -1283,14 +1115,6 @@ WriteRecoveryConf(void)
disconnect_and_exit(1);
}
- if (fwrite(recoveryconfcontents->data, recoveryconfcontents->len, 1, cf) != 1)
- {
- fprintf(stderr,
- _("%s: could not write to file \"%s\": %s\n"),
- progname, filename, strerror(errno));
- disconnect_and_exit(1);
- }
-
fclose(cf);
}
@@ -1346,12 +1170,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 +1446,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 +1466,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 +1527,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 8399cdd..e10a4ad 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
+ * recovery.trigger 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
+ * recovery.trigger 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 recovery.trigger doesn't exist, the server is not in standby mode */
if (stat(recovery_file, &statbuf) != 0)
{
write_stderr(_("%s: cannot promote server; "
@@ -2229,7 +2229,7 @@ main(int argc, char **argv)
snprintf(postopts_file, MAXPGPATH, "%s/postmaster.opts", pg_data);
snprintf(pid_file, MAXPGPATH, "%s/postmaster.pid", pg_data);
snprintf(backup_file, MAXPGPATH, "%s/backup_label", pg_data);
- snprintf(recovery_file, MAXPGPATH, "%s/recovery.conf", pg_data);
+ snprintf(recovery_file, MAXPGPATH, "%s/recovery.trigger", pg_data);
}
switch (ctl_command)
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index 002862c..9bb286c 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -187,9 +187,23 @@ extern int XLOGbuffers;
extern int XLogArchiveTimeout;
extern bool XLogArchiveMode;
extern char *XLogArchiveCommand;
+extern char *XLogRestoreCommand;
extern bool EnableHotStandby;
extern bool fullPageWrites;
extern bool log_checkpoints;
+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,
Hi,
On 2013-11-15 22:38:05 -0500, Jaime Casanova wrote:
sorry, i clearly misunderstood you. attached a rebased patch with
those functions removed.
* --write-standby-enable seems to loose quite some functionality in
comparison to --write-recovery-conf since it doesn't seem to set
primary_conninfo, standby anymore.
* CheckRecoveryReadyFile() doesn't seem to be a very descriptive
function name.
* Why does StartupXLOG() now use ArchiveRecoveryRequested &&
StandbyModeRequested instead of just the former?
* I am not sure I like "recovery.trigger" as a name. It seems to close
to what I've seen people use to trigger failover and too close to
trigger_file.
* You check for a trigger file in a way that's not compatible with it
being NULL. Why did you change that?
- if (TriggerFile == NULL)
+ if (!trigger_file[0])
* You made recovery_target_inclusive/pause_at_recovery_target PGC_SIGHUP
- did you review that actually works? Imo that should be changed in a
separate commit.
* Maybe we should rename names like pause_at_recovery_target to
recovery_pause_at_target? Since we already force everyone to bother
changing their setup...
* the description of archive_cleanup_command seems wrong to me.
* Why did you change some of the recovery gucs to lowercase names, but
left out XLogRestoreCommand?
* Why the PG_TRY/PG_CATCH in check_recovery_target_time? Besides being
really strangely formatted (multiline :? inside a function?) it
doesn't a) seem to be correct to ignore potential memory allocation
errors by just switching back into the context that just errored out,
and continue to work there b) forgo cleanup by just continuing as if
nothing happened. That's unlikely to be acceptable.
* You access recovery_target_name[0] unconditionally, although it's
intialized to NULL.
* Generally, ISTM there's too much logic in the assign hooks.
* Why do you include xlog_internal.h in guc.c and not xlog.h?
Ok, I think that's enough for now ;)
Greetings,
Andres Freund
--
Andres Freund 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
On Tue, Nov 19, 2013 at 2:27 AM, Andres Freund <andres@2ndquadrant.com> wrote:
* --write-standby-enable seems to loose quite some functionality in
comparison to --write-recovery-conf since it doesn't seem to set
primary_conninfo, standby anymore.
Yes... The idea here might be to generate a new file that is then
included in postgresql.conf or to add parameters at the bottom of
postgresql.conf itself. The code for plain base backup is
straight-forward, but it could get ugly for the tar part...
* CheckRecoveryReadyFile() doesn't seem to be a very descriptive
function name.
CheckRecoveryTriggerPresence?
* Why does StartupXLOG() now use ArchiveRecoveryRequested &&
StandbyModeRequested instead of just the former?
* I am not sure I like "recovery.trigger" as a name. It seems to close
to what I've seen people use to trigger failover and too close to
trigger_file.
This name was chosen and kept in accordance to the spec of this
feature. Looks fine for me...
* You made recovery_target_inclusive/pause_at_recovery_target PGC_SIGHUP
- did you review that actually works? Imo that should be changed in a
separate commit.
Yep, I'd rather see those parameters as PGC_POSTMASTER... As of now,
once recovery is started those parameter values do not change once
readRecoveryCommandFile is kicked. Having them SIGHUP would mean that
you could change them during recovery. Sounds kind of dangerous, no?
* Maybe we should rename names like pause_at_recovery_target to
recovery_pause_at_target? Since we already force everyone to bother
changing their setup...
I disagree here. It is true that this patch introduces many changes
with a new configuration file layer, but this idea with this patch was
to allow people to reuse their old recovery.conf as it is. And what is
actually wrong with pause_at_recovery_target?
* the description of archive_cleanup_command seems wrong to me.
* Why did you change some of the recovery gucs to lowercase names, but
left out XLogRestoreCommand?
This was part of the former patch, perhaps you are right and keeping
the names as close as possible to the old ones would make sense to
facilitate maintenance across versions.
* Why the PG_TRY/PG_CATCH in check_recovery_target_time? Besides being
really strangely formatted (multiline :? inside a function?) it
doesn't a) seem to be correct to ignore potential memory allocation
errors by just switching back into the context that just errored out,
and continue to work there b) forgo cleanup by just continuing as if
nothing happened. That's unlikely to be acceptable.
Interestingly, that was part of the first versions of the patch as
well. I don't recall modifying anything in this area when I hacked
that... But yes it should be modified to something like what is in
check_recovery_target_xid.
Regards,
--
Michael
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 2013-11-19 22:09:48 +0900, Michael Paquier wrote:
On Tue, Nov 19, 2013 at 2:27 AM, Andres Freund <andres@2ndquadrant.com> wrote:
* --write-standby-enable seems to loose quite some functionality in
comparison to --write-recovery-conf since it doesn't seem to set
primary_conninfo, standby anymore.
Yes... The idea here might be to generate a new file that is then
included in postgresql.conf or to add parameters at the bottom of
postgresql.conf itself. The code for plain base backup is
straight-forward, but it could get ugly for the tar part...
Well, just removing most of the feature - which the current patch seems
to be doing - looks like a regression to me, so it has to be either
fixed or explicitly discussed.
* CheckRecoveryReadyFile() doesn't seem to be a very descriptive
function name.
CheckRecoveryTriggerPresence?
CheckStartingAsStandby()? Recovery alone doesn't say very much.
* Why does StartupXLOG() now use ArchiveRecoveryRequested &&
StandbyModeRequested instead of just the former?
?
* I am not sure I like "recovery.trigger" as a name. It seems to close
to what I've seen people use to trigger failover and too close to
trigger_file.
This name was chosen and kept in accordance to the spec of this
feature. Looks fine for me...
I still think "start_as_standby.trigger" or such would be much clearer
and far less likely to be confused with the promotion trigger file.
* You made recovery_target_inclusive/pause_at_recovery_target PGC_SIGHUP
- did you review that actually works? Imo that should be changed in a
separate commit.Yep, I'd rather see those parameters as PGC_POSTMASTER... As of now,
once recovery is started those parameter values do not change once
readRecoveryCommandFile is kicked. Having them SIGHUP would mean that
you could change them during recovery. Sounds kind of dangerous, no?
I think it's desirable to make them changeable during recovery, but it's
a separate patch.
* Maybe we should rename names like pause_at_recovery_target to
recovery_pause_at_target? Since we already force everyone to bother
changing their setup...
I disagree here. It is true that this patch introduces many changes
with a new configuration file layer, but this idea with this patch was
to allow people to reuse their old recovery.conf as it is. And what is
actually wrong with pause_at_recovery_target?
That nearly all the other variables start with recovery_. But I don't
feel very strongly abou thtis.
* Why did you change some of the recovery gucs to lowercase names, but
left out XLogRestoreCommand?This was part of the former patch, perhaps you are right and keeping
the names as close as possible to the old ones would make sense to
facilitate maintenance across versions.
I think lowercase is slightly more consistent with the majority of the
other GUCs, but if you change it you should change all the new GUC variables.
Greetings,
Andres Freund
--
Andres Freund 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
Andres Freund <andres@2ndquadrant.com> writes:
On 2013-11-19 22:09:48 +0900, Michael Paquier wrote:
On Tue, Nov 19, 2013 at 2:27 AM, Andres Freund <andres@2ndquadrant.com> wrote:
* Why did you change some of the recovery gucs to lowercase names, but
left out XLogRestoreCommand?
This was part of the former patch, perhaps you are right and keeping
the names as close as possible to the old ones would make sense to
facilitate maintenance across versions.
I think lowercase is slightly more consistent with the majority of the
other GUCs, but if you change it you should change all the new GUC variables.
Please *don't* create any more mixed-case GUC names. The spelling of
TimeZone and the one or two other historical exceptions was a very
unfortunate thing; it's confused more people than it's helped.
Put in some underscores if you feel a need for word boundaries.
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
On Tue, Nov 19, 2013 at 3:32 PM, Andres Freund <andres@2ndquadrant.com> wrote:
On 2013-11-19 22:09:48 +0900, Michael Paquier wrote:
On Tue, Nov 19, 2013 at 2:27 AM, Andres Freund <andres@2ndquadrant.com> wrote:
* I am not sure I like "recovery.trigger" as a name. It seems to close
to what I've seen people use to trigger failover and too close to
trigger_file.This name was chosen and kept in accordance to the spec of this
feature. Looks fine for me...I still think "start_as_standby.trigger" or such would be much clearer
and far less likely to be confused with the promotion trigger file.
the function of the file is to inform the server it's in recovery and
it needs to consider recovery parameters, not to make the server a
standby. yes, i admit that is half the way to make the server a
standby. for example, if you are doing PITR and stopping the server
before some specific point (recovery_target_*) then
"start_as_standby.trigger" will has no meaning and could confuse
people
* You made recovery_target_inclusive/pause_at_recovery_target PGC_SIGHUP
- did you review that actually works? Imo that should be changed in a
separate commit.Yep, I'd rather see those parameters as PGC_POSTMASTER... As of now,
once recovery is started those parameter values do not change once
readRecoveryCommandFile is kicked. Having them SIGHUP would mean that
you could change them during recovery. Sounds kind of dangerous, no?I think it's desirable to make them changeable during recovery, but it's
a separate patch.
uh! i read the patch and miss that. will change
* Why did you change some of the recovery gucs to lowercase names, but
left out XLogRestoreCommand?This was part of the former patch, perhaps you are right and keeping
the names as close as possible to the old ones would make sense to
facilitate maintenance across versions.I think lowercase is slightly more consistent with the majority of the
other GUCs, but if you change it you should change all the new GUC variables.
This one was my change, in the original patch is called
"restore_command" and i changed it because archive_command's parameter
is called XLogArchiveCommand so i wanted the name to follow the same
format.
i can return it to the original name if no one likes XLogRestoreCommand
--
Jaime Casanova www.2ndQuadrant.com
Professional PostgreSQL: Soporte 24x7 y capacitación
Phone: +593 4 5107566 Cell: +593 987171157
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 2013-11-19 22:24:19 -0500, Tom Lane wrote:
Andres Freund <andres@2ndquadrant.com> writes:
On 2013-11-19 22:09:48 +0900, Michael Paquier wrote:
On Tue, Nov 19, 2013 at 2:27 AM, Andres Freund <andres@2ndquadrant.com> wrote:
* Why did you change some of the recovery gucs to lowercase names, but
left out XLogRestoreCommand?This was part of the former patch, perhaps you are right and keeping
the names as close as possible to the old ones would make sense to
facilitate maintenance across versions.I think lowercase is slightly more consistent with the majority of the
other GUCs, but if you change it you should change all the new GUC variables.Please *don't* create any more mixed-case GUC names. The spelling of
TimeZone and the one or two other historical exceptions was a very
unfortunate thing; it's confused more people than it's helped.
Put in some underscores if you feel a need for word boundaries.
That's a misunderstanding - I was only talking about the variables below
the GUCs, no the GUC's name. The patch changed quite some variable
names, around, but left others leaving an inconsistent casing of related
variables...
Greetings,
Andres Freund
--
Andres Freund 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
On 2013-11-20 08:10:44 -0500, Jaime Casanova wrote:
On Tue, Nov 19, 2013 at 3:32 PM, Andres Freund <andres@2ndquadrant.com> wrote:
On 2013-11-19 22:09:48 +0900, Michael Paquier wrote:
On Tue, Nov 19, 2013 at 2:27 AM, Andres Freund <andres@2ndquadrant.com> wrote:
* I am not sure I like "recovery.trigger" as a name. It seems to close
to what I've seen people use to trigger failover and too close to
trigger_file.This name was chosen and kept in accordance to the spec of this
feature. Looks fine for me...I still think "start_as_standby.trigger" or such would be much clearer
and far less likely to be confused with the promotion trigger file.the function of the file is to inform the server it's in recovery and
it needs to consider recovery parameters, not to make the server a
standby. yes, i admit that is half the way to make the server a
standby. for example, if you are doing PITR and stopping the server
before some specific point (recovery_target_*) then
"start_as_standby.trigger" will has no meaning and could confuse
people
'recovery' includes crash recovery, that's why I quite dislike your
function name since it's not crash recovery you're checking for since
during that we certainly do not want to interpet those parameters.
Greetings,
Andres Freund
--
Andres Freund 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
On Mon, Nov 18, 2013 at 12:27 PM, Andres Freund <andres@2ndquadrant.com> wrote:
Hi,
On 2013-11-15 22:38:05 -0500, Jaime Casanova wrote:
sorry, i clearly misunderstood you. attached a rebased patch with
those functions removed.* --write-standby-enable seems to loose quite some functionality in
comparison to --write-recovery-conf since it doesn't seem to set
primary_conninfo, standby anymore.
we can add code that looks for postgresql.conf in $PGDATA but if
postgresql.conf is not there (like the case in debian, there is not
much we can do about it) or we can write a file ready to be included
in postgresql.conf, any sugestion?
* CheckRecoveryReadyFile() doesn't seem to be a very descriptive
function name.
I left it as CheckStartingAsStandby() but i still have a problem of
this not being completely clear. this function is useful for standby
or pitr.
which leads me to the other problem i have: the recovery trigger file,
i have left it as standby.enabled but i still don't like it.
other options for the recovery trigger file:
recovery.trigger (Andres objected on this name)
forced_recovery.trigger
user_forced_recovery.trigger
or just allow standby.enabled and pitr.enabled. One advantage of this
is that if you put pitr.enabled you can check that standby_mode is
off.
the bad part on this approach is that it can end being
any_number_of_features.enabled, but i don't think that will happen
* Why does StartupXLOG() now use ArchiveRecoveryRequested &&
StandbyModeRequested instead of just the former?
good question. anyway, this patch shouldn't change that. if that
should be changed that is probably a bug and deserves to be in its own
patch
* I am not sure I like "recovery.trigger" as a name. It seems to close
to what I've seen people use to trigger failover and too close to
trigger_file.
look above
* You check for a trigger file in a way that's not compatible with it being NULL. Why did you change that? - if (TriggerFile == NULL) + if (!trigger_file[0])
returned to the old way of checking it
* You made recovery_target_inclusive/pause_at_recovery_target PGC_SIGHUP
- did you review that actually works? Imo that should be changed in a
separate commit.
agreed. i left all parameters that were in recovery.conf as
PGC_POSTMASTER and will start a new thread about which ones we should
change
* Maybe we should rename names like pause_at_recovery_target to
recovery_pause_at_target? Since we already force everyone to bother
changing their setup...
i don't have a problem with this, anyone else? if no one speaks i will
do what Andres suggests
* the description of archive_cleanup_command seems wrong to me.
why? it seems to be the same that was in recovery.conf. where did you
see the description you're complaining at?
* Why did you change some of the recovery gucs to lowercase names, but
left out XLogRestoreCommand?
my bad, left it as it was in the original patch: restore_command
* Why the PG_TRY/PG_CATCH in check_recovery_target_time? Besides being
really strangely formatted (multiline :? inside a function?) it
doesn't a) seem to be correct to ignore potential memory allocation
errors by just switching back into the context that just errored out,
and continue to work there b) forgo cleanup by just continuing as if
nothing happened. That's unlikely to be acceptable.
the code that read recovery.conf didn't has that, so i just removed it
* You access recovery_target_name[0] unconditionally, although it's
intialized to NULL.
* Generally, ISTM there's too much logic in the assign hooks.
probably that is mood now, because the comment that Heikki put in
commit 815d71deed5df2a91b06da76edbe5bc64965bfea says "If multiple
recovery_targets are specified, use the latest one." so now we should
just use the last one setted. Heikki? Any opinions?
* Why do you include xlog_internal.h in guc.c and not xlog.h?
we actually need both but including xlog_internal.h also includes xlog.h
i added xlog.h and if someone things is enough only putting
xlog_internal.h let me know
thank you
--
Jaime Casanova www.2ndQuadrant.com
Professional PostgreSQL: Soporte 24x7 y capacitación
Phone: +593 4 5107566 Cell: +593 987171157
Attachments:
recovery_guc_v5.2.patchtext/x-patch; charset=US-ASCII; name=recovery_guc_v5.2.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 059c820..907346e 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 a2361d7..673b106 100644
--- a/doc/src/sgml/backup.sgml
+++ b/doc/src/sgml/backup.sgml
@@ -1028,10 +1028,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>
@@ -1040,10 +1047,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>
@@ -1057,12 +1063,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
@@ -1124,7 +1129,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
@@ -1221,8 +1226,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 0f2f2bf..94dd4a4 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -2258,6 +2258,362 @@ 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>
+
+ <varlistentry id="min-recovery-apply-delay" xreflabel="min_recovery_apply_delay">
+ <term><varname>min_recovery_apply_delay</varname> (<type>integer</type>)</term>
+ <indexterm>
+ <primary><varname>min_recovery_apply_delay</> recovery parameter</primary>
+ </indexterm>
+ <listitem>
+ <para>
+ By default, a standby server keeps restoring WAL records from the
+ primary as soon as possible. It may be useful to have a time-delayed
+ copy of the data, offering various options to correct data loss errors.
+ This parameter allows you to delay recovery by a fixed period of time,
+ specified in milliseconds if no unit is specified. For example, if
+ you set this parameter to <literal>5min</literal>, the standby will
+ replay each transaction commit only when the system time on the standby
+ is at least five minutes past the commit time reported by the master.
+ </para>
+ <para>
+ It is possible that the replication delay between servers exceeds the
+ value of this parameter, in which case no delay is added.
+ Note that the delay is calculated between the WAL timestamp as written
+ on master and the time on the current standby. Delays
+ in transfer because of networks or cascading replication configurations
+ may reduce the actual wait time significantly. If the system
+ clocks on master and standby are not synchronised, this may lead to
+ recovery applying records earlier than expected but is not a major issue
+ because the useful settings of the parameter are much larger than
+ typical time deviation between the servers. Be careful to allow for
+ different timezone settings on master and standby.
+ </para>
+ <para>
+ The delay occurs only on WAL records for COMMIT and Restore Points.
+ Other records may be replayed earlier than the specified delay, which
+ is not an issue for MVCC though may potentially increase the number
+ of recovery conflicts generated.
+ </para>
+ <para>
+ The delay occurs until the standby is promoted or triggered. After that
+ the standby will end recovery without further waiting.
+ </para>
+ <para>
+ This parameter is intended for use with streaming replication deployments,
+ however, if the parameter is specified it will be honoured in all cases.
+ Synchronous replication is not affected by this setting because there is
+ not yet any setting to request synchronous apply of transaction commits.
+ <varname>hot_standby_feedback</> will be delayed by use of this feature
+ which could lead to bloat on the master; use both together with care.
+ </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>
@@ -2478,6 +2834,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 552c3aa..0b361c9 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 8579bdd..a8787ac 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -15782,7 +15782,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 e2e5ac9..7995796 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 b47bf52..6bc1edb 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 550cdce..0000000
--- a/doc/src/sgml/recovery-config.sgml
+++ /dev/null
@@ -1,418 +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>
- An exception is that if the command was terminated by a signal (other
- than <systemitem>SIGTERM</systemitem>, which is used as part of a
- database server shutdown) or an error by the shell (such as command
- not found), then recovery will abort and the server will not start up.
- </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 nonzero exit status then a warning log
- message will be written. An exception is that if the command was
- terminated by a signal or an error by the shell (such as command not
- found), a fatal error will be raised.
- </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 nonzero 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 or an error by the shell (such as command not found), the
- database will not proceed with startup.
- </para>
- </listitem>
- </varlistentry>
-
- <varlistentry id="min-recovery-apply-delay" xreflabel="min_recovery_apply_delay">
- <term><varname>min_recovery_apply_delay</varname> (<type>integer</type>)</term>
- <indexterm>
- <primary><varname>min_recovery_apply_delay</> recovery parameter</primary>
- </indexterm>
- <listitem>
- <para>
- By default, a standby server keeps restoring WAL records from the
- primary as soon as possible. It may be useful to have a time-delayed
- copy of the data, offering various options to correct data loss errors.
- This parameter allows you to delay recovery by a fixed period of time,
- specified in milliseconds if no unit is specified. For example, if
- you set this parameter to <literal>5min</literal>, the standby will
- replay each transaction commit only when the system time on the standby
- is at least five minutes past the commit time reported by the master.
- </para>
- <para>
- It is possible that the replication delay between servers exceeds the
- value of this parameter, in which case no delay is added.
- Note that the delay is calculated between the WAL timestamp as written
- on master and the time on the current standby. Delays
- in transfer because of networks or cascading replication configurations
- may reduce the actual wait time significantly. If the system
- clocks on master and standby are not synchronised, this may lead to
- recovery applying records earlier than expected but is not a major issue
- because the useful settings of the parameter are much larger than
- typical time deviation between the servers. Be careful to allow for
- different timezone settings on master and standby.
- </para>
- <para>
- The delay occurs only on WAL records for COMMIT and Restore Points.
- Other records may be replayed earlier than the specified delay, which
- is not an issue for MVCC though may potentially increase the number
- of recovery conflicts generated.
- </para>
- <para>
- The delay occurs until the standby is promoted or triggered. After that
- the standby will end recovery without further waiting.
- </para>
- <para>
- This parameter is intended for use with streaming replication deployments,
- however, if the parameter is specified it will be honoured in all cases.
- Synchronous replication is not affected by this setting because there is
- not yet any setting to request synchronous apply of transaction commits.
- <varname>hot_standby_feedback</> will be delayed by use of this feature
- which could lead to bloat on the master; use both together with care.
- </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 c379df5..93e6706 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 b3f5c52..7d6be40 100644
--- a/doc/src/sgml/release-9.1.sgml
+++ b/doc/src/sgml/release-9.1.sgml
@@ -5205,7 +5205,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>
@@ -5225,7 +5225,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>
@@ -5257,8 +5257,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 356890d..aaabda1 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 673605c..0000000
--- a/src/backend/access/transam/recovery.conf.sample
+++ /dev/null
@@ -1,141 +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 = ''
-#
-# By default, a standby server keeps restoring XLOG records from the
-# primary as soon as possible. If you want to explicitly delay the replay of
-# committed transactions from the master, specify a recovery apply delay.
-# For example, if you set this parameter to 5min, the standby will replay
-# each transaction commit only when the system time on the standby is least
-# five minutes past the commit time reported by the master.
-#
-#min_recovery_apply_delay = 0
-#
-#---------------------------------------------------------------------------
-# 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 b53ae87..54f6a0d 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 RECOVERY_ENABLE_FILE "standby.enabled"
#define PROMOTE_SIGNAL_FILE "promote"
#define FALLBACK_PROMOTE_SIGNAL_FILE "fallback_promote"
+/* recovery.conf is not supported anymore */
+#define RECOVERY_COMMAND_FILE "recovery.conf"
/* User-settable parameters */
int CheckPointSegments = 3;
@@ -85,7 +86,26 @@ 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;
+int min_recovery_apply_delay = 0;
+static TimestampTz recoveryDelayUntilTime;
+
+/* are we currently in standby mode? */
+bool StandbyMode = false;
#ifdef WAL_DEBUG
bool XLOG_DEBUG = false;
@@ -194,7 +214,7 @@ static int LocalXLogInsertAllowed = -1;
/*
* When ArchiveRecoveryRequested is set, archive recovery was requested,
- * ie. recovery.conf file was present. When InArchiveRecovery is set, we are
+ * ie. standby.enabled file was present. When InArchiveRecovery is set, we are
* currently recovering using offline XLOG archives. These variables are only
* valid in the startup process.
*
@@ -209,27 +229,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;
-static int min_recovery_apply_delay = 0;
-static TimestampTz recoveryDelayUntilTime;
-
-/* 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;
@@ -531,12 +530,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 CheckStartingAsStandby(void);
static void exitArchiveRecovery(TimeLineID endTLI, XLogSegNo endLogSegNo);
static bool recoveryStopsBefore(XLogRecord *record);
static bool recoveryStopsAfter(XLogRecord *record);
@@ -5308,187 +5301,27 @@ str_time(pg_time_t tnow)
* The file is parsed using the main configuration parser.
*/
static void
-readRecoveryCommandFile(void)
+CheckStartingAsStandby(void)
{
FILE *fd;
- TimeLineID rtli = 0;
- bool rtliGiven = false;
- ConfigVariable *item,
- *head = NULL,
- *tail = NULL;
- fd = AllocateFile(RECOVERY_COMMAND_FILE, "r");
+ /* Check the presence of recovery.conf, it is not supported anymore */
+ if (AllocateFile(RECOVERY_COMMAND_FILE, "r") != NULL)
+ ereport(FATAL,
+ (errmsg("\"%s\" is not supported anymore as a recovery method",
+ RECOVERY_COMMAND_FILE),
+ errdetail("Refer to appropriate documentation about migration methods")));
+
+ /* Check the presence of file standby.enabled, the file triggering recovery */
+ fd = AllocateFile(RECOVERY_ENABLE_FILE, "r");
if (fd == NULL)
{
if (errno == ENOENT)
return; /* not there, so no archive recovery */
ereport(FATAL,
(errcode_for_file_access(),
- errmsg("could not open recovery command file \"%s\": %m",
- RECOVERY_COMMAND_FILE)));
- }
-
- /*
- * Since we're asking ParseConfigFp() to report errors as FATAL, there's
- * no need to check the return value.
- */
- (void) ParseConfigFp(fd, RECOVERY_COMMAND_FILE, 0, FATAL, &head, &tail);
-
- FreeFile(fd);
-
- for (item = head; item; item = item->next)
- {
- if (strcmp(item->name, "restore_command") == 0)
- {
- recoveryRestoreCommand = pstrdup(item->value);
- ereport(DEBUG2,
- (errmsg_internal("restore_command = '%s'",
- recoveryRestoreCommand)));
- }
- else if (strcmp(item->name, "recovery_end_command") == 0)
- {
- recoveryEndCommand = pstrdup(item->value);
- ereport(DEBUG2,
- (errmsg_internal("recovery_end_command = '%s'",
- recoveryEndCommand)));
- }
- else if (strcmp(item->name, "archive_cleanup_command") == 0)
- {
- archiveCleanupCommand = pstrdup(item->value);
- ereport(DEBUG2,
- (errmsg_internal("archive_cleanup_command = '%s'",
- archiveCleanupCommand)));
- }
- else if (strcmp(item->name, "pause_at_recovery_target") == 0)
- {
- if (!parse_bool(item->value, &recoveryPauseAtTarget))
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
- errmsg("parameter \"%s\" requires a Boolean value", "pause_at_recovery_target")));
- ereport(DEBUG2,
- (errmsg_internal("pause_at_recovery_target = '%s'",
- item->value)));
- }
- else if (strcmp(item->name, "recovery_target_timeline") == 0)
- {
- rtliGiven = true;
- if (strcmp(item->value, "latest") == 0)
- rtli = 0;
- else
- {
- errno = 0;
- rtli = (TimeLineID) strtoul(item->value, NULL, 0);
- if (errno == EINVAL || errno == ERANGE)
- ereport(FATAL,
- (errmsg("recovery_target_timeline is not a valid number: \"%s\"",
- item->value)));
- }
- if (rtli)
- ereport(DEBUG2,
- (errmsg_internal("recovery_target_timeline = %u", rtli)));
- else
- ereport(DEBUG2,
- (errmsg_internal("recovery_target_timeline = latest")));
- }
- else if (strcmp(item->name, "recovery_target_xid") == 0)
- {
- errno = 0;
- recoveryTargetXid = (TransactionId) strtoul(item->value, NULL, 0);
- if (errno == EINVAL || errno == ERANGE)
- ereport(FATAL,
- (errmsg("recovery_target_xid is not a valid number: \"%s\"",
- item->value)));
- ereport(DEBUG2,
- (errmsg_internal("recovery_target_xid = %u",
- recoveryTargetXid)));
- recoveryTarget = RECOVERY_TARGET_XID;
- }
- else if (strcmp(item->name, "recovery_target_time") == 0)
- {
- 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)
- {
- 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 if (strcmp(item->name, "min_recovery_apply_delay") == 0)
- {
- const char *hintmsg;
-
- if (!parse_int(item->value, &min_recovery_apply_delay, GUC_UNIT_MS,
- &hintmsg))
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
- errmsg("parameter \"%s\" requires a temporal value", "min_recovery_apply_delay"),
- hintmsg ? errhint("%s", _(hintmsg)) : 0));
- ereport(DEBUG2,
- (errmsg("min_recovery_apply_delay = '%s'", item->value)));
- }
- else
- ereport(FATAL,
- (errmsg("unrecognized recovery parameter \"%s\"",
- item->name)));
+ errmsg("could not open recovery file trigger \"%s\": %m",
+ RECOVERY_ENABLE_FILE)));
}
/*
@@ -5496,18 +5329,16 @@ readRecoveryCommandFile(void)
*/
if (StandbyModeRequested)
{
- if (PrimaryConnInfo == NULL && recoveryRestoreCommand == NULL)
+ if (primary_conninfo == NULL && restore_command == NULL)
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 == NULL)
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 */
@@ -5519,16 +5350,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
@@ -5538,8 +5370,6 @@ readRecoveryCommandFile(void)
recoveryTargetIsLatest = true;
}
}
-
- FreeConfigVariables(head);
}
/*
@@ -5610,15 +5440,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")));
@@ -5687,7 +5515,7 @@ recoveryStopsBefore(XLogRecord *record)
else
return false;
- if (recoveryTarget == RECOVERY_TARGET_XID && !recoveryTargetInclusive)
+ if (recovery_target == RECOVERY_TARGET_XID && !recovery_target_inclusive)
{
/*
* There can be only one transaction end record with this exact
@@ -5698,10 +5526,10 @@ recoveryStopsBefore(XLogRecord *record)
* 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 (recoveryTarget == RECOVERY_TARGET_TIME &&
+ if (recovery_target == RECOVERY_TARGET_TIME &&
getRecordTimestamp(record, &recordXtime))
{
/*
@@ -5709,10 +5537,10 @@ recoveryStopsBefore(XLogRecord *record)
* 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)
@@ -5759,14 +5587,14 @@ recoveryStopsAfter(XLogRecord *record)
* There can be many restore points that share the same name; we stop
* at the first one.
*/
- if (recoveryTarget == RECOVERY_TARGET_NAME &&
+ if (recovery_target == RECOVERY_TARGET_NAME &&
record->xl_rmid == RM_XLOG_ID && record_info == XLOG_RESTORE_POINT)
{
xl_restore_point *recordRestorePointData;
recordRestorePointData = (xl_restore_point *) XLogRecGetData(record);
- if (strcmp(recordRestorePointData->rp_name, recoveryTargetName) == 0)
+ if (strcmp(recordRestorePointData->rp_name, recovery_target_name) == 0)
{
recoveryStopAfter = true;
recoveryStopXid = InvalidTransactionId;
@@ -5799,8 +5627,8 @@ recoveryStopsAfter(XLogRecord *record)
* they complete. A higher numbered xid will complete before you about
* 50% of the time...
*/
- if (recoveryTarget == RECOVERY_TARGET_XID && recoveryTargetInclusive &&
- record->xl_xid == recoveryTargetXid)
+ if (recovery_target == RECOVERY_TARGET_XID && recovery_target_inclusive &&
+ record->xl_xid == recovery_target_xid)
{
recoveryStopAfter = true;
recoveryStopXid = record->xl_xid;
@@ -6216,36 +6044,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));
+ CheckStartingAsStandby();
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")));
@@ -6512,7 +6332,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)
@@ -6526,7 +6346,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;
}
@@ -6986,7 +6806,7 @@ StartupXLOG(void)
* end of main redo apply loop
*/
- if (recoveryPauseAtTarget && reachedStopPoint)
+ if (pause_at_recovery_target && reachedStopPoint)
{
SetRecoveryPause(true);
recoveryPausesHere();
@@ -7111,17 +6931,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);
@@ -7292,8 +7112,8 @@ StartupXLOG(void)
/*
* And finally, execute the recovery_end_command, if any.
*/
- if (recoveryEndCommand)
- ExecuteRecoveryCommand(recoveryEndCommand,
+ if (recovery_end_command)
+ ExecuteRecoveryCommand(recovery_end_command,
"recovery_end_command",
true);
}
@@ -8872,8 +8692,8 @@ CreateRestartPoint(int flags)
/*
* Finally, execute archive_cleanup_command, if any.
*/
- if (XLogCtl->archiveCleanupCommand[0])
- ExecuteRecoveryCommand(XLogCtl->archiveCleanupCommand,
+ if (archive_cleanup_command)
+ ExecuteRecoveryCommand(archive_cleanup_command,
"archive_cleanup_command",
false);
@@ -10949,7 +10769,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)
{
XLogRecPtr ptr;
TimeLineID tli;
@@ -10970,7 +10790,7 @@ WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess,
tli, curFileTLI);
}
curFileTLI = tli;
- RequestXLogStreaming(tli, ptr, PrimaryConnInfo);
+ RequestXLogStreaming(tli, ptr, primary_conninfo);
receivedUpto = 0;
}
@@ -11285,14 +11105,14 @@ CheckForStandbyTrigger(void)
return true;
}
- if (TriggerFile == NULL)
+ if (trigger_file == NULL)
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 a437933..4cb6159 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 ce5aed3..6e90c07 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-2014, PostgreSQL Global Development Group
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 1217098..f144a93 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -30,6 +30,8 @@
#include "access/transam.h"
#include "access/twophase.h"
#include "access/xact.h"
+#include "access/xlog.h"
+#include "access/xlog_internal.h"
#include "catalog/namespace.h"
#include "commands/async.h"
#include "commands/prepare.h"
@@ -202,6 +204,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,
@@ -478,6 +488,8 @@ static bool data_checksums;
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;
@@ -558,6 +570,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 */
@@ -1423,6 +1439,36 @@ static struct config_bool ConfigureNamesBool[] =
},
{
+ {"recovery_target_inclusive", PGC_POSTMASTER, WAL_RECOVERY_TARGET,
+ gettext_noop("Sets whether to include or exclude transaction with recovery target."),
+ NULL
+ },
+ &recovery_target_inclusive,
+ true,
+ NULL, NULL, NULL
+ },
+
+ {
+ {"pause_at_recovery_target", PGC_POSTMASTER, 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
@@ -2647,6 +2693,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,
@@ -9404,4 +9541,140 @@ 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;
+
+ if (strcmp(*newval, "") == 0)
+ time = 0;
+ else
+ time = DatumGetTimestampTz(DirectFunctionCall3(timestamptz_in,
+ CStringGetDatum(*newval),
+ ObjectIdGetDatum(InvalidOid),
+ Int32GetDatum(-1)));
+
+ 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 27791cc..7b75ded 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -210,6 +210,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
@@ -252,7 +269,13 @@
#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
+#min_recovery_apply_delay = 0 # Minimum time the standby will be delayed from master
+ # in milliseconds; 0 disables
#------------------------------------------------------------------------------
# QUERY TUNING
diff --git a/src/bin/pg_basebackup/pg_basebackup.c b/src/bin/pg_basebackup/pg_basebackup.c
index 9d13d57..1b45861 100644
--- a/src/bin/pg_basebackup/pg_basebackup.c
+++ b/src/bin/pg_basebackup/pg_basebackup.c
@@ -44,7 +44,7 @@ static int compresslevel = 0;
static bool includewal = false;
static bool streamwal = false;
static bool fastcheckpoint = false;
-static bool writerecoveryconf = false;
+static bool writestandbyenabled = false;
static int standby_message_timeout = 10 * 1000; /* 10 sec = default */
/* Progress counters */
@@ -69,9 +69,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);
@@ -79,8 +76,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,
@@ -111,8 +107,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"));
@@ -669,7 +665,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
@@ -679,22 +675,16 @@ ReceiveTarFile(PGconn *conn, PGresult *res, int rownum)
MemSet(zerobuf, 0, sizeof(zerobuf));
- if (basetablespace && writerecoveryconf)
+ if (basetablespace && writestandbyenabled)
{
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 */
@@ -735,11 +725,11 @@ ReceiveTarFile(PGconn *conn, PGresult *res, int rownum)
disconnect_and_exit(1);
}
- if (!writerecoveryconf || !basetablespace)
+ if (!writestandbyenabled || !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);
@@ -747,7 +737,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.
*
@@ -793,12 +783,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);
@@ -1108,179 +1098,18 @@ ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum)
if (copybuf != NULL)
PQfreemem(copybuf);
- if (basetablespace && writerecoveryconf)
- WriteRecoveryConf();
-}
-
-/*
- * Escape a parameter value so that it can be used as part of a libpq
- * connection string, e.g. in:
- *
- * application_name=<value>
- *
- * The returned string is malloc'd. Return NULL on out-of-memory.
- */
-static char *
-escapeConnectionParameter(const char *src)
-{
- bool need_quotes = false;
- bool need_escaping = false;
- const char *p;
- char *dstbuf;
- char *dst;
-
- /*
- * First check if quoting is needed. Any quote (') or backslash (\)
- * characters need to be escaped. Parameters are separated by whitespace,
- * so any string containing whitespace characters need to be quoted. An
- * empty string is represented by ''.
- */
- if (strchr(src, '\'') != NULL || strchr(src, '\\') != NULL)
- need_escaping = true;
-
- for (p = src; *p; p++)
- {
- if (isspace((unsigned char) *p))
- {
- need_quotes = true;
- break;
- }
- }
-
- if (*src == '\0')
- return pg_strdup("''");
-
- if (!need_quotes && !need_escaping)
- return pg_strdup(src); /* no quoting or escaping needed */
-
- /*
- * Allocate a buffer large enough for the worst case that all the source
- * characters need to be escaped, plus quotes.
- */
- dstbuf = pg_malloc(strlen(src) * 2 + 2 + 1);
-
- dst = dstbuf;
- if (need_quotes)
- *(dst++) = '\'';
- for (; *src; src++)
- {
- if (*src == '\'' || *src == '\\')
- *(dst++) = '\\';
- *(dst++) = *src;
- }
- if (need_quotes)
- *(dst++) = '\'';
- *dst = '\0';
-
- return dstbuf;
-}
-
-/*
- * Escape a string so that it can be used as a value in a key-value pair
- * a configuration file.
- */
-static char *
-escape_quotes(const char *src)
-{
- char *result = escape_single_quotes_ascii(src);
-
- if (!result)
- {
- fprintf(stderr, _("%s: out of memory\n"), progname);
- exit(1);
- }
- return result;
-}
-
-/*
- * Create a recovery.conf file in memory using a PQExpBuffer
- */
-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);
+ if (basetablespace && writestandbyenabled)
+ WriteStandbyEnabled();
}
-/*
- * Write a recovery.conf file into the directory specified in basedir,
- * with the contents already collected in memory.
- */
static void
-WriteRecoveryConf(void)
+WriteStandbyEnabled(void)
{
char filename[MAXPGPATH];
FILE *cf;
- sprintf(filename, "%s/recovery.conf", basedir);
+ sprintf(filename, "%s/standby.enabled", basedir);
cf = fopen(filename, "w");
if (cf == NULL)
@@ -1289,14 +1118,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);
}
@@ -1352,12 +1173,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");
@@ -1634,9 +1449,6 @@ BaseBackup(void)
#endif
}
- /* Free the recovery.conf contents */
- destroyPQExpBuffer(recoveryconfcontents);
-
/*
* End of copy data. Final result is already checked inside the loop.
*/
@@ -1657,7 +1469,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'},
@@ -1719,7 +1531,7 @@ main(int argc, char **argv)
}
break;
case 'R':
- writerecoveryconf = true;
+ writestandbyenabled = 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 74b23a4..436b1d4 100644
--- a/src/bin/pg_ctl/pg_ctl.c
+++ b/src/bin/pg_ctl/pg_ctl.c
@@ -892,7 +892,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 &&
@@ -980,7 +980,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 &&
@@ -1091,7 +1091,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; "
@@ -2231,7 +2231,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 017e74d..ba60d13 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -191,6 +191,20 @@ extern bool EnableHotStandby;
extern bool fullPageWrites;
extern bool wal_log_hints;
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 47ff880..a9a231e 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,
diff --git a/src/port/quotes.c b/src/port/quotes.c
index 7c8d4ed..3d51186 100644
--- a/src/port/quotes.c
+++ b/src/port/quotes.c
@@ -18,8 +18,7 @@
/*
* Escape (by doubling) any single quotes or backslashes in given string
*
- * Note: this is used to process postgresql.conf entries and to quote
- * string literals in pg_basebackup for creating recovery.conf.
+ * Note: this is used to process postgresql.conf entries
* Since postgresql.conf strings are defined to treat backslashes as escapes,
* we have to double backslashes here.
*
On Wed, Jan 15, 2014 at 2:00 AM, Jaime Casanova <jaime@2ndquadrant.com> wrote:
On Mon, Nov 18, 2013 at 12:27 PM, Andres Freund <andres@2ndquadrant.com> wrote:
* Maybe we should rename names like pause_at_recovery_target to
recovery_pause_at_target? Since we already force everyone to bother
changing their setup...i don't have a problem with this, anyone else? if no one speaks i will
do what Andres suggests
Actually Michael had objected to this idea but i forgot about that...
so i will wait for some consensus (my personal opinion is that
Michael's argument is a good one)
--
Jaime Casanova www.2ndQuadrant.com
Professional PostgreSQL: Soporte 24x7 y capacitación
Phone: +593 4 5107566 Cell: +593 987171157
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Wed, Jan 15, 2014 at 2:06 AM, Jaime Casanova <jaime@2ndquadrant.com> wrote:
On Wed, Jan 15, 2014 at 2:00 AM, Jaime Casanova <jaime@2ndquadrant.com> wrote:
On Mon, Nov 18, 2013 at 12:27 PM, Andres Freund <andres@2ndquadrant.com> wrote:
* Maybe we should rename names like pause_at_recovery_target to
recovery_pause_at_target? Since we already force everyone to bother
changing their setup...i don't have a problem with this, anyone else? if no one speaks i will
do what Andres suggestsActually Michael had objected to this idea but i forgot about that...
so i will wait for some consensus (my personal opinion is that
Michael's argument is a good one)
I prefer the current name. It's more like the way English is spoken.
--
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
Hi,
On 2014-01-15 02:00:51 -0500, Jaime Casanova wrote:
On Mon, Nov 18, 2013 at 12:27 PM, Andres Freund <andres@2ndquadrant.com> wrote:
Hi,
On 2013-11-15 22:38:05 -0500, Jaime Casanova wrote:
sorry, i clearly misunderstood you. attached a rebased patch with
those functions removed.* --write-standby-enable seems to loose quite some functionality in
comparison to --write-recovery-conf since it doesn't seem to set
primary_conninfo, standby anymore.we can add code that looks for postgresql.conf in $PGDATA but if
postgresql.conf is not there (like the case in debian, there is not
much we can do about it) or we can write a file ready to be included
in postgresql.conf, any sugestion?
People might not like me for the suggestion, but I think we should
simply always include a 'recovery.conf' in $PGDATA
unconditionally. That'd make this easier.
Alternatively we could pass a filename to --write-recovery-conf.
* CheckRecoveryReadyFile() doesn't seem to be a very descriptive
function name.I left it as CheckStartingAsStandby() but i still have a problem of
this not being completely clear. this function is useful for standby
or pitr.
which leads me to the other problem i have: the recovery trigger file,
i have left it as standby.enabled but i still don't like it.
recovery.trigger (Andres objected on this name)
forced_recovery.trigger
user_forced_recovery.trigger
stay_in_recovery.trigger? That'd be pretty clear for anybody involved in
pg, but otherwise...
* the description of archive_cleanup_command seems wrong to me.
why? it seems to be the same that was in recovery.conf. where did you
see the description you're complaining at?
I dislike the description in guc.c
+ {"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,
previously it was:
-# specifies an optional shell command to execute at every restartpoint.
-# This can be useful for cleaning up the archive of a standby server.
* Why the PG_TRY/PG_CATCH in check_recovery_target_time? Besides being
really strangely formatted (multiline :? inside a function?) it
doesn't a) seem to be correct to ignore potential memory allocation
errors by just switching back into the context that just errored out,
and continue to work there b) forgo cleanup by just continuing as if
nothing happened. That's unlikely to be acceptable.the code that read recovery.conf didn't has that, so i just removed it
Well, that's not necessarily correct. recovery.conf was only read during
startup, while this is read on SIGHUP.
* Why do you include xlog_internal.h in guc.c and not xlog.h?
we actually need both but including xlog_internal.h also includes xlog.h
i added xlog.h and if someone things is enough only putting
xlog_internal.h let me know
What's required from xlog_internal.h?
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index b53ae87..54f6a0d 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 RECOVERY_ENABLE_FILE "standby.enabled"
Imo the file and variable names should stay coherent.
+/* recovery.conf is not supported anymore */ +#define RECOVERY_COMMAND_FILE "recovery.conf"
+bool StandbyModeRequested = false; +static TimestampTz recoveryDelayUntilTime;
This imo should be lowercase now, the majority of GUC variables are.
+/* are we currently in standby mode? */
+bool StandbyMode = false;
Why did you move this?
- if (rtliGiven) + if (strcmp(recovery_target_timeline_string, "") != 0) {
Why not have the convention that NULL indicates a unset target_timeline
like you use for other GUCs? Mixing things like this is confusing.
Why is recovery_target_timeline stored as a string? Because it's a
unsigned int? If so, you should have an assign hook setting up a)
rtliGiven, b) properly typed variable.
- 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;
So, now we have a recoveryTargetTLI and recovery_target_timeline
variable? Really? Why do we need recoveryTargetTLI at all now?
+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 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; +} +
I don't think it's correct to do such hangups in the assign hook - you
have no ideas in which order they will be called and such. Imo that
should happen at startup, like we also do it for other interdependent
variables like wal_buffers.
+static bool +check_recovery_target_time(char **newval, void **extra, GucSource source) +{ + TimestampTz time; + TimestampTz *myextra; + + if (strcmp(*newval, "") == 0) + time = 0; + else + time = DatumGetTimestampTz(DirectFunctionCall3(timestamptz_in, + CStringGetDatum(*newval), + ObjectIdGetDatum(InvalidOid), + Int32GetDatum(-1))); + + myextra = (TimestampTz *) guc_malloc(ERROR, sizeof(TimestampTz)); + *myextra = time; + *extra = (void *) myextra; + + return true; +}
Trailing space behind the strcmp().
I don't think that's correct. Afaics it will cause the postmaster to
crash on a SIGHUP with invalid data. I think you're unfortunately going
to have to copy a fair bit of timestamptz_in() and even
DateTimeParseError(), replacing the ereport()s by the guc error
reporting.
Greetings,
Andres Freund
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
This patch is in "Waiting for Author" for a couple of weeks and has
received a review at least from Andres during this commit fest. As the
situation is not much progressing, I am going to mark it as "Returned
with feedback".
If there are any problems with that please let me know.
Thanks,
--
Michael
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
All,
Can we get this patch going again for 9.5?
--
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
Import Notes
Reply to msg id not found: WM6865f4d75ad031342f9a6a415e37b3790b39d97d6e3adca70cd58d8596a2c020114cbd899b3491944cd51d8f05847891@asav-3.01.comReference msg id not found: WM2eef57bf14271a28b7764a48733ac1bb0352229c58adbbcfc444bf3b2d39b5c4e9068a10e3f688295481db2314a812ff@asav-3.01.com
Hi,
On 2014-06-04 16:32:33 -0700, Josh Berkus wrote:
Can we get this patch going again for 9.5?
A patch gets going by somebody working on it.
Greetings,
Andres Freund
--
Andres Freund 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
On 06/04/2014 04:35 PM, Andres Freund wrote:
Hi,
On 2014-06-04 16:32:33 -0700, Josh Berkus wrote:
Can we get this patch going again for 9.5?
A patch gets going by somebody working on it.
Well yes, but it is also great to have someone remind others that it is
of interest.
JD
Greetings,
Andres Freund
--
Command Prompt, Inc. - http://www.commandprompt.com/ 509-416-6579
PostgreSQL Support, Training, Professional Services and Development
High Availability, Oracle Conversion, Postgres-XC, @cmdpromptinc
Political Correctness is for cowards.
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Hello,
Here's an attempt to revive this patch.
It is rebased onto the latest master and also includes handling and
documentation of newly added recovery.conf parameters such as
primary_slot_name, recovery_min_apply_delay and
recovery_target='immediate'.
The following feedback had been addressed:
Andres Freund <andres@2ndquadrant.com> writes:
* --write-standby-enable seems to loose quite some functionality in
comparison to --write-recovery-conf since it doesn't seem to set
primary_conninfo, standby anymore.we can add code that looks for postgresql.conf in $PGDATA but if
postgresql.conf is not there (like the case in debian, there is not
much we can do about it) or we can write a file ready to be included
in postgresql.conf, any sugestion?People might not like me for the suggestion, but I think we should
simply always include a 'recovery.conf' in $PGDATA
unconditionally. That'd make this easier.
Alternatively we could pass a filename to --write-recovery-conf.
Well, the latest version of this patch fails to start when it sees
'recovery.conf' in PGDATA:
FATAL: "recovery.conf" is not supported anymore as a recovery method
DETAIL: Refer to appropriate documentation about migration methods
I've missed all the discussion behind this decision and after reading
the ALTER SYSTEM/conf.d thread I'm even more confused so I'd like
someone more knowledgeable to speak up on the status of this.
Do we want to keep this behavior of the patch?
* CheckRecoveryReadyFile() doesn't seem to be a very descriptive
function name.I left it as CheckStartingAsStandby() but i still have a problem of
this not being completely clear. this function is useful for standby
or pitr.
There's not much left for this function in the current patch version, so
maybe we should just move it to StartupXLOG (it's not called from
anywhere else either way).
which leads me to the other problem i have: the recovery trigger file,
i have left it as standby.enabled but i still don't like it.recovery.trigger (Andres objected on this name)
forced_recovery.trigger
user_forced_recovery.triggerstay_in_recovery.trigger? That'd be pretty clear for anybody involved in
pg, but otherwise...
The docs use the term "continuous recovery".
Either way, from the code it is clear that we only stay in recovery if
standby_mode is directly turned on. This makes the whole check for a
specially named file unnecessary, IMO: we should just check the value of
standby_mode (which is off by default).
By the way, is there any use in setting standby_mode=on and any of the
recovery_target* GUCs at the same time?
I think it can only play together if you set the target farther than the
latest point you've got in the archive locally. So that's sort of
"Point-in-Future-Recovery". Does that make any sense at all?
* the description of archive_cleanup_command seems wrong to me.
why? it seems to be the same that was in recovery.conf. where did you
see the description you're complaining at?I dislike the description in guc.c
+ {"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,previously it was:
-# specifies an optional shell command to execute at every restartpoint.
-# This can be useful for cleaning up the archive of a standby server.
Expanded the GUC desc.
* Why the PG_TRY/PG_CATCH in check_recovery_target_time? Besides being
really strangely formatted (multiline :? inside a function?) it
doesn't a) seem to be correct to ignore potential memory allocation
errors by just switching back into the context that just errored out,
and continue to work there b) forgo cleanup by just continuing as if
nothing happened. That's unlikely to be acceptable.the code that read recovery.conf didn't has that, so i just removed it
Well, that's not necessarily correct. recovery.conf was only read during
startup, while this is read on SIGHUP.
[copied from the bottom, related]
I don't think that's correct. Afaics it will cause the postmaster to
crash on a SIGHUP with invalid data. I think you're unfortunately going
to have to copy a fair bit of timestamptz_in() and even
DateTimeParseError(), replacing the ereport()s by the guc error
reporting.
The use of PG_TRY/CATCH does protect from FATALs in SIGHUP indeed.
Using CopyErrorData() we can also fetch the actual error message from
timestamptz_in, though I wonder we really have to make a full copy.
* Why do you include xlog_internal.h in guc.c and not xlog.h?
we actually need both but including xlog_internal.h also includes xlog.h
i added xlog.h and if someone things is enough only putting
xlog_internal.h let me knowWhat's required from xlog_internal.h?
Looks like this was addressed before me.
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index b53ae87..54f6a0d 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 RECOVERY_ENABLE_FILE "standby.enabled"Imo the file and variable names should stay coherent.
Yes, once we settle on the name (and if we really need that extra
trigger file.)
+/* recovery.conf is not supported anymore */ +#define RECOVERY_COMMAND_FILE "recovery.conf"+bool StandbyModeRequested = false; +static TimestampTz recoveryDelayUntilTime;This imo should be lowercase now, the majority of GUC variables are.
This is not a GUC variable, though it's calculated based on a GUC
recovery_min_apply_delay.
+/* are we currently in standby mode? */
+bool StandbyMode = false;Why did you move this?
It was easy to move it back though.
- if (rtliGiven) + if (strcmp(recovery_target_timeline_string, "") != 0) {Why not have the convention that NULL indicates a unset target_timeline
like you use for other GUCs? Mixing things like this is confusing.Why is recovery_target_timeline stored as a string? Because it's a
unsigned int? If so, you should have an assign hook setting up a)
rtliGiven, b) properly typed variable.
Yes, I believe setting these to NULL by default makes a lot more sense.
Then one can check if there was a non-default setting by checking the
*_string variable, which is not possible with int or TimestampTz.
- 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;So, now we have a recoveryTargetTLI and recovery_target_timeline
variable? Really? Why do we need recoveryTargetTLI at all now?
Looks like we still do need both of them. The initial value of
recoveryTargetTLI is derived from pg_control, but later it can be
overriden by this setting.
However, if the recovery_target_timeline was "latest" we need to find
the latest TLI, based on the initial value from pg_control. But we
can't set final recoveryTargetTLI value in the GUC assign hook, because
we might need to fetch some history files first.
+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; +} +I don't think it's correct to do such hangups in the assign hook - you
have no ideas in which order they will be called and such. Imo that
should happen at startup, like we also do it for other interdependent
variables like wal_buffers.
Yeah, that looked weird. Moved to StartupXLOG().
I disliked the strtoul handling in the earlier version of the patch,
especially given that with the base=0 it can parse 0x-prefixed hex
strings. I would rather error out on non-hex digit instead of stopping
and calling it OK. This change is included in the new version.
Should we really allow specifying negative values for XID/timeline?
Right now it will happily consume "-1" for recovery_target_xid and
complain if it's out of range, like this:
LOG: starting point-in-time recovery to XID 4294967295
LOG: invalid primary checkpoint record
LOG: invalid secondary checkpoint record
Allowing negative values makes even less sense for timelines, IMO.
--
Alex
Attachments:
recovery_guc_v5.3.patchtext/x-diffDownload
>From de59408e524e3818a7cea98a7c1f049e09eb9f79 Mon Sep 17 00:00:00 2001
From: Alex Shulgin <ash@commandprompt.com>
Date: Fri, 21 Nov 2014 12:22:22 +0300
Subject: [PATCH] DRAFT: rebased recovery_guc_v5.2.patch
---
contrib/pg_archivecleanup/pg_archivecleanup.c | 2 +-
contrib/pg_standby/pg_standby.c | 2 +-
doc/src/sgml/backup.sgml | 40 +-
doc/src/sgml/config.sgml | 495 ++++++++++++++++++++++++
doc/src/sgml/filelist.sgml | 1 -
doc/src/sgml/func.sgml | 2 +-
doc/src/sgml/high-availability.sgml | 39 +-
doc/src/sgml/pgarchivecleanup.sgml | 6 +-
doc/src/sgml/pgstandby.sgml | 4 +-
doc/src/sgml/postgres.sgml | 1 -
doc/src/sgml/recovery-config.sgml | 460 ----------------------
doc/src/sgml/ref/pg_basebackup.sgml | 8 +-
doc/src/sgml/release-9.1.sgml | 7 +-
doc/src/sgml/release-9.4.sgml | 12 +-
doc/src/sgml/release.sgml | 4 +-
src/backend/Makefile | 4 +-
src/backend/access/transam/recovery.conf.sample | 153 --------
src/backend/access/transam/xlog.c | 405 ++++++-------------
src/backend/access/transam/xlogarchive.c | 4 +-
src/backend/commands/extension.c | 2 +-
src/backend/utils/misc/guc.c | 290 ++++++++++++++
src/backend/utils/misc/postgresql.conf.sample | 34 +-
src/bin/pg_basebackup/pg_basebackup.c | 206 +---------
src/bin/pg_ctl/pg_ctl.c | 8 +-
src/include/access/xlog.h | 17 +
src/include/utils/guc_tables.h | 2 +
src/port/quotes.c | 3 +-
27 files changed, 1039 insertions(+), 1172 deletions(-)
delete mode 100644 doc/src/sgml/recovery-config.sgml
delete mode 100644 src/backend/access/transam/recovery.conf.sample
diff --git a/contrib/pg_archivecleanup/pg_archivecleanup.c b/contrib/pg_archivecleanup/pg_archivecleanup.c
index 97225a8..b5c1059 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 d6b1692..a6a2592 100644
--- a/contrib/pg_standby/pg_standby.c
+++ b/contrib/pg_standby/pg_standby.c
@@ -527,7 +527,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 07ca0dc..7b66e31 100644
--- a/doc/src/sgml/backup.sgml
+++ b/doc/src/sgml/backup.sgml
@@ -1046,10 +1046,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>
@@ -1058,10 +1065,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>
@@ -1075,12 +1081,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
@@ -1142,7 +1147,7 @@ restore_command = 'cp /mnt/server/archivedir/%f %p'
<para>
If you want to recover to some previous point in time (say, right before
the junior DBA dropped your main transaction table), just specify the
- required <link linkend="recovery-target-settings">stopping point</link> in <filename>recovery.conf</>. You can specify
+ required <link linkend="runtime-config-wal-recovery-target">stopping point</link> 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
@@ -1239,8 +1244,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 ab8c263..d1c1353 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -2540,6 +2540,393 @@ include_dir 'conf.d'
</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>)
+ <indexterm>
+ <primary><varname>restore_command</> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <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>)
+ <indexterm>
+ <primary><varname>archive_cleanup_command</> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <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>)
+ <indexterm>
+ <primary><varname>recovery_end_command</> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <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>
+
+ <varlistentry id="min-recovery-apply-delay" xreflabel="min_recovery_apply_delay">
+ <term><varname>min_recovery_apply_delay</varname> (<type>integer</type>)
+ <indexterm>
+ <primary><varname>min_recovery_apply_delay</> recovery parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ By default, a standby server keeps restoring WAL records from the
+ primary as soon as possible. It may be useful to have a time-delayed
+ copy of the data, offering various options to correct data loss errors.
+ This parameter allows you to delay recovery by a fixed period of time,
+ specified in milliseconds if no unit is specified. For example, if
+ you set this parameter to <literal>5min</literal>, the standby will
+ replay each transaction commit only when the system time on the standby
+ is at least five minutes past the commit time reported by the master.
+ </para>
+ <para>
+ It is possible that the replication delay between servers exceeds the
+ value of this parameter, in which case no delay is added.
+ Note that the delay is calculated between the WAL timestamp as written
+ on master and the time on the current standby. Delays
+ in transfer because of networks or cascading replication configurations
+ may reduce the actual wait time significantly. If the system
+ clocks on master and standby are not synchronised, this may lead to
+ recovery applying records earlier than expected but is not a major issue
+ because the useful settings of the parameter are much larger than
+ typical time deviation between the servers. Be careful to allow for
+ different timezone settings on master and standby.
+ </para>
+ <para>
+ The delay occurs only on WAL records for COMMIT and Restore Points.
+ Other records may be replayed earlier than the specified delay, which
+ is not an issue for MVCC though may potentially increase the number
+ of recovery conflicts generated.
+ </para>
+ <para>
+ The delay occurs until the standby is promoted or triggered. After that
+ the standby will end recovery without further waiting.
+ </para>
+ <para>
+ This parameter is intended for use with streaming replication deployments,
+ however, if the parameter is specified it will be honoured in all cases.
+ Synchronous replication is not affected by this setting because there is
+ not yet any setting to request synchronous apply of transaction commits.
+ <varname>hot_standby_feedback</> will be delayed by use of this feature
+ which could lead to bloat on the master; use both together with care.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </sect2>
+
+ <sect2 id="runtime-config-wal-recovery-target">
+ <title>Recovery Target</title>
+
+ <variablelist>
+
+ <varlistentry id="guc-recovery-target" xreflabel="recovery_target_name">
+ <term><varname>recovery_target</varname><literal> = 'immediate'</literal>
+ <indexterm>
+ <primary><varname>recovery_target</> recovery parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ This parameter specifies that recovery should end as soon as a
+ consistent state is reached, i.e. as early as possible. When restoring
+ from an online backup, this means the point where taking the backup
+ ended.
+ </para>
+ <para>
+ Technically, this is a string parameter, but <literal>'immediate'</>
+ is currently the only allowed value.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="guc-recovery-target-name" xreflabel="recovery_target_name">
+ <term><varname>recovery_target_name</varname> (<type>string</type>)
+ <indexterm>
+ <primary><varname>recovery_target_name</> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <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>)
+ <indexterm>
+ <primary><varname>recovery_target_time</> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <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>)
+ <indexterm>
+ <primary><varname>recovery_target_xid</> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <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>)
+ <indexterm>
+ <primary><varname>recovery_target_inclusive</> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <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>)
+ <indexterm>
+ <primary><varname>recovery_target_timeline</> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <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>)
+ <indexterm>
+ <primary><varname>pause_at_recovery_target</> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <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-recovery-conf-substitute">
+ <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>
@@ -2789,6 +3176,114 @@ include_dir 'conf.d'
<variablelist>
+ <varlistentry id="guc-standby-mode" xreflabel="standby_mode">
+ <term><varname>standby_mode</varname> (<type>boolean</type>)
+ <indexterm>
+ <primary><varname>standby_mode</> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <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>)
+ <indexterm>
+ <primary><varname>primary_conninfo</> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <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="primary-slot-name" xreflabel="primary_slot_name">
+ <term><varname>primary_slot_name</varname> (<type>string</type>)
+ <indexterm>
+ <primary><varname>primary_slot_name</> recovery parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Optionally specifies an existing replication slot to be used when
+ connecting to the primary via streaming replication to control
+ resource removal on the upstream node
+ (see <xref linkend="streaming-replication-slots">).
+ This setting has no effect if <varname>primary_conninfo</> is not
+ set.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="guc-trigger-file" xreflabel="trigger_file">
+ <term><varname>trigger_file</varname> (<type>string</type>)
+ <indexterm>
+ <primary><varname>trigger_file</> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <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>)
<indexterm>
diff --git a/doc/src/sgml/filelist.sgml b/doc/src/sgml/filelist.sgml
index f03b72a..feff95f3 100644
--- a/doc/src/sgml/filelist.sgml
+++ b/doc/src/sgml/filelist.sgml
@@ -44,7 +44,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 90a3460..73c5196 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -16322,7 +16322,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 d249959..e7e88aa 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
@@ -660,8 +660,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
@@ -697,7 +697,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
@@ -708,7 +708,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'
@@ -766,8 +766,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
@@ -827,15 +827,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
@@ -1292,8 +1291,8 @@ primary_slot_name = 'node_a_slot'
<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
@@ -1338,8 +1337,7 @@ primary_slot_name = 'node_a_slot'
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
@@ -1426,8 +1424,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>
@@ -1923,9 +1927,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 fdf0cbb..cf5d229 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 fb3f32e..545cf85 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 a648a4c..bce9acd 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 0f1ff34..0000000
--- a/doc/src/sgml/recovery-config.sgml
+++ /dev/null
@@ -1,460 +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>)
- <indexterm>
- <primary><varname>restore_command</> recovery parameter</primary>
- </indexterm>
- </term>
- <listitem>
- <para>
- The local 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>
- An exception is that if the command was terminated by a signal (other
- than <systemitem>SIGTERM</systemitem>, which is used as part of a
- database server shutdown) or an error by the shell (such as command
- not found), then recovery will abort and the server will not start up.
- </para>
- </listitem>
- </varlistentry>
-
- <varlistentry id="archive-cleanup-command" xreflabel="archive_cleanup_command">
- <term><varname>archive_cleanup_command</varname> (<type>string</type>)
- <indexterm>
- <primary><varname>archive_cleanup_command</> recovery parameter</primary>
- </indexterm>
- </term>
- <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 nonzero exit status then a warning log
- message will be written. An exception is that if the command was
- terminated by a signal or an error by the shell (such as command not
- found), a fatal error will be raised.
- </para>
- </listitem>
- </varlistentry>
-
- <varlistentry id="recovery-end-command" xreflabel="recovery_end_command">
- <term><varname>recovery_end_command</varname> (<type>string</type>)
- <indexterm>
- <primary><varname>recovery_end_command</> recovery parameter</primary>
- </indexterm>
- </term>
- <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 nonzero 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 or an error by the shell (such as command not found), the
- database will not proceed with startup.
- </para>
- </listitem>
- </varlistentry>
-
- </variablelist>
-
- </sect1>
-
- <sect1 id="recovery-target-settings">
-
- <title>Recovery Target Settings</title>
- <para>
- By default, recovery will recover to the end of the WAL log. The
- following parameters can be used to specify an earlier stopping point.
- At most one of <varname>recovery_target</>,
- <varname>recovery_target_name</>, <varname>recovery_target_time</>, or
- <varname>recovery_target_xid</> can be specified.
- </para>
- <variablelist>
-
- <varlistentry id="recovery-target" xreflabel="recovery_target_name">
- <term><varname>recovery_target</varname><literal> = 'immediate'</literal>
- <indexterm>
- <primary><varname>recovery_target</> recovery parameter</primary>
- </indexterm>
- </term>
- <listitem>
- <para>
- This parameter specifies that recovery should end as soon as a
- consistent state is reached, i.e. as early as possible. When restoring
- from an online backup, this means the point where taking the backup
- ended.
- </para>
- <para>
- Technically, this is a string parameter, but <literal>'immediate'</>
- is currently the only allowed value.
- </para>
- </listitem>
- </varlistentry>
-
- <varlistentry id="recovery-target-name" xreflabel="recovery_target_name">
- <term><varname>recovery_target_name</varname> (<type>string</type>)
- <indexterm>
- <primary><varname>recovery_target_name</> recovery parameter</primary>
- </indexterm>
- </term>
- <listitem>
- <para>
- This parameter specifies the named restore point, created with
- <function>pg_create_restore_point()</> to which recovery will proceed.
- </para>
- </listitem>
- </varlistentry>
-
- <varlistentry id="recovery-target-time" xreflabel="recovery_target_time">
- <term><varname>recovery_target_time</varname> (<type>timestamp</type>)
- <indexterm>
- <primary><varname>recovery_target_time</> recovery parameter</primary>
- </indexterm>
- </term>
- <listitem>
- <para>
- This parameter specifies the time stamp up to which recovery
- will proceed.
- 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>)
- <indexterm>
- <primary><varname>recovery_target_xid</> recovery parameter</primary>
- </indexterm>
- </term>
- <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.
- The precise stopping point is also influenced by
- <xref linkend="recovery-target-inclusive">.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- <para>
- The following options further specify the recovery target, and affect
- what happens when the target is reached:
- </para>
-
- <variablelist>
-
- <varlistentry id="recovery-target-inclusive"
- xreflabel="recovery_target_inclusive">
- <term><varname>recovery_target_inclusive</varname> (<type>boolean</type>)
- <indexterm>
- <primary><varname>recovery_target_inclusive</> recovery parameter</primary>
- </indexterm>
- </term>
- <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>)
- <indexterm>
- <primary><varname>recovery_target_timeline</> recovery parameter</primary>
- </indexterm>
- </term>
- <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>)
- <indexterm>
- <primary><varname>pause_at_recovery_target</> recovery parameter</primary>
- </indexterm>
- </term>
- <listitem>
- <para>
- Specifies whether recovery should pause when the recovery target
- is reached. The default is true.
- This is intended to allow queries to be executed against the
- database to check if this recovery target is the most desirable
- point for recovery. The paused state can be resumed by using
- <function>pg_xlog_replay_resume()</> (See
- <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>)
- <indexterm>
- <primary><varname>standby_mode</> recovery parameter</primary>
- </indexterm>
- </term>
- <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>)
- <indexterm>
- <primary><varname>primary_conninfo</> recovery parameter</primary>
- </indexterm>
- </term>
- <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="primary-slot-name" xreflabel="primary_slot_name">
- <term><varname>primary_slot_name</varname> (<type>string</type>)
- <indexterm>
- <primary><varname>primary_slot_name</> recovery parameter</primary>
- </indexterm>
- </term>
- <listitem>
- <para>
- Optionally specifies an existing replication slot to be used when
- connecting to the primary via streaming replication to control
- resource removal on the upstream node
- (see <xref linkend="streaming-replication-slots">).
- This setting has no effect if <varname>primary_conninfo</> is not
- set.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry id="trigger-file" xreflabel="trigger_file">
- <term><varname>trigger_file</varname> (<type>string</type>)
- <indexterm>
- <primary><varname>trigger_file</> recovery parameter</primary>
- </indexterm>
- </term>
- <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>
-
- <varlistentry id="recovery-min-apply-delay" xreflabel="recovery_min_apply_delay">
- <term><varname>recovery_min_apply_delay</varname> (<type>integer</type>)
- <indexterm>
- <primary><varname>recovery_min_apply_delay</> recovery parameter</primary>
- </indexterm>
- </term>
- <listitem>
- <para>
- By default, a standby server restores WAL records from the
- primary as soon as possible. It may be useful to have a time-delayed
- copy of the data, offering various options to correct data loss errors.
- This parameter allows you to delay recovery by a fixed period of time,
- specified in milliseconds if no unit is specified. For example, if
- you set this parameter to <literal>5min</literal>, the standby will
- replay each transaction commit only when the system time on the standby
- is at least five minutes past the commit time reported by the master.
- </para>
- <para>
- It is possible that the replication delay between servers exceeds the
- value of this parameter, in which case no delay is added.
- Note that the delay is calculated between the WAL timestamp as written
- on master and the time on the current standby. Delays
- in transfer because of networks or cascading replication configurations
- may reduce the actual wait time significantly. If the system
- clocks on master and standby are not synchronized, this may lead to
- recovery applying records earlier than expected; but that is not a
- major issue because useful settings of the parameter are much larger
- than typical time deviations between servers. Be careful to allow for
- different timezone settings on master and standby.
- </para>
- <para>
- The delay occurs only on WAL records for COMMIT and Restore Points.
- Other records may be replayed earlier than the specified delay, which
- is not an issue for MVCC though it may potentially increase the number
- of recovery conflicts generated.
- </para>
- <para>
- The delay occurs until the standby is promoted or triggered. After that
- the standby will end recovery without further waiting.
- </para>
- <para>
- This parameter is intended for use with streaming replication deployments,
- however, if the parameter is specified it will be honored in all cases.
- Synchronous replication is not affected by this setting because there is
- not yet any setting to request synchronous apply of transaction commits.
- <varname>hot_standby_feedback</> will be delayed by use of this feature
- which could lead to bloat on the master; use both together with care.
- </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 642fccf..06a91a1 100644
--- a/doc/src/sgml/ref/pg_basebackup.sgml
+++ b/doc/src/sgml/ref/pg_basebackup.sgml
@@ -211,13 +211,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 4f86b64..e899e7e 100644
--- a/doc/src/sgml/release-9.1.sgml
+++ b/doc/src/sgml/release-9.1.sgml
@@ -6302,7 +6302,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>
@@ -6322,7 +6322,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>
@@ -6354,8 +6354,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-9.4.sgml b/doc/src/sgml/release-9.4.sgml
index a249b3f..120fede 100644
--- a/doc/src/sgml/release-9.4.sgml
+++ b/doc/src/sgml/release-9.4.sgml
@@ -335,7 +335,7 @@
<listitem>
<para>
- Use the last specified <xref linkend="recovery-target"> if multiple
+ Use the last specified <xref linkend="guc-recovery-target"> if multiple
values are specified (Heikki Linnakangas)
</para>
</listitem>
@@ -349,7 +349,7 @@
<para>
User commands that did their own quote preservation might need
adjustment. This is likely to be an issue for commands used in
- <xref linkend="guc-archive-command">, <xref linkend="restore-command">,
+ <xref linkend="guc-archive-command">, <xref linkend="guc-restore-command">,
and <link linkend="sql-copy"><command>COPY TO/FROM PROGRAM</></link>.
</para>
</listitem>
@@ -993,8 +993,8 @@
<listitem>
<para>
- Add <link linkend="recovery-config"><filename>recovery.conf</></link>
- parameter <xref linkend="recovery-min-apply-delay">
+ Add <link linkend="config-setting"><filename>postgresql.conf</></link>
+ parameter <xref linkend="min-recovery-apply-delay">
to delay replication (Robert Haas, Fabrízio de Royes Mello,
Simon Riggs)
</para>
@@ -1007,7 +1007,7 @@
<listitem>
<para>
- Add <xref linkend="recovery-target">
+ Add <xref linkend="guc-recovery-target">
option <option>immediate</> to stop <link
linkend="wal"><acronym>WAL</></link> recovery as soon as a
consistent state is reached (MauMau, Heikki Linnakangas)
@@ -1044,7 +1044,7 @@
<listitem>
<para>
Report failure return codes from <link
- linkend="archive-recovery-settings">external recovery commands</>
+ linkend="runtime-config-wal-archive-recovery">external recovery commands</>
(Peter Eisentraut)
</para>
</listitem>
diff --git a/doc/src/sgml/release.sgml b/doc/src/sgml/release.sgml
index 8385220..1b983fa 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 870a022..638d0c5 100644
--- a/src/backend/Makefile
+++ b/src/backend/Makefile
@@ -215,7 +215,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)'
@@ -272,8 +271,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 7657df3..0000000
--- a/src/backend/access/transam/recovery.conf.sample
+++ /dev/null
@@ -1,153 +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
-#
-#
-# Alternatively, you can request stopping as soon as a consistent state
-# is reached, by uncommenting this option.
-#
-#recovery_target = 'immediate'
-#
-#
-# 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'
-#
-# If set, the PostgreSQL server will use the specified replication slot when
-# connecting to the primary via streaming replication to control resource
-# removal on the upstream node. This setting has no effect if primary_conninfo
-# is not set.
-#
-#primary_slot_name = ''
-#
-# 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 a 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 = ''
-#
-# By default, a standby server restores XLOG records from the primary as
-# soon as possible. If you want to explicitly delay the replay of committed
-# transactions from the master, specify a minimum apply delay. For example,
-# if you set this parameter to 5min, the standby will replay each transaction
-# commit only when the system time on the standby is at least five minutes
-# past the commit time reported by the master.
-#
-#recovery_min_apply_delay = 0
-#
-#---------------------------------------------------------------------------
-# 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 2059bbe..2fe96d1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -71,11 +71,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 RECOVERY_ENABLE_FILE "standby.enabled"
#define PROMOTE_SIGNAL_FILE "promote"
#define FALLBACK_PROMOTE_SIGNAL_FILE "fallback_promote"
+/* recovery.conf is not supported anymore */
+#define RECOVERY_COMMAND_FILE "recovery.conf"
/* User-settable parameters */
int CheckPointSegments = 3;
@@ -207,7 +208,7 @@ static int LocalXLogInsertAllowed = -1;
/*
* When ArchiveRecoveryRequested is set, archive recovery was requested,
- * ie. recovery.conf file was present. When InArchiveRecovery is set, we are
+ * ie. standby.enabled file was present. When InArchiveRecovery is set, we are
* currently recovering using offline XLOG archives. These variables are only
* valid in the startup process.
*
@@ -222,27 +223,29 @@ 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;
-static int recovery_min_apply_delay = 0;
-static TimestampTz recoveryDelayUntilTime;
-
-/* options taken from recovery.conf for XLOG streaming */
-static bool StandbyModeRequested = false;
-static char *PrimaryConnInfo = NULL;
-static char *PrimarySlotName = NULL;
-static char *TriggerFile = NULL;
+char *restore_command = NULL;
+char *archive_cleanup_command = NULL;
+char *recovery_end_command = NULL;
+char *primary_conninfo = NULL;
+char *primary_slot_name = NULL;
+char *trigger_file = NULL;
+char *recovery_target_string = NULL;
+RecoveryTargetType recovery_target = RECOVERY_TARGET_UNSET;
+char *recovery_target_xid_string = NULL;
+TransactionId recovery_target_xid = InvalidTransactionId;
+char *recovery_target_time_string = NULL;
+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 recovery_min_apply_delay = 0;
+static TimestampTz recoveryDelayUntilTime;
/* are we currently in standby mode? */
-bool StandbyMode = false;
+bool StandbyModeRequested = false;
+bool StandbyMode = false;
/* whether request for fast promotion has been made yet */
static bool fast_promote = false;
@@ -547,12 +550,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.
*/
@@ -755,7 +752,7 @@ static bool holdingAllLocks = false;
static MemoryContext walDebugCxt = NULL;
#endif
-static void readRecoveryCommandFile(void);
+static void CheckStartingAsStandby(void);
static void exitArchiveRecovery(TimeLineID endTLI, XLogSegNo endLogSegNo);
static bool recoveryStopsBefore(XLogReaderState *record);
static bool recoveryStopsAfter(XLogReaderState *record);
@@ -4639,228 +4636,45 @@ str_time(pg_time_t tnow)
* The file is parsed using the main configuration parser.
*/
static void
-readRecoveryCommandFile(void)
+CheckStartingAsStandby(void)
{
FILE *fd;
- TimeLineID rtli = 0;
- bool rtliGiven = false;
- ConfigVariable *item,
- *head = NULL,
- *tail = NULL;
- fd = AllocateFile(RECOVERY_COMMAND_FILE, "r");
+ /* Check the presence of recovery.conf, it is not supported anymore */
+ if (AllocateFile(RECOVERY_COMMAND_FILE, "r") != NULL)
+ ereport(FATAL,
+ (errmsg("\"%s\" is not supported anymore as a recovery method",
+ RECOVERY_COMMAND_FILE),
+ errdetail("Refer to appropriate documentation about migration methods")));
+
+ /* Check the presence of file standby.enabled, the file triggering recovery */
+ fd = AllocateFile(RECOVERY_ENABLE_FILE, "r");
if (fd == NULL)
{
if (errno == ENOENT)
return; /* not there, so no archive recovery */
ereport(FATAL,
(errcode_for_file_access(),
- errmsg("could not open recovery command file \"%s\": %m",
- RECOVERY_COMMAND_FILE)));
+ errmsg("could not open recovery file trigger \"%s\": %m",
+ RECOVERY_ENABLE_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)
- {
- 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)
- {
- 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") == 0)
- {
- if (strcmp(item->value, "immediate") == 0)
- recoveryTarget = RECOVERY_TARGET_IMMEDIATE;
- else
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
- errmsg("invalid value for recovery parameter \"recovery_target\""),
- errhint("The only allowed value is \"immediate\".")));
- ereport(DEBUG2,
- (errmsg_internal("recovery_target = '%s'",
- item->value)));
- }
- else if (strcmp(item->name, "recovery_target_inclusive") == 0)
- {
- /*
- * does nothing if a recovery_target is not also set
- */
- if (!parse_bool(item->value, &recoveryTargetInclusive))
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
- errmsg("parameter \"%s\" requires a Boolean value",
- "recovery_target_inclusive")));
- ereport(DEBUG2,
- (errmsg_internal("recovery_target_inclusive = %s",
- item->value)));
- }
- else if (strcmp(item->name, "standby_mode") == 0)
- {
- if (!parse_bool(item->value, &StandbyModeRequested))
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
- errmsg("parameter \"%s\" requires a Boolean value",
- "standby_mode")));
- ereport(DEBUG2,
- (errmsg_internal("standby_mode = '%s'", item->value)));
- }
- else if (strcmp(item->name, "primary_conninfo") == 0)
- {
- PrimaryConnInfo = pstrdup(item->value);
- ereport(DEBUG2,
- (errmsg_internal("primary_conninfo = '%s'",
- PrimaryConnInfo)));
- }
- else if (strcmp(item->name, "primary_slot_name") == 0)
- {
- ReplicationSlotValidateName(item->value, ERROR);
- PrimarySlotName = pstrdup(item->value);
- ereport(DEBUG2,
- (errmsg_internal("primary_slot_name = '%s'",
- PrimarySlotName)));
- }
- else if (strcmp(item->name, "trigger_file") == 0)
- {
- TriggerFile = pstrdup(item->value);
- ereport(DEBUG2,
- (errmsg_internal("trigger_file = '%s'",
- TriggerFile)));
- }
- else if (strcmp(item->name, "recovery_min_apply_delay") == 0)
- {
- const char *hintmsg;
-
- if (!parse_int(item->value, &recovery_min_apply_delay, GUC_UNIT_MS,
- &hintmsg))
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
- errmsg("parameter \"%s\" requires a temporal value",
- "recovery_min_apply_delay"),
- hintmsg ? errhint("%s", _(hintmsg)) : 0));
- ereport(DEBUG2,
- (errmsg_internal("recovery_min_apply_delay = '%s'", item->value)));
- }
- else
- ereport(FATAL,
- (errmsg("unrecognized recovery parameter \"%s\"",
- item->name)));
- }
-
/*
* Check for compulsory parameters
*/
if (StandbyModeRequested)
{
- if (PrimaryConnInfo == NULL && recoveryRestoreCommand == NULL)
+ if (primary_conninfo == NULL && restore_command == NULL)
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 == NULL)
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 */
@@ -4872,16 +4686,17 @@ readRecoveryCommandFile(void)
* command and set InArchiveRecovery, because we need to fetch timeline
* history files from the archive.
*/
- if (rtliGiven)
+ if (recovery_target_timeline_string != NULL)
{
- if (rtli)
+ if (recovery_target_timeline != 0) /* not "", "0" or "latest" */
{
/* 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
@@ -4891,8 +4706,6 @@ readRecoveryCommandFile(void)
recoveryTargetIsLatest = true;
}
}
-
- FreeConfigVariables(head);
}
/*
@@ -4965,15 +4778,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")));
@@ -5044,7 +4855,7 @@ recoveryStopsBefore(XLogReaderState *record)
TransactionId recordXid;
/* Check if we should stop as soon as reaching consistency */
- if (recoveryTarget == RECOVERY_TARGET_IMMEDIATE && reachedConsistency)
+ if (recovery_target == RECOVERY_TARGET_IMMEDIATE && reachedConsistency)
{
ereport(LOG,
(errmsg("recovery stopping after reaching consistency")));
@@ -5084,7 +4895,7 @@ recoveryStopsBefore(XLogReaderState *record)
else
return false;
- if (recoveryTarget == RECOVERY_TARGET_XID && !recoveryTargetInclusive)
+ if (recovery_target == RECOVERY_TARGET_XID && !recovery_target_inclusive)
{
/*
* There can be only one transaction end record with this exact
@@ -5095,10 +4906,10 @@ recoveryStopsBefore(XLogReaderState *record)
* they complete. A higher numbered xid will complete before you about
* 50% of the time...
*/
- stopsHere = (recordXid == recoveryTargetXid);
+ stopsHere = (recordXid == recovery_target_xid);
}
- if (recoveryTarget == RECOVERY_TARGET_TIME &&
+ if (recovery_target == RECOVERY_TARGET_TIME &&
getRecordTimestamp(record, &recordXtime))
{
/*
@@ -5106,10 +4917,10 @@ recoveryStopsBefore(XLogReaderState *record)
* 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)
@@ -5158,14 +4969,14 @@ recoveryStopsAfter(XLogReaderState *record)
* There can be many restore points that share the same name; we stop at
* the first one.
*/
- if (recoveryTarget == RECOVERY_TARGET_NAME &&
+ if (recovery_target == RECOVERY_TARGET_NAME &&
rmid == RM_XLOG_ID && record_info == XLOG_RESTORE_POINT)
{
xl_restore_point *recordRestorePointData;
recordRestorePointData = (xl_restore_point *) XLogRecGetData(record);
- if (strcmp(recordRestorePointData->rp_name, recoveryTargetName) == 0)
+ if (strcmp(recordRestorePointData->rp_name, recovery_target_name) == 0)
{
recoveryStopAfter = true;
recoveryStopXid = InvalidTransactionId;
@@ -5210,8 +5021,8 @@ recoveryStopsAfter(XLogReaderState *record)
* they complete. A higher numbered xid will complete before you about
* 50% of the time...
*/
- if (recoveryTarget == RECOVERY_TARGET_XID && recoveryTargetInclusive &&
- recordXid == recoveryTargetXid)
+ if (recovery_target == RECOVERY_TARGET_XID && recovery_target_inclusive &&
+ recordXid == recovery_target_xid)
{
recoveryStopAfter = true;
recoveryStopXid = recordXid;
@@ -5240,7 +5051,7 @@ recoveryStopsAfter(XLogReaderState *record)
}
/* Check if we should stop as soon as reaching consistency */
- if (recoveryTarget == RECOVERY_TARGET_IMMEDIATE && reachedConsistency)
+ if (recovery_target == RECOVERY_TARGET_IMMEDIATE && reachedConsistency)
{
ereport(LOG,
(errmsg("recovery stopping after reaching consistency")));
@@ -5524,6 +5335,16 @@ CheckRequiredParameterValues(void)
}
}
+static void
+InitRecoveryTarget(RecoveryTargetType new_value)
+{
+ if (recovery_target != RECOVERY_TARGET_UNSET)
+ ereport(FATAL,
+ (errmsg("At most one of recovery_target, recovery_target_name, recovery_target_time or recovery_target_xid may be specified.")));
+
+ recovery_target = new_value;
+}
+
/*
* This must be called ONCE during postmaster or standalone-backend startup
*/
@@ -5629,37 +5450,45 @@ StartupXLOG(void)
recoveryTargetTLI = ControlFile->checkPointCopy.ThisTimeLineID;
/*
- * Check for recovery control file, and if so set up state for offline
- * recovery
+ * Set recovery_target, make sure only one of the recovery_target* GUCs is
+ * used.
*/
- readRecoveryCommandFile();
+ if (recovery_target_xid_string != NULL)
+ InitRecoveryTarget(RECOVERY_TARGET_XID);
+
+ if (recovery_target_time_string != NULL)
+ InitRecoveryTarget(RECOVERY_TARGET_TIME);
+
+ if (recovery_target_name != NULL)
+ InitRecoveryTarget(RECOVERY_TARGET_NAME);
+
+ if (recovery_target_string != NULL)
+ InitRecoveryTarget(RECOVERY_TARGET_IMMEDIATE);
/*
- * Save archive_cleanup_command in shared memory so that other processes
- * can see it.
- */
- strlcpy(XLogCtl->archiveCleanupCommand,
- archiveCleanupCommand ? archiveCleanupCommand : "",
- sizeof(XLogCtl->archiveCleanupCommand));
+ * Check for recovery trigger file, and if so set up state for offline
+ * recovery.
+ */
+ CheckStartingAsStandby();
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)));
- else if (recoveryTarget == RECOVERY_TARGET_IMMEDIATE)
+ recovery_target_name)));
+ else if (recovery_target == RECOVERY_TARGET_IMMEDIATE)
ereport(LOG,
(errmsg("starting point-in-time recovery to earliest consistent point")));
else
@@ -5942,7 +5771,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)
@@ -5956,7 +5785,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;
}
@@ -6415,7 +6244,7 @@ StartupXLOG(void)
* end of main redo apply loop
*/
- if (recoveryPauseAtTarget && reachedStopPoint)
+ if (pause_at_recovery_target && reachedStopPoint)
{
SetRecoveryPause(true);
recoveryPausesHere();
@@ -6557,21 +6386,21 @@ 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);
- else if (recoveryTarget == RECOVERY_TARGET_IMMEDIATE)
+ else if (recovery_target == RECOVERY_TARGET_IMMEDIATE)
snprintf(reason, sizeof(reason), "reached consistency");
else
snprintf(reason, sizeof(reason), "no recovery target specified");
@@ -6719,8 +6548,8 @@ StartupXLOG(void)
/*
* And finally, execute the recovery_end_command, if any.
*/
- if (recoveryEndCommand)
- ExecuteRecoveryCommand(recoveryEndCommand,
+ if (recovery_end_command)
+ ExecuteRecoveryCommand(recovery_end_command,
"recovery_end_command",
true);
}
@@ -8248,8 +8077,8 @@ CreateRestartPoint(int flags)
/*
* Finally, execute archive_cleanup_command, if any.
*/
- if (XLogCtl->archiveCleanupCommand[0])
- ExecuteRecoveryCommand(XLogCtl->archiveCleanupCommand,
+ if (archive_cleanup_command)
+ ExecuteRecoveryCommand(archive_cleanup_command,
"archive_cleanup_command",
false);
@@ -10244,7 +10073,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)
{
XLogRecPtr ptr;
TimeLineID tli;
@@ -10265,8 +10094,8 @@ WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess,
tli, curFileTLI);
}
curFileTLI = tli;
- RequestXLogStreaming(tli, ptr, PrimaryConnInfo,
- PrimarySlotName);
+ RequestXLogStreaming(tli, ptr, primary_conninfo,
+ primary_slot_name);
receivedUpto = 0;
}
@@ -10583,14 +10412,14 @@ CheckForStandbyTrigger(void)
return true;
}
- if (TriggerFile == NULL)
+ if (trigger_file == NULL)
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;
@@ -10599,7 +10428,7 @@ CheckForStandbyTrigger(void)
ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not stat trigger file \"%s\": %m",
- TriggerFile)));
+ trigger_file)));
return false;
}
diff --git a/src/backend/access/transam/xlogarchive.c b/src/backend/access/transam/xlogarchive.c
index 047efa2..46e5945 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 9a0afa4..0ed51dd 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-2014, PostgreSQL Global Development Group
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 23cbe90..6d7d306 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -190,6 +190,14 @@ static void assign_application_name(const char *newval, void *extra);
static bool check_cluster_name(char **newval, void **extra, GucSource source);
static const char *show_unix_socket_permissions(void);
static const char *show_log_file_mode(void);
+static bool check_recovery_target(char **newval, void **extra, GucSource source);
+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 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,
@@ -585,6 +593,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 */
@@ -1448,6 +1460,36 @@ static struct config_bool ConfigureNamesBool[] =
},
{
+ {"recovery_target_inclusive", PGC_POSTMASTER, WAL_RECOVERY_TARGET,
+ gettext_noop("Sets whether to include or exclude transaction with recovery target."),
+ NULL
+ },
+ &recovery_target_inclusive,
+ true,
+ NULL, NULL, NULL
+ },
+
+ {
+ {"pause_at_recovery_target", PGC_POSTMASTER, 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
@@ -2714,6 +2756,107 @@ 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 an optional shell command to execute at every restartpoint (can be useful to clean up the archive of a standby server)."),
+ 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", PGC_POSTMASTER, WAL_RECOVERY_TARGET,
+ gettext_noop("Sets the recovery 'target' (currently, the only supported value is 'immediate')."),
+ NULL
+ },
+ &recovery_target_string,
+ NULL,
+ check_recovery_target, 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,
+ NULL,
+ 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,
+ NULL,
+ check_recovery_target_name, NULL, 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,
+ NULL,
+ 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,
@@ -9560,4 +9703,151 @@ show_log_file_mode(void)
return buf;
}
+static bool
+check_recovery_target(char **newval, void **extra, GucSource source)
+{
+ if (*newval != NULL && strcmp(*newval, "immediate") != 0) /* strcasecmp? */
+ {
+ GUC_check_errdetail("the only supported value is 'immediate'");
+ return false;
+ }
+ return true;
+}
+
+static bool
+check_recovery_target_xid(char **newval, void **extra, GucSource source)
+{
+ TransactionId xid;
+ TransactionId *myextra;
+ char *endptr;
+
+ if (*newval == NULL)
+ return true;
+
+ if ((*newval)[0] == 0)
+ xid = InvalidTransactionId;
+ else
+ {
+ errno = 0;
+ xid = (TransactionId) strtoul(*newval, &endptr, 0);
+ if (*endptr != 0 || errno == EINVAL || errno == ERANGE)
+ {
+ GUC_check_errdetail("positive integer expected");
+ return false;
+ }
+ }
+
+ myextra = (TransactionId *) guc_malloc(ERROR, sizeof(TransactionId));
+ *myextra = xid;
+ *extra = (void *) myextra;
+
+ return true;
+}
+
+static void
+assign_recovery_target_xid(const char *newval, void *extra)
+{
+ if (extra != NULL)
+ recovery_target_xid = *((TransactionId *) extra);
+}
+
+static bool
+check_recovery_target_name(char **newval, void **extra, GucSource source)
+{
+ if (*newval != NULL && strlen(*newval) >= MAXFNAMELEN)
+ {
+ GUC_check_errdetail("value string is too long (maximum %d characters)",
+ MAXFNAMELEN - 1);
+ return false;
+ }
+ return true;
+}
+
+static bool
+check_recovery_target_time(char **newval, void **extra, GucSource source)
+{
+ TimestampTz time;
+ TimestampTz *myextra;
+ MemoryContext cctx = CurrentMemoryContext;
+
+ if (*newval == NULL)
+ return true;
+
+ if ((*newval)[0] == 0)
+ time = 0;
+ else
+ {
+ PG_TRY();
+ {
+ time = DatumGetTimestampTz(DirectFunctionCall3(timestamptz_in,
+ CStringGetDatum(*newval),
+ ObjectIdGetDatum(InvalidOid),
+ Int32GetDatum(-1)));
+ }
+ PG_CATCH();
+ {
+ ErrorData *errdata;
+
+ MemoryContextSwitchTo(cctx);
+ errdata = CopyErrorData(); /* do we really have to make a copy? */
+
+ GUC_check_errdetail("%s", errdata->message);
+ /* Don't FlushErrorState() here, the hook caller does that. */
+
+ return false;
+ }
+ PG_END_TRY();
+ }
+
+ myextra = (TimestampTz *) guc_malloc(ERROR, sizeof(TimestampTz));
+ *myextra = time;
+ *extra = (void *) myextra;
+
+ return true;
+}
+
+static void
+assign_recovery_target_time(const char *newval, void *extra)
+{
+ if (extra != NULL)
+ recovery_target_time = *((TimestampTz *) extra);
+}
+
+static bool
+check_recovery_target_timeline(char **newval, void **extra, GucSource source)
+{
+ TimeLineID tli = 0;
+ TimeLineID *myextra;
+ char *endptr;
+
+ if (*newval == NULL)
+ return true;
+
+ if ((*newval)[0] == 0 || strcmp(*newval, "latest") == 0)
+ tli = 0;
+ else
+ {
+ errno = 0;
+ tli = (TimeLineID) strtoul(*newval, &endptr, 0);
+ if (*endptr != 0 || errno == EINVAL || errno == ERANGE)
+ {
+ GUC_check_errdetail("positive integer expected");
+ 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)
+{
+ if (extra != NULL)
+ 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 4a89cb7..75b683d 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -212,6 +212,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
@@ -257,7 +274,22 @@
#wal_receiver_timeout = 60s # time that receiver waits for
# communication from master
# in milliseconds; 0 disables
-
+#
+# FIXME: do we really need this one if we already have hot_standby and trigger_file?
+#
+#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'
+#primary_slot_name = '' # replication slot name to use when
+ # connecting to the master server
+ # (has no effect if primary_conninfo
+ # is not set).
+# FIXME: standby_trigger_file ?
+#trigger_file = '' # trigger file to promote the standby
+#recovery_min_apply_delay = 0 # minimum time the standby will be
+ # delayed from master in milliseconds;
+ # 0 disables
#------------------------------------------------------------------------------
# QUERY TUNING
diff --git a/src/bin/pg_basebackup/pg_basebackup.c b/src/bin/pg_basebackup/pg_basebackup.c
index e7c2939..7fabf45 100644
--- a/src/bin/pg_basebackup/pg_basebackup.c
+++ b/src/bin/pg_basebackup/pg_basebackup.c
@@ -90,9 +90,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 disconnect_and_exit(int code);
@@ -101,7 +98,6 @@ static void progress_report(int tablespacenum, const char *filename, bool force)
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 BaseBackup(void);
@@ -899,7 +895,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
@@ -912,19 +908,13 @@ ReceiveTarFile(PGconn *conn, PGresult *res, int rownum)
if (basetablespace && writerecoveryconf)
{
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 */
@@ -968,8 +958,8 @@ ReceiveTarFile(PGconn *conn, PGresult *res, int rownum)
if (!writerecoveryconf || !basetablespace)
{
/*
- * When not writing recovery.conf, or when not working on the base
- * tablespace, we never have to look for an existing recovery.conf
+ * When not writing 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);
@@ -977,7 +967,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.
*
@@ -1023,12 +1013,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);
@@ -1375,175 +1365,14 @@ ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum)
WriteRecoveryConf();
}
-/*
- * Escape a parameter value so that it can be used as part of a libpq
- * connection string, e.g. in:
- *
- * application_name=<value>
- *
- * The returned string is malloc'd. Return NULL on out-of-memory.
- */
-static char *
-escapeConnectionParameter(const char *src)
-{
- bool need_quotes = false;
- bool need_escaping = false;
- const char *p;
- char *dstbuf;
- char *dst;
-
- /*
- * First check if quoting is needed. Any quote (') or backslash (\)
- * characters need to be escaped. Parameters are separated by whitespace,
- * so any string containing whitespace characters need to be quoted. An
- * empty string is represented by ''.
- */
- if (strchr(src, '\'') != NULL || strchr(src, '\\') != NULL)
- need_escaping = true;
- for (p = src; *p; p++)
- {
- if (isspace((unsigned char) *p))
- {
- need_quotes = true;
- break;
- }
- }
-
- if (*src == '\0')
- return pg_strdup("''");
-
- if (!need_quotes && !need_escaping)
- return pg_strdup(src); /* no quoting or escaping needed */
-
- /*
- * Allocate a buffer large enough for the worst case that all the source
- * characters need to be escaped, plus quotes.
- */
- dstbuf = pg_malloc(strlen(src) * 2 + 2 + 1);
-
- dst = dstbuf;
- if (need_quotes)
- *(dst++) = '\'';
- for (; *src; src++)
- {
- if (*src == '\'' || *src == '\\')
- *(dst++) = '\\';
- *(dst++) = *src;
- }
- if (need_quotes)
- *(dst++) = '\'';
- *dst = '\0';
-
- return dstbuf;
-}
-
-/*
- * Escape a string so that it can be used as a value in a key-value pair
- * a configuration file.
- */
-static char *
-escape_quotes(const char *src)
-{
- char *result = escape_single_quotes_ascii(src);
-
- if (!result)
- {
- fprintf(stderr, _("%s: out of memory\n"), progname);
- exit(1);
- }
- return result;
-}
-
-/*
- * Create a recovery.conf file in memory using a PQExpBuffer
- */
-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.
- */
static void
WriteRecoveryConf(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)
@@ -1552,14 +1381,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);
}
@@ -1616,12 +1437,6 @@ BaseBackup(void)
}
/*
- * Build contents of recovery.conf if requested
- */
- if (writerecoveryconf)
- GenerateRecoveryConf(conn);
-
- /*
* Run IDENTIFY_SYSTEM so we can get the timeline
*/
if (!RunIdentifySystem(conn, &sysidentifier, &latesttli, NULL, NULL))
@@ -1892,9 +1707,6 @@ BaseBackup(void)
#endif
}
- /* Free the recovery.conf contents */
- destroyPQExpBuffer(recoveryconfcontents);
-
/*
* End of copy data. Final result is already checked inside the loop.
*/
diff --git a/src/bin/pg_ctl/pg_ctl.c b/src/bin/pg_ctl/pg_ctl.c
index 733f1cb..fc44586 100644
--- a/src/bin/pg_ctl/pg_ctl.c
+++ b/src/bin/pg_ctl/pg_ctl.c
@@ -956,7 +956,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 &&
@@ -1044,7 +1044,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 &&
@@ -1155,7 +1155,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; "
@@ -2371,7 +2371,7 @@ main(int argc, char **argv)
snprintf(version_file, MAXPGPATH, "%s/PG_VERSION", 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 d06fbc0..d8fabe0 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -99,6 +99,23 @@ extern bool EnableHotStandby;
extern bool fullPageWrites;
extern bool wal_log_hints;
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 char *recovery_target_string;
+extern RecoveryTargetType recovery_target;
+extern char *recovery_target_xid_string;
+extern TransactionId recovery_target_xid;
+extern char *recovery_target_time_string;
+extern TimestampTz recovery_target_time;
+extern char *recovery_target_name;
+extern bool recovery_target_inclusive;
+extern bool pause_at_recovery_target;
+extern char *recovery_target_timeline_string;
+extern TimeLineID recovery_target_timeline;
/* WAL levels */
typedef enum WalLevel
diff --git a/src/include/utils/guc_tables.h b/src/include/utils/guc_tables.h
index 47ff880..a9a231e 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,
diff --git a/src/port/quotes.c b/src/port/quotes.c
index 7c8d4ed..3bc23a6 100644
--- a/src/port/quotes.c
+++ b/src/port/quotes.c
@@ -18,8 +18,7 @@
/*
* Escape (by doubling) any single quotes or backslashes in given string
*
- * Note: this is used to process postgresql.conf entries and to quote
- * string literals in pg_basebackup for creating recovery.conf.
+ * Note: this is used to process postgresql.conf entries
* Since postgresql.conf strings are defined to treat backslashes as escapes,
* we have to double backslashes here.
*
--
2.1.0
On 11/21/2014 09:35 AM, Alex Shulgin wrote:
Hello,
Here's an attempt to revive this patch.
Yayy! Thank you.
People might not like me for the suggestion, but I think we should
simply always include a 'recovery.conf' in $PGDATA
unconditionally. That'd make this easier.
Alternatively we could pass a filename to --write-recovery-conf.Well, the latest version of this patch fails to start when it sees
'recovery.conf' in PGDATA:FATAL: "recovery.conf" is not supported anymore as a recovery method
DETAIL: Refer to appropriate documentation about migration methodsI've missed all the discussion behind this decision and after reading
the ALTER SYSTEM/conf.d thread I'm even more confused so I'd like
someone more knowledgeable to speak up on the status of this.
The argument was that people wanted to be able to have an empty
recovery.conf file as a "we're in standby" trigger so that they could
preserve backwards compatibility with external tools. I don't agree
with this argument, but several people championed it.
The docs use the term "continuous recovery".
Either way, from the code it is clear that we only stay in recovery if
standby_mode is directly turned on. This makes the whole check for a
specially named file unnecessary, IMO: we should just check the value of
standby_mode (which is off by default).
So, what happens when someone does "pg_ctl promote"? Somehow
standby_mode needs to get set to "off". Maybe we write "standby_mode =
off" to postgresql.auto.conf?
By the way, is there any use in setting standby_mode=on and any of the
recovery_target* GUCs at the same time?
See my thread on this topic from last week. Short answer: No.
I think it can only play together if you set the target farther than the
latest point you've got in the archive locally. So that's sort of
"Point-in-Future-Recovery". Does that make any sense at all?
Again, see the thread. This doesn't work in a useful way, so there's no
reason to write code to enable it.
/* File path names (all relative to $PGDATA) */ -#define RECOVERY_COMMAND_FILE "recovery.conf" -#define RECOVERY_COMMAND_DONE "recovery.done" +#define RECOVERY_ENABLE_FILE "standby.enabled"Imo the file and variable names should stay coherent.
Yes, once we settle on the name (and if we really need that extra
trigger file.)
Personally, if we have three methods of promotion:
1) pg_ctl promote
2) edit postgresql.conf and reload
3) ALTER SYSTEM SET and reload
... I don't honestly think we need a 4th method for promotion.
The main reason to want a "we're in recovery file" is for PITR rather
than for replication, where it has a number of advantages as a method,
the main one being that recovery.conf is unlikely to be overwritten by
the contents of the backup.
HOWEVER, there's a clear out for this with conf.d. If we enable conf.d
by default, then we can simply put recovery settings in conf.d, and
since that specific file (which can have whatever name the user chooses)
will not be part of backups, it would have the same advantage as
recovery.conf, without the drawbacks.
Discuss?
--
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
Import Notes
Reply to msg id not found: WM975925117d9c3b6912af80946dcf674e21f771800c03a4f03232143358ffd1bedf02f975e0dabea6552f35087095e33e@asav-3.01.comReference msg id not found: WM2eef57bf14271a28b7764a48733ac1bb0352229c58adbbcfc444bf3b2d39b5c4e9068a10e3f688295481db2314a812ff@asav-3.01.com
* Josh Berkus (josh@agliodbs.com) wrote:
Either way, from the code it is clear that we only stay in recovery if
standby_mode is directly turned on. This makes the whole check for a
specially named file unnecessary, IMO: we should just check the value of
standby_mode (which is off by default).So, what happens when someone does "pg_ctl promote"? Somehow
standby_mode needs to get set to "off". Maybe we write "standby_mode =
off" to postgresql.auto.conf?
Uhh, and then not work for the sane folks who disable
postgresql.auto.conf? No thanks..
HOWEVER, there's a clear out for this with conf.d. If we enable conf.d
by default, then we can simply put recovery settings in conf.d, and
since that specific file (which can have whatever name the user chooses)
will not be part of backups, it would have the same advantage as
recovery.conf, without the drawbacks.
conf.d is a possibility, but there may be environments where the
postgres users doesn't have access to write into the conf.d directrory..
Not sure if that'd be an issue for what you're suggesting but wanted to
point it out.
Thanks,
Stephen
On 11/21/2014 10:54 AM, Stephen Frost wrote:
* Josh Berkus (josh@agliodbs.com) wrote:
Either way, from the code it is clear that we only stay in recovery if
standby_mode is directly turned on. This makes the whole check for a
specially named file unnecessary, IMO: we should just check the value of
standby_mode (which is off by default).So, what happens when someone does "pg_ctl promote"? Somehow
standby_mode needs to get set to "off". Maybe we write "standby_mode =
off" to postgresql.auto.conf?Uhh, and then not work for the sane folks who disable
postgresql.auto.conf? No thanks..
Other ideas then, without reverting to the old system? Being able to
promote servers over port 5432 will be a huge advantage for
container-based systems, so I don't want to give that up as a feature.
HOWEVER, there's a clear out for this with conf.d. If we enable conf.d
by default, then we can simply put recovery settings in conf.d, and
since that specific file (which can have whatever name the user chooses)
will not be part of backups, it would have the same advantage as
recovery.conf, without the drawbacks.conf.d is a possibility, but there may be environments where the
postgres users doesn't have access to write into the conf.d directrory..
Not sure if that'd be an issue for what you're suggesting but wanted to
point it out.
It's not a real issue for any use-case I'm currently dealing with.
Would this approach break things for other people?
--
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
Import Notes
Reply to msg id not found: WM880491598d0e895193703f34e3fdfa0e486235d7489aa439dd0c695b8013e67d23e82c67839c90814088eddfc06c80fa@asav-2.01.com
On Sat, Nov 22, 2014 at 12:24 AM, Stephen Frost <sfrost@snowman.net> wrote:
* Josh Berkus (josh@agliodbs.com) wrote:
Either way, from the code it is clear that we only stay in recovery if
standby_mode is directly turned on. This makes the whole check for a
specially named file unnecessary, IMO: we should just check the value
of
standby_mode (which is off by default).
So, what happens when someone does "pg_ctl promote"? Somehow
standby_mode needs to get set to "off". Maybe we write "standby_mode =
off" to postgresql.auto.conf?Uhh, and then not work for the sane folks who disable
postgresql.auto.conf? No thanks..
What exactly you mean by 'disable postgresql.auto.conf', do you
mean user runs Alter System to remove that entry or manually disable
some particular entry?
By default postgresql.auto.conf is always read, so if there is any
setting present in that file, that will taken into consideration.
With Regards,
Amit Kapila.
EnterpriseDB: http://www.enterprisedb.com
On 2014-11-21 10:59:23 -0800, Josh Berkus wrote:
On 11/21/2014 10:54 AM, Stephen Frost wrote:
* Josh Berkus (josh@agliodbs.com) wrote:
Either way, from the code it is clear that we only stay in recovery if
standby_mode is directly turned on. This makes the whole check for a
specially named file unnecessary, IMO: we should just check the value of
standby_mode (which is off by default).So, what happens when someone does "pg_ctl promote"? Somehow
standby_mode needs to get set to "off". Maybe we write "standby_mode =
off" to postgresql.auto.conf?Uhh, and then not work for the sane folks who disable
postgresql.auto.conf? No thanks..Other ideas then, without reverting to the old system? Being able to
promote servers over port 5432 will be a huge advantage for
container-based systems, so I don't want to give that up as a feature.
Why is a trigger file making that impossible? Adding the code from
pg_ctl promote into a SQL callable function is a couple minutes worth of
work?
A guc alone won't work very well - standby_mode is checked in specific
places, you can't just turn that off and expect that that'd result in
speedy promotion. And it'd break people using scripts pg_standby. And it also
has other effects.
So, no.
Greetings,
Andres Freund
--
Andres Freund 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
Alex Shulgin <ash@commandprompt.com> writes:
* Why do you include xlog_internal.h in guc.c and not xlog.h?
we actually need both but including xlog_internal.h also includes xlog.h
i added xlog.h and if someone things is enough only putting
xlog_internal.h let me knowWhat's required from xlog_internal.h?
Looks like this was addressed before me.
Actually, it's there to bring in MAXFNAMELEN which is used in
check_recovery_target_name. Not sure how it even compiled without that,
but after some branch switching it doesn't anymore. :-p
Maybe we should move these check/assign hooks to xlog.c, but that's
likely going to create header files dependency problem due to use of
GucSource in the hook prototype...
--
Alex
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Josh Berkus <josh@agliodbs.com> writes:
Well, the latest version of this patch fails to start when it sees
'recovery.conf' in PGDATA:FATAL: "recovery.conf" is not supported anymore as a recovery method
DETAIL: Refer to appropriate documentation about migration methodsI've missed all the discussion behind this decision and after reading
the ALTER SYSTEM/conf.d thread I'm even more confused so I'd like
someone more knowledgeable to speak up on the status of this.The argument was that people wanted to be able to have an empty
recovery.conf file as a "we're in standby" trigger so that they could
preserve backwards compatibility with external tools. I don't agree
with this argument, but several people championed it.
It doesn't look like we can provide for 100% backwards compatibility
with existing tools, here's why:
a) The only sensible way to use recovery.conf as GUC source is via
include/include_dir from postgresql.conf.
b) The server used to rename $PGDATA/recovery.conf to
$PGDATA/recovery.done so when it is re-started it doesn't
accidentally start in recovery mode.
We can't keep doing (b) because that will make postgres fail to start on
a missing include. Well, it won't error out if we place the file under
include_dir, as only files with the ".conf" suffix are included, but
then again the server wouldn't know which file to rename unless we tell
it or hard-code the the filename. Either way this is not 100% backwards
compatible.
Now the question is if we are going to break compatibility anyway:
should we try to minimize the difference or will it disserve the user by
providing a false sense of compatibility?
For one, if we're breaking things, the trigger_file GUC should be
renamed to end_recovery_trigger_file or something like that, IMO.
That's if we decide to keep it at all.
The docs use the term "continuous recovery".
Either way, from the code it is clear that we only stay in recovery if
standby_mode is directly turned on. This makes the whole check for a
specially named file unnecessary, IMO: we should just check the value of
standby_mode (which is off by default).So, what happens when someone does "pg_ctl promote"? Somehow
standby_mode needs to get set to "off". Maybe we write "standby_mode =
off" to postgresql.auto.conf?
Well, standby_mode is only consulted at startup after crash recovery.
But suddenly, a tool that *writes* recovery.conf needs to also
consult/edit postgresql.auto.conf... Maybe that's inevitable, but still
a point to consider.
By the way, is there any use in setting standby_mode=on and any of the
recovery_target* GUCs at the same time?See my thread on this topic from last week. Short answer: No.
I think it can only play together if you set the target farther than the
latest point you've got in the archive locally. So that's sort of
"Point-in-Future-Recovery". Does that make any sense at all?Again, see the thread. This doesn't work in a useful way, so there's no
reason to write code to enable it.
Makes sense. Should we incorporate the actual tech and doc fix in this
patch?
/* File path names (all relative to $PGDATA) */ -#define RECOVERY_COMMAND_FILE "recovery.conf" -#define RECOVERY_COMMAND_DONE "recovery.done" +#define RECOVERY_ENABLE_FILE "standby.enabled"Imo the file and variable names should stay coherent.
Yes, once we settle on the name (and if we really need that extra
trigger file.)Personally, if we have three methods of promotion:
1) pg_ctl promote
2) edit postgresql.conf and reload
3) ALTER SYSTEM SET and reload... I don't honestly think we need a 4th method for promotion.
Me neither. It is tempting to make everything spin around GUCs without
the need for any external trigger files.
The main reason to want a "we're in recovery file" is for PITR rather
than for replication, where it has a number of advantages as a method,
the main one being that recovery.conf is unlikely to be overwritten by
the contents of the backup.HOWEVER, there's a clear out for this with conf.d. If we enable conf.d
by default, then we can simply put recovery settings in conf.d, and
since that specific file (which can have whatever name the user chooses)
will not be part of backups, it would have the same advantage as
recovery.conf, without the drawbacks.Discuss?
Well, I don't readily see how conf.d is special with regard to base
backup, wouldn't you need to exclude it explicitly still?
--
Alex
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
* Amit Kapila (amit.kapila16@gmail.com) wrote:
What exactly you mean by 'disable postgresql.auto.conf', do you
mean user runs Alter System to remove that entry or manually disable
some particular entry?
Last I paid attention to this, there was a clear way to disable the
inclusion of postgresql.auto.conf in the postgresql.conf. If that's
gone, then there is a serious problem. Administrators who manage their
postgresql.conf (eg: through a CM system like puppet or chef..) must
have a way to prevent other changes.
Thanks,
Stephen
Stephen Frost wrote:
* Amit Kapila (amit.kapila16@gmail.com) wrote:
What exactly you mean by 'disable postgresql.auto.conf', do you
mean user runs Alter System to remove that entry or manually disable
some particular entry?Last I paid attention to this, there was a clear way to disable the
inclusion of postgresql.auto.conf in the postgresql.conf. If that's
gone, then there is a serious problem. Administrators who manage their
postgresql.conf (eg: through a CM system like puppet or chef..) must
have a way to prevent other changes.
Sigh, here we go again. I don't think you can disable postgresql.auto.conf
in the current code. As I recall, the argument was that it's harder to
diagnose problems if postgresql.auto.conf takes effect in some system
but not others.
I think if you want puppet or chef etc you'd add postgresql.auto.conf as
a config file in those systems, so that ALTER SYSTEM is reflected there.
--
�lvaro Herrera http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
* Alvaro Herrera (alvherre@2ndquadrant.com) wrote:
Stephen Frost wrote:
* Amit Kapila (amit.kapila16@gmail.com) wrote:
What exactly you mean by 'disable postgresql.auto.conf', do you
mean user runs Alter System to remove that entry or manually disable
some particular entry?Last I paid attention to this, there was a clear way to disable the
inclusion of postgresql.auto.conf in the postgresql.conf. If that's
gone, then there is a serious problem. Administrators who manage their
postgresql.conf (eg: through a CM system like puppet or chef..) must
have a way to prevent other changes.Sigh, here we go again. I don't think you can disable postgresql.auto.conf
in the current code. As I recall, the argument was that it's harder to
diagnose problems if postgresql.auto.conf takes effect in some system
but not others.
I don't buy this at all. What's going to be terribly confusing is to
have config changes start happening for users who are managing their
configs through a CM (which most should be..). ALTER SYSTEM is going to
cause more problems than it solves.
I think if you want puppet or chef etc you'd add postgresql.auto.conf as
a config file in those systems, so that ALTER SYSTEM is reflected there.
That's really a horrible, horrible answer. The DBA makes some change
and then reloads remotely, only to have puppet or chef come along and
change it back later? Talk about a recipe for disaster.
The only reason I stopped worrying about the foolishness of ALTER SYSTEM
was because it could be disabled. I'm very disappointed to hear that
someone saw fit to remove that. I'll also predict that it'll be going
back in for 9.5.
Thanks,
Stephen
Stephen Frost wrote:
* Alvaro Herrera (alvherre@2ndquadrant.com) wrote:
Last I paid attention to this, there was a clear way to disable the
inclusion of postgresql.auto.conf in the postgresql.conf. If that's
gone, then there is a serious problem. Administrators who manage their
postgresql.conf (eg: through a CM system like puppet or chef..) must
have a way to prevent other changes.Sigh, here we go again. I don't think you can disable postgresql.auto.conf
in the current code. As I recall, the argument was that it's harder to
diagnose problems if postgresql.auto.conf takes effect in some system
but not others.I don't buy this at all. What's going to be terribly confusing is to
have config changes start happening for users who are managing their
configs through a CM (which most should be..). ALTER SYSTEM is going to
cause more problems than it solves.
I guess if you have two DBAs who don't talk to each other, and one
changes things through puppet and another through ALTER SYSTEM, it's
going to be confusing, yes.
I think if you want puppet or chef etc you'd add postgresql.auto.conf as
a config file in those systems, so that ALTER SYSTEM is reflected there.That's really a horrible, horrible answer. The DBA makes some change
and then reloads remotely, only to have puppet or chef come along and
change it back later? Talk about a recipe for disaster.
Are you saying puppet/chef don't have the concept that a file is to be
backed up and changes on it notified, but that direct changes to it
should not be allowed? That sounds, um, limited.
The only reason I stopped worrying about the foolishness of ALTER SYSTEM
was because it could be disabled. I'm very disappointed to hear that
someone saw fit to remove that. I'll also predict that it'll be going
back in for 9.5.
*shrug*
--
�lvaro Herrera http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
* Alvaro Herrera (alvherre@2ndquadrant.com) wrote:
Stephen Frost wrote:
* Alvaro Herrera (alvherre@2ndquadrant.com) wrote:
Last I paid attention to this, there was a clear way to disable the
inclusion of postgresql.auto.conf in the postgresql.conf. If that's
gone, then there is a serious problem. Administrators who manage their
postgresql.conf (eg: through a CM system like puppet or chef..) must
have a way to prevent other changes.Sigh, here we go again. I don't think you can disable postgresql.auto.conf
in the current code. As I recall, the argument was that it's harder to
diagnose problems if postgresql.auto.conf takes effect in some system
but not others.I don't buy this at all. What's going to be terribly confusing is to
have config changes start happening for users who are managing their
configs through a CM (which most should be..). ALTER SYSTEM is going to
cause more problems than it solves.I guess if you have two DBAs who don't talk to each other, and one
changes things through puppet and another through ALTER SYSTEM, it's
going to be confusing, yes.
It's not DBAs, that's the point.. You have sysadmins who manage the
system configs (things like postgresql.conf) and you have DBAs whose
only access to the system is through 5432. This seperation of
responsibilities is very common, in my experience at least, and
conflating the two through ALTER SYSTEM is going to cause nothing but
problems. There had been a way to keep that seperation by simply
disabling the postgresql.auto.conf, but that's now been removed.
I think if you want puppet or chef etc you'd add postgresql.auto.conf as
a config file in those systems, so that ALTER SYSTEM is reflected there.That's really a horrible, horrible answer. The DBA makes some change
and then reloads remotely, only to have puppet or chef come along and
change it back later? Talk about a recipe for disaster.Are you saying puppet/chef don't have the concept that a file is to be
backed up and changes on it notified, but that direct changes to it
should not be allowed? That sounds, um, limited.
Of course they can but that's completely missing the point. The
postgresql.conf file is *already* managed in puppet or chef in a *lot*
of places. We're removing the ability to do that and reverting to a
situation where auditing has to be done instead. That's a regression,
not a step forward.
The only reason I stopped worrying about the foolishness of ALTER SYSTEM
was because it could be disabled. I'm very disappointed to hear that
someone saw fit to remove that. I'll also predict that it'll be going
back in for 9.5.*shrug*
... and I'll continue to argue against anything which requires
postgresql.auto.conf to be hacked to work (as was proposed on this
thread..).
Thanks,
Stephen
On 2014-11-24 10:13:58 -0500, Stephen Frost wrote:
* Alvaro Herrera (alvherre@2ndquadrant.com) wrote:
Stephen Frost wrote:
* Amit Kapila (amit.kapila16@gmail.com) wrote:
What exactly you mean by 'disable postgresql.auto.conf', do you
mean user runs Alter System to remove that entry or manually disable
some particular entry?Last I paid attention to this, there was a clear way to disable the
inclusion of postgresql.auto.conf in the postgresql.conf. If that's
gone, then there is a serious problem. Administrators who manage their
postgresql.conf (eg: through a CM system like puppet or chef..) must
have a way to prevent other changes.Sigh, here we go again. I don't think you can disable postgresql.auto.conf
in the current code. As I recall, the argument was that it's harder to
diagnose problems if postgresql.auto.conf takes effect in some system
but not others.I don't buy this at all. What's going to be terribly confusing is to
have config changes start happening for users who are managing their
configs through a CM (which most should be..). ALTER SYSTEM is going to
cause more problems than it solves.
I fail to see how this really has really anything to do with this
topic. Obviously ALTER SYSTEM isn't a applicable solution for this as HS
might not be in use or HS might not have reached consistency at that
point.
Greetings,
Andres Freund
--
Andres Freund 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
Alex Shulgin <ash@commandprompt.com> writes:
Maybe we should move these check/assign hooks to xlog.c, but that's
likely going to create header files dependency problem due to use of
GucSource in the hook prototype...
As far as that goes, there is already plenty of precedent for declaring
assorted check/assign hook functions in guc.h rather than including guc.h
into the headers where they would otherwise belong.
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
Stephen Frost wrote
* Alvaro Herrera (
alvherre@
) wrote:
Stephen Frost wrote:
* Amit Kapila (
amit.kapila16@
) wrote:
What exactly you mean by 'disable postgresql.auto.conf', do you
mean user runs Alter System to remove that entry or manually disable
some particular entry?Sigh, here we go again. I don't think you can disable
postgresql.auto.conf
in the current code. As I recall, the argument was that it's harder to
diagnose problems if postgresql.auto.conf takes effect in some system
but not others.I don't buy this at all. What's going to be terribly confusing is to
have config changes start happening for users who are managing their
configs through a CM (which most should be..). ALTER SYSTEM is going to
cause more problems than it solves.
So what happens if someone makes postgresql.auto.conf read-only (to
everyone)?
David J.
--
View this message in context: http://postgresql.nabble.com/Turning-recovery-conf-into-GUCs-tp5774757p5828052.html
Sent from the PostgreSQL - hackers mailing list archive at Nabble.com.
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Fri, Nov 21, 2014 at 12:55 PM, Josh Berkus <josh@agliodbs.com> wrote:
On 11/21/2014 09:35 AM, Alex Shulgin wrote:
Hello,
Here's an attempt to revive this patch.
Yayy! Thank you.
People might not like me for the suggestion, but I think we should
simply always include a 'recovery.conf' in $PGDATA
unconditionally. That'd make this easier.
Alternatively we could pass a filename to --write-recovery-conf.Well, the latest version of this patch fails to start when it sees
'recovery.conf' in PGDATA:FATAL: "recovery.conf" is not supported anymore as a recovery method
DETAIL: Refer to appropriate documentation about migration methodsI've missed all the discussion behind this decision and after reading
the ALTER SYSTEM/conf.d thread I'm even more confused so I'd like
someone more knowledgeable to speak up on the status of this.The argument was that people wanted to be able to have an empty
recovery.conf file as a "we're in standby" trigger so that they could
preserve backwards compatibility with external tools. I don't agree
with this argument, but several people championed it.
well, my approach was that postgres just ignore the file completely. I
mean, recovery.conf will no longer mean anything special.
Then, every tool that create recovery.conf in $PGDATA only has to add
an ALTER SYSTEM to include it
The docs use the term "continuous recovery".
Either way, from the code it is clear that we only stay in recovery if
standby_mode is directly turned on. This makes the whole check for a
specially named file unnecessary, IMO: we should just check the value of
standby_mode (which is off by default).
no. currently we enter in recovery mode when postgres see a
recovery.conf and stays in recovery mode when standby_mode is on or an
appropiate restore_command is provided.
which means recovery.conf has two uses:
1) start in recovery mode (not continuous)
2) provide parameters for recovery mode and for streaming
we still need a "recovery trigger" file that forces postgres to start
in recovery mode and acts accordingly to recovery GUCs
So, what happens when someone does "pg_ctl promote"? Somehow
standby_mode needs to get set to "off". Maybe we write "standby_mode =
off" to postgresql.auto.conf?
we need to delete or rename the "recovery trigger" file, all standby
GUCs are ignored (and recovery GUCs should be ignored too) unless
you're in recovery mode
By the way, is there any use in setting standby_mode=on and any of the
recovery_target* GUCs at the same time?See my thread on this topic from last week. Short answer: No.
haven't read that thread, will do
/* File path names (all relative to $PGDATA) */ -#define RECOVERY_COMMAND_FILE "recovery.conf" -#define RECOVERY_COMMAND_DONE "recovery.done" +#define RECOVERY_ENABLE_FILE "standby.enabled"Imo the file and variable names should stay coherent.
Yes, once we settle on the name (and if we really need that extra
trigger file.)
yes, we need it. but other names were suggested "standby.enabled"
transmit the wrong idea
Personally, if we have three methods of promotion:
1) pg_ctl promote
2) edit postgresql.conf and reload
3) ALTER SYSTEM SET and reload... I don't honestly think we need a 4th method for promotion.
this is not for promotion, this is to force postgres to start in
recovery mode and read recovery configuration parameters.
The main reason to want a "we're in recovery file" is for PITR rather
than for replication, where it has a number of advantages as a method,
the main one being that recovery.conf is unlikely to be overwritten by
the contents of the backup.
only that you need to start in recovery mode to start replication
--
Jaime Casanova www.2ndQuadrant.com
Professional PostgreSQL: Soporte 24x7 y capacitación
Phone: +593 4 5107566 Cell: +593 987171157
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Mon, Nov 24, 2014 at 12:24 PM, Jaime Casanova <jaime@2ndquadrant.com> wrote:
On Fri, Nov 21, 2014 at 12:55 PM, Josh Berkus <josh@agliodbs.com> wrote:
On 11/21/2014 09:35 AM, Alex Shulgin wrote:
Hello,
Here's an attempt to revive this patch.
Yayy! Thank you.
People might not like me for the suggestion, but I think we should
simply always include a 'recovery.conf' in $PGDATA
unconditionally. That'd make this easier.
Alternatively we could pass a filename to --write-recovery-conf.Well, the latest version of this patch fails to start when it sees
'recovery.conf' in PGDATA:FATAL: "recovery.conf" is not supported anymore as a recovery method
DETAIL: Refer to appropriate documentation about migration methodsI've missed all the discussion behind this decision and after reading
the ALTER SYSTEM/conf.d thread I'm even more confused so I'd like
someone more knowledgeable to speak up on the status of this.The argument was that people wanted to be able to have an empty
recovery.conf file as a "we're in standby" trigger so that they could
preserve backwards compatibility with external tools. I don't agree
with this argument, but several people championed it.well, my approach was that postgres just ignore the file completely. I
mean, recovery.conf will no longer mean anything special.
Then, every tool that create recovery.conf in $PGDATA only has to add
an ALTER SYSTEM to include it
i mean ALTER SYSTEM in master before copying or just add the line in
postgresql.conf
but, as the patch shows agreement was to break backwards compatibility
and fail to start if the file is present
--
Jaime Casanova www.2ndQuadrant.com
Professional PostgreSQL: Soporte 24x7 y capacitación
Phone: +593 4 5107566 Cell: +593 987171157
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 11/24/2014 09:24 AM, Jaime Casanova wrote:
... I don't honestly think we need a 4th method for promotion.
this is not for promotion, this is to force postgres to start in
recovery mode and read recovery configuration parameters.The main reason to want a "we're in recovery file" is for PITR rather
than for replication, where it has a number of advantages as a method,
the main one being that recovery.conf is unlikely to be overwritten by
the contents of the backup.only that you need to start in recovery mode to start replication
Right, but my point is that having a trigger file *is not necessary for
replication, only for PITR* -- and maybe not necessary even for PITR.
That is, in a streaming replication configuration, having a
"standby_mode = on|off" parameter is 100% sufficient to control
replication with the small detail that "pg_ctl promote" needs to set it
in pg.auto.conf or conf.d.
And, now, having given it some thought, I'm going to argue that it's not
required for PITR either, provided that we can use the auto.conf method.
Before I go into my ideas, though, what does the current patch do
regarding non-replication PITR?
--
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
Import Notes
Reply to msg id not found: WM60472faea14f1894c099f0e0c35774219fc42d09898f690a1012e3ad8392161fe19773a71f4a0272f7c8b56c7b616e8a@asav-2.01.comReference msg id not found: WM2eef57bf14271a28b7764a48733ac1bb0352229c58adbbcfc444bf3b2d39b5c4e9068a10e3f688295481db2314a812ff@asav-3.01.com
On 11/24/2014 07:29 AM, Stephen Frost wrote:
Sigh, here we go again. I don't think you can disable postgresql.auto.conf
in the current code. As I recall, the argument was that it's harder to
diagnose problems if postgresql.auto.conf takes effect in some system
but not others.I don't buy this at all. What's going to be terribly confusing is to
have config changes start happening for users who are managing their
configs through a CM (which most should be..). ALTER SYSTEM is going to
cause more problems than it solves.
The main reason why disabling auto.conf was found not to be worthwhile
is that anyone with superuser rights can *already* change the config by
using ALTER DATABASE and ALTER ROLE, and that's a LOT less auditable
than pg.auto.conf is. Heck, we don't even have a good system view for
SET parameters on DB objects.
--
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
Import Notes
Reply to msg id not found: WM6510d8fe4999c88684f56a7d8fe1ce8f9c1f5f762f985ba069dfab31e819f7abe8b98257e2d4155b499c6cc6dc3094e2@asav-3.01.com
* Josh Berkus (josh@agliodbs.com) wrote:
On 11/24/2014 07:29 AM, Stephen Frost wrote:
Sigh, here we go again. I don't think you can disable postgresql.auto.conf
in the current code. As I recall, the argument was that it's harder to
diagnose problems if postgresql.auto.conf takes effect in some system
but not others.I don't buy this at all. What's going to be terribly confusing is to
have config changes start happening for users who are managing their
configs through a CM (which most should be..). ALTER SYSTEM is going to
cause more problems than it solves.The main reason why disabling auto.conf was found not to be worthwhile
is that anyone with superuser rights can *already* change the config by
using ALTER DATABASE and ALTER ROLE, and that's a LOT less auditable
than pg.auto.conf is. Heck, we don't even have a good system view for
SET parameters on DB objects.
If this was accurate, we wouldn't have any need for ALTER SYSTEM.
They *can't* make certain configuration changes which is why ALTER
SYSTEM was put into place to begin with. Those pieces are also,
generally speaking, what's needed to get the database started and which
control authentication (and possibly authorization to connect). As I've
pointed out before, we'll end up with DBAs making changes which break
the system from starting and they can't properly test that change nor do
anything about it when the DB can no longer start, and the sysadmins
will be extremely confused and, worse, will have zero clue that this
'auto.conf' thing even exists or where the config is coming from that's
preventing the DB from starting. At least when postgresql.auto.conf was
explicitly in the top-level postgresql.conf, there was a hope that
they'd realize there's another config file in play (and figure out how
to disable it to get the system back online..) and now we haven't even
got that.
I agree that it'd be nice to have a better view of what has been set
using ALTER DATABASE and ALTER ROLE, but nothing here makes me feel any
differently about ALTER SYSTEM.
Thanks,
Stephen
Jaime Casanova <jaime@2ndquadrant.com> writes:
Either way, from the code it is clear that we only stay in recovery if
standby_mode is directly turned on. This makes the whole check for a
specially named file unnecessary, IMO: we should just check the value of
standby_mode (which is off by default).no. currently we enter in recovery mode when postgres see a
recovery.conf and stays in recovery mode when standby_mode is on or an
appropiate restore_command is provided.which means recovery.conf has two uses:
1) start in recovery mode (not continuous)
2) provide parameters for recovery mode and for streamingwe still need a "recovery trigger" file that forces postgres to start
in recovery mode and acts accordingly to recovery GUCs
Yes, these were my latest findings also, but if instead of removing the
trigger file upon successful recovery the server would set
standby_mode=off, that would also work.
--
Alex
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Josh Berkus <josh@agliodbs.com> writes:
only that you need to start in recovery mode to start replication
Right, but my point is that having a trigger file *is not necessary for
replication, only for PITR* -- and maybe not necessary even for PITR.
That is, in a streaming replication configuration, having a
"standby_mode = on|off" parameter is 100% sufficient to control
replication with the small detail that "pg_ctl promote" needs to set it
in pg.auto.conf or conf.d.And, now, having given it some thought, I'm going to argue that it's not
required for PITR either, provided that we can use the auto.conf method.Before I go into my ideas, though, what does the current patch do
regarding non-replication PITR?
It removes that $PGDATA/standby.enable trigger file it relies on to
start the PITR in the first place.
--
Alex
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 2014-11-24 12:02:52 -0800, Josh Berkus wrote:
On 11/24/2014 09:24 AM, Jaime Casanova wrote:
... I don't honestly think we need a 4th method for promotion.
this is not for promotion, this is to force postgres to start in
recovery mode and read recovery configuration parameters.The main reason to want a "we're in recovery file" is for PITR rather
than for replication, where it has a number of advantages as a method,
the main one being that recovery.conf is unlikely to be overwritten by
the contents of the backup.only that you need to start in recovery mode to start replication
Right, but my point is that having a trigger file *is not necessary for
replication, only for PITR* -- and maybe not necessary even for PITR.
That is, in a streaming replication configuration, having a
"standby_mode = on|off" parameter is 100% sufficient to control
replication with the small detail that "pg_ctl promote" needs to set it
in pg.auto.conf or conf.d.And, now, having given it some thought, I'm going to argue that it's not
required for PITR either, provided that we can use the auto.conf method.Before I go into my ideas, though, what does the current patch do
regarding non-replication PITR?
Guys. We aren't rereading the GUCs in the relevant places. It's also
decidedly nontrivial to make standby_mode PGC_SIGHUP. Don't make this
patch more complex than it has to be. That's what stalled it the last
times round.
Greetings,
Andres Freund
--
Andres Freund 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
On 11/24/2014 02:00 PM, Alex Shulgin wrote:
Josh Berkus <josh@agliodbs.com> writes:
only that you need to start in recovery mode to start replication
Right, but my point is that having a trigger file *is not necessary for
replication, only for PITR* -- and maybe not necessary even for PITR.
That is, in a streaming replication configuration, having a
"standby_mode = on|off" parameter is 100% sufficient to control
replication with the small detail that "pg_ctl promote" needs to set it
in pg.auto.conf or conf.d.And, now, having given it some thought, I'm going to argue that it's not
required for PITR either, provided that we can use the auto.conf method.Before I go into my ideas, though, what does the current patch do
regarding non-replication PITR?It removes that $PGDATA/standby.enable trigger file it relies on to
start the PITR in the first place.
OK, and that's required for replication too? I'm OK with that if it
gets the patch in.
--
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
Import Notes
Reply to msg id not found: WM0507bc2eb0c2652ddc43bb2d6d5afd1af7efd920d5bcfd98b79e5902e75af230915fabb5cc1fd84303e2c47035b04e67@asav-1.01.comReference msg id not found: WM2eef57bf14271a28b7764a48733ac1bb0352229c58adbbcfc444bf3b2d39b5c4e9068a10e3f688295481db2314a812ff@asav-3.01.com
Josh Berkus <josh@agliodbs.com> writes:
Before I go into my ideas, though, what does the current patch do
regarding non-replication PITR?It removes that $PGDATA/standby.enable trigger file it relies on to
start the PITR in the first place.OK, and that's required for replication too? I'm OK with that if it
gets the patch in.
In the current form of the patch, yes. Thought I don't think I like it.
--
Alex
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On 11/24/2014 02:18 PM, Alex Shulgin wrote:
Josh Berkus <josh@agliodbs.com> writes:
Before I go into my ideas, though, what does the current patch do
regarding non-replication PITR?It removes that $PGDATA/standby.enable trigger file it relies on to
start the PITR in the first place.OK, and that's required for replication too? I'm OK with that if it
gets the patch in.In the current form of the patch, yes. Thought I don't think I like it.
One step at a time.
--
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
Import Notes
Reply to msg id not found: WMaaa3dc332ac9d488539c3967a1b742ce3792bdb033b453ac1dae53947c16de972766ccb4590f6bfff3cd38bf88a8e997@asav-1.01.comReference msg id not found: WM2eef57bf14271a28b7764a48733ac1bb0352229c58adbbcfc444bf3b2d39b5c4e9068a10e3f688295481db2314a812ff@asav-3.01.com
Alex Shulgin <ash@commandprompt.com> writes:
Here's an attempt to revive this patch.
Here's the patch rebased against current HEAD, that is including the
recently committed action_at_recovery_target option.
The default for the new GUC is 'pause', as in HEAD, and
pause_at_recovery_target is removed completely in favor of it.
I've also taken the liberty to remove that part that errors out when
finding $PGDATA/recovery.conf. Now get your rotten tomatoes ready. ;-)
--
Alex
Attachments:
recovery_guc_v5.4.patch.gzapplication/gzipDownload
���|T recovery_guc_v5.4.patch ��iw�� ���#��$e @��d)��(��jI���|p����Af������j������&��y�z�����^$��kow����p�����w�;����a������������`��^��w�����n?��y�v�s�����������4��������������<k�_O�=�����" ^����?�����>������[�������({�����������8y�%��O�1�w����b4��ou[s?����l6�y�8��p�9?���,����-��OZ#����3�=�V>�0~���O�s�6��:�n��/t�{������IxzI�~{�����5 ��4L���p��]�d�jWP����������?�avQzn�{�O�s)��sn��T�S�d��+���i�W���f�i�!A��Oa� bbu��v��O�T4�Z��
\��W��Sr���9rXc/�S�7_����N5=��(H��,����i���-�d�����oy
�5�?M���-�?o��k�'��.O�6�|B
���SDiGEr��*��"���,LG�@�J���l�=����sj���v>m�����������eS�O����w��a4�.��2�Yu�������7�@���;��?�E(�/���q�m�sg��z{y�-�$�^�����i0nx����Fi�d���w�Y�y7�?jn���o������.'H���x����� ���0�����������s���hL��N���w[�a�i���=|����A���kzh�x��?
�?��x���������_����yF�d}������_N4���b.N��,��������&������Xi���9������ ?j�H��BW���}oe:���X~���'��>B� =�sY���/�����U���[+�����w'�o���j����g?�����g�����A�f�N[7�jse�p�`;��U25
@
1B� �?� :d��~�U��}^���������n��o���^�H�JG,���V��~w����*#4����_~�?<99|}@�5�?y)\d`7�,��} ��������D�7
ga��������fO�����q��� ����`1`i'A%�q��m�#0�+'��yv^:~5*ZcYQ�UBV�P��P����YD�R�V~UG6�;#�=�Z;���`�#d�r(��_������������t��_v���0L}E7���MT
�Y0{*8{����
�@?���.��W�S��
��F�,xj]��7�"z ����H� Q�����������0�'���#dL��:�������k��f��Y����)^�(�+���O��A8�0�9�zY�|��HZD>,�<I� *��uK�So�x�]��$��E��4<��j���'�iKAq��x)��������`\������,�r ��q98�+� �CP��g���r�s����T3�>� ����7��� ����
f����w��Q /G�t
�+��zk�/��E%��X����k��4�������wEZ��E�1h���G������%����V+x2�~�������y�t=�S���4�a�A2 e�{�||�� �q�I�O� I���3�i<y��JC_i |"���+�������a��!
�iGH��,yk�0�o;�8M��i���^_�j��*�vG��"}I=����0M~
D�(zv� �d��������:�F��� �h��/��OJ�k���> ���A��D!X�RD�Jdz�i��j�NN��tb�bw��9�L������!��*�3��7���f���,x7L��3_��q��@��B�I���2 �
����}�)a��� ���i%�#�2:F�T�i<"���&�R<UZ�Zjb���MA�;$��8�bY�]���H�( n���aOY��<g^:F�&�
o������G?�[
M�2�g��r0���aU��(�.���8��+�D8�������(������fx�_�{ZQ��B������ty�!M3�'0�aF����@e�$���� ����a���v _�:�uc|-c�,U�s8zs�(���o�k�{�p��;q�%�%2��Lq�����6��]�8T�;����U<���E
r7�DW�����hx 1��`���8�XDa�x����I<�=�)o��d���()�>6��@|���.�:�4��i���&\ �a����:�)i���D����K��++0v���X
�C�GH#�����x%tnA
o����0�D�5<\�X��@4����O\��Lp�{K�O�+ D;OB���hJ��'�;]:���e�F�� H�d�~�������3���u���n�����"�����V����~��1=7 iX&�Z�W��x:Z$ r�d��W$�O 6�|��V��azfL#����a($�l�8�D!p����I�/p]��#��a���wD��80A%��g������TS�{F�|M����qQ�ix��d$��!���f�'/��i���/���r/�{
�dW$�n���7�L����Q��b����Z�*1R�cJ����R�7���_����������j�&{{{�a�:��Dn~��A��������M����
�GT�l����z��U���7����CXk[x�����_�����/��rK�{�����#���M�[�cu��*��J75�>7��'P<���D E��97v����3MP�
���Ef���T��P���q���>=Ei�6�keI�F���q����
q
U�x+�����OMc��������>i5'~�� C
��9��MycW=�SL�����L�T�d��ZRR_x������E84�c��n
��"U8���� �:*
C��t6f�,�V�|�����XX���\@�O�h�����\=("`�9"�!B���[��^s�dA���0�a8\(v��Rk |��X�:��#�V���]8��������h4�a��,����Q�C�[�r�,�Z+B��&�����c�/P ����O;;������PWZ[\�#�}xTY}�-���8��{�:+k�a+h5L��Z���Z��M*vW��������8�AJ��O����2�HC�
�o$��zDV�Q�3�,�Q��Yc�>�U�HF�z��!��2�� %h���0�>b6E<~N"~�����Y����4Z�A��:'Yl��@b�)�Q1$�:D�f2k*��EF,L/3��]��g��$��X�Q:�!i�=��p-�D�����2cs��?)��C:�-v2�x���h�$����+Hbr� r���@O
~�v7�\�#}������S�����;�Ab�9 ���n�9>
Dv���1�I�)��Wj��^1O�:�D���4B��)�I"��)BgY�1���`��>���U�C���������������&������~��%>G������*���~�dt>C�d���ks4������Q+��-D#��& c�xAt_�k_Ia}bd������kZb4?�i2$&S��(Q�JY�
O�����MY��r����!qm}�s�� ����^�2�:�H�E2������I
7����1���,@�0�����C0��s.3��Hl2Dy<���Q��\��%���{�m�-�x�t�qy]��v������I�f�����!g>� �wd`�*P�
a�����A�P�d \�t^p7*k�)���������#rX�:���1R��iP�g4�~�������S`�V�yob8���<���!0[L��h�[��)�������PG�s���S�� ����c����d���f�!rO���(K���5[�������� �X7�����\������+���}d������@�c�t����K8�S�):{�w�p����?�!��e����Uho$�,��)6�&�|����+Q�,��^L�B�
G)eZ.��\�K���ZNi1��>F�� !�T���������o�WH��{Z��F
_A��}�F������^~����Y?~~�e�M�����4<�j�,�En^�y���R�@�'��n����������M�]���B�����h���ipU�"�0�S$��&��s=-q��{:���2�6���b>�A0O
��B\d2NK9QY,�G�qLn��i2���3��MS����������j�.H�^��"�_�-��"N8�+!�E���e?��(/�w�����a��`��(�\�9��kC>=`'
fWg@B�t�E����z�K!
hf�K�[��EOo�>���2�_
K�FBT�\����s���Pn����p�f������Hi@41}J�I�o5�V4�28���,�f~zm��B&&������|z� ;Py)���`���
O�"��3�
<Dv�!]�R���cG�&IN�E7!f����9�FY�$ ����<i�1���9�0���L��s��R++?� :����#N>�H�ac#�r&�
����b$J�(���"z)�Q6�5 ��d��i<�X[Tx�T��E4:Kb��0��?� ���"*�b�4Y����;:�E��������+MV(���JiK��!�v��g��)�b�t�M��Y�8�2�M�P���%�,�r�Ql�+E@����t������l���x��2q��-�`{�������Ht^����)�[r�S���39��(8��d�� n�������h)����t���b#��!��{@N3Z�`o��tLB������7����U'������\�(?|��s�U��t��<V0�} ^$i���|3f����;�,���X�a��i|A^���(������ �3����(^$��A�N�F�c!
���kPxA|�zhp���N���/���X�=Y���@epjLId��@���x���� L�Bw)Rw�����/��1� %]���dB
��4�3�2��L���NF<<�-����]�&�I��Q�mWo{4y'�S[�;r����Ff,U��w<�e�6��W}�Y4T��Y0�����MT7����
�PwXDh'��(�!X4`A��#~�������A����[���T-�X".�",%�/$�%*�!�#6����9Q��� JimG���t4�E����"$Q��b0���h<���/�����M�1q@2�}���N�F�{q{�����Z�,_P�yl\��������7���P��b 87(� ���!�~#� W���F���4�@/�b\5�Y�l���a����?��}f[�)>�Eq
op��yv!KESI���`1��J��p*���;
����,O���4(��JH���X��r�LU��n��
b�s�2*���M�H<\����p02?����/����"�7�/E���U�H^\!����� ��)��!i4�4�F A�\`�=I�������5�33�2�3��ZZ��/O����)��J�!#>�"1�� ��2]����+��]c�����"��~��P9k�#�\��(�`m
�$�����,]�b$��pI`c�e��Kb����P[V��i�u�;�d���5�.�� {�7mY��Hr'$W��wDs
B��
4�&�Km�O��yh��s-��[-O�t��0��������-_1>?5������/�f��8A�c��1@��F���b����"�jt� ";L�|>��"fu�ed���q �cB�Hm�o�i� ����$�cT/ 4I����?��
>�w���VP���y�~�Fz�����t��uc]��n������(�w$�R��e�-�h_I��.�G����
z$�� G��)�Q���DG���9�\�4T$�TjK)�d��ce$:+�Q�[����T����o��L�E��zY��������:�biK��v�}�o��]KB��~�q�&?��k���*�����|#Q�J�p�k��N�@,<�t���>�������W2UJ�0-�����B{jFBC3G�)����w��g���b������?8��.���O�� F�$��z�����S��$9��C1�!a��2�����K��H������mdcK�%^;��������szK*J&��0��*����C�$��x�d`��: -��4��Y���H��8>��m�8Ucx��Wg��q����� ��X;�8;��sA�8��2��;�1S��+���g���F�g���,��A&h��vb:���K�+DXq`������0)���Er��3�NlZZRl�I�*�!���H��&���� ���lg7r�0��!Jc� +��k8�!���M�_��+�2��!5s.A����6J���b�v����
�_�����@@��r�"M�,��t�FE F���F VP��q��&�0��yc����.��'���(\�Dw6���S������&���Q��n\��W���;����%x��tQ�$Y�Y���e
=%��S�����H\TxN�W��R,�[�+9���}�LC��^���ux����������tB�LT��s��mH�T3�r�����_-���b~Y�B�w7��Q��U��qL�\���
��������M�*AH@��c+��
82 ���8��Np]�r�v'IZ(h��Fa�J�N�'@�T\�s��)���� :�C+����r0�������Yq���8�X5�������1�ui����\/�<C��Q�_Ct�ik��o�#q�s�J���h��@�iM6)}u�`�$>X>S���^�����3�muvw[[��������,7���!T�����1�C�#/���W��
E��*RA�P��e"A��)*`ud)����by��/��zb��|Q�����hk���n�DQY�X/�11��d�6!vs+���h�Ns4.�$y����[����M��L�c�D���� �$:��l���������S��<�c3^�x��H���)lM�P]���E�[�`��%R���]d R��('.����E`\ V�"����.�j-9�/Ll|C�V������rU�
D�c5 ��.��:9��Z��X�����4D�w�)���7�������� ���o�)C�>%��RQ��^��G�#��������y&�(4*�>�I�l �H��J������ ��/
6�iMq�?U$�������Z���p.#��z��j��8=�����&�����e
JpQ�`F�c�U���Y�c8���wPqW�mP����s7<��#Y���V�U�`NA�� �}�P����/��R$��L<�]
�~.���:��t�����z���
s��G���A*f5c$*�eL`����i�2M�����NJ�}��L����::B8D�@;B����"�U��=M2`��WE0�,$QY�v���zu����6���m����:�DbITr��:�l�q���JmU�a�9���1�jz�
�&_p5�5-��F���_J����8�9`X@S.a�$���*tN+|��<��6Wt{�8�l�2"ky9�vCfH1B�4.��P(������nzg��1��qJ����=���$S`�".����m����[4�c�WC�<���9i�HH;;�A�R�h1�A�^�M�P�Y�Ss�A��z]g-�Zx/m��� �Dca�|1�/*��lu��l���z+�9��8����h�XRxct� � �s���Ea99aU@��3m��T�gy(8)�}l���*b~ �����o�
L�7�WU����.W��1���������Ve�����0io
w�~�5���'eu��J*3�
�'���5�mUu���oNO~Q%�O���7�����������#��=�(��6f�iI�$ FC]S�"���M��a+ O���e3�����?-i/8�+�Gy�I�1�������{{�5�� ����G}Q�9C�� �Vko���z���*����#W$��7@�x���w����kt ������N��m�e�.�����>��g�i`�3���`dl�V��g�R+(*T�{6K����8�eXp�|��d�(�GS����\$Fe#���b1����q8�{���V@l��O2 �������I�,6�I�H(���������T*x�����q�Fe����������~5M;O���G?N���������v�noo���j;�����Q��QKH_E�������Gf�����,�F����3����:���Ne�I�e�&�a&^�S���l��d�� �x0�_�|ZO�:�_*M��)���|����'����
�G�
����5�����;y��Td���~�&<�b���U4���������:���v���Q���2�R�$��|`0��x���qGlUe������R��>�]���vc{�������Ej#�~�����<����������X��{f�Q���=�F10�
%�9�����}k�:.&U����D���H���PH��DQeNf�x�o�������02^(��Tm������_e�x4��s���xT
���V���b�
;*h�W�W*�<~���78�=nFu�v;m-hU*^#�';��o`� @�_����X��ciN�#D!9@�HU�m��yW���Q�D�U��� �.�QQ�Dn ��^M~[��J�;Z��������R�����i����t^J�R�q9�7���E]���������i�6v:=�)��Y�S�c�W�G�s����4}t�+V��f���/���i���7�7h�����:���N��&��~o�Kz�'�8��e�_#4U�3����.G���r;rz�4|�����KM/�� ���
�H�t���Qo�L�B�P�g��~Z��cWZQ�2z�aJSy���%�J�����q�T������#'�0"
�j�V�4Y��X��c0}E��5�Mqf�HE<@�%B�_�a��1���������z���N;�\<�4��x���i��M��`O�N��,��'�YXO w�mm\�F~^��I�?@���vw����o�49�
���]�L���3�0e|��������� Y�B��K�E�\� AI��*+f�o�M����V��Y���4�T�Fe<�����O���'����(�Dp>|��o�q�OH��#������)�G�x��q �������`���l��������#� ��)K�2�x,>�*T������:����<b���o��� �.a���n�D��~�-���p?�����wr1,a��us�&��z�|�/JB����(
|����:��n����gj��NI%LrO)� �,e�ZD5�/TeC)�d7��(�z�+��X*�:|�qIR|J��V��!���(�6�z����C����Q��I��HI���j��"��0bQL)Y^���CG�1�'�i���N��oT��V�kj��J.��v�:�
�5���3*�d���C�&����mt�z}Kz&S�i8����ERZ�c��8�J�@��SJ:����:y�
$R;�x���6��W�Z�E��e����"�
���j�P\Za�@)v�Hu,�p;�'�]�]��*�s��}�{��B�\?/�#�A,�J����q��[���q�B�>"&ZDRyK���W���������e[y�c6X���J���:�C��|J���&<��;v� ������?L~z��F��e)�,�R�Q�������02rN��h����7�x@/��R���pBX��>_F�����!
�z���< >��Wp�_�����=��i��"l���6+.s����L{��� ���9�e�[�*s�/I�qgH"�a�Wv�K����V���ej�$[��)"���[��c��L%��C#��������-Fv�< I�--I�!�]����2�L%Gd��|�U~���rvg���vq�NJW���;�(���H�%R���'�,��$(I&�B��T �����$�/k&��+2�
��[�|J8I�{�<������9Y<�B���?���l�}8���U�����Qm��x�
���h�w�{D\��������C�h�Zr���K�Ob���C���X(������IJ���<N%��������.k��/mU�|�<��v<H�8�QY�4����f�6���}`-=���f�KA�F��N�o����!��C������RT���=)���J r.0����4�O�Q�c��b6�\"�����3�h��)��.�d�P.0R�K+���s$�zy*��9�8��h~By�G���5U���?W�������X:��q��3����O���A�9/|�ok_���d��Z�^4����:�h��������m7� f�}���F�j)����S�:���{0�}RB������-)��_���@j0_��r�7���{����F��p���q)�[�������;�~��m����|���Q�',�����������)���R�`����>���YJ���/�,"uw]��uK�`��� �V+���<m�p%�.mW
�F�-��Y��-6�c��Gg��r��1����p�BQ�g&����f�J7�NK�����C��U
�Gc��(-Ny�ci#g�4s��S� ����i-F���\Ld�85
A@�U$���m�5���o:r��L0@�7_h���@>0���PE��t���cE����>V���BW,���
;T�{1��^�`�������h�y�`25���P��T���
D t�.���S�
���
>���r�!��&#iG���Y#V�mTY#v�Y�8?"|�!5��|�;l��2Wb��J����s���Y-z��:����bu�
����h�� %a�&jl�hm���\�}��D�\63��3 ���7%�
���#��R��z:%�[K��U�����(J���E]��|;Z{$�4�Q�c�no�[���$�p�w���������g��%�R�0.-�,�X���M����,�@%K����f���zlOc�uz�y�� I�/�J�0�H��u�QIJ��O���LI��r�P�R 3 ����h�aSU���:����������_�$�Fk���� ��0����J~]s&�\N�����t���$�5f���8�&6������[g�0��������tM�8�j�yd�1�ge���t�+��J�&;+ �HIm�Q����@��"