Postgres restart in the middle of exclusive backup and the presence of backup_label file
Hi Hackers,
While an exclusive backup is in progress if Postgres restarts, postgres
runs the recovery from the checkpoint identified by the label file instead
of the control file. This can cause long recovery or even sometimes fail to
recover as the WAL records corresponding to that checkpoint location are
removed. I can write a layer in my control plane to remove the backup_label
file when I know the server is not in restore from the base backup but I
don't see a reason why everyone has to repeat this step. Am I missing
something?
If there are no standby.signal or recovery.signal, what is the use case of
honoring backup_label file? Even when they exist, for a long running
recovery, should we honor the backup_label file as the majority of the WAL
already applied? It does slow down the recovery on restart right as it has
to start all the way from the beginning?
Thanks,
Satya
On Wed, Nov 24, 2021 at 02:12:19PM -0800, SATYANARAYANA NARLAPURAM wrote:
While an exclusive backup is in progress if Postgres restarts, postgres
runs the recovery from the checkpoint identified by the label file instead
of the control file. This can cause long recovery or even sometimes fail to
recover as the WAL records corresponding to that checkpoint location are
removed. I can write a layer in my control plane to remove the backup_label
file when I know the server is not in restore from the base backup but I
don't see a reason why everyone has to repeat this step. Am I missing
something?
This is a known issue with exclusive backups, which is a reason why
non-exclusive backups have been implemented. pg_basebackup does that,
and using "false" as the third argument of pg_start_backup() would
have the same effect. So I would recommend to switch to that.
--
Michael
Thanks Michael!
This is a known issue with exclusive backups, which is a reason why
non-exclusive backups have been implemented. pg_basebackup does that,
and using "false" as the third argument of pg_start_backup() would
have the same effect. So I would recommend to switch to that.
Is there a plan in place to remove the exclusive backup option from the
core in PG 15/16? If we are keeping it then why not make it better?
On Thu, Nov 25, 2021 at 06:19:03PM -0800, SATYANARAYANA NARLAPURAM wrote:
Is there a plan in place to remove the exclusive backup option from the
core in PG 15/16?
This was discussed, but removing it could also harm users relying on
it. Perhaps it could be revisited, but I am not sure if this is worth
worrying about either.
If we are keeping it then why not make it better?
Well, non-exclusive backups are better by design in many aspects, so I
don't quite see the point in spending time on something that has more
limitations than what's already in place.
--
Michael
Michael Paquier <michael@paquier.xyz> writes:
On Thu, Nov 25, 2021 at 06:19:03PM -0800, SATYANARAYANA NARLAPURAM wrote:
If we are keeping it then why not make it better?
Well, non-exclusive backups are better by design in many aspects, so I
don't quite see the point in spending time on something that has more
limitations than what's already in place.
IMO the main reason for keeping it is backwards compatibility for users
who have a satisfactory backup arrangement using it. That same argument
implies that we shouldn't change how it works (at least, not very much).
regards, tom lane
On 11/26/21, 7:33 AM, "Tom Lane" <tgl@sss.pgh.pa.us> wrote:
Michael Paquier <michael@paquier.xyz> writes:
On Thu, Nov 25, 2021 at 06:19:03PM -0800, SATYANARAYANA NARLAPURAM wrote:
If we are keeping it then why not make it better?
Well, non-exclusive backups are better by design in many aspects, so I
don't quite see the point in spending time on something that has more
limitations than what's already in place.IMO the main reason for keeping it is backwards compatibility for users
who have a satisfactory backup arrangement using it. That same argument
implies that we shouldn't change how it works (at least, not very much).
The issues with exclusive backups seem to be fairly well-documented
(e.g., c900c15), but perhaps there should also be a note in the
"Backup Control Functions" table [0]https://www.postgresql.org/docs/devel/functions-admin.html#FUNCTIONS-ADMIN-BACKUP.
Nathan
[0]: https://www.postgresql.org/docs/devel/functions-admin.html#FUNCTIONS-ADMIN-BACKUP
Greetings,
* Tom Lane (tgl@sss.pgh.pa.us) wrote:
Michael Paquier <michael@paquier.xyz> writes:
On Thu, Nov 25, 2021 at 06:19:03PM -0800, SATYANARAYANA NARLAPURAM wrote:
If we are keeping it then why not make it better?
Well, non-exclusive backups are better by design in many aspects, so I
don't quite see the point in spending time on something that has more
limitations than what's already in place.IMO the main reason for keeping it is backwards compatibility for users
who have a satisfactory backup arrangement using it. That same argument
implies that we shouldn't change how it works (at least, not very much).
There isn't a satisfactory backup approach using it specifically because
of this issue, hence why we should remove it to make it so users don't
run into this. Would also simplify the documentation around the low
level backup API, which would be a very good thing. Right now, making
improvements in that area is very challenging even if all you want to do
is improve the documentation around the non-exclusive API.
We dealt with this as best as one could in pgbackrest for PG versions
prior to when non-exclusive backup was added- which is to remove the
backup_label file as soon as possible and then put it back right before
you call pg_stop_backup() (since it'll complain otherwise). Not a
perfect answer though and a risk still exists there of a failed restart
happening. Of course, for versions which support non-exclusive backup,
we use that to avoid this issue.
We also extensively changed how restore works a couple releases ago and
while there was some noise about it, it certainly wasn't all that bad.
I don't find the reasons brought up to continue to support exclusive
backup to be at all compelling and the lack of huge issues with the new
way restore works to make it abundently clear that we can, in fact,
remove exclusive backup in a major version change without the world
coming down.
Thanks,
Stephen
On Tue, 2021-11-30 at 09:20 -0500, Stephen Frost wrote:
Greetings,
* Tom Lane (tgl@sss.pgh.pa.us) wrote:
Michael Paquier <michael@paquier.xyz> writes:
On Thu, Nov 25, 2021 at 06:19:03PM -0800, SATYANARAYANA NARLAPURAM wrote:
If we are keeping it then why not make it better?
Well, non-exclusive backups are better by design in many aspects, so I
don't quite see the point in spending time on something that has more
limitations than what's already in place.IMO the main reason for keeping it is backwards compatibility for users
who have a satisfactory backup arrangement using it. That same argument
implies that we shouldn't change how it works (at least, not very much).There isn't a satisfactory backup approach using it specifically because
of this issue, hence why we should remove it to make it so users don't
run into this.
There is a satisfactory approach, as long as you are satisfied with
manually restarting the server if it crashed during a backup.
I don't find the reasons brought up to continue to support exclusive
backup to be at all compelling and the lack of huge issues with the new
way restore works to make it abundently clear that we can, in fact,
remove exclusive backup in a major version change without the world
coming down.
I guess the lack of hue and cry was at least to a certain extent because
the exclusive backup API was deprecated, but not removed.
Yours,
Laurenz Albe
Greetings,
On Tue, Nov 30, 2021 at 11:47 Laurenz Albe <laurenz.albe@cybertec.at> wrote:
On Tue, 2021-11-30 at 09:20 -0500, Stephen Frost wrote:
Greetings,
* Tom Lane (tgl@sss.pgh.pa.us) wrote:
Michael Paquier <michael@paquier.xyz> writes:
On Thu, Nov 25, 2021 at 06:19:03PM -0800, SATYANARAYANA NARLAPURAM
wrote:
If we are keeping it then why not make it better?
Well, non-exclusive backups are better by design in many aspects, so
I
don't quite see the point in spending time on something that has more
limitations than what's already in place.IMO the main reason for keeping it is backwards compatibility for users
who have a satisfactory backup arrangement using it. That sameargument
implies that we shouldn't change how it works (at least, not very
much).
There isn't a satisfactory backup approach using it specifically because
of this issue, hence why we should remove it to make it so users don't
run into this.There is a satisfactory approach, as long as you are satisfied with
manually restarting the server if it crashed during a backup.
I disagree that that’s a satisfactory approach. It certainly wasn’t
intended or documented as part of the original feature and therefore to
call it satisfactory strikes me quite strongly as revisionist history.
I don't find the reasons brought up to continue to support exclusive
backup to be at all compelling and the lack of huge issues with the new
way restore works to make it abundently clear that we can, in fact,
remove exclusive backup in a major version change without the world
coming down.I guess the lack of hue and cry was at least to a certain extent because
the exclusive backup API was deprecated, but not removed.
These comments were in reference to the restore API, which was quite
changed (new special files that have to be touched, removing of
recovery.conf, options moved to postgresql.conf/.auto, etc). So, no.
Thanks,
Stephen
Show quoted text
On 11/30/21, 9:51 AM, "Stephen Frost" <sfrost@snowman.net> wrote:
I disagree that that’s a satisfactory approach. It certainly wasn’t
intended or documented as part of the original feature and therefore
to call it satisfactory strikes me quite strongly as revisionist
history.
It looks like the exclusive way has been marked deprecated in all
supported versions along with a note that it will eventually be
removed. If it's not going to be removed out of fear of breaking
backward compatibility, I think the documentation should be updated to
say that. However, unless there is something that is preventing users
from switching to the non-exclusive approach, I think it is reasonable
to begin thinking about removing it.
Nathan
"Bossart, Nathan" <bossartn@amazon.com> writes:
It looks like the exclusive way has been marked deprecated in all
supported versions along with a note that it will eventually be
removed. If it's not going to be removed out of fear of breaking
backward compatibility, I think the documentation should be updated to
say that. However, unless there is something that is preventing users
from switching to the non-exclusive approach, I think it is reasonable
to begin thinking about removing it.
If we're willing to outright remove it, I don't have any great objection.
My original two cents was that we shouldn't put effort into improving it;
but removing it isn't that.
regards, tom lane
On 11/30/21, 2:27 PM, "Tom Lane" <tgl@sss.pgh.pa.us> wrote:
If we're willing to outright remove it, I don't have any great objection.
My original two cents was that we shouldn't put effort into improving it;
but removing it isn't that.
I might try to put a patch together for the January commitfest, given
there is enough support.
Nathan
On 11/30/21 17:26, Tom Lane wrote:
"Bossart, Nathan" <bossartn@amazon.com> writes:
It looks like the exclusive way has been marked deprecated in all
supported versions along with a note that it will eventually be
removed. If it's not going to be removed out of fear of breaking
backward compatibility, I think the documentation should be updated to
say that. However, unless there is something that is preventing users
from switching to the non-exclusive approach, I think it is reasonable
to begin thinking about removing it.If we're willing to outright remove it, I don't have any great objection.
My original two cents was that we shouldn't put effort into improving it;
but removing it isn't that.
The main objections as I recall are that it is much harder for simple
backup scripts and commercial backup integrations to hold a connection
to postgres open and write the backup label separately into the backup.
As Stephen noted, working in this area is much harder (even in the docs)
due to the need to keep both methods working. When I removed exclusive
backup it didn't break any tests, other than one that needed to generate
a corrupt backup, so we have virtually no coverage for that method.
I did figure out how to keep the safe part of exclusive backup (not
having to maintain a connection) while removing the dangerous part
(writing backup_label into PGDATA), but it was a substantial amount of
work and I felt that it had little chance of being committed.
Attaching the thread [1]/messages/by-id/ac7339ca-3718-3c93-929f-99e725d1172c@pgmasters.net that I started with a patch to remove exclusive
backup for reference.
--
[1]: /messages/by-id/ac7339ca-3718-3c93-929f-99e725d1172c@pgmasters.net
/messages/by-id/ac7339ca-3718-3c93-929f-99e725d1172c@pgmasters.net
On 11/30/21, 2:58 PM, "David Steele" <david@pgmasters.net> wrote:
I did figure out how to keep the safe part of exclusive backup (not
having to maintain a connection) while removing the dangerous part
(writing backup_label into PGDATA), but it was a substantial amount of
work and I felt that it had little chance of being committed.
Do you think it's still worth trying to make it safe, or do you think
we should just remove exclusive mode completely?
Attaching the thread [1] that I started with a patch to remove exclusive
backup for reference.
Ah, good, some light reading. :)
Nathan
On Tue, Nov 30, 2021 at 05:58:15PM -0500, David Steele wrote:
The main objections as I recall are that it is much harder for simple backup
scripts and commercial backup integrations to hold a connection to postgres
open and write the backup label separately into the backup.
I don't quite understand why this argument would not hold even today,
even if I'd like to think that more people are using pg_basebackup.
I did figure out how to keep the safe part of exclusive backup (not having
to maintain a connection) while removing the dangerous part (writing
backup_label into PGDATA), but it was a substantial amount of work and I
felt that it had little chance of being committed.
Which was, I guess, done by storing the backup_label contents within a
file different than backup_label, still maintained in the main data
folder to ensure that it gets included in the backup?
--
Michael
On Tue, Nov 30, 2021 at 4:54 PM Michael Paquier <michael@paquier.xyz> wrote:
On Tue, Nov 30, 2021 at 05:58:15PM -0500, David Steele wrote:
The main objections as I recall are that it is much harder for simple
backup
scripts and commercial backup integrations to hold a connection to
postgres
open and write the backup label separately into the backup.
I don't quite understand why this argument would not hold even today,
even if I'd like to think that more people are using pg_basebackup.I did figure out how to keep the safe part of exclusive backup (not
having
to maintain a connection) while removing the dangerous part (writing
backup_label into PGDATA), but it was a substantial amount of work and I
felt that it had little chance of being committed.Which was, I guess, done by storing the backup_label contents within a
file different than backup_label, still maintained in the main data
folder to ensure that it gets included in the backup?
Non-exclusive backup has significant advantages over exclusive backups but
would like to add a few comments on the simplicity of exclusive backups -
1/ It is not uncommon nowadays to take a snapshot based backup. Exclusive
backup simplifies this story as the backup label file is part of the
snapshot. Otherwise, one needs to store it somewhere outside as snapshot
metadata and copy this file over during restore (after creating a disk from
the snapshot) to the data directory. Typical steps included are 1/ start
pg_base_backup 2/ Take disk snapshot 3/ pg_stop_backup() 4/ Mark snapshot
as consistent and add some create time metadata.
2/ Control plane code responsible for taking backups is simpler with
exclusive backups than non-exclusive as it doesn't maintain a connection to
the server, particularly when that orchestration is outside the machine the
Postgres server is running on.
IMHO, we should either remove the support for it or improve it but not
leave it hanging there.
On 11/30/21 19:54, Michael Paquier wrote:
On Tue, Nov 30, 2021 at 05:58:15PM -0500, David Steele wrote:
I did figure out how to keep the safe part of exclusive backup (not having
to maintain a connection) while removing the dangerous part (writing
backup_label into PGDATA), but it was a substantial amount of work and I
felt that it had little chance of being committed.Which was, I guess, done by storing the backup_label contents within a
file different than backup_label, still maintained in the main data
folder to ensure that it gets included in the backup?
That, or emit it from pg_start_backup() so the user can write it
wherever they please. That would include writing it into PGDATA if they
really wanted to, but that would be on them and the default behavior
would be safe. The problem with this is if the user does not
rename/supply backup_label on restore then they will get corruption and
not know it.
Here's another idea. Since the contents of pg_wal are not supposed to be
copied, we could add a file there to indicate that the cluster should
remove backup_label on restart. Our instructions also say to remove the
contents of pg_wal on restore if they were originally copied, so
hopefully one of the two would happen. But, again, if they fail to
follow the directions it would lead to corruption.
Order would be important here. When starting the backup the proper order
would be to write pg_wal/backup_in_progress and then backup_label. When
stopping the backup they would be removed in the reverse order.
On a restart if both are present then delete both in the correct order
and start crash recovery using the info in pg_control. If only
backup_label is present then go into recovery using the info from
backup_label.
It's possible for pg_wal/backup_in_process to be present by itself if
the server crashes after deleting backup_label but before deleting
pg_wal/backup_in_progress. In that case the server should simply remove
it on start and go into crash recovery using the info from pg_control.
The advantage of this idea is that it does not change the current
instructions as far as I can see. If the user is already following them,
they'll be fine. If they are not, then they'll need to start doing so.
Of course, none of this affects users who are using non-exclusive
backup, which I do hope covers the majority by now.
Thoughts?
Regards,
-David
On 11/30/21 17:26, Tom Lane wrote:
"Bossart, Nathan" <bossartn@amazon.com> writes:
It looks like the exclusive way has been marked deprecated in all
supported versions along with a note that it will eventually be
removed. If it's not going to be removed out of fear of breaking
backward compatibility, I think the documentation should be updated to
say that. However, unless there is something that is preventing users
from switching to the non-exclusive approach, I think it is reasonable
to begin thinking about removing it.If we're willing to outright remove it, I don't have any great objection.
My original two cents was that we shouldn't put effort into improving it;
but removing it isn't that.
+1
Let's just remove it. We already know it's a footgun, and there's been
plenty of warning.
cheers
andrew
--
Andrew Dunstan
EDB: https://www.enterprisedb.com
On 11/30/21 18:31, Bossart, Nathan wrote:
On 11/30/21, 2:58 PM, "David Steele" <david@pgmasters.net> wrote:
I did figure out how to keep the safe part of exclusive backup (not
having to maintain a connection) while removing the dangerous part
(writing backup_label into PGDATA), but it was a substantial amount of
work and I felt that it had little chance of being committed.Do you think it's still worth trying to make it safe, or do you think
we should just remove exclusive mode completely?
My preference would be to remove it completely, but I haven't gotten a
lot of traction so far.
Attaching the thread [1] that I started with a patch to remove exclusive
backup for reference.Ah, good, some light reading. :)
Sure, if you say so!
Regards,
-David
On 12/1/21, 8:27 AM, "David Steele" <david@pgmasters.net> wrote:
On 11/30/21 18:31, Bossart, Nathan wrote:
Do you think it's still worth trying to make it safe, or do you think
we should just remove exclusive mode completely?My preference would be to remove it completely, but I haven't gotten a
lot of traction so far.
In this thread, I count 6 people who seem alright with removing it,
and 2 who might be opposed, although I don't think anyone has
explicitly stated they are against it.
Nathan
On 12/1/21, 10:37 AM, "Bossart, Nathan" <bossartn@amazon.com> wrote:
On 12/1/21, 8:27 AM, "David Steele" <david@pgmasters.net> wrote:
On 11/30/21 18:31, Bossart, Nathan wrote:
Do you think it's still worth trying to make it safe, or do you think
we should just remove exclusive mode completely?My preference would be to remove it completely, but I haven't gotten a
lot of traction so far.In this thread, I count 6 people who seem alright with removing it,
and 2 who might be opposed, although I don't think anyone has
explicitly stated they are against it.
I hastily rebased the patch from 2018 and got it building and passing
the tests. I'm sure it will need additional changes, but I'll wait
for more feedback before I expend too much more effort on this.
Nathan
Attachments:
v1-0001-remove-exclusive-backup-mode.patchapplication/octet-stream; name=v1-0001-remove-exclusive-backup-mode.patchDownload
From f132dd976e7c92866bb38fbd6665ae87a4600eda Mon Sep 17 00:00:00 2001
From: Nathan Bossart <bossartn@amazon.com>
Date: Wed, 1 Dec 2021 23:50:49 +0000
Subject: [PATCH v1 1/1] remove exclusive backup mode
---
doc/src/sgml/backup.sgml | 154 +------
doc/src/sgml/func.sgml | 30 +-
src/backend/access/transam/xlog.c | 466 ++-------------------
src/backend/access/transam/xlogfuncs.c | 235 ++---------
src/backend/catalog/system_functions.sql | 14 +-
src/backend/postmaster/postmaster.c | 46 +-
src/backend/replication/basebackup.c | 6 +-
src/bin/pg_basebackup/t/010_pg_basebackup.pl | 4 +
src/bin/pg_rewind/filemap.c | 6 +-
src/include/access/xlog.h | 3 +-
src/include/catalog/pg_proc.dat | 20 +-
src/include/miscadmin.h | 4 -
src/test/perl/PostgreSQL/Test/Cluster.pm | 56 +--
.../recovery/t/010_logical_decoding_timelines.pl | 4 +-
14 files changed, 113 insertions(+), 935 deletions(-)
diff --git a/doc/src/sgml/backup.sgml b/doc/src/sgml/backup.sgml
index cba32b6eb3..9a8b9f84ea 100644
--- a/doc/src/sgml/backup.sgml
+++ b/doc/src/sgml/backup.sgml
@@ -837,16 +837,8 @@ test ! -f /mnt/server/archivedir/00000001000000A900000065 && cp pg_wal/0
sequence, and that the success of a step is verified before
proceeding to the next step.
</para>
- <para>
- Low level base backups can be made in a non-exclusive or an exclusive
- way. The non-exclusive method is recommended and the exclusive one is
- deprecated and will eventually be removed.
- </para>
-
- <sect3 id="backup-lowlevel-base-backup-nonexclusive">
- <title>Making a Non-Exclusive Low-Level Backup</title>
<para>
- A non-exclusive low level backup is one that allows other
+ A low level backup allows other
concurrent backups to be running (both those started using
the same backup API and those started using
<xref linkend="app-pgbasebackup"/>).
@@ -864,7 +856,7 @@ test ! -f /mnt/server/archivedir/00000001000000A900000065 && cp pg_wal/0
rights to run pg_start_backup (superuser, or a user who has been granted
EXECUTE on the function) and issue the command:
<programlisting>
-SELECT pg_start_backup('label', false, false);
+SELECT pg_start_backup('label', false);
</programlisting>
where <literal>label</literal> is any string you want to use to uniquely
identify this backup operation. The connection
@@ -885,10 +877,6 @@ SELECT pg_start_backup('label', false, false);
issue an immediate checkpoint using as much I/O as available.
</para>
- <para>
- The third parameter being <literal>false</literal> tells
- <function>pg_start_backup</function> to initiate a non-exclusive base backup.
- </para>
</listitem>
<listitem>
<para>
@@ -906,7 +894,7 @@ SELECT pg_start_backup('label', false, false);
<para>
In the same connection as before, issue the command:
<programlisting>
-SELECT * FROM pg_stop_backup(false, true);
+SELECT * FROM pg_stop_backup(true);
</programlisting>
This terminates backup mode. On a primary, it also performs an automatic
switch to the next WAL segment. On a standby, it is not possible to
@@ -965,142 +953,6 @@ SELECT * FROM pg_stop_backup(false, true);
</listitem>
</orderedlist>
</para>
- </sect3>
- <sect3 id="backup-lowlevel-base-backup-exclusive">
- <title>Making an Exclusive Low-Level Backup</title>
-
- <note>
- <para>
- The exclusive backup method is deprecated and should be avoided.
- Prior to <productname>PostgreSQL</productname> 9.6, this was the only
- low-level method available, but it is now recommended that all users
- upgrade their scripts to use non-exclusive backups.
- </para>
- </note>
-
- <para>
- The process for an exclusive backup is mostly the same as for a
- non-exclusive one, but it differs in a few key steps. This type of
- backup can only be taken on a primary and does not allow concurrent
- backups. Moreover, because it creates a backup label file, as
- described below, it can block automatic restart of the primary server
- after a crash. On the other hand, the erroneous removal of this
- file from a backup or standby is a common mistake, which can result
- in serious data corruption. If it is necessary to use this method,
- the following steps may be used.
- </para>
- <para>
- <orderedlist>
- <listitem>
- <para>
- Ensure that WAL archiving is enabled and working.
- </para>
- </listitem>
- <listitem>
- <para>
- Connect to the server (it does not matter which database) as a user with
- rights to run pg_start_backup (superuser, or a user who has been granted
- EXECUTE on the function) and issue the command:
-<programlisting>
-SELECT pg_start_backup('label');
-</programlisting>
- where <literal>label</literal> is any string you want to use to uniquely
- identify this backup operation.
- <function>pg_start_backup</function> creates a <firstterm>backup label</firstterm> file,
- called <filename>backup_label</filename>, in the cluster directory with
- information about your backup, including the start time and label string.
- The function also creates a <firstterm>tablespace map</firstterm> file,
- called <filename>tablespace_map</filename>, in the cluster directory with
- information about tablespace symbolic links in <filename>pg_tblspc/</filename> if
- one or more such link is present. Both files are critical to the
- integrity of the backup, should you need to restore from it.
- </para>
-
- <para>
- By default, <function>pg_start_backup</function> can take a long time to finish.
- This is because it performs a checkpoint, and the I/O
- required for the checkpoint will be spread out over a significant
- period of time, by default half your inter-checkpoint interval
- (see the configuration parameter
- <xref linkend="guc-checkpoint-completion-target"/>). This is
- usually what you want, because it minimizes the impact on query
- processing. If you want to start the backup as soon as
- possible, use:
-<programlisting>
-SELECT pg_start_backup('label', true);
-</programlisting>
- This forces the checkpoint to be done as quickly as possible.
- </para>
- </listitem>
- <listitem>
- <para>
- Perform the backup, using any convenient file-system-backup tool
- such as <application>tar</application> or <application>cpio</application> (not
- <application>pg_dump</application> or
- <application>pg_dumpall</application>). It is neither
- necessary nor desirable to stop normal operation of the database
- while you do this. See
- <xref linkend="backup-lowlevel-base-backup-data"/> for things to
- consider during this backup.
- </para>
- <para>
- As noted above, if the server crashes during the backup it may not be
- possible to restart until the <filename>backup_label</filename> file has
- been manually deleted from the <envar>PGDATA</envar> directory. Note
- that it is very important to never remove the
- <filename>backup_label</filename> file when restoring a backup, because
- this will result in corruption. Confusion about when it is appropriate
- to remove this file is a common cause of data corruption when using this
- method; be very certain that you remove the file only on an existing
- primary and never when building a standby or restoring a backup, even if
- you are building a standby that will subsequently be promoted to a new
- primary.
- </para>
- </listitem>
- <listitem>
- <para>
- Again connect to the database as a user with rights to run
- pg_stop_backup (superuser, or a user who has been granted EXECUTE on
- the function), and issue the command:
-<programlisting>
-SELECT pg_stop_backup();
-</programlisting>
- This function terminates backup mode and
- performs an automatic switch to the next WAL segment. The reason for the
- switch is to arrange for the last WAL segment written during the backup
- interval to be ready to archive.
- </para>
- </listitem>
- <listitem>
- <para>
- Once the WAL segment files active during the backup are archived, you are
- done. The file identified by <function>pg_stop_backup</function>'s result is
- the last segment that is required to form a complete set of backup files.
- If <varname>archive_mode</varname> is enabled,
- <function>pg_stop_backup</function> does not return until the last segment has
- been archived.
- Archiving of these files happens automatically since you have
- already configured <varname>archive_command</varname>. In most cases this
- happens quickly, but you are advised to monitor your archive
- system to ensure there are no delays.
- If the archive process has fallen behind
- because of failures of the archive command, it will keep retrying
- until the archive succeeds and the backup is complete.
- </para>
-
- <para>
- When using exclusive backup mode, it is absolutely imperative to ensure
- that <function>pg_stop_backup</function> completes successfully at the
- end of the backup. Even if the backup itself fails, for example due to
- lack of disk space, failure to call <function>pg_stop_backup</function>
- will leave the server in backup mode indefinitely, causing future backups
- to fail and increasing the risk of a restart failure during the time that
- <filename>backup_label</filename> exists.
- </para>
- </listitem>
- </orderedlist>
- </para>
- </sect3>
<sect3 id="backup-lowlevel-base-backup-data">
<title>Backing Up the Data Directory</title>
<para>
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 0a725a6711..28db66bb77 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -25580,8 +25580,7 @@ LOG: Grand total: 1651920 bytes in 201 blocks; 622360 free (88 chunks); 1029560
<function>pg_start_backup</function> (
<parameter>label</parameter> <type>text</type>
<optional>, <parameter>fast</parameter> <type>boolean</type>
- <optional>, <parameter>exclusive</parameter> <type>boolean</type>
- </optional></optional> )
+ </optional> )
<returnvalue>pg_lsn</returnvalue>
</para>
<para>
@@ -25593,20 +25592,6 @@ LOG: Grand total: 1651920 bytes in 201 blocks; 622360 free (88 chunks); 1029560
it specifies executing <function>pg_start_backup</function> as quickly
as possible. This forces an immediate checkpoint which will cause a
spike in I/O operations, slowing any concurrently executing queries.
- The optional third parameter specifies whether to perform an exclusive
- or non-exclusive backup (default is exclusive).
- </para>
- <para>
- When used in exclusive mode, this function writes a backup label file
- (<filename>backup_label</filename>) and, if there are any links in
- the <filename>pg_tblspc/</filename> directory, a tablespace map file
- (<filename>tablespace_map</filename>) into the database cluster's data
- directory, then performs a checkpoint, and then returns the backup's
- starting write-ahead log location. (The user can ignore this
- result value, but it is provided in case it is useful.) When used in
- non-exclusive mode, the contents of these files are instead returned
- by the <function>pg_stop_backup</function> function, and should be
- copied to the backup area by the user.
</para>
<para>
This function is restricted to superusers by default, but other users
@@ -25620,7 +25605,6 @@ LOG: Grand total: 1651920 bytes in 201 blocks; 622360 free (88 chunks); 1029560
<primary>pg_stop_backup</primary>
</indexterm>
<function>pg_stop_backup</function> (
- <parameter>exclusive</parameter> <type>boolean</type>
<optional>, <parameter>wait_for_archive</parameter> <type>boolean</type>
</optional> )
<returnvalue>setof record</returnvalue>
@@ -25629,13 +25613,8 @@ LOG: Grand total: 1651920 bytes in 201 blocks; 622360 free (88 chunks); 1029560
<parameter>spcmapfile</parameter> <type>text</type> )
</para>
<para>
- Finishes performing an exclusive or non-exclusive on-line backup.
- The <parameter>exclusive</parameter> parameter must match the
- previous <function>pg_start_backup</function> call.
- In an exclusive backup, <function>pg_stop_backup</function> removes
- the backup label file and, if it exists, the tablespace map file
- created by <function>pg_start_backup</function>. In a non-exclusive
- backup, the desired contents of these files are returned as part of
+ Finishes performing an on-line backup. The desired contents of the
+ backup label file and the tablespace map file are returned as part of
the result of the function, and should be written to files in the
backup area (not in the data directory).
</para>
@@ -25668,8 +25647,7 @@ LOG: Grand total: 1651920 bytes in 201 blocks; 622360 free (88 chunks); 1029560
The result of the function is a single record.
The <parameter>lsn</parameter> column holds the backup's ending
write-ahead log location (which again can be ignored). The second and
- third columns are <literal>NULL</literal> when ending an exclusive
- backup; after a non-exclusive backup they hold the desired contents of
+ third columns hold the desired contents of
the label and tablespace map files.
</para>
<para>
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index d894af310a..d4ca313d8a 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -482,29 +482,6 @@ typedef union WALInsertLockPadded
char pad[PG_CACHE_LINE_SIZE];
} WALInsertLockPadded;
-/*
- * State of an exclusive backup, necessary to control concurrent activities
- * across sessions when working on exclusive backups.
- *
- * EXCLUSIVE_BACKUP_NONE means that there is no exclusive backup actually
- * running, to be more precise pg_start_backup() is not being executed for
- * an exclusive backup and there is no exclusive backup in progress.
- * EXCLUSIVE_BACKUP_STARTING means that pg_start_backup() is starting an
- * exclusive backup.
- * EXCLUSIVE_BACKUP_IN_PROGRESS means that pg_start_backup() has finished
- * running and an exclusive backup is in progress. pg_stop_backup() is
- * needed to finish it.
- * EXCLUSIVE_BACKUP_STOPPING means that pg_stop_backup() is stopping an
- * exclusive backup.
- */
-typedef enum ExclusiveBackupState
-{
- EXCLUSIVE_BACKUP_NONE = 0,
- EXCLUSIVE_BACKUP_STARTING,
- EXCLUSIVE_BACKUP_IN_PROGRESS,
- EXCLUSIVE_BACKUP_STOPPING
-} ExclusiveBackupState;
-
/*
* Session status of running backup, used for sanity checks in SQL-callable
* functions to start and stop backups.
@@ -553,15 +530,12 @@ typedef struct XLogCtlInsert
bool fullPageWrites;
/*
- * exclusiveBackupState indicates the state of an exclusive backup (see
- * comments of ExclusiveBackupState for more details). nonExclusiveBackups
- * is a counter indicating the number of streaming base backups currently
- * in progress. forcePageWrites is set to true when either of these is
- * non-zero. lastBackupStart is the latest checkpoint redo location used
- * as a starting point for an online backup.
+ * runningBackups is a counter indicating the number of backups currently in
+ * progress. forcePageWrites is set to true when either of these is
+ * non-zero. lastBackupStart is the latest checkpoint redo location used as
+ * a starting point for an online backup.
*/
- ExclusiveBackupState exclusiveBackupState;
- int nonExclusiveBackups;
+ int runningBackups;
XLogRecPtr lastBackupStart;
/*
@@ -958,7 +932,6 @@ static void xlog_outrec(StringInfo buf, XLogReaderState *record);
static void xlog_block_info(StringInfo buf, XLogReaderState *record);
static void xlog_outdesc(StringInfo buf, XLogReaderState *record);
static void pg_start_backup_callback(int code, Datum arg);
-static void pg_stop_backup_callback(int code, Datum arg);
static bool read_backup_label(XLogRecPtr *checkPointLoc,
TimeLineID *backupLabelTLI,
bool *backupEndRequired, bool *backupFromStandby);
@@ -9801,7 +9774,7 @@ CreateRestartPoint(int flags)
* Ensure minRecoveryPoint is past the checkpoint record. Normally,
* this will have happened already while writing out dirty buffers,
* but not necessarily - e.g. because no buffers were dirtied. We do
- * this because a non-exclusive base backup uses minRecoveryPoint to
+ * this because a backup performed in recovery uses minRecoveryPoint to
* determine which WAL files must be included in the backup, and the
* file (or files) containing the checkpoint record must be included,
* at a minimum. Note that for an ordinary restart of recovery there's
@@ -10968,32 +10941,14 @@ issue_xlog_fsync(int fd, XLogSegNo segno, TimeLineID tli)
}
/*
- * do_pg_start_backup
- *
- * Utility function called at the start of an online backup. It creates the
- * necessary starting checkpoint and constructs the backup label file.
+ * do_pg_start_backup is the workhorse of the user-visible pg_start_backup()
+ * function. It creates the necessary starting checkpoint and constructs the
+ * backup label and tablespace map.
*
- * There are two kind of backups: exclusive and non-exclusive. An exclusive
- * backup is started with pg_start_backup(), and there can be only one active
- * at a time. The backup and tablespace map files of an exclusive backup are
- * written to $PGDATA/backup_label and $PGDATA/tablespace_map, and they are
- * removed by pg_stop_backup().
- *
- * A non-exclusive backup is used for the streaming base backups (see
- * src/backend/replication/basebackup.c). The difference to exclusive backups
- * is that the backup label and tablespace map files are not written to disk.
- * Instead, their would-be contents are returned in *labelfile and *tblspcmapfile,
- * and the caller is responsible for including them in the backup archive as
- * 'backup_label' and 'tablespace_map'. There can be many non-exclusive backups
- * active at the same time, and they don't conflict with an exclusive backup
- * either.
- *
- * labelfile and tblspcmapfile must be passed as NULL when starting an
- * exclusive backup, and as initially-empty StringInfos for a non-exclusive
- * backup.
- *
- * If "tablespaces" isn't NULL, it receives a list of tablespaceinfo structs
- * describing the cluster's tablespaces.
+ * The backup label and tablespace map contents are returned in *labelfile and
+ * *tblspcmapfile, and the caller is responsible for including them in the
+ * backup archive as 'backup_label' and 'tablespace_map'. There can be many
+ * backups active at the same time.
*
* tblspcmapfile is required mainly for tar format in windows as native windows
* utilities are not able to create symlinks while extracting files from tar.
@@ -11002,7 +10957,7 @@ issue_xlog_fsync(int fd, XLogSegNo segno, TimeLineID tli)
* Returns the minimum WAL location that must be present to restore from this
* backup, and the corresponding timeline ID in *starttli_p.
*
- * Every successfully started non-exclusive backup must be stopped by calling
+ * Every successfully started backup must be stopped by calling
* do_pg_stop_backup() or do_pg_abort_backup().
*
* It is the responsibility of the caller of this function to verify the
@@ -11013,7 +10968,6 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
StringInfo labelfile, List **tablespaces,
StringInfo tblspcmapfile)
{
- bool exclusive = (labelfile == NULL);
bool backup_started_in_recovery = false;
XLogRecPtr checkpointloc;
XLogRecPtr startpoint;
@@ -11022,20 +10976,9 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
char strfbuf[128];
char xlogfilename[MAXFNAMELEN];
XLogSegNo _logSegNo;
- struct stat stat_buf;
- FILE *fp;
backup_started_in_recovery = RecoveryInProgress();
- /*
- * Currently only non-exclusive backup can be taken during recovery.
- */
- if (backup_started_in_recovery && exclusive)
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("recovery is in progress"),
- errhint("WAL control functions cannot be executed during recovery.")));
-
/*
* During recovery, we don't need to check WAL level. Because, if WAL
* level is not sufficient, it's impossible to get here during recovery.
@@ -11074,30 +11017,12 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
* XLogInsertRecord().
*/
WALInsertLockAcquireExclusive();
- if (exclusive)
- {
- /*
- * At first, mark that we're now starting an exclusive backup, to
- * ensure that there are no other sessions currently running
- * pg_start_backup() or pg_stop_backup().
- */
- if (XLogCtl->Insert.exclusiveBackupState != EXCLUSIVE_BACKUP_NONE)
- {
- WALInsertLockRelease();
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("a backup is already in progress"),
- errhint("Run pg_stop_backup() and try again.")));
- }
- XLogCtl->Insert.exclusiveBackupState = EXCLUSIVE_BACKUP_STARTING;
- }
- else
- XLogCtl->Insert.nonExclusiveBackups++;
+ XLogCtl->Insert.runningBackups++;
XLogCtl->Insert.forcePageWrites = true;
WALInsertLockRelease();
/* Ensure we release forcePageWrites if fail below */
- PG_ENSURE_ERROR_CLEANUP(pg_start_backup_callback, (Datum) BoolGetDatum(exclusive));
+ PG_ENSURE_ERROR_CLEANUP(pg_start_backup_callback, (Datum) 0);
{
bool gotUniqueStartpoint = false;
DIR *tblspcdir;
@@ -11332,122 +11257,19 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
LSN_FORMAT_ARGS(startpoint), xlogfilename);
appendStringInfo(labelfile, "CHECKPOINT LOCATION: %X/%X\n",
LSN_FORMAT_ARGS(checkpointloc));
- appendStringInfo(labelfile, "BACKUP METHOD: %s\n",
- exclusive ? "pg_start_backup" : "streamed");
+ appendStringInfo(labelfile, "BACKUP METHOD: streamed\n");
appendStringInfo(labelfile, "BACKUP FROM: %s\n",
backup_started_in_recovery ? "standby" : "primary");
appendStringInfo(labelfile, "START TIME: %s\n", strfbuf);
appendStringInfo(labelfile, "LABEL: %s\n", backupidstr);
appendStringInfo(labelfile, "START TIMELINE: %u\n", starttli);
-
- /*
- * Okay, write the file, or return its contents to caller.
- */
- if (exclusive)
- {
- /*
- * Check for existing backup label --- implies a backup is already
- * running. (XXX given that we checked exclusiveBackupState
- * above, maybe it would be OK to just unlink any such label
- * file?)
- */
- if (stat(BACKUP_LABEL_FILE, &stat_buf) != 0)
- {
- if (errno != ENOENT)
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not stat file \"%s\": %m",
- BACKUP_LABEL_FILE)));
- }
- else
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("a backup is already in progress"),
- errhint("If you're sure there is no backup in progress, remove file \"%s\" and try again.",
- BACKUP_LABEL_FILE)));
-
- fp = AllocateFile(BACKUP_LABEL_FILE, "w");
-
- if (!fp)
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not create file \"%s\": %m",
- BACKUP_LABEL_FILE)));
- if (fwrite(labelfile->data, labelfile->len, 1, fp) != 1 ||
- fflush(fp) != 0 ||
- pg_fsync(fileno(fp)) != 0 ||
- ferror(fp) ||
- FreeFile(fp))
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not write file \"%s\": %m",
- BACKUP_LABEL_FILE)));
- /* Allocated locally for exclusive backups, so free separately */
- pfree(labelfile->data);
- pfree(labelfile);
-
- /* Write backup tablespace_map file. */
- if (tblspcmapfile->len > 0)
- {
- if (stat(TABLESPACE_MAP, &stat_buf) != 0)
- {
- if (errno != ENOENT)
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not stat file \"%s\": %m",
- TABLESPACE_MAP)));
- }
- else
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("a backup is already in progress"),
- errhint("If you're sure there is no backup in progress, remove file \"%s\" and try again.",
- TABLESPACE_MAP)));
-
- fp = AllocateFile(TABLESPACE_MAP, "w");
-
- if (!fp)
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not create file \"%s\": %m",
- TABLESPACE_MAP)));
- if (fwrite(tblspcmapfile->data, tblspcmapfile->len, 1, fp) != 1 ||
- fflush(fp) != 0 ||
- pg_fsync(fileno(fp)) != 0 ||
- ferror(fp) ||
- FreeFile(fp))
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not write file \"%s\": %m",
- TABLESPACE_MAP)));
- }
-
- /* Allocated locally for exclusive backups, so free separately */
- pfree(tblspcmapfile->data);
- pfree(tblspcmapfile);
- }
}
- PG_END_ENSURE_ERROR_CLEANUP(pg_start_backup_callback, (Datum) BoolGetDatum(exclusive));
+ PG_END_ENSURE_ERROR_CLEANUP(pg_start_backup_callback, (Datum) 0);
/*
- * Mark that start phase has correctly finished for an exclusive backup.
- * Session-level locks are updated as well to reflect that state.
- *
- * Note that CHECK_FOR_INTERRUPTS() must not occur while updating backup
- * counters and session-level lock. Otherwise they can be updated
- * inconsistently, and which might cause do_pg_abort_backup() to fail.
+ * Mark that the start phase has correctly finished for the backup.
*/
- if (exclusive)
- {
- WALInsertLockAcquireExclusive();
- XLogCtl->Insert.exclusiveBackupState = EXCLUSIVE_BACKUP_IN_PROGRESS;
-
- /* Set session-level lock */
- sessionBackupState = SESSION_BACKUP_EXCLUSIVE;
- WALInsertLockRelease();
- }
- else
- sessionBackupState = SESSION_BACKUP_NON_EXCLUSIVE;
+ sessionBackupState = SESSION_BACKUP_RUNNING;
/*
* We're done. As a convenience, return the starting WAL location.
@@ -11461,43 +11283,15 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
static void
pg_start_backup_callback(int code, Datum arg)
{
- bool exclusive = DatumGetBool(arg);
-
/* Update backup counters and forcePageWrites on failure */
WALInsertLockAcquireExclusive();
- if (exclusive)
- {
- Assert(XLogCtl->Insert.exclusiveBackupState == EXCLUSIVE_BACKUP_STARTING);
- XLogCtl->Insert.exclusiveBackupState = EXCLUSIVE_BACKUP_NONE;
- }
- else
- {
- Assert(XLogCtl->Insert.nonExclusiveBackups > 0);
- XLogCtl->Insert.nonExclusiveBackups--;
- }
- if (XLogCtl->Insert.exclusiveBackupState == EXCLUSIVE_BACKUP_NONE &&
- XLogCtl->Insert.nonExclusiveBackups == 0)
- {
- XLogCtl->Insert.forcePageWrites = false;
- }
- WALInsertLockRelease();
-}
-
-/*
- * Error cleanup callback for pg_stop_backup
- */
-static void
-pg_stop_backup_callback(int code, Datum arg)
-{
- bool exclusive = DatumGetBool(arg);
+ Assert(XLogCtl->Insert.runningBackups > 0);
+ XLogCtl->Insert.runningBackups--;
- /* Update backup status on failure */
- WALInsertLockAcquireExclusive();
- if (exclusive)
+ if (XLogCtl->Insert.runningBackups == 0)
{
- Assert(XLogCtl->Insert.exclusiveBackupState == EXCLUSIVE_BACKUP_STOPPING);
- XLogCtl->Insert.exclusiveBackupState = EXCLUSIVE_BACKUP_IN_PROGRESS;
+ XLogCtl->Insert.forcePageWrites = false;
}
WALInsertLockRelease();
}
@@ -11517,9 +11311,6 @@ get_backup_status(void)
* Utility function called at the end of an online backup. It cleans up the
* backup state and can optionally wait for WAL segments to be archived.
*
- * If labelfile is NULL, this stops an exclusive backup. Otherwise this stops
- * the non-exclusive backup specified by 'labelfile'.
- *
* Returns the last WAL location that must be present to restore from this
* backup, and the corresponding timeline ID in *stoptli_p.
*
@@ -11529,7 +11320,6 @@ get_backup_status(void)
XLogRecPtr
do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
{
- bool exclusive = (labelfile == NULL);
bool backup_started_in_recovery = false;
XLogRecPtr startpoint;
XLogRecPtr stoppoint;
@@ -11543,7 +11333,6 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
char histfilename[MAXFNAMELEN];
char backupfrom[20];
XLogSegNo _logSegNo;
- FILE *lfp;
FILE *fp;
char ch;
int seconds_before_warning;
@@ -11556,15 +11345,6 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
backup_started_in_recovery = RecoveryInProgress();
- /*
- * Currently only non-exclusive backup can be taken during recovery.
- */
- if (backup_started_in_recovery && exclusive)
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("recovery is in progress"),
- errhint("WAL control functions cannot be executed during recovery.")));
-
/*
* During recovery, we don't need to check WAL level. Because, if WAL
* level is not sufficient, it's impossible to get here during recovery.
@@ -11575,106 +11355,23 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
errmsg("WAL level not sufficient for making an online backup"),
errhint("wal_level must be set to \"replica\" or \"logical\" at server start.")));
- if (exclusive)
- {
- /*
- * At first, mark that we're now stopping an exclusive backup, to
- * ensure that there are no other sessions currently running
- * pg_start_backup() or pg_stop_backup().
- */
- WALInsertLockAcquireExclusive();
- if (XLogCtl->Insert.exclusiveBackupState != EXCLUSIVE_BACKUP_IN_PROGRESS)
- {
- WALInsertLockRelease();
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("exclusive backup not in progress")));
- }
- XLogCtl->Insert.exclusiveBackupState = EXCLUSIVE_BACKUP_STOPPING;
- WALInsertLockRelease();
-
- /*
- * Remove backup_label. In case of failure, the state for an exclusive
- * backup is switched back to in-progress.
- */
- PG_ENSURE_ERROR_CLEANUP(pg_stop_backup_callback, (Datum) BoolGetDatum(exclusive));
- {
- /*
- * Read the existing label file into memory.
- */
- struct stat statbuf;
- int r;
-
- if (stat(BACKUP_LABEL_FILE, &statbuf))
- {
- /* should not happen per the upper checks */
- if (errno != ENOENT)
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not stat file \"%s\": %m",
- BACKUP_LABEL_FILE)));
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("a backup is not in progress")));
- }
-
- lfp = AllocateFile(BACKUP_LABEL_FILE, "r");
- if (!lfp)
- {
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not read file \"%s\": %m",
- BACKUP_LABEL_FILE)));
- }
- labelfile = palloc(statbuf.st_size + 1);
- r = fread(labelfile, statbuf.st_size, 1, lfp);
- labelfile[statbuf.st_size] = '\0';
-
- /*
- * Close and remove the backup label file
- */
- if (r != 1 || ferror(lfp) || FreeFile(lfp))
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not read file \"%s\": %m",
- BACKUP_LABEL_FILE)));
- durable_unlink(BACKUP_LABEL_FILE, ERROR);
-
- /*
- * Remove tablespace_map file if present, it is created only if
- * there are tablespaces.
- */
- durable_unlink(TABLESPACE_MAP, DEBUG1);
- }
- PG_END_ENSURE_ERROR_CLEANUP(pg_stop_backup_callback, (Datum) BoolGetDatum(exclusive));
- }
-
/*
- * OK to update backup counters, forcePageWrites and session-level lock.
+ * OK to update backup counters and forcePageWrites.
*
* Note that CHECK_FOR_INTERRUPTS() must not occur while updating them.
* Otherwise they can be updated inconsistently, and which might cause
* do_pg_abort_backup() to fail.
*/
WALInsertLockAcquireExclusive();
- if (exclusive)
- {
- XLogCtl->Insert.exclusiveBackupState = EXCLUSIVE_BACKUP_NONE;
- }
- else
- {
- /*
- * The user-visible pg_start/stop_backup() functions that operate on
- * exclusive backups can be called at any time, but for non-exclusive
- * backups, it is expected that each do_pg_start_backup() call is
- * matched by exactly one do_pg_stop_backup() call.
- */
- Assert(XLogCtl->Insert.nonExclusiveBackups > 0);
- XLogCtl->Insert.nonExclusiveBackups--;
- }
- if (XLogCtl->Insert.exclusiveBackupState == EXCLUSIVE_BACKUP_NONE &&
- XLogCtl->Insert.nonExclusiveBackups == 0)
+ /*
+ * It is expected that each do_pg_start_backup() call is matched by exactly
+ * one do_pg_stop_backup() call.
+ */
+ Assert(XLogCtl->Insert.runningBackups > 0);
+ XLogCtl->Insert.runningBackups--;
+
+ if (XLogCtl->Insert.runningBackups == 0)
{
XLogCtl->Insert.forcePageWrites = false;
}
@@ -11939,10 +11636,6 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
* The caller can pass 'arg' as 'true' or 'false' to control whether a warning
* is emitted.
*
- * NB: This is only for aborting a non-exclusive backup that doesn't write
- * backup_label. A backup started with pg_start_backup() needs to be finished
- * with pg_stop_backup().
- *
* NB: This gets used as a before_shmem_exit handler, hence the odd-looking
* signature.
*/
@@ -11952,18 +11645,16 @@ do_pg_abort_backup(int code, Datum arg)
bool emit_warning = DatumGetBool(arg);
/*
- * Quick exit if session is not keeping around a non-exclusive backup
- * already started.
+ * Quick exit if session does not have a running backup.
*/
- if (sessionBackupState != SESSION_BACKUP_NON_EXCLUSIVE)
+ if (sessionBackupState != SESSION_BACKUP_RUNNING)
return;
WALInsertLockAcquireExclusive();
- Assert(XLogCtl->Insert.nonExclusiveBackups > 0);
- XLogCtl->Insert.nonExclusiveBackups--;
+ Assert(XLogCtl->Insert.runningBackups > 0);
+ XLogCtl->Insert.runningBackups--;
- if (XLogCtl->Insert.exclusiveBackupState == EXCLUSIVE_BACKUP_NONE &&
- XLogCtl->Insert.nonExclusiveBackups == 0)
+ if (XLogCtl->Insert.runningBackups == 0)
{
XLogCtl->Insert.forcePageWrites = false;
}
@@ -12308,87 +11999,6 @@ rm_redo_error_callback(void *arg)
pfree(buf.data);
}
-/*
- * BackupInProgress: check if online backup mode is active
- *
- * This is done by checking for existence of the "backup_label" file.
- */
-bool
-BackupInProgress(void)
-{
- struct stat stat_buf;
-
- return (stat(BACKUP_LABEL_FILE, &stat_buf) == 0);
-}
-
-/*
- * CancelBackup: rename the "backup_label" and "tablespace_map"
- * files to cancel backup mode
- *
- * If the "backup_label" file exists, it will be renamed to "backup_label.old".
- * Similarly, if the "tablespace_map" file exists, it will be renamed to
- * "tablespace_map.old".
- *
- * Note that this will render an online backup in progress
- * useless. To correctly finish an online backup, pg_stop_backup must be
- * called.
- */
-void
-CancelBackup(void)
-{
- struct stat stat_buf;
-
- /* if the backup_label file is not there, return */
- if (stat(BACKUP_LABEL_FILE, &stat_buf) < 0)
- return;
-
- /* remove leftover file from previously canceled backup if it exists */
- unlink(BACKUP_LABEL_OLD);
-
- if (durable_rename(BACKUP_LABEL_FILE, BACKUP_LABEL_OLD, DEBUG1) != 0)
- {
- ereport(WARNING,
- (errcode_for_file_access(),
- errmsg("online backup mode was not canceled"),
- errdetail("File \"%s\" could not be renamed to \"%s\": %m.",
- BACKUP_LABEL_FILE, BACKUP_LABEL_OLD)));
- return;
- }
-
- /* if the tablespace_map file is not there, return */
- if (stat(TABLESPACE_MAP, &stat_buf) < 0)
- {
- ereport(LOG,
- (errmsg("online backup mode canceled"),
- errdetail("File \"%s\" was renamed to \"%s\".",
- BACKUP_LABEL_FILE, BACKUP_LABEL_OLD)));
- return;
- }
-
- /* remove leftover file from previously canceled backup if it exists */
- unlink(TABLESPACE_MAP_OLD);
-
- if (durable_rename(TABLESPACE_MAP, TABLESPACE_MAP_OLD, DEBUG1) == 0)
- {
- ereport(LOG,
- (errmsg("online backup mode canceled"),
- errdetail("Files \"%s\" and \"%s\" were renamed to "
- "\"%s\" and \"%s\", respectively.",
- BACKUP_LABEL_FILE, TABLESPACE_MAP,
- BACKUP_LABEL_OLD, TABLESPACE_MAP_OLD)));
- }
- else
- {
- ereport(WARNING,
- (errcode_for_file_access(),
- errmsg("online backup mode canceled"),
- errdetail("File \"%s\" was renamed to \"%s\", but "
- "file \"%s\" could not be renamed to \"%s\": %m.",
- BACKUP_LABEL_FILE, BACKUP_LABEL_OLD,
- TABLESPACE_MAP, TABLESPACE_MAP_OLD)));
- }
-}
-
/*
* Read the XLOG page containing RecPtr into readBuf (if not read already).
* Returns number of bytes read, if the page is read successfully, or -1
diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c
index dd9a45c186..aab5dd88fa 100644
--- a/src/backend/access/transam/xlogfuncs.c
+++ b/src/backend/access/transam/xlogfuncs.c
@@ -39,7 +39,7 @@
#include "utils/tuplestore.h"
/*
- * Store label file and tablespace map during non-exclusive backups.
+ * Store label file and tablespace map during backups.
*/
static StringInfo label_file;
static StringInfo tblspc_map_file;
@@ -61,101 +61,40 @@ pg_start_backup(PG_FUNCTION_ARGS)
{
text *backupid = PG_GETARG_TEXT_PP(0);
bool fast = PG_GETARG_BOOL(1);
- bool exclusive = PG_GETARG_BOOL(2);
char *backupidstr;
XLogRecPtr startpoint;
SessionBackupState status = get_backup_status();
+ MemoryContext oldcontext;
backupidstr = text_to_cstring(backupid);
- if (status == SESSION_BACKUP_NON_EXCLUSIVE)
+ if (status == SESSION_BACKUP_RUNNING)
ereport(ERROR,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("a backup is already in progress in this session")));
- if (exclusive)
- {
- startpoint = do_pg_start_backup(backupidstr, fast, NULL, NULL,
- NULL, NULL);
- }
- else
- {
- MemoryContext oldcontext;
-
- /*
- * Label file and tablespace map file need to be long-lived, since
- * they are read in pg_stop_backup.
- */
- oldcontext = MemoryContextSwitchTo(TopMemoryContext);
- label_file = makeStringInfo();
- tblspc_map_file = makeStringInfo();
- MemoryContextSwitchTo(oldcontext);
+ /*
+ * Label file and tablespace map file need to be long-lived, since
+ * they are read in pg_stop_backup.
+ */
+ oldcontext = MemoryContextSwitchTo(TopMemoryContext);
+ label_file = makeStringInfo();
+ tblspc_map_file = makeStringInfo();
+ MemoryContextSwitchTo(oldcontext);
- register_persistent_abort_backup_handler();
+ register_persistent_abort_backup_handler();
- startpoint = do_pg_start_backup(backupidstr, fast, NULL, label_file,
- NULL, tblspc_map_file);
- }
+ startpoint = do_pg_start_backup(backupidstr, fast, NULL, label_file,
+ NULL, tblspc_map_file);
PG_RETURN_LSN(startpoint);
}
-/*
- * pg_stop_backup: finish taking an on-line backup dump
- *
- * We write an end-of-backup WAL record, and remove the backup label file
- * created by pg_start_backup, creating a backup history file in pg_wal
- * instead (whence it will immediately be archived). The backup history file
- * contains the same info found in the label file, plus the backup-end time
- * and WAL location. Before 9.0, the backup-end time was read from the backup
- * history file at the beginning of archive recovery, but we now use the WAL
- * record for that and the file is for informational and debug purposes only.
- *
- * Note: different from CancelBackup which just cancels online backup mode.
- *
- * Note: this version is only called to stop an exclusive backup. The function
- * pg_stop_backup_v2 (overloaded as pg_stop_backup in SQL) is called to
- * stop non-exclusive backups.
- *
- * Permission checking for this function is managed through the normal
- * GRANT system.
- */
-Datum
-pg_stop_backup(PG_FUNCTION_ARGS)
-{
- XLogRecPtr stoppoint;
- SessionBackupState status = get_backup_status();
-
- if (status == SESSION_BACKUP_NON_EXCLUSIVE)
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("non-exclusive backup in progress"),
- errhint("Did you mean to use pg_stop_backup('f')?")));
-
- /*
- * Exclusive backups were typically started in a different connection, so
- * don't try to verify that status of backup is set to
- * SESSION_BACKUP_EXCLUSIVE in this function. Actual verification that an
- * exclusive backup is in fact running is handled inside
- * do_pg_stop_backup.
- */
- stoppoint = do_pg_stop_backup(NULL, true, NULL);
-
- PG_RETURN_LSN(stoppoint);
-}
-
/*
- * pg_stop_backup_v2: finish taking exclusive or nonexclusive on-line backup.
- *
- * Works the same as pg_stop_backup, except for non-exclusive backups it returns
- * the backup label and tablespace map files as text fields in as part of the
- * resultset.
+ * pg_stop_backup: finish taking an on-line backup.
*
- * The first parameter (variable 'exclusive') allows the user to tell us if
- * this is an exclusive or a non-exclusive backup.
- *
- * The second parameter (variable 'waitforarchive'), which is optional,
+ * The first parameter (variable 'waitforarchive'), which is optional,
* allows the user to choose if they want to wait for the WAL to be archived
* or if we should just return as soon as the WAL record is written.
*
@@ -163,7 +102,7 @@ pg_stop_backup(PG_FUNCTION_ARGS)
* GRANT system.
*/
Datum
-pg_stop_backup_v2(PG_FUNCTION_ARGS)
+pg_stop_backup(PG_FUNCTION_ARGS)
{
ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
TupleDesc tupdesc;
@@ -173,8 +112,7 @@ pg_stop_backup_v2(PG_FUNCTION_ARGS)
Datum values[3];
bool nulls[3];
- bool exclusive = PG_GETARG_BOOL(0);
- bool waitforarchive = PG_GETARG_BOOL(1);
+ bool waitforarchive = PG_GETARG_BOOL(0);
XLogRecPtr stoppoint;
SessionBackupState status = get_backup_status();
@@ -205,51 +143,29 @@ pg_stop_backup_v2(PG_FUNCTION_ARGS)
MemSet(values, 0, sizeof(values));
MemSet(nulls, 0, sizeof(nulls));
- if (exclusive)
- {
- if (status == SESSION_BACKUP_NON_EXCLUSIVE)
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("non-exclusive backup in progress"),
- errhint("Did you mean to use pg_stop_backup('f')?")));
-
- /*
- * Stop the exclusive backup, and since we're in an exclusive backup
- * return NULL for both backup_label and tablespace_map.
- */
- stoppoint = do_pg_stop_backup(NULL, waitforarchive, NULL);
-
- nulls[1] = true;
- nulls[2] = true;
- }
- else
- {
- if (status != SESSION_BACKUP_NON_EXCLUSIVE)
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("non-exclusive backup is not in progress"),
- errhint("Did you mean to use pg_stop_backup('t')?")));
+ if (status != SESSION_BACKUP_RUNNING)
+ ereport(ERROR,
+ (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ errmsg("backup is not in progress"),
+ errhint("Did you call pg_start_backup()?")));
- /*
- * Stop the non-exclusive backup. Return a copy of the backup label
- * and tablespace map so they can be written to disk by the caller.
- */
- stoppoint = do_pg_stop_backup(label_file->data, waitforarchive, NULL);
-
- values[1] = CStringGetTextDatum(label_file->data);
- values[2] = CStringGetTextDatum(tblspc_map_file->data);
-
- /* Free structures allocated in TopMemoryContext */
- pfree(label_file->data);
- pfree(label_file);
- label_file = NULL;
- pfree(tblspc_map_file->data);
- pfree(tblspc_map_file);
- tblspc_map_file = NULL;
- }
+ /*
+ * Stop the backup. Return a copy of the backup label and tablespace map so
+ * they can be written to disk by the caller.
+ */
+ stoppoint = do_pg_stop_backup(label_file->data, waitforarchive, NULL);
- /* Stoppoint is included on both exclusive and nonexclusive backups */
values[0] = LSNGetDatum(stoppoint);
+ values[1] = CStringGetTextDatum(label_file->data);
+ values[2] = CStringGetTextDatum(tblspc_map_file->data);
+
+ /* Free structures allocated in TopMemoryContext */
+ pfree(label_file->data);
+ pfree(label_file);
+ label_file = NULL;
+ pfree(tblspc_map_file->data);
+ pfree(tblspc_map_file);
+ tblspc_map_file = NULL;
tuplestore_putvalues(tupstore, tupdesc, values, nulls);
tuplestore_donestoring(tupstore);
@@ -670,81 +586,6 @@ pg_wal_lsn_diff(PG_FUNCTION_ARGS)
PG_RETURN_NUMERIC(result);
}
-/*
- * Returns bool with current on-line backup mode, a global state.
- */
-Datum
-pg_is_in_backup(PG_FUNCTION_ARGS)
-{
- PG_RETURN_BOOL(BackupInProgress());
-}
-
-/*
- * Returns start time of an online exclusive backup.
- *
- * When there's no exclusive backup in progress, the function
- * returns NULL.
- */
-Datum
-pg_backup_start_time(PG_FUNCTION_ARGS)
-{
- Datum xtime;
- FILE *lfp;
- char fline[MAXPGPATH];
- char backup_start_time[30];
-
- /*
- * See if label file is present
- */
- lfp = AllocateFile(BACKUP_LABEL_FILE, "r");
- if (lfp == NULL)
- {
- if (errno != ENOENT)
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not read file \"%s\": %m",
- BACKUP_LABEL_FILE)));
- PG_RETURN_NULL();
- }
-
- /*
- * Parse the file to find the START TIME line.
- */
- backup_start_time[0] = '\0';
- while (fgets(fline, sizeof(fline), lfp) != NULL)
- {
- if (sscanf(fline, "START TIME: %25[^\n]\n", backup_start_time) == 1)
- break;
- }
-
- /* Check for a read error. */
- if (ferror(lfp))
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not read file \"%s\": %m", BACKUP_LABEL_FILE)));
-
- /* Close the backup label file. */
- if (FreeFile(lfp))
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not close file \"%s\": %m", BACKUP_LABEL_FILE)));
-
- if (strlen(backup_start_time) == 0)
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("invalid data in file \"%s\"", BACKUP_LABEL_FILE)));
-
- /*
- * Convert the time string read from file to TimestampTz form.
- */
- xtime = DirectFunctionCall3(timestamptz_in,
- CStringGetDatum(backup_start_time),
- ObjectIdGetDatum(InvalidOid),
- Int32GetDatum(-1));
-
- PG_RETURN_DATUM(xtime);
-}
-
/*
* Promotes a standby server.
*
diff --git a/src/backend/catalog/system_functions.sql b/src/backend/catalog/system_functions.sql
index 3a4fa9091b..c8390cca06 100644
--- a/src/backend/catalog/system_functions.sql
+++ b/src/backend/catalog/system_functions.sql
@@ -377,14 +377,14 @@ BEGIN ATOMIC
END;
CREATE OR REPLACE FUNCTION
- pg_start_backup(label text, fast boolean DEFAULT false, exclusive boolean DEFAULT true)
+ pg_start_backup(label text, fast boolean DEFAULT false)
RETURNS pg_lsn STRICT VOLATILE LANGUAGE internal AS 'pg_start_backup'
PARALLEL RESTRICTED;
CREATE OR REPLACE FUNCTION pg_stop_backup (
- exclusive boolean, wait_for_archive boolean DEFAULT true,
- OUT lsn pg_lsn, OUT labelfile text, OUT spcmapfile text)
- RETURNS SETOF record STRICT VOLATILE LANGUAGE internal as 'pg_stop_backup_v2'
+ wait_for_archive boolean DEFAULT true, OUT lsn pg_lsn,
+ OUT labelfile text, OUT spcmapfile text)
+ RETURNS SETOF record STRICT VOLATILE LANGUAGE internal as 'pg_stop_backup'
PARALLEL RESTRICTED;
CREATE OR REPLACE FUNCTION
@@ -603,11 +603,9 @@ AS 'unicode_is_normalized';
-- available to superuser / cluster owner, if they choose.
--
-REVOKE EXECUTE ON FUNCTION pg_start_backup(text, boolean, boolean) FROM public;
+REVOKE EXECUTE ON FUNCTION pg_start_backup(text, boolean) FROM public;
-REVOKE EXECUTE ON FUNCTION pg_stop_backup() FROM public;
-
-REVOKE EXECUTE ON FUNCTION pg_stop_backup(boolean, boolean) FROM public;
+REVOKE EXECUTE ON FUNCTION pg_stop_backup(boolean) FROM public;
REVOKE EXECUTE ON FUNCTION pg_create_restore_point(text) FROM public;
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index 328ecafa8c..fc84244c6a 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -347,7 +347,6 @@ static PMState pmState = PM_INIT;
typedef enum
{
ALLOW_ALL_CONNS, /* normal not-shutting-down state */
- ALLOW_SUPERUSER_CONNS, /* only superusers can connect */
ALLOW_NO_CONNS /* no new connections allowed, period */
} ConnsAllowedState;
@@ -2547,19 +2546,11 @@ canAcceptConnections(int backend_type)
/*
* "Smart shutdown" restrictions are applied only to normal connections,
- * not to autovac workers or bgworkers. When only superusers can connect,
- * we return CAC_SUPERUSER to indicate that superuserness must be checked
- * later. Note that neither CAC_OK nor CAC_SUPERUSER can safely be
- * returned until we have checked for too many children.
+ * not to autovac workers or bgworkers.
*/
if (connsAllowed != ALLOW_ALL_CONNS &&
backend_type == BACKEND_TYPE_NORMAL)
- {
- if (connsAllowed == ALLOW_SUPERUSER_CONNS)
- result = CAC_SUPERUSER; /* allow superusers only */
- else
- return CAC_SHUTDOWN; /* shutdown is pending */
- }
+ return CAC_SHUTDOWN; /* shutdown is pending */
/*
* Don't start too many children.
@@ -2878,16 +2869,11 @@ pmdie(SIGNAL_ARGS)
#endif
/*
- * If we reached normal running, we have to wait for any online
- * backup mode to end; otherwise go straight to waiting for client
- * backends to exit. (The difference is that in the former state,
- * we'll still let in new superuser clients, so that somebody can
- * end the online backup mode.) If already in PM_STOP_BACKENDS or
+ * If we reached normal running, we go straight to waiting for
+ * client backends to exit. If already in PM_STOP_BACKENDS or
* a later state, do not change it.
*/
- if (pmState == PM_RUN)
- connsAllowed = ALLOW_SUPERUSER_CONNS;
- else if (pmState == PM_HOT_STANDBY)
+ if (pmState == PM_RUN || pmState == PM_HOT_STANDBY)
connsAllowed = ALLOW_NO_CONNS;
else if (pmState == PM_STARTUP || pmState == PM_RECOVERY)
{
@@ -3843,16 +3829,6 @@ PostmasterStateMachine(void)
/* If we're doing a smart shutdown, try to advance that state. */
if (pmState == PM_RUN || pmState == PM_HOT_STANDBY)
{
- if (connsAllowed == ALLOW_SUPERUSER_CONNS)
- {
- /*
- * ALLOW_SUPERUSER_CONNS state ends as soon as online backup mode
- * is not active.
- */
- if (!BackupInProgress())
- connsAllowed = ALLOW_NO_CONNS;
- }
-
if (connsAllowed == ALLOW_NO_CONNS)
{
/*
@@ -4045,18 +4021,6 @@ PostmasterStateMachine(void)
}
else
{
- /*
- * Terminate exclusive backup mode to avoid recovery after a clean
- * fast shutdown. Since an exclusive backup can only be taken
- * during normal running (and not, for example, while running
- * under Hot Standby) it only makes sense to do this if we reached
- * normal running. If we're still in recovery, the backup file is
- * one we're recovering *from*, and we must keep it around so that
- * recovery restarts from the right place.
- */
- if (ReachedNormalRunning)
- CancelBackup();
-
/*
* Normal exit from the postmaster is here. We don't need to log
* anything here, since the UnlinkLockFiles proc_exit callback
diff --git a/src/backend/replication/basebackup.c b/src/backend/replication/basebackup.c
index ec0485705d..3d3b111c79 100644
--- a/src/backend/replication/basebackup.c
+++ b/src/backend/replication/basebackup.c
@@ -177,10 +177,8 @@ static const struct exclude_list_item excludeFiles[] =
{RELCACHE_INIT_FILENAME, true},
/*
- * If there's a backup_label or tablespace_map file, it belongs to a
- * backup started by the user with pg_start_backup(). It is *not* correct
- * for this backup. Our backup_label/tablespace_map is injected into the
- * tar separately.
+ * backup_label and tablespace_map should not exist in in a running cluster
+ * capable of doing an online backup, but exclude then just in case.
*/
{BACKUP_LABEL_FILE, false},
{TABLESPACE_MAP, false},
diff --git a/src/bin/pg_basebackup/t/010_pg_basebackup.pl b/src/bin/pg_basebackup/t/010_pg_basebackup.pl
index 89f45b77a3..f21d53086d 100644
--- a/src/bin/pg_basebackup/t/010_pg_basebackup.pl
+++ b/src/bin/pg_basebackup/t/010_pg_basebackup.pl
@@ -163,6 +163,10 @@ isnt(slurp_file("$tempdir/backup/backup_label"),
'DONOTCOPY', 'existing backup_label not copied');
rmtree("$tempdir/backup");
+# Now delete the bogus backup_label file since it will interfere with startup
+unlink("$pgdata/backup_label")
+ or BAIL_OUT("unable to unlink $pgdata/backup_label");
+
$node->command_ok(
[
'pg_basebackup', '-D',
diff --git a/src/bin/pg_rewind/filemap.c b/src/bin/pg_rewind/filemap.c
index 2618b4c957..37b669a3cb 100644
--- a/src/bin/pg_rewind/filemap.c
+++ b/src/bin/pg_rewind/filemap.c
@@ -140,9 +140,9 @@ static const struct exclude_list_item excludeFiles[] =
{"pg_internal.init", true}, /* defined as RELCACHE_INIT_FILENAME */
/*
- * If there's a backup_label or tablespace_map file, it belongs to a
- * backup started by the user with pg_start_backup(). It is *not* correct
- * for this backup. Our backup_label is written later on separately.
+ * If there is a backup_label or tablespace_map file, it indicates that
+ * a recovery failed and this cluster probably can't be rewound, but
+ * exclude them anyway if they are found.
*/
{"backup_label", false}, /* defined as BACKUP_LABEL_FILE */
{"tablespace_map", false}, /* defined as TABLESPACE_MAP */
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index 898df2ee03..f9f34f9792 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -343,8 +343,7 @@ extern void assign_checkpoint_completion_target(double newval, void *extra);
typedef enum SessionBackupState
{
SESSION_BACKUP_NONE,
- SESSION_BACKUP_EXCLUSIVE,
- SESSION_BACKUP_NON_EXCLUSIVE
+ SESSION_BACKUP_RUNNING,
} SessionBackupState;
extern XLogRecPtr do_pg_start_backup(const char *backupidstr, bool fast,
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 79d787cd26..55b1f741f5 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -6282,25 +6282,15 @@
prosrc => 'pg_terminate_backend' },
{ oid => '2172', descr => 'prepare for taking an online backup',
proname => 'pg_start_backup', provolatile => 'v', proparallel => 'r',
- prorettype => 'pg_lsn', proargtypes => 'text bool bool',
+ prorettype => 'pg_lsn', proargtypes => 'text bool',
prosrc => 'pg_start_backup' },
-{ oid => '2173', descr => 'finish taking an online backup',
- proname => 'pg_stop_backup', provolatile => 'v', proparallel => 'r',
- prorettype => 'pg_lsn', proargtypes => '', prosrc => 'pg_stop_backup' },
{ oid => '2739', descr => 'finish taking an online backup',
proname => 'pg_stop_backup', prorows => '1', proretset => 't',
provolatile => 'v', proparallel => 'r', prorettype => 'record',
- proargtypes => 'bool bool', proallargtypes => '{bool,bool,pg_lsn,text,text}',
- proargmodes => '{i,i,o,o,o}',
- proargnames => '{exclusive,wait_for_archive,lsn,labelfile,spcmapfile}',
- prosrc => 'pg_stop_backup_v2' },
-{ oid => '3813', descr => 'true if server is in online backup',
- proname => 'pg_is_in_backup', provolatile => 'v', prorettype => 'bool',
- proargtypes => '', prosrc => 'pg_is_in_backup' },
-{ oid => '3814', descr => 'start time of an online backup',
- proname => 'pg_backup_start_time', provolatile => 's',
- prorettype => 'timestamptz', proargtypes => '',
- prosrc => 'pg_backup_start_time' },
+ proargtypes => 'bool', proallargtypes => '{bool,pg_lsn,text,text}',
+ proargmodes => '{i,o,o,o}',
+ proargnames => '{wait_for_archive,lsn,labelfile,spcmapfile}',
+ prosrc => 'pg_stop_backup' },
{ oid => '3436', descr => 'promote standby server',
proname => 'pg_promote', provolatile => 'v', prorettype => 'bool',
proargtypes => 'bool int4', proargnames => '{wait,wait_seconds}',
diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h
index 90a3016065..2c6454a51e 100644
--- a/src/include/miscadmin.h
+++ b/src/include/miscadmin.h
@@ -480,10 +480,6 @@ extern void process_session_preload_libraries(void);
extern void pg_bindtextdomain(const char *domain);
extern bool has_rolreplication(Oid roleid);
-/* in access/transam/xlog.c */
-extern bool BackupInProgress(void);
-extern void CancelBackup(void);
-
/* in executor/nodeHash.c */
extern size_t get_hash_memory_limit(void);
diff --git a/src/test/perl/PostgreSQL/Test/Cluster.pm b/src/test/perl/PostgreSQL/Test/Cluster.pm
index 9467a199c8..55dc60ba2b 100644
--- a/src/test/perl/PostgreSQL/Test/Cluster.pm
+++ b/src/test/perl/PostgreSQL/Test/Cluster.pm
@@ -598,25 +598,6 @@ sub backup
return;
}
-=item $node->backup_fs_hot(backup_name)
-
-Create a backup with a filesystem level copy in subdirectory B<backup_name> of
-B<< $node->backup_dir >>, including WAL.
-
-Archiving must be enabled, as B<pg_start_backup()> and B<pg_stop_backup()> are
-used. This is not checked or enforced.
-
-The backup name is passed as the backup label to B<pg_start_backup()>.
-
-=cut
-
-sub backup_fs_hot
-{
- my ($self, $backup_name) = @_;
- $self->_backup_fs($backup_name, 1);
- return;
-}
-
=item $node->backup_fs_cold(backup_name)
Create a backup with a filesystem level copy in subdirectory B<backup_name> of
@@ -630,53 +611,18 @@ Use B<backup> or B<backup_fs_hot> if you want to back up a running server.
sub backup_fs_cold
{
my ($self, $backup_name) = @_;
- $self->_backup_fs($backup_name, 0);
- return;
-}
-
-
-# Common sub of backup_fs_hot and backup_fs_cold
-sub _backup_fs
-{
- my ($self, $backup_name, $hot) = @_;
- my $backup_path = $self->backup_dir . '/' . $backup_name;
- my $port = $self->port;
- my $name = $self->name;
-
- print "# Taking filesystem backup $backup_name from node \"$name\"\n";
-
- if ($hot)
- {
- my $stdout = $self->safe_psql('postgres',
- "SELECT * FROM pg_start_backup('$backup_name');");
- print "# pg_start_backup: $stdout\n";
- }
PostgreSQL::Test::RecursiveCopy::copypath(
$self->data_dir,
- $backup_path,
+ $self->backup_dir . '/' . $backup_name,
filterfn => sub {
my $src = shift;
return ($src ne 'log' and $src ne 'postmaster.pid');
});
- if ($hot)
- {
-
- # We ignore pg_stop_backup's return value. We also assume archiving
- # is enabled; otherwise the caller will have to copy the remaining
- # segments.
- my $stdout =
- $self->safe_psql('postgres', 'SELECT * FROM pg_stop_backup();');
- print "# pg_stop_backup: $stdout\n";
- }
-
- print "# Backup finished\n";
return;
}
-
-
=pod
=item $node->init_from_backup(root_node, backup_name)
diff --git a/src/test/recovery/t/010_logical_decoding_timelines.pl b/src/test/recovery/t/010_logical_decoding_timelines.pl
index 68d94ac91c..2e7b72593f 100644
--- a/src/test/recovery/t/010_logical_decoding_timelines.pl
+++ b/src/test/recovery/t/010_logical_decoding_timelines.pl
@@ -69,7 +69,9 @@ $node_primary->safe_psql('dropme',
$node_primary->safe_psql('postgres', 'CHECKPOINT;');
my $backup_name = 'b1';
-$node_primary->backup_fs_hot($backup_name);
+$node_primary->stop();
+$node_primary->backup_fs_cold($backup_name);
+$node_primary->start();
$node_primary->safe_psql('postgres',
q[SELECT pg_create_physical_replication_slot('phys_slot');]);
--
2.16.6
On 12/1/21 19:30, Bossart, Nathan wrote:
On 12/1/21, 10:37 AM, "Bossart, Nathan" <bossartn@amazon.com> wrote:
On 12/1/21, 8:27 AM, "David Steele" <david@pgmasters.net> wrote:
On 11/30/21 18:31, Bossart, Nathan wrote:
Do you think it's still worth trying to make it safe, or do you think
we should just remove exclusive mode completely?My preference would be to remove it completely, but I haven't gotten a
lot of traction so far.In this thread, I count 6 people who seem alright with removing it,
and 2 who might be opposed, although I don't think anyone has
explicitly stated they are against it.I hastily rebased the patch from 2018 and got it building and passing
the tests. I'm sure it will need additional changes, but I'll wait
for more feedback before I expend too much more effort on this.
Should we really be getting rid of
PostgreSQL::Test::Cluster::backup_fs_hot() ?
cheers
andrew
--
Andrew Dunstan
EDB: https://www.enterprisedb.com
On 12/2/21 11:00, Andrew Dunstan wrote:
On 12/1/21 19:30, Bossart, Nathan wrote:
On 12/1/21, 10:37 AM, "Bossart, Nathan" <bossartn@amazon.com> wrote:
On 12/1/21, 8:27 AM, "David Steele" <david@pgmasters.net> wrote:
On 11/30/21 18:31, Bossart, Nathan wrote:
Do you think it's still worth trying to make it safe, or do you think
we should just remove exclusive mode completely?My preference would be to remove it completely, but I haven't gotten a
lot of traction so far.In this thread, I count 6 people who seem alright with removing it,
and 2 who might be opposed, although I don't think anyone has
explicitly stated they are against it.I hastily rebased the patch from 2018 and got it building and passing
the tests. I'm sure it will need additional changes, but I'll wait
for more feedback before I expend too much more effort on this.Should we really be getting rid of
PostgreSQL::Test::Cluster::backup_fs_hot() ?
Agreed, it would be better to update backup_fs_hot() to use exclusive
mode and save out backup_label instead.
Regards,
-David
On 12/2/21 12:38, David Steele wrote:
On 12/2/21 11:00, Andrew Dunstan wrote:
Should we really be getting rid of
PostgreSQL::Test::Cluster::backup_fs_hot() ?Agreed, it would be better to update backup_fs_hot() to use exclusive
mode and save out backup_label instead.
Oops, of course I meant non-exclusive mode.
Regards,
-David
On 12/2/21, 9:50 AM, "David Steele" <david@pgmasters.net> wrote:
On 12/2/21 12:38, David Steele wrote:
On 12/2/21 11:00, Andrew Dunstan wrote:
Should we really be getting rid of
PostgreSQL::Test::Cluster::backup_fs_hot() ?Agreed, it would be better to update backup_fs_hot() to use exclusive
mode and save out backup_label instead.Oops, of course I meant non-exclusive mode.
+1. I'll fix that in the next revision.
Nathan
On 12/2/21, 1:34 PM, "Bossart, Nathan" <bossartn@amazon.com> wrote:
On 12/2/21, 9:50 AM, "David Steele" <david@pgmasters.net> wrote:
On 12/2/21 12:38, David Steele wrote:
On 12/2/21 11:00, Andrew Dunstan wrote:
Should we really be getting rid of
PostgreSQL::Test::Cluster::backup_fs_hot() ?Agreed, it would be better to update backup_fs_hot() to use exclusive
mode and save out backup_label instead.Oops, of course I meant non-exclusive mode.
+1. I'll fix that in the next revision.
I finally got around to looking into this, and I think I found why it
was done this way in 2018. backup_fs_hot() runs pg_start_backup(),
closes the session, copies the data, and then runs pg_stop_backup() in
a different session. This doesn't work with non-exclusive mode
because the backup will be aborted when the session that runs
pg_start_backup() is closed. pg_stop_backup() will fail with a
"backup is not in progress" error. Furthermore,
010_logical_decoding_timelines.pl seems to be the only test that uses
backup_fs_hot().
After a quick glance, I didn't see an easy way to hold a session open
while the test does other things. If there isn't one, modifying
backup_fs_hot() to work with non-exclusive mode might be more trouble
than it is worth.
Nathan
On Thu, Jan 6, 2022, at 9:48 PM, Bossart, Nathan wrote:
After a quick glance, I didn't see an easy way to hold a session open
while the test does other things. If there isn't one, modifying
backup_fs_hot() to work with non-exclusive mode might be more trouble
than it is worth.
You can use IPC::Run to start psql in background. See examples in
src/test/recovery.
--
Euler Taveira
EDB https://www.enterprisedb.com/
On 1/6/22 20:20, Euler Taveira wrote:
On Thu, Jan 6, 2022, at 9:48 PM, Bossart, Nathan wrote:
After a quick glance, I didn't see an easy way to hold a session open
while the test does other things. If there isn't one, modifying
backup_fs_hot() to work with non-exclusive mode might be more trouble
than it is worth.You can use IPC::Run to start psql in background. See examples in
src/test/recovery.
I don't think updating backup_fs_hot() is worth it here.
backup_fs_cold() works just fine for this case and if there is a need
for backup_fs_hot() in the future it can be implemented as needed.
Regards,
-David
On 1/7/22, 5:52 AM, "David Steele" <david@pgmasters.net> wrote:
On 1/6/22 20:20, Euler Taveira wrote:
On Thu, Jan 6, 2022, at 9:48 PM, Bossart, Nathan wrote:
After a quick glance, I didn't see an easy way to hold a session open
while the test does other things. If there isn't one, modifying
backup_fs_hot() to work with non-exclusive mode might be more trouble
than it is worth.You can use IPC::Run to start psql in background. See examples in
src/test/recovery.I don't think updating backup_fs_hot() is worth it here.
backup_fs_cold() works just fine for this case and if there is a need
for backup_fs_hot() in the future it can be implemented as needed.
Thanks for the pointer on IPC::Run. I had a feeling I was missing
something obvious!
I think I agree with David that it still isn't worth it for just this
one test. Of course, it would be great to test the non-exclusive
backup logic as much as possible, but I'm not sure that this
particular test will provide any sort of meaningful coverage.
Nathan
Here is a rebased patch.
--
Nathan Bossart
Amazon Web Services: https://aws.amazon.com
Attachments:
v2-0001-remove-exclusive-backup-mode.patchtext/x-diff; charset=us-asciiDownload
From 8fc744a0b22a1fff9f3470bfdc0e08d9dd5da5be Mon Sep 17 00:00:00 2001
From: Nathan Bossart <bossartn@amazon.com>
Date: Wed, 1 Dec 2021 23:50:49 +0000
Subject: [PATCH v2 1/1] remove exclusive backup mode
---
doc/src/sgml/backup.sgml | 154 +-----
doc/src/sgml/func.sgml | 30 +-
src/backend/access/transam/xlog.c | 466 ++----------------
src/backend/access/transam/xlogfuncs.c | 235 ++-------
src/backend/catalog/system_functions.sql | 14 +-
src/backend/postmaster/postmaster.c | 46 +-
src/backend/replication/basebackup.c | 6 +-
src/bin/pg_basebackup/t/010_pg_basebackup.pl | 4 +
src/bin/pg_rewind/filemap.c | 6 +-
src/include/access/xlog.h | 3 +-
src/include/catalog/pg_proc.dat | 20 +-
src/include/miscadmin.h | 4 -
src/test/perl/PostgreSQL/Test/Cluster.pm | 56 +--
.../t/010_logical_decoding_timelines.pl | 4 +-
14 files changed, 113 insertions(+), 935 deletions(-)
diff --git a/doc/src/sgml/backup.sgml b/doc/src/sgml/backup.sgml
index 0d69851bb1..f241bcab9c 100644
--- a/doc/src/sgml/backup.sgml
+++ b/doc/src/sgml/backup.sgml
@@ -857,16 +857,8 @@ test ! -f /mnt/server/archivedir/00000001000000A900000065 && cp pg_wal/0
sequence, and that the success of a step is verified before
proceeding to the next step.
</para>
- <para>
- Low level base backups can be made in a non-exclusive or an exclusive
- way. The non-exclusive method is recommended and the exclusive one is
- deprecated and will eventually be removed.
- </para>
-
- <sect3 id="backup-lowlevel-base-backup-nonexclusive">
- <title>Making a Non-Exclusive Low-Level Backup</title>
<para>
- A non-exclusive low level backup is one that allows other
+ A low level backup allows other
concurrent backups to be running (both those started using
the same backup API and those started using
<xref linkend="app-pgbasebackup"/>).
@@ -884,7 +876,7 @@ test ! -f /mnt/server/archivedir/00000001000000A900000065 && cp pg_wal/0
rights to run pg_start_backup (superuser, or a user who has been granted
EXECUTE on the function) and issue the command:
<programlisting>
-SELECT pg_start_backup('label', false, false);
+SELECT pg_start_backup('label', false);
</programlisting>
where <literal>label</literal> is any string you want to use to uniquely
identify this backup operation. The connection
@@ -905,10 +897,6 @@ SELECT pg_start_backup('label', false, false);
issue an immediate checkpoint using as much I/O as available.
</para>
- <para>
- The third parameter being <literal>false</literal> tells
- <function>pg_start_backup</function> to initiate a non-exclusive base backup.
- </para>
</listitem>
<listitem>
<para>
@@ -926,7 +914,7 @@ SELECT pg_start_backup('label', false, false);
<para>
In the same connection as before, issue the command:
<programlisting>
-SELECT * FROM pg_stop_backup(false, true);
+SELECT * FROM pg_stop_backup(true);
</programlisting>
This terminates backup mode. On a primary, it also performs an automatic
switch to the next WAL segment. On a standby, it is not possible to
@@ -985,142 +973,6 @@ SELECT * FROM pg_stop_backup(false, true);
</listitem>
</orderedlist>
</para>
- </sect3>
- <sect3 id="backup-lowlevel-base-backup-exclusive">
- <title>Making an Exclusive Low-Level Backup</title>
-
- <note>
- <para>
- The exclusive backup method is deprecated and should be avoided.
- Prior to <productname>PostgreSQL</productname> 9.6, this was the only
- low-level method available, but it is now recommended that all users
- upgrade their scripts to use non-exclusive backups.
- </para>
- </note>
-
- <para>
- The process for an exclusive backup is mostly the same as for a
- non-exclusive one, but it differs in a few key steps. This type of
- backup can only be taken on a primary and does not allow concurrent
- backups. Moreover, because it creates a backup label file, as
- described below, it can block automatic restart of the primary server
- after a crash. On the other hand, the erroneous removal of this
- file from a backup or standby is a common mistake, which can result
- in serious data corruption. If it is necessary to use this method,
- the following steps may be used.
- </para>
- <para>
- <orderedlist>
- <listitem>
- <para>
- Ensure that WAL archiving is enabled and working.
- </para>
- </listitem>
- <listitem>
- <para>
- Connect to the server (it does not matter which database) as a user with
- rights to run pg_start_backup (superuser, or a user who has been granted
- EXECUTE on the function) and issue the command:
-<programlisting>
-SELECT pg_start_backup('label');
-</programlisting>
- where <literal>label</literal> is any string you want to use to uniquely
- identify this backup operation.
- <function>pg_start_backup</function> creates a <firstterm>backup label</firstterm> file,
- called <filename>backup_label</filename>, in the cluster directory with
- information about your backup, including the start time and label string.
- The function also creates a <firstterm>tablespace map</firstterm> file,
- called <filename>tablespace_map</filename>, in the cluster directory with
- information about tablespace symbolic links in <filename>pg_tblspc/</filename> if
- one or more such link is present. Both files are critical to the
- integrity of the backup, should you need to restore from it.
- </para>
-
- <para>
- By default, <function>pg_start_backup</function> can take a long time to finish.
- This is because it performs a checkpoint, and the I/O
- required for the checkpoint will be spread out over a significant
- period of time, by default half your inter-checkpoint interval
- (see the configuration parameter
- <xref linkend="guc-checkpoint-completion-target"/>). This is
- usually what you want, because it minimizes the impact on query
- processing. If you want to start the backup as soon as
- possible, use:
-<programlisting>
-SELECT pg_start_backup('label', true);
-</programlisting>
- This forces the checkpoint to be done as quickly as possible.
- </para>
- </listitem>
- <listitem>
- <para>
- Perform the backup, using any convenient file-system-backup tool
- such as <application>tar</application> or <application>cpio</application> (not
- <application>pg_dump</application> or
- <application>pg_dumpall</application>). It is neither
- necessary nor desirable to stop normal operation of the database
- while you do this. See
- <xref linkend="backup-lowlevel-base-backup-data"/> for things to
- consider during this backup.
- </para>
- <para>
- As noted above, if the server crashes during the backup it may not be
- possible to restart until the <filename>backup_label</filename> file has
- been manually deleted from the <envar>PGDATA</envar> directory. Note
- that it is very important to never remove the
- <filename>backup_label</filename> file when restoring a backup, because
- this will result in corruption. Confusion about when it is appropriate
- to remove this file is a common cause of data corruption when using this
- method; be very certain that you remove the file only on an existing
- primary and never when building a standby or restoring a backup, even if
- you are building a standby that will subsequently be promoted to a new
- primary.
- </para>
- </listitem>
- <listitem>
- <para>
- Again connect to the database as a user with rights to run
- pg_stop_backup (superuser, or a user who has been granted EXECUTE on
- the function), and issue the command:
-<programlisting>
-SELECT pg_stop_backup();
-</programlisting>
- This function terminates backup mode and
- performs an automatic switch to the next WAL segment. The reason for the
- switch is to arrange for the last WAL segment written during the backup
- interval to be ready to archive.
- </para>
- </listitem>
- <listitem>
- <para>
- Once the WAL segment files active during the backup are archived, you are
- done. The file identified by <function>pg_stop_backup</function>'s result is
- the last segment that is required to form a complete set of backup files.
- If <varname>archive_mode</varname> is enabled,
- <function>pg_stop_backup</function> does not return until the last segment has
- been archived.
- Archiving of these files happens automatically since you have
- already configured <varname>archive_command</varname>. In most cases this
- happens quickly, but you are advised to monitor your archive
- system to ensure there are no delays.
- If the archive process has fallen behind
- because of failures of the archive command, it will keep retrying
- until the archive succeeds and the backup is complete.
- </para>
-
- <para>
- When using exclusive backup mode, it is absolutely imperative to ensure
- that <function>pg_stop_backup</function> completes successfully at the
- end of the backup. Even if the backup itself fails, for example due to
- lack of disk space, failure to call <function>pg_stop_backup</function>
- will leave the server in backup mode indefinitely, causing future backups
- to fail and increasing the risk of a restart failure during the time that
- <filename>backup_label</filename> exists.
- </para>
- </listitem>
- </orderedlist>
- </para>
- </sect3>
<sect3 id="backup-lowlevel-base-backup-data">
<title>Backing Up the Data Directory</title>
<para>
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index df3cd5987b..3d4c8bf851 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -25683,8 +25683,7 @@ LOG: Grand total: 1651920 bytes in 201 blocks; 622360 free (88 chunks); 1029560
<function>pg_start_backup</function> (
<parameter>label</parameter> <type>text</type>
<optional>, <parameter>fast</parameter> <type>boolean</type>
- <optional>, <parameter>exclusive</parameter> <type>boolean</type>
- </optional></optional> )
+ </optional> )
<returnvalue>pg_lsn</returnvalue>
</para>
<para>
@@ -25696,20 +25695,6 @@ LOG: Grand total: 1651920 bytes in 201 blocks; 622360 free (88 chunks); 1029560
it specifies executing <function>pg_start_backup</function> as quickly
as possible. This forces an immediate checkpoint which will cause a
spike in I/O operations, slowing any concurrently executing queries.
- The optional third parameter specifies whether to perform an exclusive
- or non-exclusive backup (default is exclusive).
- </para>
- <para>
- When used in exclusive mode, this function writes a backup label file
- (<filename>backup_label</filename>) and, if there are any links in
- the <filename>pg_tblspc/</filename> directory, a tablespace map file
- (<filename>tablespace_map</filename>) into the database cluster's data
- directory, then performs a checkpoint, and then returns the backup's
- starting write-ahead log location. (The user can ignore this
- result value, but it is provided in case it is useful.) When used in
- non-exclusive mode, the contents of these files are instead returned
- by the <function>pg_stop_backup</function> function, and should be
- copied to the backup area by the user.
</para>
<para>
This function is restricted to superusers by default, but other users
@@ -25723,7 +25708,6 @@ LOG: Grand total: 1651920 bytes in 201 blocks; 622360 free (88 chunks); 1029560
<primary>pg_stop_backup</primary>
</indexterm>
<function>pg_stop_backup</function> (
- <parameter>exclusive</parameter> <type>boolean</type>
<optional>, <parameter>wait_for_archive</parameter> <type>boolean</type>
</optional> )
<returnvalue>setof record</returnvalue>
@@ -25732,13 +25716,8 @@ LOG: Grand total: 1651920 bytes in 201 blocks; 622360 free (88 chunks); 1029560
<parameter>spcmapfile</parameter> <type>text</type> )
</para>
<para>
- Finishes performing an exclusive or non-exclusive on-line backup.
- The <parameter>exclusive</parameter> parameter must match the
- previous <function>pg_start_backup</function> call.
- In an exclusive backup, <function>pg_stop_backup</function> removes
- the backup label file and, if it exists, the tablespace map file
- created by <function>pg_start_backup</function>. In a non-exclusive
- backup, the desired contents of these files are returned as part of
+ Finishes performing an on-line backup. The desired contents of the
+ backup label file and the tablespace map file are returned as part of
the result of the function, and should be written to files in the
backup area (not in the data directory).
</para>
@@ -25771,8 +25750,7 @@ LOG: Grand total: 1651920 bytes in 201 blocks; 622360 free (88 chunks); 1029560
The result of the function is a single record.
The <parameter>lsn</parameter> column holds the backup's ending
write-ahead log location (which again can be ignored). The second and
- third columns are <literal>NULL</literal> when ending an exclusive
- backup; after a non-exclusive backup they hold the desired contents of
+ third columns hold the desired contents of
the label and tablespace map files.
</para>
<para>
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index ce78ac413e..e12e86dc2d 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -384,29 +384,6 @@ typedef union WALInsertLockPadded
char pad[PG_CACHE_LINE_SIZE];
} WALInsertLockPadded;
-/*
- * State of an exclusive backup, necessary to control concurrent activities
- * across sessions when working on exclusive backups.
- *
- * EXCLUSIVE_BACKUP_NONE means that there is no exclusive backup actually
- * running, to be more precise pg_start_backup() is not being executed for
- * an exclusive backup and there is no exclusive backup in progress.
- * EXCLUSIVE_BACKUP_STARTING means that pg_start_backup() is starting an
- * exclusive backup.
- * EXCLUSIVE_BACKUP_IN_PROGRESS means that pg_start_backup() has finished
- * running and an exclusive backup is in progress. pg_stop_backup() is
- * needed to finish it.
- * EXCLUSIVE_BACKUP_STOPPING means that pg_stop_backup() is stopping an
- * exclusive backup.
- */
-typedef enum ExclusiveBackupState
-{
- EXCLUSIVE_BACKUP_NONE = 0,
- EXCLUSIVE_BACKUP_STARTING,
- EXCLUSIVE_BACKUP_IN_PROGRESS,
- EXCLUSIVE_BACKUP_STOPPING
-} ExclusiveBackupState;
-
/*
* Session status of running backup, used for sanity checks in SQL-callable
* functions to start and stop backups.
@@ -455,15 +432,12 @@ typedef struct XLogCtlInsert
bool fullPageWrites;
/*
- * exclusiveBackupState indicates the state of an exclusive backup (see
- * comments of ExclusiveBackupState for more details). nonExclusiveBackups
- * is a counter indicating the number of streaming base backups currently
- * in progress. forcePageWrites is set to true when either of these is
- * non-zero. lastBackupStart is the latest checkpoint redo location used
- * as a starting point for an online backup.
+ * runningBackups is a counter indicating the number of backups currently in
+ * progress. forcePageWrites is set to true when either of these is
+ * non-zero. lastBackupStart is the latest checkpoint redo location used as
+ * a starting point for an online backup.
*/
- ExclusiveBackupState exclusiveBackupState;
- int nonExclusiveBackups;
+ int runningBackups;
XLogRecPtr lastBackupStart;
/*
@@ -696,7 +670,6 @@ static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow);
static void pg_start_backup_callback(int code, Datum arg);
-static void pg_stop_backup_callback(int code, Datum arg);
static int get_sync_bit(int method);
@@ -7006,7 +6979,7 @@ CreateRestartPoint(int flags)
* Ensure minRecoveryPoint is past the checkpoint record. Normally,
* this will have happened already while writing out dirty buffers,
* but not necessarily - e.g. because no buffers were dirtied. We do
- * this because a non-exclusive base backup uses minRecoveryPoint to
+ * this because a backup performed in recovery uses minRecoveryPoint to
* determine which WAL files must be included in the backup, and the
* file (or files) containing the checkpoint record must be included,
* at a minimum. Note that for an ordinary restart of recovery there's
@@ -8009,32 +7982,14 @@ issue_xlog_fsync(int fd, XLogSegNo segno, TimeLineID tli)
}
/*
- * do_pg_start_backup
- *
- * Utility function called at the start of an online backup. It creates the
- * necessary starting checkpoint and constructs the backup label file.
- *
- * There are two kind of backups: exclusive and non-exclusive. An exclusive
- * backup is started with pg_start_backup(), and there can be only one active
- * at a time. The backup and tablespace map files of an exclusive backup are
- * written to $PGDATA/backup_label and $PGDATA/tablespace_map, and they are
- * removed by pg_stop_backup().
+ * do_pg_start_backup is the workhorse of the user-visible pg_start_backup()
+ * function. It creates the necessary starting checkpoint and constructs the
+ * backup label and tablespace map.
*
- * A non-exclusive backup is used for the streaming base backups (see
- * src/backend/replication/basebackup.c). The difference to exclusive backups
- * is that the backup label and tablespace map files are not written to disk.
- * Instead, their would-be contents are returned in *labelfile and *tblspcmapfile,
- * and the caller is responsible for including them in the backup archive as
- * 'backup_label' and 'tablespace_map'. There can be many non-exclusive backups
- * active at the same time, and they don't conflict with an exclusive backup
- * either.
- *
- * labelfile and tblspcmapfile must be passed as NULL when starting an
- * exclusive backup, and as initially-empty StringInfos for a non-exclusive
- * backup.
- *
- * If "tablespaces" isn't NULL, it receives a list of tablespaceinfo structs
- * describing the cluster's tablespaces.
+ * The backup label and tablespace map contents are returned in *labelfile and
+ * *tblspcmapfile, and the caller is responsible for including them in the
+ * backup archive as 'backup_label' and 'tablespace_map'. There can be many
+ * backups active at the same time.
*
* tblspcmapfile is required mainly for tar format in windows as native windows
* utilities are not able to create symlinks while extracting files from tar.
@@ -8043,7 +7998,7 @@ issue_xlog_fsync(int fd, XLogSegNo segno, TimeLineID tli)
* Returns the minimum WAL location that must be present to restore from this
* backup, and the corresponding timeline ID in *starttli_p.
*
- * Every successfully started non-exclusive backup must be stopped by calling
+ * Every successfully started backup must be stopped by calling
* do_pg_stop_backup() or do_pg_abort_backup().
*
* It is the responsibility of the caller of this function to verify the
@@ -8054,7 +8009,6 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
StringInfo labelfile, List **tablespaces,
StringInfo tblspcmapfile)
{
- bool exclusive = (labelfile == NULL);
bool backup_started_in_recovery = false;
XLogRecPtr checkpointloc;
XLogRecPtr startpoint;
@@ -8063,20 +8017,9 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
char strfbuf[128];
char xlogfilename[MAXFNAMELEN];
XLogSegNo _logSegNo;
- struct stat stat_buf;
- FILE *fp;
backup_started_in_recovery = RecoveryInProgress();
- /*
- * Currently only non-exclusive backup can be taken during recovery.
- */
- if (backup_started_in_recovery && exclusive)
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("recovery is in progress"),
- errhint("WAL control functions cannot be executed during recovery.")));
-
/*
* During recovery, we don't need to check WAL level. Because, if WAL
* level is not sufficient, it's impossible to get here during recovery.
@@ -8115,30 +8058,12 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
* XLogInsertRecord().
*/
WALInsertLockAcquireExclusive();
- if (exclusive)
- {
- /*
- * At first, mark that we're now starting an exclusive backup, to
- * ensure that there are no other sessions currently running
- * pg_start_backup() or pg_stop_backup().
- */
- if (XLogCtl->Insert.exclusiveBackupState != EXCLUSIVE_BACKUP_NONE)
- {
- WALInsertLockRelease();
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("a backup is already in progress"),
- errhint("Run pg_stop_backup() and try again.")));
- }
- XLogCtl->Insert.exclusiveBackupState = EXCLUSIVE_BACKUP_STARTING;
- }
- else
- XLogCtl->Insert.nonExclusiveBackups++;
+ XLogCtl->Insert.runningBackups++;
XLogCtl->Insert.forcePageWrites = true;
WALInsertLockRelease();
/* Ensure we release forcePageWrites if fail below */
- PG_ENSURE_ERROR_CLEANUP(pg_start_backup_callback, (Datum) BoolGetDatum(exclusive));
+ PG_ENSURE_ERROR_CLEANUP(pg_start_backup_callback, (Datum) 0);
{
bool gotUniqueStartpoint = false;
DIR *tblspcdir;
@@ -8373,122 +8298,19 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
LSN_FORMAT_ARGS(startpoint), xlogfilename);
appendStringInfo(labelfile, "CHECKPOINT LOCATION: %X/%X\n",
LSN_FORMAT_ARGS(checkpointloc));
- appendStringInfo(labelfile, "BACKUP METHOD: %s\n",
- exclusive ? "pg_start_backup" : "streamed");
+ appendStringInfo(labelfile, "BACKUP METHOD: streamed\n");
appendStringInfo(labelfile, "BACKUP FROM: %s\n",
backup_started_in_recovery ? "standby" : "primary");
appendStringInfo(labelfile, "START TIME: %s\n", strfbuf);
appendStringInfo(labelfile, "LABEL: %s\n", backupidstr);
appendStringInfo(labelfile, "START TIMELINE: %u\n", starttli);
-
- /*
- * Okay, write the file, or return its contents to caller.
- */
- if (exclusive)
- {
- /*
- * Check for existing backup label --- implies a backup is already
- * running. (XXX given that we checked exclusiveBackupState
- * above, maybe it would be OK to just unlink any such label
- * file?)
- */
- if (stat(BACKUP_LABEL_FILE, &stat_buf) != 0)
- {
- if (errno != ENOENT)
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not stat file \"%s\": %m",
- BACKUP_LABEL_FILE)));
- }
- else
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("a backup is already in progress"),
- errhint("If you're sure there is no backup in progress, remove file \"%s\" and try again.",
- BACKUP_LABEL_FILE)));
-
- fp = AllocateFile(BACKUP_LABEL_FILE, "w");
-
- if (!fp)
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not create file \"%s\": %m",
- BACKUP_LABEL_FILE)));
- if (fwrite(labelfile->data, labelfile->len, 1, fp) != 1 ||
- fflush(fp) != 0 ||
- pg_fsync(fileno(fp)) != 0 ||
- ferror(fp) ||
- FreeFile(fp))
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not write file \"%s\": %m",
- BACKUP_LABEL_FILE)));
- /* Allocated locally for exclusive backups, so free separately */
- pfree(labelfile->data);
- pfree(labelfile);
-
- /* Write backup tablespace_map file. */
- if (tblspcmapfile->len > 0)
- {
- if (stat(TABLESPACE_MAP, &stat_buf) != 0)
- {
- if (errno != ENOENT)
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not stat file \"%s\": %m",
- TABLESPACE_MAP)));
- }
- else
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("a backup is already in progress"),
- errhint("If you're sure there is no backup in progress, remove file \"%s\" and try again.",
- TABLESPACE_MAP)));
-
- fp = AllocateFile(TABLESPACE_MAP, "w");
-
- if (!fp)
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not create file \"%s\": %m",
- TABLESPACE_MAP)));
- if (fwrite(tblspcmapfile->data, tblspcmapfile->len, 1, fp) != 1 ||
- fflush(fp) != 0 ||
- pg_fsync(fileno(fp)) != 0 ||
- ferror(fp) ||
- FreeFile(fp))
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not write file \"%s\": %m",
- TABLESPACE_MAP)));
- }
-
- /* Allocated locally for exclusive backups, so free separately */
- pfree(tblspcmapfile->data);
- pfree(tblspcmapfile);
- }
}
- PG_END_ENSURE_ERROR_CLEANUP(pg_start_backup_callback, (Datum) BoolGetDatum(exclusive));
+ PG_END_ENSURE_ERROR_CLEANUP(pg_start_backup_callback, (Datum) 0);
/*
- * Mark that start phase has correctly finished for an exclusive backup.
- * Session-level locks are updated as well to reflect that state.
- *
- * Note that CHECK_FOR_INTERRUPTS() must not occur while updating backup
- * counters and session-level lock. Otherwise they can be updated
- * inconsistently, and which might cause do_pg_abort_backup() to fail.
+ * Mark that the start phase has correctly finished for the backup.
*/
- if (exclusive)
- {
- WALInsertLockAcquireExclusive();
- XLogCtl->Insert.exclusiveBackupState = EXCLUSIVE_BACKUP_IN_PROGRESS;
-
- /* Set session-level lock */
- sessionBackupState = SESSION_BACKUP_EXCLUSIVE;
- WALInsertLockRelease();
- }
- else
- sessionBackupState = SESSION_BACKUP_NON_EXCLUSIVE;
+ sessionBackupState = SESSION_BACKUP_RUNNING;
/*
* We're done. As a convenience, return the starting WAL location.
@@ -8502,43 +8324,15 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
static void
pg_start_backup_callback(int code, Datum arg)
{
- bool exclusive = DatumGetBool(arg);
-
/* Update backup counters and forcePageWrites on failure */
WALInsertLockAcquireExclusive();
- if (exclusive)
- {
- Assert(XLogCtl->Insert.exclusiveBackupState == EXCLUSIVE_BACKUP_STARTING);
- XLogCtl->Insert.exclusiveBackupState = EXCLUSIVE_BACKUP_NONE;
- }
- else
- {
- Assert(XLogCtl->Insert.nonExclusiveBackups > 0);
- XLogCtl->Insert.nonExclusiveBackups--;
- }
- if (XLogCtl->Insert.exclusiveBackupState == EXCLUSIVE_BACKUP_NONE &&
- XLogCtl->Insert.nonExclusiveBackups == 0)
- {
- XLogCtl->Insert.forcePageWrites = false;
- }
- WALInsertLockRelease();
-}
-
-/*
- * Error cleanup callback for pg_stop_backup
- */
-static void
-pg_stop_backup_callback(int code, Datum arg)
-{
- bool exclusive = DatumGetBool(arg);
+ Assert(XLogCtl->Insert.runningBackups > 0);
+ XLogCtl->Insert.runningBackups--;
- /* Update backup status on failure */
- WALInsertLockAcquireExclusive();
- if (exclusive)
+ if (XLogCtl->Insert.runningBackups == 0)
{
- Assert(XLogCtl->Insert.exclusiveBackupState == EXCLUSIVE_BACKUP_STOPPING);
- XLogCtl->Insert.exclusiveBackupState = EXCLUSIVE_BACKUP_IN_PROGRESS;
+ XLogCtl->Insert.forcePageWrites = false;
}
WALInsertLockRelease();
}
@@ -8558,9 +8352,6 @@ get_backup_status(void)
* Utility function called at the end of an online backup. It cleans up the
* backup state and can optionally wait for WAL segments to be archived.
*
- * If labelfile is NULL, this stops an exclusive backup. Otherwise this stops
- * the non-exclusive backup specified by 'labelfile'.
- *
* Returns the last WAL location that must be present to restore from this
* backup, and the corresponding timeline ID in *stoptli_p.
*
@@ -8570,7 +8361,6 @@ get_backup_status(void)
XLogRecPtr
do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
{
- bool exclusive = (labelfile == NULL);
bool backup_started_in_recovery = false;
XLogRecPtr startpoint;
XLogRecPtr stoppoint;
@@ -8584,7 +8374,6 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
char histfilename[MAXFNAMELEN];
char backupfrom[20];
XLogSegNo _logSegNo;
- FILE *lfp;
FILE *fp;
char ch;
int seconds_before_warning;
@@ -8597,15 +8386,6 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
backup_started_in_recovery = RecoveryInProgress();
- /*
- * Currently only non-exclusive backup can be taken during recovery.
- */
- if (backup_started_in_recovery && exclusive)
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("recovery is in progress"),
- errhint("WAL control functions cannot be executed during recovery.")));
-
/*
* During recovery, we don't need to check WAL level. Because, if WAL
* level is not sufficient, it's impossible to get here during recovery.
@@ -8616,106 +8396,23 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
errmsg("WAL level not sufficient for making an online backup"),
errhint("wal_level must be set to \"replica\" or \"logical\" at server start.")));
- if (exclusive)
- {
- /*
- * At first, mark that we're now stopping an exclusive backup, to
- * ensure that there are no other sessions currently running
- * pg_start_backup() or pg_stop_backup().
- */
- WALInsertLockAcquireExclusive();
- if (XLogCtl->Insert.exclusiveBackupState != EXCLUSIVE_BACKUP_IN_PROGRESS)
- {
- WALInsertLockRelease();
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("exclusive backup not in progress")));
- }
- XLogCtl->Insert.exclusiveBackupState = EXCLUSIVE_BACKUP_STOPPING;
- WALInsertLockRelease();
-
- /*
- * Remove backup_label. In case of failure, the state for an exclusive
- * backup is switched back to in-progress.
- */
- PG_ENSURE_ERROR_CLEANUP(pg_stop_backup_callback, (Datum) BoolGetDatum(exclusive));
- {
- /*
- * Read the existing label file into memory.
- */
- struct stat statbuf;
- int r;
-
- if (stat(BACKUP_LABEL_FILE, &statbuf))
- {
- /* should not happen per the upper checks */
- if (errno != ENOENT)
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not stat file \"%s\": %m",
- BACKUP_LABEL_FILE)));
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("a backup is not in progress")));
- }
-
- lfp = AllocateFile(BACKUP_LABEL_FILE, "r");
- if (!lfp)
- {
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not read file \"%s\": %m",
- BACKUP_LABEL_FILE)));
- }
- labelfile = palloc(statbuf.st_size + 1);
- r = fread(labelfile, statbuf.st_size, 1, lfp);
- labelfile[statbuf.st_size] = '\0';
-
- /*
- * Close and remove the backup label file
- */
- if (r != 1 || ferror(lfp) || FreeFile(lfp))
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not read file \"%s\": %m",
- BACKUP_LABEL_FILE)));
- durable_unlink(BACKUP_LABEL_FILE, ERROR);
-
- /*
- * Remove tablespace_map file if present, it is created only if
- * there are tablespaces.
- */
- durable_unlink(TABLESPACE_MAP, DEBUG1);
- }
- PG_END_ENSURE_ERROR_CLEANUP(pg_stop_backup_callback, (Datum) BoolGetDatum(exclusive));
- }
-
/*
- * OK to update backup counters, forcePageWrites and session-level lock.
+ * OK to update backup counters and forcePageWrites.
*
* Note that CHECK_FOR_INTERRUPTS() must not occur while updating them.
* Otherwise they can be updated inconsistently, and which might cause
* do_pg_abort_backup() to fail.
*/
WALInsertLockAcquireExclusive();
- if (exclusive)
- {
- XLogCtl->Insert.exclusiveBackupState = EXCLUSIVE_BACKUP_NONE;
- }
- else
- {
- /*
- * The user-visible pg_start/stop_backup() functions that operate on
- * exclusive backups can be called at any time, but for non-exclusive
- * backups, it is expected that each do_pg_start_backup() call is
- * matched by exactly one do_pg_stop_backup() call.
- */
- Assert(XLogCtl->Insert.nonExclusiveBackups > 0);
- XLogCtl->Insert.nonExclusiveBackups--;
- }
- if (XLogCtl->Insert.exclusiveBackupState == EXCLUSIVE_BACKUP_NONE &&
- XLogCtl->Insert.nonExclusiveBackups == 0)
+ /*
+ * It is expected that each do_pg_start_backup() call is matched by exactly
+ * one do_pg_stop_backup() call.
+ */
+ Assert(XLogCtl->Insert.runningBackups > 0);
+ XLogCtl->Insert.runningBackups--;
+
+ if (XLogCtl->Insert.runningBackups == 0)
{
XLogCtl->Insert.forcePageWrites = false;
}
@@ -8980,10 +8677,6 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
* The caller can pass 'arg' as 'true' or 'false' to control whether a warning
* is emitted.
*
- * NB: This is only for aborting a non-exclusive backup that doesn't write
- * backup_label. A backup started with pg_start_backup() needs to be finished
- * with pg_stop_backup().
- *
* NB: This gets used as a before_shmem_exit handler, hence the odd-looking
* signature.
*/
@@ -8993,18 +8686,16 @@ do_pg_abort_backup(int code, Datum arg)
bool emit_warning = DatumGetBool(arg);
/*
- * Quick exit if session is not keeping around a non-exclusive backup
- * already started.
+ * Quick exit if session does not have a running backup.
*/
- if (sessionBackupState != SESSION_BACKUP_NON_EXCLUSIVE)
+ if (sessionBackupState != SESSION_BACKUP_RUNNING)
return;
WALInsertLockAcquireExclusive();
- Assert(XLogCtl->Insert.nonExclusiveBackups > 0);
- XLogCtl->Insert.nonExclusiveBackups--;
+ Assert(XLogCtl->Insert.runningBackups > 0);
+ XLogCtl->Insert.runningBackups--;
- if (XLogCtl->Insert.exclusiveBackupState == EXCLUSIVE_BACKUP_NONE &&
- XLogCtl->Insert.nonExclusiveBackups == 0)
+ if (XLogCtl->Insert.runningBackups == 0)
{
XLogCtl->Insert.forcePageWrites = false;
}
@@ -9072,87 +8763,6 @@ GetOldestRestartPoint(XLogRecPtr *oldrecptr, TimeLineID *oldtli)
LWLockRelease(ControlFileLock);
}
-/*
- * BackupInProgress: check if online backup mode is active
- *
- * This is done by checking for existence of the "backup_label" file.
- */
-bool
-BackupInProgress(void)
-{
- struct stat stat_buf;
-
- return (stat(BACKUP_LABEL_FILE, &stat_buf) == 0);
-}
-
-/*
- * CancelBackup: rename the "backup_label" and "tablespace_map"
- * files to cancel backup mode
- *
- * If the "backup_label" file exists, it will be renamed to "backup_label.old".
- * Similarly, if the "tablespace_map" file exists, it will be renamed to
- * "tablespace_map.old".
- *
- * Note that this will render an online backup in progress
- * useless. To correctly finish an online backup, pg_stop_backup must be
- * called.
- */
-void
-CancelBackup(void)
-{
- struct stat stat_buf;
-
- /* if the backup_label file is not there, return */
- if (stat(BACKUP_LABEL_FILE, &stat_buf) < 0)
- return;
-
- /* remove leftover file from previously canceled backup if it exists */
- unlink(BACKUP_LABEL_OLD);
-
- if (durable_rename(BACKUP_LABEL_FILE, BACKUP_LABEL_OLD, DEBUG1) != 0)
- {
- ereport(WARNING,
- (errcode_for_file_access(),
- errmsg("online backup mode was not canceled"),
- errdetail("File \"%s\" could not be renamed to \"%s\": %m.",
- BACKUP_LABEL_FILE, BACKUP_LABEL_OLD)));
- return;
- }
-
- /* if the tablespace_map file is not there, return */
- if (stat(TABLESPACE_MAP, &stat_buf) < 0)
- {
- ereport(LOG,
- (errmsg("online backup mode canceled"),
- errdetail("File \"%s\" was renamed to \"%s\".",
- BACKUP_LABEL_FILE, BACKUP_LABEL_OLD)));
- return;
- }
-
- /* remove leftover file from previously canceled backup if it exists */
- unlink(TABLESPACE_MAP_OLD);
-
- if (durable_rename(TABLESPACE_MAP, TABLESPACE_MAP_OLD, DEBUG1) == 0)
- {
- ereport(LOG,
- (errmsg("online backup mode canceled"),
- errdetail("Files \"%s\" and \"%s\" were renamed to "
- "\"%s\" and \"%s\", respectively.",
- BACKUP_LABEL_FILE, TABLESPACE_MAP,
- BACKUP_LABEL_OLD, TABLESPACE_MAP_OLD)));
- }
- else
- {
- ereport(WARNING,
- (errcode_for_file_access(),
- errmsg("online backup mode canceled"),
- errdetail("File \"%s\" was renamed to \"%s\", but "
- "file \"%s\" could not be renamed to \"%s\": %m.",
- BACKUP_LABEL_FILE, BACKUP_LABEL_OLD,
- TABLESPACE_MAP, TABLESPACE_MAP_OLD)));
- }
-}
-
/* Thin wrapper around ShutdownWalRcv(). */
void
XLogShutdownWalRcv(void)
diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c
index 12e2bf4135..148b506a22 100644
--- a/src/backend/access/transam/xlogfuncs.c
+++ b/src/backend/access/transam/xlogfuncs.c
@@ -39,7 +39,7 @@
#include "utils/tuplestore.h"
/*
- * Store label file and tablespace map during non-exclusive backups.
+ * Store label file and tablespace map during backups.
*/
static StringInfo label_file;
static StringInfo tblspc_map_file;
@@ -61,101 +61,40 @@ pg_start_backup(PG_FUNCTION_ARGS)
{
text *backupid = PG_GETARG_TEXT_PP(0);
bool fast = PG_GETARG_BOOL(1);
- bool exclusive = PG_GETARG_BOOL(2);
char *backupidstr;
XLogRecPtr startpoint;
SessionBackupState status = get_backup_status();
+ MemoryContext oldcontext;
backupidstr = text_to_cstring(backupid);
- if (status == SESSION_BACKUP_NON_EXCLUSIVE)
+ if (status == SESSION_BACKUP_RUNNING)
ereport(ERROR,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("a backup is already in progress in this session")));
- if (exclusive)
- {
- startpoint = do_pg_start_backup(backupidstr, fast, NULL, NULL,
- NULL, NULL);
- }
- else
- {
- MemoryContext oldcontext;
-
- /*
- * Label file and tablespace map file need to be long-lived, since
- * they are read in pg_stop_backup.
- */
- oldcontext = MemoryContextSwitchTo(TopMemoryContext);
- label_file = makeStringInfo();
- tblspc_map_file = makeStringInfo();
- MemoryContextSwitchTo(oldcontext);
+ /*
+ * Label file and tablespace map file need to be long-lived, since
+ * they are read in pg_stop_backup.
+ */
+ oldcontext = MemoryContextSwitchTo(TopMemoryContext);
+ label_file = makeStringInfo();
+ tblspc_map_file = makeStringInfo();
+ MemoryContextSwitchTo(oldcontext);
- register_persistent_abort_backup_handler();
+ register_persistent_abort_backup_handler();
- startpoint = do_pg_start_backup(backupidstr, fast, NULL, label_file,
- NULL, tblspc_map_file);
- }
+ startpoint = do_pg_start_backup(backupidstr, fast, NULL, label_file,
+ NULL, tblspc_map_file);
PG_RETURN_LSN(startpoint);
}
-/*
- * pg_stop_backup: finish taking an on-line backup dump
- *
- * We write an end-of-backup WAL record, and remove the backup label file
- * created by pg_start_backup, creating a backup history file in pg_wal
- * instead (whence it will immediately be archived). The backup history file
- * contains the same info found in the label file, plus the backup-end time
- * and WAL location. Before 9.0, the backup-end time was read from the backup
- * history file at the beginning of archive recovery, but we now use the WAL
- * record for that and the file is for informational and debug purposes only.
- *
- * Note: different from CancelBackup which just cancels online backup mode.
- *
- * Note: this version is only called to stop an exclusive backup. The function
- * pg_stop_backup_v2 (overloaded as pg_stop_backup in SQL) is called to
- * stop non-exclusive backups.
- *
- * Permission checking for this function is managed through the normal
- * GRANT system.
- */
-Datum
-pg_stop_backup(PG_FUNCTION_ARGS)
-{
- XLogRecPtr stoppoint;
- SessionBackupState status = get_backup_status();
-
- if (status == SESSION_BACKUP_NON_EXCLUSIVE)
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("non-exclusive backup in progress"),
- errhint("Did you mean to use pg_stop_backup('f')?")));
-
- /*
- * Exclusive backups were typically started in a different connection, so
- * don't try to verify that status of backup is set to
- * SESSION_BACKUP_EXCLUSIVE in this function. Actual verification that an
- * exclusive backup is in fact running is handled inside
- * do_pg_stop_backup.
- */
- stoppoint = do_pg_stop_backup(NULL, true, NULL);
-
- PG_RETURN_LSN(stoppoint);
-}
-
/*
- * pg_stop_backup_v2: finish taking exclusive or nonexclusive on-line backup.
- *
- * Works the same as pg_stop_backup, except for non-exclusive backups it returns
- * the backup label and tablespace map files as text fields in as part of the
- * resultset.
+ * pg_stop_backup: finish taking an on-line backup.
*
- * The first parameter (variable 'exclusive') allows the user to tell us if
- * this is an exclusive or a non-exclusive backup.
- *
- * The second parameter (variable 'waitforarchive'), which is optional,
+ * The first parameter (variable 'waitforarchive'), which is optional,
* allows the user to choose if they want to wait for the WAL to be archived
* or if we should just return as soon as the WAL record is written.
*
@@ -163,7 +102,7 @@ pg_stop_backup(PG_FUNCTION_ARGS)
* GRANT system.
*/
Datum
-pg_stop_backup_v2(PG_FUNCTION_ARGS)
+pg_stop_backup(PG_FUNCTION_ARGS)
{
ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
TupleDesc tupdesc;
@@ -173,8 +112,7 @@ pg_stop_backup_v2(PG_FUNCTION_ARGS)
Datum values[3];
bool nulls[3];
- bool exclusive = PG_GETARG_BOOL(0);
- bool waitforarchive = PG_GETARG_BOOL(1);
+ bool waitforarchive = PG_GETARG_BOOL(0);
XLogRecPtr stoppoint;
SessionBackupState status = get_backup_status();
@@ -205,51 +143,29 @@ pg_stop_backup_v2(PG_FUNCTION_ARGS)
MemSet(values, 0, sizeof(values));
MemSet(nulls, 0, sizeof(nulls));
- if (exclusive)
- {
- if (status == SESSION_BACKUP_NON_EXCLUSIVE)
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("non-exclusive backup in progress"),
- errhint("Did you mean to use pg_stop_backup('f')?")));
-
- /*
- * Stop the exclusive backup, and since we're in an exclusive backup
- * return NULL for both backup_label and tablespace_map.
- */
- stoppoint = do_pg_stop_backup(NULL, waitforarchive, NULL);
-
- nulls[1] = true;
- nulls[2] = true;
- }
- else
- {
- if (status != SESSION_BACKUP_NON_EXCLUSIVE)
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("non-exclusive backup is not in progress"),
- errhint("Did you mean to use pg_stop_backup('t')?")));
+ if (status != SESSION_BACKUP_RUNNING)
+ ereport(ERROR,
+ (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ errmsg("backup is not in progress"),
+ errhint("Did you call pg_start_backup()?")));
- /*
- * Stop the non-exclusive backup. Return a copy of the backup label
- * and tablespace map so they can be written to disk by the caller.
- */
- stoppoint = do_pg_stop_backup(label_file->data, waitforarchive, NULL);
-
- values[1] = CStringGetTextDatum(label_file->data);
- values[2] = CStringGetTextDatum(tblspc_map_file->data);
-
- /* Free structures allocated in TopMemoryContext */
- pfree(label_file->data);
- pfree(label_file);
- label_file = NULL;
- pfree(tblspc_map_file->data);
- pfree(tblspc_map_file);
- tblspc_map_file = NULL;
- }
+ /*
+ * Stop the backup. Return a copy of the backup label and tablespace map so
+ * they can be written to disk by the caller.
+ */
+ stoppoint = do_pg_stop_backup(label_file->data, waitforarchive, NULL);
- /* Stoppoint is included on both exclusive and nonexclusive backups */
values[0] = LSNGetDatum(stoppoint);
+ values[1] = CStringGetTextDatum(label_file->data);
+ values[2] = CStringGetTextDatum(tblspc_map_file->data);
+
+ /* Free structures allocated in TopMemoryContext */
+ pfree(label_file->data);
+ pfree(label_file);
+ label_file = NULL;
+ pfree(tblspc_map_file->data);
+ pfree(tblspc_map_file);
+ tblspc_map_file = NULL;
tuplestore_putvalues(tupstore, tupdesc, values, nulls);
@@ -669,81 +585,6 @@ pg_wal_lsn_diff(PG_FUNCTION_ARGS)
PG_RETURN_NUMERIC(result);
}
-/*
- * Returns bool with current on-line backup mode, a global state.
- */
-Datum
-pg_is_in_backup(PG_FUNCTION_ARGS)
-{
- PG_RETURN_BOOL(BackupInProgress());
-}
-
-/*
- * Returns start time of an online exclusive backup.
- *
- * When there's no exclusive backup in progress, the function
- * returns NULL.
- */
-Datum
-pg_backup_start_time(PG_FUNCTION_ARGS)
-{
- Datum xtime;
- FILE *lfp;
- char fline[MAXPGPATH];
- char backup_start_time[30];
-
- /*
- * See if label file is present
- */
- lfp = AllocateFile(BACKUP_LABEL_FILE, "r");
- if (lfp == NULL)
- {
- if (errno != ENOENT)
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not read file \"%s\": %m",
- BACKUP_LABEL_FILE)));
- PG_RETURN_NULL();
- }
-
- /*
- * Parse the file to find the START TIME line.
- */
- backup_start_time[0] = '\0';
- while (fgets(fline, sizeof(fline), lfp) != NULL)
- {
- if (sscanf(fline, "START TIME: %25[^\n]\n", backup_start_time) == 1)
- break;
- }
-
- /* Check for a read error. */
- if (ferror(lfp))
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not read file \"%s\": %m", BACKUP_LABEL_FILE)));
-
- /* Close the backup label file. */
- if (FreeFile(lfp))
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not close file \"%s\": %m", BACKUP_LABEL_FILE)));
-
- if (strlen(backup_start_time) == 0)
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("invalid data in file \"%s\"", BACKUP_LABEL_FILE)));
-
- /*
- * Convert the time string read from file to TimestampTz form.
- */
- xtime = DirectFunctionCall3(timestamptz_in,
- CStringGetDatum(backup_start_time),
- ObjectIdGetDatum(InvalidOid),
- Int32GetDatum(-1));
-
- PG_RETURN_DATUM(xtime);
-}
-
/*
* Promotes a standby server.
*
diff --git a/src/backend/catalog/system_functions.sql b/src/backend/catalog/system_functions.sql
index fd1421788e..111eff6e14 100644
--- a/src/backend/catalog/system_functions.sql
+++ b/src/backend/catalog/system_functions.sql
@@ -377,14 +377,14 @@ BEGIN ATOMIC
END;
CREATE OR REPLACE FUNCTION
- pg_start_backup(label text, fast boolean DEFAULT false, exclusive boolean DEFAULT true)
+ pg_start_backup(label text, fast boolean DEFAULT false)
RETURNS pg_lsn STRICT VOLATILE LANGUAGE internal AS 'pg_start_backup'
PARALLEL RESTRICTED;
CREATE OR REPLACE FUNCTION pg_stop_backup (
- exclusive boolean, wait_for_archive boolean DEFAULT true,
- OUT lsn pg_lsn, OUT labelfile text, OUT spcmapfile text)
- RETURNS SETOF record STRICT VOLATILE LANGUAGE internal as 'pg_stop_backup_v2'
+ wait_for_archive boolean DEFAULT true, OUT lsn pg_lsn,
+ OUT labelfile text, OUT spcmapfile text)
+ RETURNS SETOF record STRICT VOLATILE LANGUAGE internal as 'pg_stop_backup'
PARALLEL RESTRICTED;
CREATE OR REPLACE FUNCTION
@@ -603,11 +603,9 @@ AS 'unicode_is_normalized';
-- available to superuser / cluster owner, if they choose.
--
-REVOKE EXECUTE ON FUNCTION pg_start_backup(text, boolean, boolean) FROM public;
+REVOKE EXECUTE ON FUNCTION pg_start_backup(text, boolean) FROM public;
-REVOKE EXECUTE ON FUNCTION pg_stop_backup() FROM public;
-
-REVOKE EXECUTE ON FUNCTION pg_stop_backup(boolean, boolean) FROM public;
+REVOKE EXECUTE ON FUNCTION pg_stop_backup(boolean) FROM public;
REVOKE EXECUTE ON FUNCTION pg_create_restore_point(text) FROM public;
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index 735fed490b..12d8ef9bfe 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -348,7 +348,6 @@ static PMState pmState = PM_INIT;
typedef enum
{
ALLOW_ALL_CONNS, /* normal not-shutting-down state */
- ALLOW_SUPERUSER_CONNS, /* only superusers can connect */
ALLOW_NO_CONNS /* no new connections allowed, period */
} ConnsAllowedState;
@@ -2546,19 +2545,11 @@ canAcceptConnections(int backend_type)
/*
* "Smart shutdown" restrictions are applied only to normal connections,
- * not to autovac workers or bgworkers. When only superusers can connect,
- * we return CAC_SUPERUSER to indicate that superuserness must be checked
- * later. Note that neither CAC_OK nor CAC_SUPERUSER can safely be
- * returned until we have checked for too many children.
+ * not to autovac workers or bgworkers.
*/
if (connsAllowed != ALLOW_ALL_CONNS &&
backend_type == BACKEND_TYPE_NORMAL)
- {
- if (connsAllowed == ALLOW_SUPERUSER_CONNS)
- result = CAC_SUPERUSER; /* allow superusers only */
- else
- return CAC_SHUTDOWN; /* shutdown is pending */
- }
+ return CAC_SHUTDOWN; /* shutdown is pending */
/*
* Don't start too many children.
@@ -2877,16 +2868,11 @@ pmdie(SIGNAL_ARGS)
#endif
/*
- * If we reached normal running, we have to wait for any online
- * backup mode to end; otherwise go straight to waiting for client
- * backends to exit. (The difference is that in the former state,
- * we'll still let in new superuser clients, so that somebody can
- * end the online backup mode.) If already in PM_STOP_BACKENDS or
+ * If we reached normal running, we go straight to waiting for
+ * client backends to exit. If already in PM_STOP_BACKENDS or
* a later state, do not change it.
*/
- if (pmState == PM_RUN)
- connsAllowed = ALLOW_SUPERUSER_CONNS;
- else if (pmState == PM_HOT_STANDBY)
+ if (pmState == PM_RUN || pmState == PM_HOT_STANDBY)
connsAllowed = ALLOW_NO_CONNS;
else if (pmState == PM_STARTUP || pmState == PM_RECOVERY)
{
@@ -3842,16 +3828,6 @@ PostmasterStateMachine(void)
/* If we're doing a smart shutdown, try to advance that state. */
if (pmState == PM_RUN || pmState == PM_HOT_STANDBY)
{
- if (connsAllowed == ALLOW_SUPERUSER_CONNS)
- {
- /*
- * ALLOW_SUPERUSER_CONNS state ends as soon as online backup mode
- * is not active.
- */
- if (!BackupInProgress())
- connsAllowed = ALLOW_NO_CONNS;
- }
-
if (connsAllowed == ALLOW_NO_CONNS)
{
/*
@@ -4044,18 +4020,6 @@ PostmasterStateMachine(void)
}
else
{
- /*
- * Terminate exclusive backup mode to avoid recovery after a clean
- * fast shutdown. Since an exclusive backup can only be taken
- * during normal running (and not, for example, while running
- * under Hot Standby) it only makes sense to do this if we reached
- * normal running. If we're still in recovery, the backup file is
- * one we're recovering *from*, and we must keep it around so that
- * recovery restarts from the right place.
- */
- if (ReachedNormalRunning)
- CancelBackup();
-
/*
* Normal exit from the postmaster is here. We don't need to log
* anything here, since the UnlinkLockFiles proc_exit callback
diff --git a/src/backend/replication/basebackup.c b/src/backend/replication/basebackup.c
index 0bf28b55d7..4682b28a85 100644
--- a/src/backend/replication/basebackup.c
+++ b/src/backend/replication/basebackup.c
@@ -195,10 +195,8 @@ static const struct exclude_list_item excludeFiles[] =
{RELCACHE_INIT_FILENAME, true},
/*
- * If there's a backup_label or tablespace_map file, it belongs to a
- * backup started by the user with pg_start_backup(). It is *not* correct
- * for this backup. Our backup_label/tablespace_map is injected into the
- * tar separately.
+ * backup_label and tablespace_map should not exist in in a running cluster
+ * capable of doing an online backup, but exclude then just in case.
*/
{BACKUP_LABEL_FILE, false},
{TABLESPACE_MAP, false},
diff --git a/src/bin/pg_basebackup/t/010_pg_basebackup.pl b/src/bin/pg_basebackup/t/010_pg_basebackup.pl
index 8c70e5b32b..5019a51009 100644
--- a/src/bin/pg_basebackup/t/010_pg_basebackup.pl
+++ b/src/bin/pg_basebackup/t/010_pg_basebackup.pl
@@ -185,6 +185,10 @@ isnt(slurp_file("$tempdir/backup/backup_label"),
'DONOTCOPY', 'existing backup_label not copied');
rmtree("$tempdir/backup");
+# Now delete the bogus backup_label file since it will interfere with startup
+unlink("$pgdata/backup_label")
+ or BAIL_OUT("unable to unlink $pgdata/backup_label");
+
$node->command_ok(
[
@pg_basebackup_defs, '-D',
diff --git a/src/bin/pg_rewind/filemap.c b/src/bin/pg_rewind/filemap.c
index 7211090f47..fb52debf7a 100644
--- a/src/bin/pg_rewind/filemap.c
+++ b/src/bin/pg_rewind/filemap.c
@@ -140,9 +140,9 @@ static const struct exclude_list_item excludeFiles[] =
{"pg_internal.init", true}, /* defined as RELCACHE_INIT_FILENAME */
/*
- * If there's a backup_label or tablespace_map file, it belongs to a
- * backup started by the user with pg_start_backup(). It is *not* correct
- * for this backup. Our backup_label is written later on separately.
+ * If there is a backup_label or tablespace_map file, it indicates that
+ * a recovery failed and this cluster probably can't be rewound, but
+ * exclude them anyway if they are found.
*/
{"backup_label", false}, /* defined as BACKUP_LABEL_FILE */
{"tablespace_map", false}, /* defined as TABLESPACE_MAP */
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index 4b45ac64db..00a3d14c76 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -275,8 +275,7 @@ extern void XLogShutdownWalRcv(void);
typedef enum SessionBackupState
{
SESSION_BACKUP_NONE,
- SESSION_BACKUP_EXCLUSIVE,
- SESSION_BACKUP_NON_EXCLUSIVE
+ SESSION_BACKUP_RUNNING,
} SessionBackupState;
extern XLogRecPtr do_pg_start_backup(const char *backupidstr, bool fast,
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 7f1ee97f55..8f126e2f54 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -6275,25 +6275,15 @@
prosrc => 'pg_terminate_backend' },
{ oid => '2172', descr => 'prepare for taking an online backup',
proname => 'pg_start_backup', provolatile => 'v', proparallel => 'r',
- prorettype => 'pg_lsn', proargtypes => 'text bool bool',
+ prorettype => 'pg_lsn', proargtypes => 'text bool',
prosrc => 'pg_start_backup' },
-{ oid => '2173', descr => 'finish taking an online backup',
- proname => 'pg_stop_backup', provolatile => 'v', proparallel => 'r',
- prorettype => 'pg_lsn', proargtypes => '', prosrc => 'pg_stop_backup' },
{ oid => '2739', descr => 'finish taking an online backup',
proname => 'pg_stop_backup', prorows => '1', proretset => 't',
provolatile => 'v', proparallel => 'r', prorettype => 'record',
- proargtypes => 'bool bool', proallargtypes => '{bool,bool,pg_lsn,text,text}',
- proargmodes => '{i,i,o,o,o}',
- proargnames => '{exclusive,wait_for_archive,lsn,labelfile,spcmapfile}',
- prosrc => 'pg_stop_backup_v2' },
-{ oid => '3813', descr => 'true if server is in online backup',
- proname => 'pg_is_in_backup', provolatile => 'v', prorettype => 'bool',
- proargtypes => '', prosrc => 'pg_is_in_backup' },
-{ oid => '3814', descr => 'start time of an online backup',
- proname => 'pg_backup_start_time', provolatile => 's',
- prorettype => 'timestamptz', proargtypes => '',
- prosrc => 'pg_backup_start_time' },
+ proargtypes => 'bool', proallargtypes => '{bool,pg_lsn,text,text}',
+ proargmodes => '{i,o,o,o}',
+ proargnames => '{wait_for_archive,lsn,labelfile,spcmapfile}',
+ prosrc => 'pg_stop_backup' },
{ oid => '3436', descr => 'promote standby server',
proname => 'pg_promote', provolatile => 'v', prorettype => 'bool',
proargtypes => 'bool int4', proargnames => '{wait,wait_seconds}',
diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h
index 0abc3ad540..9321d7f264 100644
--- a/src/include/miscadmin.h
+++ b/src/include/miscadmin.h
@@ -481,10 +481,6 @@ extern void process_session_preload_libraries(void);
extern void pg_bindtextdomain(const char *domain);
extern bool has_rolreplication(Oid roleid);
-/* in access/transam/xlog.c */
-extern bool BackupInProgress(void);
-extern void CancelBackup(void);
-
/* in executor/nodeHash.c */
extern size_t get_hash_memory_limit(void);
diff --git a/src/test/perl/PostgreSQL/Test/Cluster.pm b/src/test/perl/PostgreSQL/Test/Cluster.pm
index ed70eff374..49573f9d7d 100644
--- a/src/test/perl/PostgreSQL/Test/Cluster.pm
+++ b/src/test/perl/PostgreSQL/Test/Cluster.pm
@@ -634,25 +634,6 @@ sub backup
return;
}
-=item $node->backup_fs_hot(backup_name)
-
-Create a backup with a filesystem level copy in subdirectory B<backup_name> of
-B<< $node->backup_dir >>, including WAL.
-
-Archiving must be enabled, as B<pg_start_backup()> and B<pg_stop_backup()> are
-used. This is not checked or enforced.
-
-The backup name is passed as the backup label to B<pg_start_backup()>.
-
-=cut
-
-sub backup_fs_hot
-{
- my ($self, $backup_name) = @_;
- $self->_backup_fs($backup_name, 1);
- return;
-}
-
=item $node->backup_fs_cold(backup_name)
Create a backup with a filesystem level copy in subdirectory B<backup_name> of
@@ -666,53 +647,18 @@ Use B<backup> or B<backup_fs_hot> if you want to back up a running server.
sub backup_fs_cold
{
my ($self, $backup_name) = @_;
- $self->_backup_fs($backup_name, 0);
- return;
-}
-
-
-# Common sub of backup_fs_hot and backup_fs_cold
-sub _backup_fs
-{
- my ($self, $backup_name, $hot) = @_;
- my $backup_path = $self->backup_dir . '/' . $backup_name;
- my $port = $self->port;
- my $name = $self->name;
-
- print "# Taking filesystem backup $backup_name from node \"$name\"\n";
-
- if ($hot)
- {
- my $stdout = $self->safe_psql('postgres',
- "SELECT * FROM pg_start_backup('$backup_name');");
- print "# pg_start_backup: $stdout\n";
- }
PostgreSQL::Test::RecursiveCopy::copypath(
$self->data_dir,
- $backup_path,
+ $self->backup_dir . '/' . $backup_name,
filterfn => sub {
my $src = shift;
return ($src ne 'log' and $src ne 'postmaster.pid');
});
- if ($hot)
- {
-
- # We ignore pg_stop_backup's return value. We also assume archiving
- # is enabled; otherwise the caller will have to copy the remaining
- # segments.
- my $stdout =
- $self->safe_psql('postgres', 'SELECT * FROM pg_stop_backup();');
- print "# pg_stop_backup: $stdout\n";
- }
-
- print "# Backup finished\n";
return;
}
-
-
=pod
=item $node->init_from_backup(root_node, backup_name)
diff --git a/src/test/recovery/t/010_logical_decoding_timelines.pl b/src/test/recovery/t/010_logical_decoding_timelines.pl
index 6e8b0b1b96..6351633b50 100644
--- a/src/test/recovery/t/010_logical_decoding_timelines.pl
+++ b/src/test/recovery/t/010_logical_decoding_timelines.pl
@@ -69,7 +69,9 @@ $node_primary->safe_psql('dropme',
$node_primary->safe_psql('postgres', 'CHECKPOINT;');
my $backup_name = 'b1';
-$node_primary->backup_fs_hot($backup_name);
+$node_primary->stop();
+$node_primary->backup_fs_cold($backup_name);
+$node_primary->start();
$node_primary->safe_psql('postgres',
q[SELECT pg_create_physical_replication_slot('phys_slot');]);
--
2.25.1
Some review comments on the latest version:
+ * runningBackups is a counter indicating the number of backups currently in
+ * progress. forcePageWrites is set to true when either of these is
+ * non-zero. lastBackupStart is the latest checkpoint redo location used as
+ * a starting point for an online backup.
*/
- ExclusiveBackupState exclusiveBackupState;
- int nonExclusiveBackups;
What do you mean by "either of these is non-zero ''. Earlier we used
to set forcePageWrites in case of both exclusive and non-exclusive
backups, but we have just one type of backup now.
==
- * OK to update backup counters, forcePageWrites and session-level lock.
+ * OK to update backup counters and forcePageWrites.
*
We still update the status of session-level lock so I don't think we
should update the above comment. See below code:
if (XLogCtl->Insert.runningBackups == 0)
{
XLogCtl->Insert.forcePageWrites = false;
}
/*
* Clean up session-level lock.
*
* You might think that WALInsertLockRelease() can be called before
* cleaning up session-level lock because session-level lock doesn't need
* to be protected with WAL insertion lock. But since
* CHECK_FOR_INTERRUPTS() can occur in it, session-level lock must be
* cleaned up before it.
*/
sessionBackupState = SESSION_BACKUP_NONE;
WALInsertLockRelease();
==
@@ -8993,18 +8686,16 @@ do_pg_abort_backup(int code, Datum arg)
bool emit_warning = DatumGetBool(arg);
/*
- * Quick exit if session is not keeping around a non-exclusive backup
- * already started.
+ * Quick exit if session does not have a running backup.
*/
- if (sessionBackupState != SESSION_BACKUP_NON_EXCLUSIVE)
+ if (sessionBackupState != SESSION_BACKUP_RUNNING)
return;
WALInsertLockAcquireExclusive();
- Assert(XLogCtl->Insert.nonExclusiveBackups > 0);
- XLogCtl->Insert.nonExclusiveBackups--;
+ Assert(XLogCtl->Insert.runningBackups > 0);
+ XLogCtl->Insert.runningBackups--;
- if (XLogCtl->Insert.exclusiveBackupState == EXCLUSIVE_BACKUP_NONE &&
- XLogCtl->Insert.nonExclusiveBackups == 0)
+ if (XLogCtl->Insert.runningBackups == 0)
{
XLogCtl->Insert.forcePageWrites = false;
}
I think we have a lot of common code in do_pg_abort_backup() and
pg_do_stop_backup(). So why not have a common function that can be
called from both these functions.
==
+# Now delete the bogus backup_label file since it will interfere with startup
+unlink("$pgdata/backup_label")
+ or BAIL_OUT("unable to unlink $pgdata/backup_label");
+
Why do we need this additional change? Earlier this was not required.
--
With Regards,
Ashutosh Sharma.
Show quoted text
On Thu, Feb 17, 2022 at 6:41 AM Nathan Bossart <nathandbossart@gmail.com> wrote:
Here is a rebased patch.
--
Nathan Bossart
Amazon Web Services: https://aws.amazon.com
On Fri, Feb 18, 2022 at 10:48:10PM +0530, Ashutosh Sharma wrote:
Some review comments on the latest version:
Thanks for the feedback! Before I start spending more time on this one, I
should probably ask if this has any chance of making it into v15.
--
Nathan Bossart
Amazon Web Services: https://aws.amazon.com
On Sat, Feb 19, 2022 at 2:24 AM Nathan Bossart <nathandbossart@gmail.com> wrote:
On Fri, Feb 18, 2022 at 10:48:10PM +0530, Ashutosh Sharma wrote:
Some review comments on the latest version:
Thanks for the feedback! Before I start spending more time on this one, I
should probably ask if this has any chance of making it into v15.
I don't see any reason why it can't make it to v15. However, it is not
super urgent as the users facing this problem have a choice. They can
use non-exclusive mode.
--
With Regards,
Ashutosh Sharma.
I've attached an updated patch.
On Fri, Feb 18, 2022 at 10:48:10PM +0530, Ashutosh Sharma wrote:
+ * runningBackups is a counter indicating the number of backups currently in + * progress. forcePageWrites is set to true when either of these is + * non-zero. lastBackupStart is the latest checkpoint redo location used as + * a starting point for an online backup. */ - ExclusiveBackupState exclusiveBackupState; - int nonExclusiveBackups;What do you mean by "either of these is non-zero ''. Earlier we used
to set forcePageWrites in case of both exclusive and non-exclusive
backups, but we have just one type of backup now.
Fixed this.
- * OK to update backup counters, forcePageWrites and session-level lock. + * OK to update backup counters and forcePageWrites. *We still update the status of session-level lock so I don't think we
should update the above comment. See below code:
Fixed this.
I think we have a lot of common code in do_pg_abort_backup() and
pg_do_stop_backup(). So why not have a common function that can be
called from both these functions.
I didn't follow through with this change. I only saw a handful of lines
that looked similar, and AFAICT we'd need an extra branch for cleaning up
the session-level lock since do_pg_abort_backup() doesn't.
+# Now delete the bogus backup_label file since it will interfere with startup +unlink("$pgdata/backup_label") + or BAIL_OUT("unable to unlink $pgdata/backup_label"); +Why do we need this additional change? Earlier this was not required.
IIUC this test relied on the following code to handle the bogus file:
/*
* Terminate exclusive backup mode to avoid recovery after a clean
* fast shutdown. Since an exclusive backup can only be taken
* during normal running (and not, for example, while running
* under Hot Standby) it only makes sense to do this if we reached
* normal running. If we're still in recovery, the backup file is
* one we're recovering *from*, and we must keep it around so that
* recovery restarts from the right place.
*/
if (ReachedNormalRunning)
CancelBackup();
The attached patch removes this code.
--
Nathan Bossart
Amazon Web Services: https://aws.amazon.com
Attachments:
v3-0001-remove-exclusive-backup-mode.patchtext/x-diff; charset=us-asciiDownload
From 7fd092c90be90018eeddf3ea5088197627cbe593 Mon Sep 17 00:00:00 2001
From: Nathan Bossart <bossartn@amazon.com>
Date: Wed, 1 Dec 2021 23:50:49 +0000
Subject: [PATCH v3 1/1] remove exclusive backup mode
---
doc/src/sgml/backup.sgml | 154 +-----
doc/src/sgml/func.sgml | 30 +-
src/backend/access/transam/xlog.c | 466 ++----------------
src/backend/access/transam/xlogfuncs.c | 235 ++-------
src/backend/catalog/system_functions.sql | 14 +-
src/backend/postmaster/postmaster.c | 46 +-
src/backend/replication/basebackup.c | 6 +-
src/bin/pg_basebackup/t/010_pg_basebackup.pl | 4 +
src/bin/pg_rewind/filemap.c | 6 +-
src/include/access/xlog.h | 3 +-
src/include/catalog/pg_proc.dat | 20 +-
src/include/miscadmin.h | 4 -
src/test/perl/PostgreSQL/Test/Cluster.pm | 56 +--
.../t/010_logical_decoding_timelines.pl | 4 +-
14 files changed, 113 insertions(+), 935 deletions(-)
diff --git a/doc/src/sgml/backup.sgml b/doc/src/sgml/backup.sgml
index 0d69851bb1..f241bcab9c 100644
--- a/doc/src/sgml/backup.sgml
+++ b/doc/src/sgml/backup.sgml
@@ -857,16 +857,8 @@ test ! -f /mnt/server/archivedir/00000001000000A900000065 && cp pg_wal/0
sequence, and that the success of a step is verified before
proceeding to the next step.
</para>
- <para>
- Low level base backups can be made in a non-exclusive or an exclusive
- way. The non-exclusive method is recommended and the exclusive one is
- deprecated and will eventually be removed.
- </para>
-
- <sect3 id="backup-lowlevel-base-backup-nonexclusive">
- <title>Making a Non-Exclusive Low-Level Backup</title>
<para>
- A non-exclusive low level backup is one that allows other
+ A low level backup allows other
concurrent backups to be running (both those started using
the same backup API and those started using
<xref linkend="app-pgbasebackup"/>).
@@ -884,7 +876,7 @@ test ! -f /mnt/server/archivedir/00000001000000A900000065 && cp pg_wal/0
rights to run pg_start_backup (superuser, or a user who has been granted
EXECUTE on the function) and issue the command:
<programlisting>
-SELECT pg_start_backup('label', false, false);
+SELECT pg_start_backup('label', false);
</programlisting>
where <literal>label</literal> is any string you want to use to uniquely
identify this backup operation. The connection
@@ -905,10 +897,6 @@ SELECT pg_start_backup('label', false, false);
issue an immediate checkpoint using as much I/O as available.
</para>
- <para>
- The third parameter being <literal>false</literal> tells
- <function>pg_start_backup</function> to initiate a non-exclusive base backup.
- </para>
</listitem>
<listitem>
<para>
@@ -926,7 +914,7 @@ SELECT pg_start_backup('label', false, false);
<para>
In the same connection as before, issue the command:
<programlisting>
-SELECT * FROM pg_stop_backup(false, true);
+SELECT * FROM pg_stop_backup(true);
</programlisting>
This terminates backup mode. On a primary, it also performs an automatic
switch to the next WAL segment. On a standby, it is not possible to
@@ -985,142 +973,6 @@ SELECT * FROM pg_stop_backup(false, true);
</listitem>
</orderedlist>
</para>
- </sect3>
- <sect3 id="backup-lowlevel-base-backup-exclusive">
- <title>Making an Exclusive Low-Level Backup</title>
-
- <note>
- <para>
- The exclusive backup method is deprecated and should be avoided.
- Prior to <productname>PostgreSQL</productname> 9.6, this was the only
- low-level method available, but it is now recommended that all users
- upgrade their scripts to use non-exclusive backups.
- </para>
- </note>
-
- <para>
- The process for an exclusive backup is mostly the same as for a
- non-exclusive one, but it differs in a few key steps. This type of
- backup can only be taken on a primary and does not allow concurrent
- backups. Moreover, because it creates a backup label file, as
- described below, it can block automatic restart of the primary server
- after a crash. On the other hand, the erroneous removal of this
- file from a backup or standby is a common mistake, which can result
- in serious data corruption. If it is necessary to use this method,
- the following steps may be used.
- </para>
- <para>
- <orderedlist>
- <listitem>
- <para>
- Ensure that WAL archiving is enabled and working.
- </para>
- </listitem>
- <listitem>
- <para>
- Connect to the server (it does not matter which database) as a user with
- rights to run pg_start_backup (superuser, or a user who has been granted
- EXECUTE on the function) and issue the command:
-<programlisting>
-SELECT pg_start_backup('label');
-</programlisting>
- where <literal>label</literal> is any string you want to use to uniquely
- identify this backup operation.
- <function>pg_start_backup</function> creates a <firstterm>backup label</firstterm> file,
- called <filename>backup_label</filename>, in the cluster directory with
- information about your backup, including the start time and label string.
- The function also creates a <firstterm>tablespace map</firstterm> file,
- called <filename>tablespace_map</filename>, in the cluster directory with
- information about tablespace symbolic links in <filename>pg_tblspc/</filename> if
- one or more such link is present. Both files are critical to the
- integrity of the backup, should you need to restore from it.
- </para>
-
- <para>
- By default, <function>pg_start_backup</function> can take a long time to finish.
- This is because it performs a checkpoint, and the I/O
- required for the checkpoint will be spread out over a significant
- period of time, by default half your inter-checkpoint interval
- (see the configuration parameter
- <xref linkend="guc-checkpoint-completion-target"/>). This is
- usually what you want, because it minimizes the impact on query
- processing. If you want to start the backup as soon as
- possible, use:
-<programlisting>
-SELECT pg_start_backup('label', true);
-</programlisting>
- This forces the checkpoint to be done as quickly as possible.
- </para>
- </listitem>
- <listitem>
- <para>
- Perform the backup, using any convenient file-system-backup tool
- such as <application>tar</application> or <application>cpio</application> (not
- <application>pg_dump</application> or
- <application>pg_dumpall</application>). It is neither
- necessary nor desirable to stop normal operation of the database
- while you do this. See
- <xref linkend="backup-lowlevel-base-backup-data"/> for things to
- consider during this backup.
- </para>
- <para>
- As noted above, if the server crashes during the backup it may not be
- possible to restart until the <filename>backup_label</filename> file has
- been manually deleted from the <envar>PGDATA</envar> directory. Note
- that it is very important to never remove the
- <filename>backup_label</filename> file when restoring a backup, because
- this will result in corruption. Confusion about when it is appropriate
- to remove this file is a common cause of data corruption when using this
- method; be very certain that you remove the file only on an existing
- primary and never when building a standby or restoring a backup, even if
- you are building a standby that will subsequently be promoted to a new
- primary.
- </para>
- </listitem>
- <listitem>
- <para>
- Again connect to the database as a user with rights to run
- pg_stop_backup (superuser, or a user who has been granted EXECUTE on
- the function), and issue the command:
-<programlisting>
-SELECT pg_stop_backup();
-</programlisting>
- This function terminates backup mode and
- performs an automatic switch to the next WAL segment. The reason for the
- switch is to arrange for the last WAL segment written during the backup
- interval to be ready to archive.
- </para>
- </listitem>
- <listitem>
- <para>
- Once the WAL segment files active during the backup are archived, you are
- done. The file identified by <function>pg_stop_backup</function>'s result is
- the last segment that is required to form a complete set of backup files.
- If <varname>archive_mode</varname> is enabled,
- <function>pg_stop_backup</function> does not return until the last segment has
- been archived.
- Archiving of these files happens automatically since you have
- already configured <varname>archive_command</varname>. In most cases this
- happens quickly, but you are advised to monitor your archive
- system to ensure there are no delays.
- If the archive process has fallen behind
- because of failures of the archive command, it will keep retrying
- until the archive succeeds and the backup is complete.
- </para>
-
- <para>
- When using exclusive backup mode, it is absolutely imperative to ensure
- that <function>pg_stop_backup</function> completes successfully at the
- end of the backup. Even if the backup itself fails, for example due to
- lack of disk space, failure to call <function>pg_stop_backup</function>
- will leave the server in backup mode indefinitely, causing future backups
- to fail and increasing the risk of a restart failure during the time that
- <filename>backup_label</filename> exists.
- </para>
- </listitem>
- </orderedlist>
- </para>
- </sect3>
<sect3 id="backup-lowlevel-base-backup-data">
<title>Backing Up the Data Directory</title>
<para>
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index df3cd5987b..3d4c8bf851 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -25683,8 +25683,7 @@ LOG: Grand total: 1651920 bytes in 201 blocks; 622360 free (88 chunks); 1029560
<function>pg_start_backup</function> (
<parameter>label</parameter> <type>text</type>
<optional>, <parameter>fast</parameter> <type>boolean</type>
- <optional>, <parameter>exclusive</parameter> <type>boolean</type>
- </optional></optional> )
+ </optional> )
<returnvalue>pg_lsn</returnvalue>
</para>
<para>
@@ -25696,20 +25695,6 @@ LOG: Grand total: 1651920 bytes in 201 blocks; 622360 free (88 chunks); 1029560
it specifies executing <function>pg_start_backup</function> as quickly
as possible. This forces an immediate checkpoint which will cause a
spike in I/O operations, slowing any concurrently executing queries.
- The optional third parameter specifies whether to perform an exclusive
- or non-exclusive backup (default is exclusive).
- </para>
- <para>
- When used in exclusive mode, this function writes a backup label file
- (<filename>backup_label</filename>) and, if there are any links in
- the <filename>pg_tblspc/</filename> directory, a tablespace map file
- (<filename>tablespace_map</filename>) into the database cluster's data
- directory, then performs a checkpoint, and then returns the backup's
- starting write-ahead log location. (The user can ignore this
- result value, but it is provided in case it is useful.) When used in
- non-exclusive mode, the contents of these files are instead returned
- by the <function>pg_stop_backup</function> function, and should be
- copied to the backup area by the user.
</para>
<para>
This function is restricted to superusers by default, but other users
@@ -25723,7 +25708,6 @@ LOG: Grand total: 1651920 bytes in 201 blocks; 622360 free (88 chunks); 1029560
<primary>pg_stop_backup</primary>
</indexterm>
<function>pg_stop_backup</function> (
- <parameter>exclusive</parameter> <type>boolean</type>
<optional>, <parameter>wait_for_archive</parameter> <type>boolean</type>
</optional> )
<returnvalue>setof record</returnvalue>
@@ -25732,13 +25716,8 @@ LOG: Grand total: 1651920 bytes in 201 blocks; 622360 free (88 chunks); 1029560
<parameter>spcmapfile</parameter> <type>text</type> )
</para>
<para>
- Finishes performing an exclusive or non-exclusive on-line backup.
- The <parameter>exclusive</parameter> parameter must match the
- previous <function>pg_start_backup</function> call.
- In an exclusive backup, <function>pg_stop_backup</function> removes
- the backup label file and, if it exists, the tablespace map file
- created by <function>pg_start_backup</function>. In a non-exclusive
- backup, the desired contents of these files are returned as part of
+ Finishes performing an on-line backup. The desired contents of the
+ backup label file and the tablespace map file are returned as part of
the result of the function, and should be written to files in the
backup area (not in the data directory).
</para>
@@ -25771,8 +25750,7 @@ LOG: Grand total: 1651920 bytes in 201 blocks; 622360 free (88 chunks); 1029560
The result of the function is a single record.
The <parameter>lsn</parameter> column holds the backup's ending
write-ahead log location (which again can be ignored). The second and
- third columns are <literal>NULL</literal> when ending an exclusive
- backup; after a non-exclusive backup they hold the desired contents of
+ third columns hold the desired contents of
the label and tablespace map files.
</para>
<para>
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 0d2bd7a357..4f62f77d02 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -384,29 +384,6 @@ typedef union WALInsertLockPadded
char pad[PG_CACHE_LINE_SIZE];
} WALInsertLockPadded;
-/*
- * State of an exclusive backup, necessary to control concurrent activities
- * across sessions when working on exclusive backups.
- *
- * EXCLUSIVE_BACKUP_NONE means that there is no exclusive backup actually
- * running, to be more precise pg_start_backup() is not being executed for
- * an exclusive backup and there is no exclusive backup in progress.
- * EXCLUSIVE_BACKUP_STARTING means that pg_start_backup() is starting an
- * exclusive backup.
- * EXCLUSIVE_BACKUP_IN_PROGRESS means that pg_start_backup() has finished
- * running and an exclusive backup is in progress. pg_stop_backup() is
- * needed to finish it.
- * EXCLUSIVE_BACKUP_STOPPING means that pg_stop_backup() is stopping an
- * exclusive backup.
- */
-typedef enum ExclusiveBackupState
-{
- EXCLUSIVE_BACKUP_NONE = 0,
- EXCLUSIVE_BACKUP_STARTING,
- EXCLUSIVE_BACKUP_IN_PROGRESS,
- EXCLUSIVE_BACKUP_STOPPING
-} ExclusiveBackupState;
-
/*
* Session status of running backup, used for sanity checks in SQL-callable
* functions to start and stop backups.
@@ -455,15 +432,12 @@ typedef struct XLogCtlInsert
bool fullPageWrites;
/*
- * exclusiveBackupState indicates the state of an exclusive backup (see
- * comments of ExclusiveBackupState for more details). nonExclusiveBackups
- * is a counter indicating the number of streaming base backups currently
- * in progress. forcePageWrites is set to true when either of these is
- * non-zero. lastBackupStart is the latest checkpoint redo location used
- * as a starting point for an online backup.
+ * runningBackups is a counter indicating the number of backups currently in
+ * progress. forcePageWrites is set to true when runningBackups is non-zero.
+ * lastBackupStart is the latest checkpoint redo location used as a starting
+ * point for an online backup.
*/
- ExclusiveBackupState exclusiveBackupState;
- int nonExclusiveBackups;
+ int runningBackups;
XLogRecPtr lastBackupStart;
/*
@@ -696,7 +670,6 @@ static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow);
static void pg_start_backup_callback(int code, Datum arg);
-static void pg_stop_backup_callback(int code, Datum arg);
static int get_sync_bit(int method);
@@ -7008,7 +6981,7 @@ CreateRestartPoint(int flags)
* Ensure minRecoveryPoint is past the checkpoint record. Normally,
* this will have happened already while writing out dirty buffers,
* but not necessarily - e.g. because no buffers were dirtied. We do
- * this because a non-exclusive base backup uses minRecoveryPoint to
+ * this because a backup performed in recovery uses minRecoveryPoint to
* determine which WAL files must be included in the backup, and the
* file (or files) containing the checkpoint record must be included,
* at a minimum. Note that for an ordinary restart of recovery there's
@@ -8011,32 +7984,14 @@ issue_xlog_fsync(int fd, XLogSegNo segno, TimeLineID tli)
}
/*
- * do_pg_start_backup
- *
- * Utility function called at the start of an online backup. It creates the
- * necessary starting checkpoint and constructs the backup label file.
- *
- * There are two kind of backups: exclusive and non-exclusive. An exclusive
- * backup is started with pg_start_backup(), and there can be only one active
- * at a time. The backup and tablespace map files of an exclusive backup are
- * written to $PGDATA/backup_label and $PGDATA/tablespace_map, and they are
- * removed by pg_stop_backup().
+ * do_pg_start_backup is the workhorse of the user-visible pg_start_backup()
+ * function. It creates the necessary starting checkpoint and constructs the
+ * backup label and tablespace map.
*
- * A non-exclusive backup is used for the streaming base backups (see
- * src/backend/replication/basebackup.c). The difference to exclusive backups
- * is that the backup label and tablespace map files are not written to disk.
- * Instead, their would-be contents are returned in *labelfile and *tblspcmapfile,
- * and the caller is responsible for including them in the backup archive as
- * 'backup_label' and 'tablespace_map'. There can be many non-exclusive backups
- * active at the same time, and they don't conflict with an exclusive backup
- * either.
- *
- * labelfile and tblspcmapfile must be passed as NULL when starting an
- * exclusive backup, and as initially-empty StringInfos for a non-exclusive
- * backup.
- *
- * If "tablespaces" isn't NULL, it receives a list of tablespaceinfo structs
- * describing the cluster's tablespaces.
+ * The backup label and tablespace map contents are returned in *labelfile and
+ * *tblspcmapfile, and the caller is responsible for including them in the
+ * backup archive as 'backup_label' and 'tablespace_map'. There can be many
+ * backups active at the same time.
*
* tblspcmapfile is required mainly for tar format in windows as native windows
* utilities are not able to create symlinks while extracting files from tar.
@@ -8045,7 +8000,7 @@ issue_xlog_fsync(int fd, XLogSegNo segno, TimeLineID tli)
* Returns the minimum WAL location that must be present to restore from this
* backup, and the corresponding timeline ID in *starttli_p.
*
- * Every successfully started non-exclusive backup must be stopped by calling
+ * Every successfully started backup must be stopped by calling
* do_pg_stop_backup() or do_pg_abort_backup().
*
* It is the responsibility of the caller of this function to verify the
@@ -8056,7 +8011,6 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
StringInfo labelfile, List **tablespaces,
StringInfo tblspcmapfile)
{
- bool exclusive = (labelfile == NULL);
bool backup_started_in_recovery = false;
XLogRecPtr checkpointloc;
XLogRecPtr startpoint;
@@ -8065,20 +8019,9 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
char strfbuf[128];
char xlogfilename[MAXFNAMELEN];
XLogSegNo _logSegNo;
- struct stat stat_buf;
- FILE *fp;
backup_started_in_recovery = RecoveryInProgress();
- /*
- * Currently only non-exclusive backup can be taken during recovery.
- */
- if (backup_started_in_recovery && exclusive)
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("recovery is in progress"),
- errhint("WAL control functions cannot be executed during recovery.")));
-
/*
* During recovery, we don't need to check WAL level. Because, if WAL
* level is not sufficient, it's impossible to get here during recovery.
@@ -8117,30 +8060,12 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
* XLogInsertRecord().
*/
WALInsertLockAcquireExclusive();
- if (exclusive)
- {
- /*
- * At first, mark that we're now starting an exclusive backup, to
- * ensure that there are no other sessions currently running
- * pg_start_backup() or pg_stop_backup().
- */
- if (XLogCtl->Insert.exclusiveBackupState != EXCLUSIVE_BACKUP_NONE)
- {
- WALInsertLockRelease();
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("a backup is already in progress"),
- errhint("Run pg_stop_backup() and try again.")));
- }
- XLogCtl->Insert.exclusiveBackupState = EXCLUSIVE_BACKUP_STARTING;
- }
- else
- XLogCtl->Insert.nonExclusiveBackups++;
+ XLogCtl->Insert.runningBackups++;
XLogCtl->Insert.forcePageWrites = true;
WALInsertLockRelease();
/* Ensure we release forcePageWrites if fail below */
- PG_ENSURE_ERROR_CLEANUP(pg_start_backup_callback, (Datum) BoolGetDatum(exclusive));
+ PG_ENSURE_ERROR_CLEANUP(pg_start_backup_callback, (Datum) 0);
{
bool gotUniqueStartpoint = false;
DIR *tblspcdir;
@@ -8375,122 +8300,19 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
LSN_FORMAT_ARGS(startpoint), xlogfilename);
appendStringInfo(labelfile, "CHECKPOINT LOCATION: %X/%X\n",
LSN_FORMAT_ARGS(checkpointloc));
- appendStringInfo(labelfile, "BACKUP METHOD: %s\n",
- exclusive ? "pg_start_backup" : "streamed");
+ appendStringInfo(labelfile, "BACKUP METHOD: streamed\n");
appendStringInfo(labelfile, "BACKUP FROM: %s\n",
backup_started_in_recovery ? "standby" : "primary");
appendStringInfo(labelfile, "START TIME: %s\n", strfbuf);
appendStringInfo(labelfile, "LABEL: %s\n", backupidstr);
appendStringInfo(labelfile, "START TIMELINE: %u\n", starttli);
-
- /*
- * Okay, write the file, or return its contents to caller.
- */
- if (exclusive)
- {
- /*
- * Check for existing backup label --- implies a backup is already
- * running. (XXX given that we checked exclusiveBackupState
- * above, maybe it would be OK to just unlink any such label
- * file?)
- */
- if (stat(BACKUP_LABEL_FILE, &stat_buf) != 0)
- {
- if (errno != ENOENT)
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not stat file \"%s\": %m",
- BACKUP_LABEL_FILE)));
- }
- else
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("a backup is already in progress"),
- errhint("If you're sure there is no backup in progress, remove file \"%s\" and try again.",
- BACKUP_LABEL_FILE)));
-
- fp = AllocateFile(BACKUP_LABEL_FILE, "w");
-
- if (!fp)
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not create file \"%s\": %m",
- BACKUP_LABEL_FILE)));
- if (fwrite(labelfile->data, labelfile->len, 1, fp) != 1 ||
- fflush(fp) != 0 ||
- pg_fsync(fileno(fp)) != 0 ||
- ferror(fp) ||
- FreeFile(fp))
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not write file \"%s\": %m",
- BACKUP_LABEL_FILE)));
- /* Allocated locally for exclusive backups, so free separately */
- pfree(labelfile->data);
- pfree(labelfile);
-
- /* Write backup tablespace_map file. */
- if (tblspcmapfile->len > 0)
- {
- if (stat(TABLESPACE_MAP, &stat_buf) != 0)
- {
- if (errno != ENOENT)
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not stat file \"%s\": %m",
- TABLESPACE_MAP)));
- }
- else
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("a backup is already in progress"),
- errhint("If you're sure there is no backup in progress, remove file \"%s\" and try again.",
- TABLESPACE_MAP)));
-
- fp = AllocateFile(TABLESPACE_MAP, "w");
-
- if (!fp)
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not create file \"%s\": %m",
- TABLESPACE_MAP)));
- if (fwrite(tblspcmapfile->data, tblspcmapfile->len, 1, fp) != 1 ||
- fflush(fp) != 0 ||
- pg_fsync(fileno(fp)) != 0 ||
- ferror(fp) ||
- FreeFile(fp))
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not write file \"%s\": %m",
- TABLESPACE_MAP)));
- }
-
- /* Allocated locally for exclusive backups, so free separately */
- pfree(tblspcmapfile->data);
- pfree(tblspcmapfile);
- }
}
- PG_END_ENSURE_ERROR_CLEANUP(pg_start_backup_callback, (Datum) BoolGetDatum(exclusive));
+ PG_END_ENSURE_ERROR_CLEANUP(pg_start_backup_callback, (Datum) 0);
/*
- * Mark that start phase has correctly finished for an exclusive backup.
- * Session-level locks are updated as well to reflect that state.
- *
- * Note that CHECK_FOR_INTERRUPTS() must not occur while updating backup
- * counters and session-level lock. Otherwise they can be updated
- * inconsistently, and which might cause do_pg_abort_backup() to fail.
+ * Mark that the start phase has correctly finished for the backup.
*/
- if (exclusive)
- {
- WALInsertLockAcquireExclusive();
- XLogCtl->Insert.exclusiveBackupState = EXCLUSIVE_BACKUP_IN_PROGRESS;
-
- /* Set session-level lock */
- sessionBackupState = SESSION_BACKUP_EXCLUSIVE;
- WALInsertLockRelease();
- }
- else
- sessionBackupState = SESSION_BACKUP_NON_EXCLUSIVE;
+ sessionBackupState = SESSION_BACKUP_RUNNING;
/*
* We're done. As a convenience, return the starting WAL location.
@@ -8504,43 +8326,15 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
static void
pg_start_backup_callback(int code, Datum arg)
{
- bool exclusive = DatumGetBool(arg);
-
/* Update backup counters and forcePageWrites on failure */
WALInsertLockAcquireExclusive();
- if (exclusive)
- {
- Assert(XLogCtl->Insert.exclusiveBackupState == EXCLUSIVE_BACKUP_STARTING);
- XLogCtl->Insert.exclusiveBackupState = EXCLUSIVE_BACKUP_NONE;
- }
- else
- {
- Assert(XLogCtl->Insert.nonExclusiveBackups > 0);
- XLogCtl->Insert.nonExclusiveBackups--;
- }
- if (XLogCtl->Insert.exclusiveBackupState == EXCLUSIVE_BACKUP_NONE &&
- XLogCtl->Insert.nonExclusiveBackups == 0)
- {
- XLogCtl->Insert.forcePageWrites = false;
- }
- WALInsertLockRelease();
-}
-
-/*
- * Error cleanup callback for pg_stop_backup
- */
-static void
-pg_stop_backup_callback(int code, Datum arg)
-{
- bool exclusive = DatumGetBool(arg);
+ Assert(XLogCtl->Insert.runningBackups > 0);
+ XLogCtl->Insert.runningBackups--;
- /* Update backup status on failure */
- WALInsertLockAcquireExclusive();
- if (exclusive)
+ if (XLogCtl->Insert.runningBackups == 0)
{
- Assert(XLogCtl->Insert.exclusiveBackupState == EXCLUSIVE_BACKUP_STOPPING);
- XLogCtl->Insert.exclusiveBackupState = EXCLUSIVE_BACKUP_IN_PROGRESS;
+ XLogCtl->Insert.forcePageWrites = false;
}
WALInsertLockRelease();
}
@@ -8560,9 +8354,6 @@ get_backup_status(void)
* Utility function called at the end of an online backup. It cleans up the
* backup state and can optionally wait for WAL segments to be archived.
*
- * If labelfile is NULL, this stops an exclusive backup. Otherwise this stops
- * the non-exclusive backup specified by 'labelfile'.
- *
* Returns the last WAL location that must be present to restore from this
* backup, and the corresponding timeline ID in *stoptli_p.
*
@@ -8572,7 +8363,6 @@ get_backup_status(void)
XLogRecPtr
do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
{
- bool exclusive = (labelfile == NULL);
bool backup_started_in_recovery = false;
XLogRecPtr startpoint;
XLogRecPtr stoppoint;
@@ -8586,7 +8376,6 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
char histfilename[MAXFNAMELEN];
char backupfrom[20];
XLogSegNo _logSegNo;
- FILE *lfp;
FILE *fp;
char ch;
int seconds_before_warning;
@@ -8599,15 +8388,6 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
backup_started_in_recovery = RecoveryInProgress();
- /*
- * Currently only non-exclusive backup can be taken during recovery.
- */
- if (backup_started_in_recovery && exclusive)
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("recovery is in progress"),
- errhint("WAL control functions cannot be executed during recovery.")));
-
/*
* During recovery, we don't need to check WAL level. Because, if WAL
* level is not sufficient, it's impossible to get here during recovery.
@@ -8618,106 +8398,23 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
errmsg("WAL level not sufficient for making an online backup"),
errhint("wal_level must be set to \"replica\" or \"logical\" at server start.")));
- if (exclusive)
- {
- /*
- * At first, mark that we're now stopping an exclusive backup, to
- * ensure that there are no other sessions currently running
- * pg_start_backup() or pg_stop_backup().
- */
- WALInsertLockAcquireExclusive();
- if (XLogCtl->Insert.exclusiveBackupState != EXCLUSIVE_BACKUP_IN_PROGRESS)
- {
- WALInsertLockRelease();
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("exclusive backup not in progress")));
- }
- XLogCtl->Insert.exclusiveBackupState = EXCLUSIVE_BACKUP_STOPPING;
- WALInsertLockRelease();
-
- /*
- * Remove backup_label. In case of failure, the state for an exclusive
- * backup is switched back to in-progress.
- */
- PG_ENSURE_ERROR_CLEANUP(pg_stop_backup_callback, (Datum) BoolGetDatum(exclusive));
- {
- /*
- * Read the existing label file into memory.
- */
- struct stat statbuf;
- int r;
-
- if (stat(BACKUP_LABEL_FILE, &statbuf))
- {
- /* should not happen per the upper checks */
- if (errno != ENOENT)
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not stat file \"%s\": %m",
- BACKUP_LABEL_FILE)));
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("a backup is not in progress")));
- }
-
- lfp = AllocateFile(BACKUP_LABEL_FILE, "r");
- if (!lfp)
- {
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not read file \"%s\": %m",
- BACKUP_LABEL_FILE)));
- }
- labelfile = palloc(statbuf.st_size + 1);
- r = fread(labelfile, statbuf.st_size, 1, lfp);
- labelfile[statbuf.st_size] = '\0';
-
- /*
- * Close and remove the backup label file
- */
- if (r != 1 || ferror(lfp) || FreeFile(lfp))
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not read file \"%s\": %m",
- BACKUP_LABEL_FILE)));
- durable_unlink(BACKUP_LABEL_FILE, ERROR);
-
- /*
- * Remove tablespace_map file if present, it is created only if
- * there are tablespaces.
- */
- durable_unlink(TABLESPACE_MAP, DEBUG1);
- }
- PG_END_ENSURE_ERROR_CLEANUP(pg_stop_backup_callback, (Datum) BoolGetDatum(exclusive));
- }
-
/*
- * OK to update backup counters, forcePageWrites and session-level lock.
+ * OK to update backup counters, forcePageWrites, and session-level lock.
*
* Note that CHECK_FOR_INTERRUPTS() must not occur while updating them.
* Otherwise they can be updated inconsistently, and which might cause
* do_pg_abort_backup() to fail.
*/
WALInsertLockAcquireExclusive();
- if (exclusive)
- {
- XLogCtl->Insert.exclusiveBackupState = EXCLUSIVE_BACKUP_NONE;
- }
- else
- {
- /*
- * The user-visible pg_start/stop_backup() functions that operate on
- * exclusive backups can be called at any time, but for non-exclusive
- * backups, it is expected that each do_pg_start_backup() call is
- * matched by exactly one do_pg_stop_backup() call.
- */
- Assert(XLogCtl->Insert.nonExclusiveBackups > 0);
- XLogCtl->Insert.nonExclusiveBackups--;
- }
- if (XLogCtl->Insert.exclusiveBackupState == EXCLUSIVE_BACKUP_NONE &&
- XLogCtl->Insert.nonExclusiveBackups == 0)
+ /*
+ * It is expected that each do_pg_start_backup() call is matched by exactly
+ * one do_pg_stop_backup() call.
+ */
+ Assert(XLogCtl->Insert.runningBackups > 0);
+ XLogCtl->Insert.runningBackups--;
+
+ if (XLogCtl->Insert.runningBackups == 0)
{
XLogCtl->Insert.forcePageWrites = false;
}
@@ -8982,10 +8679,6 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
* The caller can pass 'arg' as 'true' or 'false' to control whether a warning
* is emitted.
*
- * NB: This is only for aborting a non-exclusive backup that doesn't write
- * backup_label. A backup started with pg_start_backup() needs to be finished
- * with pg_stop_backup().
- *
* NB: This gets used as a before_shmem_exit handler, hence the odd-looking
* signature.
*/
@@ -8995,18 +8688,16 @@ do_pg_abort_backup(int code, Datum arg)
bool emit_warning = DatumGetBool(arg);
/*
- * Quick exit if session is not keeping around a non-exclusive backup
- * already started.
+ * Quick exit if session does not have a running backup.
*/
- if (sessionBackupState != SESSION_BACKUP_NON_EXCLUSIVE)
+ if (sessionBackupState != SESSION_BACKUP_RUNNING)
return;
WALInsertLockAcquireExclusive();
- Assert(XLogCtl->Insert.nonExclusiveBackups > 0);
- XLogCtl->Insert.nonExclusiveBackups--;
+ Assert(XLogCtl->Insert.runningBackups > 0);
+ XLogCtl->Insert.runningBackups--;
- if (XLogCtl->Insert.exclusiveBackupState == EXCLUSIVE_BACKUP_NONE &&
- XLogCtl->Insert.nonExclusiveBackups == 0)
+ if (XLogCtl->Insert.runningBackups == 0)
{
XLogCtl->Insert.forcePageWrites = false;
}
@@ -9074,87 +8765,6 @@ GetOldestRestartPoint(XLogRecPtr *oldrecptr, TimeLineID *oldtli)
LWLockRelease(ControlFileLock);
}
-/*
- * BackupInProgress: check if online backup mode is active
- *
- * This is done by checking for existence of the "backup_label" file.
- */
-bool
-BackupInProgress(void)
-{
- struct stat stat_buf;
-
- return (stat(BACKUP_LABEL_FILE, &stat_buf) == 0);
-}
-
-/*
- * CancelBackup: rename the "backup_label" and "tablespace_map"
- * files to cancel backup mode
- *
- * If the "backup_label" file exists, it will be renamed to "backup_label.old".
- * Similarly, if the "tablespace_map" file exists, it will be renamed to
- * "tablespace_map.old".
- *
- * Note that this will render an online backup in progress
- * useless. To correctly finish an online backup, pg_stop_backup must be
- * called.
- */
-void
-CancelBackup(void)
-{
- struct stat stat_buf;
-
- /* if the backup_label file is not there, return */
- if (stat(BACKUP_LABEL_FILE, &stat_buf) < 0)
- return;
-
- /* remove leftover file from previously canceled backup if it exists */
- unlink(BACKUP_LABEL_OLD);
-
- if (durable_rename(BACKUP_LABEL_FILE, BACKUP_LABEL_OLD, DEBUG1) != 0)
- {
- ereport(WARNING,
- (errcode_for_file_access(),
- errmsg("online backup mode was not canceled"),
- errdetail("File \"%s\" could not be renamed to \"%s\": %m.",
- BACKUP_LABEL_FILE, BACKUP_LABEL_OLD)));
- return;
- }
-
- /* if the tablespace_map file is not there, return */
- if (stat(TABLESPACE_MAP, &stat_buf) < 0)
- {
- ereport(LOG,
- (errmsg("online backup mode canceled"),
- errdetail("File \"%s\" was renamed to \"%s\".",
- BACKUP_LABEL_FILE, BACKUP_LABEL_OLD)));
- return;
- }
-
- /* remove leftover file from previously canceled backup if it exists */
- unlink(TABLESPACE_MAP_OLD);
-
- if (durable_rename(TABLESPACE_MAP, TABLESPACE_MAP_OLD, DEBUG1) == 0)
- {
- ereport(LOG,
- (errmsg("online backup mode canceled"),
- errdetail("Files \"%s\" and \"%s\" were renamed to "
- "\"%s\" and \"%s\", respectively.",
- BACKUP_LABEL_FILE, TABLESPACE_MAP,
- BACKUP_LABEL_OLD, TABLESPACE_MAP_OLD)));
- }
- else
- {
- ereport(WARNING,
- (errcode_for_file_access(),
- errmsg("online backup mode canceled"),
- errdetail("File \"%s\" was renamed to \"%s\", but "
- "file \"%s\" could not be renamed to \"%s\": %m.",
- BACKUP_LABEL_FILE, BACKUP_LABEL_OLD,
- TABLESPACE_MAP, TABLESPACE_MAP_OLD)));
- }
-}
-
/* Thin wrapper around ShutdownWalRcv(). */
void
XLogShutdownWalRcv(void)
diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c
index 12e2bf4135..148b506a22 100644
--- a/src/backend/access/transam/xlogfuncs.c
+++ b/src/backend/access/transam/xlogfuncs.c
@@ -39,7 +39,7 @@
#include "utils/tuplestore.h"
/*
- * Store label file and tablespace map during non-exclusive backups.
+ * Store label file and tablespace map during backups.
*/
static StringInfo label_file;
static StringInfo tblspc_map_file;
@@ -61,101 +61,40 @@ pg_start_backup(PG_FUNCTION_ARGS)
{
text *backupid = PG_GETARG_TEXT_PP(0);
bool fast = PG_GETARG_BOOL(1);
- bool exclusive = PG_GETARG_BOOL(2);
char *backupidstr;
XLogRecPtr startpoint;
SessionBackupState status = get_backup_status();
+ MemoryContext oldcontext;
backupidstr = text_to_cstring(backupid);
- if (status == SESSION_BACKUP_NON_EXCLUSIVE)
+ if (status == SESSION_BACKUP_RUNNING)
ereport(ERROR,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("a backup is already in progress in this session")));
- if (exclusive)
- {
- startpoint = do_pg_start_backup(backupidstr, fast, NULL, NULL,
- NULL, NULL);
- }
- else
- {
- MemoryContext oldcontext;
-
- /*
- * Label file and tablespace map file need to be long-lived, since
- * they are read in pg_stop_backup.
- */
- oldcontext = MemoryContextSwitchTo(TopMemoryContext);
- label_file = makeStringInfo();
- tblspc_map_file = makeStringInfo();
- MemoryContextSwitchTo(oldcontext);
+ /*
+ * Label file and tablespace map file need to be long-lived, since
+ * they are read in pg_stop_backup.
+ */
+ oldcontext = MemoryContextSwitchTo(TopMemoryContext);
+ label_file = makeStringInfo();
+ tblspc_map_file = makeStringInfo();
+ MemoryContextSwitchTo(oldcontext);
- register_persistent_abort_backup_handler();
+ register_persistent_abort_backup_handler();
- startpoint = do_pg_start_backup(backupidstr, fast, NULL, label_file,
- NULL, tblspc_map_file);
- }
+ startpoint = do_pg_start_backup(backupidstr, fast, NULL, label_file,
+ NULL, tblspc_map_file);
PG_RETURN_LSN(startpoint);
}
-/*
- * pg_stop_backup: finish taking an on-line backup dump
- *
- * We write an end-of-backup WAL record, and remove the backup label file
- * created by pg_start_backup, creating a backup history file in pg_wal
- * instead (whence it will immediately be archived). The backup history file
- * contains the same info found in the label file, plus the backup-end time
- * and WAL location. Before 9.0, the backup-end time was read from the backup
- * history file at the beginning of archive recovery, but we now use the WAL
- * record for that and the file is for informational and debug purposes only.
- *
- * Note: different from CancelBackup which just cancels online backup mode.
- *
- * Note: this version is only called to stop an exclusive backup. The function
- * pg_stop_backup_v2 (overloaded as pg_stop_backup in SQL) is called to
- * stop non-exclusive backups.
- *
- * Permission checking for this function is managed through the normal
- * GRANT system.
- */
-Datum
-pg_stop_backup(PG_FUNCTION_ARGS)
-{
- XLogRecPtr stoppoint;
- SessionBackupState status = get_backup_status();
-
- if (status == SESSION_BACKUP_NON_EXCLUSIVE)
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("non-exclusive backup in progress"),
- errhint("Did you mean to use pg_stop_backup('f')?")));
-
- /*
- * Exclusive backups were typically started in a different connection, so
- * don't try to verify that status of backup is set to
- * SESSION_BACKUP_EXCLUSIVE in this function. Actual verification that an
- * exclusive backup is in fact running is handled inside
- * do_pg_stop_backup.
- */
- stoppoint = do_pg_stop_backup(NULL, true, NULL);
-
- PG_RETURN_LSN(stoppoint);
-}
-
/*
- * pg_stop_backup_v2: finish taking exclusive or nonexclusive on-line backup.
- *
- * Works the same as pg_stop_backup, except for non-exclusive backups it returns
- * the backup label and tablespace map files as text fields in as part of the
- * resultset.
+ * pg_stop_backup: finish taking an on-line backup.
*
- * The first parameter (variable 'exclusive') allows the user to tell us if
- * this is an exclusive or a non-exclusive backup.
- *
- * The second parameter (variable 'waitforarchive'), which is optional,
+ * The first parameter (variable 'waitforarchive'), which is optional,
* allows the user to choose if they want to wait for the WAL to be archived
* or if we should just return as soon as the WAL record is written.
*
@@ -163,7 +102,7 @@ pg_stop_backup(PG_FUNCTION_ARGS)
* GRANT system.
*/
Datum
-pg_stop_backup_v2(PG_FUNCTION_ARGS)
+pg_stop_backup(PG_FUNCTION_ARGS)
{
ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
TupleDesc tupdesc;
@@ -173,8 +112,7 @@ pg_stop_backup_v2(PG_FUNCTION_ARGS)
Datum values[3];
bool nulls[3];
- bool exclusive = PG_GETARG_BOOL(0);
- bool waitforarchive = PG_GETARG_BOOL(1);
+ bool waitforarchive = PG_GETARG_BOOL(0);
XLogRecPtr stoppoint;
SessionBackupState status = get_backup_status();
@@ -205,51 +143,29 @@ pg_stop_backup_v2(PG_FUNCTION_ARGS)
MemSet(values, 0, sizeof(values));
MemSet(nulls, 0, sizeof(nulls));
- if (exclusive)
- {
- if (status == SESSION_BACKUP_NON_EXCLUSIVE)
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("non-exclusive backup in progress"),
- errhint("Did you mean to use pg_stop_backup('f')?")));
-
- /*
- * Stop the exclusive backup, and since we're in an exclusive backup
- * return NULL for both backup_label and tablespace_map.
- */
- stoppoint = do_pg_stop_backup(NULL, waitforarchive, NULL);
-
- nulls[1] = true;
- nulls[2] = true;
- }
- else
- {
- if (status != SESSION_BACKUP_NON_EXCLUSIVE)
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("non-exclusive backup is not in progress"),
- errhint("Did you mean to use pg_stop_backup('t')?")));
+ if (status != SESSION_BACKUP_RUNNING)
+ ereport(ERROR,
+ (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ errmsg("backup is not in progress"),
+ errhint("Did you call pg_start_backup()?")));
- /*
- * Stop the non-exclusive backup. Return a copy of the backup label
- * and tablespace map so they can be written to disk by the caller.
- */
- stoppoint = do_pg_stop_backup(label_file->data, waitforarchive, NULL);
-
- values[1] = CStringGetTextDatum(label_file->data);
- values[2] = CStringGetTextDatum(tblspc_map_file->data);
-
- /* Free structures allocated in TopMemoryContext */
- pfree(label_file->data);
- pfree(label_file);
- label_file = NULL;
- pfree(tblspc_map_file->data);
- pfree(tblspc_map_file);
- tblspc_map_file = NULL;
- }
+ /*
+ * Stop the backup. Return a copy of the backup label and tablespace map so
+ * they can be written to disk by the caller.
+ */
+ stoppoint = do_pg_stop_backup(label_file->data, waitforarchive, NULL);
- /* Stoppoint is included on both exclusive and nonexclusive backups */
values[0] = LSNGetDatum(stoppoint);
+ values[1] = CStringGetTextDatum(label_file->data);
+ values[2] = CStringGetTextDatum(tblspc_map_file->data);
+
+ /* Free structures allocated in TopMemoryContext */
+ pfree(label_file->data);
+ pfree(label_file);
+ label_file = NULL;
+ pfree(tblspc_map_file->data);
+ pfree(tblspc_map_file);
+ tblspc_map_file = NULL;
tuplestore_putvalues(tupstore, tupdesc, values, nulls);
@@ -669,81 +585,6 @@ pg_wal_lsn_diff(PG_FUNCTION_ARGS)
PG_RETURN_NUMERIC(result);
}
-/*
- * Returns bool with current on-line backup mode, a global state.
- */
-Datum
-pg_is_in_backup(PG_FUNCTION_ARGS)
-{
- PG_RETURN_BOOL(BackupInProgress());
-}
-
-/*
- * Returns start time of an online exclusive backup.
- *
- * When there's no exclusive backup in progress, the function
- * returns NULL.
- */
-Datum
-pg_backup_start_time(PG_FUNCTION_ARGS)
-{
- Datum xtime;
- FILE *lfp;
- char fline[MAXPGPATH];
- char backup_start_time[30];
-
- /*
- * See if label file is present
- */
- lfp = AllocateFile(BACKUP_LABEL_FILE, "r");
- if (lfp == NULL)
- {
- if (errno != ENOENT)
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not read file \"%s\": %m",
- BACKUP_LABEL_FILE)));
- PG_RETURN_NULL();
- }
-
- /*
- * Parse the file to find the START TIME line.
- */
- backup_start_time[0] = '\0';
- while (fgets(fline, sizeof(fline), lfp) != NULL)
- {
- if (sscanf(fline, "START TIME: %25[^\n]\n", backup_start_time) == 1)
- break;
- }
-
- /* Check for a read error. */
- if (ferror(lfp))
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not read file \"%s\": %m", BACKUP_LABEL_FILE)));
-
- /* Close the backup label file. */
- if (FreeFile(lfp))
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not close file \"%s\": %m", BACKUP_LABEL_FILE)));
-
- if (strlen(backup_start_time) == 0)
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("invalid data in file \"%s\"", BACKUP_LABEL_FILE)));
-
- /*
- * Convert the time string read from file to TimestampTz form.
- */
- xtime = DirectFunctionCall3(timestamptz_in,
- CStringGetDatum(backup_start_time),
- ObjectIdGetDatum(InvalidOid),
- Int32GetDatum(-1));
-
- PG_RETURN_DATUM(xtime);
-}
-
/*
* Promotes a standby server.
*
diff --git a/src/backend/catalog/system_functions.sql b/src/backend/catalog/system_functions.sql
index fd1421788e..111eff6e14 100644
--- a/src/backend/catalog/system_functions.sql
+++ b/src/backend/catalog/system_functions.sql
@@ -377,14 +377,14 @@ BEGIN ATOMIC
END;
CREATE OR REPLACE FUNCTION
- pg_start_backup(label text, fast boolean DEFAULT false, exclusive boolean DEFAULT true)
+ pg_start_backup(label text, fast boolean DEFAULT false)
RETURNS pg_lsn STRICT VOLATILE LANGUAGE internal AS 'pg_start_backup'
PARALLEL RESTRICTED;
CREATE OR REPLACE FUNCTION pg_stop_backup (
- exclusive boolean, wait_for_archive boolean DEFAULT true,
- OUT lsn pg_lsn, OUT labelfile text, OUT spcmapfile text)
- RETURNS SETOF record STRICT VOLATILE LANGUAGE internal as 'pg_stop_backup_v2'
+ wait_for_archive boolean DEFAULT true, OUT lsn pg_lsn,
+ OUT labelfile text, OUT spcmapfile text)
+ RETURNS SETOF record STRICT VOLATILE LANGUAGE internal as 'pg_stop_backup'
PARALLEL RESTRICTED;
CREATE OR REPLACE FUNCTION
@@ -603,11 +603,9 @@ AS 'unicode_is_normalized';
-- available to superuser / cluster owner, if they choose.
--
-REVOKE EXECUTE ON FUNCTION pg_start_backup(text, boolean, boolean) FROM public;
+REVOKE EXECUTE ON FUNCTION pg_start_backup(text, boolean) FROM public;
-REVOKE EXECUTE ON FUNCTION pg_stop_backup() FROM public;
-
-REVOKE EXECUTE ON FUNCTION pg_stop_backup(boolean, boolean) FROM public;
+REVOKE EXECUTE ON FUNCTION pg_stop_backup(boolean) FROM public;
REVOKE EXECUTE ON FUNCTION pg_create_restore_point(text) FROM public;
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index 80bb269599..b6767ed72e 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -348,7 +348,6 @@ static PMState pmState = PM_INIT;
typedef enum
{
ALLOW_ALL_CONNS, /* normal not-shutting-down state */
- ALLOW_SUPERUSER_CONNS, /* only superusers can connect */
ALLOW_NO_CONNS /* no new connections allowed, period */
} ConnsAllowedState;
@@ -2546,19 +2545,11 @@ canAcceptConnections(int backend_type)
/*
* "Smart shutdown" restrictions are applied only to normal connections,
- * not to autovac workers or bgworkers. When only superusers can connect,
- * we return CAC_SUPERUSER to indicate that superuserness must be checked
- * later. Note that neither CAC_OK nor CAC_SUPERUSER can safely be
- * returned until we have checked for too many children.
+ * not to autovac workers or bgworkers.
*/
if (connsAllowed != ALLOW_ALL_CONNS &&
backend_type == BACKEND_TYPE_NORMAL)
- {
- if (connsAllowed == ALLOW_SUPERUSER_CONNS)
- result = CAC_SUPERUSER; /* allow superusers only */
- else
- return CAC_SHUTDOWN; /* shutdown is pending */
- }
+ return CAC_SHUTDOWN; /* shutdown is pending */
/*
* Don't start too many children.
@@ -2877,16 +2868,11 @@ pmdie(SIGNAL_ARGS)
#endif
/*
- * If we reached normal running, we have to wait for any online
- * backup mode to end; otherwise go straight to waiting for client
- * backends to exit. (The difference is that in the former state,
- * we'll still let in new superuser clients, so that somebody can
- * end the online backup mode.) If already in PM_STOP_BACKENDS or
+ * If we reached normal running, we go straight to waiting for
+ * client backends to exit. If already in PM_STOP_BACKENDS or
* a later state, do not change it.
*/
- if (pmState == PM_RUN)
- connsAllowed = ALLOW_SUPERUSER_CONNS;
- else if (pmState == PM_HOT_STANDBY)
+ if (pmState == PM_RUN || pmState == PM_HOT_STANDBY)
connsAllowed = ALLOW_NO_CONNS;
else if (pmState == PM_STARTUP || pmState == PM_RECOVERY)
{
@@ -3842,16 +3828,6 @@ PostmasterStateMachine(void)
/* If we're doing a smart shutdown, try to advance that state. */
if (pmState == PM_RUN || pmState == PM_HOT_STANDBY)
{
- if (connsAllowed == ALLOW_SUPERUSER_CONNS)
- {
- /*
- * ALLOW_SUPERUSER_CONNS state ends as soon as online backup mode
- * is not active.
- */
- if (!BackupInProgress())
- connsAllowed = ALLOW_NO_CONNS;
- }
-
if (connsAllowed == ALLOW_NO_CONNS)
{
/*
@@ -4044,18 +4020,6 @@ PostmasterStateMachine(void)
}
else
{
- /*
- * Terminate exclusive backup mode to avoid recovery after a clean
- * fast shutdown. Since an exclusive backup can only be taken
- * during normal running (and not, for example, while running
- * under Hot Standby) it only makes sense to do this if we reached
- * normal running. If we're still in recovery, the backup file is
- * one we're recovering *from*, and we must keep it around so that
- * recovery restarts from the right place.
- */
- if (ReachedNormalRunning)
- CancelBackup();
-
/*
* Normal exit from the postmaster is here. We don't need to log
* anything here, since the UnlinkLockFiles proc_exit callback
diff --git a/src/backend/replication/basebackup.c b/src/backend/replication/basebackup.c
index 0bf28b55d7..4682b28a85 100644
--- a/src/backend/replication/basebackup.c
+++ b/src/backend/replication/basebackup.c
@@ -195,10 +195,8 @@ static const struct exclude_list_item excludeFiles[] =
{RELCACHE_INIT_FILENAME, true},
/*
- * If there's a backup_label or tablespace_map file, it belongs to a
- * backup started by the user with pg_start_backup(). It is *not* correct
- * for this backup. Our backup_label/tablespace_map is injected into the
- * tar separately.
+ * backup_label and tablespace_map should not exist in in a running cluster
+ * capable of doing an online backup, but exclude then just in case.
*/
{BACKUP_LABEL_FILE, false},
{TABLESPACE_MAP, false},
diff --git a/src/bin/pg_basebackup/t/010_pg_basebackup.pl b/src/bin/pg_basebackup/t/010_pg_basebackup.pl
index 75d6810d3e..bd6ff92f9a 100644
--- a/src/bin/pg_basebackup/t/010_pg_basebackup.pl
+++ b/src/bin/pg_basebackup/t/010_pg_basebackup.pl
@@ -185,6 +185,10 @@ isnt(slurp_file("$tempdir/backup/backup_label"),
'DONOTCOPY', 'existing backup_label not copied');
rmtree("$tempdir/backup");
+# Now delete the bogus backup_label file since it will interfere with startup
+unlink("$pgdata/backup_label")
+ or BAIL_OUT("unable to unlink $pgdata/backup_label");
+
$node->command_ok(
[
@pg_basebackup_defs, '-D',
diff --git a/src/bin/pg_rewind/filemap.c b/src/bin/pg_rewind/filemap.c
index 7211090f47..fb52debf7a 100644
--- a/src/bin/pg_rewind/filemap.c
+++ b/src/bin/pg_rewind/filemap.c
@@ -140,9 +140,9 @@ static const struct exclude_list_item excludeFiles[] =
{"pg_internal.init", true}, /* defined as RELCACHE_INIT_FILENAME */
/*
- * If there's a backup_label or tablespace_map file, it belongs to a
- * backup started by the user with pg_start_backup(). It is *not* correct
- * for this backup. Our backup_label is written later on separately.
+ * If there is a backup_label or tablespace_map file, it indicates that
+ * a recovery failed and this cluster probably can't be rewound, but
+ * exclude them anyway if they are found.
*/
{"backup_label", false}, /* defined as BACKUP_LABEL_FILE */
{"tablespace_map", false}, /* defined as TABLESPACE_MAP */
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index 4b45ac64db..00a3d14c76 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -275,8 +275,7 @@ extern void XLogShutdownWalRcv(void);
typedef enum SessionBackupState
{
SESSION_BACKUP_NONE,
- SESSION_BACKUP_EXCLUSIVE,
- SESSION_BACKUP_NON_EXCLUSIVE
+ SESSION_BACKUP_RUNNING,
} SessionBackupState;
extern XLogRecPtr do_pg_start_backup(const char *backupidstr, bool fast,
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 7f1ee97f55..8f126e2f54 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -6275,25 +6275,15 @@
prosrc => 'pg_terminate_backend' },
{ oid => '2172', descr => 'prepare for taking an online backup',
proname => 'pg_start_backup', provolatile => 'v', proparallel => 'r',
- prorettype => 'pg_lsn', proargtypes => 'text bool bool',
+ prorettype => 'pg_lsn', proargtypes => 'text bool',
prosrc => 'pg_start_backup' },
-{ oid => '2173', descr => 'finish taking an online backup',
- proname => 'pg_stop_backup', provolatile => 'v', proparallel => 'r',
- prorettype => 'pg_lsn', proargtypes => '', prosrc => 'pg_stop_backup' },
{ oid => '2739', descr => 'finish taking an online backup',
proname => 'pg_stop_backup', prorows => '1', proretset => 't',
provolatile => 'v', proparallel => 'r', prorettype => 'record',
- proargtypes => 'bool bool', proallargtypes => '{bool,bool,pg_lsn,text,text}',
- proargmodes => '{i,i,o,o,o}',
- proargnames => '{exclusive,wait_for_archive,lsn,labelfile,spcmapfile}',
- prosrc => 'pg_stop_backup_v2' },
-{ oid => '3813', descr => 'true if server is in online backup',
- proname => 'pg_is_in_backup', provolatile => 'v', prorettype => 'bool',
- proargtypes => '', prosrc => 'pg_is_in_backup' },
-{ oid => '3814', descr => 'start time of an online backup',
- proname => 'pg_backup_start_time', provolatile => 's',
- prorettype => 'timestamptz', proargtypes => '',
- prosrc => 'pg_backup_start_time' },
+ proargtypes => 'bool', proallargtypes => '{bool,pg_lsn,text,text}',
+ proargmodes => '{i,o,o,o}',
+ proargnames => '{wait_for_archive,lsn,labelfile,spcmapfile}',
+ prosrc => 'pg_stop_backup' },
{ oid => '3436', descr => 'promote standby server',
proname => 'pg_promote', provolatile => 'v', prorettype => 'bool',
proargtypes => 'bool int4', proargnames => '{wait,wait_seconds}',
diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h
index 0abc3ad540..9321d7f264 100644
--- a/src/include/miscadmin.h
+++ b/src/include/miscadmin.h
@@ -481,10 +481,6 @@ extern void process_session_preload_libraries(void);
extern void pg_bindtextdomain(const char *domain);
extern bool has_rolreplication(Oid roleid);
-/* in access/transam/xlog.c */
-extern bool BackupInProgress(void);
-extern void CancelBackup(void);
-
/* in executor/nodeHash.c */
extern size_t get_hash_memory_limit(void);
diff --git a/src/test/perl/PostgreSQL/Test/Cluster.pm b/src/test/perl/PostgreSQL/Test/Cluster.pm
index be05845248..065670b5c1 100644
--- a/src/test/perl/PostgreSQL/Test/Cluster.pm
+++ b/src/test/perl/PostgreSQL/Test/Cluster.pm
@@ -634,25 +634,6 @@ sub backup
return;
}
-=item $node->backup_fs_hot(backup_name)
-
-Create a backup with a filesystem level copy in subdirectory B<backup_name> of
-B<< $node->backup_dir >>, including WAL.
-
-Archiving must be enabled, as B<pg_start_backup()> and B<pg_stop_backup()> are
-used. This is not checked or enforced.
-
-The backup name is passed as the backup label to B<pg_start_backup()>.
-
-=cut
-
-sub backup_fs_hot
-{
- my ($self, $backup_name) = @_;
- $self->_backup_fs($backup_name, 1);
- return;
-}
-
=item $node->backup_fs_cold(backup_name)
Create a backup with a filesystem level copy in subdirectory B<backup_name> of
@@ -666,53 +647,18 @@ Use B<backup> or B<backup_fs_hot> if you want to back up a running server.
sub backup_fs_cold
{
my ($self, $backup_name) = @_;
- $self->_backup_fs($backup_name, 0);
- return;
-}
-
-
-# Common sub of backup_fs_hot and backup_fs_cold
-sub _backup_fs
-{
- my ($self, $backup_name, $hot) = @_;
- my $backup_path = $self->backup_dir . '/' . $backup_name;
- my $port = $self->port;
- my $name = $self->name;
-
- print "# Taking filesystem backup $backup_name from node \"$name\"\n";
-
- if ($hot)
- {
- my $stdout = $self->safe_psql('postgres',
- "SELECT * FROM pg_start_backup('$backup_name');");
- print "# pg_start_backup: $stdout\n";
- }
PostgreSQL::Test::RecursiveCopy::copypath(
$self->data_dir,
- $backup_path,
+ $self->backup_dir . '/' . $backup_name,
filterfn => sub {
my $src = shift;
return ($src ne 'log' and $src ne 'postmaster.pid');
});
- if ($hot)
- {
-
- # We ignore pg_stop_backup's return value. We also assume archiving
- # is enabled; otherwise the caller will have to copy the remaining
- # segments.
- my $stdout =
- $self->safe_psql('postgres', 'SELECT * FROM pg_stop_backup();');
- print "# pg_stop_backup: $stdout\n";
- }
-
- print "# Backup finished\n";
return;
}
-
-
=pod
=item $node->init_from_backup(root_node, backup_name)
diff --git a/src/test/recovery/t/010_logical_decoding_timelines.pl b/src/test/recovery/t/010_logical_decoding_timelines.pl
index 6e8b0b1b96..6351633b50 100644
--- a/src/test/recovery/t/010_logical_decoding_timelines.pl
+++ b/src/test/recovery/t/010_logical_decoding_timelines.pl
@@ -69,7 +69,9 @@ $node_primary->safe_psql('dropme',
$node_primary->safe_psql('postgres', 'CHECKPOINT;');
my $backup_name = 'b1';
-$node_primary->backup_fs_hot($backup_name);
+$node_primary->stop();
+$node_primary->backup_fs_cold($backup_name);
+$node_primary->start();
$node_primary->safe_psql('postgres',
q[SELECT pg_create_physical_replication_slot('phys_slot');]);
--
2.25.1
The following review has been posted through the commitfest application:
make installcheck-world: tested, passed
Implements feature: tested, passed
Spec compliant: not tested
Documentation: not tested
This patch applies cleanly for me and passes installcheck-world.
I have not yet studied all of the changes in detail.
Some proofreading nits in the documentation: the pg_stop_backup
with arguments has lost the 'exclusive' argument, but still shows a comma
before the 'wait_for_archive' argument. And the niladic pg_stop_backup
is still documented, though it no longer exists.
My biggest concerns are the changes to the SQL-visible pg_start_backup
and pg_stop_backup functions. When the non-exclusive API was implemented
(in 7117685), that was done with care (with a new optional argument to
pg_start_backup, and a new overload of pg_stop_backup) to avoid immediate
breakage of working backup scripts.
With this patch, even scripts that were dutifully migrated to that new API and
now invoke pg_start_backup(label, false) or (label, exclusive => false) will
immediately and unnecessarily break. What I would suggest for this patch
would be to change the exclusive default from true to false, and have the
function report an ERROR if true is passed.
Otherwise, for sites using a third-party backup solution, there will be an
unnecessary requirement to synchronize a PostgreSQL upgrade with an
upgrade of the backup solution that won't be broken by the change. For
a site with their backup procedures scripted in-house, there will be an
unnecessarily urgent need for the current admin team to study and patch
the currently-working scripts.
That can be avoided by just changing the default to false and rejecting calls
where true is passed. That will break only scripts that never got the memo
about moving to non-exclusive backup, available for six years now.
Assuming the value is false, so no error is thrown, is it practical to determine
from flinfo->fn_expr whether the value was defaulted or supplied? If so, I would
further suggest reporting a deprecation WARNING if it was explicitly supplied,
with a HINT that the argument can simply be removed at the call site, and will
become unrecognized in some future release.
pg_stop_backup needs thought, because 7117685 added a new overload for that
function, rather than just an optional argument. This patch removes the old
niladic version that returned pg_lsn, leaving just one version, with an optional
argument, that returns a record.
Here again, the old niladic one was only suitable for exclusive backups, so there
can't be any script existing in 2022 that still calls that unless it has never been
updated in six years to nonexclusive backups, and that breakage can't be
helped.
Any scripts that did get dutifully updated over the last six years will be calling the
record-returning version, passing false, or exclusive => false. This patch as it
stands will unnecessarily break those, but here again I think that can be avoided
just by making the exclusive parameter optional with default false, and reporting
an error if true is passed.
Here again, I would consider also issuing a deprecation warning if the argument
is explicitly supplied, if it is practical to determine that from fn_expr. (I haven't
looked yet to see how practical that is.)
Regards,
-Chap
On 02/26/22 11:48, Chapman Flack wrote:
This patch applies cleanly for me and passes installcheck-world.
I have not yet studied all of the changes in detail.
I've now looked through the rest, and the only further thing I noticed
was that xlog.c's do_pg_start_backup still has a tablespaces parameter
to receive a List* of tablespaces if the caller wants, but this patch
removes the comment describing it:
- * If "tablespaces" isn't NULL, it receives a list of tablespaceinfo structs
- * describing the cluster's tablespaces.
which seems like collateral damage.
Regards,
-Chap
On Sat, Feb 26, 2022 at 04:48:52PM +0000, Chapman Flack wrote:
My biggest concerns are the changes to the SQL-visible pg_start_backup
and pg_stop_backup functions. When the non-exclusive API was implemented
(in 7117685), that was done with care (with a new optional argument to
pg_start_backup, and a new overload of pg_stop_backup) to avoid immediate
breakage of working backup scripts.With this patch, even scripts that were dutifully migrated to that new API and
now invoke pg_start_backup(label, false) or (label, exclusive => false) will
immediately and unnecessarily break. What I would suggest for this patch
would be to change the exclusive default from true to false, and have the
function report an ERROR if true is passed.Otherwise, for sites using a third-party backup solution, there will be an
unnecessary requirement to synchronize a PostgreSQL upgrade with an
upgrade of the backup solution that won't be broken by the change. For
a site with their backup procedures scripted in-house, there will be an
unnecessarily urgent need for the current admin team to study and patch
the currently-working scripts.That can be avoided by just changing the default to false and rejecting calls
where true is passed. That will break only scripts that never got the memo
about moving to non-exclusive backup, available for six years now.Assuming the value is false, so no error is thrown, is it practical to determine
from flinfo->fn_expr whether the value was defaulted or supplied? If so, I would
further suggest reporting a deprecation WARNING if it was explicitly supplied,
with a HINT that the argument can simply be removed at the call site, and will
become unrecognized in some future release.
This is a good point. I think I agree with your proposed changes. I
believe it is possible to add a deprecation warning only when 'exclusive'
is specified. If anything, we can create a separate function that accepts
the 'exclusive' parameter and that always emits a NOTICE or WARNING.
pg_stop_backup needs thought, because 7117685 added a new overload for that
function, rather than just an optional argument. This patch removes the old
niladic version that returned pg_lsn, leaving just one version, with an optional
argument, that returns a record.Here again, the old niladic one was only suitable for exclusive backups, so there
can't be any script existing in 2022 that still calls that unless it has never been
updated in six years to nonexclusive backups, and that breakage can't be
helped.Any scripts that did get dutifully updated over the last six years will be calling the
record-returning version, passing false, or exclusive => false. This patch as it
stands will unnecessarily break those, but here again I think that can be avoided
just by making the exclusive parameter optional with default false, and reporting
an error if true is passed.Here again, I would consider also issuing a deprecation warning if the argument
is explicitly supplied, if it is practical to determine that from fn_expr. (I haven't
looked yet to see how practical that is.)
Agreed. I will look into updating this one, too. I think the 'exclusive'
parameter should remain documented for now for both pg_start_backup() and
pg_stop_backup(), but this documentation will just note that it is there
for backward compatibility and must be set to false.
--
Nathan Bossart
Amazon Web Services: https://aws.amazon.com
On Sat, Feb 26, 2022 at 05:03:04PM -0500, Chapman Flack wrote:
I've now looked through the rest, and the only further thing I noticed
was that xlog.c's do_pg_start_backup still has a tablespaces parameter
to receive a List* of tablespaces if the caller wants, but this patch
removes the comment describing it:- * If "tablespaces" isn't NULL, it receives a list of tablespaceinfo structs
- * describing the cluster's tablespaces.which seems like collateral damage.
Thanks. I will fix this and the proofreading nits you noted upthread in
the next revision.
--
Nathan Bossart
Amazon Web Services: https://aws.amazon.com
On Sat, Feb 26, 2022 at 02:06:14PM -0800, Nathan Bossart wrote:
On Sat, Feb 26, 2022 at 04:48:52PM +0000, Chapman Flack wrote:
Assuming the value is false, so no error is thrown, is it practical to determine
from flinfo->fn_expr whether the value was defaulted or supplied? If so, I would
further suggest reporting a deprecation WARNING if it was explicitly supplied,
with a HINT that the argument can simply be removed at the call site, and will
become unrecognized in some future release.This is a good point. I think I agree with your proposed changes. I
believe it is possible to add a deprecation warning only when 'exclusive'
is specified. If anything, we can create a separate function that accepts
the 'exclusive' parameter and that always emits a NOTICE or WARNING.
I've spent some time looking into this, and I haven't found a clean way to
emit a WARNING only if the "exclusive" parameter is supplied (and set to
false). AFAICT flinfo->fn_expr doesn't tell us whether the parameter was
supplied or the default value was used. I was able to get it working by
splitting pg_start_backup() into 3 separate internal functions (i.e.,
pg_start_backup_1arg(), pg_start_backup_2arg(), and
pg_start_backup_3arg()), but this breaks calls such as
pg_start_backup('mylabel', exclusive => false), and it might complicate
privilege management for users.
Without a WARNING, I think it will be difficult to justify removing the
"exclusive" parameter in the future. We would either need to leave it
around forever, or we would have to risk unnecessarily breaking some
working backup scripts. I wonder if we should just remove it now and make
sure that this change is well-documented in the release notes.
--
Nathan Bossart
Amazon Web Services: https://aws.amazon.com
On 2/28/22 23:51, Nathan Bossart wrote:
On Sat, Feb 26, 2022 at 02:06:14PM -0800, Nathan Bossart wrote:
On Sat, Feb 26, 2022 at 04:48:52PM +0000, Chapman Flack wrote:
Assuming the value is false, so no error is thrown, is it practical to determine
from flinfo->fn_expr whether the value was defaulted or supplied? If so, I would
further suggest reporting a deprecation WARNING if it was explicitly supplied,
with a HINT that the argument can simply be removed at the call site, and will
become unrecognized in some future release.This is a good point. I think I agree with your proposed changes. I
believe it is possible to add a deprecation warning only when 'exclusive'
is specified. If anything, we can create a separate function that accepts
the 'exclusive' parameter and that always emits a NOTICE or WARNING.I've spent some time looking into this, and I haven't found a clean way to
emit a WARNING only if the "exclusive" parameter is supplied (and set to
false). AFAICT flinfo->fn_expr doesn't tell us whether the parameter was
supplied or the default value was used. I was able to get it working by
splitting pg_start_backup() into 3 separate internal functions (i.e.,
pg_start_backup_1arg(), pg_start_backup_2arg(), and
pg_start_backup_3arg()), but this breaks calls such as
pg_start_backup('mylabel', exclusive => false), and it might complicate
privilege management for users.Without a WARNING, I think it will be difficult to justify removing the
"exclusive" parameter in the future. We would either need to leave it
around forever, or we would have to risk unnecessarily breaking some
working backup scripts. I wonder if we should just remove it now and make
sure that this change is well-documented in the release notes.
Personally, I am in favor of removing it. We change/rename
functions/tables/views when we need to, and this happens in almost every
release.
What we need to do is make sure that an older installation won't
silently work in a broken way, i.e. if we remove the exclusive flag
somebody expecting the pre-9.6 behavior might not receive an error and
think everything is OK. That would not be good.
One option might be to rename the functions. Something like
pg_backup_start/stop.
Regards,
-David
On Tue, Mar 01, 2022 at 08:44:51AM -0600, David Steele wrote:
Personally, I am in favor of removing it. We change/rename
functions/tables/views when we need to, and this happens in almost every
release.What we need to do is make sure that an older installation won't silently
work in a broken way, i.e. if we remove the exclusive flag somebody
expecting the pre-9.6 behavior might not receive an error and think
everything is OK. That would not be good.One option might be to rename the functions. Something like
pg_backup_start/stop.
I'm fine with this approach.
--
Nathan Bossart
Amazon Web Services: https://aws.amazon.com
On 03/01/22 09:44, David Steele wrote:
Personally, I am in favor of removing it. We change/rename
functions/tables/views when we need to, and this happens in almost every
release.
For clarification, is that a suggestion to remove the 'exclusive' parameter
in some later release, after using this release to default it to false and
reject calls with true?
I can get behind that proposal, even if we don't have a practical way
to add the warning I suggested. I'd be happier with the warning, but can
live without it. Release notes can be the warning.
That way, at least, there would be a period of time where procedures
that currently work (by passing exclusive => false) would continue to work,
and could be adapted as time permits by removing that argument, with no
behavioral change.
The later release removing the argument would then break only procedures
that had never done so. That's comparable to what's proposed for this
release, which will only break procedures that have never migrated away
from exclusive mode despite the time and notice to do so.
That seems ok to me.
Regards,
-Chap
Greetings,
* Nathan Bossart (nathandbossart@gmail.com) wrote:
On Tue, Mar 01, 2022 at 08:44:51AM -0600, David Steele wrote:
Personally, I am in favor of removing it. We change/rename
functions/tables/views when we need to, and this happens in almost every
release.What we need to do is make sure that an older installation won't silently
work in a broken way, i.e. if we remove the exclusive flag somebody
expecting the pre-9.6 behavior might not receive an error and think
everything is OK. That would not be good.One option might be to rename the functions. Something like
pg_backup_start/stop.I'm fine with this approach.
+1.
Thanks,
Stephen
On Tue, Mar 01, 2022 at 11:09:13AM -0500, Chapman Flack wrote:
On 03/01/22 09:44, David Steele wrote:
Personally, I am in favor of removing it. We change/rename
functions/tables/views when we need to, and this happens in almost every
release.For clarification, is that a suggestion to remove the 'exclusive' parameter
in some later release, after using this release to default it to false and
reject calls with true?
My suggestion was to remove it in v15. My impression is that David and
Stephen agree, but I could be misinterpreting their responses.
That way, at least, there would be a period of time where procedures
that currently work (by passing exclusive => false) would continue to work,
and could be adapted as time permits by removing that argument, with no
behavioral change.
I'm not sure if there's any advantage to kicking the can down the road. At
some point, we'll need to break existing backup scripts. Will we be more
prepared to do that in v17 than we are now? We could maintain two sets of
functions for a few releases and make it really clear in the documentation
that pg_start/stop_backup() are going to be removed soon (and always emit a
WARNING when they are used). Would that address your concerns?
--
Nathan Bossart
Amazon Web Services: https://aws.amazon.com
On 3/1/22 11:32, Nathan Bossart wrote:
On Tue, Mar 01, 2022 at 11:09:13AM -0500, Chapman Flack wrote:
On 03/01/22 09:44, David Steele wrote:
Personally, I am in favor of removing it. We change/rename
functions/tables/views when we need to, and this happens in almost every
release.For clarification, is that a suggestion to remove the 'exclusive' parameter
in some later release, after using this release to default it to false and
reject calls with true?My suggestion was to remove it in v15. My impression is that David and
Stephen agree, but I could be misinterpreting their responses.
I agree and I'm pretty sure Stephen does as well.
That way, at least, there would be a period of time where procedures
that currently work (by passing exclusive => false) would continue to work,
and could be adapted as time permits by removing that argument, with no
behavioral change.I'm not sure if there's any advantage to kicking the can down the road. At
some point, we'll need to break existing backup scripts. Will we be more
prepared to do that in v17 than we are now? We could maintain two sets of
functions for a few releases and make it really clear in the documentation
that pg_start/stop_backup() are going to be removed soon (and always emit a
WARNING when they are used). Would that address your concerns?
I think people are going to complain no matter what. If scripts are
being maintained changing the name is not a big deal (though moving from
exclusive to non-exclusive may be). If they aren't being maintained then
they'll just blow up a few versions down the road when we remove the
compatibility functions.
Regards,
-David
On 03/01/22 12:32, Nathan Bossart wrote:
On Tue, Mar 01, 2022 at 11:09:13AM -0500, Chapman Flack wrote:
That way, at least, there would be a period of time where procedures
that currently work (by passing exclusive => false) would continue to work,
and could be adapted as time permits by removing that argument, with no
behavioral change.I'm not sure if there's any advantage to kicking the can down the road. At
some point, we'll need to break existing backup scripts. Will we be more
prepared to do that in v17 than we are now?
Yes, if we have provided a transition period the way we did in 7117685.
The way the on-ramp to that transition worked:
- Initially, your procedures used exclusive mode.
- If you changed nothing, they continued to work, with no behavior change.
- You then had ample time to adapt them to non-exclusive mode so now
they work that way.
- You knew a day would come (here it comes) where, if you've never
gotten around to doing that, your unchanged exclusive-mode procedures
are going to break.
So here we are, arrived at that day. If you're still using exclusive mode,
your stuff's going to break; serves you right. So now limit the cases we
care about to people who made use of the time they were given to change
their procedures to use exclusive => false. So the off-ramp can look like:
- Initially, your procedures pass exclusive => false.
- If you change nothing, they should continue to work, with no
behavior change.
- You should then have ample time to change to a new spelling without
exclusive => false, and have them work that way.
- You know some later day is coming where, if you've never
gotten around to doing that, they're going to break.
Then, when that day comes, if you're still passing exclusive at all,
your stuff's going to break; serves you right. If you have made use of
the time you were given for the changes, you'll be fine. So yes, at that
point, I think we can do it with clear conscience. We'll have made the
off-ramp as smooth and navigable as the on-ramp was.
We could maintain two sets of
functions for a few releases and make it really clear in the documentation
that pg_start/stop_backup() are going to be removed soon (and always emit a
WARNING when they are used). Would that address your concerns?
That would. I had been thinking of not changing the names, and just making
the parameter go away. But I wasn't thinking of your concern here:
What we need to do is make sure that an older installation won't silently
work in a broken way, i.e. if we remove the exclusive flag somebody
expecting the pre-9.6 behavior might not receive an error and think
everything is OK. That would not be good.
So I'm ok with changing the names. Then step 3 of the off-ramp
would just be to call the functions by the new names, as well as to drop
the exclusive => false.
The thing I'd want to avoid is just, after the trouble that was taken
to make the on-ramp navigable, making the off-ramp be a cliff.
Regards,
-Chap
On 03/01/22 13:22, David Steele wrote:
I think people are going to complain no matter what. If scripts are being
maintained changing the name is not a big deal (though moving from exclusive
to non-exclusive may be). If they aren't being maintained then they'll just
blow up a few versions down the road when we remove the compatibility
functions.
I might have already said enough in the message that crossed with this,
but I think what I'm saying is there's a less-binary distinction between
scripts that are/aren't "being maintained".
There can't really be many teams out there thinking "we'll just ignore
these scripts forever, and nothing bad will happen." They all know they'll
have to do stuff sometimes. But it matters how we allow them to schedule it.
In the on-ramp, at first there was only exclusive. Then there were both
modes, with exclusive being deprecated, so teams knew they'd need to do
stuff, and most by now probably have. They were able to do separation of
hazards and schedule that work; they did not have to pile it onto the
whole plate of "upgrade PG from 9.5 to 9.6 and make sure everything works".
So now we're dropping the other shoe: first there was one mode, then both,
now there's only the other one. Again there's some work for teams to do;
let's again allow them to separate hazards and schedule that work apart
from the whole 14 to 15 upgrade project.
We can't help getting complaints in the off-ramp from anybody who ignored
the on-ramp. But we can avoid clobbering the teams who dutifully played
along before, and only want the same space to do so now.
Regards,
-Chap
Greetings,
* David Steele (david@pgmasters.net) wrote:
On 3/1/22 11:32, Nathan Bossart wrote:
On Tue, Mar 01, 2022 at 11:09:13AM -0500, Chapman Flack wrote:
On 03/01/22 09:44, David Steele wrote:
Personally, I am in favor of removing it. We change/rename
functions/tables/views when we need to, and this happens in almost every
release.For clarification, is that a suggestion to remove the 'exclusive' parameter
in some later release, after using this release to default it to false and
reject calls with true?My suggestion was to remove it in v15. My impression is that David and
Stephen agree, but I could be misinterpreting their responses.I agree and I'm pretty sure Stephen does as well.
Yes, +1 to removing it.
That way, at least, there would be a period of time where procedures
that currently work (by passing exclusive => false) would continue to work,
and could be adapted as time permits by removing that argument, with no
behavioral change.I'm not sure if there's any advantage to kicking the can down the road. At
some point, we'll need to break existing backup scripts. Will we be more
prepared to do that in v17 than we are now? We could maintain two sets of
functions for a few releases and make it really clear in the documentation
that pg_start/stop_backup() are going to be removed soon (and always emit a
WARNING when they are used). Would that address your concerns?I think people are going to complain no matter what. If scripts are being
maintained changing the name is not a big deal (though moving from exclusive
to non-exclusive may be). If they aren't being maintained then they'll just
blow up a few versions down the road when we remove the compatibility
functions.
I don't consider "maintained" and "still using the exclusive backup
method" to both be able to be true at the same time.
Thanks,
Stephen
Greetings,
* Chapman Flack (chap@anastigmatix.net) wrote:
On 03/01/22 13:22, David Steele wrote:
I think people are going to complain no matter what. If scripts are being
maintained changing the name is not a big deal (though moving from exclusive
to non-exclusive may be). If they aren't being maintained then they'll just
blow up a few versions down the road when we remove the compatibility
functions.I might have already said enough in the message that crossed with this,
but I think what I'm saying is there's a less-binary distinction between
scripts that are/aren't "being maintained".There can't really be many teams out there thinking "we'll just ignore
these scripts forever, and nothing bad will happen." They all know they'll
have to do stuff sometimes. But it matters how we allow them to schedule it.
We only make these changes between major versions. That's as much as we
should be required to provide.
Further, we seriously changed around how restores work a few versions
back and there was rather little complaining.
Thanks,
Stephen
On 03/01/22 14:14, Stephen Frost wrote:
There can't really be many teams out there thinking "we'll just ignore
these scripts forever, and nothing bad will happen." They all know they'll
have to do stuff sometimes. But it matters how we allow them to schedule it.We only make these changes between major versions. That's as much as we
should be required to provide.
It's an OSS project, so I guess we're not required to provide anything.
But in the course of this multi-release exclusive to non-exclusive
transition, we already demonstrated, in 7117685, that we can avoid
inflicting immediate breakage when there's nothing in our objective
that inherently requires it, and avoiding it is relatively easy.
I can't bring myself to think that was a bad precedent.
Now, granted, the difference between the adaptations being required then
and the ones required now is that those required both: changes to some
function calls, and corresponding changes to how the scripts handled
label and tablespace files. Here, it's only a clerical update to some
function calls.
So if I'm outvoted here and the reason is "look, a lighter burden is
involved this time than that time", then ok. I would rather bow to that
argument on the specific facts of one case than abandon the precedent
from 7117685 generally.
Regards,
-Chap
Greetings,
* Chapman Flack (chap@anastigmatix.net) wrote:
On 03/01/22 14:14, Stephen Frost wrote:
There can't really be many teams out there thinking "we'll just ignore
these scripts forever, and nothing bad will happen." They all know they'll
have to do stuff sometimes. But it matters how we allow them to schedule it.We only make these changes between major versions. That's as much as we
should be required to provide.It's an OSS project, so I guess we're not required to provide anything.
But in the course of this multi-release exclusive to non-exclusive
transition, we already demonstrated, in 7117685, that we can avoid
inflicting immediate breakage when there's nothing in our objective
that inherently requires it, and avoiding it is relatively easy.I can't bring myself to think that was a bad precedent.
It's actively bad because we are ridiculously inconsistent when it comes
to these things and we're terrible about ever removing anything once
it's gotten into the tree as 'deprecated'. Witness that it's 8 years
since 7117685 and we still have these old and clearly broken APIs
around. We absolutely need to move *away* from this approach, exactly
how 2dedf4d9, much more recently than 7117685, for all of its other
flaws, did.
So if I'm outvoted here and the reason is "look, a lighter burden is
involved this time than that time", then ok. I would rather bow to that
argument on the specific facts of one case than abandon the precedent
from 7117685 generally.
It's far from precedent- if anything, it's quite the opposite from how
most changes around here are made, and much more recent commits in the
same area clearly tossed out entirely the idea of trying to maintain
some kind of backwards compatibility with existing scripts.
Thanks,
Stephen
Here is a new version of the patch with the following changes:
1. Addressed Chap's feedback from upthread.
2. Renamed pg_start/stop_backup() to pg_backup_start/stop() as
suggested by David.
3. A couple of other small documentation adjustments.
--
Nathan Bossart
Amazon Web Services: https://aws.amazon.com
Attachments:
v4-0001-remove-exclusive-backup-mode.patchtext/x-diff; charset=us-asciiDownload
From 7119f9063f22652fca1e2a44fdf6b4b6b3fbf679 Mon Sep 17 00:00:00 2001
From: Nathan Bossart <bossartn@amazon.com>
Date: Wed, 1 Dec 2021 23:50:49 +0000
Subject: [PATCH v4 1/1] remove exclusive backup mode
---
doc/src/sgml/backup.sgml | 188 +------
doc/src/sgml/func.sgml | 99 +---
doc/src/sgml/high-availability.sgml | 6 +-
doc/src/sgml/monitoring.sgml | 4 +-
doc/src/sgml/ref/pgupgrade.sgml | 2 +-
src/backend/access/transam/xlog.c | 493 ++----------------
src/backend/access/transam/xlogfuncs.c | 253 ++-------
src/backend/access/transam/xlogrecovery.c | 2 +-
src/backend/catalog/system_functions.sql | 18 +-
src/backend/postmaster/postmaster.c | 46 +-
src/backend/replication/basebackup.c | 20 +-
src/bin/pg_basebackup/t/010_pg_basebackup.pl | 4 +
src/bin/pg_ctl/pg_ctl.c | 4 +-
src/bin/pg_rewind/filemap.c | 6 +-
src/include/access/xlog.h | 7 +-
src/include/catalog/pg_control.h | 2 +-
src/include/catalog/pg_proc.dat | 26 +-
src/include/miscadmin.h | 4 -
src/test/perl/PostgreSQL/Test/Cluster.pm | 56 +-
.../t/010_logical_decoding_timelines.pl | 4 +-
20 files changed, 190 insertions(+), 1054 deletions(-)
diff --git a/doc/src/sgml/backup.sgml b/doc/src/sgml/backup.sgml
index 0d69851bb1..acffee4688 100644
--- a/doc/src/sgml/backup.sgml
+++ b/doc/src/sgml/backup.sgml
@@ -857,16 +857,8 @@ test ! -f /mnt/server/archivedir/00000001000000A900000065 && cp pg_wal/0
sequence, and that the success of a step is verified before
proceeding to the next step.
</para>
- <para>
- Low level base backups can be made in a non-exclusive or an exclusive
- way. The non-exclusive method is recommended and the exclusive one is
- deprecated and will eventually be removed.
- </para>
-
- <sect3 id="backup-lowlevel-base-backup-nonexclusive">
- <title>Making a Non-Exclusive Low-Level Backup</title>
<para>
- A non-exclusive low level backup is one that allows other
+ A low level backup allows other
concurrent backups to be running (both those started using
the same backup API and those started using
<xref linkend="app-pgbasebackup"/>).
@@ -881,19 +873,19 @@ test ! -f /mnt/server/archivedir/00000001000000A900000065 && cp pg_wal/0
<listitem>
<para>
Connect to the server (it does not matter which database) as a user with
- rights to run pg_start_backup (superuser, or a user who has been granted
+ rights to run pg_backup_start (superuser, or a user who has been granted
EXECUTE on the function) and issue the command:
<programlisting>
-SELECT pg_start_backup('label', false, false);
+SELECT pg_backup_start('label', false);
</programlisting>
where <literal>label</literal> is any string you want to use to uniquely
identify this backup operation. The connection
- calling <function>pg_start_backup</function> must be maintained until the end of
+ calling <function>pg_backup_start</function> must be maintained until the end of
the backup, or the backup will be automatically aborted.
</para>
<para>
- By default, <function>pg_start_backup</function> can take a long time to finish.
+ By default, <function>pg_backup_start</function> can take a long time to finish.
This is because it performs a checkpoint, and the I/O
required for the checkpoint will be spread out over a significant
period of time, by default half your inter-checkpoint interval
@@ -905,10 +897,6 @@ SELECT pg_start_backup('label', false, false);
issue an immediate checkpoint using as much I/O as available.
</para>
- <para>
- The third parameter being <literal>false</literal> tells
- <function>pg_start_backup</function> to initiate a non-exclusive base backup.
- </para>
</listitem>
<listitem>
<para>
@@ -926,7 +914,7 @@ SELECT pg_start_backup('label', false, false);
<para>
In the same connection as before, issue the command:
<programlisting>
-SELECT * FROM pg_stop_backup(false, true);
+SELECT * FROM pg_backup_stop(true);
</programlisting>
This terminates backup mode. On a primary, it also performs an automatic
switch to the next WAL segment. On a standby, it is not possible to
@@ -937,7 +925,7 @@ SELECT * FROM pg_stop_backup(false, true);
ready to archive.
</para>
<para>
- The <function>pg_stop_backup</function> will return one row with three
+ The <function>pg_backup_stop</function> will return one row with three
values. The second of these fields should be written to a file named
<filename>backup_label</filename> in the root directory of the backup. The
third field should be written to a file named
@@ -949,14 +937,14 @@ SELECT * FROM pg_stop_backup(false, true);
<listitem>
<para>
Once the WAL segment files active during the backup are archived, you are
- done. The file identified by <function>pg_stop_backup</function>'s first return
+ done. The file identified by <function>pg_backup_stop</function>'s first return
value is the last segment that is required to form a complete set of
backup files. On a primary, if <varname>archive_mode</varname> is enabled and the
<literal>wait_for_archive</literal> parameter is <literal>true</literal>,
- <function>pg_stop_backup</function> does not return until the last segment has
+ <function>pg_backup_stop</function> does not return until the last segment has
been archived.
On a standby, <varname>archive_mode</varname> must be <literal>always</literal> in order
- for <function>pg_stop_backup</function> to wait.
+ for <function>pg_backup_stop</function> to wait.
Archiving of these files happens automatically since you have
already configured <varname>archive_library</varname>. In most cases this
happens quickly, but you are advised to monitor your archive
@@ -965,9 +953,9 @@ SELECT * FROM pg_stop_backup(false, true);
because of failures of the archive library, it will keep retrying
until the archive succeeds and the backup is complete.
If you wish to place a time limit on the execution of
- <function>pg_stop_backup</function>, set an appropriate
+ <function>pg_backup_stop</function>, set an appropriate
<varname>statement_timeout</varname> value, but make note that if
- <function>pg_stop_backup</function> terminates because of this your backup
+ <function>pg_backup_stop</function> terminates because of this your backup
may not be valid.
</para>
<para>
@@ -975,8 +963,8 @@ SELECT * FROM pg_stop_backup(false, true);
required for the backup are successfully archived then the
<literal>wait_for_archive</literal> parameter (which defaults to true) can be set
to false to have
- <function>pg_stop_backup</function> return as soon as the stop backup record is
- written to the WAL. By default, <function>pg_stop_backup</function> will wait
+ <function>pg_backup_stop</function> return as soon as the stop backup record is
+ written to the WAL. By default, <function>pg_backup_stop</function> will wait
until all WAL has been archived, which can take some time. This option
must be used with caution: if WAL archiving is not monitored correctly
then the backup might not include all of the WAL files and will
@@ -985,142 +973,6 @@ SELECT * FROM pg_stop_backup(false, true);
</listitem>
</orderedlist>
</para>
- </sect3>
- <sect3 id="backup-lowlevel-base-backup-exclusive">
- <title>Making an Exclusive Low-Level Backup</title>
-
- <note>
- <para>
- The exclusive backup method is deprecated and should be avoided.
- Prior to <productname>PostgreSQL</productname> 9.6, this was the only
- low-level method available, but it is now recommended that all users
- upgrade their scripts to use non-exclusive backups.
- </para>
- </note>
-
- <para>
- The process for an exclusive backup is mostly the same as for a
- non-exclusive one, but it differs in a few key steps. This type of
- backup can only be taken on a primary and does not allow concurrent
- backups. Moreover, because it creates a backup label file, as
- described below, it can block automatic restart of the primary server
- after a crash. On the other hand, the erroneous removal of this
- file from a backup or standby is a common mistake, which can result
- in serious data corruption. If it is necessary to use this method,
- the following steps may be used.
- </para>
- <para>
- <orderedlist>
- <listitem>
- <para>
- Ensure that WAL archiving is enabled and working.
- </para>
- </listitem>
- <listitem>
- <para>
- Connect to the server (it does not matter which database) as a user with
- rights to run pg_start_backup (superuser, or a user who has been granted
- EXECUTE on the function) and issue the command:
-<programlisting>
-SELECT pg_start_backup('label');
-</programlisting>
- where <literal>label</literal> is any string you want to use to uniquely
- identify this backup operation.
- <function>pg_start_backup</function> creates a <firstterm>backup label</firstterm> file,
- called <filename>backup_label</filename>, in the cluster directory with
- information about your backup, including the start time and label string.
- The function also creates a <firstterm>tablespace map</firstterm> file,
- called <filename>tablespace_map</filename>, in the cluster directory with
- information about tablespace symbolic links in <filename>pg_tblspc/</filename> if
- one or more such link is present. Both files are critical to the
- integrity of the backup, should you need to restore from it.
- </para>
-
- <para>
- By default, <function>pg_start_backup</function> can take a long time to finish.
- This is because it performs a checkpoint, and the I/O
- required for the checkpoint will be spread out over a significant
- period of time, by default half your inter-checkpoint interval
- (see the configuration parameter
- <xref linkend="guc-checkpoint-completion-target"/>). This is
- usually what you want, because it minimizes the impact on query
- processing. If you want to start the backup as soon as
- possible, use:
-<programlisting>
-SELECT pg_start_backup('label', true);
-</programlisting>
- This forces the checkpoint to be done as quickly as possible.
- </para>
- </listitem>
- <listitem>
- <para>
- Perform the backup, using any convenient file-system-backup tool
- such as <application>tar</application> or <application>cpio</application> (not
- <application>pg_dump</application> or
- <application>pg_dumpall</application>). It is neither
- necessary nor desirable to stop normal operation of the database
- while you do this. See
- <xref linkend="backup-lowlevel-base-backup-data"/> for things to
- consider during this backup.
- </para>
- <para>
- As noted above, if the server crashes during the backup it may not be
- possible to restart until the <filename>backup_label</filename> file has
- been manually deleted from the <envar>PGDATA</envar> directory. Note
- that it is very important to never remove the
- <filename>backup_label</filename> file when restoring a backup, because
- this will result in corruption. Confusion about when it is appropriate
- to remove this file is a common cause of data corruption when using this
- method; be very certain that you remove the file only on an existing
- primary and never when building a standby or restoring a backup, even if
- you are building a standby that will subsequently be promoted to a new
- primary.
- </para>
- </listitem>
- <listitem>
- <para>
- Again connect to the database as a user with rights to run
- pg_stop_backup (superuser, or a user who has been granted EXECUTE on
- the function), and issue the command:
-<programlisting>
-SELECT pg_stop_backup();
-</programlisting>
- This function terminates backup mode and
- performs an automatic switch to the next WAL segment. The reason for the
- switch is to arrange for the last WAL segment written during the backup
- interval to be ready to archive.
- </para>
- </listitem>
- <listitem>
- <para>
- Once the WAL segment files active during the backup are archived, you are
- done. The file identified by <function>pg_stop_backup</function>'s result is
- the last segment that is required to form a complete set of backup files.
- If <varname>archive_mode</varname> is enabled,
- <function>pg_stop_backup</function> does not return until the last segment has
- been archived.
- Archiving of these files happens automatically since you have
- already configured <varname>archive_command</varname>. In most cases this
- happens quickly, but you are advised to monitor your archive
- system to ensure there are no delays.
- If the archive process has fallen behind
- because of failures of the archive command, it will keep retrying
- until the archive succeeds and the backup is complete.
- </para>
-
- <para>
- When using exclusive backup mode, it is absolutely imperative to ensure
- that <function>pg_stop_backup</function> completes successfully at the
- end of the backup. Even if the backup itself fails, for example due to
- lack of disk space, failure to call <function>pg_stop_backup</function>
- will leave the server in backup mode indefinitely, causing future backups
- to fail and increasing the risk of a restart failure during the time that
- <filename>backup_label</filename> exists.
- </para>
- </listitem>
- </orderedlist>
- </para>
- </sect3>
<sect3 id="backup-lowlevel-base-backup-data">
<title>Backing Up the Data Directory</title>
<para>
@@ -1203,8 +1055,8 @@ SELECT pg_stop_backup();
<para>
The backup label
- file includes the label string you gave to <function>pg_start_backup</function>,
- as well as the time at which <function>pg_start_backup</function> was run, and
+ file includes the label string you gave to <function>pg_backup_start</function>,
+ as well as the time at which <function>pg_backup_start</function> was run, and
the name of the starting WAL file. In case of confusion it is therefore
possible to look inside a backup file and determine exactly which
backup session the dump file came from. The tablespace map file includes
@@ -1218,7 +1070,7 @@ SELECT pg_stop_backup();
<para>
It is also possible to make a backup while the server is
stopped. In this case, you obviously cannot use
- <function>pg_start_backup</function> or <function>pg_stop_backup</function>, and
+ <function>pg_backup_start</function> or <function>pg_backup_stop</function>, and
you will therefore be left to your own devices to keep track of which
backup is which and how far back the associated WAL files go.
It is generally better to follow the continuous archiving procedure above.
@@ -1393,7 +1245,7 @@ restore_command = 'cp /mnt/server/archivedir/%f %p'
<note>
<para>
The stop point must be after the ending time of the base backup, i.e.,
- the end time of <function>pg_stop_backup</function>. You cannot use a base backup
+ the end time of <function>pg_backup_stop</function>. You cannot use a base backup
to recover to a time when that backup was in progress. (To
recover to such a time, you must go back to your previous base backup
and roll forward from there.)
@@ -1537,9 +1389,9 @@ archive_command = 'test ! -f /var/lib/pgsql/backup_in_progress || (test ! -f /va
following:
<programlisting>
touch /var/lib/pgsql/backup_in_progress
-psql -c "select pg_start_backup('hot_backup');"
+psql -c "select pg_backup_start('hot_backup');"
tar -cf /var/lib/pgsql/backup.tar /var/lib/pgsql/data/
-psql -c "select pg_stop_backup();"
+psql -c "select pg_backup_stop();"
rm /var/lib/pgsql/backup_in_progress
tar -rf /var/lib/pgsql/backup.tar /var/lib/pgsql/archive/
</programlisting>
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index df3cd5987b..b19664a857 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -25587,9 +25587,8 @@ LOG: Grand total: 1651920 bytes in 201 blocks; 622360 free (88 chunks); 1029560
The functions shown in <xref
linkend="functions-admin-backup-table"/> assist in making on-line backups.
These functions cannot be executed during recovery (except
- non-exclusive <function>pg_start_backup</function>,
- non-exclusive <function>pg_stop_backup</function>,
- <function>pg_is_in_backup</function>, <function>pg_backup_start_time</function>
+ <function>pg_backup_start</function>,
+ <function>pg_backup_stop</function>,
and <function>pg_wal_lsn_diff</function>).
</para>
@@ -25678,13 +25677,12 @@ LOG: Grand total: 1651920 bytes in 201 blocks; 622360 free (88 chunks); 1029560
<row>
<entry role="func_table_entry"><para role="func_signature">
<indexterm>
- <primary>pg_start_backup</primary>
+ <primary>pg_backup_start</primary>
</indexterm>
- <function>pg_start_backup</function> (
+ <function>pg_backup_start</function> (
<parameter>label</parameter> <type>text</type>
<optional>, <parameter>fast</parameter> <type>boolean</type>
- <optional>, <parameter>exclusive</parameter> <type>boolean</type>
- </optional></optional> )
+ </optional> )
<returnvalue>pg_lsn</returnvalue>
</para>
<para>
@@ -25693,23 +25691,9 @@ LOG: Grand total: 1651920 bytes in 201 blocks; 622360 free (88 chunks); 1029560
(Typically this would be the name under which the backup dump file
will be stored.)
If the optional second parameter is given as <literal>true</literal>,
- it specifies executing <function>pg_start_backup</function> as quickly
+ it specifies executing <function>pg_backup_start</function> as quickly
as possible. This forces an immediate checkpoint which will cause a
spike in I/O operations, slowing any concurrently executing queries.
- The optional third parameter specifies whether to perform an exclusive
- or non-exclusive backup (default is exclusive).
- </para>
- <para>
- When used in exclusive mode, this function writes a backup label file
- (<filename>backup_label</filename>) and, if there are any links in
- the <filename>pg_tblspc/</filename> directory, a tablespace map file
- (<filename>tablespace_map</filename>) into the database cluster's data
- directory, then performs a checkpoint, and then returns the backup's
- starting write-ahead log location. (The user can ignore this
- result value, but it is provided in case it is useful.) When used in
- non-exclusive mode, the contents of these files are instead returned
- by the <function>pg_stop_backup</function> function, and should be
- copied to the backup area by the user.
</para>
<para>
This function is restricted to superusers by default, but other users
@@ -25720,11 +25704,10 @@ LOG: Grand total: 1651920 bytes in 201 blocks; 622360 free (88 chunks); 1029560
<row>
<entry role="func_table_entry"><para role="func_signature">
<indexterm>
- <primary>pg_stop_backup</primary>
+ <primary>pg_backup_stop</primary>
</indexterm>
- <function>pg_stop_backup</function> (
- <parameter>exclusive</parameter> <type>boolean</type>
- <optional>, <parameter>wait_for_archive</parameter> <type>boolean</type>
+ <function>pg_backup_stop</function> (
+ <optional><parameter>wait_for_archive</parameter> <type>boolean</type>
</optional> )
<returnvalue>setof record</returnvalue>
( <parameter>lsn</parameter> <type>pg_lsn</type>,
@@ -25732,24 +25715,19 @@ LOG: Grand total: 1651920 bytes in 201 blocks; 622360 free (88 chunks); 1029560
<parameter>spcmapfile</parameter> <type>text</type> )
</para>
<para>
- Finishes performing an exclusive or non-exclusive on-line backup.
- The <parameter>exclusive</parameter> parameter must match the
- previous <function>pg_start_backup</function> call.
- In an exclusive backup, <function>pg_stop_backup</function> removes
- the backup label file and, if it exists, the tablespace map file
- created by <function>pg_start_backup</function>. In a non-exclusive
- backup, the desired contents of these files are returned as part of
+ Finishes performing an on-line backup. The desired contents of the
+ backup label file and the tablespace map file are returned as part of
the result of the function, and should be written to files in the
backup area (not in the data directory).
</para>
<para>
- There is an optional second parameter of type <type>boolean</type>.
+ There is an optional parameter of type <type>boolean</type>.
If false, the function will return immediately after the backup is
completed, without waiting for WAL to be archived. This behavior is
only useful with backup software that independently monitors WAL
archiving. Otherwise, WAL required to make the backup consistent might
be missing and make the backup useless. By default or when this
- parameter is true, <function>pg_stop_backup</function> will wait for
+ parameter is true, <function>pg_backup_stop</function> will wait for
WAL to be archived when archiving is enabled. (On a standby, this
means that it will wait only when <varname>archive_mode</varname> =
<literal>always</literal>. If write activity on the primary is low,
@@ -25759,7 +25737,7 @@ LOG: Grand total: 1651920 bytes in 201 blocks; 622360 free (88 chunks); 1029560
<para>
When executed on a primary, this function also creates a backup
history file in the write-ahead log archive area. The history file
- includes the label given to <function>pg_start_backup</function>, the
+ includes the label given to <function>pg_backup_start</function>, the
starting and ending write-ahead log locations for the backup, and the
starting and ending times of the backup. After recording the ending
location, the current write-ahead log insertion point is automatically
@@ -25771,8 +25749,7 @@ LOG: Grand total: 1651920 bytes in 201 blocks; 622360 free (88 chunks); 1029560
The result of the function is a single record.
The <parameter>lsn</parameter> column holds the backup's ending
write-ahead log location (which again can be ignored). The second and
- third columns are <literal>NULL</literal> when ending an exclusive
- backup; after a non-exclusive backup they hold the desired contents of
+ third columns hold the desired contents of
the label and tablespace map files.
</para>
<para>
@@ -25781,50 +25758,6 @@ LOG: Grand total: 1651920 bytes in 201 blocks; 622360 free (88 chunks); 1029560
</para></entry>
</row>
- <row>
- <entry role="func_table_entry"><para role="func_signature">
- <function>pg_stop_backup</function> ()
- <returnvalue>pg_lsn</returnvalue>
- </para>
- <para>
- Finishes performing an exclusive on-line backup. This simplified
- version is equivalent to <literal>pg_stop_backup(true,
- true)</literal>, except that it only returns the <type>pg_lsn</type>
- result.
- </para>
- <para>
- This function is restricted to superusers by default, but other users
- can be granted EXECUTE to run the function.
- </para></entry>
- </row>
-
- <row>
- <entry role="func_table_entry"><para role="func_signature">
- <indexterm>
- <primary>pg_is_in_backup</primary>
- </indexterm>
- <function>pg_is_in_backup</function> ()
- <returnvalue>boolean</returnvalue>
- </para>
- <para>
- Returns true if an on-line exclusive backup is in progress.
- </para></entry>
- </row>
-
- <row>
- <entry role="func_table_entry"><para role="func_signature">
- <indexterm>
- <primary>pg_backup_start_time</primary>
- </indexterm>
- <function>pg_backup_start_time</function> ()
- <returnvalue>timestamp with time zone</returnvalue>
- </para>
- <para>
- Returns the start time of the current on-line exclusive backup if one
- is in progress, otherwise <literal>NULL</literal>.
- </para></entry>
- </row>
-
<row>
<entry role="func_table_entry"><para role="func_signature">
<indexterm>
@@ -25922,7 +25855,7 @@ LOG: Grand total: 1651920 bytes in 201 blocks; 622360 free (88 chunks); 1029560
corresponding write-ahead log file name and byte offset from
a <type>pg_lsn</type> value. For example:
<programlisting>
-postgres=# SELECT * FROM pg_walfile_name_offset(pg_stop_backup());
+postgres=# SELECT * FROM pg_walfile_name_offset(pg_backup_stop());
file_name | file_offset
--------------------------+-------------
00000001000000000000000D | 4039624
diff --git a/doc/src/sgml/high-availability.sgml b/doc/src/sgml/high-availability.sgml
index b5b6042104..1f0ba66943 100644
--- a/doc/src/sgml/high-availability.sgml
+++ b/doc/src/sgml/high-availability.sgml
@@ -1361,8 +1361,8 @@ synchronous_standby_names = 'ANY 2 (s1, s2, s3)'
<para>
If you need to re-create a standby server while transactions are
- waiting, make sure that the commands pg_start_backup() and
- pg_stop_backup() are run in a session with
+ waiting, make sure that the commands pg_backup_start() and
+ pg_backup_stop() are run in a session with
<varname>synchronous_commit</varname> = <literal>off</literal>, otherwise those
requests will wait forever for the standby to appear.
</para>
@@ -2159,7 +2159,7 @@ HINT: You can then restart the server after making the necessary configuration
<para>
WAL file control commands will not work during recovery,
- e.g., <function>pg_start_backup</function>, <function>pg_switch_wal</function> etc.
+ e.g., <function>pg_backup_start</function>, <function>pg_switch_wal</function> etc.
</para>
<para>
diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
index 9fb62fec8e..0320ce7078 100644
--- a/doc/src/sgml/monitoring.sgml
+++ b/doc/src/sgml/monitoring.sgml
@@ -6661,7 +6661,7 @@ SELECT pg_stat_get_backend_pid(s.backendid) AS pid,
<entry><literal>waiting for checkpoint to finish</literal></entry>
<entry>
The WAL sender process is currently performing
- <function>pg_start_backup</function> to prepare to
+ <function>pg_backup_start</function> to prepare to
take a base backup, and waiting for the start-of-backup
checkpoint to finish.
</entry>
@@ -6684,7 +6684,7 @@ SELECT pg_stat_get_backend_pid(s.backendid) AS pid,
<entry><literal>waiting for wal archiving to finish</literal></entry>
<entry>
The WAL sender process is currently performing
- <function>pg_stop_backup</function> to finish the backup,
+ <function>pg_backup_stop</function> to finish the backup,
and waiting for all the WAL files required for the base backup
to be successfully archived.
If either <literal>--wal-method=none</literal> or
diff --git a/doc/src/sgml/ref/pgupgrade.sgml b/doc/src/sgml/ref/pgupgrade.sgml
index 729c886ac0..3fbe141456 100644
--- a/doc/src/sgml/ref/pgupgrade.sgml
+++ b/doc/src/sgml/ref/pgupgrade.sgml
@@ -618,7 +618,7 @@ rsync --archive --delete --hard-links --size-only --no-inc-recursive /vol1/pg_tb
<para>
Configure the servers for log shipping. (You do not need to run
- <function>pg_start_backup()</function> and <function>pg_stop_backup()</function>
+ <function>pg_backup_start()</function> and <function>pg_backup_stop()</function>
or take a file system backup as the standbys are still synchronized
with the primary.)
</para>
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 0d2bd7a357..d5032118d3 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -384,29 +384,6 @@ typedef union WALInsertLockPadded
char pad[PG_CACHE_LINE_SIZE];
} WALInsertLockPadded;
-/*
- * State of an exclusive backup, necessary to control concurrent activities
- * across sessions when working on exclusive backups.
- *
- * EXCLUSIVE_BACKUP_NONE means that there is no exclusive backup actually
- * running, to be more precise pg_start_backup() is not being executed for
- * an exclusive backup and there is no exclusive backup in progress.
- * EXCLUSIVE_BACKUP_STARTING means that pg_start_backup() is starting an
- * exclusive backup.
- * EXCLUSIVE_BACKUP_IN_PROGRESS means that pg_start_backup() has finished
- * running and an exclusive backup is in progress. pg_stop_backup() is
- * needed to finish it.
- * EXCLUSIVE_BACKUP_STOPPING means that pg_stop_backup() is stopping an
- * exclusive backup.
- */
-typedef enum ExclusiveBackupState
-{
- EXCLUSIVE_BACKUP_NONE = 0,
- EXCLUSIVE_BACKUP_STARTING,
- EXCLUSIVE_BACKUP_IN_PROGRESS,
- EXCLUSIVE_BACKUP_STOPPING
-} ExclusiveBackupState;
-
/*
* Session status of running backup, used for sanity checks in SQL-callable
* functions to start and stop backups.
@@ -455,15 +432,12 @@ typedef struct XLogCtlInsert
bool fullPageWrites;
/*
- * exclusiveBackupState indicates the state of an exclusive backup (see
- * comments of ExclusiveBackupState for more details). nonExclusiveBackups
- * is a counter indicating the number of streaming base backups currently
- * in progress. forcePageWrites is set to true when either of these is
- * non-zero. lastBackupStart is the latest checkpoint redo location used
- * as a starting point for an online backup.
+ * runningBackups is a counter indicating the number of backups currently in
+ * progress. forcePageWrites is set to true when runningBackups is non-zero.
+ * lastBackupStart is the latest checkpoint redo location used as a starting
+ * point for an online backup.
*/
- ExclusiveBackupState exclusiveBackupState;
- int nonExclusiveBackups;
+ int runningBackups;
XLogRecPtr lastBackupStart;
/*
@@ -695,8 +669,7 @@ static void ReadControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow);
-static void pg_start_backup_callback(int code, Datum arg);
-static void pg_stop_backup_callback(int code, Datum arg);
+static void pg_backup_start_callback(int code, Datum arg);
static int get_sync_bit(int method);
@@ -5313,7 +5286,7 @@ StartupXLOG(void)
* Ran off end of WAL before reaching end-of-backup WAL record, or
* minRecoveryPoint. That's usually a bad sign, indicating that you
* tried to recover from an online backup but never called
- * pg_stop_backup(), or you didn't archive all the WAL up to that
+ * pg_backup_stop(), or you didn't archive all the WAL up to that
* point. However, this also happens in crash recovery, if the system
* crashes while an online backup is in progress. We must not treat
* that as an error, or the database will refuse to start up.
@@ -5327,7 +5300,7 @@ StartupXLOG(void)
else if (!XLogRecPtrIsInvalid(ControlFile->backupStartPoint))
ereport(FATAL,
(errmsg("WAL ends before end of online backup"),
- errhint("Online backup started with pg_start_backup() must be ended with pg_stop_backup(), and all WAL up to that point must be available at recovery.")));
+ errhint("Online backup started with pg_backup_start() must be ended with pg_backup_stop(), and all WAL up to that point must be available at recovery.")));
else
ereport(FATAL,
(errmsg("WAL ends before consistent recovery point")));
@@ -7008,7 +6981,7 @@ CreateRestartPoint(int flags)
* Ensure minRecoveryPoint is past the checkpoint record. Normally,
* this will have happened already while writing out dirty buffers,
* but not necessarily - e.g. because no buffers were dirtied. We do
- * this because a non-exclusive base backup uses minRecoveryPoint to
+ * this because a backup performed in recovery uses minRecoveryPoint to
* determine which WAL files must be included in the backup, and the
* file (or files) containing the checkpoint record must be included,
* at a minimum. Note that for an ordinary restart of recovery there's
@@ -7812,7 +7785,7 @@ xlog_redo(XLogReaderState *record)
/*
* Update the LSN of the last replayed XLOG_FPW_CHANGE record so that
- * do_pg_start_backup() and do_pg_stop_backup() can check whether
+ * do_pg_backup_start() and do_pg_backup_stop() can check whether
* full_page_writes has been disabled during online backup.
*/
if (!fpw)
@@ -8011,29 +7984,14 @@ issue_xlog_fsync(int fd, XLogSegNo segno, TimeLineID tli)
}
/*
- * do_pg_start_backup
- *
- * Utility function called at the start of an online backup. It creates the
- * necessary starting checkpoint and constructs the backup label file.
- *
- * There are two kind of backups: exclusive and non-exclusive. An exclusive
- * backup is started with pg_start_backup(), and there can be only one active
- * at a time. The backup and tablespace map files of an exclusive backup are
- * written to $PGDATA/backup_label and $PGDATA/tablespace_map, and they are
- * removed by pg_stop_backup().
- *
- * A non-exclusive backup is used for the streaming base backups (see
- * src/backend/replication/basebackup.c). The difference to exclusive backups
- * is that the backup label and tablespace map files are not written to disk.
- * Instead, their would-be contents are returned in *labelfile and *tblspcmapfile,
- * and the caller is responsible for including them in the backup archive as
- * 'backup_label' and 'tablespace_map'. There can be many non-exclusive backups
- * active at the same time, and they don't conflict with an exclusive backup
- * either.
- *
- * labelfile and tblspcmapfile must be passed as NULL when starting an
- * exclusive backup, and as initially-empty StringInfos for a non-exclusive
- * backup.
+ * do_pg_backup_start is the workhorse of the user-visible pg_backup_start()
+ * function. It creates the necessary starting checkpoint and constructs the
+ * backup label and tablespace map.
+ *
+ * The backup label and tablespace map contents are returned in *labelfile and
+ * *tblspcmapfile, and the caller is responsible for including them in the
+ * backup archive as 'backup_label' and 'tablespace_map'. There can be many
+ * backups active at the same time.
*
* If "tablespaces" isn't NULL, it receives a list of tablespaceinfo structs
* describing the cluster's tablespaces.
@@ -8045,18 +8003,17 @@ issue_xlog_fsync(int fd, XLogSegNo segno, TimeLineID tli)
* Returns the minimum WAL location that must be present to restore from this
* backup, and the corresponding timeline ID in *starttli_p.
*
- * Every successfully started non-exclusive backup must be stopped by calling
- * do_pg_stop_backup() or do_pg_abort_backup().
+ * Every successfully started backup must be stopped by calling
+ * do_pg_backup_stop() or do_pg_abort_backup().
*
* It is the responsibility of the caller of this function to verify the
* permissions of the calling user!
*/
XLogRecPtr
-do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
+do_pg_backup_start(const char *backupidstr, bool fast, TimeLineID *starttli_p,
StringInfo labelfile, List **tablespaces,
StringInfo tblspcmapfile)
{
- bool exclusive = (labelfile == NULL);
bool backup_started_in_recovery = false;
XLogRecPtr checkpointloc;
XLogRecPtr startpoint;
@@ -8065,20 +8022,9 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
char strfbuf[128];
char xlogfilename[MAXFNAMELEN];
XLogSegNo _logSegNo;
- struct stat stat_buf;
- FILE *fp;
backup_started_in_recovery = RecoveryInProgress();
- /*
- * Currently only non-exclusive backup can be taken during recovery.
- */
- if (backup_started_in_recovery && exclusive)
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("recovery is in progress"),
- errhint("WAL control functions cannot be executed during recovery.")));
-
/*
* During recovery, we don't need to check WAL level. Because, if WAL
* level is not sufficient, it's impossible to get here during recovery.
@@ -8117,30 +8063,12 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
* XLogInsertRecord().
*/
WALInsertLockAcquireExclusive();
- if (exclusive)
- {
- /*
- * At first, mark that we're now starting an exclusive backup, to
- * ensure that there are no other sessions currently running
- * pg_start_backup() or pg_stop_backup().
- */
- if (XLogCtl->Insert.exclusiveBackupState != EXCLUSIVE_BACKUP_NONE)
- {
- WALInsertLockRelease();
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("a backup is already in progress"),
- errhint("Run pg_stop_backup() and try again.")));
- }
- XLogCtl->Insert.exclusiveBackupState = EXCLUSIVE_BACKUP_STARTING;
- }
- else
- XLogCtl->Insert.nonExclusiveBackups++;
+ XLogCtl->Insert.runningBackups++;
XLogCtl->Insert.forcePageWrites = true;
WALInsertLockRelease();
/* Ensure we release forcePageWrites if fail below */
- PG_ENSURE_ERROR_CLEANUP(pg_start_backup_callback, (Datum) BoolGetDatum(exclusive));
+ PG_ENSURE_ERROR_CLEANUP(pg_backup_start_callback, (Datum) 0);
{
bool gotUniqueStartpoint = false;
DIR *tblspcdir;
@@ -8152,7 +8080,7 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
* Force an XLOG file switch before the checkpoint, to ensure that the
* WAL segment the checkpoint is written to doesn't contain pages with
* old timeline IDs. That would otherwise happen if you called
- * pg_start_backup() right after restoring from a PITR archive: the
+ * pg_backup_start() right after restoring from a PITR archive: the
* first WAL segment containing the startup checkpoint has pages in
* the beginning with the old timeline ID. That can cause trouble at
* recovery: we won't have a history file covering the old timeline if
@@ -8187,7 +8115,7 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
* means that two successive backup runs can have same checkpoint
* positions.
*
- * Since the fact that we are executing do_pg_start_backup()
+ * Since the fact that we are executing do_pg_backup_start()
* during recovery means that checkpointer is running, we can use
* RequestCheckpoint() to establish a restartpoint.
*
@@ -8375,122 +8303,19 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
LSN_FORMAT_ARGS(startpoint), xlogfilename);
appendStringInfo(labelfile, "CHECKPOINT LOCATION: %X/%X\n",
LSN_FORMAT_ARGS(checkpointloc));
- appendStringInfo(labelfile, "BACKUP METHOD: %s\n",
- exclusive ? "pg_start_backup" : "streamed");
+ appendStringInfo(labelfile, "BACKUP METHOD: streamed\n");
appendStringInfo(labelfile, "BACKUP FROM: %s\n",
backup_started_in_recovery ? "standby" : "primary");
appendStringInfo(labelfile, "START TIME: %s\n", strfbuf);
appendStringInfo(labelfile, "LABEL: %s\n", backupidstr);
appendStringInfo(labelfile, "START TIMELINE: %u\n", starttli);
-
- /*
- * Okay, write the file, or return its contents to caller.
- */
- if (exclusive)
- {
- /*
- * Check for existing backup label --- implies a backup is already
- * running. (XXX given that we checked exclusiveBackupState
- * above, maybe it would be OK to just unlink any such label
- * file?)
- */
- if (stat(BACKUP_LABEL_FILE, &stat_buf) != 0)
- {
- if (errno != ENOENT)
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not stat file \"%s\": %m",
- BACKUP_LABEL_FILE)));
- }
- else
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("a backup is already in progress"),
- errhint("If you're sure there is no backup in progress, remove file \"%s\" and try again.",
- BACKUP_LABEL_FILE)));
-
- fp = AllocateFile(BACKUP_LABEL_FILE, "w");
-
- if (!fp)
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not create file \"%s\": %m",
- BACKUP_LABEL_FILE)));
- if (fwrite(labelfile->data, labelfile->len, 1, fp) != 1 ||
- fflush(fp) != 0 ||
- pg_fsync(fileno(fp)) != 0 ||
- ferror(fp) ||
- FreeFile(fp))
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not write file \"%s\": %m",
- BACKUP_LABEL_FILE)));
- /* Allocated locally for exclusive backups, so free separately */
- pfree(labelfile->data);
- pfree(labelfile);
-
- /* Write backup tablespace_map file. */
- if (tblspcmapfile->len > 0)
- {
- if (stat(TABLESPACE_MAP, &stat_buf) != 0)
- {
- if (errno != ENOENT)
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not stat file \"%s\": %m",
- TABLESPACE_MAP)));
- }
- else
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("a backup is already in progress"),
- errhint("If you're sure there is no backup in progress, remove file \"%s\" and try again.",
- TABLESPACE_MAP)));
-
- fp = AllocateFile(TABLESPACE_MAP, "w");
-
- if (!fp)
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not create file \"%s\": %m",
- TABLESPACE_MAP)));
- if (fwrite(tblspcmapfile->data, tblspcmapfile->len, 1, fp) != 1 ||
- fflush(fp) != 0 ||
- pg_fsync(fileno(fp)) != 0 ||
- ferror(fp) ||
- FreeFile(fp))
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not write file \"%s\": %m",
- TABLESPACE_MAP)));
- }
-
- /* Allocated locally for exclusive backups, so free separately */
- pfree(tblspcmapfile->data);
- pfree(tblspcmapfile);
- }
}
- PG_END_ENSURE_ERROR_CLEANUP(pg_start_backup_callback, (Datum) BoolGetDatum(exclusive));
+ PG_END_ENSURE_ERROR_CLEANUP(pg_backup_start_callback, (Datum) 0);
/*
- * Mark that start phase has correctly finished for an exclusive backup.
- * Session-level locks are updated as well to reflect that state.
- *
- * Note that CHECK_FOR_INTERRUPTS() must not occur while updating backup
- * counters and session-level lock. Otherwise they can be updated
- * inconsistently, and which might cause do_pg_abort_backup() to fail.
+ * Mark that the start phase has correctly finished for the backup.
*/
- if (exclusive)
- {
- WALInsertLockAcquireExclusive();
- XLogCtl->Insert.exclusiveBackupState = EXCLUSIVE_BACKUP_IN_PROGRESS;
-
- /* Set session-level lock */
- sessionBackupState = SESSION_BACKUP_EXCLUSIVE;
- WALInsertLockRelease();
- }
- else
- sessionBackupState = SESSION_BACKUP_NON_EXCLUSIVE;
+ sessionBackupState = SESSION_BACKUP_RUNNING;
/*
* We're done. As a convenience, return the starting WAL location.
@@ -8500,47 +8325,19 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
return startpoint;
}
-/* Error cleanup callback for pg_start_backup */
+/* Error cleanup callback for pg_backup_start */
static void
-pg_start_backup_callback(int code, Datum arg)
+pg_backup_start_callback(int code, Datum arg)
{
- bool exclusive = DatumGetBool(arg);
-
/* Update backup counters and forcePageWrites on failure */
WALInsertLockAcquireExclusive();
- if (exclusive)
- {
- Assert(XLogCtl->Insert.exclusiveBackupState == EXCLUSIVE_BACKUP_STARTING);
- XLogCtl->Insert.exclusiveBackupState = EXCLUSIVE_BACKUP_NONE;
- }
- else
- {
- Assert(XLogCtl->Insert.nonExclusiveBackups > 0);
- XLogCtl->Insert.nonExclusiveBackups--;
- }
- if (XLogCtl->Insert.exclusiveBackupState == EXCLUSIVE_BACKUP_NONE &&
- XLogCtl->Insert.nonExclusiveBackups == 0)
- {
- XLogCtl->Insert.forcePageWrites = false;
- }
- WALInsertLockRelease();
-}
+ Assert(XLogCtl->Insert.runningBackups > 0);
+ XLogCtl->Insert.runningBackups--;
-/*
- * Error cleanup callback for pg_stop_backup
- */
-static void
-pg_stop_backup_callback(int code, Datum arg)
-{
- bool exclusive = DatumGetBool(arg);
-
- /* Update backup status on failure */
- WALInsertLockAcquireExclusive();
- if (exclusive)
+ if (XLogCtl->Insert.runningBackups == 0)
{
- Assert(XLogCtl->Insert.exclusiveBackupState == EXCLUSIVE_BACKUP_STOPPING);
- XLogCtl->Insert.exclusiveBackupState = EXCLUSIVE_BACKUP_IN_PROGRESS;
+ XLogCtl->Insert.forcePageWrites = false;
}
WALInsertLockRelease();
}
@@ -8555,14 +8352,11 @@ get_backup_status(void)
}
/*
- * do_pg_stop_backup
+ * do_pg_backup_stop
*
* Utility function called at the end of an online backup. It cleans up the
* backup state and can optionally wait for WAL segments to be archived.
*
- * If labelfile is NULL, this stops an exclusive backup. Otherwise this stops
- * the non-exclusive backup specified by 'labelfile'.
- *
* Returns the last WAL location that must be present to restore from this
* backup, and the corresponding timeline ID in *stoptli_p.
*
@@ -8570,9 +8364,8 @@ get_backup_status(void)
* permissions of the calling user!
*/
XLogRecPtr
-do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
+do_pg_backup_stop(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
{
- bool exclusive = (labelfile == NULL);
bool backup_started_in_recovery = false;
XLogRecPtr startpoint;
XLogRecPtr stoppoint;
@@ -8586,7 +8379,6 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
char histfilename[MAXFNAMELEN];
char backupfrom[20];
XLogSegNo _logSegNo;
- FILE *lfp;
FILE *fp;
char ch;
int seconds_before_warning;
@@ -8599,15 +8391,6 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
backup_started_in_recovery = RecoveryInProgress();
- /*
- * Currently only non-exclusive backup can be taken during recovery.
- */
- if (backup_started_in_recovery && exclusive)
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("recovery is in progress"),
- errhint("WAL control functions cannot be executed during recovery.")));
-
/*
* During recovery, we don't need to check WAL level. Because, if WAL
* level is not sufficient, it's impossible to get here during recovery.
@@ -8618,106 +8401,23 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
errmsg("WAL level not sufficient for making an online backup"),
errhint("wal_level must be set to \"replica\" or \"logical\" at server start.")));
- if (exclusive)
- {
- /*
- * At first, mark that we're now stopping an exclusive backup, to
- * ensure that there are no other sessions currently running
- * pg_start_backup() or pg_stop_backup().
- */
- WALInsertLockAcquireExclusive();
- if (XLogCtl->Insert.exclusiveBackupState != EXCLUSIVE_BACKUP_IN_PROGRESS)
- {
- WALInsertLockRelease();
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("exclusive backup not in progress")));
- }
- XLogCtl->Insert.exclusiveBackupState = EXCLUSIVE_BACKUP_STOPPING;
- WALInsertLockRelease();
-
- /*
- * Remove backup_label. In case of failure, the state for an exclusive
- * backup is switched back to in-progress.
- */
- PG_ENSURE_ERROR_CLEANUP(pg_stop_backup_callback, (Datum) BoolGetDatum(exclusive));
- {
- /*
- * Read the existing label file into memory.
- */
- struct stat statbuf;
- int r;
-
- if (stat(BACKUP_LABEL_FILE, &statbuf))
- {
- /* should not happen per the upper checks */
- if (errno != ENOENT)
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not stat file \"%s\": %m",
- BACKUP_LABEL_FILE)));
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("a backup is not in progress")));
- }
-
- lfp = AllocateFile(BACKUP_LABEL_FILE, "r");
- if (!lfp)
- {
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not read file \"%s\": %m",
- BACKUP_LABEL_FILE)));
- }
- labelfile = palloc(statbuf.st_size + 1);
- r = fread(labelfile, statbuf.st_size, 1, lfp);
- labelfile[statbuf.st_size] = '\0';
-
- /*
- * Close and remove the backup label file
- */
- if (r != 1 || ferror(lfp) || FreeFile(lfp))
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not read file \"%s\": %m",
- BACKUP_LABEL_FILE)));
- durable_unlink(BACKUP_LABEL_FILE, ERROR);
-
- /*
- * Remove tablespace_map file if present, it is created only if
- * there are tablespaces.
- */
- durable_unlink(TABLESPACE_MAP, DEBUG1);
- }
- PG_END_ENSURE_ERROR_CLEANUP(pg_stop_backup_callback, (Datum) BoolGetDatum(exclusive));
- }
-
/*
- * OK to update backup counters, forcePageWrites and session-level lock.
+ * OK to update backup counters, forcePageWrites, and session-level lock.
*
* Note that CHECK_FOR_INTERRUPTS() must not occur while updating them.
* Otherwise they can be updated inconsistently, and which might cause
* do_pg_abort_backup() to fail.
*/
WALInsertLockAcquireExclusive();
- if (exclusive)
- {
- XLogCtl->Insert.exclusiveBackupState = EXCLUSIVE_BACKUP_NONE;
- }
- else
- {
- /*
- * The user-visible pg_start/stop_backup() functions that operate on
- * exclusive backups can be called at any time, but for non-exclusive
- * backups, it is expected that each do_pg_start_backup() call is
- * matched by exactly one do_pg_stop_backup() call.
- */
- Assert(XLogCtl->Insert.nonExclusiveBackups > 0);
- XLogCtl->Insert.nonExclusiveBackups--;
- }
- if (XLogCtl->Insert.exclusiveBackupState == EXCLUSIVE_BACKUP_NONE &&
- XLogCtl->Insert.nonExclusiveBackups == 0)
+ /*
+ * It is expected that each do_pg_backup_start() call is matched by exactly
+ * one do_pg_backup_stop() call.
+ */
+ Assert(XLogCtl->Insert.runningBackups > 0);
+ XLogCtl->Insert.runningBackups--;
+
+ if (XLogCtl->Insert.runningBackups == 0)
{
XLogCtl->Insert.forcePageWrites = false;
}
@@ -8975,17 +8675,13 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
/*
* do_pg_abort_backup: abort a running backup
*
- * This does just the most basic steps of do_pg_stop_backup(), by taking the
+ * This does just the most basic steps of do_pg_backup_stop(), by taking the
* system out of backup mode, thus making it a lot more safe to call from
* an error handler.
*
* The caller can pass 'arg' as 'true' or 'false' to control whether a warning
* is emitted.
*
- * NB: This is only for aborting a non-exclusive backup that doesn't write
- * backup_label. A backup started with pg_start_backup() needs to be finished
- * with pg_stop_backup().
- *
* NB: This gets used as a before_shmem_exit handler, hence the odd-looking
* signature.
*/
@@ -8995,18 +8691,16 @@ do_pg_abort_backup(int code, Datum arg)
bool emit_warning = DatumGetBool(arg);
/*
- * Quick exit if session is not keeping around a non-exclusive backup
- * already started.
+ * Quick exit if session does not have a running backup.
*/
- if (sessionBackupState != SESSION_BACKUP_NON_EXCLUSIVE)
+ if (sessionBackupState != SESSION_BACKUP_RUNNING)
return;
WALInsertLockAcquireExclusive();
- Assert(XLogCtl->Insert.nonExclusiveBackups > 0);
- XLogCtl->Insert.nonExclusiveBackups--;
+ Assert(XLogCtl->Insert.runningBackups > 0);
+ XLogCtl->Insert.runningBackups--;
- if (XLogCtl->Insert.exclusiveBackupState == EXCLUSIVE_BACKUP_NONE &&
- XLogCtl->Insert.nonExclusiveBackups == 0)
+ if (XLogCtl->Insert.runningBackups == 0)
{
XLogCtl->Insert.forcePageWrites = false;
}
@@ -9014,7 +8708,7 @@ do_pg_abort_backup(int code, Datum arg)
if (emit_warning)
ereport(WARNING,
- (errmsg("aborting backup due to backend exiting before pg_stop_backup was called")));
+ (errmsg("aborting backup due to backend exiting before pg_backup_stop was called")));
}
/*
@@ -9074,87 +8768,6 @@ GetOldestRestartPoint(XLogRecPtr *oldrecptr, TimeLineID *oldtli)
LWLockRelease(ControlFileLock);
}
-/*
- * BackupInProgress: check if online backup mode is active
- *
- * This is done by checking for existence of the "backup_label" file.
- */
-bool
-BackupInProgress(void)
-{
- struct stat stat_buf;
-
- return (stat(BACKUP_LABEL_FILE, &stat_buf) == 0);
-}
-
-/*
- * CancelBackup: rename the "backup_label" and "tablespace_map"
- * files to cancel backup mode
- *
- * If the "backup_label" file exists, it will be renamed to "backup_label.old".
- * Similarly, if the "tablespace_map" file exists, it will be renamed to
- * "tablespace_map.old".
- *
- * Note that this will render an online backup in progress
- * useless. To correctly finish an online backup, pg_stop_backup must be
- * called.
- */
-void
-CancelBackup(void)
-{
- struct stat stat_buf;
-
- /* if the backup_label file is not there, return */
- if (stat(BACKUP_LABEL_FILE, &stat_buf) < 0)
- return;
-
- /* remove leftover file from previously canceled backup if it exists */
- unlink(BACKUP_LABEL_OLD);
-
- if (durable_rename(BACKUP_LABEL_FILE, BACKUP_LABEL_OLD, DEBUG1) != 0)
- {
- ereport(WARNING,
- (errcode_for_file_access(),
- errmsg("online backup mode was not canceled"),
- errdetail("File \"%s\" could not be renamed to \"%s\": %m.",
- BACKUP_LABEL_FILE, BACKUP_LABEL_OLD)));
- return;
- }
-
- /* if the tablespace_map file is not there, return */
- if (stat(TABLESPACE_MAP, &stat_buf) < 0)
- {
- ereport(LOG,
- (errmsg("online backup mode canceled"),
- errdetail("File \"%s\" was renamed to \"%s\".",
- BACKUP_LABEL_FILE, BACKUP_LABEL_OLD)));
- return;
- }
-
- /* remove leftover file from previously canceled backup if it exists */
- unlink(TABLESPACE_MAP_OLD);
-
- if (durable_rename(TABLESPACE_MAP, TABLESPACE_MAP_OLD, DEBUG1) == 0)
- {
- ereport(LOG,
- (errmsg("online backup mode canceled"),
- errdetail("Files \"%s\" and \"%s\" were renamed to "
- "\"%s\" and \"%s\", respectively.",
- BACKUP_LABEL_FILE, TABLESPACE_MAP,
- BACKUP_LABEL_OLD, TABLESPACE_MAP_OLD)));
- }
- else
- {
- ereport(WARNING,
- (errcode_for_file_access(),
- errmsg("online backup mode canceled"),
- errdetail("File \"%s\" was renamed to \"%s\", but "
- "file \"%s\" could not be renamed to \"%s\": %m.",
- BACKUP_LABEL_FILE, BACKUP_LABEL_OLD,
- TABLESPACE_MAP, TABLESPACE_MAP_OLD)));
- }
-}
-
/* Thin wrapper around ShutdownWalRcv(). */
void
XLogShutdownWalRcv(void)
diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c
index 12e2bf4135..ee375f1bde 100644
--- a/src/backend/access/transam/xlogfuncs.c
+++ b/src/backend/access/transam/xlogfuncs.c
@@ -39,13 +39,13 @@
#include "utils/tuplestore.h"
/*
- * Store label file and tablespace map during non-exclusive backups.
+ * Store label file and tablespace map during backups.
*/
static StringInfo label_file;
static StringInfo tblspc_map_file;
/*
- * pg_start_backup: set up for taking an on-line backup dump
+ * pg_backup_start: set up for taking an on-line backup dump
*
* Essentially what this does is to create a backup label file in $PGDATA,
* where it will be archived as part of the backup dump. The label file
@@ -57,105 +57,44 @@ static StringInfo tblspc_map_file;
* GRANT system.
*/
Datum
-pg_start_backup(PG_FUNCTION_ARGS)
+pg_backup_start(PG_FUNCTION_ARGS)
{
text *backupid = PG_GETARG_TEXT_PP(0);
bool fast = PG_GETARG_BOOL(1);
- bool exclusive = PG_GETARG_BOOL(2);
char *backupidstr;
XLogRecPtr startpoint;
SessionBackupState status = get_backup_status();
+ MemoryContext oldcontext;
backupidstr = text_to_cstring(backupid);
- if (status == SESSION_BACKUP_NON_EXCLUSIVE)
+ if (status == SESSION_BACKUP_RUNNING)
ereport(ERROR,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("a backup is already in progress in this session")));
- if (exclusive)
- {
- startpoint = do_pg_start_backup(backupidstr, fast, NULL, NULL,
- NULL, NULL);
- }
- else
- {
- MemoryContext oldcontext;
-
- /*
- * Label file and tablespace map file need to be long-lived, since
- * they are read in pg_stop_backup.
- */
- oldcontext = MemoryContextSwitchTo(TopMemoryContext);
- label_file = makeStringInfo();
- tblspc_map_file = makeStringInfo();
- MemoryContextSwitchTo(oldcontext);
+ /*
+ * Label file and tablespace map file need to be long-lived, since
+ * they are read in pg_backup_stop.
+ */
+ oldcontext = MemoryContextSwitchTo(TopMemoryContext);
+ label_file = makeStringInfo();
+ tblspc_map_file = makeStringInfo();
+ MemoryContextSwitchTo(oldcontext);
- register_persistent_abort_backup_handler();
+ register_persistent_abort_backup_handler();
- startpoint = do_pg_start_backup(backupidstr, fast, NULL, label_file,
- NULL, tblspc_map_file);
- }
+ startpoint = do_pg_backup_start(backupidstr, fast, NULL, label_file,
+ NULL, tblspc_map_file);
PG_RETURN_LSN(startpoint);
}
-/*
- * pg_stop_backup: finish taking an on-line backup dump
- *
- * We write an end-of-backup WAL record, and remove the backup label file
- * created by pg_start_backup, creating a backup history file in pg_wal
- * instead (whence it will immediately be archived). The backup history file
- * contains the same info found in the label file, plus the backup-end time
- * and WAL location. Before 9.0, the backup-end time was read from the backup
- * history file at the beginning of archive recovery, but we now use the WAL
- * record for that and the file is for informational and debug purposes only.
- *
- * Note: different from CancelBackup which just cancels online backup mode.
- *
- * Note: this version is only called to stop an exclusive backup. The function
- * pg_stop_backup_v2 (overloaded as pg_stop_backup in SQL) is called to
- * stop non-exclusive backups.
- *
- * Permission checking for this function is managed through the normal
- * GRANT system.
- */
-Datum
-pg_stop_backup(PG_FUNCTION_ARGS)
-{
- XLogRecPtr stoppoint;
- SessionBackupState status = get_backup_status();
-
- if (status == SESSION_BACKUP_NON_EXCLUSIVE)
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("non-exclusive backup in progress"),
- errhint("Did you mean to use pg_stop_backup('f')?")));
-
- /*
- * Exclusive backups were typically started in a different connection, so
- * don't try to verify that status of backup is set to
- * SESSION_BACKUP_EXCLUSIVE in this function. Actual verification that an
- * exclusive backup is in fact running is handled inside
- * do_pg_stop_backup.
- */
- stoppoint = do_pg_stop_backup(NULL, true, NULL);
-
- PG_RETURN_LSN(stoppoint);
-}
-
/*
- * pg_stop_backup_v2: finish taking exclusive or nonexclusive on-line backup.
- *
- * Works the same as pg_stop_backup, except for non-exclusive backups it returns
- * the backup label and tablespace map files as text fields in as part of the
- * resultset.
+ * pg_backup_stop: finish taking an on-line backup.
*
- * The first parameter (variable 'exclusive') allows the user to tell us if
- * this is an exclusive or a non-exclusive backup.
- *
- * The second parameter (variable 'waitforarchive'), which is optional,
+ * The first parameter (variable 'waitforarchive'), which is optional,
* allows the user to choose if they want to wait for the WAL to be archived
* or if we should just return as soon as the WAL record is written.
*
@@ -163,7 +102,7 @@ pg_stop_backup(PG_FUNCTION_ARGS)
* GRANT system.
*/
Datum
-pg_stop_backup_v2(PG_FUNCTION_ARGS)
+pg_backup_stop(PG_FUNCTION_ARGS)
{
ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
TupleDesc tupdesc;
@@ -173,8 +112,7 @@ pg_stop_backup_v2(PG_FUNCTION_ARGS)
Datum values[3];
bool nulls[3];
- bool exclusive = PG_GETARG_BOOL(0);
- bool waitforarchive = PG_GETARG_BOOL(1);
+ bool waitforarchive = PG_GETARG_BOOL(0);
XLogRecPtr stoppoint;
SessionBackupState status = get_backup_status();
@@ -205,51 +143,29 @@ pg_stop_backup_v2(PG_FUNCTION_ARGS)
MemSet(values, 0, sizeof(values));
MemSet(nulls, 0, sizeof(nulls));
- if (exclusive)
- {
- if (status == SESSION_BACKUP_NON_EXCLUSIVE)
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("non-exclusive backup in progress"),
- errhint("Did you mean to use pg_stop_backup('f')?")));
-
- /*
- * Stop the exclusive backup, and since we're in an exclusive backup
- * return NULL for both backup_label and tablespace_map.
- */
- stoppoint = do_pg_stop_backup(NULL, waitforarchive, NULL);
-
- nulls[1] = true;
- nulls[2] = true;
- }
- else
- {
- if (status != SESSION_BACKUP_NON_EXCLUSIVE)
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("non-exclusive backup is not in progress"),
- errhint("Did you mean to use pg_stop_backup('t')?")));
+ if (status != SESSION_BACKUP_RUNNING)
+ ereport(ERROR,
+ (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ errmsg("backup is not in progress"),
+ errhint("Did you call pg_backup_start()?")));
- /*
- * Stop the non-exclusive backup. Return a copy of the backup label
- * and tablespace map so they can be written to disk by the caller.
- */
- stoppoint = do_pg_stop_backup(label_file->data, waitforarchive, NULL);
-
- values[1] = CStringGetTextDatum(label_file->data);
- values[2] = CStringGetTextDatum(tblspc_map_file->data);
-
- /* Free structures allocated in TopMemoryContext */
- pfree(label_file->data);
- pfree(label_file);
- label_file = NULL;
- pfree(tblspc_map_file->data);
- pfree(tblspc_map_file);
- tblspc_map_file = NULL;
- }
+ /*
+ * Stop the backup. Return a copy of the backup label and tablespace map so
+ * they can be written to disk by the caller.
+ */
+ stoppoint = do_pg_backup_stop(label_file->data, waitforarchive, NULL);
- /* Stoppoint is included on both exclusive and nonexclusive backups */
values[0] = LSNGetDatum(stoppoint);
+ values[1] = CStringGetTextDatum(label_file->data);
+ values[2] = CStringGetTextDatum(tblspc_map_file->data);
+
+ /* Free structures allocated in TopMemoryContext */
+ pfree(label_file->data);
+ pfree(label_file);
+ label_file = NULL;
+ pfree(tblspc_map_file->data);
+ pfree(tblspc_map_file);
+ tblspc_map_file = NULL;
tuplestore_putvalues(tupstore, tupdesc, values, nulls);
@@ -322,7 +238,7 @@ pg_create_restore_point(PG_FUNCTION_ARGS)
}
/*
- * Report the current WAL write location (same format as pg_start_backup etc)
+ * Report the current WAL write location (same format as pg_backup_start etc)
*
* This is useful for determining how much of WAL is visible to an external
* archiving process. Note that the data before this point is written out
@@ -345,7 +261,7 @@ pg_current_wal_lsn(PG_FUNCTION_ARGS)
}
/*
- * Report the current WAL insert location (same format as pg_start_backup etc)
+ * Report the current WAL insert location (same format as pg_backup_start etc)
*
* This function is mostly for debugging purposes.
*/
@@ -366,7 +282,7 @@ pg_current_wal_insert_lsn(PG_FUNCTION_ARGS)
}
/*
- * Report the current WAL flush location (same format as pg_start_backup etc)
+ * Report the current WAL flush location (same format as pg_backup_start etc)
*
* This function is mostly for debugging purposes.
*/
@@ -387,7 +303,7 @@ pg_current_wal_flush_lsn(PG_FUNCTION_ARGS)
}
/*
- * Report the last WAL receive location (same format as pg_start_backup etc)
+ * Report the last WAL receive location (same format as pg_backup_start etc)
*
* This is useful for determining how much of WAL is guaranteed to be received
* and synced to disk by walreceiver.
@@ -406,7 +322,7 @@ pg_last_wal_receive_lsn(PG_FUNCTION_ARGS)
}
/*
- * Report the last WAL replay location (same format as pg_start_backup etc)
+ * Report the last WAL replay location (same format as pg_backup_start etc)
*
* This is useful for determining how much of WAL is visible to read-only
* connections during recovery.
@@ -426,7 +342,7 @@ pg_last_wal_replay_lsn(PG_FUNCTION_ARGS)
/*
* Compute an xlog file name and decimal byte offset given a WAL location,
- * such as is returned by pg_stop_backup() or pg_switch_wal().
+ * such as is returned by pg_backup_stop() or pg_switch_wal().
*
* Note that a location exactly at a segment boundary is taken to be in
* the previous segment. This is usually the right thing, since the
@@ -494,7 +410,7 @@ pg_walfile_name_offset(PG_FUNCTION_ARGS)
/*
* Compute an xlog file name given a WAL location,
- * such as is returned by pg_stop_backup() or pg_switch_wal().
+ * such as is returned by pg_backup_stop() or pg_switch_wal().
*/
Datum
pg_walfile_name(PG_FUNCTION_ARGS)
@@ -669,81 +585,6 @@ pg_wal_lsn_diff(PG_FUNCTION_ARGS)
PG_RETURN_NUMERIC(result);
}
-/*
- * Returns bool with current on-line backup mode, a global state.
- */
-Datum
-pg_is_in_backup(PG_FUNCTION_ARGS)
-{
- PG_RETURN_BOOL(BackupInProgress());
-}
-
-/*
- * Returns start time of an online exclusive backup.
- *
- * When there's no exclusive backup in progress, the function
- * returns NULL.
- */
-Datum
-pg_backup_start_time(PG_FUNCTION_ARGS)
-{
- Datum xtime;
- FILE *lfp;
- char fline[MAXPGPATH];
- char backup_start_time[30];
-
- /*
- * See if label file is present
- */
- lfp = AllocateFile(BACKUP_LABEL_FILE, "r");
- if (lfp == NULL)
- {
- if (errno != ENOENT)
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not read file \"%s\": %m",
- BACKUP_LABEL_FILE)));
- PG_RETURN_NULL();
- }
-
- /*
- * Parse the file to find the START TIME line.
- */
- backup_start_time[0] = '\0';
- while (fgets(fline, sizeof(fline), lfp) != NULL)
- {
- if (sscanf(fline, "START TIME: %25[^\n]\n", backup_start_time) == 1)
- break;
- }
-
- /* Check for a read error. */
- if (ferror(lfp))
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not read file \"%s\": %m", BACKUP_LABEL_FILE)));
-
- /* Close the backup label file. */
- if (FreeFile(lfp))
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not close file \"%s\": %m", BACKUP_LABEL_FILE)));
-
- if (strlen(backup_start_time) == 0)
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("invalid data in file \"%s\"", BACKUP_LABEL_FILE)));
-
- /*
- * Convert the time string read from file to TimestampTz form.
- */
- xtime = DirectFunctionCall3(timestamptz_in,
- CStringGetDatum(backup_start_time),
- ObjectIdGetDatum(InvalidOid),
- Int32GetDatum(-1));
-
- PG_RETURN_DATUM(xtime);
-}
-
/*
* Promotes a standby server.
*
diff --git a/src/backend/access/transam/xlogrecovery.c b/src/backend/access/transam/xlogrecovery.c
index f9f212680b..d2b5e7f32c 100644
--- a/src/backend/access/transam/xlogrecovery.c
+++ b/src/backend/access/transam/xlogrecovery.c
@@ -1966,7 +1966,7 @@ xlogrecovery_redo(XLogReaderState *record, TimeLineID replayTLI)
{
/*
* We have reached the end of base backup, the point where
- * pg_stop_backup() was done. The data on disk is now consistent
+ * pg_backup_stop() was done. The data on disk is now consistent
* (assuming we have also reached minRecoveryPoint). Set
* backupEndPoint to the current LSN, so that the next call to
* CheckRecoveryConsistency() will notice it and do the
diff --git a/src/backend/catalog/system_functions.sql b/src/backend/catalog/system_functions.sql
index 758ab6e25a..36aa175e66 100644
--- a/src/backend/catalog/system_functions.sql
+++ b/src/backend/catalog/system_functions.sql
@@ -377,14 +377,14 @@ BEGIN ATOMIC
END;
CREATE OR REPLACE FUNCTION
- pg_start_backup(label text, fast boolean DEFAULT false, exclusive boolean DEFAULT true)
- RETURNS pg_lsn STRICT VOLATILE LANGUAGE internal AS 'pg_start_backup'
+ pg_backup_start(label text, fast boolean DEFAULT false)
+ RETURNS pg_lsn STRICT VOLATILE LANGUAGE internal AS 'pg_backup_start'
PARALLEL RESTRICTED;
-CREATE OR REPLACE FUNCTION pg_stop_backup (
- exclusive boolean, wait_for_archive boolean DEFAULT true,
- OUT lsn pg_lsn, OUT labelfile text, OUT spcmapfile text)
- RETURNS SETOF record STRICT VOLATILE LANGUAGE internal as 'pg_stop_backup_v2'
+CREATE OR REPLACE FUNCTION pg_backup_stop (
+ wait_for_archive boolean DEFAULT true, OUT lsn pg_lsn,
+ OUT labelfile text, OUT spcmapfile text)
+ RETURNS SETOF record STRICT VOLATILE LANGUAGE internal as 'pg_backup_stop'
PARALLEL RESTRICTED;
CREATE OR REPLACE FUNCTION
@@ -603,11 +603,9 @@ AS 'unicode_is_normalized';
-- available to superuser / cluster owner, if they choose.
--
-REVOKE EXECUTE ON FUNCTION pg_start_backup(text, boolean, boolean) FROM public;
+REVOKE EXECUTE ON FUNCTION pg_backup_start(text, boolean) FROM public;
-REVOKE EXECUTE ON FUNCTION pg_stop_backup() FROM public;
-
-REVOKE EXECUTE ON FUNCTION pg_stop_backup(boolean, boolean) FROM public;
+REVOKE EXECUTE ON FUNCTION pg_backup_stop(boolean) FROM public;
REVOKE EXECUTE ON FUNCTION pg_create_restore_point(text) FROM public;
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index 80bb269599..b6767ed72e 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -348,7 +348,6 @@ static PMState pmState = PM_INIT;
typedef enum
{
ALLOW_ALL_CONNS, /* normal not-shutting-down state */
- ALLOW_SUPERUSER_CONNS, /* only superusers can connect */
ALLOW_NO_CONNS /* no new connections allowed, period */
} ConnsAllowedState;
@@ -2546,19 +2545,11 @@ canAcceptConnections(int backend_type)
/*
* "Smart shutdown" restrictions are applied only to normal connections,
- * not to autovac workers or bgworkers. When only superusers can connect,
- * we return CAC_SUPERUSER to indicate that superuserness must be checked
- * later. Note that neither CAC_OK nor CAC_SUPERUSER can safely be
- * returned until we have checked for too many children.
+ * not to autovac workers or bgworkers.
*/
if (connsAllowed != ALLOW_ALL_CONNS &&
backend_type == BACKEND_TYPE_NORMAL)
- {
- if (connsAllowed == ALLOW_SUPERUSER_CONNS)
- result = CAC_SUPERUSER; /* allow superusers only */
- else
- return CAC_SHUTDOWN; /* shutdown is pending */
- }
+ return CAC_SHUTDOWN; /* shutdown is pending */
/*
* Don't start too many children.
@@ -2877,16 +2868,11 @@ pmdie(SIGNAL_ARGS)
#endif
/*
- * If we reached normal running, we have to wait for any online
- * backup mode to end; otherwise go straight to waiting for client
- * backends to exit. (The difference is that in the former state,
- * we'll still let in new superuser clients, so that somebody can
- * end the online backup mode.) If already in PM_STOP_BACKENDS or
+ * If we reached normal running, we go straight to waiting for
+ * client backends to exit. If already in PM_STOP_BACKENDS or
* a later state, do not change it.
*/
- if (pmState == PM_RUN)
- connsAllowed = ALLOW_SUPERUSER_CONNS;
- else if (pmState == PM_HOT_STANDBY)
+ if (pmState == PM_RUN || pmState == PM_HOT_STANDBY)
connsAllowed = ALLOW_NO_CONNS;
else if (pmState == PM_STARTUP || pmState == PM_RECOVERY)
{
@@ -3842,16 +3828,6 @@ PostmasterStateMachine(void)
/* If we're doing a smart shutdown, try to advance that state. */
if (pmState == PM_RUN || pmState == PM_HOT_STANDBY)
{
- if (connsAllowed == ALLOW_SUPERUSER_CONNS)
- {
- /*
- * ALLOW_SUPERUSER_CONNS state ends as soon as online backup mode
- * is not active.
- */
- if (!BackupInProgress())
- connsAllowed = ALLOW_NO_CONNS;
- }
-
if (connsAllowed == ALLOW_NO_CONNS)
{
/*
@@ -4044,18 +4020,6 @@ PostmasterStateMachine(void)
}
else
{
- /*
- * Terminate exclusive backup mode to avoid recovery after a clean
- * fast shutdown. Since an exclusive backup can only be taken
- * during normal running (and not, for example, while running
- * under Hot Standby) it only makes sense to do this if we reached
- * normal running. If we're still in recovery, the backup file is
- * one we're recovering *from*, and we must keep it around so that
- * recovery restarts from the right place.
- */
- if (ReachedNormalRunning)
- CancelBackup();
-
/*
* Normal exit from the postmaster is here. We don't need to log
* anything here, since the UnlinkLockFiles proc_exit callback
diff --git a/src/backend/replication/basebackup.c b/src/backend/replication/basebackup.c
index 0bf28b55d7..a3b845579b 100644
--- a/src/backend/replication/basebackup.c
+++ b/src/backend/replication/basebackup.c
@@ -195,10 +195,8 @@ static const struct exclude_list_item excludeFiles[] =
{RELCACHE_INIT_FILENAME, true},
/*
- * If there's a backup_label or tablespace_map file, it belongs to a
- * backup started by the user with pg_start_backup(). It is *not* correct
- * for this backup. Our backup_label/tablespace_map is injected into the
- * tar separately.
+ * backup_label and tablespace_map should not exist in in a running cluster
+ * capable of doing an online backup, but exclude then just in case.
*/
{BACKUP_LABEL_FILE, false},
{TABLESPACE_MAP, false},
@@ -275,16 +273,16 @@ perform_base_backup(basebackup_options *opt, bbsink *sink)
total_checksum_failures = 0;
basebackup_progress_wait_checkpoint();
- state.startptr = do_pg_start_backup(opt->label, opt->fastcheckpoint,
+ state.startptr = do_pg_backup_start(opt->label, opt->fastcheckpoint,
&state.starttli,
labelfile, &state.tablespaces,
tblspc_map_file);
/*
- * Once do_pg_start_backup has been called, ensure that any failure causes
+ * Once do_pg_backup_start has been called, ensure that any failure causes
* us to abort the backup so we don't "leak" a backup counter. For this
- * reason, *all* functionality between do_pg_start_backup() and the end of
- * do_pg_stop_backup() should be inside the error cleanup block!
+ * reason, *all* functionality between do_pg_backup_start() and the end of
+ * do_pg_backup_stop() should be inside the error cleanup block!
*/
PG_ENSURE_ERROR_CLEANUP(do_pg_abort_backup, BoolGetDatum(false));
@@ -405,7 +403,7 @@ perform_base_backup(basebackup_options *opt, bbsink *sink)
}
basebackup_progress_wait_wal_archive(&state);
- endptr = do_pg_stop_backup(labelfile->data, !opt->nowait, &endtli);
+ endptr = do_pg_backup_stop(labelfile->data, !opt->nowait, &endtli);
}
PG_END_ENSURE_ERROR_CLEANUP(do_pg_abort_backup, BoolGetDatum(false));
@@ -966,7 +964,7 @@ parse_basebackup_options(List *options, basebackup_options *opt)
/*
* SendBaseBackup() - send a complete base backup.
*
- * The function will put the system into backup mode like pg_start_backup()
+ * The function will put the system into backup mode like pg_backup_start()
* does, so that the backup is consistent even though we read directly from
* the filesystem, bypassing the buffer cache.
*/
@@ -1225,7 +1223,7 @@ sendDir(bbsink *sink, const char *path, int basepathlen, bool sizeonly,
* error in that case. The error handler further up will call
* do_pg_abort_backup() for us. Also check that if the backup was
* started while still in recovery, the server wasn't promoted.
- * do_pg_stop_backup() will check that too, but it's better to stop
+ * do_pg_backup_stop() will check that too, but it's better to stop
* the backup early than continue to the end and fail there.
*/
CHECK_FOR_INTERRUPTS();
diff --git a/src/bin/pg_basebackup/t/010_pg_basebackup.pl b/src/bin/pg_basebackup/t/010_pg_basebackup.pl
index 8cb8cfe045..c7c01a0992 100644
--- a/src/bin/pg_basebackup/t/010_pg_basebackup.pl
+++ b/src/bin/pg_basebackup/t/010_pg_basebackup.pl
@@ -185,6 +185,10 @@ isnt(slurp_file("$tempdir/backup/backup_label"),
'DONOTCOPY', 'existing backup_label not copied');
rmtree("$tempdir/backup");
+# Now delete the bogus backup_label file since it will interfere with startup
+unlink("$pgdata/backup_label")
+ or BAIL_OUT("unable to unlink $pgdata/backup_label");
+
$node->command_ok(
[
@pg_basebackup_defs, '-D',
diff --git a/src/bin/pg_ctl/pg_ctl.c b/src/bin/pg_ctl/pg_ctl.c
index 3c182c97d4..ee3fa148b6 100644
--- a/src/bin/pg_ctl/pg_ctl.c
+++ b/src/bin/pg_ctl/pg_ctl.c
@@ -1069,7 +1069,7 @@ do_stop(void)
get_control_dbstate() != DB_IN_ARCHIVE_RECOVERY)
{
print_msg(_("WARNING: online backup mode is active\n"
- "Shutdown will not complete until pg_stop_backup() is called.\n\n"));
+ "Shutdown will not complete until pg_backup_stop() is called.\n\n"));
}
print_msg(_("waiting for server to shut down..."));
@@ -1145,7 +1145,7 @@ do_restart(void)
get_control_dbstate() != DB_IN_ARCHIVE_RECOVERY)
{
print_msg(_("WARNING: online backup mode is active\n"
- "Shutdown will not complete until pg_stop_backup() is called.\n\n"));
+ "Shutdown will not complete until pg_backup_stop() is called.\n\n"));
}
print_msg(_("waiting for server to shut down..."));
diff --git a/src/bin/pg_rewind/filemap.c b/src/bin/pg_rewind/filemap.c
index 7211090f47..fb52debf7a 100644
--- a/src/bin/pg_rewind/filemap.c
+++ b/src/bin/pg_rewind/filemap.c
@@ -140,9 +140,9 @@ static const struct exclude_list_item excludeFiles[] =
{"pg_internal.init", true}, /* defined as RELCACHE_INIT_FILENAME */
/*
- * If there's a backup_label or tablespace_map file, it belongs to a
- * backup started by the user with pg_start_backup(). It is *not* correct
- * for this backup. Our backup_label is written later on separately.
+ * If there is a backup_label or tablespace_map file, it indicates that
+ * a recovery failed and this cluster probably can't be rewound, but
+ * exclude them anyway if they are found.
*/
{"backup_label", false}, /* defined as BACKUP_LABEL_FILE */
{"tablespace_map", false}, /* defined as TABLESPACE_MAP */
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index 4b45ac64db..be375df248 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -275,14 +275,13 @@ extern void XLogShutdownWalRcv(void);
typedef enum SessionBackupState
{
SESSION_BACKUP_NONE,
- SESSION_BACKUP_EXCLUSIVE,
- SESSION_BACKUP_NON_EXCLUSIVE
+ SESSION_BACKUP_RUNNING,
} SessionBackupState;
-extern XLogRecPtr do_pg_start_backup(const char *backupidstr, bool fast,
+extern XLogRecPtr do_pg_backup_start(const char *backupidstr, bool fast,
TimeLineID *starttli_p, StringInfo labelfile,
List **tablespaces, StringInfo tblspcmapfile);
-extern XLogRecPtr do_pg_stop_backup(char *labelfile, bool waitforarchive,
+extern XLogRecPtr do_pg_backup_stop(char *labelfile, bool waitforarchive,
TimeLineID *stoptli_p);
extern void do_pg_abort_backup(int code, Datum arg);
extern void register_persistent_abort_backup_handler(void);
diff --git a/src/include/catalog/pg_control.h b/src/include/catalog/pg_control.h
index 1f3dc24ac1..3d075fcef3 100644
--- a/src/include/catalog/pg_control.h
+++ b/src/include/catalog/pg_control.h
@@ -163,7 +163,7 @@ typedef struct ControlFileData
* from a backup, and must see a backup-end record before we can safely
* start up. If it's false, but backupStartPoint is set, a backup_label
* file was found at startup but it may have been a leftover from a stray
- * pg_start_backup() call, not accompanied by pg_stop_backup().
+ * pg_backup_start() call, not accompanied by pg_backup_stop().
*/
XLogRecPtr minRecoveryPoint;
TimeLineID minRecoveryPointTLI;
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index bf88858171..f49bf17e5b 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -6268,26 +6268,16 @@
proargtypes => 'int4 int8', proargnames => '{pid,timeout}',
prosrc => 'pg_terminate_backend' },
{ oid => '2172', descr => 'prepare for taking an online backup',
- proname => 'pg_start_backup', provolatile => 'v', proparallel => 'r',
- prorettype => 'pg_lsn', proargtypes => 'text bool bool',
- prosrc => 'pg_start_backup' },
-{ oid => '2173', descr => 'finish taking an online backup',
- proname => 'pg_stop_backup', provolatile => 'v', proparallel => 'r',
- prorettype => 'pg_lsn', proargtypes => '', prosrc => 'pg_stop_backup' },
+ proname => 'pg_backup_start', provolatile => 'v', proparallel => 'r',
+ prorettype => 'pg_lsn', proargtypes => 'text bool',
+ prosrc => 'pg_backup_start' },
{ oid => '2739', descr => 'finish taking an online backup',
- proname => 'pg_stop_backup', prorows => '1', proretset => 't',
+ proname => 'pg_backup_stop', prorows => '1', proretset => 't',
provolatile => 'v', proparallel => 'r', prorettype => 'record',
- proargtypes => 'bool bool', proallargtypes => '{bool,bool,pg_lsn,text,text}',
- proargmodes => '{i,i,o,o,o}',
- proargnames => '{exclusive,wait_for_archive,lsn,labelfile,spcmapfile}',
- prosrc => 'pg_stop_backup_v2' },
-{ oid => '3813', descr => 'true if server is in online backup',
- proname => 'pg_is_in_backup', provolatile => 'v', prorettype => 'bool',
- proargtypes => '', prosrc => 'pg_is_in_backup' },
-{ oid => '3814', descr => 'start time of an online backup',
- proname => 'pg_backup_start_time', provolatile => 's',
- prorettype => 'timestamptz', proargtypes => '',
- prosrc => 'pg_backup_start_time' },
+ proargtypes => 'bool', proallargtypes => '{bool,pg_lsn,text,text}',
+ proargmodes => '{i,o,o,o}',
+ proargnames => '{wait_for_archive,lsn,labelfile,spcmapfile}',
+ prosrc => 'pg_backup_stop' },
{ oid => '3436', descr => 'promote standby server',
proname => 'pg_promote', provolatile => 'v', prorettype => 'bool',
proargtypes => 'bool int4', proargnames => '{wait,wait_seconds}',
diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h
index 0abc3ad540..9321d7f264 100644
--- a/src/include/miscadmin.h
+++ b/src/include/miscadmin.h
@@ -481,10 +481,6 @@ extern void process_session_preload_libraries(void);
extern void pg_bindtextdomain(const char *domain);
extern bool has_rolreplication(Oid roleid);
-/* in access/transam/xlog.c */
-extern bool BackupInProgress(void);
-extern void CancelBackup(void);
-
/* in executor/nodeHash.c */
extern size_t get_hash_memory_limit(void);
diff --git a/src/test/perl/PostgreSQL/Test/Cluster.pm b/src/test/perl/PostgreSQL/Test/Cluster.pm
index be05845248..065670b5c1 100644
--- a/src/test/perl/PostgreSQL/Test/Cluster.pm
+++ b/src/test/perl/PostgreSQL/Test/Cluster.pm
@@ -634,25 +634,6 @@ sub backup
return;
}
-=item $node->backup_fs_hot(backup_name)
-
-Create a backup with a filesystem level copy in subdirectory B<backup_name> of
-B<< $node->backup_dir >>, including WAL.
-
-Archiving must be enabled, as B<pg_start_backup()> and B<pg_stop_backup()> are
-used. This is not checked or enforced.
-
-The backup name is passed as the backup label to B<pg_start_backup()>.
-
-=cut
-
-sub backup_fs_hot
-{
- my ($self, $backup_name) = @_;
- $self->_backup_fs($backup_name, 1);
- return;
-}
-
=item $node->backup_fs_cold(backup_name)
Create a backup with a filesystem level copy in subdirectory B<backup_name> of
@@ -666,53 +647,18 @@ Use B<backup> or B<backup_fs_hot> if you want to back up a running server.
sub backup_fs_cold
{
my ($self, $backup_name) = @_;
- $self->_backup_fs($backup_name, 0);
- return;
-}
-
-
-# Common sub of backup_fs_hot and backup_fs_cold
-sub _backup_fs
-{
- my ($self, $backup_name, $hot) = @_;
- my $backup_path = $self->backup_dir . '/' . $backup_name;
- my $port = $self->port;
- my $name = $self->name;
-
- print "# Taking filesystem backup $backup_name from node \"$name\"\n";
-
- if ($hot)
- {
- my $stdout = $self->safe_psql('postgres',
- "SELECT * FROM pg_start_backup('$backup_name');");
- print "# pg_start_backup: $stdout\n";
- }
PostgreSQL::Test::RecursiveCopy::copypath(
$self->data_dir,
- $backup_path,
+ $self->backup_dir . '/' . $backup_name,
filterfn => sub {
my $src = shift;
return ($src ne 'log' and $src ne 'postmaster.pid');
});
- if ($hot)
- {
-
- # We ignore pg_stop_backup's return value. We also assume archiving
- # is enabled; otherwise the caller will have to copy the remaining
- # segments.
- my $stdout =
- $self->safe_psql('postgres', 'SELECT * FROM pg_stop_backup();');
- print "# pg_stop_backup: $stdout\n";
- }
-
- print "# Backup finished\n";
return;
}
-
-
=pod
=item $node->init_from_backup(root_node, backup_name)
diff --git a/src/test/recovery/t/010_logical_decoding_timelines.pl b/src/test/recovery/t/010_logical_decoding_timelines.pl
index 6e8b0b1b96..6351633b50 100644
--- a/src/test/recovery/t/010_logical_decoding_timelines.pl
+++ b/src/test/recovery/t/010_logical_decoding_timelines.pl
@@ -69,7 +69,9 @@ $node_primary->safe_psql('dropme',
$node_primary->safe_psql('postgres', 'CHECKPOINT;');
my $backup_name = 'b1';
-$node_primary->backup_fs_hot($backup_name);
+$node_primary->stop();
+$node_primary->backup_fs_cold($backup_name);
+$node_primary->start();
$node_primary->safe_psql('postgres',
q[SELECT pg_create_physical_replication_slot('phys_slot');]);
--
2.25.1
On 03/01/22 20:03, Nathan Bossart wrote:
Here is a new version of the patch with the following changes:
I did not notice this earlier (sorry), but there seems to remain in
backup.sgml a programlisting example that shows a psql invocation
for pg_backup_start, then a tar command, then another psql invocation
for pg_backup_stop.
I think that was only workable for the exclusive mode, and now it is
necessary to issue pg_backup_start and pg_backup_stop in the same session.
(The 'touch backup_in_progress' business seems a bit bogus now too,
suggesting an exclusivity remembered from bygone days.)
I am not sure what a workable, simple example ought to look like.
Maybe a single psql script issuing the pg_backup_start and the
pg_backup_stop, with a tar command in between with \! ?
Several bricks shy of production-ready, but it would give the idea.
Regards,
-Chap
On Wed, Mar 02, 2022 at 02:23:51PM -0500, Chapman Flack wrote:
I did not notice this earlier (sorry), but there seems to remain in
backup.sgml a programlisting example that shows a psql invocation
for pg_backup_start, then a tar command, then another psql invocation
for pg_backup_stop.I think that was only workable for the exclusive mode, and now it is
necessary to issue pg_backup_start and pg_backup_stop in the same session.(The 'touch backup_in_progress' business seems a bit bogus now too,
suggesting an exclusivity remembered from bygone days.)I am not sure what a workable, simple example ought to look like.
Maybe a single psql script issuing the pg_backup_start and the
pg_backup_stop, with a tar command in between with \! ?Several bricks shy of production-ready, but it would give the idea.
Another option might be to just remove this section. The top of the
section mentions that this is easily done using pg_basebackup with the -X
parameter. The bottom part of the section includes more complicated steps
for when "more flexibility in copying the backup files is needed..."
AFAICT the more complicated strategy was around before pg_basebackup, and
the pg_basebackup recommendation was added in 2012 as part of 920febd.
Thoughts?
--
Nathan Bossart
Amazon Web Services: https://aws.amazon.com
On 3/8/22 14:01, Nathan Bossart wrote:
On Wed, Mar 02, 2022 at 02:23:51PM -0500, Chapman Flack wrote:
I did not notice this earlier (sorry), but there seems to remain in
backup.sgml a programlisting example that shows a psql invocation
for pg_backup_start, then a tar command, then another psql invocation
for pg_backup_stop.I think that was only workable for the exclusive mode, and now it is
necessary to issue pg_backup_start and pg_backup_stop in the same session.(The 'touch backup_in_progress' business seems a bit bogus now too,
suggesting an exclusivity remembered from bygone days.)I am not sure what a workable, simple example ought to look like.
Maybe a single psql script issuing the pg_backup_start and the
pg_backup_stop, with a tar command in between with \! ?Several bricks shy of production-ready, but it would give the idea.
Another option might be to just remove this section. The top of the
section mentions that this is easily done using pg_basebackup with the -X
parameter. The bottom part of the section includes more complicated steps
for when "more flexibility in copying the backup files is needed..."
AFAICT the more complicated strategy was around before pg_basebackup, and
the pg_basebackup recommendation was added in 2012 as part of 920febd.
Thoughts?
This makes sense to me. I think pg_basebackup is far preferable to doing
anything like what is described in this section. Unless you are planning
to do something fancy (parallelization, snapshots, object stores, etc.)
then pg_basebackup is the way to go.
Regards,
-David
On Tue, Mar 08, 2022 at 03:09:50PM -0600, David Steele wrote:
On 3/8/22 14:01, Nathan Bossart wrote:
On Wed, Mar 02, 2022 at 02:23:51PM -0500, Chapman Flack wrote:
I did not notice this earlier (sorry), but there seems to remain in
backup.sgml a programlisting example that shows a psql invocation
for pg_backup_start, then a tar command, then another psql invocation
for pg_backup_stop.I think that was only workable for the exclusive mode, and now it is
necessary to issue pg_backup_start and pg_backup_stop in the same session.(The 'touch backup_in_progress' business seems a bit bogus now too,
suggesting an exclusivity remembered from bygone days.)I am not sure what a workable, simple example ought to look like.
Maybe a single psql script issuing the pg_backup_start and the
pg_backup_stop, with a tar command in between with \! ?Several bricks shy of production-ready, but it would give the idea.
Another option might be to just remove this section. The top of the
section mentions that this is easily done using pg_basebackup with the -X
parameter. The bottom part of the section includes more complicated steps
for when "more flexibility in copying the backup files is needed..."
AFAICT the more complicated strategy was around before pg_basebackup, and
the pg_basebackup recommendation was added in 2012 as part of 920febd.
Thoughts?This makes sense to me. I think pg_basebackup is far preferable to doing
anything like what is described in this section. Unless you are planning to
do something fancy (parallelization, snapshots, object stores, etc.) then
pg_basebackup is the way to go.
I spent some time trying to come up with a workable script to replace the
existing one. I think the main problem is that you need to write out both
the backup label file and the tablespace map file, but I didn't find an
easy way to write the different output columns of pg_backup_stop() to
separate files via psql. We'd probably need to write out the steps in
prose like the 'Making a Base Backup Using the Low Level API' section does.
Ultimately, I just removed everything beyond the pg_basebackup
recommendation in the 'Standalone Hot Backups' section.
--
Nathan Bossart
Amazon Web Services: https://aws.amazon.com
Attachments:
v5-0001-remove-exclusive-backup-mode.patchtext/x-diff; charset=us-asciiDownload
From 8b6fa9d0b7794e3c37f79f3c71472b2c6adabe47 Mon Sep 17 00:00:00 2001
From: Nathan Bossart <bossartn@amazon.com>
Date: Wed, 1 Dec 2021 23:50:49 +0000
Subject: [PATCH v5 1/1] remove exclusive backup mode
---
doc/src/sgml/backup.sgml | 222 +-------
doc/src/sgml/func.sgml | 99 +---
doc/src/sgml/high-availability.sgml | 6 +-
doc/src/sgml/monitoring.sgml | 4 +-
doc/src/sgml/ref/pgupgrade.sgml | 2 +-
src/backend/access/transam/xlog.c | 493 ++----------------
src/backend/access/transam/xlogfuncs.c | 253 ++-------
src/backend/access/transam/xlogrecovery.c | 2 +-
src/backend/catalog/system_functions.sql | 18 +-
src/backend/postmaster/postmaster.c | 46 +-
src/backend/replication/basebackup.c | 20 +-
src/bin/pg_basebackup/t/010_pg_basebackup.pl | 4 +
src/bin/pg_ctl/pg_ctl.c | 4 +-
src/bin/pg_rewind/filemap.c | 6 +-
src/include/access/xlog.h | 7 +-
src/include/catalog/pg_control.h | 2 +-
src/include/catalog/pg_proc.dat | 28 +-
src/include/miscadmin.h | 4 -
src/test/perl/PostgreSQL/Test/Cluster.pm | 56 +-
.../t/010_logical_decoding_timelines.pl | 4 +-
20 files changed, 189 insertions(+), 1091 deletions(-)
diff --git a/doc/src/sgml/backup.sgml b/doc/src/sgml/backup.sgml
index 0d69851bb1..79eeb25eee 100644
--- a/doc/src/sgml/backup.sgml
+++ b/doc/src/sgml/backup.sgml
@@ -857,16 +857,8 @@ test ! -f /mnt/server/archivedir/00000001000000A900000065 && cp pg_wal/0
sequence, and that the success of a step is verified before
proceeding to the next step.
</para>
- <para>
- Low level base backups can be made in a non-exclusive or an exclusive
- way. The non-exclusive method is recommended and the exclusive one is
- deprecated and will eventually be removed.
- </para>
-
- <sect3 id="backup-lowlevel-base-backup-nonexclusive">
- <title>Making a Non-Exclusive Low-Level Backup</title>
<para>
- A non-exclusive low level backup is one that allows other
+ A low level backup allows other
concurrent backups to be running (both those started using
the same backup API and those started using
<xref linkend="app-pgbasebackup"/>).
@@ -881,19 +873,19 @@ test ! -f /mnt/server/archivedir/00000001000000A900000065 && cp pg_wal/0
<listitem>
<para>
Connect to the server (it does not matter which database) as a user with
- rights to run pg_start_backup (superuser, or a user who has been granted
+ rights to run pg_backup_start (superuser, or a user who has been granted
EXECUTE on the function) and issue the command:
<programlisting>
-SELECT pg_start_backup('label', false, false);
+SELECT pg_backup_start('label', false);
</programlisting>
where <literal>label</literal> is any string you want to use to uniquely
identify this backup operation. The connection
- calling <function>pg_start_backup</function> must be maintained until the end of
+ calling <function>pg_backup_start</function> must be maintained until the end of
the backup, or the backup will be automatically aborted.
</para>
<para>
- By default, <function>pg_start_backup</function> can take a long time to finish.
+ By default, <function>pg_backup_start</function> can take a long time to finish.
This is because it performs a checkpoint, and the I/O
required for the checkpoint will be spread out over a significant
period of time, by default half your inter-checkpoint interval
@@ -905,10 +897,6 @@ SELECT pg_start_backup('label', false, false);
issue an immediate checkpoint using as much I/O as available.
</para>
- <para>
- The third parameter being <literal>false</literal> tells
- <function>pg_start_backup</function> to initiate a non-exclusive base backup.
- </para>
</listitem>
<listitem>
<para>
@@ -926,7 +914,7 @@ SELECT pg_start_backup('label', false, false);
<para>
In the same connection as before, issue the command:
<programlisting>
-SELECT * FROM pg_stop_backup(false, true);
+SELECT * FROM pg_backup_stop(true);
</programlisting>
This terminates backup mode. On a primary, it also performs an automatic
switch to the next WAL segment. On a standby, it is not possible to
@@ -937,7 +925,7 @@ SELECT * FROM pg_stop_backup(false, true);
ready to archive.
</para>
<para>
- The <function>pg_stop_backup</function> will return one row with three
+ The <function>pg_backup_stop</function> will return one row with three
values. The second of these fields should be written to a file named
<filename>backup_label</filename> in the root directory of the backup. The
third field should be written to a file named
@@ -949,14 +937,14 @@ SELECT * FROM pg_stop_backup(false, true);
<listitem>
<para>
Once the WAL segment files active during the backup are archived, you are
- done. The file identified by <function>pg_stop_backup</function>'s first return
+ done. The file identified by <function>pg_backup_stop</function>'s first return
value is the last segment that is required to form a complete set of
backup files. On a primary, if <varname>archive_mode</varname> is enabled and the
<literal>wait_for_archive</literal> parameter is <literal>true</literal>,
- <function>pg_stop_backup</function> does not return until the last segment has
+ <function>pg_backup_stop</function> does not return until the last segment has
been archived.
On a standby, <varname>archive_mode</varname> must be <literal>always</literal> in order
- for <function>pg_stop_backup</function> to wait.
+ for <function>pg_backup_stop</function> to wait.
Archiving of these files happens automatically since you have
already configured <varname>archive_library</varname>. In most cases this
happens quickly, but you are advised to monitor your archive
@@ -965,9 +953,9 @@ SELECT * FROM pg_stop_backup(false, true);
because of failures of the archive library, it will keep retrying
until the archive succeeds and the backup is complete.
If you wish to place a time limit on the execution of
- <function>pg_stop_backup</function>, set an appropriate
+ <function>pg_backup_stop</function>, set an appropriate
<varname>statement_timeout</varname> value, but make note that if
- <function>pg_stop_backup</function> terminates because of this your backup
+ <function>pg_backup_stop</function> terminates because of this your backup
may not be valid.
</para>
<para>
@@ -975,8 +963,8 @@ SELECT * FROM pg_stop_backup(false, true);
required for the backup are successfully archived then the
<literal>wait_for_archive</literal> parameter (which defaults to true) can be set
to false to have
- <function>pg_stop_backup</function> return as soon as the stop backup record is
- written to the WAL. By default, <function>pg_stop_backup</function> will wait
+ <function>pg_backup_stop</function> return as soon as the stop backup record is
+ written to the WAL. By default, <function>pg_backup_stop</function> will wait
until all WAL has been archived, which can take some time. This option
must be used with caution: if WAL archiving is not monitored correctly
then the backup might not include all of the WAL files and will
@@ -985,142 +973,6 @@ SELECT * FROM pg_stop_backup(false, true);
</listitem>
</orderedlist>
</para>
- </sect3>
- <sect3 id="backup-lowlevel-base-backup-exclusive">
- <title>Making an Exclusive Low-Level Backup</title>
-
- <note>
- <para>
- The exclusive backup method is deprecated and should be avoided.
- Prior to <productname>PostgreSQL</productname> 9.6, this was the only
- low-level method available, but it is now recommended that all users
- upgrade their scripts to use non-exclusive backups.
- </para>
- </note>
-
- <para>
- The process for an exclusive backup is mostly the same as for a
- non-exclusive one, but it differs in a few key steps. This type of
- backup can only be taken on a primary and does not allow concurrent
- backups. Moreover, because it creates a backup label file, as
- described below, it can block automatic restart of the primary server
- after a crash. On the other hand, the erroneous removal of this
- file from a backup or standby is a common mistake, which can result
- in serious data corruption. If it is necessary to use this method,
- the following steps may be used.
- </para>
- <para>
- <orderedlist>
- <listitem>
- <para>
- Ensure that WAL archiving is enabled and working.
- </para>
- </listitem>
- <listitem>
- <para>
- Connect to the server (it does not matter which database) as a user with
- rights to run pg_start_backup (superuser, or a user who has been granted
- EXECUTE on the function) and issue the command:
-<programlisting>
-SELECT pg_start_backup('label');
-</programlisting>
- where <literal>label</literal> is any string you want to use to uniquely
- identify this backup operation.
- <function>pg_start_backup</function> creates a <firstterm>backup label</firstterm> file,
- called <filename>backup_label</filename>, in the cluster directory with
- information about your backup, including the start time and label string.
- The function also creates a <firstterm>tablespace map</firstterm> file,
- called <filename>tablespace_map</filename>, in the cluster directory with
- information about tablespace symbolic links in <filename>pg_tblspc/</filename> if
- one or more such link is present. Both files are critical to the
- integrity of the backup, should you need to restore from it.
- </para>
-
- <para>
- By default, <function>pg_start_backup</function> can take a long time to finish.
- This is because it performs a checkpoint, and the I/O
- required for the checkpoint will be spread out over a significant
- period of time, by default half your inter-checkpoint interval
- (see the configuration parameter
- <xref linkend="guc-checkpoint-completion-target"/>). This is
- usually what you want, because it minimizes the impact on query
- processing. If you want to start the backup as soon as
- possible, use:
-<programlisting>
-SELECT pg_start_backup('label', true);
-</programlisting>
- This forces the checkpoint to be done as quickly as possible.
- </para>
- </listitem>
- <listitem>
- <para>
- Perform the backup, using any convenient file-system-backup tool
- such as <application>tar</application> or <application>cpio</application> (not
- <application>pg_dump</application> or
- <application>pg_dumpall</application>). It is neither
- necessary nor desirable to stop normal operation of the database
- while you do this. See
- <xref linkend="backup-lowlevel-base-backup-data"/> for things to
- consider during this backup.
- </para>
- <para>
- As noted above, if the server crashes during the backup it may not be
- possible to restart until the <filename>backup_label</filename> file has
- been manually deleted from the <envar>PGDATA</envar> directory. Note
- that it is very important to never remove the
- <filename>backup_label</filename> file when restoring a backup, because
- this will result in corruption. Confusion about when it is appropriate
- to remove this file is a common cause of data corruption when using this
- method; be very certain that you remove the file only on an existing
- primary and never when building a standby or restoring a backup, even if
- you are building a standby that will subsequently be promoted to a new
- primary.
- </para>
- </listitem>
- <listitem>
- <para>
- Again connect to the database as a user with rights to run
- pg_stop_backup (superuser, or a user who has been granted EXECUTE on
- the function), and issue the command:
-<programlisting>
-SELECT pg_stop_backup();
-</programlisting>
- This function terminates backup mode and
- performs an automatic switch to the next WAL segment. The reason for the
- switch is to arrange for the last WAL segment written during the backup
- interval to be ready to archive.
- </para>
- </listitem>
- <listitem>
- <para>
- Once the WAL segment files active during the backup are archived, you are
- done. The file identified by <function>pg_stop_backup</function>'s result is
- the last segment that is required to form a complete set of backup files.
- If <varname>archive_mode</varname> is enabled,
- <function>pg_stop_backup</function> does not return until the last segment has
- been archived.
- Archiving of these files happens automatically since you have
- already configured <varname>archive_command</varname>. In most cases this
- happens quickly, but you are advised to monitor your archive
- system to ensure there are no delays.
- If the archive process has fallen behind
- because of failures of the archive command, it will keep retrying
- until the archive succeeds and the backup is complete.
- </para>
-
- <para>
- When using exclusive backup mode, it is absolutely imperative to ensure
- that <function>pg_stop_backup</function> completes successfully at the
- end of the backup. Even if the backup itself fails, for example due to
- lack of disk space, failure to call <function>pg_stop_backup</function>
- will leave the server in backup mode indefinitely, causing future backups
- to fail and increasing the risk of a restart failure during the time that
- <filename>backup_label</filename> exists.
- </para>
- </listitem>
- </orderedlist>
- </para>
- </sect3>
<sect3 id="backup-lowlevel-base-backup-data">
<title>Backing Up the Data Directory</title>
<para>
@@ -1203,8 +1055,8 @@ SELECT pg_stop_backup();
<para>
The backup label
- file includes the label string you gave to <function>pg_start_backup</function>,
- as well as the time at which <function>pg_start_backup</function> was run, and
+ file includes the label string you gave to <function>pg_backup_start</function>,
+ as well as the time at which <function>pg_backup_start</function> was run, and
the name of the starting WAL file. In case of confusion it is therefore
possible to look inside a backup file and determine exactly which
backup session the dump file came from. The tablespace map file includes
@@ -1218,7 +1070,7 @@ SELECT pg_stop_backup();
<para>
It is also possible to make a backup while the server is
stopped. In this case, you obviously cannot use
- <function>pg_start_backup</function> or <function>pg_stop_backup</function>, and
+ <function>pg_backup_start</function> or <function>pg_backup_stop</function>, and
you will therefore be left to your own devices to keep track of which
backup is which and how far back the associated WAL files go.
It is generally better to follow the continuous archiving procedure above.
@@ -1393,7 +1245,7 @@ restore_command = 'cp /mnt/server/archivedir/%f %p'
<note>
<para>
The stop point must be after the ending time of the base backup, i.e.,
- the end time of <function>pg_stop_backup</function>. You cannot use a base backup
+ the end time of <function>pg_backup_stop</function>. You cannot use a base backup
to recover to a time when that backup was in progress. (To
recover to such a time, you must go back to your previous base backup
and roll forward from there.)
@@ -1513,44 +1365,6 @@ restore_command = 'cp /mnt/server/archivedir/%f %p'
included in the backup automatically, and no special action is
required to restore the backup.
</para>
-
- <para>
- If more flexibility in copying the backup files is needed, a lower
- level process can be used for standalone hot backups as well.
- To prepare for low level standalone hot backups, make sure
- <varname>wal_level</varname> is set to
- <literal>replica</literal> or higher, <varname>archive_mode</varname> to
- <literal>on</literal>, and set up an <varname>archive_library</varname> that performs
- archiving only when a <emphasis>switch file</emphasis> exists. For example:
-<programlisting>
-archive_library = '' # use shell command
-archive_command = 'test ! -f /var/lib/pgsql/backup_in_progress || (test ! -f /var/lib/pgsql/archive/%f && cp %p /var/lib/pgsql/archive/%f)'
-</programlisting>
- This command will perform archiving when
- <filename>/var/lib/pgsql/backup_in_progress</filename> exists, and otherwise
- silently return zero exit status (allowing <productname>PostgreSQL</productname>
- to recycle the unwanted WAL file).
- </para>
-
- <para>
- With this preparation, a backup can be taken using a script like the
- following:
-<programlisting>
-touch /var/lib/pgsql/backup_in_progress
-psql -c "select pg_start_backup('hot_backup');"
-tar -cf /var/lib/pgsql/backup.tar /var/lib/pgsql/data/
-psql -c "select pg_stop_backup();"
-rm /var/lib/pgsql/backup_in_progress
-tar -rf /var/lib/pgsql/backup.tar /var/lib/pgsql/archive/
-</programlisting>
- The switch file <filename>/var/lib/pgsql/backup_in_progress</filename> is
- created first, enabling archiving of completed WAL files to occur.
- After the backup the switch file is removed. Archived WAL files are
- then added to the backup so that both base backup and all required
- WAL files are part of the same <application>tar</application> file.
- Please remember to add error handling to your backup scripts.
- </para>
-
</sect3>
<sect3 id="compressed-archive-logs">
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 8a802fb225..8790c07fac 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -25587,9 +25587,8 @@ LOG: Grand total: 1651920 bytes in 201 blocks; 622360 free (88 chunks); 1029560
The functions shown in <xref
linkend="functions-admin-backup-table"/> assist in making on-line backups.
These functions cannot be executed during recovery (except
- non-exclusive <function>pg_start_backup</function>,
- non-exclusive <function>pg_stop_backup</function>,
- <function>pg_is_in_backup</function>, <function>pg_backup_start_time</function>
+ <function>pg_backup_start</function>,
+ <function>pg_backup_stop</function>,
and <function>pg_wal_lsn_diff</function>).
</para>
@@ -25678,13 +25677,12 @@ LOG: Grand total: 1651920 bytes in 201 blocks; 622360 free (88 chunks); 1029560
<row>
<entry role="func_table_entry"><para role="func_signature">
<indexterm>
- <primary>pg_start_backup</primary>
+ <primary>pg_backup_start</primary>
</indexterm>
- <function>pg_start_backup</function> (
+ <function>pg_backup_start</function> (
<parameter>label</parameter> <type>text</type>
<optional>, <parameter>fast</parameter> <type>boolean</type>
- <optional>, <parameter>exclusive</parameter> <type>boolean</type>
- </optional></optional> )
+ </optional> )
<returnvalue>pg_lsn</returnvalue>
</para>
<para>
@@ -25693,23 +25691,9 @@ LOG: Grand total: 1651920 bytes in 201 blocks; 622360 free (88 chunks); 1029560
(Typically this would be the name under which the backup dump file
will be stored.)
If the optional second parameter is given as <literal>true</literal>,
- it specifies executing <function>pg_start_backup</function> as quickly
+ it specifies executing <function>pg_backup_start</function> as quickly
as possible. This forces an immediate checkpoint which will cause a
spike in I/O operations, slowing any concurrently executing queries.
- The optional third parameter specifies whether to perform an exclusive
- or non-exclusive backup (default is exclusive).
- </para>
- <para>
- When used in exclusive mode, this function writes a backup label file
- (<filename>backup_label</filename>) and, if there are any links in
- the <filename>pg_tblspc/</filename> directory, a tablespace map file
- (<filename>tablespace_map</filename>) into the database cluster's data
- directory, then performs a checkpoint, and then returns the backup's
- starting write-ahead log location. (The user can ignore this
- result value, but it is provided in case it is useful.) When used in
- non-exclusive mode, the contents of these files are instead returned
- by the <function>pg_stop_backup</function> function, and should be
- copied to the backup area by the user.
</para>
<para>
This function is restricted to superusers by default, but other users
@@ -25720,11 +25704,10 @@ LOG: Grand total: 1651920 bytes in 201 blocks; 622360 free (88 chunks); 1029560
<row>
<entry role="func_table_entry"><para role="func_signature">
<indexterm>
- <primary>pg_stop_backup</primary>
+ <primary>pg_backup_stop</primary>
</indexterm>
- <function>pg_stop_backup</function> (
- <parameter>exclusive</parameter> <type>boolean</type>
- <optional>, <parameter>wait_for_archive</parameter> <type>boolean</type>
+ <function>pg_backup_stop</function> (
+ <optional><parameter>wait_for_archive</parameter> <type>boolean</type>
</optional> )
<returnvalue>record</returnvalue>
( <parameter>lsn</parameter> <type>pg_lsn</type>,
@@ -25732,24 +25715,19 @@ LOG: Grand total: 1651920 bytes in 201 blocks; 622360 free (88 chunks); 1029560
<parameter>spcmapfile</parameter> <type>text</type> )
</para>
<para>
- Finishes performing an exclusive or non-exclusive on-line backup.
- The <parameter>exclusive</parameter> parameter must match the
- previous <function>pg_start_backup</function> call.
- In an exclusive backup, <function>pg_stop_backup</function> removes
- the backup label file and, if it exists, the tablespace map file
- created by <function>pg_start_backup</function>. In a non-exclusive
- backup, the desired contents of these files are returned as part of
+ Finishes performing an on-line backup. The desired contents of the
+ backup label file and the tablespace map file are returned as part of
the result of the function, and should be written to files in the
backup area (not in the data directory).
</para>
<para>
- There is an optional second parameter of type <type>boolean</type>.
+ There is an optional parameter of type <type>boolean</type>.
If false, the function will return immediately after the backup is
completed, without waiting for WAL to be archived. This behavior is
only useful with backup software that independently monitors WAL
archiving. Otherwise, WAL required to make the backup consistent might
be missing and make the backup useless. By default or when this
- parameter is true, <function>pg_stop_backup</function> will wait for
+ parameter is true, <function>pg_backup_stop</function> will wait for
WAL to be archived when archiving is enabled. (On a standby, this
means that it will wait only when <varname>archive_mode</varname> =
<literal>always</literal>. If write activity on the primary is low,
@@ -25759,7 +25737,7 @@ LOG: Grand total: 1651920 bytes in 201 blocks; 622360 free (88 chunks); 1029560
<para>
When executed on a primary, this function also creates a backup
history file in the write-ahead log archive area. The history file
- includes the label given to <function>pg_start_backup</function>, the
+ includes the label given to <function>pg_backup_start</function>, the
starting and ending write-ahead log locations for the backup, and the
starting and ending times of the backup. After recording the ending
location, the current write-ahead log insertion point is automatically
@@ -25771,8 +25749,7 @@ LOG: Grand total: 1651920 bytes in 201 blocks; 622360 free (88 chunks); 1029560
The result of the function is a single record.
The <parameter>lsn</parameter> column holds the backup's ending
write-ahead log location (which again can be ignored). The second and
- third columns are <literal>NULL</literal> when ending an exclusive
- backup; after a non-exclusive backup they hold the desired contents of
+ third columns hold the desired contents of
the label and tablespace map files.
</para>
<para>
@@ -25781,50 +25758,6 @@ LOG: Grand total: 1651920 bytes in 201 blocks; 622360 free (88 chunks); 1029560
</para></entry>
</row>
- <row>
- <entry role="func_table_entry"><para role="func_signature">
- <function>pg_stop_backup</function> ()
- <returnvalue>pg_lsn</returnvalue>
- </para>
- <para>
- Finishes performing an exclusive on-line backup. This simplified
- version is equivalent to <literal>pg_stop_backup(true,
- true)</literal>, except that it only returns the <type>pg_lsn</type>
- result.
- </para>
- <para>
- This function is restricted to superusers by default, but other users
- can be granted EXECUTE to run the function.
- </para></entry>
- </row>
-
- <row>
- <entry role="func_table_entry"><para role="func_signature">
- <indexterm>
- <primary>pg_is_in_backup</primary>
- </indexterm>
- <function>pg_is_in_backup</function> ()
- <returnvalue>boolean</returnvalue>
- </para>
- <para>
- Returns true if an on-line exclusive backup is in progress.
- </para></entry>
- </row>
-
- <row>
- <entry role="func_table_entry"><para role="func_signature">
- <indexterm>
- <primary>pg_backup_start_time</primary>
- </indexterm>
- <function>pg_backup_start_time</function> ()
- <returnvalue>timestamp with time zone</returnvalue>
- </para>
- <para>
- Returns the start time of the current on-line exclusive backup if one
- is in progress, otherwise <literal>NULL</literal>.
- </para></entry>
- </row>
-
<row>
<entry role="func_table_entry"><para role="func_signature">
<indexterm>
@@ -25922,7 +25855,7 @@ LOG: Grand total: 1651920 bytes in 201 blocks; 622360 free (88 chunks); 1029560
corresponding write-ahead log file name and byte offset from
a <type>pg_lsn</type> value. For example:
<programlisting>
-postgres=# SELECT * FROM pg_walfile_name_offset(pg_stop_backup());
+postgres=# SELECT * FROM pg_walfile_name_offset(pg_backup_stop());
file_name | file_offset
--------------------------+-------------
00000001000000000000000D | 4039624
diff --git a/doc/src/sgml/high-availability.sgml b/doc/src/sgml/high-availability.sgml
index b5b6042104..1f0ba66943 100644
--- a/doc/src/sgml/high-availability.sgml
+++ b/doc/src/sgml/high-availability.sgml
@@ -1361,8 +1361,8 @@ synchronous_standby_names = 'ANY 2 (s1, s2, s3)'
<para>
If you need to re-create a standby server while transactions are
- waiting, make sure that the commands pg_start_backup() and
- pg_stop_backup() are run in a session with
+ waiting, make sure that the commands pg_backup_start() and
+ pg_backup_stop() are run in a session with
<varname>synchronous_commit</varname> = <literal>off</literal>, otherwise those
requests will wait forever for the standby to appear.
</para>
@@ -2159,7 +2159,7 @@ HINT: You can then restart the server after making the necessary configuration
<para>
WAL file control commands will not work during recovery,
- e.g., <function>pg_start_backup</function>, <function>pg_switch_wal</function> etc.
+ e.g., <function>pg_backup_start</function>, <function>pg_switch_wal</function> etc.
</para>
<para>
diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
index 9fb62fec8e..0320ce7078 100644
--- a/doc/src/sgml/monitoring.sgml
+++ b/doc/src/sgml/monitoring.sgml
@@ -6661,7 +6661,7 @@ SELECT pg_stat_get_backend_pid(s.backendid) AS pid,
<entry><literal>waiting for checkpoint to finish</literal></entry>
<entry>
The WAL sender process is currently performing
- <function>pg_start_backup</function> to prepare to
+ <function>pg_backup_start</function> to prepare to
take a base backup, and waiting for the start-of-backup
checkpoint to finish.
</entry>
@@ -6684,7 +6684,7 @@ SELECT pg_stat_get_backend_pid(s.backendid) AS pid,
<entry><literal>waiting for wal archiving to finish</literal></entry>
<entry>
The WAL sender process is currently performing
- <function>pg_stop_backup</function> to finish the backup,
+ <function>pg_backup_stop</function> to finish the backup,
and waiting for all the WAL files required for the base backup
to be successfully archived.
If either <literal>--wal-method=none</literal> or
diff --git a/doc/src/sgml/ref/pgupgrade.sgml b/doc/src/sgml/ref/pgupgrade.sgml
index 729c886ac0..3fbe141456 100644
--- a/doc/src/sgml/ref/pgupgrade.sgml
+++ b/doc/src/sgml/ref/pgupgrade.sgml
@@ -618,7 +618,7 @@ rsync --archive --delete --hard-links --size-only --no-inc-recursive /vol1/pg_tb
<para>
Configure the servers for log shipping. (You do not need to run
- <function>pg_start_backup()</function> and <function>pg_stop_backup()</function>
+ <function>pg_backup_start()</function> and <function>pg_backup_stop()</function>
or take a file system backup as the standbys are still synchronized
with the primary.)
</para>
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 0d2bd7a357..d5032118d3 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -384,29 +384,6 @@ typedef union WALInsertLockPadded
char pad[PG_CACHE_LINE_SIZE];
} WALInsertLockPadded;
-/*
- * State of an exclusive backup, necessary to control concurrent activities
- * across sessions when working on exclusive backups.
- *
- * EXCLUSIVE_BACKUP_NONE means that there is no exclusive backup actually
- * running, to be more precise pg_start_backup() is not being executed for
- * an exclusive backup and there is no exclusive backup in progress.
- * EXCLUSIVE_BACKUP_STARTING means that pg_start_backup() is starting an
- * exclusive backup.
- * EXCLUSIVE_BACKUP_IN_PROGRESS means that pg_start_backup() has finished
- * running and an exclusive backup is in progress. pg_stop_backup() is
- * needed to finish it.
- * EXCLUSIVE_BACKUP_STOPPING means that pg_stop_backup() is stopping an
- * exclusive backup.
- */
-typedef enum ExclusiveBackupState
-{
- EXCLUSIVE_BACKUP_NONE = 0,
- EXCLUSIVE_BACKUP_STARTING,
- EXCLUSIVE_BACKUP_IN_PROGRESS,
- EXCLUSIVE_BACKUP_STOPPING
-} ExclusiveBackupState;
-
/*
* Session status of running backup, used for sanity checks in SQL-callable
* functions to start and stop backups.
@@ -455,15 +432,12 @@ typedef struct XLogCtlInsert
bool fullPageWrites;
/*
- * exclusiveBackupState indicates the state of an exclusive backup (see
- * comments of ExclusiveBackupState for more details). nonExclusiveBackups
- * is a counter indicating the number of streaming base backups currently
- * in progress. forcePageWrites is set to true when either of these is
- * non-zero. lastBackupStart is the latest checkpoint redo location used
- * as a starting point for an online backup.
+ * runningBackups is a counter indicating the number of backups currently in
+ * progress. forcePageWrites is set to true when runningBackups is non-zero.
+ * lastBackupStart is the latest checkpoint redo location used as a starting
+ * point for an online backup.
*/
- ExclusiveBackupState exclusiveBackupState;
- int nonExclusiveBackups;
+ int runningBackups;
XLogRecPtr lastBackupStart;
/*
@@ -695,8 +669,7 @@ static void ReadControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow);
-static void pg_start_backup_callback(int code, Datum arg);
-static void pg_stop_backup_callback(int code, Datum arg);
+static void pg_backup_start_callback(int code, Datum arg);
static int get_sync_bit(int method);
@@ -5313,7 +5286,7 @@ StartupXLOG(void)
* Ran off end of WAL before reaching end-of-backup WAL record, or
* minRecoveryPoint. That's usually a bad sign, indicating that you
* tried to recover from an online backup but never called
- * pg_stop_backup(), or you didn't archive all the WAL up to that
+ * pg_backup_stop(), or you didn't archive all the WAL up to that
* point. However, this also happens in crash recovery, if the system
* crashes while an online backup is in progress. We must not treat
* that as an error, or the database will refuse to start up.
@@ -5327,7 +5300,7 @@ StartupXLOG(void)
else if (!XLogRecPtrIsInvalid(ControlFile->backupStartPoint))
ereport(FATAL,
(errmsg("WAL ends before end of online backup"),
- errhint("Online backup started with pg_start_backup() must be ended with pg_stop_backup(), and all WAL up to that point must be available at recovery.")));
+ errhint("Online backup started with pg_backup_start() must be ended with pg_backup_stop(), and all WAL up to that point must be available at recovery.")));
else
ereport(FATAL,
(errmsg("WAL ends before consistent recovery point")));
@@ -7008,7 +6981,7 @@ CreateRestartPoint(int flags)
* Ensure minRecoveryPoint is past the checkpoint record. Normally,
* this will have happened already while writing out dirty buffers,
* but not necessarily - e.g. because no buffers were dirtied. We do
- * this because a non-exclusive base backup uses minRecoveryPoint to
+ * this because a backup performed in recovery uses minRecoveryPoint to
* determine which WAL files must be included in the backup, and the
* file (or files) containing the checkpoint record must be included,
* at a minimum. Note that for an ordinary restart of recovery there's
@@ -7812,7 +7785,7 @@ xlog_redo(XLogReaderState *record)
/*
* Update the LSN of the last replayed XLOG_FPW_CHANGE record so that
- * do_pg_start_backup() and do_pg_stop_backup() can check whether
+ * do_pg_backup_start() and do_pg_backup_stop() can check whether
* full_page_writes has been disabled during online backup.
*/
if (!fpw)
@@ -8011,29 +7984,14 @@ issue_xlog_fsync(int fd, XLogSegNo segno, TimeLineID tli)
}
/*
- * do_pg_start_backup
- *
- * Utility function called at the start of an online backup. It creates the
- * necessary starting checkpoint and constructs the backup label file.
- *
- * There are two kind of backups: exclusive and non-exclusive. An exclusive
- * backup is started with pg_start_backup(), and there can be only one active
- * at a time. The backup and tablespace map files of an exclusive backup are
- * written to $PGDATA/backup_label and $PGDATA/tablespace_map, and they are
- * removed by pg_stop_backup().
- *
- * A non-exclusive backup is used for the streaming base backups (see
- * src/backend/replication/basebackup.c). The difference to exclusive backups
- * is that the backup label and tablespace map files are not written to disk.
- * Instead, their would-be contents are returned in *labelfile and *tblspcmapfile,
- * and the caller is responsible for including them in the backup archive as
- * 'backup_label' and 'tablespace_map'. There can be many non-exclusive backups
- * active at the same time, and they don't conflict with an exclusive backup
- * either.
- *
- * labelfile and tblspcmapfile must be passed as NULL when starting an
- * exclusive backup, and as initially-empty StringInfos for a non-exclusive
- * backup.
+ * do_pg_backup_start is the workhorse of the user-visible pg_backup_start()
+ * function. It creates the necessary starting checkpoint and constructs the
+ * backup label and tablespace map.
+ *
+ * The backup label and tablespace map contents are returned in *labelfile and
+ * *tblspcmapfile, and the caller is responsible for including them in the
+ * backup archive as 'backup_label' and 'tablespace_map'. There can be many
+ * backups active at the same time.
*
* If "tablespaces" isn't NULL, it receives a list of tablespaceinfo structs
* describing the cluster's tablespaces.
@@ -8045,18 +8003,17 @@ issue_xlog_fsync(int fd, XLogSegNo segno, TimeLineID tli)
* Returns the minimum WAL location that must be present to restore from this
* backup, and the corresponding timeline ID in *starttli_p.
*
- * Every successfully started non-exclusive backup must be stopped by calling
- * do_pg_stop_backup() or do_pg_abort_backup().
+ * Every successfully started backup must be stopped by calling
+ * do_pg_backup_stop() or do_pg_abort_backup().
*
* It is the responsibility of the caller of this function to verify the
* permissions of the calling user!
*/
XLogRecPtr
-do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
+do_pg_backup_start(const char *backupidstr, bool fast, TimeLineID *starttli_p,
StringInfo labelfile, List **tablespaces,
StringInfo tblspcmapfile)
{
- bool exclusive = (labelfile == NULL);
bool backup_started_in_recovery = false;
XLogRecPtr checkpointloc;
XLogRecPtr startpoint;
@@ -8065,20 +8022,9 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
char strfbuf[128];
char xlogfilename[MAXFNAMELEN];
XLogSegNo _logSegNo;
- struct stat stat_buf;
- FILE *fp;
backup_started_in_recovery = RecoveryInProgress();
- /*
- * Currently only non-exclusive backup can be taken during recovery.
- */
- if (backup_started_in_recovery && exclusive)
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("recovery is in progress"),
- errhint("WAL control functions cannot be executed during recovery.")));
-
/*
* During recovery, we don't need to check WAL level. Because, if WAL
* level is not sufficient, it's impossible to get here during recovery.
@@ -8117,30 +8063,12 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
* XLogInsertRecord().
*/
WALInsertLockAcquireExclusive();
- if (exclusive)
- {
- /*
- * At first, mark that we're now starting an exclusive backup, to
- * ensure that there are no other sessions currently running
- * pg_start_backup() or pg_stop_backup().
- */
- if (XLogCtl->Insert.exclusiveBackupState != EXCLUSIVE_BACKUP_NONE)
- {
- WALInsertLockRelease();
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("a backup is already in progress"),
- errhint("Run pg_stop_backup() and try again.")));
- }
- XLogCtl->Insert.exclusiveBackupState = EXCLUSIVE_BACKUP_STARTING;
- }
- else
- XLogCtl->Insert.nonExclusiveBackups++;
+ XLogCtl->Insert.runningBackups++;
XLogCtl->Insert.forcePageWrites = true;
WALInsertLockRelease();
/* Ensure we release forcePageWrites if fail below */
- PG_ENSURE_ERROR_CLEANUP(pg_start_backup_callback, (Datum) BoolGetDatum(exclusive));
+ PG_ENSURE_ERROR_CLEANUP(pg_backup_start_callback, (Datum) 0);
{
bool gotUniqueStartpoint = false;
DIR *tblspcdir;
@@ -8152,7 +8080,7 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
* Force an XLOG file switch before the checkpoint, to ensure that the
* WAL segment the checkpoint is written to doesn't contain pages with
* old timeline IDs. That would otherwise happen if you called
- * pg_start_backup() right after restoring from a PITR archive: the
+ * pg_backup_start() right after restoring from a PITR archive: the
* first WAL segment containing the startup checkpoint has pages in
* the beginning with the old timeline ID. That can cause trouble at
* recovery: we won't have a history file covering the old timeline if
@@ -8187,7 +8115,7 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
* means that two successive backup runs can have same checkpoint
* positions.
*
- * Since the fact that we are executing do_pg_start_backup()
+ * Since the fact that we are executing do_pg_backup_start()
* during recovery means that checkpointer is running, we can use
* RequestCheckpoint() to establish a restartpoint.
*
@@ -8375,122 +8303,19 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
LSN_FORMAT_ARGS(startpoint), xlogfilename);
appendStringInfo(labelfile, "CHECKPOINT LOCATION: %X/%X\n",
LSN_FORMAT_ARGS(checkpointloc));
- appendStringInfo(labelfile, "BACKUP METHOD: %s\n",
- exclusive ? "pg_start_backup" : "streamed");
+ appendStringInfo(labelfile, "BACKUP METHOD: streamed\n");
appendStringInfo(labelfile, "BACKUP FROM: %s\n",
backup_started_in_recovery ? "standby" : "primary");
appendStringInfo(labelfile, "START TIME: %s\n", strfbuf);
appendStringInfo(labelfile, "LABEL: %s\n", backupidstr);
appendStringInfo(labelfile, "START TIMELINE: %u\n", starttli);
-
- /*
- * Okay, write the file, or return its contents to caller.
- */
- if (exclusive)
- {
- /*
- * Check for existing backup label --- implies a backup is already
- * running. (XXX given that we checked exclusiveBackupState
- * above, maybe it would be OK to just unlink any such label
- * file?)
- */
- if (stat(BACKUP_LABEL_FILE, &stat_buf) != 0)
- {
- if (errno != ENOENT)
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not stat file \"%s\": %m",
- BACKUP_LABEL_FILE)));
- }
- else
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("a backup is already in progress"),
- errhint("If you're sure there is no backup in progress, remove file \"%s\" and try again.",
- BACKUP_LABEL_FILE)));
-
- fp = AllocateFile(BACKUP_LABEL_FILE, "w");
-
- if (!fp)
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not create file \"%s\": %m",
- BACKUP_LABEL_FILE)));
- if (fwrite(labelfile->data, labelfile->len, 1, fp) != 1 ||
- fflush(fp) != 0 ||
- pg_fsync(fileno(fp)) != 0 ||
- ferror(fp) ||
- FreeFile(fp))
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not write file \"%s\": %m",
- BACKUP_LABEL_FILE)));
- /* Allocated locally for exclusive backups, so free separately */
- pfree(labelfile->data);
- pfree(labelfile);
-
- /* Write backup tablespace_map file. */
- if (tblspcmapfile->len > 0)
- {
- if (stat(TABLESPACE_MAP, &stat_buf) != 0)
- {
- if (errno != ENOENT)
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not stat file \"%s\": %m",
- TABLESPACE_MAP)));
- }
- else
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("a backup is already in progress"),
- errhint("If you're sure there is no backup in progress, remove file \"%s\" and try again.",
- TABLESPACE_MAP)));
-
- fp = AllocateFile(TABLESPACE_MAP, "w");
-
- if (!fp)
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not create file \"%s\": %m",
- TABLESPACE_MAP)));
- if (fwrite(tblspcmapfile->data, tblspcmapfile->len, 1, fp) != 1 ||
- fflush(fp) != 0 ||
- pg_fsync(fileno(fp)) != 0 ||
- ferror(fp) ||
- FreeFile(fp))
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not write file \"%s\": %m",
- TABLESPACE_MAP)));
- }
-
- /* Allocated locally for exclusive backups, so free separately */
- pfree(tblspcmapfile->data);
- pfree(tblspcmapfile);
- }
}
- PG_END_ENSURE_ERROR_CLEANUP(pg_start_backup_callback, (Datum) BoolGetDatum(exclusive));
+ PG_END_ENSURE_ERROR_CLEANUP(pg_backup_start_callback, (Datum) 0);
/*
- * Mark that start phase has correctly finished for an exclusive backup.
- * Session-level locks are updated as well to reflect that state.
- *
- * Note that CHECK_FOR_INTERRUPTS() must not occur while updating backup
- * counters and session-level lock. Otherwise they can be updated
- * inconsistently, and which might cause do_pg_abort_backup() to fail.
+ * Mark that the start phase has correctly finished for the backup.
*/
- if (exclusive)
- {
- WALInsertLockAcquireExclusive();
- XLogCtl->Insert.exclusiveBackupState = EXCLUSIVE_BACKUP_IN_PROGRESS;
-
- /* Set session-level lock */
- sessionBackupState = SESSION_BACKUP_EXCLUSIVE;
- WALInsertLockRelease();
- }
- else
- sessionBackupState = SESSION_BACKUP_NON_EXCLUSIVE;
+ sessionBackupState = SESSION_BACKUP_RUNNING;
/*
* We're done. As a convenience, return the starting WAL location.
@@ -8500,47 +8325,19 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
return startpoint;
}
-/* Error cleanup callback for pg_start_backup */
+/* Error cleanup callback for pg_backup_start */
static void
-pg_start_backup_callback(int code, Datum arg)
+pg_backup_start_callback(int code, Datum arg)
{
- bool exclusive = DatumGetBool(arg);
-
/* Update backup counters and forcePageWrites on failure */
WALInsertLockAcquireExclusive();
- if (exclusive)
- {
- Assert(XLogCtl->Insert.exclusiveBackupState == EXCLUSIVE_BACKUP_STARTING);
- XLogCtl->Insert.exclusiveBackupState = EXCLUSIVE_BACKUP_NONE;
- }
- else
- {
- Assert(XLogCtl->Insert.nonExclusiveBackups > 0);
- XLogCtl->Insert.nonExclusiveBackups--;
- }
- if (XLogCtl->Insert.exclusiveBackupState == EXCLUSIVE_BACKUP_NONE &&
- XLogCtl->Insert.nonExclusiveBackups == 0)
- {
- XLogCtl->Insert.forcePageWrites = false;
- }
- WALInsertLockRelease();
-}
+ Assert(XLogCtl->Insert.runningBackups > 0);
+ XLogCtl->Insert.runningBackups--;
-/*
- * Error cleanup callback for pg_stop_backup
- */
-static void
-pg_stop_backup_callback(int code, Datum arg)
-{
- bool exclusive = DatumGetBool(arg);
-
- /* Update backup status on failure */
- WALInsertLockAcquireExclusive();
- if (exclusive)
+ if (XLogCtl->Insert.runningBackups == 0)
{
- Assert(XLogCtl->Insert.exclusiveBackupState == EXCLUSIVE_BACKUP_STOPPING);
- XLogCtl->Insert.exclusiveBackupState = EXCLUSIVE_BACKUP_IN_PROGRESS;
+ XLogCtl->Insert.forcePageWrites = false;
}
WALInsertLockRelease();
}
@@ -8555,14 +8352,11 @@ get_backup_status(void)
}
/*
- * do_pg_stop_backup
+ * do_pg_backup_stop
*
* Utility function called at the end of an online backup. It cleans up the
* backup state and can optionally wait for WAL segments to be archived.
*
- * If labelfile is NULL, this stops an exclusive backup. Otherwise this stops
- * the non-exclusive backup specified by 'labelfile'.
- *
* Returns the last WAL location that must be present to restore from this
* backup, and the corresponding timeline ID in *stoptli_p.
*
@@ -8570,9 +8364,8 @@ get_backup_status(void)
* permissions of the calling user!
*/
XLogRecPtr
-do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
+do_pg_backup_stop(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
{
- bool exclusive = (labelfile == NULL);
bool backup_started_in_recovery = false;
XLogRecPtr startpoint;
XLogRecPtr stoppoint;
@@ -8586,7 +8379,6 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
char histfilename[MAXFNAMELEN];
char backupfrom[20];
XLogSegNo _logSegNo;
- FILE *lfp;
FILE *fp;
char ch;
int seconds_before_warning;
@@ -8599,15 +8391,6 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
backup_started_in_recovery = RecoveryInProgress();
- /*
- * Currently only non-exclusive backup can be taken during recovery.
- */
- if (backup_started_in_recovery && exclusive)
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("recovery is in progress"),
- errhint("WAL control functions cannot be executed during recovery.")));
-
/*
* During recovery, we don't need to check WAL level. Because, if WAL
* level is not sufficient, it's impossible to get here during recovery.
@@ -8618,106 +8401,23 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
errmsg("WAL level not sufficient for making an online backup"),
errhint("wal_level must be set to \"replica\" or \"logical\" at server start.")));
- if (exclusive)
- {
- /*
- * At first, mark that we're now stopping an exclusive backup, to
- * ensure that there are no other sessions currently running
- * pg_start_backup() or pg_stop_backup().
- */
- WALInsertLockAcquireExclusive();
- if (XLogCtl->Insert.exclusiveBackupState != EXCLUSIVE_BACKUP_IN_PROGRESS)
- {
- WALInsertLockRelease();
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("exclusive backup not in progress")));
- }
- XLogCtl->Insert.exclusiveBackupState = EXCLUSIVE_BACKUP_STOPPING;
- WALInsertLockRelease();
-
- /*
- * Remove backup_label. In case of failure, the state for an exclusive
- * backup is switched back to in-progress.
- */
- PG_ENSURE_ERROR_CLEANUP(pg_stop_backup_callback, (Datum) BoolGetDatum(exclusive));
- {
- /*
- * Read the existing label file into memory.
- */
- struct stat statbuf;
- int r;
-
- if (stat(BACKUP_LABEL_FILE, &statbuf))
- {
- /* should not happen per the upper checks */
- if (errno != ENOENT)
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not stat file \"%s\": %m",
- BACKUP_LABEL_FILE)));
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("a backup is not in progress")));
- }
-
- lfp = AllocateFile(BACKUP_LABEL_FILE, "r");
- if (!lfp)
- {
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not read file \"%s\": %m",
- BACKUP_LABEL_FILE)));
- }
- labelfile = palloc(statbuf.st_size + 1);
- r = fread(labelfile, statbuf.st_size, 1, lfp);
- labelfile[statbuf.st_size] = '\0';
-
- /*
- * Close and remove the backup label file
- */
- if (r != 1 || ferror(lfp) || FreeFile(lfp))
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not read file \"%s\": %m",
- BACKUP_LABEL_FILE)));
- durable_unlink(BACKUP_LABEL_FILE, ERROR);
-
- /*
- * Remove tablespace_map file if present, it is created only if
- * there are tablespaces.
- */
- durable_unlink(TABLESPACE_MAP, DEBUG1);
- }
- PG_END_ENSURE_ERROR_CLEANUP(pg_stop_backup_callback, (Datum) BoolGetDatum(exclusive));
- }
-
/*
- * OK to update backup counters, forcePageWrites and session-level lock.
+ * OK to update backup counters, forcePageWrites, and session-level lock.
*
* Note that CHECK_FOR_INTERRUPTS() must not occur while updating them.
* Otherwise they can be updated inconsistently, and which might cause
* do_pg_abort_backup() to fail.
*/
WALInsertLockAcquireExclusive();
- if (exclusive)
- {
- XLogCtl->Insert.exclusiveBackupState = EXCLUSIVE_BACKUP_NONE;
- }
- else
- {
- /*
- * The user-visible pg_start/stop_backup() functions that operate on
- * exclusive backups can be called at any time, but for non-exclusive
- * backups, it is expected that each do_pg_start_backup() call is
- * matched by exactly one do_pg_stop_backup() call.
- */
- Assert(XLogCtl->Insert.nonExclusiveBackups > 0);
- XLogCtl->Insert.nonExclusiveBackups--;
- }
- if (XLogCtl->Insert.exclusiveBackupState == EXCLUSIVE_BACKUP_NONE &&
- XLogCtl->Insert.nonExclusiveBackups == 0)
+ /*
+ * It is expected that each do_pg_backup_start() call is matched by exactly
+ * one do_pg_backup_stop() call.
+ */
+ Assert(XLogCtl->Insert.runningBackups > 0);
+ XLogCtl->Insert.runningBackups--;
+
+ if (XLogCtl->Insert.runningBackups == 0)
{
XLogCtl->Insert.forcePageWrites = false;
}
@@ -8975,17 +8675,13 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
/*
* do_pg_abort_backup: abort a running backup
*
- * This does just the most basic steps of do_pg_stop_backup(), by taking the
+ * This does just the most basic steps of do_pg_backup_stop(), by taking the
* system out of backup mode, thus making it a lot more safe to call from
* an error handler.
*
* The caller can pass 'arg' as 'true' or 'false' to control whether a warning
* is emitted.
*
- * NB: This is only for aborting a non-exclusive backup that doesn't write
- * backup_label. A backup started with pg_start_backup() needs to be finished
- * with pg_stop_backup().
- *
* NB: This gets used as a before_shmem_exit handler, hence the odd-looking
* signature.
*/
@@ -8995,18 +8691,16 @@ do_pg_abort_backup(int code, Datum arg)
bool emit_warning = DatumGetBool(arg);
/*
- * Quick exit if session is not keeping around a non-exclusive backup
- * already started.
+ * Quick exit if session does not have a running backup.
*/
- if (sessionBackupState != SESSION_BACKUP_NON_EXCLUSIVE)
+ if (sessionBackupState != SESSION_BACKUP_RUNNING)
return;
WALInsertLockAcquireExclusive();
- Assert(XLogCtl->Insert.nonExclusiveBackups > 0);
- XLogCtl->Insert.nonExclusiveBackups--;
+ Assert(XLogCtl->Insert.runningBackups > 0);
+ XLogCtl->Insert.runningBackups--;
- if (XLogCtl->Insert.exclusiveBackupState == EXCLUSIVE_BACKUP_NONE &&
- XLogCtl->Insert.nonExclusiveBackups == 0)
+ if (XLogCtl->Insert.runningBackups == 0)
{
XLogCtl->Insert.forcePageWrites = false;
}
@@ -9014,7 +8708,7 @@ do_pg_abort_backup(int code, Datum arg)
if (emit_warning)
ereport(WARNING,
- (errmsg("aborting backup due to backend exiting before pg_stop_backup was called")));
+ (errmsg("aborting backup due to backend exiting before pg_backup_stop was called")));
}
/*
@@ -9074,87 +8768,6 @@ GetOldestRestartPoint(XLogRecPtr *oldrecptr, TimeLineID *oldtli)
LWLockRelease(ControlFileLock);
}
-/*
- * BackupInProgress: check if online backup mode is active
- *
- * This is done by checking for existence of the "backup_label" file.
- */
-bool
-BackupInProgress(void)
-{
- struct stat stat_buf;
-
- return (stat(BACKUP_LABEL_FILE, &stat_buf) == 0);
-}
-
-/*
- * CancelBackup: rename the "backup_label" and "tablespace_map"
- * files to cancel backup mode
- *
- * If the "backup_label" file exists, it will be renamed to "backup_label.old".
- * Similarly, if the "tablespace_map" file exists, it will be renamed to
- * "tablespace_map.old".
- *
- * Note that this will render an online backup in progress
- * useless. To correctly finish an online backup, pg_stop_backup must be
- * called.
- */
-void
-CancelBackup(void)
-{
- struct stat stat_buf;
-
- /* if the backup_label file is not there, return */
- if (stat(BACKUP_LABEL_FILE, &stat_buf) < 0)
- return;
-
- /* remove leftover file from previously canceled backup if it exists */
- unlink(BACKUP_LABEL_OLD);
-
- if (durable_rename(BACKUP_LABEL_FILE, BACKUP_LABEL_OLD, DEBUG1) != 0)
- {
- ereport(WARNING,
- (errcode_for_file_access(),
- errmsg("online backup mode was not canceled"),
- errdetail("File \"%s\" could not be renamed to \"%s\": %m.",
- BACKUP_LABEL_FILE, BACKUP_LABEL_OLD)));
- return;
- }
-
- /* if the tablespace_map file is not there, return */
- if (stat(TABLESPACE_MAP, &stat_buf) < 0)
- {
- ereport(LOG,
- (errmsg("online backup mode canceled"),
- errdetail("File \"%s\" was renamed to \"%s\".",
- BACKUP_LABEL_FILE, BACKUP_LABEL_OLD)));
- return;
- }
-
- /* remove leftover file from previously canceled backup if it exists */
- unlink(TABLESPACE_MAP_OLD);
-
- if (durable_rename(TABLESPACE_MAP, TABLESPACE_MAP_OLD, DEBUG1) == 0)
- {
- ereport(LOG,
- (errmsg("online backup mode canceled"),
- errdetail("Files \"%s\" and \"%s\" were renamed to "
- "\"%s\" and \"%s\", respectively.",
- BACKUP_LABEL_FILE, TABLESPACE_MAP,
- BACKUP_LABEL_OLD, TABLESPACE_MAP_OLD)));
- }
- else
- {
- ereport(WARNING,
- (errcode_for_file_access(),
- errmsg("online backup mode canceled"),
- errdetail("File \"%s\" was renamed to \"%s\", but "
- "file \"%s\" could not be renamed to \"%s\": %m.",
- BACKUP_LABEL_FILE, BACKUP_LABEL_OLD,
- TABLESPACE_MAP, TABLESPACE_MAP_OLD)));
- }
-}
-
/* Thin wrapper around ShutdownWalRcv(). */
void
XLogShutdownWalRcv(void)
diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c
index 2752be63c1..b61ae6c0b4 100644
--- a/src/backend/access/transam/xlogfuncs.c
+++ b/src/backend/access/transam/xlogfuncs.c
@@ -39,13 +39,13 @@
#include "utils/tuplestore.h"
/*
- * Store label file and tablespace map during non-exclusive backups.
+ * Store label file and tablespace map during backups.
*/
static StringInfo label_file;
static StringInfo tblspc_map_file;
/*
- * pg_start_backup: set up for taking an on-line backup dump
+ * pg_backup_start: set up for taking an on-line backup dump
*
* Essentially what this does is to create a backup label file in $PGDATA,
* where it will be archived as part of the backup dump. The label file
@@ -57,105 +57,44 @@ static StringInfo tblspc_map_file;
* GRANT system.
*/
Datum
-pg_start_backup(PG_FUNCTION_ARGS)
+pg_backup_start(PG_FUNCTION_ARGS)
{
text *backupid = PG_GETARG_TEXT_PP(0);
bool fast = PG_GETARG_BOOL(1);
- bool exclusive = PG_GETARG_BOOL(2);
char *backupidstr;
XLogRecPtr startpoint;
SessionBackupState status = get_backup_status();
+ MemoryContext oldcontext;
backupidstr = text_to_cstring(backupid);
- if (status == SESSION_BACKUP_NON_EXCLUSIVE)
+ if (status == SESSION_BACKUP_RUNNING)
ereport(ERROR,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("a backup is already in progress in this session")));
- if (exclusive)
- {
- startpoint = do_pg_start_backup(backupidstr, fast, NULL, NULL,
- NULL, NULL);
- }
- else
- {
- MemoryContext oldcontext;
-
- /*
- * Label file and tablespace map file need to be long-lived, since
- * they are read in pg_stop_backup.
- */
- oldcontext = MemoryContextSwitchTo(TopMemoryContext);
- label_file = makeStringInfo();
- tblspc_map_file = makeStringInfo();
- MemoryContextSwitchTo(oldcontext);
+ /*
+ * Label file and tablespace map file need to be long-lived, since
+ * they are read in pg_backup_stop.
+ */
+ oldcontext = MemoryContextSwitchTo(TopMemoryContext);
+ label_file = makeStringInfo();
+ tblspc_map_file = makeStringInfo();
+ MemoryContextSwitchTo(oldcontext);
- register_persistent_abort_backup_handler();
+ register_persistent_abort_backup_handler();
- startpoint = do_pg_start_backup(backupidstr, fast, NULL, label_file,
- NULL, tblspc_map_file);
- }
+ startpoint = do_pg_backup_start(backupidstr, fast, NULL, label_file,
+ NULL, tblspc_map_file);
PG_RETURN_LSN(startpoint);
}
-/*
- * pg_stop_backup: finish taking an on-line backup dump
- *
- * We write an end-of-backup WAL record, and remove the backup label file
- * created by pg_start_backup, creating a backup history file in pg_wal
- * instead (whence it will immediately be archived). The backup history file
- * contains the same info found in the label file, plus the backup-end time
- * and WAL location. Before 9.0, the backup-end time was read from the backup
- * history file at the beginning of archive recovery, but we now use the WAL
- * record for that and the file is for informational and debug purposes only.
- *
- * Note: different from CancelBackup which just cancels online backup mode.
- *
- * Note: this version is only called to stop an exclusive backup. The function
- * pg_stop_backup_v2 (overloaded as pg_stop_backup in SQL) is called to
- * stop non-exclusive backups.
- *
- * Permission checking for this function is managed through the normal
- * GRANT system.
- */
-Datum
-pg_stop_backup(PG_FUNCTION_ARGS)
-{
- XLogRecPtr stoppoint;
- SessionBackupState status = get_backup_status();
-
- if (status == SESSION_BACKUP_NON_EXCLUSIVE)
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("non-exclusive backup in progress"),
- errhint("Did you mean to use pg_stop_backup('f')?")));
-
- /*
- * Exclusive backups were typically started in a different connection, so
- * don't try to verify that status of backup is set to
- * SESSION_BACKUP_EXCLUSIVE in this function. Actual verification that an
- * exclusive backup is in fact running is handled inside
- * do_pg_stop_backup.
- */
- stoppoint = do_pg_stop_backup(NULL, true, NULL);
-
- PG_RETURN_LSN(stoppoint);
-}
-
/*
- * pg_stop_backup_v2: finish taking exclusive or nonexclusive on-line backup.
- *
- * Works the same as pg_stop_backup, except for non-exclusive backups it returns
- * the backup label and tablespace map files as text fields in as part of the
- * resultset.
+ * pg_backup_stop: finish taking an on-line backup.
*
- * The first parameter (variable 'exclusive') allows the user to tell us if
- * this is an exclusive or a non-exclusive backup.
- *
- * The second parameter (variable 'waitforarchive'), which is optional,
+ * The first parameter (variable 'waitforarchive'), which is optional,
* allows the user to choose if they want to wait for the WAL to be archived
* or if we should just return as soon as the WAL record is written.
*
@@ -163,15 +102,14 @@ pg_stop_backup(PG_FUNCTION_ARGS)
* GRANT system.
*/
Datum
-pg_stop_backup_v2(PG_FUNCTION_ARGS)
+pg_backup_stop(PG_FUNCTION_ARGS)
{
#define PG_STOP_BACKUP_V2_COLS 3
TupleDesc tupdesc;
Datum values[PG_STOP_BACKUP_V2_COLS];
bool nulls[PG_STOP_BACKUP_V2_COLS];
- bool exclusive = PG_GETARG_BOOL(0);
- bool waitforarchive = PG_GETARG_BOOL(1);
+ bool waitforarchive = PG_GETARG_BOOL(0);
XLogRecPtr stoppoint;
SessionBackupState status = get_backup_status();
@@ -182,51 +120,29 @@ pg_stop_backup_v2(PG_FUNCTION_ARGS)
MemSet(values, 0, sizeof(values));
MemSet(nulls, 0, sizeof(nulls));
- if (exclusive)
- {
- if (status == SESSION_BACKUP_NON_EXCLUSIVE)
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("non-exclusive backup in progress"),
- errhint("Did you mean to use pg_stop_backup('f')?")));
-
- /*
- * Stop the exclusive backup, and since we're in an exclusive backup
- * return NULL for both backup_label and tablespace_map.
- */
- stoppoint = do_pg_stop_backup(NULL, waitforarchive, NULL);
-
- nulls[1] = true;
- nulls[2] = true;
- }
- else
- {
- if (status != SESSION_BACKUP_NON_EXCLUSIVE)
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("non-exclusive backup is not in progress"),
- errhint("Did you mean to use pg_stop_backup('t')?")));
+ if (status != SESSION_BACKUP_RUNNING)
+ ereport(ERROR,
+ (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ errmsg("backup is not in progress"),
+ errhint("Did you call pg_backup_start()?")));
- /*
- * Stop the non-exclusive backup. Return a copy of the backup label
- * and tablespace map so they can be written to disk by the caller.
- */
- stoppoint = do_pg_stop_backup(label_file->data, waitforarchive, NULL);
-
- values[1] = CStringGetTextDatum(label_file->data);
- values[2] = CStringGetTextDatum(tblspc_map_file->data);
-
- /* Free structures allocated in TopMemoryContext */
- pfree(label_file->data);
- pfree(label_file);
- label_file = NULL;
- pfree(tblspc_map_file->data);
- pfree(tblspc_map_file);
- tblspc_map_file = NULL;
- }
+ /*
+ * Stop the backup. Return a copy of the backup label and tablespace map so
+ * they can be written to disk by the caller.
+ */
+ stoppoint = do_pg_backup_stop(label_file->data, waitforarchive, NULL);
- /* Stoppoint is included on both exclusive and nonexclusive backups */
values[0] = LSNGetDatum(stoppoint);
+ values[1] = CStringGetTextDatum(label_file->data);
+ values[2] = CStringGetTextDatum(tblspc_map_file->data);
+
+ /* Free structures allocated in TopMemoryContext */
+ pfree(label_file->data);
+ pfree(label_file);
+ label_file = NULL;
+ pfree(tblspc_map_file->data);
+ pfree(tblspc_map_file);
+ tblspc_map_file = NULL;
/* Returns the record as Datum */
PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
@@ -298,7 +214,7 @@ pg_create_restore_point(PG_FUNCTION_ARGS)
}
/*
- * Report the current WAL write location (same format as pg_start_backup etc)
+ * Report the current WAL write location (same format as pg_backup_start etc)
*
* This is useful for determining how much of WAL is visible to an external
* archiving process. Note that the data before this point is written out
@@ -321,7 +237,7 @@ pg_current_wal_lsn(PG_FUNCTION_ARGS)
}
/*
- * Report the current WAL insert location (same format as pg_start_backup etc)
+ * Report the current WAL insert location (same format as pg_backup_start etc)
*
* This function is mostly for debugging purposes.
*/
@@ -342,7 +258,7 @@ pg_current_wal_insert_lsn(PG_FUNCTION_ARGS)
}
/*
- * Report the current WAL flush location (same format as pg_start_backup etc)
+ * Report the current WAL flush location (same format as pg_backup_start etc)
*
* This function is mostly for debugging purposes.
*/
@@ -363,7 +279,7 @@ pg_current_wal_flush_lsn(PG_FUNCTION_ARGS)
}
/*
- * Report the last WAL receive location (same format as pg_start_backup etc)
+ * Report the last WAL receive location (same format as pg_backup_start etc)
*
* This is useful for determining how much of WAL is guaranteed to be received
* and synced to disk by walreceiver.
@@ -382,7 +298,7 @@ pg_last_wal_receive_lsn(PG_FUNCTION_ARGS)
}
/*
- * Report the last WAL replay location (same format as pg_start_backup etc)
+ * Report the last WAL replay location (same format as pg_backup_start etc)
*
* This is useful for determining how much of WAL is visible to read-only
* connections during recovery.
@@ -402,7 +318,7 @@ pg_last_wal_replay_lsn(PG_FUNCTION_ARGS)
/*
* Compute an xlog file name and decimal byte offset given a WAL location,
- * such as is returned by pg_stop_backup() or pg_switch_wal().
+ * such as is returned by pg_backup_stop() or pg_switch_wal().
*
* Note that a location exactly at a segment boundary is taken to be in
* the previous segment. This is usually the right thing, since the
@@ -470,7 +386,7 @@ pg_walfile_name_offset(PG_FUNCTION_ARGS)
/*
* Compute an xlog file name given a WAL location,
- * such as is returned by pg_stop_backup() or pg_switch_wal().
+ * such as is returned by pg_backup_stop() or pg_switch_wal().
*/
Datum
pg_walfile_name(PG_FUNCTION_ARGS)
@@ -645,81 +561,6 @@ pg_wal_lsn_diff(PG_FUNCTION_ARGS)
PG_RETURN_NUMERIC(result);
}
-/*
- * Returns bool with current on-line backup mode, a global state.
- */
-Datum
-pg_is_in_backup(PG_FUNCTION_ARGS)
-{
- PG_RETURN_BOOL(BackupInProgress());
-}
-
-/*
- * Returns start time of an online exclusive backup.
- *
- * When there's no exclusive backup in progress, the function
- * returns NULL.
- */
-Datum
-pg_backup_start_time(PG_FUNCTION_ARGS)
-{
- Datum xtime;
- FILE *lfp;
- char fline[MAXPGPATH];
- char backup_start_time[30];
-
- /*
- * See if label file is present
- */
- lfp = AllocateFile(BACKUP_LABEL_FILE, "r");
- if (lfp == NULL)
- {
- if (errno != ENOENT)
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not read file \"%s\": %m",
- BACKUP_LABEL_FILE)));
- PG_RETURN_NULL();
- }
-
- /*
- * Parse the file to find the START TIME line.
- */
- backup_start_time[0] = '\0';
- while (fgets(fline, sizeof(fline), lfp) != NULL)
- {
- if (sscanf(fline, "START TIME: %25[^\n]\n", backup_start_time) == 1)
- break;
- }
-
- /* Check for a read error. */
- if (ferror(lfp))
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not read file \"%s\": %m", BACKUP_LABEL_FILE)));
-
- /* Close the backup label file. */
- if (FreeFile(lfp))
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not close file \"%s\": %m", BACKUP_LABEL_FILE)));
-
- if (strlen(backup_start_time) == 0)
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("invalid data in file \"%s\"", BACKUP_LABEL_FILE)));
-
- /*
- * Convert the time string read from file to TimestampTz form.
- */
- xtime = DirectFunctionCall3(timestamptz_in,
- CStringGetDatum(backup_start_time),
- ObjectIdGetDatum(InvalidOid),
- Int32GetDatum(-1));
-
- PG_RETURN_DATUM(xtime);
-}
-
/*
* Promotes a standby server.
*
diff --git a/src/backend/access/transam/xlogrecovery.c b/src/backend/access/transam/xlogrecovery.c
index f9f212680b..d2b5e7f32c 100644
--- a/src/backend/access/transam/xlogrecovery.c
+++ b/src/backend/access/transam/xlogrecovery.c
@@ -1966,7 +1966,7 @@ xlogrecovery_redo(XLogReaderState *record, TimeLineID replayTLI)
{
/*
* We have reached the end of base backup, the point where
- * pg_stop_backup() was done. The data on disk is now consistent
+ * pg_backup_stop() was done. The data on disk is now consistent
* (assuming we have also reached minRecoveryPoint). Set
* backupEndPoint to the current LSN, so that the next call to
* CheckRecoveryConsistency() will notice it and do the
diff --git a/src/backend/catalog/system_functions.sql b/src/backend/catalog/system_functions.sql
index 81bac6f581..6ae4388d3f 100644
--- a/src/backend/catalog/system_functions.sql
+++ b/src/backend/catalog/system_functions.sql
@@ -377,14 +377,14 @@ BEGIN ATOMIC
END;
CREATE OR REPLACE FUNCTION
- pg_start_backup(label text, fast boolean DEFAULT false, exclusive boolean DEFAULT true)
- RETURNS pg_lsn STRICT VOLATILE LANGUAGE internal AS 'pg_start_backup'
+ pg_backup_start(label text, fast boolean DEFAULT false)
+ RETURNS pg_lsn STRICT VOLATILE LANGUAGE internal AS 'pg_backup_start'
PARALLEL RESTRICTED;
-CREATE OR REPLACE FUNCTION pg_stop_backup (
- exclusive boolean, wait_for_archive boolean DEFAULT true,
- OUT lsn pg_lsn, OUT labelfile text, OUT spcmapfile text)
- RETURNS record STRICT VOLATILE LANGUAGE internal as 'pg_stop_backup_v2'
+CREATE OR REPLACE FUNCTION pg_backup_stop (
+ wait_for_archive boolean DEFAULT true, OUT lsn pg_lsn,
+ OUT labelfile text, OUT spcmapfile text)
+ RETURNS record STRICT VOLATILE LANGUAGE internal as 'pg_backup_stop'
PARALLEL RESTRICTED;
CREATE OR REPLACE FUNCTION
@@ -603,11 +603,9 @@ AS 'unicode_is_normalized';
-- available to superuser / cluster owner, if they choose.
--
-REVOKE EXECUTE ON FUNCTION pg_start_backup(text, boolean, boolean) FROM public;
+REVOKE EXECUTE ON FUNCTION pg_backup_start(text, boolean) FROM public;
-REVOKE EXECUTE ON FUNCTION pg_stop_backup() FROM public;
-
-REVOKE EXECUTE ON FUNCTION pg_stop_backup(boolean, boolean) FROM public;
+REVOKE EXECUTE ON FUNCTION pg_backup_stop(boolean) FROM public;
REVOKE EXECUTE ON FUNCTION pg_create_restore_point(text) FROM public;
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index 80bb269599..b6767ed72e 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -348,7 +348,6 @@ static PMState pmState = PM_INIT;
typedef enum
{
ALLOW_ALL_CONNS, /* normal not-shutting-down state */
- ALLOW_SUPERUSER_CONNS, /* only superusers can connect */
ALLOW_NO_CONNS /* no new connections allowed, period */
} ConnsAllowedState;
@@ -2546,19 +2545,11 @@ canAcceptConnections(int backend_type)
/*
* "Smart shutdown" restrictions are applied only to normal connections,
- * not to autovac workers or bgworkers. When only superusers can connect,
- * we return CAC_SUPERUSER to indicate that superuserness must be checked
- * later. Note that neither CAC_OK nor CAC_SUPERUSER can safely be
- * returned until we have checked for too many children.
+ * not to autovac workers or bgworkers.
*/
if (connsAllowed != ALLOW_ALL_CONNS &&
backend_type == BACKEND_TYPE_NORMAL)
- {
- if (connsAllowed == ALLOW_SUPERUSER_CONNS)
- result = CAC_SUPERUSER; /* allow superusers only */
- else
- return CAC_SHUTDOWN; /* shutdown is pending */
- }
+ return CAC_SHUTDOWN; /* shutdown is pending */
/*
* Don't start too many children.
@@ -2877,16 +2868,11 @@ pmdie(SIGNAL_ARGS)
#endif
/*
- * If we reached normal running, we have to wait for any online
- * backup mode to end; otherwise go straight to waiting for client
- * backends to exit. (The difference is that in the former state,
- * we'll still let in new superuser clients, so that somebody can
- * end the online backup mode.) If already in PM_STOP_BACKENDS or
+ * If we reached normal running, we go straight to waiting for
+ * client backends to exit. If already in PM_STOP_BACKENDS or
* a later state, do not change it.
*/
- if (pmState == PM_RUN)
- connsAllowed = ALLOW_SUPERUSER_CONNS;
- else if (pmState == PM_HOT_STANDBY)
+ if (pmState == PM_RUN || pmState == PM_HOT_STANDBY)
connsAllowed = ALLOW_NO_CONNS;
else if (pmState == PM_STARTUP || pmState == PM_RECOVERY)
{
@@ -3842,16 +3828,6 @@ PostmasterStateMachine(void)
/* If we're doing a smart shutdown, try to advance that state. */
if (pmState == PM_RUN || pmState == PM_HOT_STANDBY)
{
- if (connsAllowed == ALLOW_SUPERUSER_CONNS)
- {
- /*
- * ALLOW_SUPERUSER_CONNS state ends as soon as online backup mode
- * is not active.
- */
- if (!BackupInProgress())
- connsAllowed = ALLOW_NO_CONNS;
- }
-
if (connsAllowed == ALLOW_NO_CONNS)
{
/*
@@ -4044,18 +4020,6 @@ PostmasterStateMachine(void)
}
else
{
- /*
- * Terminate exclusive backup mode to avoid recovery after a clean
- * fast shutdown. Since an exclusive backup can only be taken
- * during normal running (and not, for example, while running
- * under Hot Standby) it only makes sense to do this if we reached
- * normal running. If we're still in recovery, the backup file is
- * one we're recovering *from*, and we must keep it around so that
- * recovery restarts from the right place.
- */
- if (ReachedNormalRunning)
- CancelBackup();
-
/*
* Normal exit from the postmaster is here. We don't need to log
* anything here, since the UnlinkLockFiles proc_exit callback
diff --git a/src/backend/replication/basebackup.c b/src/backend/replication/basebackup.c
index 2378ce5c5e..b12ffb4529 100644
--- a/src/backend/replication/basebackup.c
+++ b/src/backend/replication/basebackup.c
@@ -196,10 +196,8 @@ static const struct exclude_list_item excludeFiles[] =
{RELCACHE_INIT_FILENAME, true},
/*
- * If there's a backup_label or tablespace_map file, it belongs to a
- * backup started by the user with pg_start_backup(). It is *not* correct
- * for this backup. Our backup_label/tablespace_map is injected into the
- * tar separately.
+ * backup_label and tablespace_map should not exist in in a running cluster
+ * capable of doing an online backup, but exclude then just in case.
*/
{BACKUP_LABEL_FILE, false},
{TABLESPACE_MAP, false},
@@ -276,16 +274,16 @@ perform_base_backup(basebackup_options *opt, bbsink *sink)
total_checksum_failures = 0;
basebackup_progress_wait_checkpoint();
- state.startptr = do_pg_start_backup(opt->label, opt->fastcheckpoint,
+ state.startptr = do_pg_backup_start(opt->label, opt->fastcheckpoint,
&state.starttli,
labelfile, &state.tablespaces,
tblspc_map_file);
/*
- * Once do_pg_start_backup has been called, ensure that any failure causes
+ * Once do_pg_backup_start has been called, ensure that any failure causes
* us to abort the backup so we don't "leak" a backup counter. For this
- * reason, *all* functionality between do_pg_start_backup() and the end of
- * do_pg_stop_backup() should be inside the error cleanup block!
+ * reason, *all* functionality between do_pg_backup_start() and the end of
+ * do_pg_backup_stop() should be inside the error cleanup block!
*/
PG_ENSURE_ERROR_CLEANUP(do_pg_abort_backup, BoolGetDatum(false));
@@ -406,7 +404,7 @@ perform_base_backup(basebackup_options *opt, bbsink *sink)
}
basebackup_progress_wait_wal_archive(&state);
- endptr = do_pg_stop_backup(labelfile->data, !opt->nowait, &endtli);
+ endptr = do_pg_backup_stop(labelfile->data, !opt->nowait, &endtli);
}
PG_END_ENSURE_ERROR_CLEANUP(do_pg_abort_backup, BoolGetDatum(false));
@@ -969,7 +967,7 @@ parse_basebackup_options(List *options, basebackup_options *opt)
/*
* SendBaseBackup() - send a complete base backup.
*
- * The function will put the system into backup mode like pg_start_backup()
+ * The function will put the system into backup mode like pg_backup_start()
* does, so that the backup is consistent even though we read directly from
* the filesystem, bypassing the buffer cache.
*/
@@ -1230,7 +1228,7 @@ sendDir(bbsink *sink, const char *path, int basepathlen, bool sizeonly,
* error in that case. The error handler further up will call
* do_pg_abort_backup() for us. Also check that if the backup was
* started while still in recovery, the server wasn't promoted.
- * do_pg_stop_backup() will check that too, but it's better to stop
+ * do_pg_backup_stop() will check that too, but it's better to stop
* the backup early than continue to the end and fail there.
*/
CHECK_FOR_INTERRUPTS();
diff --git a/src/bin/pg_basebackup/t/010_pg_basebackup.pl b/src/bin/pg_basebackup/t/010_pg_basebackup.pl
index 8cb8cfe045..c7c01a0992 100644
--- a/src/bin/pg_basebackup/t/010_pg_basebackup.pl
+++ b/src/bin/pg_basebackup/t/010_pg_basebackup.pl
@@ -185,6 +185,10 @@ isnt(slurp_file("$tempdir/backup/backup_label"),
'DONOTCOPY', 'existing backup_label not copied');
rmtree("$tempdir/backup");
+# Now delete the bogus backup_label file since it will interfere with startup
+unlink("$pgdata/backup_label")
+ or BAIL_OUT("unable to unlink $pgdata/backup_label");
+
$node->command_ok(
[
@pg_basebackup_defs, '-D',
diff --git a/src/bin/pg_ctl/pg_ctl.c b/src/bin/pg_ctl/pg_ctl.c
index 3c182c97d4..ee3fa148b6 100644
--- a/src/bin/pg_ctl/pg_ctl.c
+++ b/src/bin/pg_ctl/pg_ctl.c
@@ -1069,7 +1069,7 @@ do_stop(void)
get_control_dbstate() != DB_IN_ARCHIVE_RECOVERY)
{
print_msg(_("WARNING: online backup mode is active\n"
- "Shutdown will not complete until pg_stop_backup() is called.\n\n"));
+ "Shutdown will not complete until pg_backup_stop() is called.\n\n"));
}
print_msg(_("waiting for server to shut down..."));
@@ -1145,7 +1145,7 @@ do_restart(void)
get_control_dbstate() != DB_IN_ARCHIVE_RECOVERY)
{
print_msg(_("WARNING: online backup mode is active\n"
- "Shutdown will not complete until pg_stop_backup() is called.\n\n"));
+ "Shutdown will not complete until pg_backup_stop() is called.\n\n"));
}
print_msg(_("waiting for server to shut down..."));
diff --git a/src/bin/pg_rewind/filemap.c b/src/bin/pg_rewind/filemap.c
index 7211090f47..fb52debf7a 100644
--- a/src/bin/pg_rewind/filemap.c
+++ b/src/bin/pg_rewind/filemap.c
@@ -140,9 +140,9 @@ static const struct exclude_list_item excludeFiles[] =
{"pg_internal.init", true}, /* defined as RELCACHE_INIT_FILENAME */
/*
- * If there's a backup_label or tablespace_map file, it belongs to a
- * backup started by the user with pg_start_backup(). It is *not* correct
- * for this backup. Our backup_label is written later on separately.
+ * If there is a backup_label or tablespace_map file, it indicates that
+ * a recovery failed and this cluster probably can't be rewound, but
+ * exclude them anyway if they are found.
*/
{"backup_label", false}, /* defined as BACKUP_LABEL_FILE */
{"tablespace_map", false}, /* defined as TABLESPACE_MAP */
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index 4b45ac64db..be375df248 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -275,14 +275,13 @@ extern void XLogShutdownWalRcv(void);
typedef enum SessionBackupState
{
SESSION_BACKUP_NONE,
- SESSION_BACKUP_EXCLUSIVE,
- SESSION_BACKUP_NON_EXCLUSIVE
+ SESSION_BACKUP_RUNNING,
} SessionBackupState;
-extern XLogRecPtr do_pg_start_backup(const char *backupidstr, bool fast,
+extern XLogRecPtr do_pg_backup_start(const char *backupidstr, bool fast,
TimeLineID *starttli_p, StringInfo labelfile,
List **tablespaces, StringInfo tblspcmapfile);
-extern XLogRecPtr do_pg_stop_backup(char *labelfile, bool waitforarchive,
+extern XLogRecPtr do_pg_backup_stop(char *labelfile, bool waitforarchive,
TimeLineID *stoptli_p);
extern void do_pg_abort_backup(int code, Datum arg);
extern void register_persistent_abort_backup_handler(void);
diff --git a/src/include/catalog/pg_control.h b/src/include/catalog/pg_control.h
index 1f3dc24ac1..3d075fcef3 100644
--- a/src/include/catalog/pg_control.h
+++ b/src/include/catalog/pg_control.h
@@ -163,7 +163,7 @@ typedef struct ControlFileData
* from a backup, and must see a backup-end record before we can safely
* start up. If it's false, but backupStartPoint is set, a backup_label
* file was found at startup but it may have been a leftover from a stray
- * pg_start_backup() call, not accompanied by pg_stop_backup().
+ * pg_backup_start() call, not accompanied by pg_backup_stop().
*/
XLogRecPtr minRecoveryPoint;
TimeLineID minRecoveryPointTLI;
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index d8e8715ed1..8563714c9c 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -6268,26 +6268,16 @@
proargtypes => 'int4 int8', proargnames => '{pid,timeout}',
prosrc => 'pg_terminate_backend' },
{ oid => '2172', descr => 'prepare for taking an online backup',
- proname => 'pg_start_backup', provolatile => 'v', proparallel => 'r',
- prorettype => 'pg_lsn', proargtypes => 'text bool bool',
- prosrc => 'pg_start_backup' },
-{ oid => '2173', descr => 'finish taking an online backup',
- proname => 'pg_stop_backup', provolatile => 'v', proparallel => 'r',
- prorettype => 'pg_lsn', proargtypes => '', prosrc => 'pg_stop_backup' },
+ proname => 'pg_backup_start', provolatile => 'v', proparallel => 'r',
+ prorettype => 'pg_lsn', proargtypes => 'text bool',
+ prosrc => 'pg_backup_start' },
{ oid => '2739', descr => 'finish taking an online backup',
- proname => 'pg_stop_backup', provolatile => 'v', proparallel => 'r',
- prorettype => 'record', proargtypes => 'bool bool',
- proallargtypes => '{bool,bool,pg_lsn,text,text}',
- proargmodes => '{i,i,o,o,o}',
- proargnames => '{exclusive,wait_for_archive,lsn,labelfile,spcmapfile}',
- prosrc => 'pg_stop_backup_v2' },
-{ oid => '3813', descr => 'true if server is in online backup',
- proname => 'pg_is_in_backup', provolatile => 'v', prorettype => 'bool',
- proargtypes => '', prosrc => 'pg_is_in_backup' },
-{ oid => '3814', descr => 'start time of an online backup',
- proname => 'pg_backup_start_time', provolatile => 's',
- prorettype => 'timestamptz', proargtypes => '',
- prosrc => 'pg_backup_start_time' },
+ proname => 'pg_backup_stop', provolatile => 'v', proparallel => 'r',
+ prorettype => 'record', proargtypes => 'bool',
+ proallargtypes => '{bool,pg_lsn,text,text}',
+ proargmodes => '{i,o,o,o}',
+ proargnames => '{wait_for_archive,lsn,labelfile,spcmapfile}',
+ prosrc => 'pg_backup_stop' },
{ oid => '3436', descr => 'promote standby server',
proname => 'pg_promote', provolatile => 'v', prorettype => 'bool',
proargtypes => 'bool int4', proargnames => '{wait,wait_seconds}',
diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h
index 0abc3ad540..9321d7f264 100644
--- a/src/include/miscadmin.h
+++ b/src/include/miscadmin.h
@@ -481,10 +481,6 @@ extern void process_session_preload_libraries(void);
extern void pg_bindtextdomain(const char *domain);
extern bool has_rolreplication(Oid roleid);
-/* in access/transam/xlog.c */
-extern bool BackupInProgress(void);
-extern void CancelBackup(void);
-
/* in executor/nodeHash.c */
extern size_t get_hash_memory_limit(void);
diff --git a/src/test/perl/PostgreSQL/Test/Cluster.pm b/src/test/perl/PostgreSQL/Test/Cluster.pm
index 4db52bc936..e1316abf3f 100644
--- a/src/test/perl/PostgreSQL/Test/Cluster.pm
+++ b/src/test/perl/PostgreSQL/Test/Cluster.pm
@@ -635,25 +635,6 @@ sub backup
return;
}
-=item $node->backup_fs_hot(backup_name)
-
-Create a backup with a filesystem level copy in subdirectory B<backup_name> of
-B<< $node->backup_dir >>, including WAL.
-
-Archiving must be enabled, as B<pg_start_backup()> and B<pg_stop_backup()> are
-used. This is not checked or enforced.
-
-The backup name is passed as the backup label to B<pg_start_backup()>.
-
-=cut
-
-sub backup_fs_hot
-{
- my ($self, $backup_name) = @_;
- $self->_backup_fs($backup_name, 1);
- return;
-}
-
=item $node->backup_fs_cold(backup_name)
Create a backup with a filesystem level copy in subdirectory B<backup_name> of
@@ -667,53 +648,18 @@ Use B<backup> or B<backup_fs_hot> if you want to back up a running server.
sub backup_fs_cold
{
my ($self, $backup_name) = @_;
- $self->_backup_fs($backup_name, 0);
- return;
-}
-
-
-# Common sub of backup_fs_hot and backup_fs_cold
-sub _backup_fs
-{
- my ($self, $backup_name, $hot) = @_;
- my $backup_path = $self->backup_dir . '/' . $backup_name;
- my $port = $self->port;
- my $name = $self->name;
-
- print "# Taking filesystem backup $backup_name from node \"$name\"\n";
-
- if ($hot)
- {
- my $stdout = $self->safe_psql('postgres',
- "SELECT * FROM pg_start_backup('$backup_name');");
- print "# pg_start_backup: $stdout\n";
- }
PostgreSQL::Test::RecursiveCopy::copypath(
$self->data_dir,
- $backup_path,
+ $self->backup_dir . '/' . $backup_name,
filterfn => sub {
my $src = shift;
return ($src ne 'log' and $src ne 'postmaster.pid');
});
- if ($hot)
- {
-
- # We ignore pg_stop_backup's return value. We also assume archiving
- # is enabled; otherwise the caller will have to copy the remaining
- # segments.
- my $stdout =
- $self->safe_psql('postgres', 'SELECT * FROM pg_stop_backup();');
- print "# pg_stop_backup: $stdout\n";
- }
-
- print "# Backup finished\n";
return;
}
-
-
=pod
=item $node->init_from_backup(root_node, backup_name)
diff --git a/src/test/recovery/t/010_logical_decoding_timelines.pl b/src/test/recovery/t/010_logical_decoding_timelines.pl
index 01ff31e61f..135fb1a72d 100644
--- a/src/test/recovery/t/010_logical_decoding_timelines.pl
+++ b/src/test/recovery/t/010_logical_decoding_timelines.pl
@@ -69,7 +69,9 @@ $node_primary->safe_psql('dropme',
$node_primary->safe_psql('postgres', 'CHECKPOINT;');
my $backup_name = 'b1';
-$node_primary->backup_fs_hot($backup_name);
+$node_primary->stop();
+$node_primary->backup_fs_cold($backup_name);
+$node_primary->start();
$node_primary->safe_psql('postgres',
q[SELECT pg_create_physical_replication_slot('phys_slot');]);
--
2.25.1
On 03/08/22 17:12, Nathan Bossart wrote:
I spent some time trying to come up with a workable script to replace the
existing one. I think the main problem is that you need to write out both
the backup label file and the tablespace map file, but I didn't find an
easy way to write the different output columns of pg_backup_stop() to
separate files via psql.
Something like this might work:
SELECT * FROM pg_backup_stop(true) \gset
\out /tmp/backup_label \qecho :labelfile
\out /tmp/tablespace_map \qecho :spcmapfile
\out
\! ... tar command adding /tmp/{backup_label,tablespace_map} to the tarball
I notice the \qecho adds a final newline (and so if :spcmapfile is empty,
a file containing a single newline is made). In a quick test with a bogus
restore_command, I did not see any error messages specific to the format
of the backup_label or tablespace_map files, so maybe the final newline
isn't a problem.
Assuming the newline isn't a problem, that might be simple enough to
use in an example, and maybe it's not a bad thing that it highlights a few
psql capabilities the reader might not have stumbled on before. Or, maybe
it is just too confusing to bother.
While agreeing that pg_basebackup is the production-ready thing that
does it all for you (with tests for likely errors and so on), I think
there is also some value in a dead-simple example that concretely
shows you what "it" is, what the basic steps are that happen beneath
pg_basebackup's chrome.
If the added newline is a problem, I haven't thought of a way to exclude
it that doesn't take the example out of the realm of dead-simple.
Regards,
-Chap
Greetings,
* Chapman Flack (chap@anastigmatix.net) wrote:
On 03/08/22 17:12, Nathan Bossart wrote:
I spent some time trying to come up with a workable script to replace the
existing one. I think the main problem is that you need to write out both
the backup label file and the tablespace map file, but I didn't find an
easy way to write the different output columns of pg_backup_stop() to
separate files via psql.
Let's not confuse ourselves here- the existing script *doesn't* work in
any reasonable way when we're talking about everything that needs to be
done to perform a backup. That a lot of people are using it because
it's in the documentation is an actively bad thing.
The same goes for the archive command example.
Something like this might work:
SELECT * FROM pg_backup_stop(true) \gset
\out /tmp/backup_label \qecho :labelfile
\out /tmp/tablespace_map \qecho :spcmapfile
\out
\! ... tar command adding /tmp/{backup_label,tablespace_map} to the tarball
... this doesn't do what's needed either. We could try to write down
some minimum set of things that are needed for a backup tool to do but
it's not something that a 3 line script is going to cover. Indeed, it's
a lot more like pg_basebackup and if we want to give folks a script to
use, it should be "run pg_basebackup".
I notice the \qecho adds a final newline (and so if :spcmapfile is empty,
a file containing a single newline is made). In a quick test with a bogus
restore_command, I did not see any error messages specific to the format
of the backup_label or tablespace_map files, so maybe the final newline
isn't a problem.Assuming the newline isn't a problem, that might be simple enough to
use in an example, and maybe it's not a bad thing that it highlights a few
psql capabilities the reader might not have stumbled on before. Or, maybe
it is just too confusing to bother.
It's more than just too confusing, it's actively bad because people will
actually use it and then end up with backups that don't work.
While agreeing that pg_basebackup is the production-ready thing that
does it all for you (with tests for likely errors and so on), I think
there is also some value in a dead-simple example that concretely
shows you what "it" is, what the basic steps are that happen beneath
pg_basebackup's chrome.
Documenting everything that pg_basebackup does to make sure that the
backup is viable might be something to work on if someone is really
excited about this, but it's not 'dead-simple' and it's darn close to
the bare minimum, something that none of these simple scripts will come
anywhere close to being and instead they'll be far less than the
minimum.
If the added newline is a problem, I haven't thought of a way to exclude
it that doesn't take the example out of the realm of dead-simple.
I disagree that there's really a way to provide 'dead-simple' backups
with what's built into core without using pg_basebackup. If we want a
'dead-simple' solution in core then we'd need to write an appropriate
backup tool that does all the basic things and include and maintain
that. Writing a shell script isn't enough and we shouldn't encourage
our users to do exactly that by having it in our documentation because
then they'll think it's enough.
Thanks,
Stephen
On Wed, Mar 9, 2022 at 4:42 PM Stephen Frost <sfrost@snowman.net> wrote:
Greetings,
* Chapman Flack (chap@anastigmatix.net) wrote:
On 03/08/22 17:12, Nathan Bossart wrote:
I spent some time trying to come up with a workable script to replace the
existing one. I think the main problem is that you need to write out both
the backup label file and the tablespace map file, but I didn't find an
easy way to write the different output columns of pg_backup_stop() to
separate files via psql.Let's not confuse ourselves here- the existing script *doesn't* work in
any reasonable way when we're talking about everything that needs to be
done to perform a backup. That a lot of people are using it because
it's in the documentation is an actively bad thing.The same goes for the archive command example.
Something like this might work:
SELECT * FROM pg_backup_stop(true) \gset
\out /tmp/backup_label \qecho :labelfile
\out /tmp/tablespace_map \qecho :spcmapfile
\out
\! ... tar command adding /tmp/{backup_label,tablespace_map} to the tarball... this doesn't do what's needed either. We could try to write down
some minimum set of things that are needed for a backup tool to do but
it's not something that a 3 line script is going to cover. Indeed, it's
a lot more like pg_basebackup and if we want to give folks a script to
use, it should be "run pg_basebackup".I notice the \qecho adds a final newline (and so if :spcmapfile is empty,
a file containing a single newline is made). In a quick test with a bogus
restore_command, I did not see any error messages specific to the format
of the backup_label or tablespace_map files, so maybe the final newline
isn't a problem.Assuming the newline isn't a problem, that might be simple enough to
use in an example, and maybe it's not a bad thing that it highlights a few
psql capabilities the reader might not have stumbled on before. Or, maybe
it is just too confusing to bother.It's more than just too confusing, it's actively bad because people will
actually use it and then end up with backups that don't work.
+1.
Or even worse, backups that sometimes work, but not reliably and not every time.
While agreeing that pg_basebackup is the production-ready thing that
does it all for you (with tests for likely errors and so on), I think
there is also some value in a dead-simple example that concretely
shows you what "it" is, what the basic steps are that happen beneath
pg_basebackup's chrome.
I agree that having a dead simple script would be good.
The *only* dead simple script that's going to be possible is one that
calls pg_basebackup.
The current APIs don't make it *possible* to drive them directly with
a dead simple script.
Pretending something is simple when it's not, is not doing anybody a favor.
Documenting everything that pg_basebackup does to make sure that the
backup is viable might be something to work on if someone is really
excited about this, but it's not 'dead-simple' and it's darn close to
the bare minimum, something that none of these simple scripts will come
anywhere close to being and instead they'll be far less than the
minimum.
Yeah, having the full set of steps required documented certainly
wouldn't be a bad thing. But it's a very *different* thing.
If the added newline is a problem, I haven't thought of a way to exclude
it that doesn't take the example out of the realm of dead-simple.I disagree that there's really a way to provide 'dead-simple' backups
with what's built into core without using pg_basebackup. If we want a
'dead-simple' solution in core then we'd need to write an appropriate
backup tool that does all the basic things and include and maintain
that. Writing a shell script isn't enough and we shouldn't encourage
our users to do exactly that by having it in our documentation because
then they'll think it's enough.
+1.
We need to accept that the current APIs are far too low level to be
driven by a shellscript. No matter how much documentation we write is
not going to change that fact.
For the people who want to drive their backups from a shellscript and
for some reason *don't* want to use pg_basebackup, we need to come up
with a different API or a different set of tools. That is not a
documentation task. That is a "start from a list of which things
pg_basebackup cannot do that are still simple, or that tools like
pgbackrest cannot do if they're complicated". And then design an API
that's actually safe and easy to use *for that usecase*.
For example, if the use case is "i want to use filesystemor SAN
snapshots for my backups", we shouldn't try to write workarounds using
bash coprocs or whatever. Instead, we could write a tool that
interacts with the current api to start the backup, then launches a
shellscript that interacts with the snapshot system, and then stops
the backup after. With a well defined set of rules for how that shell
script should work and interact.
--
Magnus Hagander
Me: https://www.hagander.net/
Work: https://www.redpill-linpro.com/
On 03/09/22 11:22, Magnus Hagander wrote:
It's more than just too confusing, it's actively bad because people will
actually use it and then end up with backups that don't work.+1.
Or even worse, backups that sometimes work, but not reliably and not
every time.
...
Pretending something is simple when it's not, is not doing anybody a favor.
Okay, I bow to this reasoning, for the purpose of this patch. Let's
just lose the example.
Documenting everything that pg_basebackup does to make sure that the
backup is viable might be something to work on if someone is really
excited about this, but it's not 'dead-simple' and it's darn close to
the bare minimum, something that none of these simple scripts will come
anywhere close to being and instead they'll be far less than the
minimum.Yeah, having the full set of steps required documented certainly
wouldn't be a bad thing.
I'd say that qualifies as an understatement. While it certainly doesn't
have to be part of this patch, if the claim is that an admin who relies
on pg_basebackup is relying on essential things pg_basebackup does that
have not been enumerated in our documentation yet, I would argue they
should be.
with a different API or a different set of tools. That is not a
documentation task. That is a "start from a list of which things
pg_basebackup cannot do that are still simple, or that tools like
pgbackrest cannot do if they're complicated". And then design an API
that's actually safe and easy to use *for that usecase*.
That might also be a good thing, but I don't see it as a substitute
for documenting the present reality of what the irreducibly essential
behaviors of pg_basebackup (or of third-party tools like pgbackrest)
are, and why they are so.
Regards,
-Chap
Greetings,
* Chapman Flack (chap@anastigmatix.net) wrote:
On 03/09/22 11:22, Magnus Hagander wrote:
It's more than just too confusing, it's actively bad because people will
actually use it and then end up with backups that don't work.+1.
Or even worse, backups that sometimes work, but not reliably and not
every time.
...
Pretending something is simple when it's not, is not doing anybody a favor.Okay, I bow to this reasoning, for the purpose of this patch. Let's
just lose the example.
Great.
Documenting everything that pg_basebackup does to make sure that the
backup is viable might be something to work on if someone is really
excited about this, but it's not 'dead-simple' and it's darn close to
the bare minimum, something that none of these simple scripts will come
anywhere close to being and instead they'll be far less than the
minimum.Yeah, having the full set of steps required documented certainly
wouldn't be a bad thing.I'd say that qualifies as an understatement. While it certainly doesn't
have to be part of this patch, if the claim is that an admin who relies
on pg_basebackup is relying on essential things pg_basebackup does that
have not been enumerated in our documentation yet, I would argue they
should be.
It doesn't have to be part of this patch and we should move forward with
this patch. Let's avoid hijacking this thread, which is about this
patch, for an independent debate about what our documentation should or
shouldn't include.
with a different API or a different set of tools. That is not a
documentation task. That is a "start from a list of which things
pg_basebackup cannot do that are still simple, or that tools like
pgbackrest cannot do if they're complicated". And then design an API
that's actually safe and easy to use *for that usecase*.That might also be a good thing, but I don't see it as a substitute
for documenting the present reality of what the irreducibly essential
behaviors of pg_basebackup (or of third-party tools like pgbackrest)
are, and why they are so.
I disagree. If we provided a tool then we'd document that tool and how
users can use it, not every single step that it does (see also:
pg_basebackup).
Thanks,
Stephen
On 03/09/22 12:19, Stephen Frost wrote:
Let's avoid hijacking this thread, which is about this
patch, for an independent debate about what our documentation should or
shouldn't include.
Agreed. New thread here:
/messages/by-id/6228FFE4.3050309@anastigmatix.net
Regards,
-Chap
On Wed, Mar 09, 2022 at 02:32:24PM -0500, Chapman Flack wrote:
On 03/09/22 12:19, Stephen Frost wrote:
Let's avoid hijacking this thread, which is about this
patch, for an independent debate about what our documentation should or
shouldn't include.Agreed. New thread here:
Great. Is there any additional feedback on this patch? Should we add an
example of using pg_basebackup in the "Standalone Hot Backups" section, or
should we leave all documentation additions like this for Chap's new
thread?
--
Nathan Bossart
Amazon Web Services: https://aws.amazon.com
On 03/09/22 17:21, Nathan Bossart wrote:
Great. Is there any additional feedback on this patch? Should we add an
example of using pg_basebackup in the "Standalone Hot Backups" section, or
should we leave all documentation additions like this for Chap's new
thread?
I'm composing something longer for the new thread, but on the way
I noticed something we might fit into this one.
I think the listitem
In the same connection as before, issue the command:
SELECT * FROM pg_backup_stop(true);
would be clearer if it used named-parameter form, wait_for_archive => true.
This is not strictly necessary, of course, for a function with a single
IN parameter, but it's good documentation (and also could save us headaches
like these if there is ever another future need to give it more parameters).
That listitem doesn't say anything about what the parameter means, which
is a little weird, but probably ok because the next listitem does go into
it in some detail. I don't think a larger reorg is needed to bring that
language one listitem earlier. Just naming the parameter is probably
enough to make it less puzzling (or adding in that listitem, at most,
"the effect of the wait_for_archive parameter is explained below").
For consistency (and the same futureproofing benefit), I'd go to
fast => false in the earlier pg_backup_start as well.
I'm more ambivalent about label => 'label'. It would be consistent,
but should we just agree for conciseness that there will always be
a label and it will always be first?
You can pretty much tell in a call what's a label; it's those anonymous
trues and falses that are easier to read with named notation.
Regards,
-Chap
On Wed, Mar 09, 2022 at 06:11:19PM -0500, Chapman Flack wrote:
I think the listitem
In the same connection as before, issue the command:
SELECT * FROM pg_backup_stop(true);would be clearer if it used named-parameter form, wait_for_archive => true.
This is not strictly necessary, of course, for a function with a single
IN parameter, but it's good documentation (and also could save us headaches
like these if there is ever another future need to give it more parameters).That listitem doesn't say anything about what the parameter means, which
is a little weird, but probably ok because the next listitem does go into
it in some detail. I don't think a larger reorg is needed to bring that
language one listitem earlier. Just naming the parameter is probably
enough to make it less puzzling (or adding in that listitem, at most,
"the effect of the wait_for_archive parameter is explained below").For consistency (and the same futureproofing benefit), I'd go to
fast => false in the earlier pg_backup_start as well.I'm more ambivalent about label => 'label'. It would be consistent,
but should we just agree for conciseness that there will always be
a label and it will always be first?You can pretty much tell in a call what's a label; it's those anonymous
trues and falses that are easier to read with named notation.
Done. I went ahead and added "label => 'label'" for consistency.
--
Nathan Bossart
Amazon Web Services: https://aws.amazon.com
Attachments:
v6-0001-remove-exclusive-backup-mode.patchtext/x-diff; charset=us-asciiDownload
From 904d5b9f77262fe0ea740de86ca41c7dbaf210ef Mon Sep 17 00:00:00 2001
From: Nathan Bossart <bossartn@amazon.com>
Date: Wed, 1 Dec 2021 23:50:49 +0000
Subject: [PATCH v6 1/1] remove exclusive backup mode
---
doc/src/sgml/backup.sgml | 222 +-------
doc/src/sgml/func.sgml | 99 +---
doc/src/sgml/high-availability.sgml | 6 +-
doc/src/sgml/monitoring.sgml | 4 +-
doc/src/sgml/ref/pgupgrade.sgml | 2 +-
src/backend/access/transam/xlog.c | 493 ++----------------
src/backend/access/transam/xlogfuncs.c | 253 ++-------
src/backend/access/transam/xlogrecovery.c | 2 +-
src/backend/catalog/system_functions.sql | 18 +-
src/backend/postmaster/postmaster.c | 46 +-
src/backend/replication/basebackup.c | 20 +-
src/bin/pg_basebackup/t/010_pg_basebackup.pl | 4 +
src/bin/pg_ctl/pg_ctl.c | 4 +-
src/bin/pg_rewind/filemap.c | 6 +-
src/include/access/xlog.h | 7 +-
src/include/catalog/pg_control.h | 2 +-
src/include/catalog/pg_proc.dat | 28 +-
src/include/miscadmin.h | 4 -
src/test/perl/PostgreSQL/Test/Cluster.pm | 56 +-
.../t/010_logical_decoding_timelines.pl | 4 +-
20 files changed, 189 insertions(+), 1091 deletions(-)
diff --git a/doc/src/sgml/backup.sgml b/doc/src/sgml/backup.sgml
index 0d69851bb1..c8b914c1aa 100644
--- a/doc/src/sgml/backup.sgml
+++ b/doc/src/sgml/backup.sgml
@@ -857,16 +857,8 @@ test ! -f /mnt/server/archivedir/00000001000000A900000065 && cp pg_wal/0
sequence, and that the success of a step is verified before
proceeding to the next step.
</para>
- <para>
- Low level base backups can be made in a non-exclusive or an exclusive
- way. The non-exclusive method is recommended and the exclusive one is
- deprecated and will eventually be removed.
- </para>
-
- <sect3 id="backup-lowlevel-base-backup-nonexclusive">
- <title>Making a Non-Exclusive Low-Level Backup</title>
<para>
- A non-exclusive low level backup is one that allows other
+ A low level backup allows other
concurrent backups to be running (both those started using
the same backup API and those started using
<xref linkend="app-pgbasebackup"/>).
@@ -881,19 +873,19 @@ test ! -f /mnt/server/archivedir/00000001000000A900000065 && cp pg_wal/0
<listitem>
<para>
Connect to the server (it does not matter which database) as a user with
- rights to run pg_start_backup (superuser, or a user who has been granted
+ rights to run pg_backup_start (superuser, or a user who has been granted
EXECUTE on the function) and issue the command:
<programlisting>
-SELECT pg_start_backup('label', false, false);
+SELECT pg_backup_start(label => 'label', fast => false);
</programlisting>
where <literal>label</literal> is any string you want to use to uniquely
identify this backup operation. The connection
- calling <function>pg_start_backup</function> must be maintained until the end of
+ calling <function>pg_backup_start</function> must be maintained until the end of
the backup, or the backup will be automatically aborted.
</para>
<para>
- By default, <function>pg_start_backup</function> can take a long time to finish.
+ By default, <function>pg_backup_start</function> can take a long time to finish.
This is because it performs a checkpoint, and the I/O
required for the checkpoint will be spread out over a significant
period of time, by default half your inter-checkpoint interval
@@ -905,10 +897,6 @@ SELECT pg_start_backup('label', false, false);
issue an immediate checkpoint using as much I/O as available.
</para>
- <para>
- The third parameter being <literal>false</literal> tells
- <function>pg_start_backup</function> to initiate a non-exclusive base backup.
- </para>
</listitem>
<listitem>
<para>
@@ -926,7 +914,7 @@ SELECT pg_start_backup('label', false, false);
<para>
In the same connection as before, issue the command:
<programlisting>
-SELECT * FROM pg_stop_backup(false, true);
+SELECT * FROM pg_backup_stop(wait_for_archive => true);
</programlisting>
This terminates backup mode. On a primary, it also performs an automatic
switch to the next WAL segment. On a standby, it is not possible to
@@ -937,7 +925,7 @@ SELECT * FROM pg_stop_backup(false, true);
ready to archive.
</para>
<para>
- The <function>pg_stop_backup</function> will return one row with three
+ The <function>pg_backup_stop</function> will return one row with three
values. The second of these fields should be written to a file named
<filename>backup_label</filename> in the root directory of the backup. The
third field should be written to a file named
@@ -949,14 +937,14 @@ SELECT * FROM pg_stop_backup(false, true);
<listitem>
<para>
Once the WAL segment files active during the backup are archived, you are
- done. The file identified by <function>pg_stop_backup</function>'s first return
+ done. The file identified by <function>pg_backup_stop</function>'s first return
value is the last segment that is required to form a complete set of
backup files. On a primary, if <varname>archive_mode</varname> is enabled and the
<literal>wait_for_archive</literal> parameter is <literal>true</literal>,
- <function>pg_stop_backup</function> does not return until the last segment has
+ <function>pg_backup_stop</function> does not return until the last segment has
been archived.
On a standby, <varname>archive_mode</varname> must be <literal>always</literal> in order
- for <function>pg_stop_backup</function> to wait.
+ for <function>pg_backup_stop</function> to wait.
Archiving of these files happens automatically since you have
already configured <varname>archive_library</varname>. In most cases this
happens quickly, but you are advised to monitor your archive
@@ -965,9 +953,9 @@ SELECT * FROM pg_stop_backup(false, true);
because of failures of the archive library, it will keep retrying
until the archive succeeds and the backup is complete.
If you wish to place a time limit on the execution of
- <function>pg_stop_backup</function>, set an appropriate
+ <function>pg_backup_stop</function>, set an appropriate
<varname>statement_timeout</varname> value, but make note that if
- <function>pg_stop_backup</function> terminates because of this your backup
+ <function>pg_backup_stop</function> terminates because of this your backup
may not be valid.
</para>
<para>
@@ -975,8 +963,8 @@ SELECT * FROM pg_stop_backup(false, true);
required for the backup are successfully archived then the
<literal>wait_for_archive</literal> parameter (which defaults to true) can be set
to false to have
- <function>pg_stop_backup</function> return as soon as the stop backup record is
- written to the WAL. By default, <function>pg_stop_backup</function> will wait
+ <function>pg_backup_stop</function> return as soon as the stop backup record is
+ written to the WAL. By default, <function>pg_backup_stop</function> will wait
until all WAL has been archived, which can take some time. This option
must be used with caution: if WAL archiving is not monitored correctly
then the backup might not include all of the WAL files and will
@@ -985,142 +973,6 @@ SELECT * FROM pg_stop_backup(false, true);
</listitem>
</orderedlist>
</para>
- </sect3>
- <sect3 id="backup-lowlevel-base-backup-exclusive">
- <title>Making an Exclusive Low-Level Backup</title>
-
- <note>
- <para>
- The exclusive backup method is deprecated and should be avoided.
- Prior to <productname>PostgreSQL</productname> 9.6, this was the only
- low-level method available, but it is now recommended that all users
- upgrade their scripts to use non-exclusive backups.
- </para>
- </note>
-
- <para>
- The process for an exclusive backup is mostly the same as for a
- non-exclusive one, but it differs in a few key steps. This type of
- backup can only be taken on a primary and does not allow concurrent
- backups. Moreover, because it creates a backup label file, as
- described below, it can block automatic restart of the primary server
- after a crash. On the other hand, the erroneous removal of this
- file from a backup or standby is a common mistake, which can result
- in serious data corruption. If it is necessary to use this method,
- the following steps may be used.
- </para>
- <para>
- <orderedlist>
- <listitem>
- <para>
- Ensure that WAL archiving is enabled and working.
- </para>
- </listitem>
- <listitem>
- <para>
- Connect to the server (it does not matter which database) as a user with
- rights to run pg_start_backup (superuser, or a user who has been granted
- EXECUTE on the function) and issue the command:
-<programlisting>
-SELECT pg_start_backup('label');
-</programlisting>
- where <literal>label</literal> is any string you want to use to uniquely
- identify this backup operation.
- <function>pg_start_backup</function> creates a <firstterm>backup label</firstterm> file,
- called <filename>backup_label</filename>, in the cluster directory with
- information about your backup, including the start time and label string.
- The function also creates a <firstterm>tablespace map</firstterm> file,
- called <filename>tablespace_map</filename>, in the cluster directory with
- information about tablespace symbolic links in <filename>pg_tblspc/</filename> if
- one or more such link is present. Both files are critical to the
- integrity of the backup, should you need to restore from it.
- </para>
-
- <para>
- By default, <function>pg_start_backup</function> can take a long time to finish.
- This is because it performs a checkpoint, and the I/O
- required for the checkpoint will be spread out over a significant
- period of time, by default half your inter-checkpoint interval
- (see the configuration parameter
- <xref linkend="guc-checkpoint-completion-target"/>). This is
- usually what you want, because it minimizes the impact on query
- processing. If you want to start the backup as soon as
- possible, use:
-<programlisting>
-SELECT pg_start_backup('label', true);
-</programlisting>
- This forces the checkpoint to be done as quickly as possible.
- </para>
- </listitem>
- <listitem>
- <para>
- Perform the backup, using any convenient file-system-backup tool
- such as <application>tar</application> or <application>cpio</application> (not
- <application>pg_dump</application> or
- <application>pg_dumpall</application>). It is neither
- necessary nor desirable to stop normal operation of the database
- while you do this. See
- <xref linkend="backup-lowlevel-base-backup-data"/> for things to
- consider during this backup.
- </para>
- <para>
- As noted above, if the server crashes during the backup it may not be
- possible to restart until the <filename>backup_label</filename> file has
- been manually deleted from the <envar>PGDATA</envar> directory. Note
- that it is very important to never remove the
- <filename>backup_label</filename> file when restoring a backup, because
- this will result in corruption. Confusion about when it is appropriate
- to remove this file is a common cause of data corruption when using this
- method; be very certain that you remove the file only on an existing
- primary and never when building a standby or restoring a backup, even if
- you are building a standby that will subsequently be promoted to a new
- primary.
- </para>
- </listitem>
- <listitem>
- <para>
- Again connect to the database as a user with rights to run
- pg_stop_backup (superuser, or a user who has been granted EXECUTE on
- the function), and issue the command:
-<programlisting>
-SELECT pg_stop_backup();
-</programlisting>
- This function terminates backup mode and
- performs an automatic switch to the next WAL segment. The reason for the
- switch is to arrange for the last WAL segment written during the backup
- interval to be ready to archive.
- </para>
- </listitem>
- <listitem>
- <para>
- Once the WAL segment files active during the backup are archived, you are
- done. The file identified by <function>pg_stop_backup</function>'s result is
- the last segment that is required to form a complete set of backup files.
- If <varname>archive_mode</varname> is enabled,
- <function>pg_stop_backup</function> does not return until the last segment has
- been archived.
- Archiving of these files happens automatically since you have
- already configured <varname>archive_command</varname>. In most cases this
- happens quickly, but you are advised to monitor your archive
- system to ensure there are no delays.
- If the archive process has fallen behind
- because of failures of the archive command, it will keep retrying
- until the archive succeeds and the backup is complete.
- </para>
-
- <para>
- When using exclusive backup mode, it is absolutely imperative to ensure
- that <function>pg_stop_backup</function> completes successfully at the
- end of the backup. Even if the backup itself fails, for example due to
- lack of disk space, failure to call <function>pg_stop_backup</function>
- will leave the server in backup mode indefinitely, causing future backups
- to fail and increasing the risk of a restart failure during the time that
- <filename>backup_label</filename> exists.
- </para>
- </listitem>
- </orderedlist>
- </para>
- </sect3>
<sect3 id="backup-lowlevel-base-backup-data">
<title>Backing Up the Data Directory</title>
<para>
@@ -1203,8 +1055,8 @@ SELECT pg_stop_backup();
<para>
The backup label
- file includes the label string you gave to <function>pg_start_backup</function>,
- as well as the time at which <function>pg_start_backup</function> was run, and
+ file includes the label string you gave to <function>pg_backup_start</function>,
+ as well as the time at which <function>pg_backup_start</function> was run, and
the name of the starting WAL file. In case of confusion it is therefore
possible to look inside a backup file and determine exactly which
backup session the dump file came from. The tablespace map file includes
@@ -1218,7 +1070,7 @@ SELECT pg_stop_backup();
<para>
It is also possible to make a backup while the server is
stopped. In this case, you obviously cannot use
- <function>pg_start_backup</function> or <function>pg_stop_backup</function>, and
+ <function>pg_backup_start</function> or <function>pg_backup_stop</function>, and
you will therefore be left to your own devices to keep track of which
backup is which and how far back the associated WAL files go.
It is generally better to follow the continuous archiving procedure above.
@@ -1393,7 +1245,7 @@ restore_command = 'cp /mnt/server/archivedir/%f %p'
<note>
<para>
The stop point must be after the ending time of the base backup, i.e.,
- the end time of <function>pg_stop_backup</function>. You cannot use a base backup
+ the end time of <function>pg_backup_stop</function>. You cannot use a base backup
to recover to a time when that backup was in progress. (To
recover to such a time, you must go back to your previous base backup
and roll forward from there.)
@@ -1513,44 +1365,6 @@ restore_command = 'cp /mnt/server/archivedir/%f %p'
included in the backup automatically, and no special action is
required to restore the backup.
</para>
-
- <para>
- If more flexibility in copying the backup files is needed, a lower
- level process can be used for standalone hot backups as well.
- To prepare for low level standalone hot backups, make sure
- <varname>wal_level</varname> is set to
- <literal>replica</literal> or higher, <varname>archive_mode</varname> to
- <literal>on</literal>, and set up an <varname>archive_library</varname> that performs
- archiving only when a <emphasis>switch file</emphasis> exists. For example:
-<programlisting>
-archive_library = '' # use shell command
-archive_command = 'test ! -f /var/lib/pgsql/backup_in_progress || (test ! -f /var/lib/pgsql/archive/%f && cp %p /var/lib/pgsql/archive/%f)'
-</programlisting>
- This command will perform archiving when
- <filename>/var/lib/pgsql/backup_in_progress</filename> exists, and otherwise
- silently return zero exit status (allowing <productname>PostgreSQL</productname>
- to recycle the unwanted WAL file).
- </para>
-
- <para>
- With this preparation, a backup can be taken using a script like the
- following:
-<programlisting>
-touch /var/lib/pgsql/backup_in_progress
-psql -c "select pg_start_backup('hot_backup');"
-tar -cf /var/lib/pgsql/backup.tar /var/lib/pgsql/data/
-psql -c "select pg_stop_backup();"
-rm /var/lib/pgsql/backup_in_progress
-tar -rf /var/lib/pgsql/backup.tar /var/lib/pgsql/archive/
-</programlisting>
- The switch file <filename>/var/lib/pgsql/backup_in_progress</filename> is
- created first, enabling archiving of completed WAL files to occur.
- After the backup the switch file is removed. Archived WAL files are
- then added to the backup so that both base backup and all required
- WAL files are part of the same <application>tar</application> file.
- Please remember to add error handling to your backup scripts.
- </para>
-
</sect3>
<sect3 id="compressed-archive-logs">
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 8a802fb225..8790c07fac 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -25587,9 +25587,8 @@ LOG: Grand total: 1651920 bytes in 201 blocks; 622360 free (88 chunks); 1029560
The functions shown in <xref
linkend="functions-admin-backup-table"/> assist in making on-line backups.
These functions cannot be executed during recovery (except
- non-exclusive <function>pg_start_backup</function>,
- non-exclusive <function>pg_stop_backup</function>,
- <function>pg_is_in_backup</function>, <function>pg_backup_start_time</function>
+ <function>pg_backup_start</function>,
+ <function>pg_backup_stop</function>,
and <function>pg_wal_lsn_diff</function>).
</para>
@@ -25678,13 +25677,12 @@ LOG: Grand total: 1651920 bytes in 201 blocks; 622360 free (88 chunks); 1029560
<row>
<entry role="func_table_entry"><para role="func_signature">
<indexterm>
- <primary>pg_start_backup</primary>
+ <primary>pg_backup_start</primary>
</indexterm>
- <function>pg_start_backup</function> (
+ <function>pg_backup_start</function> (
<parameter>label</parameter> <type>text</type>
<optional>, <parameter>fast</parameter> <type>boolean</type>
- <optional>, <parameter>exclusive</parameter> <type>boolean</type>
- </optional></optional> )
+ </optional> )
<returnvalue>pg_lsn</returnvalue>
</para>
<para>
@@ -25693,23 +25691,9 @@ LOG: Grand total: 1651920 bytes in 201 blocks; 622360 free (88 chunks); 1029560
(Typically this would be the name under which the backup dump file
will be stored.)
If the optional second parameter is given as <literal>true</literal>,
- it specifies executing <function>pg_start_backup</function> as quickly
+ it specifies executing <function>pg_backup_start</function> as quickly
as possible. This forces an immediate checkpoint which will cause a
spike in I/O operations, slowing any concurrently executing queries.
- The optional third parameter specifies whether to perform an exclusive
- or non-exclusive backup (default is exclusive).
- </para>
- <para>
- When used in exclusive mode, this function writes a backup label file
- (<filename>backup_label</filename>) and, if there are any links in
- the <filename>pg_tblspc/</filename> directory, a tablespace map file
- (<filename>tablespace_map</filename>) into the database cluster's data
- directory, then performs a checkpoint, and then returns the backup's
- starting write-ahead log location. (The user can ignore this
- result value, but it is provided in case it is useful.) When used in
- non-exclusive mode, the contents of these files are instead returned
- by the <function>pg_stop_backup</function> function, and should be
- copied to the backup area by the user.
</para>
<para>
This function is restricted to superusers by default, but other users
@@ -25720,11 +25704,10 @@ LOG: Grand total: 1651920 bytes in 201 blocks; 622360 free (88 chunks); 1029560
<row>
<entry role="func_table_entry"><para role="func_signature">
<indexterm>
- <primary>pg_stop_backup</primary>
+ <primary>pg_backup_stop</primary>
</indexterm>
- <function>pg_stop_backup</function> (
- <parameter>exclusive</parameter> <type>boolean</type>
- <optional>, <parameter>wait_for_archive</parameter> <type>boolean</type>
+ <function>pg_backup_stop</function> (
+ <optional><parameter>wait_for_archive</parameter> <type>boolean</type>
</optional> )
<returnvalue>record</returnvalue>
( <parameter>lsn</parameter> <type>pg_lsn</type>,
@@ -25732,24 +25715,19 @@ LOG: Grand total: 1651920 bytes in 201 blocks; 622360 free (88 chunks); 1029560
<parameter>spcmapfile</parameter> <type>text</type> )
</para>
<para>
- Finishes performing an exclusive or non-exclusive on-line backup.
- The <parameter>exclusive</parameter> parameter must match the
- previous <function>pg_start_backup</function> call.
- In an exclusive backup, <function>pg_stop_backup</function> removes
- the backup label file and, if it exists, the tablespace map file
- created by <function>pg_start_backup</function>. In a non-exclusive
- backup, the desired contents of these files are returned as part of
+ Finishes performing an on-line backup. The desired contents of the
+ backup label file and the tablespace map file are returned as part of
the result of the function, and should be written to files in the
backup area (not in the data directory).
</para>
<para>
- There is an optional second parameter of type <type>boolean</type>.
+ There is an optional parameter of type <type>boolean</type>.
If false, the function will return immediately after the backup is
completed, without waiting for WAL to be archived. This behavior is
only useful with backup software that independently monitors WAL
archiving. Otherwise, WAL required to make the backup consistent might
be missing and make the backup useless. By default or when this
- parameter is true, <function>pg_stop_backup</function> will wait for
+ parameter is true, <function>pg_backup_stop</function> will wait for
WAL to be archived when archiving is enabled. (On a standby, this
means that it will wait only when <varname>archive_mode</varname> =
<literal>always</literal>. If write activity on the primary is low,
@@ -25759,7 +25737,7 @@ LOG: Grand total: 1651920 bytes in 201 blocks; 622360 free (88 chunks); 1029560
<para>
When executed on a primary, this function also creates a backup
history file in the write-ahead log archive area. The history file
- includes the label given to <function>pg_start_backup</function>, the
+ includes the label given to <function>pg_backup_start</function>, the
starting and ending write-ahead log locations for the backup, and the
starting and ending times of the backup. After recording the ending
location, the current write-ahead log insertion point is automatically
@@ -25771,8 +25749,7 @@ LOG: Grand total: 1651920 bytes in 201 blocks; 622360 free (88 chunks); 1029560
The result of the function is a single record.
The <parameter>lsn</parameter> column holds the backup's ending
write-ahead log location (which again can be ignored). The second and
- third columns are <literal>NULL</literal> when ending an exclusive
- backup; after a non-exclusive backup they hold the desired contents of
+ third columns hold the desired contents of
the label and tablespace map files.
</para>
<para>
@@ -25781,50 +25758,6 @@ LOG: Grand total: 1651920 bytes in 201 blocks; 622360 free (88 chunks); 1029560
</para></entry>
</row>
- <row>
- <entry role="func_table_entry"><para role="func_signature">
- <function>pg_stop_backup</function> ()
- <returnvalue>pg_lsn</returnvalue>
- </para>
- <para>
- Finishes performing an exclusive on-line backup. This simplified
- version is equivalent to <literal>pg_stop_backup(true,
- true)</literal>, except that it only returns the <type>pg_lsn</type>
- result.
- </para>
- <para>
- This function is restricted to superusers by default, but other users
- can be granted EXECUTE to run the function.
- </para></entry>
- </row>
-
- <row>
- <entry role="func_table_entry"><para role="func_signature">
- <indexterm>
- <primary>pg_is_in_backup</primary>
- </indexterm>
- <function>pg_is_in_backup</function> ()
- <returnvalue>boolean</returnvalue>
- </para>
- <para>
- Returns true if an on-line exclusive backup is in progress.
- </para></entry>
- </row>
-
- <row>
- <entry role="func_table_entry"><para role="func_signature">
- <indexterm>
- <primary>pg_backup_start_time</primary>
- </indexterm>
- <function>pg_backup_start_time</function> ()
- <returnvalue>timestamp with time zone</returnvalue>
- </para>
- <para>
- Returns the start time of the current on-line exclusive backup if one
- is in progress, otherwise <literal>NULL</literal>.
- </para></entry>
- </row>
-
<row>
<entry role="func_table_entry"><para role="func_signature">
<indexterm>
@@ -25922,7 +25855,7 @@ LOG: Grand total: 1651920 bytes in 201 blocks; 622360 free (88 chunks); 1029560
corresponding write-ahead log file name and byte offset from
a <type>pg_lsn</type> value. For example:
<programlisting>
-postgres=# SELECT * FROM pg_walfile_name_offset(pg_stop_backup());
+postgres=# SELECT * FROM pg_walfile_name_offset(pg_backup_stop());
file_name | file_offset
--------------------------+-------------
00000001000000000000000D | 4039624
diff --git a/doc/src/sgml/high-availability.sgml b/doc/src/sgml/high-availability.sgml
index b5b6042104..1f0ba66943 100644
--- a/doc/src/sgml/high-availability.sgml
+++ b/doc/src/sgml/high-availability.sgml
@@ -1361,8 +1361,8 @@ synchronous_standby_names = 'ANY 2 (s1, s2, s3)'
<para>
If you need to re-create a standby server while transactions are
- waiting, make sure that the commands pg_start_backup() and
- pg_stop_backup() are run in a session with
+ waiting, make sure that the commands pg_backup_start() and
+ pg_backup_stop() are run in a session with
<varname>synchronous_commit</varname> = <literal>off</literal>, otherwise those
requests will wait forever for the standby to appear.
</para>
@@ -2159,7 +2159,7 @@ HINT: You can then restart the server after making the necessary configuration
<para>
WAL file control commands will not work during recovery,
- e.g., <function>pg_start_backup</function>, <function>pg_switch_wal</function> etc.
+ e.g., <function>pg_backup_start</function>, <function>pg_switch_wal</function> etc.
</para>
<para>
diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
index 9fb62fec8e..0320ce7078 100644
--- a/doc/src/sgml/monitoring.sgml
+++ b/doc/src/sgml/monitoring.sgml
@@ -6661,7 +6661,7 @@ SELECT pg_stat_get_backend_pid(s.backendid) AS pid,
<entry><literal>waiting for checkpoint to finish</literal></entry>
<entry>
The WAL sender process is currently performing
- <function>pg_start_backup</function> to prepare to
+ <function>pg_backup_start</function> to prepare to
take a base backup, and waiting for the start-of-backup
checkpoint to finish.
</entry>
@@ -6684,7 +6684,7 @@ SELECT pg_stat_get_backend_pid(s.backendid) AS pid,
<entry><literal>waiting for wal archiving to finish</literal></entry>
<entry>
The WAL sender process is currently performing
- <function>pg_stop_backup</function> to finish the backup,
+ <function>pg_backup_stop</function> to finish the backup,
and waiting for all the WAL files required for the base backup
to be successfully archived.
If either <literal>--wal-method=none</literal> or
diff --git a/doc/src/sgml/ref/pgupgrade.sgml b/doc/src/sgml/ref/pgupgrade.sgml
index 729c886ac0..3fbe141456 100644
--- a/doc/src/sgml/ref/pgupgrade.sgml
+++ b/doc/src/sgml/ref/pgupgrade.sgml
@@ -618,7 +618,7 @@ rsync --archive --delete --hard-links --size-only --no-inc-recursive /vol1/pg_tb
<para>
Configure the servers for log shipping. (You do not need to run
- <function>pg_start_backup()</function> and <function>pg_stop_backup()</function>
+ <function>pg_backup_start()</function> and <function>pg_backup_stop()</function>
or take a file system backup as the standbys are still synchronized
with the primary.)
</para>
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 0d2bd7a357..d5032118d3 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -384,29 +384,6 @@ typedef union WALInsertLockPadded
char pad[PG_CACHE_LINE_SIZE];
} WALInsertLockPadded;
-/*
- * State of an exclusive backup, necessary to control concurrent activities
- * across sessions when working on exclusive backups.
- *
- * EXCLUSIVE_BACKUP_NONE means that there is no exclusive backup actually
- * running, to be more precise pg_start_backup() is not being executed for
- * an exclusive backup and there is no exclusive backup in progress.
- * EXCLUSIVE_BACKUP_STARTING means that pg_start_backup() is starting an
- * exclusive backup.
- * EXCLUSIVE_BACKUP_IN_PROGRESS means that pg_start_backup() has finished
- * running and an exclusive backup is in progress. pg_stop_backup() is
- * needed to finish it.
- * EXCLUSIVE_BACKUP_STOPPING means that pg_stop_backup() is stopping an
- * exclusive backup.
- */
-typedef enum ExclusiveBackupState
-{
- EXCLUSIVE_BACKUP_NONE = 0,
- EXCLUSIVE_BACKUP_STARTING,
- EXCLUSIVE_BACKUP_IN_PROGRESS,
- EXCLUSIVE_BACKUP_STOPPING
-} ExclusiveBackupState;
-
/*
* Session status of running backup, used for sanity checks in SQL-callable
* functions to start and stop backups.
@@ -455,15 +432,12 @@ typedef struct XLogCtlInsert
bool fullPageWrites;
/*
- * exclusiveBackupState indicates the state of an exclusive backup (see
- * comments of ExclusiveBackupState for more details). nonExclusiveBackups
- * is a counter indicating the number of streaming base backups currently
- * in progress. forcePageWrites is set to true when either of these is
- * non-zero. lastBackupStart is the latest checkpoint redo location used
- * as a starting point for an online backup.
+ * runningBackups is a counter indicating the number of backups currently in
+ * progress. forcePageWrites is set to true when runningBackups is non-zero.
+ * lastBackupStart is the latest checkpoint redo location used as a starting
+ * point for an online backup.
*/
- ExclusiveBackupState exclusiveBackupState;
- int nonExclusiveBackups;
+ int runningBackups;
XLogRecPtr lastBackupStart;
/*
@@ -695,8 +669,7 @@ static void ReadControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow);
-static void pg_start_backup_callback(int code, Datum arg);
-static void pg_stop_backup_callback(int code, Datum arg);
+static void pg_backup_start_callback(int code, Datum arg);
static int get_sync_bit(int method);
@@ -5313,7 +5286,7 @@ StartupXLOG(void)
* Ran off end of WAL before reaching end-of-backup WAL record, or
* minRecoveryPoint. That's usually a bad sign, indicating that you
* tried to recover from an online backup but never called
- * pg_stop_backup(), or you didn't archive all the WAL up to that
+ * pg_backup_stop(), or you didn't archive all the WAL up to that
* point. However, this also happens in crash recovery, if the system
* crashes while an online backup is in progress. We must not treat
* that as an error, or the database will refuse to start up.
@@ -5327,7 +5300,7 @@ StartupXLOG(void)
else if (!XLogRecPtrIsInvalid(ControlFile->backupStartPoint))
ereport(FATAL,
(errmsg("WAL ends before end of online backup"),
- errhint("Online backup started with pg_start_backup() must be ended with pg_stop_backup(), and all WAL up to that point must be available at recovery.")));
+ errhint("Online backup started with pg_backup_start() must be ended with pg_backup_stop(), and all WAL up to that point must be available at recovery.")));
else
ereport(FATAL,
(errmsg("WAL ends before consistent recovery point")));
@@ -7008,7 +6981,7 @@ CreateRestartPoint(int flags)
* Ensure minRecoveryPoint is past the checkpoint record. Normally,
* this will have happened already while writing out dirty buffers,
* but not necessarily - e.g. because no buffers were dirtied. We do
- * this because a non-exclusive base backup uses minRecoveryPoint to
+ * this because a backup performed in recovery uses minRecoveryPoint to
* determine which WAL files must be included in the backup, and the
* file (or files) containing the checkpoint record must be included,
* at a minimum. Note that for an ordinary restart of recovery there's
@@ -7812,7 +7785,7 @@ xlog_redo(XLogReaderState *record)
/*
* Update the LSN of the last replayed XLOG_FPW_CHANGE record so that
- * do_pg_start_backup() and do_pg_stop_backup() can check whether
+ * do_pg_backup_start() and do_pg_backup_stop() can check whether
* full_page_writes has been disabled during online backup.
*/
if (!fpw)
@@ -8011,29 +7984,14 @@ issue_xlog_fsync(int fd, XLogSegNo segno, TimeLineID tli)
}
/*
- * do_pg_start_backup
- *
- * Utility function called at the start of an online backup. It creates the
- * necessary starting checkpoint and constructs the backup label file.
- *
- * There are two kind of backups: exclusive and non-exclusive. An exclusive
- * backup is started with pg_start_backup(), and there can be only one active
- * at a time. The backup and tablespace map files of an exclusive backup are
- * written to $PGDATA/backup_label and $PGDATA/tablespace_map, and they are
- * removed by pg_stop_backup().
- *
- * A non-exclusive backup is used for the streaming base backups (see
- * src/backend/replication/basebackup.c). The difference to exclusive backups
- * is that the backup label and tablespace map files are not written to disk.
- * Instead, their would-be contents are returned in *labelfile and *tblspcmapfile,
- * and the caller is responsible for including them in the backup archive as
- * 'backup_label' and 'tablespace_map'. There can be many non-exclusive backups
- * active at the same time, and they don't conflict with an exclusive backup
- * either.
- *
- * labelfile and tblspcmapfile must be passed as NULL when starting an
- * exclusive backup, and as initially-empty StringInfos for a non-exclusive
- * backup.
+ * do_pg_backup_start is the workhorse of the user-visible pg_backup_start()
+ * function. It creates the necessary starting checkpoint and constructs the
+ * backup label and tablespace map.
+ *
+ * The backup label and tablespace map contents are returned in *labelfile and
+ * *tblspcmapfile, and the caller is responsible for including them in the
+ * backup archive as 'backup_label' and 'tablespace_map'. There can be many
+ * backups active at the same time.
*
* If "tablespaces" isn't NULL, it receives a list of tablespaceinfo structs
* describing the cluster's tablespaces.
@@ -8045,18 +8003,17 @@ issue_xlog_fsync(int fd, XLogSegNo segno, TimeLineID tli)
* Returns the minimum WAL location that must be present to restore from this
* backup, and the corresponding timeline ID in *starttli_p.
*
- * Every successfully started non-exclusive backup must be stopped by calling
- * do_pg_stop_backup() or do_pg_abort_backup().
+ * Every successfully started backup must be stopped by calling
+ * do_pg_backup_stop() or do_pg_abort_backup().
*
* It is the responsibility of the caller of this function to verify the
* permissions of the calling user!
*/
XLogRecPtr
-do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
+do_pg_backup_start(const char *backupidstr, bool fast, TimeLineID *starttli_p,
StringInfo labelfile, List **tablespaces,
StringInfo tblspcmapfile)
{
- bool exclusive = (labelfile == NULL);
bool backup_started_in_recovery = false;
XLogRecPtr checkpointloc;
XLogRecPtr startpoint;
@@ -8065,20 +8022,9 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
char strfbuf[128];
char xlogfilename[MAXFNAMELEN];
XLogSegNo _logSegNo;
- struct stat stat_buf;
- FILE *fp;
backup_started_in_recovery = RecoveryInProgress();
- /*
- * Currently only non-exclusive backup can be taken during recovery.
- */
- if (backup_started_in_recovery && exclusive)
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("recovery is in progress"),
- errhint("WAL control functions cannot be executed during recovery.")));
-
/*
* During recovery, we don't need to check WAL level. Because, if WAL
* level is not sufficient, it's impossible to get here during recovery.
@@ -8117,30 +8063,12 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
* XLogInsertRecord().
*/
WALInsertLockAcquireExclusive();
- if (exclusive)
- {
- /*
- * At first, mark that we're now starting an exclusive backup, to
- * ensure that there are no other sessions currently running
- * pg_start_backup() or pg_stop_backup().
- */
- if (XLogCtl->Insert.exclusiveBackupState != EXCLUSIVE_BACKUP_NONE)
- {
- WALInsertLockRelease();
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("a backup is already in progress"),
- errhint("Run pg_stop_backup() and try again.")));
- }
- XLogCtl->Insert.exclusiveBackupState = EXCLUSIVE_BACKUP_STARTING;
- }
- else
- XLogCtl->Insert.nonExclusiveBackups++;
+ XLogCtl->Insert.runningBackups++;
XLogCtl->Insert.forcePageWrites = true;
WALInsertLockRelease();
/* Ensure we release forcePageWrites if fail below */
- PG_ENSURE_ERROR_CLEANUP(pg_start_backup_callback, (Datum) BoolGetDatum(exclusive));
+ PG_ENSURE_ERROR_CLEANUP(pg_backup_start_callback, (Datum) 0);
{
bool gotUniqueStartpoint = false;
DIR *tblspcdir;
@@ -8152,7 +8080,7 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
* Force an XLOG file switch before the checkpoint, to ensure that the
* WAL segment the checkpoint is written to doesn't contain pages with
* old timeline IDs. That would otherwise happen if you called
- * pg_start_backup() right after restoring from a PITR archive: the
+ * pg_backup_start() right after restoring from a PITR archive: the
* first WAL segment containing the startup checkpoint has pages in
* the beginning with the old timeline ID. That can cause trouble at
* recovery: we won't have a history file covering the old timeline if
@@ -8187,7 +8115,7 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
* means that two successive backup runs can have same checkpoint
* positions.
*
- * Since the fact that we are executing do_pg_start_backup()
+ * Since the fact that we are executing do_pg_backup_start()
* during recovery means that checkpointer is running, we can use
* RequestCheckpoint() to establish a restartpoint.
*
@@ -8375,122 +8303,19 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
LSN_FORMAT_ARGS(startpoint), xlogfilename);
appendStringInfo(labelfile, "CHECKPOINT LOCATION: %X/%X\n",
LSN_FORMAT_ARGS(checkpointloc));
- appendStringInfo(labelfile, "BACKUP METHOD: %s\n",
- exclusive ? "pg_start_backup" : "streamed");
+ appendStringInfo(labelfile, "BACKUP METHOD: streamed\n");
appendStringInfo(labelfile, "BACKUP FROM: %s\n",
backup_started_in_recovery ? "standby" : "primary");
appendStringInfo(labelfile, "START TIME: %s\n", strfbuf);
appendStringInfo(labelfile, "LABEL: %s\n", backupidstr);
appendStringInfo(labelfile, "START TIMELINE: %u\n", starttli);
-
- /*
- * Okay, write the file, or return its contents to caller.
- */
- if (exclusive)
- {
- /*
- * Check for existing backup label --- implies a backup is already
- * running. (XXX given that we checked exclusiveBackupState
- * above, maybe it would be OK to just unlink any such label
- * file?)
- */
- if (stat(BACKUP_LABEL_FILE, &stat_buf) != 0)
- {
- if (errno != ENOENT)
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not stat file \"%s\": %m",
- BACKUP_LABEL_FILE)));
- }
- else
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("a backup is already in progress"),
- errhint("If you're sure there is no backup in progress, remove file \"%s\" and try again.",
- BACKUP_LABEL_FILE)));
-
- fp = AllocateFile(BACKUP_LABEL_FILE, "w");
-
- if (!fp)
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not create file \"%s\": %m",
- BACKUP_LABEL_FILE)));
- if (fwrite(labelfile->data, labelfile->len, 1, fp) != 1 ||
- fflush(fp) != 0 ||
- pg_fsync(fileno(fp)) != 0 ||
- ferror(fp) ||
- FreeFile(fp))
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not write file \"%s\": %m",
- BACKUP_LABEL_FILE)));
- /* Allocated locally for exclusive backups, so free separately */
- pfree(labelfile->data);
- pfree(labelfile);
-
- /* Write backup tablespace_map file. */
- if (tblspcmapfile->len > 0)
- {
- if (stat(TABLESPACE_MAP, &stat_buf) != 0)
- {
- if (errno != ENOENT)
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not stat file \"%s\": %m",
- TABLESPACE_MAP)));
- }
- else
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("a backup is already in progress"),
- errhint("If you're sure there is no backup in progress, remove file \"%s\" and try again.",
- TABLESPACE_MAP)));
-
- fp = AllocateFile(TABLESPACE_MAP, "w");
-
- if (!fp)
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not create file \"%s\": %m",
- TABLESPACE_MAP)));
- if (fwrite(tblspcmapfile->data, tblspcmapfile->len, 1, fp) != 1 ||
- fflush(fp) != 0 ||
- pg_fsync(fileno(fp)) != 0 ||
- ferror(fp) ||
- FreeFile(fp))
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not write file \"%s\": %m",
- TABLESPACE_MAP)));
- }
-
- /* Allocated locally for exclusive backups, so free separately */
- pfree(tblspcmapfile->data);
- pfree(tblspcmapfile);
- }
}
- PG_END_ENSURE_ERROR_CLEANUP(pg_start_backup_callback, (Datum) BoolGetDatum(exclusive));
+ PG_END_ENSURE_ERROR_CLEANUP(pg_backup_start_callback, (Datum) 0);
/*
- * Mark that start phase has correctly finished for an exclusive backup.
- * Session-level locks are updated as well to reflect that state.
- *
- * Note that CHECK_FOR_INTERRUPTS() must not occur while updating backup
- * counters and session-level lock. Otherwise they can be updated
- * inconsistently, and which might cause do_pg_abort_backup() to fail.
+ * Mark that the start phase has correctly finished for the backup.
*/
- if (exclusive)
- {
- WALInsertLockAcquireExclusive();
- XLogCtl->Insert.exclusiveBackupState = EXCLUSIVE_BACKUP_IN_PROGRESS;
-
- /* Set session-level lock */
- sessionBackupState = SESSION_BACKUP_EXCLUSIVE;
- WALInsertLockRelease();
- }
- else
- sessionBackupState = SESSION_BACKUP_NON_EXCLUSIVE;
+ sessionBackupState = SESSION_BACKUP_RUNNING;
/*
* We're done. As a convenience, return the starting WAL location.
@@ -8500,47 +8325,19 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
return startpoint;
}
-/* Error cleanup callback for pg_start_backup */
+/* Error cleanup callback for pg_backup_start */
static void
-pg_start_backup_callback(int code, Datum arg)
+pg_backup_start_callback(int code, Datum arg)
{
- bool exclusive = DatumGetBool(arg);
-
/* Update backup counters and forcePageWrites on failure */
WALInsertLockAcquireExclusive();
- if (exclusive)
- {
- Assert(XLogCtl->Insert.exclusiveBackupState == EXCLUSIVE_BACKUP_STARTING);
- XLogCtl->Insert.exclusiveBackupState = EXCLUSIVE_BACKUP_NONE;
- }
- else
- {
- Assert(XLogCtl->Insert.nonExclusiveBackups > 0);
- XLogCtl->Insert.nonExclusiveBackups--;
- }
- if (XLogCtl->Insert.exclusiveBackupState == EXCLUSIVE_BACKUP_NONE &&
- XLogCtl->Insert.nonExclusiveBackups == 0)
- {
- XLogCtl->Insert.forcePageWrites = false;
- }
- WALInsertLockRelease();
-}
+ Assert(XLogCtl->Insert.runningBackups > 0);
+ XLogCtl->Insert.runningBackups--;
-/*
- * Error cleanup callback for pg_stop_backup
- */
-static void
-pg_stop_backup_callback(int code, Datum arg)
-{
- bool exclusive = DatumGetBool(arg);
-
- /* Update backup status on failure */
- WALInsertLockAcquireExclusive();
- if (exclusive)
+ if (XLogCtl->Insert.runningBackups == 0)
{
- Assert(XLogCtl->Insert.exclusiveBackupState == EXCLUSIVE_BACKUP_STOPPING);
- XLogCtl->Insert.exclusiveBackupState = EXCLUSIVE_BACKUP_IN_PROGRESS;
+ XLogCtl->Insert.forcePageWrites = false;
}
WALInsertLockRelease();
}
@@ -8555,14 +8352,11 @@ get_backup_status(void)
}
/*
- * do_pg_stop_backup
+ * do_pg_backup_stop
*
* Utility function called at the end of an online backup. It cleans up the
* backup state and can optionally wait for WAL segments to be archived.
*
- * If labelfile is NULL, this stops an exclusive backup. Otherwise this stops
- * the non-exclusive backup specified by 'labelfile'.
- *
* Returns the last WAL location that must be present to restore from this
* backup, and the corresponding timeline ID in *stoptli_p.
*
@@ -8570,9 +8364,8 @@ get_backup_status(void)
* permissions of the calling user!
*/
XLogRecPtr
-do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
+do_pg_backup_stop(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
{
- bool exclusive = (labelfile == NULL);
bool backup_started_in_recovery = false;
XLogRecPtr startpoint;
XLogRecPtr stoppoint;
@@ -8586,7 +8379,6 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
char histfilename[MAXFNAMELEN];
char backupfrom[20];
XLogSegNo _logSegNo;
- FILE *lfp;
FILE *fp;
char ch;
int seconds_before_warning;
@@ -8599,15 +8391,6 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
backup_started_in_recovery = RecoveryInProgress();
- /*
- * Currently only non-exclusive backup can be taken during recovery.
- */
- if (backup_started_in_recovery && exclusive)
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("recovery is in progress"),
- errhint("WAL control functions cannot be executed during recovery.")));
-
/*
* During recovery, we don't need to check WAL level. Because, if WAL
* level is not sufficient, it's impossible to get here during recovery.
@@ -8618,106 +8401,23 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
errmsg("WAL level not sufficient for making an online backup"),
errhint("wal_level must be set to \"replica\" or \"logical\" at server start.")));
- if (exclusive)
- {
- /*
- * At first, mark that we're now stopping an exclusive backup, to
- * ensure that there are no other sessions currently running
- * pg_start_backup() or pg_stop_backup().
- */
- WALInsertLockAcquireExclusive();
- if (XLogCtl->Insert.exclusiveBackupState != EXCLUSIVE_BACKUP_IN_PROGRESS)
- {
- WALInsertLockRelease();
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("exclusive backup not in progress")));
- }
- XLogCtl->Insert.exclusiveBackupState = EXCLUSIVE_BACKUP_STOPPING;
- WALInsertLockRelease();
-
- /*
- * Remove backup_label. In case of failure, the state for an exclusive
- * backup is switched back to in-progress.
- */
- PG_ENSURE_ERROR_CLEANUP(pg_stop_backup_callback, (Datum) BoolGetDatum(exclusive));
- {
- /*
- * Read the existing label file into memory.
- */
- struct stat statbuf;
- int r;
-
- if (stat(BACKUP_LABEL_FILE, &statbuf))
- {
- /* should not happen per the upper checks */
- if (errno != ENOENT)
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not stat file \"%s\": %m",
- BACKUP_LABEL_FILE)));
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("a backup is not in progress")));
- }
-
- lfp = AllocateFile(BACKUP_LABEL_FILE, "r");
- if (!lfp)
- {
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not read file \"%s\": %m",
- BACKUP_LABEL_FILE)));
- }
- labelfile = palloc(statbuf.st_size + 1);
- r = fread(labelfile, statbuf.st_size, 1, lfp);
- labelfile[statbuf.st_size] = '\0';
-
- /*
- * Close and remove the backup label file
- */
- if (r != 1 || ferror(lfp) || FreeFile(lfp))
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not read file \"%s\": %m",
- BACKUP_LABEL_FILE)));
- durable_unlink(BACKUP_LABEL_FILE, ERROR);
-
- /*
- * Remove tablespace_map file if present, it is created only if
- * there are tablespaces.
- */
- durable_unlink(TABLESPACE_MAP, DEBUG1);
- }
- PG_END_ENSURE_ERROR_CLEANUP(pg_stop_backup_callback, (Datum) BoolGetDatum(exclusive));
- }
-
/*
- * OK to update backup counters, forcePageWrites and session-level lock.
+ * OK to update backup counters, forcePageWrites, and session-level lock.
*
* Note that CHECK_FOR_INTERRUPTS() must not occur while updating them.
* Otherwise they can be updated inconsistently, and which might cause
* do_pg_abort_backup() to fail.
*/
WALInsertLockAcquireExclusive();
- if (exclusive)
- {
- XLogCtl->Insert.exclusiveBackupState = EXCLUSIVE_BACKUP_NONE;
- }
- else
- {
- /*
- * The user-visible pg_start/stop_backup() functions that operate on
- * exclusive backups can be called at any time, but for non-exclusive
- * backups, it is expected that each do_pg_start_backup() call is
- * matched by exactly one do_pg_stop_backup() call.
- */
- Assert(XLogCtl->Insert.nonExclusiveBackups > 0);
- XLogCtl->Insert.nonExclusiveBackups--;
- }
- if (XLogCtl->Insert.exclusiveBackupState == EXCLUSIVE_BACKUP_NONE &&
- XLogCtl->Insert.nonExclusiveBackups == 0)
+ /*
+ * It is expected that each do_pg_backup_start() call is matched by exactly
+ * one do_pg_backup_stop() call.
+ */
+ Assert(XLogCtl->Insert.runningBackups > 0);
+ XLogCtl->Insert.runningBackups--;
+
+ if (XLogCtl->Insert.runningBackups == 0)
{
XLogCtl->Insert.forcePageWrites = false;
}
@@ -8975,17 +8675,13 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
/*
* do_pg_abort_backup: abort a running backup
*
- * This does just the most basic steps of do_pg_stop_backup(), by taking the
+ * This does just the most basic steps of do_pg_backup_stop(), by taking the
* system out of backup mode, thus making it a lot more safe to call from
* an error handler.
*
* The caller can pass 'arg' as 'true' or 'false' to control whether a warning
* is emitted.
*
- * NB: This is only for aborting a non-exclusive backup that doesn't write
- * backup_label. A backup started with pg_start_backup() needs to be finished
- * with pg_stop_backup().
- *
* NB: This gets used as a before_shmem_exit handler, hence the odd-looking
* signature.
*/
@@ -8995,18 +8691,16 @@ do_pg_abort_backup(int code, Datum arg)
bool emit_warning = DatumGetBool(arg);
/*
- * Quick exit if session is not keeping around a non-exclusive backup
- * already started.
+ * Quick exit if session does not have a running backup.
*/
- if (sessionBackupState != SESSION_BACKUP_NON_EXCLUSIVE)
+ if (sessionBackupState != SESSION_BACKUP_RUNNING)
return;
WALInsertLockAcquireExclusive();
- Assert(XLogCtl->Insert.nonExclusiveBackups > 0);
- XLogCtl->Insert.nonExclusiveBackups--;
+ Assert(XLogCtl->Insert.runningBackups > 0);
+ XLogCtl->Insert.runningBackups--;
- if (XLogCtl->Insert.exclusiveBackupState == EXCLUSIVE_BACKUP_NONE &&
- XLogCtl->Insert.nonExclusiveBackups == 0)
+ if (XLogCtl->Insert.runningBackups == 0)
{
XLogCtl->Insert.forcePageWrites = false;
}
@@ -9014,7 +8708,7 @@ do_pg_abort_backup(int code, Datum arg)
if (emit_warning)
ereport(WARNING,
- (errmsg("aborting backup due to backend exiting before pg_stop_backup was called")));
+ (errmsg("aborting backup due to backend exiting before pg_backup_stop was called")));
}
/*
@@ -9074,87 +8768,6 @@ GetOldestRestartPoint(XLogRecPtr *oldrecptr, TimeLineID *oldtli)
LWLockRelease(ControlFileLock);
}
-/*
- * BackupInProgress: check if online backup mode is active
- *
- * This is done by checking for existence of the "backup_label" file.
- */
-bool
-BackupInProgress(void)
-{
- struct stat stat_buf;
-
- return (stat(BACKUP_LABEL_FILE, &stat_buf) == 0);
-}
-
-/*
- * CancelBackup: rename the "backup_label" and "tablespace_map"
- * files to cancel backup mode
- *
- * If the "backup_label" file exists, it will be renamed to "backup_label.old".
- * Similarly, if the "tablespace_map" file exists, it will be renamed to
- * "tablespace_map.old".
- *
- * Note that this will render an online backup in progress
- * useless. To correctly finish an online backup, pg_stop_backup must be
- * called.
- */
-void
-CancelBackup(void)
-{
- struct stat stat_buf;
-
- /* if the backup_label file is not there, return */
- if (stat(BACKUP_LABEL_FILE, &stat_buf) < 0)
- return;
-
- /* remove leftover file from previously canceled backup if it exists */
- unlink(BACKUP_LABEL_OLD);
-
- if (durable_rename(BACKUP_LABEL_FILE, BACKUP_LABEL_OLD, DEBUG1) != 0)
- {
- ereport(WARNING,
- (errcode_for_file_access(),
- errmsg("online backup mode was not canceled"),
- errdetail("File \"%s\" could not be renamed to \"%s\": %m.",
- BACKUP_LABEL_FILE, BACKUP_LABEL_OLD)));
- return;
- }
-
- /* if the tablespace_map file is not there, return */
- if (stat(TABLESPACE_MAP, &stat_buf) < 0)
- {
- ereport(LOG,
- (errmsg("online backup mode canceled"),
- errdetail("File \"%s\" was renamed to \"%s\".",
- BACKUP_LABEL_FILE, BACKUP_LABEL_OLD)));
- return;
- }
-
- /* remove leftover file from previously canceled backup if it exists */
- unlink(TABLESPACE_MAP_OLD);
-
- if (durable_rename(TABLESPACE_MAP, TABLESPACE_MAP_OLD, DEBUG1) == 0)
- {
- ereport(LOG,
- (errmsg("online backup mode canceled"),
- errdetail("Files \"%s\" and \"%s\" were renamed to "
- "\"%s\" and \"%s\", respectively.",
- BACKUP_LABEL_FILE, TABLESPACE_MAP,
- BACKUP_LABEL_OLD, TABLESPACE_MAP_OLD)));
- }
- else
- {
- ereport(WARNING,
- (errcode_for_file_access(),
- errmsg("online backup mode canceled"),
- errdetail("File \"%s\" was renamed to \"%s\", but "
- "file \"%s\" could not be renamed to \"%s\": %m.",
- BACKUP_LABEL_FILE, BACKUP_LABEL_OLD,
- TABLESPACE_MAP, TABLESPACE_MAP_OLD)));
- }
-}
-
/* Thin wrapper around ShutdownWalRcv(). */
void
XLogShutdownWalRcv(void)
diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c
index 2752be63c1..b61ae6c0b4 100644
--- a/src/backend/access/transam/xlogfuncs.c
+++ b/src/backend/access/transam/xlogfuncs.c
@@ -39,13 +39,13 @@
#include "utils/tuplestore.h"
/*
- * Store label file and tablespace map during non-exclusive backups.
+ * Store label file and tablespace map during backups.
*/
static StringInfo label_file;
static StringInfo tblspc_map_file;
/*
- * pg_start_backup: set up for taking an on-line backup dump
+ * pg_backup_start: set up for taking an on-line backup dump
*
* Essentially what this does is to create a backup label file in $PGDATA,
* where it will be archived as part of the backup dump. The label file
@@ -57,105 +57,44 @@ static StringInfo tblspc_map_file;
* GRANT system.
*/
Datum
-pg_start_backup(PG_FUNCTION_ARGS)
+pg_backup_start(PG_FUNCTION_ARGS)
{
text *backupid = PG_GETARG_TEXT_PP(0);
bool fast = PG_GETARG_BOOL(1);
- bool exclusive = PG_GETARG_BOOL(2);
char *backupidstr;
XLogRecPtr startpoint;
SessionBackupState status = get_backup_status();
+ MemoryContext oldcontext;
backupidstr = text_to_cstring(backupid);
- if (status == SESSION_BACKUP_NON_EXCLUSIVE)
+ if (status == SESSION_BACKUP_RUNNING)
ereport(ERROR,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("a backup is already in progress in this session")));
- if (exclusive)
- {
- startpoint = do_pg_start_backup(backupidstr, fast, NULL, NULL,
- NULL, NULL);
- }
- else
- {
- MemoryContext oldcontext;
-
- /*
- * Label file and tablespace map file need to be long-lived, since
- * they are read in pg_stop_backup.
- */
- oldcontext = MemoryContextSwitchTo(TopMemoryContext);
- label_file = makeStringInfo();
- tblspc_map_file = makeStringInfo();
- MemoryContextSwitchTo(oldcontext);
+ /*
+ * Label file and tablespace map file need to be long-lived, since
+ * they are read in pg_backup_stop.
+ */
+ oldcontext = MemoryContextSwitchTo(TopMemoryContext);
+ label_file = makeStringInfo();
+ tblspc_map_file = makeStringInfo();
+ MemoryContextSwitchTo(oldcontext);
- register_persistent_abort_backup_handler();
+ register_persistent_abort_backup_handler();
- startpoint = do_pg_start_backup(backupidstr, fast, NULL, label_file,
- NULL, tblspc_map_file);
- }
+ startpoint = do_pg_backup_start(backupidstr, fast, NULL, label_file,
+ NULL, tblspc_map_file);
PG_RETURN_LSN(startpoint);
}
-/*
- * pg_stop_backup: finish taking an on-line backup dump
- *
- * We write an end-of-backup WAL record, and remove the backup label file
- * created by pg_start_backup, creating a backup history file in pg_wal
- * instead (whence it will immediately be archived). The backup history file
- * contains the same info found in the label file, plus the backup-end time
- * and WAL location. Before 9.0, the backup-end time was read from the backup
- * history file at the beginning of archive recovery, but we now use the WAL
- * record for that and the file is for informational and debug purposes only.
- *
- * Note: different from CancelBackup which just cancels online backup mode.
- *
- * Note: this version is only called to stop an exclusive backup. The function
- * pg_stop_backup_v2 (overloaded as pg_stop_backup in SQL) is called to
- * stop non-exclusive backups.
- *
- * Permission checking for this function is managed through the normal
- * GRANT system.
- */
-Datum
-pg_stop_backup(PG_FUNCTION_ARGS)
-{
- XLogRecPtr stoppoint;
- SessionBackupState status = get_backup_status();
-
- if (status == SESSION_BACKUP_NON_EXCLUSIVE)
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("non-exclusive backup in progress"),
- errhint("Did you mean to use pg_stop_backup('f')?")));
-
- /*
- * Exclusive backups were typically started in a different connection, so
- * don't try to verify that status of backup is set to
- * SESSION_BACKUP_EXCLUSIVE in this function. Actual verification that an
- * exclusive backup is in fact running is handled inside
- * do_pg_stop_backup.
- */
- stoppoint = do_pg_stop_backup(NULL, true, NULL);
-
- PG_RETURN_LSN(stoppoint);
-}
-
/*
- * pg_stop_backup_v2: finish taking exclusive or nonexclusive on-line backup.
- *
- * Works the same as pg_stop_backup, except for non-exclusive backups it returns
- * the backup label and tablespace map files as text fields in as part of the
- * resultset.
+ * pg_backup_stop: finish taking an on-line backup.
*
- * The first parameter (variable 'exclusive') allows the user to tell us if
- * this is an exclusive or a non-exclusive backup.
- *
- * The second parameter (variable 'waitforarchive'), which is optional,
+ * The first parameter (variable 'waitforarchive'), which is optional,
* allows the user to choose if they want to wait for the WAL to be archived
* or if we should just return as soon as the WAL record is written.
*
@@ -163,15 +102,14 @@ pg_stop_backup(PG_FUNCTION_ARGS)
* GRANT system.
*/
Datum
-pg_stop_backup_v2(PG_FUNCTION_ARGS)
+pg_backup_stop(PG_FUNCTION_ARGS)
{
#define PG_STOP_BACKUP_V2_COLS 3
TupleDesc tupdesc;
Datum values[PG_STOP_BACKUP_V2_COLS];
bool nulls[PG_STOP_BACKUP_V2_COLS];
- bool exclusive = PG_GETARG_BOOL(0);
- bool waitforarchive = PG_GETARG_BOOL(1);
+ bool waitforarchive = PG_GETARG_BOOL(0);
XLogRecPtr stoppoint;
SessionBackupState status = get_backup_status();
@@ -182,51 +120,29 @@ pg_stop_backup_v2(PG_FUNCTION_ARGS)
MemSet(values, 0, sizeof(values));
MemSet(nulls, 0, sizeof(nulls));
- if (exclusive)
- {
- if (status == SESSION_BACKUP_NON_EXCLUSIVE)
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("non-exclusive backup in progress"),
- errhint("Did you mean to use pg_stop_backup('f')?")));
-
- /*
- * Stop the exclusive backup, and since we're in an exclusive backup
- * return NULL for both backup_label and tablespace_map.
- */
- stoppoint = do_pg_stop_backup(NULL, waitforarchive, NULL);
-
- nulls[1] = true;
- nulls[2] = true;
- }
- else
- {
- if (status != SESSION_BACKUP_NON_EXCLUSIVE)
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("non-exclusive backup is not in progress"),
- errhint("Did you mean to use pg_stop_backup('t')?")));
+ if (status != SESSION_BACKUP_RUNNING)
+ ereport(ERROR,
+ (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ errmsg("backup is not in progress"),
+ errhint("Did you call pg_backup_start()?")));
- /*
- * Stop the non-exclusive backup. Return a copy of the backup label
- * and tablespace map so they can be written to disk by the caller.
- */
- stoppoint = do_pg_stop_backup(label_file->data, waitforarchive, NULL);
-
- values[1] = CStringGetTextDatum(label_file->data);
- values[2] = CStringGetTextDatum(tblspc_map_file->data);
-
- /* Free structures allocated in TopMemoryContext */
- pfree(label_file->data);
- pfree(label_file);
- label_file = NULL;
- pfree(tblspc_map_file->data);
- pfree(tblspc_map_file);
- tblspc_map_file = NULL;
- }
+ /*
+ * Stop the backup. Return a copy of the backup label and tablespace map so
+ * they can be written to disk by the caller.
+ */
+ stoppoint = do_pg_backup_stop(label_file->data, waitforarchive, NULL);
- /* Stoppoint is included on both exclusive and nonexclusive backups */
values[0] = LSNGetDatum(stoppoint);
+ values[1] = CStringGetTextDatum(label_file->data);
+ values[2] = CStringGetTextDatum(tblspc_map_file->data);
+
+ /* Free structures allocated in TopMemoryContext */
+ pfree(label_file->data);
+ pfree(label_file);
+ label_file = NULL;
+ pfree(tblspc_map_file->data);
+ pfree(tblspc_map_file);
+ tblspc_map_file = NULL;
/* Returns the record as Datum */
PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
@@ -298,7 +214,7 @@ pg_create_restore_point(PG_FUNCTION_ARGS)
}
/*
- * Report the current WAL write location (same format as pg_start_backup etc)
+ * Report the current WAL write location (same format as pg_backup_start etc)
*
* This is useful for determining how much of WAL is visible to an external
* archiving process. Note that the data before this point is written out
@@ -321,7 +237,7 @@ pg_current_wal_lsn(PG_FUNCTION_ARGS)
}
/*
- * Report the current WAL insert location (same format as pg_start_backup etc)
+ * Report the current WAL insert location (same format as pg_backup_start etc)
*
* This function is mostly for debugging purposes.
*/
@@ -342,7 +258,7 @@ pg_current_wal_insert_lsn(PG_FUNCTION_ARGS)
}
/*
- * Report the current WAL flush location (same format as pg_start_backup etc)
+ * Report the current WAL flush location (same format as pg_backup_start etc)
*
* This function is mostly for debugging purposes.
*/
@@ -363,7 +279,7 @@ pg_current_wal_flush_lsn(PG_FUNCTION_ARGS)
}
/*
- * Report the last WAL receive location (same format as pg_start_backup etc)
+ * Report the last WAL receive location (same format as pg_backup_start etc)
*
* This is useful for determining how much of WAL is guaranteed to be received
* and synced to disk by walreceiver.
@@ -382,7 +298,7 @@ pg_last_wal_receive_lsn(PG_FUNCTION_ARGS)
}
/*
- * Report the last WAL replay location (same format as pg_start_backup etc)
+ * Report the last WAL replay location (same format as pg_backup_start etc)
*
* This is useful for determining how much of WAL is visible to read-only
* connections during recovery.
@@ -402,7 +318,7 @@ pg_last_wal_replay_lsn(PG_FUNCTION_ARGS)
/*
* Compute an xlog file name and decimal byte offset given a WAL location,
- * such as is returned by pg_stop_backup() or pg_switch_wal().
+ * such as is returned by pg_backup_stop() or pg_switch_wal().
*
* Note that a location exactly at a segment boundary is taken to be in
* the previous segment. This is usually the right thing, since the
@@ -470,7 +386,7 @@ pg_walfile_name_offset(PG_FUNCTION_ARGS)
/*
* Compute an xlog file name given a WAL location,
- * such as is returned by pg_stop_backup() or pg_switch_wal().
+ * such as is returned by pg_backup_stop() or pg_switch_wal().
*/
Datum
pg_walfile_name(PG_FUNCTION_ARGS)
@@ -645,81 +561,6 @@ pg_wal_lsn_diff(PG_FUNCTION_ARGS)
PG_RETURN_NUMERIC(result);
}
-/*
- * Returns bool with current on-line backup mode, a global state.
- */
-Datum
-pg_is_in_backup(PG_FUNCTION_ARGS)
-{
- PG_RETURN_BOOL(BackupInProgress());
-}
-
-/*
- * Returns start time of an online exclusive backup.
- *
- * When there's no exclusive backup in progress, the function
- * returns NULL.
- */
-Datum
-pg_backup_start_time(PG_FUNCTION_ARGS)
-{
- Datum xtime;
- FILE *lfp;
- char fline[MAXPGPATH];
- char backup_start_time[30];
-
- /*
- * See if label file is present
- */
- lfp = AllocateFile(BACKUP_LABEL_FILE, "r");
- if (lfp == NULL)
- {
- if (errno != ENOENT)
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not read file \"%s\": %m",
- BACKUP_LABEL_FILE)));
- PG_RETURN_NULL();
- }
-
- /*
- * Parse the file to find the START TIME line.
- */
- backup_start_time[0] = '\0';
- while (fgets(fline, sizeof(fline), lfp) != NULL)
- {
- if (sscanf(fline, "START TIME: %25[^\n]\n", backup_start_time) == 1)
- break;
- }
-
- /* Check for a read error. */
- if (ferror(lfp))
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not read file \"%s\": %m", BACKUP_LABEL_FILE)));
-
- /* Close the backup label file. */
- if (FreeFile(lfp))
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not close file \"%s\": %m", BACKUP_LABEL_FILE)));
-
- if (strlen(backup_start_time) == 0)
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("invalid data in file \"%s\"", BACKUP_LABEL_FILE)));
-
- /*
- * Convert the time string read from file to TimestampTz form.
- */
- xtime = DirectFunctionCall3(timestamptz_in,
- CStringGetDatum(backup_start_time),
- ObjectIdGetDatum(InvalidOid),
- Int32GetDatum(-1));
-
- PG_RETURN_DATUM(xtime);
-}
-
/*
* Promotes a standby server.
*
diff --git a/src/backend/access/transam/xlogrecovery.c b/src/backend/access/transam/xlogrecovery.c
index f9f212680b..d2b5e7f32c 100644
--- a/src/backend/access/transam/xlogrecovery.c
+++ b/src/backend/access/transam/xlogrecovery.c
@@ -1966,7 +1966,7 @@ xlogrecovery_redo(XLogReaderState *record, TimeLineID replayTLI)
{
/*
* We have reached the end of base backup, the point where
- * pg_stop_backup() was done. The data on disk is now consistent
+ * pg_backup_stop() was done. The data on disk is now consistent
* (assuming we have also reached minRecoveryPoint). Set
* backupEndPoint to the current LSN, so that the next call to
* CheckRecoveryConsistency() will notice it and do the
diff --git a/src/backend/catalog/system_functions.sql b/src/backend/catalog/system_functions.sql
index 81bac6f581..6ae4388d3f 100644
--- a/src/backend/catalog/system_functions.sql
+++ b/src/backend/catalog/system_functions.sql
@@ -377,14 +377,14 @@ BEGIN ATOMIC
END;
CREATE OR REPLACE FUNCTION
- pg_start_backup(label text, fast boolean DEFAULT false, exclusive boolean DEFAULT true)
- RETURNS pg_lsn STRICT VOLATILE LANGUAGE internal AS 'pg_start_backup'
+ pg_backup_start(label text, fast boolean DEFAULT false)
+ RETURNS pg_lsn STRICT VOLATILE LANGUAGE internal AS 'pg_backup_start'
PARALLEL RESTRICTED;
-CREATE OR REPLACE FUNCTION pg_stop_backup (
- exclusive boolean, wait_for_archive boolean DEFAULT true,
- OUT lsn pg_lsn, OUT labelfile text, OUT spcmapfile text)
- RETURNS record STRICT VOLATILE LANGUAGE internal as 'pg_stop_backup_v2'
+CREATE OR REPLACE FUNCTION pg_backup_stop (
+ wait_for_archive boolean DEFAULT true, OUT lsn pg_lsn,
+ OUT labelfile text, OUT spcmapfile text)
+ RETURNS record STRICT VOLATILE LANGUAGE internal as 'pg_backup_stop'
PARALLEL RESTRICTED;
CREATE OR REPLACE FUNCTION
@@ -603,11 +603,9 @@ AS 'unicode_is_normalized';
-- available to superuser / cluster owner, if they choose.
--
-REVOKE EXECUTE ON FUNCTION pg_start_backup(text, boolean, boolean) FROM public;
+REVOKE EXECUTE ON FUNCTION pg_backup_start(text, boolean) FROM public;
-REVOKE EXECUTE ON FUNCTION pg_stop_backup() FROM public;
-
-REVOKE EXECUTE ON FUNCTION pg_stop_backup(boolean, boolean) FROM public;
+REVOKE EXECUTE ON FUNCTION pg_backup_stop(boolean) FROM public;
REVOKE EXECUTE ON FUNCTION pg_create_restore_point(text) FROM public;
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index 80bb269599..b6767ed72e 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -348,7 +348,6 @@ static PMState pmState = PM_INIT;
typedef enum
{
ALLOW_ALL_CONNS, /* normal not-shutting-down state */
- ALLOW_SUPERUSER_CONNS, /* only superusers can connect */
ALLOW_NO_CONNS /* no new connections allowed, period */
} ConnsAllowedState;
@@ -2546,19 +2545,11 @@ canAcceptConnections(int backend_type)
/*
* "Smart shutdown" restrictions are applied only to normal connections,
- * not to autovac workers or bgworkers. When only superusers can connect,
- * we return CAC_SUPERUSER to indicate that superuserness must be checked
- * later. Note that neither CAC_OK nor CAC_SUPERUSER can safely be
- * returned until we have checked for too many children.
+ * not to autovac workers or bgworkers.
*/
if (connsAllowed != ALLOW_ALL_CONNS &&
backend_type == BACKEND_TYPE_NORMAL)
- {
- if (connsAllowed == ALLOW_SUPERUSER_CONNS)
- result = CAC_SUPERUSER; /* allow superusers only */
- else
- return CAC_SHUTDOWN; /* shutdown is pending */
- }
+ return CAC_SHUTDOWN; /* shutdown is pending */
/*
* Don't start too many children.
@@ -2877,16 +2868,11 @@ pmdie(SIGNAL_ARGS)
#endif
/*
- * If we reached normal running, we have to wait for any online
- * backup mode to end; otherwise go straight to waiting for client
- * backends to exit. (The difference is that in the former state,
- * we'll still let in new superuser clients, so that somebody can
- * end the online backup mode.) If already in PM_STOP_BACKENDS or
+ * If we reached normal running, we go straight to waiting for
+ * client backends to exit. If already in PM_STOP_BACKENDS or
* a later state, do not change it.
*/
- if (pmState == PM_RUN)
- connsAllowed = ALLOW_SUPERUSER_CONNS;
- else if (pmState == PM_HOT_STANDBY)
+ if (pmState == PM_RUN || pmState == PM_HOT_STANDBY)
connsAllowed = ALLOW_NO_CONNS;
else if (pmState == PM_STARTUP || pmState == PM_RECOVERY)
{
@@ -3842,16 +3828,6 @@ PostmasterStateMachine(void)
/* If we're doing a smart shutdown, try to advance that state. */
if (pmState == PM_RUN || pmState == PM_HOT_STANDBY)
{
- if (connsAllowed == ALLOW_SUPERUSER_CONNS)
- {
- /*
- * ALLOW_SUPERUSER_CONNS state ends as soon as online backup mode
- * is not active.
- */
- if (!BackupInProgress())
- connsAllowed = ALLOW_NO_CONNS;
- }
-
if (connsAllowed == ALLOW_NO_CONNS)
{
/*
@@ -4044,18 +4020,6 @@ PostmasterStateMachine(void)
}
else
{
- /*
- * Terminate exclusive backup mode to avoid recovery after a clean
- * fast shutdown. Since an exclusive backup can only be taken
- * during normal running (and not, for example, while running
- * under Hot Standby) it only makes sense to do this if we reached
- * normal running. If we're still in recovery, the backup file is
- * one we're recovering *from*, and we must keep it around so that
- * recovery restarts from the right place.
- */
- if (ReachedNormalRunning)
- CancelBackup();
-
/*
* Normal exit from the postmaster is here. We don't need to log
* anything here, since the UnlinkLockFiles proc_exit callback
diff --git a/src/backend/replication/basebackup.c b/src/backend/replication/basebackup.c
index 2378ce5c5e..b12ffb4529 100644
--- a/src/backend/replication/basebackup.c
+++ b/src/backend/replication/basebackup.c
@@ -196,10 +196,8 @@ static const struct exclude_list_item excludeFiles[] =
{RELCACHE_INIT_FILENAME, true},
/*
- * If there's a backup_label or tablespace_map file, it belongs to a
- * backup started by the user with pg_start_backup(). It is *not* correct
- * for this backup. Our backup_label/tablespace_map is injected into the
- * tar separately.
+ * backup_label and tablespace_map should not exist in in a running cluster
+ * capable of doing an online backup, but exclude then just in case.
*/
{BACKUP_LABEL_FILE, false},
{TABLESPACE_MAP, false},
@@ -276,16 +274,16 @@ perform_base_backup(basebackup_options *opt, bbsink *sink)
total_checksum_failures = 0;
basebackup_progress_wait_checkpoint();
- state.startptr = do_pg_start_backup(opt->label, opt->fastcheckpoint,
+ state.startptr = do_pg_backup_start(opt->label, opt->fastcheckpoint,
&state.starttli,
labelfile, &state.tablespaces,
tblspc_map_file);
/*
- * Once do_pg_start_backup has been called, ensure that any failure causes
+ * Once do_pg_backup_start has been called, ensure that any failure causes
* us to abort the backup so we don't "leak" a backup counter. For this
- * reason, *all* functionality between do_pg_start_backup() and the end of
- * do_pg_stop_backup() should be inside the error cleanup block!
+ * reason, *all* functionality between do_pg_backup_start() and the end of
+ * do_pg_backup_stop() should be inside the error cleanup block!
*/
PG_ENSURE_ERROR_CLEANUP(do_pg_abort_backup, BoolGetDatum(false));
@@ -406,7 +404,7 @@ perform_base_backup(basebackup_options *opt, bbsink *sink)
}
basebackup_progress_wait_wal_archive(&state);
- endptr = do_pg_stop_backup(labelfile->data, !opt->nowait, &endtli);
+ endptr = do_pg_backup_stop(labelfile->data, !opt->nowait, &endtli);
}
PG_END_ENSURE_ERROR_CLEANUP(do_pg_abort_backup, BoolGetDatum(false));
@@ -969,7 +967,7 @@ parse_basebackup_options(List *options, basebackup_options *opt)
/*
* SendBaseBackup() - send a complete base backup.
*
- * The function will put the system into backup mode like pg_start_backup()
+ * The function will put the system into backup mode like pg_backup_start()
* does, so that the backup is consistent even though we read directly from
* the filesystem, bypassing the buffer cache.
*/
@@ -1230,7 +1228,7 @@ sendDir(bbsink *sink, const char *path, int basepathlen, bool sizeonly,
* error in that case. The error handler further up will call
* do_pg_abort_backup() for us. Also check that if the backup was
* started while still in recovery, the server wasn't promoted.
- * do_pg_stop_backup() will check that too, but it's better to stop
+ * do_pg_backup_stop() will check that too, but it's better to stop
* the backup early than continue to the end and fail there.
*/
CHECK_FOR_INTERRUPTS();
diff --git a/src/bin/pg_basebackup/t/010_pg_basebackup.pl b/src/bin/pg_basebackup/t/010_pg_basebackup.pl
index 8cb8cfe045..c7c01a0992 100644
--- a/src/bin/pg_basebackup/t/010_pg_basebackup.pl
+++ b/src/bin/pg_basebackup/t/010_pg_basebackup.pl
@@ -185,6 +185,10 @@ isnt(slurp_file("$tempdir/backup/backup_label"),
'DONOTCOPY', 'existing backup_label not copied');
rmtree("$tempdir/backup");
+# Now delete the bogus backup_label file since it will interfere with startup
+unlink("$pgdata/backup_label")
+ or BAIL_OUT("unable to unlink $pgdata/backup_label");
+
$node->command_ok(
[
@pg_basebackup_defs, '-D',
diff --git a/src/bin/pg_ctl/pg_ctl.c b/src/bin/pg_ctl/pg_ctl.c
index 3c182c97d4..ee3fa148b6 100644
--- a/src/bin/pg_ctl/pg_ctl.c
+++ b/src/bin/pg_ctl/pg_ctl.c
@@ -1069,7 +1069,7 @@ do_stop(void)
get_control_dbstate() != DB_IN_ARCHIVE_RECOVERY)
{
print_msg(_("WARNING: online backup mode is active\n"
- "Shutdown will not complete until pg_stop_backup() is called.\n\n"));
+ "Shutdown will not complete until pg_backup_stop() is called.\n\n"));
}
print_msg(_("waiting for server to shut down..."));
@@ -1145,7 +1145,7 @@ do_restart(void)
get_control_dbstate() != DB_IN_ARCHIVE_RECOVERY)
{
print_msg(_("WARNING: online backup mode is active\n"
- "Shutdown will not complete until pg_stop_backup() is called.\n\n"));
+ "Shutdown will not complete until pg_backup_stop() is called.\n\n"));
}
print_msg(_("waiting for server to shut down..."));
diff --git a/src/bin/pg_rewind/filemap.c b/src/bin/pg_rewind/filemap.c
index 7211090f47..fb52debf7a 100644
--- a/src/bin/pg_rewind/filemap.c
+++ b/src/bin/pg_rewind/filemap.c
@@ -140,9 +140,9 @@ static const struct exclude_list_item excludeFiles[] =
{"pg_internal.init", true}, /* defined as RELCACHE_INIT_FILENAME */
/*
- * If there's a backup_label or tablespace_map file, it belongs to a
- * backup started by the user with pg_start_backup(). It is *not* correct
- * for this backup. Our backup_label is written later on separately.
+ * If there is a backup_label or tablespace_map file, it indicates that
+ * a recovery failed and this cluster probably can't be rewound, but
+ * exclude them anyway if they are found.
*/
{"backup_label", false}, /* defined as BACKUP_LABEL_FILE */
{"tablespace_map", false}, /* defined as TABLESPACE_MAP */
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index 4b45ac64db..be375df248 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -275,14 +275,13 @@ extern void XLogShutdownWalRcv(void);
typedef enum SessionBackupState
{
SESSION_BACKUP_NONE,
- SESSION_BACKUP_EXCLUSIVE,
- SESSION_BACKUP_NON_EXCLUSIVE
+ SESSION_BACKUP_RUNNING,
} SessionBackupState;
-extern XLogRecPtr do_pg_start_backup(const char *backupidstr, bool fast,
+extern XLogRecPtr do_pg_backup_start(const char *backupidstr, bool fast,
TimeLineID *starttli_p, StringInfo labelfile,
List **tablespaces, StringInfo tblspcmapfile);
-extern XLogRecPtr do_pg_stop_backup(char *labelfile, bool waitforarchive,
+extern XLogRecPtr do_pg_backup_stop(char *labelfile, bool waitforarchive,
TimeLineID *stoptli_p);
extern void do_pg_abort_backup(int code, Datum arg);
extern void register_persistent_abort_backup_handler(void);
diff --git a/src/include/catalog/pg_control.h b/src/include/catalog/pg_control.h
index 1f3dc24ac1..3d075fcef3 100644
--- a/src/include/catalog/pg_control.h
+++ b/src/include/catalog/pg_control.h
@@ -163,7 +163,7 @@ typedef struct ControlFileData
* from a backup, and must see a backup-end record before we can safely
* start up. If it's false, but backupStartPoint is set, a backup_label
* file was found at startup but it may have been a leftover from a stray
- * pg_start_backup() call, not accompanied by pg_stop_backup().
+ * pg_backup_start() call, not accompanied by pg_backup_stop().
*/
XLogRecPtr minRecoveryPoint;
TimeLineID minRecoveryPointTLI;
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index d8e8715ed1..8563714c9c 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -6268,26 +6268,16 @@
proargtypes => 'int4 int8', proargnames => '{pid,timeout}',
prosrc => 'pg_terminate_backend' },
{ oid => '2172', descr => 'prepare for taking an online backup',
- proname => 'pg_start_backup', provolatile => 'v', proparallel => 'r',
- prorettype => 'pg_lsn', proargtypes => 'text bool bool',
- prosrc => 'pg_start_backup' },
-{ oid => '2173', descr => 'finish taking an online backup',
- proname => 'pg_stop_backup', provolatile => 'v', proparallel => 'r',
- prorettype => 'pg_lsn', proargtypes => '', prosrc => 'pg_stop_backup' },
+ proname => 'pg_backup_start', provolatile => 'v', proparallel => 'r',
+ prorettype => 'pg_lsn', proargtypes => 'text bool',
+ prosrc => 'pg_backup_start' },
{ oid => '2739', descr => 'finish taking an online backup',
- proname => 'pg_stop_backup', provolatile => 'v', proparallel => 'r',
- prorettype => 'record', proargtypes => 'bool bool',
- proallargtypes => '{bool,bool,pg_lsn,text,text}',
- proargmodes => '{i,i,o,o,o}',
- proargnames => '{exclusive,wait_for_archive,lsn,labelfile,spcmapfile}',
- prosrc => 'pg_stop_backup_v2' },
-{ oid => '3813', descr => 'true if server is in online backup',
- proname => 'pg_is_in_backup', provolatile => 'v', prorettype => 'bool',
- proargtypes => '', prosrc => 'pg_is_in_backup' },
-{ oid => '3814', descr => 'start time of an online backup',
- proname => 'pg_backup_start_time', provolatile => 's',
- prorettype => 'timestamptz', proargtypes => '',
- prosrc => 'pg_backup_start_time' },
+ proname => 'pg_backup_stop', provolatile => 'v', proparallel => 'r',
+ prorettype => 'record', proargtypes => 'bool',
+ proallargtypes => '{bool,pg_lsn,text,text}',
+ proargmodes => '{i,o,o,o}',
+ proargnames => '{wait_for_archive,lsn,labelfile,spcmapfile}',
+ prosrc => 'pg_backup_stop' },
{ oid => '3436', descr => 'promote standby server',
proname => 'pg_promote', provolatile => 'v', prorettype => 'bool',
proargtypes => 'bool int4', proargnames => '{wait,wait_seconds}',
diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h
index 0abc3ad540..9321d7f264 100644
--- a/src/include/miscadmin.h
+++ b/src/include/miscadmin.h
@@ -481,10 +481,6 @@ extern void process_session_preload_libraries(void);
extern void pg_bindtextdomain(const char *domain);
extern bool has_rolreplication(Oid roleid);
-/* in access/transam/xlog.c */
-extern bool BackupInProgress(void);
-extern void CancelBackup(void);
-
/* in executor/nodeHash.c */
extern size_t get_hash_memory_limit(void);
diff --git a/src/test/perl/PostgreSQL/Test/Cluster.pm b/src/test/perl/PostgreSQL/Test/Cluster.pm
index 4db52bc936..e1316abf3f 100644
--- a/src/test/perl/PostgreSQL/Test/Cluster.pm
+++ b/src/test/perl/PostgreSQL/Test/Cluster.pm
@@ -635,25 +635,6 @@ sub backup
return;
}
-=item $node->backup_fs_hot(backup_name)
-
-Create a backup with a filesystem level copy in subdirectory B<backup_name> of
-B<< $node->backup_dir >>, including WAL.
-
-Archiving must be enabled, as B<pg_start_backup()> and B<pg_stop_backup()> are
-used. This is not checked or enforced.
-
-The backup name is passed as the backup label to B<pg_start_backup()>.
-
-=cut
-
-sub backup_fs_hot
-{
- my ($self, $backup_name) = @_;
- $self->_backup_fs($backup_name, 1);
- return;
-}
-
=item $node->backup_fs_cold(backup_name)
Create a backup with a filesystem level copy in subdirectory B<backup_name> of
@@ -667,53 +648,18 @@ Use B<backup> or B<backup_fs_hot> if you want to back up a running server.
sub backup_fs_cold
{
my ($self, $backup_name) = @_;
- $self->_backup_fs($backup_name, 0);
- return;
-}
-
-
-# Common sub of backup_fs_hot and backup_fs_cold
-sub _backup_fs
-{
- my ($self, $backup_name, $hot) = @_;
- my $backup_path = $self->backup_dir . '/' . $backup_name;
- my $port = $self->port;
- my $name = $self->name;
-
- print "# Taking filesystem backup $backup_name from node \"$name\"\n";
-
- if ($hot)
- {
- my $stdout = $self->safe_psql('postgres',
- "SELECT * FROM pg_start_backup('$backup_name');");
- print "# pg_start_backup: $stdout\n";
- }
PostgreSQL::Test::RecursiveCopy::copypath(
$self->data_dir,
- $backup_path,
+ $self->backup_dir . '/' . $backup_name,
filterfn => sub {
my $src = shift;
return ($src ne 'log' and $src ne 'postmaster.pid');
});
- if ($hot)
- {
-
- # We ignore pg_stop_backup's return value. We also assume archiving
- # is enabled; otherwise the caller will have to copy the remaining
- # segments.
- my $stdout =
- $self->safe_psql('postgres', 'SELECT * FROM pg_stop_backup();');
- print "# pg_stop_backup: $stdout\n";
- }
-
- print "# Backup finished\n";
return;
}
-
-
=pod
=item $node->init_from_backup(root_node, backup_name)
diff --git a/src/test/recovery/t/010_logical_decoding_timelines.pl b/src/test/recovery/t/010_logical_decoding_timelines.pl
index 01ff31e61f..135fb1a72d 100644
--- a/src/test/recovery/t/010_logical_decoding_timelines.pl
+++ b/src/test/recovery/t/010_logical_decoding_timelines.pl
@@ -69,7 +69,9 @@ $node_primary->safe_psql('dropme',
$node_primary->safe_psql('postgres', 'CHECKPOINT;');
my $backup_name = 'b1';
-$node_primary->backup_fs_hot($backup_name);
+$node_primary->stop();
+$node_primary->backup_fs_cold($backup_name);
+$node_primary->start();
$node_primary->safe_psql('postgres',
q[SELECT pg_create_physical_replication_slot('phys_slot');]);
--
2.25.1
On 3/9/22 18:06, Nathan Bossart wrote:
On Wed, Mar 09, 2022 at 06:11:19PM -0500, Chapman Flack wrote:
I think the listitem
In the same connection as before, issue the command:
SELECT * FROM pg_backup_stop(true);would be clearer if it used named-parameter form, wait_for_archive => true.
This is not strictly necessary, of course, for a function with a single
IN parameter, but it's good documentation (and also could save us headaches
like these if there is ever another future need to give it more parameters).That listitem doesn't say anything about what the parameter means, which
is a little weird, but probably ok because the next listitem does go into
it in some detail. I don't think a larger reorg is needed to bring that
language one listitem earlier. Just naming the parameter is probably
enough to make it less puzzling (or adding in that listitem, at most,
"the effect of the wait_for_archive parameter is explained below").For consistency (and the same futureproofing benefit), I'd go to
fast => false in the earlier pg_backup_start as well.I'm more ambivalent about label => 'label'. It would be consistent,
but should we just agree for conciseness that there will always be
a label and it will always be first?You can pretty much tell in a call what's a label; it's those anonymous
trues and falses that are easier to read with named notation.Done. I went ahead and added "label => 'label'" for consistency.
+1 from me.
Regards,
-David
On 03/09/22 19:06, Nathan Bossart wrote:
Done. I went ahead and added "label => 'label'" for consistency.
Looks like this change to an example in func.sgml is not quite right:
-postgres=# SELECT * FROM pg_walfile_name_offset(pg_stop_backup());
+postgres=# SELECT * FROM pg_walfile_name_offset(pg_backup_stop());
pg_backup_stop returns a record now, not just lsn. So this works for me:
+postgres=# SELECT * FROM pg_walfile_name_offset((pg_backup_stop()).lsn);
Otherwise, all looks to be in good order.
Regards,
-Chap
On Thu, Mar 10, 2022 at 07:13:14PM -0500, Chapman Flack wrote:
Looks like this change to an example in func.sgml is not quite right:
-postgres=# SELECT * FROM pg_walfile_name_offset(pg_stop_backup()); +postgres=# SELECT * FROM pg_walfile_name_offset(pg_backup_stop());pg_backup_stop returns a record now, not just lsn. So this works for me:
+postgres=# SELECT * FROM pg_walfile_name_offset((pg_backup_stop()).lsn);
Ah, good catch. I made this change in v7. I considered doing something
like this
SELECT w.* FROM pg_backup_stop() b, pg_walfile_name_offset(b.lsn) w;
but I think your suggestion is simpler.
--
Nathan Bossart
Amazon Web Services: https://aws.amazon.com
Attachments:
v7-0001-remove-exclusive-backup-mode.patchtext/x-diff; charset=us-asciiDownload
From 3283d2b85f38f46d1e2ada0e6c5ea59d8c8e9f9d Mon Sep 17 00:00:00 2001
From: Nathan Bossart <bossartn@amazon.com>
Date: Wed, 1 Dec 2021 23:50:49 +0000
Subject: [PATCH v7 1/1] remove exclusive backup mode
---
doc/src/sgml/backup.sgml | 222 +-------
doc/src/sgml/func.sgml | 99 +---
doc/src/sgml/high-availability.sgml | 6 +-
doc/src/sgml/monitoring.sgml | 4 +-
doc/src/sgml/ref/pgupgrade.sgml | 2 +-
src/backend/access/transam/xlog.c | 493 ++----------------
src/backend/access/transam/xlogfuncs.c | 253 ++-------
src/backend/access/transam/xlogrecovery.c | 2 +-
src/backend/catalog/system_functions.sql | 18 +-
src/backend/postmaster/postmaster.c | 46 +-
src/backend/replication/basebackup.c | 20 +-
src/bin/pg_basebackup/t/010_pg_basebackup.pl | 4 +
src/bin/pg_ctl/pg_ctl.c | 4 +-
src/bin/pg_rewind/filemap.c | 6 +-
src/include/access/xlog.h | 7 +-
src/include/catalog/pg_control.h | 2 +-
src/include/catalog/pg_proc.dat | 28 +-
src/include/miscadmin.h | 4 -
src/test/perl/PostgreSQL/Test/Cluster.pm | 56 +-
.../t/010_logical_decoding_timelines.pl | 4 +-
20 files changed, 189 insertions(+), 1091 deletions(-)
diff --git a/doc/src/sgml/backup.sgml b/doc/src/sgml/backup.sgml
index 0d69851bb1..c8b914c1aa 100644
--- a/doc/src/sgml/backup.sgml
+++ b/doc/src/sgml/backup.sgml
@@ -857,16 +857,8 @@ test ! -f /mnt/server/archivedir/00000001000000A900000065 && cp pg_wal/0
sequence, and that the success of a step is verified before
proceeding to the next step.
</para>
- <para>
- Low level base backups can be made in a non-exclusive or an exclusive
- way. The non-exclusive method is recommended and the exclusive one is
- deprecated and will eventually be removed.
- </para>
-
- <sect3 id="backup-lowlevel-base-backup-nonexclusive">
- <title>Making a Non-Exclusive Low-Level Backup</title>
<para>
- A non-exclusive low level backup is one that allows other
+ A low level backup allows other
concurrent backups to be running (both those started using
the same backup API and those started using
<xref linkend="app-pgbasebackup"/>).
@@ -881,19 +873,19 @@ test ! -f /mnt/server/archivedir/00000001000000A900000065 && cp pg_wal/0
<listitem>
<para>
Connect to the server (it does not matter which database) as a user with
- rights to run pg_start_backup (superuser, or a user who has been granted
+ rights to run pg_backup_start (superuser, or a user who has been granted
EXECUTE on the function) and issue the command:
<programlisting>
-SELECT pg_start_backup('label', false, false);
+SELECT pg_backup_start(label => 'label', fast => false);
</programlisting>
where <literal>label</literal> is any string you want to use to uniquely
identify this backup operation. The connection
- calling <function>pg_start_backup</function> must be maintained until the end of
+ calling <function>pg_backup_start</function> must be maintained until the end of
the backup, or the backup will be automatically aborted.
</para>
<para>
- By default, <function>pg_start_backup</function> can take a long time to finish.
+ By default, <function>pg_backup_start</function> can take a long time to finish.
This is because it performs a checkpoint, and the I/O
required for the checkpoint will be spread out over a significant
period of time, by default half your inter-checkpoint interval
@@ -905,10 +897,6 @@ SELECT pg_start_backup('label', false, false);
issue an immediate checkpoint using as much I/O as available.
</para>
- <para>
- The third parameter being <literal>false</literal> tells
- <function>pg_start_backup</function> to initiate a non-exclusive base backup.
- </para>
</listitem>
<listitem>
<para>
@@ -926,7 +914,7 @@ SELECT pg_start_backup('label', false, false);
<para>
In the same connection as before, issue the command:
<programlisting>
-SELECT * FROM pg_stop_backup(false, true);
+SELECT * FROM pg_backup_stop(wait_for_archive => true);
</programlisting>
This terminates backup mode. On a primary, it also performs an automatic
switch to the next WAL segment. On a standby, it is not possible to
@@ -937,7 +925,7 @@ SELECT * FROM pg_stop_backup(false, true);
ready to archive.
</para>
<para>
- The <function>pg_stop_backup</function> will return one row with three
+ The <function>pg_backup_stop</function> will return one row with three
values. The second of these fields should be written to a file named
<filename>backup_label</filename> in the root directory of the backup. The
third field should be written to a file named
@@ -949,14 +937,14 @@ SELECT * FROM pg_stop_backup(false, true);
<listitem>
<para>
Once the WAL segment files active during the backup are archived, you are
- done. The file identified by <function>pg_stop_backup</function>'s first return
+ done. The file identified by <function>pg_backup_stop</function>'s first return
value is the last segment that is required to form a complete set of
backup files. On a primary, if <varname>archive_mode</varname> is enabled and the
<literal>wait_for_archive</literal> parameter is <literal>true</literal>,
- <function>pg_stop_backup</function> does not return until the last segment has
+ <function>pg_backup_stop</function> does not return until the last segment has
been archived.
On a standby, <varname>archive_mode</varname> must be <literal>always</literal> in order
- for <function>pg_stop_backup</function> to wait.
+ for <function>pg_backup_stop</function> to wait.
Archiving of these files happens automatically since you have
already configured <varname>archive_library</varname>. In most cases this
happens quickly, but you are advised to monitor your archive
@@ -965,9 +953,9 @@ SELECT * FROM pg_stop_backup(false, true);
because of failures of the archive library, it will keep retrying
until the archive succeeds and the backup is complete.
If you wish to place a time limit on the execution of
- <function>pg_stop_backup</function>, set an appropriate
+ <function>pg_backup_stop</function>, set an appropriate
<varname>statement_timeout</varname> value, but make note that if
- <function>pg_stop_backup</function> terminates because of this your backup
+ <function>pg_backup_stop</function> terminates because of this your backup
may not be valid.
</para>
<para>
@@ -975,8 +963,8 @@ SELECT * FROM pg_stop_backup(false, true);
required for the backup are successfully archived then the
<literal>wait_for_archive</literal> parameter (which defaults to true) can be set
to false to have
- <function>pg_stop_backup</function> return as soon as the stop backup record is
- written to the WAL. By default, <function>pg_stop_backup</function> will wait
+ <function>pg_backup_stop</function> return as soon as the stop backup record is
+ written to the WAL. By default, <function>pg_backup_stop</function> will wait
until all WAL has been archived, which can take some time. This option
must be used with caution: if WAL archiving is not monitored correctly
then the backup might not include all of the WAL files and will
@@ -985,142 +973,6 @@ SELECT * FROM pg_stop_backup(false, true);
</listitem>
</orderedlist>
</para>
- </sect3>
- <sect3 id="backup-lowlevel-base-backup-exclusive">
- <title>Making an Exclusive Low-Level Backup</title>
-
- <note>
- <para>
- The exclusive backup method is deprecated and should be avoided.
- Prior to <productname>PostgreSQL</productname> 9.6, this was the only
- low-level method available, but it is now recommended that all users
- upgrade their scripts to use non-exclusive backups.
- </para>
- </note>
-
- <para>
- The process for an exclusive backup is mostly the same as for a
- non-exclusive one, but it differs in a few key steps. This type of
- backup can only be taken on a primary and does not allow concurrent
- backups. Moreover, because it creates a backup label file, as
- described below, it can block automatic restart of the primary server
- after a crash. On the other hand, the erroneous removal of this
- file from a backup or standby is a common mistake, which can result
- in serious data corruption. If it is necessary to use this method,
- the following steps may be used.
- </para>
- <para>
- <orderedlist>
- <listitem>
- <para>
- Ensure that WAL archiving is enabled and working.
- </para>
- </listitem>
- <listitem>
- <para>
- Connect to the server (it does not matter which database) as a user with
- rights to run pg_start_backup (superuser, or a user who has been granted
- EXECUTE on the function) and issue the command:
-<programlisting>
-SELECT pg_start_backup('label');
-</programlisting>
- where <literal>label</literal> is any string you want to use to uniquely
- identify this backup operation.
- <function>pg_start_backup</function> creates a <firstterm>backup label</firstterm> file,
- called <filename>backup_label</filename>, in the cluster directory with
- information about your backup, including the start time and label string.
- The function also creates a <firstterm>tablespace map</firstterm> file,
- called <filename>tablespace_map</filename>, in the cluster directory with
- information about tablespace symbolic links in <filename>pg_tblspc/</filename> if
- one or more such link is present. Both files are critical to the
- integrity of the backup, should you need to restore from it.
- </para>
-
- <para>
- By default, <function>pg_start_backup</function> can take a long time to finish.
- This is because it performs a checkpoint, and the I/O
- required for the checkpoint will be spread out over a significant
- period of time, by default half your inter-checkpoint interval
- (see the configuration parameter
- <xref linkend="guc-checkpoint-completion-target"/>). This is
- usually what you want, because it minimizes the impact on query
- processing. If you want to start the backup as soon as
- possible, use:
-<programlisting>
-SELECT pg_start_backup('label', true);
-</programlisting>
- This forces the checkpoint to be done as quickly as possible.
- </para>
- </listitem>
- <listitem>
- <para>
- Perform the backup, using any convenient file-system-backup tool
- such as <application>tar</application> or <application>cpio</application> (not
- <application>pg_dump</application> or
- <application>pg_dumpall</application>). It is neither
- necessary nor desirable to stop normal operation of the database
- while you do this. See
- <xref linkend="backup-lowlevel-base-backup-data"/> for things to
- consider during this backup.
- </para>
- <para>
- As noted above, if the server crashes during the backup it may not be
- possible to restart until the <filename>backup_label</filename> file has
- been manually deleted from the <envar>PGDATA</envar> directory. Note
- that it is very important to never remove the
- <filename>backup_label</filename> file when restoring a backup, because
- this will result in corruption. Confusion about when it is appropriate
- to remove this file is a common cause of data corruption when using this
- method; be very certain that you remove the file only on an existing
- primary and never when building a standby or restoring a backup, even if
- you are building a standby that will subsequently be promoted to a new
- primary.
- </para>
- </listitem>
- <listitem>
- <para>
- Again connect to the database as a user with rights to run
- pg_stop_backup (superuser, or a user who has been granted EXECUTE on
- the function), and issue the command:
-<programlisting>
-SELECT pg_stop_backup();
-</programlisting>
- This function terminates backup mode and
- performs an automatic switch to the next WAL segment. The reason for the
- switch is to arrange for the last WAL segment written during the backup
- interval to be ready to archive.
- </para>
- </listitem>
- <listitem>
- <para>
- Once the WAL segment files active during the backup are archived, you are
- done. The file identified by <function>pg_stop_backup</function>'s result is
- the last segment that is required to form a complete set of backup files.
- If <varname>archive_mode</varname> is enabled,
- <function>pg_stop_backup</function> does not return until the last segment has
- been archived.
- Archiving of these files happens automatically since you have
- already configured <varname>archive_command</varname>. In most cases this
- happens quickly, but you are advised to monitor your archive
- system to ensure there are no delays.
- If the archive process has fallen behind
- because of failures of the archive command, it will keep retrying
- until the archive succeeds and the backup is complete.
- </para>
-
- <para>
- When using exclusive backup mode, it is absolutely imperative to ensure
- that <function>pg_stop_backup</function> completes successfully at the
- end of the backup. Even if the backup itself fails, for example due to
- lack of disk space, failure to call <function>pg_stop_backup</function>
- will leave the server in backup mode indefinitely, causing future backups
- to fail and increasing the risk of a restart failure during the time that
- <filename>backup_label</filename> exists.
- </para>
- </listitem>
- </orderedlist>
- </para>
- </sect3>
<sect3 id="backup-lowlevel-base-backup-data">
<title>Backing Up the Data Directory</title>
<para>
@@ -1203,8 +1055,8 @@ SELECT pg_stop_backup();
<para>
The backup label
- file includes the label string you gave to <function>pg_start_backup</function>,
- as well as the time at which <function>pg_start_backup</function> was run, and
+ file includes the label string you gave to <function>pg_backup_start</function>,
+ as well as the time at which <function>pg_backup_start</function> was run, and
the name of the starting WAL file. In case of confusion it is therefore
possible to look inside a backup file and determine exactly which
backup session the dump file came from. The tablespace map file includes
@@ -1218,7 +1070,7 @@ SELECT pg_stop_backup();
<para>
It is also possible to make a backup while the server is
stopped. In this case, you obviously cannot use
- <function>pg_start_backup</function> or <function>pg_stop_backup</function>, and
+ <function>pg_backup_start</function> or <function>pg_backup_stop</function>, and
you will therefore be left to your own devices to keep track of which
backup is which and how far back the associated WAL files go.
It is generally better to follow the continuous archiving procedure above.
@@ -1393,7 +1245,7 @@ restore_command = 'cp /mnt/server/archivedir/%f %p'
<note>
<para>
The stop point must be after the ending time of the base backup, i.e.,
- the end time of <function>pg_stop_backup</function>. You cannot use a base backup
+ the end time of <function>pg_backup_stop</function>. You cannot use a base backup
to recover to a time when that backup was in progress. (To
recover to such a time, you must go back to your previous base backup
and roll forward from there.)
@@ -1513,44 +1365,6 @@ restore_command = 'cp /mnt/server/archivedir/%f %p'
included in the backup automatically, and no special action is
required to restore the backup.
</para>
-
- <para>
- If more flexibility in copying the backup files is needed, a lower
- level process can be used for standalone hot backups as well.
- To prepare for low level standalone hot backups, make sure
- <varname>wal_level</varname> is set to
- <literal>replica</literal> or higher, <varname>archive_mode</varname> to
- <literal>on</literal>, and set up an <varname>archive_library</varname> that performs
- archiving only when a <emphasis>switch file</emphasis> exists. For example:
-<programlisting>
-archive_library = '' # use shell command
-archive_command = 'test ! -f /var/lib/pgsql/backup_in_progress || (test ! -f /var/lib/pgsql/archive/%f && cp %p /var/lib/pgsql/archive/%f)'
-</programlisting>
- This command will perform archiving when
- <filename>/var/lib/pgsql/backup_in_progress</filename> exists, and otherwise
- silently return zero exit status (allowing <productname>PostgreSQL</productname>
- to recycle the unwanted WAL file).
- </para>
-
- <para>
- With this preparation, a backup can be taken using a script like the
- following:
-<programlisting>
-touch /var/lib/pgsql/backup_in_progress
-psql -c "select pg_start_backup('hot_backup');"
-tar -cf /var/lib/pgsql/backup.tar /var/lib/pgsql/data/
-psql -c "select pg_stop_backup();"
-rm /var/lib/pgsql/backup_in_progress
-tar -rf /var/lib/pgsql/backup.tar /var/lib/pgsql/archive/
-</programlisting>
- The switch file <filename>/var/lib/pgsql/backup_in_progress</filename> is
- created first, enabling archiving of completed WAL files to occur.
- After the backup the switch file is removed. Archived WAL files are
- then added to the backup so that both base backup and all required
- WAL files are part of the same <application>tar</application> file.
- Please remember to add error handling to your backup scripts.
- </para>
-
</sect3>
<sect3 id="compressed-archive-logs">
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 8a802fb225..73096708cc 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -25587,9 +25587,8 @@ LOG: Grand total: 1651920 bytes in 201 blocks; 622360 free (88 chunks); 1029560
The functions shown in <xref
linkend="functions-admin-backup-table"/> assist in making on-line backups.
These functions cannot be executed during recovery (except
- non-exclusive <function>pg_start_backup</function>,
- non-exclusive <function>pg_stop_backup</function>,
- <function>pg_is_in_backup</function>, <function>pg_backup_start_time</function>
+ <function>pg_backup_start</function>,
+ <function>pg_backup_stop</function>,
and <function>pg_wal_lsn_diff</function>).
</para>
@@ -25678,13 +25677,12 @@ LOG: Grand total: 1651920 bytes in 201 blocks; 622360 free (88 chunks); 1029560
<row>
<entry role="func_table_entry"><para role="func_signature">
<indexterm>
- <primary>pg_start_backup</primary>
+ <primary>pg_backup_start</primary>
</indexterm>
- <function>pg_start_backup</function> (
+ <function>pg_backup_start</function> (
<parameter>label</parameter> <type>text</type>
<optional>, <parameter>fast</parameter> <type>boolean</type>
- <optional>, <parameter>exclusive</parameter> <type>boolean</type>
- </optional></optional> )
+ </optional> )
<returnvalue>pg_lsn</returnvalue>
</para>
<para>
@@ -25693,23 +25691,9 @@ LOG: Grand total: 1651920 bytes in 201 blocks; 622360 free (88 chunks); 1029560
(Typically this would be the name under which the backup dump file
will be stored.)
If the optional second parameter is given as <literal>true</literal>,
- it specifies executing <function>pg_start_backup</function> as quickly
+ it specifies executing <function>pg_backup_start</function> as quickly
as possible. This forces an immediate checkpoint which will cause a
spike in I/O operations, slowing any concurrently executing queries.
- The optional third parameter specifies whether to perform an exclusive
- or non-exclusive backup (default is exclusive).
- </para>
- <para>
- When used in exclusive mode, this function writes a backup label file
- (<filename>backup_label</filename>) and, if there are any links in
- the <filename>pg_tblspc/</filename> directory, a tablespace map file
- (<filename>tablespace_map</filename>) into the database cluster's data
- directory, then performs a checkpoint, and then returns the backup's
- starting write-ahead log location. (The user can ignore this
- result value, but it is provided in case it is useful.) When used in
- non-exclusive mode, the contents of these files are instead returned
- by the <function>pg_stop_backup</function> function, and should be
- copied to the backup area by the user.
</para>
<para>
This function is restricted to superusers by default, but other users
@@ -25720,11 +25704,10 @@ LOG: Grand total: 1651920 bytes in 201 blocks; 622360 free (88 chunks); 1029560
<row>
<entry role="func_table_entry"><para role="func_signature">
<indexterm>
- <primary>pg_stop_backup</primary>
+ <primary>pg_backup_stop</primary>
</indexterm>
- <function>pg_stop_backup</function> (
- <parameter>exclusive</parameter> <type>boolean</type>
- <optional>, <parameter>wait_for_archive</parameter> <type>boolean</type>
+ <function>pg_backup_stop</function> (
+ <optional><parameter>wait_for_archive</parameter> <type>boolean</type>
</optional> )
<returnvalue>record</returnvalue>
( <parameter>lsn</parameter> <type>pg_lsn</type>,
@@ -25732,24 +25715,19 @@ LOG: Grand total: 1651920 bytes in 201 blocks; 622360 free (88 chunks); 1029560
<parameter>spcmapfile</parameter> <type>text</type> )
</para>
<para>
- Finishes performing an exclusive or non-exclusive on-line backup.
- The <parameter>exclusive</parameter> parameter must match the
- previous <function>pg_start_backup</function> call.
- In an exclusive backup, <function>pg_stop_backup</function> removes
- the backup label file and, if it exists, the tablespace map file
- created by <function>pg_start_backup</function>. In a non-exclusive
- backup, the desired contents of these files are returned as part of
+ Finishes performing an on-line backup. The desired contents of the
+ backup label file and the tablespace map file are returned as part of
the result of the function, and should be written to files in the
backup area (not in the data directory).
</para>
<para>
- There is an optional second parameter of type <type>boolean</type>.
+ There is an optional parameter of type <type>boolean</type>.
If false, the function will return immediately after the backup is
completed, without waiting for WAL to be archived. This behavior is
only useful with backup software that independently monitors WAL
archiving. Otherwise, WAL required to make the backup consistent might
be missing and make the backup useless. By default or when this
- parameter is true, <function>pg_stop_backup</function> will wait for
+ parameter is true, <function>pg_backup_stop</function> will wait for
WAL to be archived when archiving is enabled. (On a standby, this
means that it will wait only when <varname>archive_mode</varname> =
<literal>always</literal>. If write activity on the primary is low,
@@ -25759,7 +25737,7 @@ LOG: Grand total: 1651920 bytes in 201 blocks; 622360 free (88 chunks); 1029560
<para>
When executed on a primary, this function also creates a backup
history file in the write-ahead log archive area. The history file
- includes the label given to <function>pg_start_backup</function>, the
+ includes the label given to <function>pg_backup_start</function>, the
starting and ending write-ahead log locations for the backup, and the
starting and ending times of the backup. After recording the ending
location, the current write-ahead log insertion point is automatically
@@ -25771,8 +25749,7 @@ LOG: Grand total: 1651920 bytes in 201 blocks; 622360 free (88 chunks); 1029560
The result of the function is a single record.
The <parameter>lsn</parameter> column holds the backup's ending
write-ahead log location (which again can be ignored). The second and
- third columns are <literal>NULL</literal> when ending an exclusive
- backup; after a non-exclusive backup they hold the desired contents of
+ third columns hold the desired contents of
the label and tablespace map files.
</para>
<para>
@@ -25781,50 +25758,6 @@ LOG: Grand total: 1651920 bytes in 201 blocks; 622360 free (88 chunks); 1029560
</para></entry>
</row>
- <row>
- <entry role="func_table_entry"><para role="func_signature">
- <function>pg_stop_backup</function> ()
- <returnvalue>pg_lsn</returnvalue>
- </para>
- <para>
- Finishes performing an exclusive on-line backup. This simplified
- version is equivalent to <literal>pg_stop_backup(true,
- true)</literal>, except that it only returns the <type>pg_lsn</type>
- result.
- </para>
- <para>
- This function is restricted to superusers by default, but other users
- can be granted EXECUTE to run the function.
- </para></entry>
- </row>
-
- <row>
- <entry role="func_table_entry"><para role="func_signature">
- <indexterm>
- <primary>pg_is_in_backup</primary>
- </indexterm>
- <function>pg_is_in_backup</function> ()
- <returnvalue>boolean</returnvalue>
- </para>
- <para>
- Returns true if an on-line exclusive backup is in progress.
- </para></entry>
- </row>
-
- <row>
- <entry role="func_table_entry"><para role="func_signature">
- <indexterm>
- <primary>pg_backup_start_time</primary>
- </indexterm>
- <function>pg_backup_start_time</function> ()
- <returnvalue>timestamp with time zone</returnvalue>
- </para>
- <para>
- Returns the start time of the current on-line exclusive backup if one
- is in progress, otherwise <literal>NULL</literal>.
- </para></entry>
- </row>
-
<row>
<entry role="func_table_entry"><para role="func_signature">
<indexterm>
@@ -25922,7 +25855,7 @@ LOG: Grand total: 1651920 bytes in 201 blocks; 622360 free (88 chunks); 1029560
corresponding write-ahead log file name and byte offset from
a <type>pg_lsn</type> value. For example:
<programlisting>
-postgres=# SELECT * FROM pg_walfile_name_offset(pg_stop_backup());
+postgres=# SELECT * FROM pg_walfile_name_offset((pg_backup_stop()).lsn);
file_name | file_offset
--------------------------+-------------
00000001000000000000000D | 4039624
diff --git a/doc/src/sgml/high-availability.sgml b/doc/src/sgml/high-availability.sgml
index b5b6042104..1f0ba66943 100644
--- a/doc/src/sgml/high-availability.sgml
+++ b/doc/src/sgml/high-availability.sgml
@@ -1361,8 +1361,8 @@ synchronous_standby_names = 'ANY 2 (s1, s2, s3)'
<para>
If you need to re-create a standby server while transactions are
- waiting, make sure that the commands pg_start_backup() and
- pg_stop_backup() are run in a session with
+ waiting, make sure that the commands pg_backup_start() and
+ pg_backup_stop() are run in a session with
<varname>synchronous_commit</varname> = <literal>off</literal>, otherwise those
requests will wait forever for the standby to appear.
</para>
@@ -2159,7 +2159,7 @@ HINT: You can then restart the server after making the necessary configuration
<para>
WAL file control commands will not work during recovery,
- e.g., <function>pg_start_backup</function>, <function>pg_switch_wal</function> etc.
+ e.g., <function>pg_backup_start</function>, <function>pg_switch_wal</function> etc.
</para>
<para>
diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
index 9fb62fec8e..0320ce7078 100644
--- a/doc/src/sgml/monitoring.sgml
+++ b/doc/src/sgml/monitoring.sgml
@@ -6661,7 +6661,7 @@ SELECT pg_stat_get_backend_pid(s.backendid) AS pid,
<entry><literal>waiting for checkpoint to finish</literal></entry>
<entry>
The WAL sender process is currently performing
- <function>pg_start_backup</function> to prepare to
+ <function>pg_backup_start</function> to prepare to
take a base backup, and waiting for the start-of-backup
checkpoint to finish.
</entry>
@@ -6684,7 +6684,7 @@ SELECT pg_stat_get_backend_pid(s.backendid) AS pid,
<entry><literal>waiting for wal archiving to finish</literal></entry>
<entry>
The WAL sender process is currently performing
- <function>pg_stop_backup</function> to finish the backup,
+ <function>pg_backup_stop</function> to finish the backup,
and waiting for all the WAL files required for the base backup
to be successfully archived.
If either <literal>--wal-method=none</literal> or
diff --git a/doc/src/sgml/ref/pgupgrade.sgml b/doc/src/sgml/ref/pgupgrade.sgml
index 729c886ac0..3fbe141456 100644
--- a/doc/src/sgml/ref/pgupgrade.sgml
+++ b/doc/src/sgml/ref/pgupgrade.sgml
@@ -618,7 +618,7 @@ rsync --archive --delete --hard-links --size-only --no-inc-recursive /vol1/pg_tb
<para>
Configure the servers for log shipping. (You do not need to run
- <function>pg_start_backup()</function> and <function>pg_stop_backup()</function>
+ <function>pg_backup_start()</function> and <function>pg_backup_stop()</function>
or take a file system backup as the standbys are still synchronized
with the primary.)
</para>
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 0d2bd7a357..d5032118d3 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -384,29 +384,6 @@ typedef union WALInsertLockPadded
char pad[PG_CACHE_LINE_SIZE];
} WALInsertLockPadded;
-/*
- * State of an exclusive backup, necessary to control concurrent activities
- * across sessions when working on exclusive backups.
- *
- * EXCLUSIVE_BACKUP_NONE means that there is no exclusive backup actually
- * running, to be more precise pg_start_backup() is not being executed for
- * an exclusive backup and there is no exclusive backup in progress.
- * EXCLUSIVE_BACKUP_STARTING means that pg_start_backup() is starting an
- * exclusive backup.
- * EXCLUSIVE_BACKUP_IN_PROGRESS means that pg_start_backup() has finished
- * running and an exclusive backup is in progress. pg_stop_backup() is
- * needed to finish it.
- * EXCLUSIVE_BACKUP_STOPPING means that pg_stop_backup() is stopping an
- * exclusive backup.
- */
-typedef enum ExclusiveBackupState
-{
- EXCLUSIVE_BACKUP_NONE = 0,
- EXCLUSIVE_BACKUP_STARTING,
- EXCLUSIVE_BACKUP_IN_PROGRESS,
- EXCLUSIVE_BACKUP_STOPPING
-} ExclusiveBackupState;
-
/*
* Session status of running backup, used for sanity checks in SQL-callable
* functions to start and stop backups.
@@ -455,15 +432,12 @@ typedef struct XLogCtlInsert
bool fullPageWrites;
/*
- * exclusiveBackupState indicates the state of an exclusive backup (see
- * comments of ExclusiveBackupState for more details). nonExclusiveBackups
- * is a counter indicating the number of streaming base backups currently
- * in progress. forcePageWrites is set to true when either of these is
- * non-zero. lastBackupStart is the latest checkpoint redo location used
- * as a starting point for an online backup.
+ * runningBackups is a counter indicating the number of backups currently in
+ * progress. forcePageWrites is set to true when runningBackups is non-zero.
+ * lastBackupStart is the latest checkpoint redo location used as a starting
+ * point for an online backup.
*/
- ExclusiveBackupState exclusiveBackupState;
- int nonExclusiveBackups;
+ int runningBackups;
XLogRecPtr lastBackupStart;
/*
@@ -695,8 +669,7 @@ static void ReadControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow);
-static void pg_start_backup_callback(int code, Datum arg);
-static void pg_stop_backup_callback(int code, Datum arg);
+static void pg_backup_start_callback(int code, Datum arg);
static int get_sync_bit(int method);
@@ -5313,7 +5286,7 @@ StartupXLOG(void)
* Ran off end of WAL before reaching end-of-backup WAL record, or
* minRecoveryPoint. That's usually a bad sign, indicating that you
* tried to recover from an online backup but never called
- * pg_stop_backup(), or you didn't archive all the WAL up to that
+ * pg_backup_stop(), or you didn't archive all the WAL up to that
* point. However, this also happens in crash recovery, if the system
* crashes while an online backup is in progress. We must not treat
* that as an error, or the database will refuse to start up.
@@ -5327,7 +5300,7 @@ StartupXLOG(void)
else if (!XLogRecPtrIsInvalid(ControlFile->backupStartPoint))
ereport(FATAL,
(errmsg("WAL ends before end of online backup"),
- errhint("Online backup started with pg_start_backup() must be ended with pg_stop_backup(), and all WAL up to that point must be available at recovery.")));
+ errhint("Online backup started with pg_backup_start() must be ended with pg_backup_stop(), and all WAL up to that point must be available at recovery.")));
else
ereport(FATAL,
(errmsg("WAL ends before consistent recovery point")));
@@ -7008,7 +6981,7 @@ CreateRestartPoint(int flags)
* Ensure minRecoveryPoint is past the checkpoint record. Normally,
* this will have happened already while writing out dirty buffers,
* but not necessarily - e.g. because no buffers were dirtied. We do
- * this because a non-exclusive base backup uses minRecoveryPoint to
+ * this because a backup performed in recovery uses minRecoveryPoint to
* determine which WAL files must be included in the backup, and the
* file (or files) containing the checkpoint record must be included,
* at a minimum. Note that for an ordinary restart of recovery there's
@@ -7812,7 +7785,7 @@ xlog_redo(XLogReaderState *record)
/*
* Update the LSN of the last replayed XLOG_FPW_CHANGE record so that
- * do_pg_start_backup() and do_pg_stop_backup() can check whether
+ * do_pg_backup_start() and do_pg_backup_stop() can check whether
* full_page_writes has been disabled during online backup.
*/
if (!fpw)
@@ -8011,29 +7984,14 @@ issue_xlog_fsync(int fd, XLogSegNo segno, TimeLineID tli)
}
/*
- * do_pg_start_backup
- *
- * Utility function called at the start of an online backup. It creates the
- * necessary starting checkpoint and constructs the backup label file.
- *
- * There are two kind of backups: exclusive and non-exclusive. An exclusive
- * backup is started with pg_start_backup(), and there can be only one active
- * at a time. The backup and tablespace map files of an exclusive backup are
- * written to $PGDATA/backup_label and $PGDATA/tablespace_map, and they are
- * removed by pg_stop_backup().
- *
- * A non-exclusive backup is used for the streaming base backups (see
- * src/backend/replication/basebackup.c). The difference to exclusive backups
- * is that the backup label and tablespace map files are not written to disk.
- * Instead, their would-be contents are returned in *labelfile and *tblspcmapfile,
- * and the caller is responsible for including them in the backup archive as
- * 'backup_label' and 'tablespace_map'. There can be many non-exclusive backups
- * active at the same time, and they don't conflict with an exclusive backup
- * either.
- *
- * labelfile and tblspcmapfile must be passed as NULL when starting an
- * exclusive backup, and as initially-empty StringInfos for a non-exclusive
- * backup.
+ * do_pg_backup_start is the workhorse of the user-visible pg_backup_start()
+ * function. It creates the necessary starting checkpoint and constructs the
+ * backup label and tablespace map.
+ *
+ * The backup label and tablespace map contents are returned in *labelfile and
+ * *tblspcmapfile, and the caller is responsible for including them in the
+ * backup archive as 'backup_label' and 'tablespace_map'. There can be many
+ * backups active at the same time.
*
* If "tablespaces" isn't NULL, it receives a list of tablespaceinfo structs
* describing the cluster's tablespaces.
@@ -8045,18 +8003,17 @@ issue_xlog_fsync(int fd, XLogSegNo segno, TimeLineID tli)
* Returns the minimum WAL location that must be present to restore from this
* backup, and the corresponding timeline ID in *starttli_p.
*
- * Every successfully started non-exclusive backup must be stopped by calling
- * do_pg_stop_backup() or do_pg_abort_backup().
+ * Every successfully started backup must be stopped by calling
+ * do_pg_backup_stop() or do_pg_abort_backup().
*
* It is the responsibility of the caller of this function to verify the
* permissions of the calling user!
*/
XLogRecPtr
-do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
+do_pg_backup_start(const char *backupidstr, bool fast, TimeLineID *starttli_p,
StringInfo labelfile, List **tablespaces,
StringInfo tblspcmapfile)
{
- bool exclusive = (labelfile == NULL);
bool backup_started_in_recovery = false;
XLogRecPtr checkpointloc;
XLogRecPtr startpoint;
@@ -8065,20 +8022,9 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
char strfbuf[128];
char xlogfilename[MAXFNAMELEN];
XLogSegNo _logSegNo;
- struct stat stat_buf;
- FILE *fp;
backup_started_in_recovery = RecoveryInProgress();
- /*
- * Currently only non-exclusive backup can be taken during recovery.
- */
- if (backup_started_in_recovery && exclusive)
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("recovery is in progress"),
- errhint("WAL control functions cannot be executed during recovery.")));
-
/*
* During recovery, we don't need to check WAL level. Because, if WAL
* level is not sufficient, it's impossible to get here during recovery.
@@ -8117,30 +8063,12 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
* XLogInsertRecord().
*/
WALInsertLockAcquireExclusive();
- if (exclusive)
- {
- /*
- * At first, mark that we're now starting an exclusive backup, to
- * ensure that there are no other sessions currently running
- * pg_start_backup() or pg_stop_backup().
- */
- if (XLogCtl->Insert.exclusiveBackupState != EXCLUSIVE_BACKUP_NONE)
- {
- WALInsertLockRelease();
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("a backup is already in progress"),
- errhint("Run pg_stop_backup() and try again.")));
- }
- XLogCtl->Insert.exclusiveBackupState = EXCLUSIVE_BACKUP_STARTING;
- }
- else
- XLogCtl->Insert.nonExclusiveBackups++;
+ XLogCtl->Insert.runningBackups++;
XLogCtl->Insert.forcePageWrites = true;
WALInsertLockRelease();
/* Ensure we release forcePageWrites if fail below */
- PG_ENSURE_ERROR_CLEANUP(pg_start_backup_callback, (Datum) BoolGetDatum(exclusive));
+ PG_ENSURE_ERROR_CLEANUP(pg_backup_start_callback, (Datum) 0);
{
bool gotUniqueStartpoint = false;
DIR *tblspcdir;
@@ -8152,7 +8080,7 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
* Force an XLOG file switch before the checkpoint, to ensure that the
* WAL segment the checkpoint is written to doesn't contain pages with
* old timeline IDs. That would otherwise happen if you called
- * pg_start_backup() right after restoring from a PITR archive: the
+ * pg_backup_start() right after restoring from a PITR archive: the
* first WAL segment containing the startup checkpoint has pages in
* the beginning with the old timeline ID. That can cause trouble at
* recovery: we won't have a history file covering the old timeline if
@@ -8187,7 +8115,7 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
* means that two successive backup runs can have same checkpoint
* positions.
*
- * Since the fact that we are executing do_pg_start_backup()
+ * Since the fact that we are executing do_pg_backup_start()
* during recovery means that checkpointer is running, we can use
* RequestCheckpoint() to establish a restartpoint.
*
@@ -8375,122 +8303,19 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
LSN_FORMAT_ARGS(startpoint), xlogfilename);
appendStringInfo(labelfile, "CHECKPOINT LOCATION: %X/%X\n",
LSN_FORMAT_ARGS(checkpointloc));
- appendStringInfo(labelfile, "BACKUP METHOD: %s\n",
- exclusive ? "pg_start_backup" : "streamed");
+ appendStringInfo(labelfile, "BACKUP METHOD: streamed\n");
appendStringInfo(labelfile, "BACKUP FROM: %s\n",
backup_started_in_recovery ? "standby" : "primary");
appendStringInfo(labelfile, "START TIME: %s\n", strfbuf);
appendStringInfo(labelfile, "LABEL: %s\n", backupidstr);
appendStringInfo(labelfile, "START TIMELINE: %u\n", starttli);
-
- /*
- * Okay, write the file, or return its contents to caller.
- */
- if (exclusive)
- {
- /*
- * Check for existing backup label --- implies a backup is already
- * running. (XXX given that we checked exclusiveBackupState
- * above, maybe it would be OK to just unlink any such label
- * file?)
- */
- if (stat(BACKUP_LABEL_FILE, &stat_buf) != 0)
- {
- if (errno != ENOENT)
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not stat file \"%s\": %m",
- BACKUP_LABEL_FILE)));
- }
- else
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("a backup is already in progress"),
- errhint("If you're sure there is no backup in progress, remove file \"%s\" and try again.",
- BACKUP_LABEL_FILE)));
-
- fp = AllocateFile(BACKUP_LABEL_FILE, "w");
-
- if (!fp)
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not create file \"%s\": %m",
- BACKUP_LABEL_FILE)));
- if (fwrite(labelfile->data, labelfile->len, 1, fp) != 1 ||
- fflush(fp) != 0 ||
- pg_fsync(fileno(fp)) != 0 ||
- ferror(fp) ||
- FreeFile(fp))
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not write file \"%s\": %m",
- BACKUP_LABEL_FILE)));
- /* Allocated locally for exclusive backups, so free separately */
- pfree(labelfile->data);
- pfree(labelfile);
-
- /* Write backup tablespace_map file. */
- if (tblspcmapfile->len > 0)
- {
- if (stat(TABLESPACE_MAP, &stat_buf) != 0)
- {
- if (errno != ENOENT)
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not stat file \"%s\": %m",
- TABLESPACE_MAP)));
- }
- else
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("a backup is already in progress"),
- errhint("If you're sure there is no backup in progress, remove file \"%s\" and try again.",
- TABLESPACE_MAP)));
-
- fp = AllocateFile(TABLESPACE_MAP, "w");
-
- if (!fp)
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not create file \"%s\": %m",
- TABLESPACE_MAP)));
- if (fwrite(tblspcmapfile->data, tblspcmapfile->len, 1, fp) != 1 ||
- fflush(fp) != 0 ||
- pg_fsync(fileno(fp)) != 0 ||
- ferror(fp) ||
- FreeFile(fp))
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not write file \"%s\": %m",
- TABLESPACE_MAP)));
- }
-
- /* Allocated locally for exclusive backups, so free separately */
- pfree(tblspcmapfile->data);
- pfree(tblspcmapfile);
- }
}
- PG_END_ENSURE_ERROR_CLEANUP(pg_start_backup_callback, (Datum) BoolGetDatum(exclusive));
+ PG_END_ENSURE_ERROR_CLEANUP(pg_backup_start_callback, (Datum) 0);
/*
- * Mark that start phase has correctly finished for an exclusive backup.
- * Session-level locks are updated as well to reflect that state.
- *
- * Note that CHECK_FOR_INTERRUPTS() must not occur while updating backup
- * counters and session-level lock. Otherwise they can be updated
- * inconsistently, and which might cause do_pg_abort_backup() to fail.
+ * Mark that the start phase has correctly finished for the backup.
*/
- if (exclusive)
- {
- WALInsertLockAcquireExclusive();
- XLogCtl->Insert.exclusiveBackupState = EXCLUSIVE_BACKUP_IN_PROGRESS;
-
- /* Set session-level lock */
- sessionBackupState = SESSION_BACKUP_EXCLUSIVE;
- WALInsertLockRelease();
- }
- else
- sessionBackupState = SESSION_BACKUP_NON_EXCLUSIVE;
+ sessionBackupState = SESSION_BACKUP_RUNNING;
/*
* We're done. As a convenience, return the starting WAL location.
@@ -8500,47 +8325,19 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
return startpoint;
}
-/* Error cleanup callback for pg_start_backup */
+/* Error cleanup callback for pg_backup_start */
static void
-pg_start_backup_callback(int code, Datum arg)
+pg_backup_start_callback(int code, Datum arg)
{
- bool exclusive = DatumGetBool(arg);
-
/* Update backup counters and forcePageWrites on failure */
WALInsertLockAcquireExclusive();
- if (exclusive)
- {
- Assert(XLogCtl->Insert.exclusiveBackupState == EXCLUSIVE_BACKUP_STARTING);
- XLogCtl->Insert.exclusiveBackupState = EXCLUSIVE_BACKUP_NONE;
- }
- else
- {
- Assert(XLogCtl->Insert.nonExclusiveBackups > 0);
- XLogCtl->Insert.nonExclusiveBackups--;
- }
- if (XLogCtl->Insert.exclusiveBackupState == EXCLUSIVE_BACKUP_NONE &&
- XLogCtl->Insert.nonExclusiveBackups == 0)
- {
- XLogCtl->Insert.forcePageWrites = false;
- }
- WALInsertLockRelease();
-}
+ Assert(XLogCtl->Insert.runningBackups > 0);
+ XLogCtl->Insert.runningBackups--;
-/*
- * Error cleanup callback for pg_stop_backup
- */
-static void
-pg_stop_backup_callback(int code, Datum arg)
-{
- bool exclusive = DatumGetBool(arg);
-
- /* Update backup status on failure */
- WALInsertLockAcquireExclusive();
- if (exclusive)
+ if (XLogCtl->Insert.runningBackups == 0)
{
- Assert(XLogCtl->Insert.exclusiveBackupState == EXCLUSIVE_BACKUP_STOPPING);
- XLogCtl->Insert.exclusiveBackupState = EXCLUSIVE_BACKUP_IN_PROGRESS;
+ XLogCtl->Insert.forcePageWrites = false;
}
WALInsertLockRelease();
}
@@ -8555,14 +8352,11 @@ get_backup_status(void)
}
/*
- * do_pg_stop_backup
+ * do_pg_backup_stop
*
* Utility function called at the end of an online backup. It cleans up the
* backup state and can optionally wait for WAL segments to be archived.
*
- * If labelfile is NULL, this stops an exclusive backup. Otherwise this stops
- * the non-exclusive backup specified by 'labelfile'.
- *
* Returns the last WAL location that must be present to restore from this
* backup, and the corresponding timeline ID in *stoptli_p.
*
@@ -8570,9 +8364,8 @@ get_backup_status(void)
* permissions of the calling user!
*/
XLogRecPtr
-do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
+do_pg_backup_stop(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
{
- bool exclusive = (labelfile == NULL);
bool backup_started_in_recovery = false;
XLogRecPtr startpoint;
XLogRecPtr stoppoint;
@@ -8586,7 +8379,6 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
char histfilename[MAXFNAMELEN];
char backupfrom[20];
XLogSegNo _logSegNo;
- FILE *lfp;
FILE *fp;
char ch;
int seconds_before_warning;
@@ -8599,15 +8391,6 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
backup_started_in_recovery = RecoveryInProgress();
- /*
- * Currently only non-exclusive backup can be taken during recovery.
- */
- if (backup_started_in_recovery && exclusive)
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("recovery is in progress"),
- errhint("WAL control functions cannot be executed during recovery.")));
-
/*
* During recovery, we don't need to check WAL level. Because, if WAL
* level is not sufficient, it's impossible to get here during recovery.
@@ -8618,106 +8401,23 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
errmsg("WAL level not sufficient for making an online backup"),
errhint("wal_level must be set to \"replica\" or \"logical\" at server start.")));
- if (exclusive)
- {
- /*
- * At first, mark that we're now stopping an exclusive backup, to
- * ensure that there are no other sessions currently running
- * pg_start_backup() or pg_stop_backup().
- */
- WALInsertLockAcquireExclusive();
- if (XLogCtl->Insert.exclusiveBackupState != EXCLUSIVE_BACKUP_IN_PROGRESS)
- {
- WALInsertLockRelease();
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("exclusive backup not in progress")));
- }
- XLogCtl->Insert.exclusiveBackupState = EXCLUSIVE_BACKUP_STOPPING;
- WALInsertLockRelease();
-
- /*
- * Remove backup_label. In case of failure, the state for an exclusive
- * backup is switched back to in-progress.
- */
- PG_ENSURE_ERROR_CLEANUP(pg_stop_backup_callback, (Datum) BoolGetDatum(exclusive));
- {
- /*
- * Read the existing label file into memory.
- */
- struct stat statbuf;
- int r;
-
- if (stat(BACKUP_LABEL_FILE, &statbuf))
- {
- /* should not happen per the upper checks */
- if (errno != ENOENT)
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not stat file \"%s\": %m",
- BACKUP_LABEL_FILE)));
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("a backup is not in progress")));
- }
-
- lfp = AllocateFile(BACKUP_LABEL_FILE, "r");
- if (!lfp)
- {
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not read file \"%s\": %m",
- BACKUP_LABEL_FILE)));
- }
- labelfile = palloc(statbuf.st_size + 1);
- r = fread(labelfile, statbuf.st_size, 1, lfp);
- labelfile[statbuf.st_size] = '\0';
-
- /*
- * Close and remove the backup label file
- */
- if (r != 1 || ferror(lfp) || FreeFile(lfp))
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not read file \"%s\": %m",
- BACKUP_LABEL_FILE)));
- durable_unlink(BACKUP_LABEL_FILE, ERROR);
-
- /*
- * Remove tablespace_map file if present, it is created only if
- * there are tablespaces.
- */
- durable_unlink(TABLESPACE_MAP, DEBUG1);
- }
- PG_END_ENSURE_ERROR_CLEANUP(pg_stop_backup_callback, (Datum) BoolGetDatum(exclusive));
- }
-
/*
- * OK to update backup counters, forcePageWrites and session-level lock.
+ * OK to update backup counters, forcePageWrites, and session-level lock.
*
* Note that CHECK_FOR_INTERRUPTS() must not occur while updating them.
* Otherwise they can be updated inconsistently, and which might cause
* do_pg_abort_backup() to fail.
*/
WALInsertLockAcquireExclusive();
- if (exclusive)
- {
- XLogCtl->Insert.exclusiveBackupState = EXCLUSIVE_BACKUP_NONE;
- }
- else
- {
- /*
- * The user-visible pg_start/stop_backup() functions that operate on
- * exclusive backups can be called at any time, but for non-exclusive
- * backups, it is expected that each do_pg_start_backup() call is
- * matched by exactly one do_pg_stop_backup() call.
- */
- Assert(XLogCtl->Insert.nonExclusiveBackups > 0);
- XLogCtl->Insert.nonExclusiveBackups--;
- }
- if (XLogCtl->Insert.exclusiveBackupState == EXCLUSIVE_BACKUP_NONE &&
- XLogCtl->Insert.nonExclusiveBackups == 0)
+ /*
+ * It is expected that each do_pg_backup_start() call is matched by exactly
+ * one do_pg_backup_stop() call.
+ */
+ Assert(XLogCtl->Insert.runningBackups > 0);
+ XLogCtl->Insert.runningBackups--;
+
+ if (XLogCtl->Insert.runningBackups == 0)
{
XLogCtl->Insert.forcePageWrites = false;
}
@@ -8975,17 +8675,13 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
/*
* do_pg_abort_backup: abort a running backup
*
- * This does just the most basic steps of do_pg_stop_backup(), by taking the
+ * This does just the most basic steps of do_pg_backup_stop(), by taking the
* system out of backup mode, thus making it a lot more safe to call from
* an error handler.
*
* The caller can pass 'arg' as 'true' or 'false' to control whether a warning
* is emitted.
*
- * NB: This is only for aborting a non-exclusive backup that doesn't write
- * backup_label. A backup started with pg_start_backup() needs to be finished
- * with pg_stop_backup().
- *
* NB: This gets used as a before_shmem_exit handler, hence the odd-looking
* signature.
*/
@@ -8995,18 +8691,16 @@ do_pg_abort_backup(int code, Datum arg)
bool emit_warning = DatumGetBool(arg);
/*
- * Quick exit if session is not keeping around a non-exclusive backup
- * already started.
+ * Quick exit if session does not have a running backup.
*/
- if (sessionBackupState != SESSION_BACKUP_NON_EXCLUSIVE)
+ if (sessionBackupState != SESSION_BACKUP_RUNNING)
return;
WALInsertLockAcquireExclusive();
- Assert(XLogCtl->Insert.nonExclusiveBackups > 0);
- XLogCtl->Insert.nonExclusiveBackups--;
+ Assert(XLogCtl->Insert.runningBackups > 0);
+ XLogCtl->Insert.runningBackups--;
- if (XLogCtl->Insert.exclusiveBackupState == EXCLUSIVE_BACKUP_NONE &&
- XLogCtl->Insert.nonExclusiveBackups == 0)
+ if (XLogCtl->Insert.runningBackups == 0)
{
XLogCtl->Insert.forcePageWrites = false;
}
@@ -9014,7 +8708,7 @@ do_pg_abort_backup(int code, Datum arg)
if (emit_warning)
ereport(WARNING,
- (errmsg("aborting backup due to backend exiting before pg_stop_backup was called")));
+ (errmsg("aborting backup due to backend exiting before pg_backup_stop was called")));
}
/*
@@ -9074,87 +8768,6 @@ GetOldestRestartPoint(XLogRecPtr *oldrecptr, TimeLineID *oldtli)
LWLockRelease(ControlFileLock);
}
-/*
- * BackupInProgress: check if online backup mode is active
- *
- * This is done by checking for existence of the "backup_label" file.
- */
-bool
-BackupInProgress(void)
-{
- struct stat stat_buf;
-
- return (stat(BACKUP_LABEL_FILE, &stat_buf) == 0);
-}
-
-/*
- * CancelBackup: rename the "backup_label" and "tablespace_map"
- * files to cancel backup mode
- *
- * If the "backup_label" file exists, it will be renamed to "backup_label.old".
- * Similarly, if the "tablespace_map" file exists, it will be renamed to
- * "tablespace_map.old".
- *
- * Note that this will render an online backup in progress
- * useless. To correctly finish an online backup, pg_stop_backup must be
- * called.
- */
-void
-CancelBackup(void)
-{
- struct stat stat_buf;
-
- /* if the backup_label file is not there, return */
- if (stat(BACKUP_LABEL_FILE, &stat_buf) < 0)
- return;
-
- /* remove leftover file from previously canceled backup if it exists */
- unlink(BACKUP_LABEL_OLD);
-
- if (durable_rename(BACKUP_LABEL_FILE, BACKUP_LABEL_OLD, DEBUG1) != 0)
- {
- ereport(WARNING,
- (errcode_for_file_access(),
- errmsg("online backup mode was not canceled"),
- errdetail("File \"%s\" could not be renamed to \"%s\": %m.",
- BACKUP_LABEL_FILE, BACKUP_LABEL_OLD)));
- return;
- }
-
- /* if the tablespace_map file is not there, return */
- if (stat(TABLESPACE_MAP, &stat_buf) < 0)
- {
- ereport(LOG,
- (errmsg("online backup mode canceled"),
- errdetail("File \"%s\" was renamed to \"%s\".",
- BACKUP_LABEL_FILE, BACKUP_LABEL_OLD)));
- return;
- }
-
- /* remove leftover file from previously canceled backup if it exists */
- unlink(TABLESPACE_MAP_OLD);
-
- if (durable_rename(TABLESPACE_MAP, TABLESPACE_MAP_OLD, DEBUG1) == 0)
- {
- ereport(LOG,
- (errmsg("online backup mode canceled"),
- errdetail("Files \"%s\" and \"%s\" were renamed to "
- "\"%s\" and \"%s\", respectively.",
- BACKUP_LABEL_FILE, TABLESPACE_MAP,
- BACKUP_LABEL_OLD, TABLESPACE_MAP_OLD)));
- }
- else
- {
- ereport(WARNING,
- (errcode_for_file_access(),
- errmsg("online backup mode canceled"),
- errdetail("File \"%s\" was renamed to \"%s\", but "
- "file \"%s\" could not be renamed to \"%s\": %m.",
- BACKUP_LABEL_FILE, BACKUP_LABEL_OLD,
- TABLESPACE_MAP, TABLESPACE_MAP_OLD)));
- }
-}
-
/* Thin wrapper around ShutdownWalRcv(). */
void
XLogShutdownWalRcv(void)
diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c
index 2752be63c1..b61ae6c0b4 100644
--- a/src/backend/access/transam/xlogfuncs.c
+++ b/src/backend/access/transam/xlogfuncs.c
@@ -39,13 +39,13 @@
#include "utils/tuplestore.h"
/*
- * Store label file and tablespace map during non-exclusive backups.
+ * Store label file and tablespace map during backups.
*/
static StringInfo label_file;
static StringInfo tblspc_map_file;
/*
- * pg_start_backup: set up for taking an on-line backup dump
+ * pg_backup_start: set up for taking an on-line backup dump
*
* Essentially what this does is to create a backup label file in $PGDATA,
* where it will be archived as part of the backup dump. The label file
@@ -57,105 +57,44 @@ static StringInfo tblspc_map_file;
* GRANT system.
*/
Datum
-pg_start_backup(PG_FUNCTION_ARGS)
+pg_backup_start(PG_FUNCTION_ARGS)
{
text *backupid = PG_GETARG_TEXT_PP(0);
bool fast = PG_GETARG_BOOL(1);
- bool exclusive = PG_GETARG_BOOL(2);
char *backupidstr;
XLogRecPtr startpoint;
SessionBackupState status = get_backup_status();
+ MemoryContext oldcontext;
backupidstr = text_to_cstring(backupid);
- if (status == SESSION_BACKUP_NON_EXCLUSIVE)
+ if (status == SESSION_BACKUP_RUNNING)
ereport(ERROR,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("a backup is already in progress in this session")));
- if (exclusive)
- {
- startpoint = do_pg_start_backup(backupidstr, fast, NULL, NULL,
- NULL, NULL);
- }
- else
- {
- MemoryContext oldcontext;
-
- /*
- * Label file and tablespace map file need to be long-lived, since
- * they are read in pg_stop_backup.
- */
- oldcontext = MemoryContextSwitchTo(TopMemoryContext);
- label_file = makeStringInfo();
- tblspc_map_file = makeStringInfo();
- MemoryContextSwitchTo(oldcontext);
+ /*
+ * Label file and tablespace map file need to be long-lived, since
+ * they are read in pg_backup_stop.
+ */
+ oldcontext = MemoryContextSwitchTo(TopMemoryContext);
+ label_file = makeStringInfo();
+ tblspc_map_file = makeStringInfo();
+ MemoryContextSwitchTo(oldcontext);
- register_persistent_abort_backup_handler();
+ register_persistent_abort_backup_handler();
- startpoint = do_pg_start_backup(backupidstr, fast, NULL, label_file,
- NULL, tblspc_map_file);
- }
+ startpoint = do_pg_backup_start(backupidstr, fast, NULL, label_file,
+ NULL, tblspc_map_file);
PG_RETURN_LSN(startpoint);
}
-/*
- * pg_stop_backup: finish taking an on-line backup dump
- *
- * We write an end-of-backup WAL record, and remove the backup label file
- * created by pg_start_backup, creating a backup history file in pg_wal
- * instead (whence it will immediately be archived). The backup history file
- * contains the same info found in the label file, plus the backup-end time
- * and WAL location. Before 9.0, the backup-end time was read from the backup
- * history file at the beginning of archive recovery, but we now use the WAL
- * record for that and the file is for informational and debug purposes only.
- *
- * Note: different from CancelBackup which just cancels online backup mode.
- *
- * Note: this version is only called to stop an exclusive backup. The function
- * pg_stop_backup_v2 (overloaded as pg_stop_backup in SQL) is called to
- * stop non-exclusive backups.
- *
- * Permission checking for this function is managed through the normal
- * GRANT system.
- */
-Datum
-pg_stop_backup(PG_FUNCTION_ARGS)
-{
- XLogRecPtr stoppoint;
- SessionBackupState status = get_backup_status();
-
- if (status == SESSION_BACKUP_NON_EXCLUSIVE)
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("non-exclusive backup in progress"),
- errhint("Did you mean to use pg_stop_backup('f')?")));
-
- /*
- * Exclusive backups were typically started in a different connection, so
- * don't try to verify that status of backup is set to
- * SESSION_BACKUP_EXCLUSIVE in this function. Actual verification that an
- * exclusive backup is in fact running is handled inside
- * do_pg_stop_backup.
- */
- stoppoint = do_pg_stop_backup(NULL, true, NULL);
-
- PG_RETURN_LSN(stoppoint);
-}
-
/*
- * pg_stop_backup_v2: finish taking exclusive or nonexclusive on-line backup.
- *
- * Works the same as pg_stop_backup, except for non-exclusive backups it returns
- * the backup label and tablespace map files as text fields in as part of the
- * resultset.
+ * pg_backup_stop: finish taking an on-line backup.
*
- * The first parameter (variable 'exclusive') allows the user to tell us if
- * this is an exclusive or a non-exclusive backup.
- *
- * The second parameter (variable 'waitforarchive'), which is optional,
+ * The first parameter (variable 'waitforarchive'), which is optional,
* allows the user to choose if they want to wait for the WAL to be archived
* or if we should just return as soon as the WAL record is written.
*
@@ -163,15 +102,14 @@ pg_stop_backup(PG_FUNCTION_ARGS)
* GRANT system.
*/
Datum
-pg_stop_backup_v2(PG_FUNCTION_ARGS)
+pg_backup_stop(PG_FUNCTION_ARGS)
{
#define PG_STOP_BACKUP_V2_COLS 3
TupleDesc tupdesc;
Datum values[PG_STOP_BACKUP_V2_COLS];
bool nulls[PG_STOP_BACKUP_V2_COLS];
- bool exclusive = PG_GETARG_BOOL(0);
- bool waitforarchive = PG_GETARG_BOOL(1);
+ bool waitforarchive = PG_GETARG_BOOL(0);
XLogRecPtr stoppoint;
SessionBackupState status = get_backup_status();
@@ -182,51 +120,29 @@ pg_stop_backup_v2(PG_FUNCTION_ARGS)
MemSet(values, 0, sizeof(values));
MemSet(nulls, 0, sizeof(nulls));
- if (exclusive)
- {
- if (status == SESSION_BACKUP_NON_EXCLUSIVE)
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("non-exclusive backup in progress"),
- errhint("Did you mean to use pg_stop_backup('f')?")));
-
- /*
- * Stop the exclusive backup, and since we're in an exclusive backup
- * return NULL for both backup_label and tablespace_map.
- */
- stoppoint = do_pg_stop_backup(NULL, waitforarchive, NULL);
-
- nulls[1] = true;
- nulls[2] = true;
- }
- else
- {
- if (status != SESSION_BACKUP_NON_EXCLUSIVE)
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("non-exclusive backup is not in progress"),
- errhint("Did you mean to use pg_stop_backup('t')?")));
+ if (status != SESSION_BACKUP_RUNNING)
+ ereport(ERROR,
+ (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ errmsg("backup is not in progress"),
+ errhint("Did you call pg_backup_start()?")));
- /*
- * Stop the non-exclusive backup. Return a copy of the backup label
- * and tablespace map so they can be written to disk by the caller.
- */
- stoppoint = do_pg_stop_backup(label_file->data, waitforarchive, NULL);
-
- values[1] = CStringGetTextDatum(label_file->data);
- values[2] = CStringGetTextDatum(tblspc_map_file->data);
-
- /* Free structures allocated in TopMemoryContext */
- pfree(label_file->data);
- pfree(label_file);
- label_file = NULL;
- pfree(tblspc_map_file->data);
- pfree(tblspc_map_file);
- tblspc_map_file = NULL;
- }
+ /*
+ * Stop the backup. Return a copy of the backup label and tablespace map so
+ * they can be written to disk by the caller.
+ */
+ stoppoint = do_pg_backup_stop(label_file->data, waitforarchive, NULL);
- /* Stoppoint is included on both exclusive and nonexclusive backups */
values[0] = LSNGetDatum(stoppoint);
+ values[1] = CStringGetTextDatum(label_file->data);
+ values[2] = CStringGetTextDatum(tblspc_map_file->data);
+
+ /* Free structures allocated in TopMemoryContext */
+ pfree(label_file->data);
+ pfree(label_file);
+ label_file = NULL;
+ pfree(tblspc_map_file->data);
+ pfree(tblspc_map_file);
+ tblspc_map_file = NULL;
/* Returns the record as Datum */
PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
@@ -298,7 +214,7 @@ pg_create_restore_point(PG_FUNCTION_ARGS)
}
/*
- * Report the current WAL write location (same format as pg_start_backup etc)
+ * Report the current WAL write location (same format as pg_backup_start etc)
*
* This is useful for determining how much of WAL is visible to an external
* archiving process. Note that the data before this point is written out
@@ -321,7 +237,7 @@ pg_current_wal_lsn(PG_FUNCTION_ARGS)
}
/*
- * Report the current WAL insert location (same format as pg_start_backup etc)
+ * Report the current WAL insert location (same format as pg_backup_start etc)
*
* This function is mostly for debugging purposes.
*/
@@ -342,7 +258,7 @@ pg_current_wal_insert_lsn(PG_FUNCTION_ARGS)
}
/*
- * Report the current WAL flush location (same format as pg_start_backup etc)
+ * Report the current WAL flush location (same format as pg_backup_start etc)
*
* This function is mostly for debugging purposes.
*/
@@ -363,7 +279,7 @@ pg_current_wal_flush_lsn(PG_FUNCTION_ARGS)
}
/*
- * Report the last WAL receive location (same format as pg_start_backup etc)
+ * Report the last WAL receive location (same format as pg_backup_start etc)
*
* This is useful for determining how much of WAL is guaranteed to be received
* and synced to disk by walreceiver.
@@ -382,7 +298,7 @@ pg_last_wal_receive_lsn(PG_FUNCTION_ARGS)
}
/*
- * Report the last WAL replay location (same format as pg_start_backup etc)
+ * Report the last WAL replay location (same format as pg_backup_start etc)
*
* This is useful for determining how much of WAL is visible to read-only
* connections during recovery.
@@ -402,7 +318,7 @@ pg_last_wal_replay_lsn(PG_FUNCTION_ARGS)
/*
* Compute an xlog file name and decimal byte offset given a WAL location,
- * such as is returned by pg_stop_backup() or pg_switch_wal().
+ * such as is returned by pg_backup_stop() or pg_switch_wal().
*
* Note that a location exactly at a segment boundary is taken to be in
* the previous segment. This is usually the right thing, since the
@@ -470,7 +386,7 @@ pg_walfile_name_offset(PG_FUNCTION_ARGS)
/*
* Compute an xlog file name given a WAL location,
- * such as is returned by pg_stop_backup() or pg_switch_wal().
+ * such as is returned by pg_backup_stop() or pg_switch_wal().
*/
Datum
pg_walfile_name(PG_FUNCTION_ARGS)
@@ -645,81 +561,6 @@ pg_wal_lsn_diff(PG_FUNCTION_ARGS)
PG_RETURN_NUMERIC(result);
}
-/*
- * Returns bool with current on-line backup mode, a global state.
- */
-Datum
-pg_is_in_backup(PG_FUNCTION_ARGS)
-{
- PG_RETURN_BOOL(BackupInProgress());
-}
-
-/*
- * Returns start time of an online exclusive backup.
- *
- * When there's no exclusive backup in progress, the function
- * returns NULL.
- */
-Datum
-pg_backup_start_time(PG_FUNCTION_ARGS)
-{
- Datum xtime;
- FILE *lfp;
- char fline[MAXPGPATH];
- char backup_start_time[30];
-
- /*
- * See if label file is present
- */
- lfp = AllocateFile(BACKUP_LABEL_FILE, "r");
- if (lfp == NULL)
- {
- if (errno != ENOENT)
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not read file \"%s\": %m",
- BACKUP_LABEL_FILE)));
- PG_RETURN_NULL();
- }
-
- /*
- * Parse the file to find the START TIME line.
- */
- backup_start_time[0] = '\0';
- while (fgets(fline, sizeof(fline), lfp) != NULL)
- {
- if (sscanf(fline, "START TIME: %25[^\n]\n", backup_start_time) == 1)
- break;
- }
-
- /* Check for a read error. */
- if (ferror(lfp))
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not read file \"%s\": %m", BACKUP_LABEL_FILE)));
-
- /* Close the backup label file. */
- if (FreeFile(lfp))
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not close file \"%s\": %m", BACKUP_LABEL_FILE)));
-
- if (strlen(backup_start_time) == 0)
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("invalid data in file \"%s\"", BACKUP_LABEL_FILE)));
-
- /*
- * Convert the time string read from file to TimestampTz form.
- */
- xtime = DirectFunctionCall3(timestamptz_in,
- CStringGetDatum(backup_start_time),
- ObjectIdGetDatum(InvalidOid),
- Int32GetDatum(-1));
-
- PG_RETURN_DATUM(xtime);
-}
-
/*
* Promotes a standby server.
*
diff --git a/src/backend/access/transam/xlogrecovery.c b/src/backend/access/transam/xlogrecovery.c
index f9f212680b..d2b5e7f32c 100644
--- a/src/backend/access/transam/xlogrecovery.c
+++ b/src/backend/access/transam/xlogrecovery.c
@@ -1966,7 +1966,7 @@ xlogrecovery_redo(XLogReaderState *record, TimeLineID replayTLI)
{
/*
* We have reached the end of base backup, the point where
- * pg_stop_backup() was done. The data on disk is now consistent
+ * pg_backup_stop() was done. The data on disk is now consistent
* (assuming we have also reached minRecoveryPoint). Set
* backupEndPoint to the current LSN, so that the next call to
* CheckRecoveryConsistency() will notice it and do the
diff --git a/src/backend/catalog/system_functions.sql b/src/backend/catalog/system_functions.sql
index 81bac6f581..6ae4388d3f 100644
--- a/src/backend/catalog/system_functions.sql
+++ b/src/backend/catalog/system_functions.sql
@@ -377,14 +377,14 @@ BEGIN ATOMIC
END;
CREATE OR REPLACE FUNCTION
- pg_start_backup(label text, fast boolean DEFAULT false, exclusive boolean DEFAULT true)
- RETURNS pg_lsn STRICT VOLATILE LANGUAGE internal AS 'pg_start_backup'
+ pg_backup_start(label text, fast boolean DEFAULT false)
+ RETURNS pg_lsn STRICT VOLATILE LANGUAGE internal AS 'pg_backup_start'
PARALLEL RESTRICTED;
-CREATE OR REPLACE FUNCTION pg_stop_backup (
- exclusive boolean, wait_for_archive boolean DEFAULT true,
- OUT lsn pg_lsn, OUT labelfile text, OUT spcmapfile text)
- RETURNS record STRICT VOLATILE LANGUAGE internal as 'pg_stop_backup_v2'
+CREATE OR REPLACE FUNCTION pg_backup_stop (
+ wait_for_archive boolean DEFAULT true, OUT lsn pg_lsn,
+ OUT labelfile text, OUT spcmapfile text)
+ RETURNS record STRICT VOLATILE LANGUAGE internal as 'pg_backup_stop'
PARALLEL RESTRICTED;
CREATE OR REPLACE FUNCTION
@@ -603,11 +603,9 @@ AS 'unicode_is_normalized';
-- available to superuser / cluster owner, if they choose.
--
-REVOKE EXECUTE ON FUNCTION pg_start_backup(text, boolean, boolean) FROM public;
+REVOKE EXECUTE ON FUNCTION pg_backup_start(text, boolean) FROM public;
-REVOKE EXECUTE ON FUNCTION pg_stop_backup() FROM public;
-
-REVOKE EXECUTE ON FUNCTION pg_stop_backup(boolean, boolean) FROM public;
+REVOKE EXECUTE ON FUNCTION pg_backup_stop(boolean) FROM public;
REVOKE EXECUTE ON FUNCTION pg_create_restore_point(text) FROM public;
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index 80bb269599..b6767ed72e 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -348,7 +348,6 @@ static PMState pmState = PM_INIT;
typedef enum
{
ALLOW_ALL_CONNS, /* normal not-shutting-down state */
- ALLOW_SUPERUSER_CONNS, /* only superusers can connect */
ALLOW_NO_CONNS /* no new connections allowed, period */
} ConnsAllowedState;
@@ -2546,19 +2545,11 @@ canAcceptConnections(int backend_type)
/*
* "Smart shutdown" restrictions are applied only to normal connections,
- * not to autovac workers or bgworkers. When only superusers can connect,
- * we return CAC_SUPERUSER to indicate that superuserness must be checked
- * later. Note that neither CAC_OK nor CAC_SUPERUSER can safely be
- * returned until we have checked for too many children.
+ * not to autovac workers or bgworkers.
*/
if (connsAllowed != ALLOW_ALL_CONNS &&
backend_type == BACKEND_TYPE_NORMAL)
- {
- if (connsAllowed == ALLOW_SUPERUSER_CONNS)
- result = CAC_SUPERUSER; /* allow superusers only */
- else
- return CAC_SHUTDOWN; /* shutdown is pending */
- }
+ return CAC_SHUTDOWN; /* shutdown is pending */
/*
* Don't start too many children.
@@ -2877,16 +2868,11 @@ pmdie(SIGNAL_ARGS)
#endif
/*
- * If we reached normal running, we have to wait for any online
- * backup mode to end; otherwise go straight to waiting for client
- * backends to exit. (The difference is that in the former state,
- * we'll still let in new superuser clients, so that somebody can
- * end the online backup mode.) If already in PM_STOP_BACKENDS or
+ * If we reached normal running, we go straight to waiting for
+ * client backends to exit. If already in PM_STOP_BACKENDS or
* a later state, do not change it.
*/
- if (pmState == PM_RUN)
- connsAllowed = ALLOW_SUPERUSER_CONNS;
- else if (pmState == PM_HOT_STANDBY)
+ if (pmState == PM_RUN || pmState == PM_HOT_STANDBY)
connsAllowed = ALLOW_NO_CONNS;
else if (pmState == PM_STARTUP || pmState == PM_RECOVERY)
{
@@ -3842,16 +3828,6 @@ PostmasterStateMachine(void)
/* If we're doing a smart shutdown, try to advance that state. */
if (pmState == PM_RUN || pmState == PM_HOT_STANDBY)
{
- if (connsAllowed == ALLOW_SUPERUSER_CONNS)
- {
- /*
- * ALLOW_SUPERUSER_CONNS state ends as soon as online backup mode
- * is not active.
- */
- if (!BackupInProgress())
- connsAllowed = ALLOW_NO_CONNS;
- }
-
if (connsAllowed == ALLOW_NO_CONNS)
{
/*
@@ -4044,18 +4020,6 @@ PostmasterStateMachine(void)
}
else
{
- /*
- * Terminate exclusive backup mode to avoid recovery after a clean
- * fast shutdown. Since an exclusive backup can only be taken
- * during normal running (and not, for example, while running
- * under Hot Standby) it only makes sense to do this if we reached
- * normal running. If we're still in recovery, the backup file is
- * one we're recovering *from*, and we must keep it around so that
- * recovery restarts from the right place.
- */
- if (ReachedNormalRunning)
- CancelBackup();
-
/*
* Normal exit from the postmaster is here. We don't need to log
* anything here, since the UnlinkLockFiles proc_exit callback
diff --git a/src/backend/replication/basebackup.c b/src/backend/replication/basebackup.c
index 2378ce5c5e..b12ffb4529 100644
--- a/src/backend/replication/basebackup.c
+++ b/src/backend/replication/basebackup.c
@@ -196,10 +196,8 @@ static const struct exclude_list_item excludeFiles[] =
{RELCACHE_INIT_FILENAME, true},
/*
- * If there's a backup_label or tablespace_map file, it belongs to a
- * backup started by the user with pg_start_backup(). It is *not* correct
- * for this backup. Our backup_label/tablespace_map is injected into the
- * tar separately.
+ * backup_label and tablespace_map should not exist in in a running cluster
+ * capable of doing an online backup, but exclude then just in case.
*/
{BACKUP_LABEL_FILE, false},
{TABLESPACE_MAP, false},
@@ -276,16 +274,16 @@ perform_base_backup(basebackup_options *opt, bbsink *sink)
total_checksum_failures = 0;
basebackup_progress_wait_checkpoint();
- state.startptr = do_pg_start_backup(opt->label, opt->fastcheckpoint,
+ state.startptr = do_pg_backup_start(opt->label, opt->fastcheckpoint,
&state.starttli,
labelfile, &state.tablespaces,
tblspc_map_file);
/*
- * Once do_pg_start_backup has been called, ensure that any failure causes
+ * Once do_pg_backup_start has been called, ensure that any failure causes
* us to abort the backup so we don't "leak" a backup counter. For this
- * reason, *all* functionality between do_pg_start_backup() and the end of
- * do_pg_stop_backup() should be inside the error cleanup block!
+ * reason, *all* functionality between do_pg_backup_start() and the end of
+ * do_pg_backup_stop() should be inside the error cleanup block!
*/
PG_ENSURE_ERROR_CLEANUP(do_pg_abort_backup, BoolGetDatum(false));
@@ -406,7 +404,7 @@ perform_base_backup(basebackup_options *opt, bbsink *sink)
}
basebackup_progress_wait_wal_archive(&state);
- endptr = do_pg_stop_backup(labelfile->data, !opt->nowait, &endtli);
+ endptr = do_pg_backup_stop(labelfile->data, !opt->nowait, &endtli);
}
PG_END_ENSURE_ERROR_CLEANUP(do_pg_abort_backup, BoolGetDatum(false));
@@ -969,7 +967,7 @@ parse_basebackup_options(List *options, basebackup_options *opt)
/*
* SendBaseBackup() - send a complete base backup.
*
- * The function will put the system into backup mode like pg_start_backup()
+ * The function will put the system into backup mode like pg_backup_start()
* does, so that the backup is consistent even though we read directly from
* the filesystem, bypassing the buffer cache.
*/
@@ -1230,7 +1228,7 @@ sendDir(bbsink *sink, const char *path, int basepathlen, bool sizeonly,
* error in that case. The error handler further up will call
* do_pg_abort_backup() for us. Also check that if the backup was
* started while still in recovery, the server wasn't promoted.
- * do_pg_stop_backup() will check that too, but it's better to stop
+ * do_pg_backup_stop() will check that too, but it's better to stop
* the backup early than continue to the end and fail there.
*/
CHECK_FOR_INTERRUPTS();
diff --git a/src/bin/pg_basebackup/t/010_pg_basebackup.pl b/src/bin/pg_basebackup/t/010_pg_basebackup.pl
index 8cb8cfe045..c7c01a0992 100644
--- a/src/bin/pg_basebackup/t/010_pg_basebackup.pl
+++ b/src/bin/pg_basebackup/t/010_pg_basebackup.pl
@@ -185,6 +185,10 @@ isnt(slurp_file("$tempdir/backup/backup_label"),
'DONOTCOPY', 'existing backup_label not copied');
rmtree("$tempdir/backup");
+# Now delete the bogus backup_label file since it will interfere with startup
+unlink("$pgdata/backup_label")
+ or BAIL_OUT("unable to unlink $pgdata/backup_label");
+
$node->command_ok(
[
@pg_basebackup_defs, '-D',
diff --git a/src/bin/pg_ctl/pg_ctl.c b/src/bin/pg_ctl/pg_ctl.c
index 3c182c97d4..ee3fa148b6 100644
--- a/src/bin/pg_ctl/pg_ctl.c
+++ b/src/bin/pg_ctl/pg_ctl.c
@@ -1069,7 +1069,7 @@ do_stop(void)
get_control_dbstate() != DB_IN_ARCHIVE_RECOVERY)
{
print_msg(_("WARNING: online backup mode is active\n"
- "Shutdown will not complete until pg_stop_backup() is called.\n\n"));
+ "Shutdown will not complete until pg_backup_stop() is called.\n\n"));
}
print_msg(_("waiting for server to shut down..."));
@@ -1145,7 +1145,7 @@ do_restart(void)
get_control_dbstate() != DB_IN_ARCHIVE_RECOVERY)
{
print_msg(_("WARNING: online backup mode is active\n"
- "Shutdown will not complete until pg_stop_backup() is called.\n\n"));
+ "Shutdown will not complete until pg_backup_stop() is called.\n\n"));
}
print_msg(_("waiting for server to shut down..."));
diff --git a/src/bin/pg_rewind/filemap.c b/src/bin/pg_rewind/filemap.c
index 7211090f47..fb52debf7a 100644
--- a/src/bin/pg_rewind/filemap.c
+++ b/src/bin/pg_rewind/filemap.c
@@ -140,9 +140,9 @@ static const struct exclude_list_item excludeFiles[] =
{"pg_internal.init", true}, /* defined as RELCACHE_INIT_FILENAME */
/*
- * If there's a backup_label or tablespace_map file, it belongs to a
- * backup started by the user with pg_start_backup(). It is *not* correct
- * for this backup. Our backup_label is written later on separately.
+ * If there is a backup_label or tablespace_map file, it indicates that
+ * a recovery failed and this cluster probably can't be rewound, but
+ * exclude them anyway if they are found.
*/
{"backup_label", false}, /* defined as BACKUP_LABEL_FILE */
{"tablespace_map", false}, /* defined as TABLESPACE_MAP */
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index 4b45ac64db..be375df248 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -275,14 +275,13 @@ extern void XLogShutdownWalRcv(void);
typedef enum SessionBackupState
{
SESSION_BACKUP_NONE,
- SESSION_BACKUP_EXCLUSIVE,
- SESSION_BACKUP_NON_EXCLUSIVE
+ SESSION_BACKUP_RUNNING,
} SessionBackupState;
-extern XLogRecPtr do_pg_start_backup(const char *backupidstr, bool fast,
+extern XLogRecPtr do_pg_backup_start(const char *backupidstr, bool fast,
TimeLineID *starttli_p, StringInfo labelfile,
List **tablespaces, StringInfo tblspcmapfile);
-extern XLogRecPtr do_pg_stop_backup(char *labelfile, bool waitforarchive,
+extern XLogRecPtr do_pg_backup_stop(char *labelfile, bool waitforarchive,
TimeLineID *stoptli_p);
extern void do_pg_abort_backup(int code, Datum arg);
extern void register_persistent_abort_backup_handler(void);
diff --git a/src/include/catalog/pg_control.h b/src/include/catalog/pg_control.h
index 1f3dc24ac1..3d075fcef3 100644
--- a/src/include/catalog/pg_control.h
+++ b/src/include/catalog/pg_control.h
@@ -163,7 +163,7 @@ typedef struct ControlFileData
* from a backup, and must see a backup-end record before we can safely
* start up. If it's false, but backupStartPoint is set, a backup_label
* file was found at startup but it may have been a leftover from a stray
- * pg_start_backup() call, not accompanied by pg_stop_backup().
+ * pg_backup_start() call, not accompanied by pg_backup_stop().
*/
XLogRecPtr minRecoveryPoint;
TimeLineID minRecoveryPointTLI;
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index d8e8715ed1..8563714c9c 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -6268,26 +6268,16 @@
proargtypes => 'int4 int8', proargnames => '{pid,timeout}',
prosrc => 'pg_terminate_backend' },
{ oid => '2172', descr => 'prepare for taking an online backup',
- proname => 'pg_start_backup', provolatile => 'v', proparallel => 'r',
- prorettype => 'pg_lsn', proargtypes => 'text bool bool',
- prosrc => 'pg_start_backup' },
-{ oid => '2173', descr => 'finish taking an online backup',
- proname => 'pg_stop_backup', provolatile => 'v', proparallel => 'r',
- prorettype => 'pg_lsn', proargtypes => '', prosrc => 'pg_stop_backup' },
+ proname => 'pg_backup_start', provolatile => 'v', proparallel => 'r',
+ prorettype => 'pg_lsn', proargtypes => 'text bool',
+ prosrc => 'pg_backup_start' },
{ oid => '2739', descr => 'finish taking an online backup',
- proname => 'pg_stop_backup', provolatile => 'v', proparallel => 'r',
- prorettype => 'record', proargtypes => 'bool bool',
- proallargtypes => '{bool,bool,pg_lsn,text,text}',
- proargmodes => '{i,i,o,o,o}',
- proargnames => '{exclusive,wait_for_archive,lsn,labelfile,spcmapfile}',
- prosrc => 'pg_stop_backup_v2' },
-{ oid => '3813', descr => 'true if server is in online backup',
- proname => 'pg_is_in_backup', provolatile => 'v', prorettype => 'bool',
- proargtypes => '', prosrc => 'pg_is_in_backup' },
-{ oid => '3814', descr => 'start time of an online backup',
- proname => 'pg_backup_start_time', provolatile => 's',
- prorettype => 'timestamptz', proargtypes => '',
- prosrc => 'pg_backup_start_time' },
+ proname => 'pg_backup_stop', provolatile => 'v', proparallel => 'r',
+ prorettype => 'record', proargtypes => 'bool',
+ proallargtypes => '{bool,pg_lsn,text,text}',
+ proargmodes => '{i,o,o,o}',
+ proargnames => '{wait_for_archive,lsn,labelfile,spcmapfile}',
+ prosrc => 'pg_backup_stop' },
{ oid => '3436', descr => 'promote standby server',
proname => 'pg_promote', provolatile => 'v', prorettype => 'bool',
proargtypes => 'bool int4', proargnames => '{wait,wait_seconds}',
diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h
index 0abc3ad540..9321d7f264 100644
--- a/src/include/miscadmin.h
+++ b/src/include/miscadmin.h
@@ -481,10 +481,6 @@ extern void process_session_preload_libraries(void);
extern void pg_bindtextdomain(const char *domain);
extern bool has_rolreplication(Oid roleid);
-/* in access/transam/xlog.c */
-extern bool BackupInProgress(void);
-extern void CancelBackup(void);
-
/* in executor/nodeHash.c */
extern size_t get_hash_memory_limit(void);
diff --git a/src/test/perl/PostgreSQL/Test/Cluster.pm b/src/test/perl/PostgreSQL/Test/Cluster.pm
index 4db52bc936..e1316abf3f 100644
--- a/src/test/perl/PostgreSQL/Test/Cluster.pm
+++ b/src/test/perl/PostgreSQL/Test/Cluster.pm
@@ -635,25 +635,6 @@ sub backup
return;
}
-=item $node->backup_fs_hot(backup_name)
-
-Create a backup with a filesystem level copy in subdirectory B<backup_name> of
-B<< $node->backup_dir >>, including WAL.
-
-Archiving must be enabled, as B<pg_start_backup()> and B<pg_stop_backup()> are
-used. This is not checked or enforced.
-
-The backup name is passed as the backup label to B<pg_start_backup()>.
-
-=cut
-
-sub backup_fs_hot
-{
- my ($self, $backup_name) = @_;
- $self->_backup_fs($backup_name, 1);
- return;
-}
-
=item $node->backup_fs_cold(backup_name)
Create a backup with a filesystem level copy in subdirectory B<backup_name> of
@@ -667,53 +648,18 @@ Use B<backup> or B<backup_fs_hot> if you want to back up a running server.
sub backup_fs_cold
{
my ($self, $backup_name) = @_;
- $self->_backup_fs($backup_name, 0);
- return;
-}
-
-
-# Common sub of backup_fs_hot and backup_fs_cold
-sub _backup_fs
-{
- my ($self, $backup_name, $hot) = @_;
- my $backup_path = $self->backup_dir . '/' . $backup_name;
- my $port = $self->port;
- my $name = $self->name;
-
- print "# Taking filesystem backup $backup_name from node \"$name\"\n";
-
- if ($hot)
- {
- my $stdout = $self->safe_psql('postgres',
- "SELECT * FROM pg_start_backup('$backup_name');");
- print "# pg_start_backup: $stdout\n";
- }
PostgreSQL::Test::RecursiveCopy::copypath(
$self->data_dir,
- $backup_path,
+ $self->backup_dir . '/' . $backup_name,
filterfn => sub {
my $src = shift;
return ($src ne 'log' and $src ne 'postmaster.pid');
});
- if ($hot)
- {
-
- # We ignore pg_stop_backup's return value. We also assume archiving
- # is enabled; otherwise the caller will have to copy the remaining
- # segments.
- my $stdout =
- $self->safe_psql('postgres', 'SELECT * FROM pg_stop_backup();');
- print "# pg_stop_backup: $stdout\n";
- }
-
- print "# Backup finished\n";
return;
}
-
-
=pod
=item $node->init_from_backup(root_node, backup_name)
diff --git a/src/test/recovery/t/010_logical_decoding_timelines.pl b/src/test/recovery/t/010_logical_decoding_timelines.pl
index 01ff31e61f..135fb1a72d 100644
--- a/src/test/recovery/t/010_logical_decoding_timelines.pl
+++ b/src/test/recovery/t/010_logical_decoding_timelines.pl
@@ -69,7 +69,9 @@ $node_primary->safe_psql('dropme',
$node_primary->safe_psql('postgres', 'CHECKPOINT;');
my $backup_name = 'b1';
-$node_primary->backup_fs_hot($backup_name);
+$node_primary->stop();
+$node_primary->backup_fs_cold($backup_name);
+$node_primary->start();
$node_primary->safe_psql('postgres',
q[SELECT pg_create_physical_replication_slot('phys_slot');]);
--
2.25.1
On 03/10/22 19:38, Nathan Bossart wrote:
On Thu, Mar 10, 2022 at 07:13:14PM -0500, Chapman Flack wrote:
+postgres=# SELECT * FROM pg_walfile_name_offset((pg_backup_stop()).lsn);
Ah, good catch. I made this change in v7. I considered doing something
v7 looks good to me. I have repeated the installcheck-world and given
the changed documentation sections one last read-through, and will
change the status to RfC.
Regards,
-Chap
On Fri, Mar 11, 2022 at 02:00:37PM -0500, Chapman Flack wrote:
v7 looks good to me. I have repeated the installcheck-world and given
the changed documentation sections one last read-through, and will
change the status to RfC.
Thanks for reviewing!
--
Nathan Bossart
Amazon Web Services: https://aws.amazon.com
Greetings,
* Nathan Bossart (nathandbossart@gmail.com) wrote:
On Thu, Mar 10, 2022 at 07:13:14PM -0500, Chapman Flack wrote:
Looks like this change to an example in func.sgml is not quite right:
-postgres=# SELECT * FROM pg_walfile_name_offset(pg_stop_backup()); +postgres=# SELECT * FROM pg_walfile_name_offset(pg_backup_stop());pg_backup_stop returns a record now, not just lsn. So this works for me:
+postgres=# SELECT * FROM pg_walfile_name_offset((pg_backup_stop()).lsn);
Ah, good catch. I made this change in v7. I considered doing something
like thisSELECT w.* FROM pg_backup_stop() b, pg_walfile_name_offset(b.lsn) w;
but I think your suggestion is simpler.
I tend to agree. More below.
Subject: [PATCH v7 1/1] remove exclusive backup mode diff --git a/doc/src/sgml/backup.sgml b/doc/src/sgml/backup.sgml index 0d69851bb1..c8b914c1aa 100644 --- a/doc/src/sgml/backup.sgml +++ b/doc/src/sgml/backup.sgml @@ -881,19 +873,19 @@ test ! -f /mnt/server/archivedir/00000001000000A900000065 && cp pg_wal/0 <listitem> <para> Connect to the server (it does not matter which database) as a user with - rights to run pg_start_backup (superuser, or a user who has been granted + rights to run pg_backup_start (superuser, or a user who has been granted EXECUTE on the function) and issue the command: <programlisting> -SELECT pg_start_backup('label', false, false); +SELECT pg_backup_start(label => 'label', fast => false); </programlisting> where <literal>label</literal> is any string you want to use to uniquely identify this backup operation. The connection - calling <function>pg_start_backup</function> must be maintained until the end of + calling <function>pg_backup_start</function> must be maintained until the end of the backup, or the backup will be automatically aborted. </para><para> - By default, <function>pg_start_backup</function> can take a long time to finish. + By default, <function>pg_backup_start</function> can take a long time to finish. This is because it performs a checkpoint, and the I/O required for the checkpoint will be spread out over a significant period of time, by default half your inter-checkpoint interval
Hrmpf. Not this patch's fault, but the default isn't 'half your
inter-checkpoint interval' anymore (checkpoint_completion_target was
changed to 0.9 ... let's not discuss who did that and missed fixing
this). Overall though, maybe we should reword this to avoid having to
remember to change it again if we ever change the completion target
again? Also it seems to imply that pg_backup_start is going to run its
own independent checkpoint or something, which isn't the typical case.
I generally explain what is going on here like this:
By default, <function>pg_backup_start</function> will wait for the next
checkpoint to complete (see ref: checkpoint_timeout ... maybe also
wal-configuration.html).
@@ -937,7 +925,7 @@ SELECT * FROM pg_stop_backup(false, true); ready to archive. </para> <para> - The <function>pg_stop_backup</function> will return one row with three + The <function>pg_backup_stop</function> will return one row with three values. The second of these fields should be written to a file named <filename>backup_label</filename> in the root directory of the backup. The third field should be written to a file named
I get that we have <function> and </function>, but those are just
formatting and don't show up in the actual text, and so it ends up
being:
The pg_backup_stop will return
Which doesn't sound quite right to me. I'd say we either drop 'The' or
add 'function' after. I realize that this patch is mostly doing a
s/pg_stop_backup/pg_backup_stop/, but, still.
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml index 8a802fb225..73096708cc 100644 --- a/doc/src/sgml/func.sgml +++ b/doc/src/sgml/func.sgml @@ -25732,24 +25715,19 @@ LOG: Grand total: 1651920 bytes in 201 blocks; 622360 free (88 chunks); 1029560 <parameter>spcmapfile</parameter> <type>text</type> ) </para> <para> - Finishes performing an exclusive or non-exclusive on-line backup. - The <parameter>exclusive</parameter> parameter must match the - previous <function>pg_start_backup</function> call. - In an exclusive backup, <function>pg_stop_backup</function> removes - the backup label file and, if it exists, the tablespace map file - created by <function>pg_start_backup</function>. In a non-exclusive - backup, the desired contents of these files are returned as part of + Finishes performing an on-line backup. The desired contents of the + backup label file and the tablespace map file are returned as part of the result of the function, and should be written to files in the backup area (not in the data directory). </para>
Given that this is a crucial part, which the exclusive mode has wrong,
I'd be a bit more forceful about it, eg:
The contents of the backup label file and the tablespace map file must
be stored as part of the backup and must NOT be stored in the live data
directory (doing so will cause PostgreSQL to fail to restart in the
event of a crash).
@@ -25771,8 +25749,7 @@ LOG: Grand total: 1651920 bytes in 201 blocks; 622360 free (88 chunks); 1029560 The result of the function is a single record. The <parameter>lsn</parameter> column holds the backup's ending write-ahead log location (which again can be ignored). The second and - third columns are <literal>NULL</literal> when ending an exclusive - backup; after a non-exclusive backup they hold the desired contents of + third columns hold the desired contents of the label and tablespace map files. </para> <para>
I dislike saying 'desired' here as if it's something that we're nicely
asking but maybe isn't a big deal, and just saying 'label' isn't good
since we call it 'backup label' elsewhere and we should try hard to be
consistent and clear. How about:
The second column returns the contents of the backup label file, the
third column returns the contents of the tablespace map file. These
must be stored as part of the backup and are required as part of the
restore process.
diff --git a/src/bin/pg_ctl/pg_ctl.c b/src/bin/pg_ctl/pg_ctl.c index 3c182c97d4..ee3fa148b6 100644 --- a/src/bin/pg_ctl/pg_ctl.c +++ b/src/bin/pg_ctl/pg_ctl.c @@ -1069,7 +1069,7 @@ do_stop(void) get_control_dbstate() != DB_IN_ARCHIVE_RECOVERY) { print_msg(_("WARNING: online backup mode is active\n" - "Shutdown will not complete until pg_stop_backup() is called.\n\n")); + "Shutdown will not complete until pg_backup_stop() is called.\n\n")); }print_msg(_("waiting for server to shut down...")); @@ -1145,7 +1145,7 @@ do_restart(void) get_control_dbstate() != DB_IN_ARCHIVE_RECOVERY) { print_msg(_("WARNING: online backup mode is active\n" - "Shutdown will not complete until pg_stop_backup() is called.\n\n")); + "Shutdown will not complete until pg_backup_stop() is called.\n\n")); }print_msg(_("waiting for server to shut down..."));
This... can't actually happen anymore, right? Shouldn't we just pull
all of this out?
On a once-over of the rest of the code, I definitely like how much we're
able to simplify things in this area and remove various hacks in things
like pg_basebackup and pg_rewind where we previously had to worry about
backup_label and tablespace_map files being in a live data directory.
I'm planning to spend more time on this and hopefully be able to get it
in for v15.
Thanks!
Stephen
On Mon, Mar 28, 2022 at 04:30:27PM -0400, Stephen Frost wrote:
- By default, <function>pg_start_backup</function> can take a long time to finish. + By default, <function>pg_backup_start</function> can take a long time to finish. This is because it performs a checkpoint, and the I/O required for the checkpoint will be spread out over a significant period of time, by default half your inter-checkpoint intervalHrmpf. Not this patch's fault, but the default isn't 'half your
inter-checkpoint interval' anymore (checkpoint_completion_target was
changed to 0.9 ... let's not discuss who did that and missed fixing
this). Overall though, maybe we should reword this to avoid having to
remember to change it again if we ever change the completion target
again? Also it seems to imply that pg_backup_start is going to run its
own independent checkpoint or something, which isn't the typical case.
I generally explain what is going on here like this:By default, <function>pg_backup_start</function> will wait for the next
checkpoint to complete (see ref: checkpoint_timeout ... maybe also
wal-configuration.html).
done
- The <function>pg_stop_backup</function> will return one row with three + The <function>pg_backup_stop</function> will return one row with three values. The second of these fields should be written to a file named <filename>backup_label</filename> in the root directory of the backup. The third field should be written to a file namedI get that we have <function> and </function>, but those are just
formatting and don't show up in the actual text, and so it ends up
being:The pg_backup_stop will return
Which doesn't sound quite right to me. I'd say we either drop 'The' or
add 'function' after. I realize that this patch is mostly doing a
s/pg_stop_backup/pg_backup_stop/, but, still.
done
- Finishes performing an exclusive or non-exclusive on-line backup. - The <parameter>exclusive</parameter> parameter must match the - previous <function>pg_start_backup</function> call. - In an exclusive backup, <function>pg_stop_backup</function> removes - the backup label file and, if it exists, the tablespace map file - created by <function>pg_start_backup</function>. In a non-exclusive - backup, the desired contents of these files are returned as part of + Finishes performing an on-line backup. The desired contents of the + backup label file and the tablespace map file are returned as part of the result of the function, and should be written to files in the backup area (not in the data directory). </para>Given that this is a crucial part, which the exclusive mode has wrong,
I'd be a bit more forceful about it, eg:The contents of the backup label file and the tablespace map file must
be stored as part of the backup and must NOT be stored in the live data
directory (doing so will cause PostgreSQL to fail to restart in the
event of a crash).
done
The result of the function is a single record. The <parameter>lsn</parameter> column holds the backup's ending write-ahead log location (which again can be ignored). The second and - third columns are <literal>NULL</literal> when ending an exclusive - backup; after a non-exclusive backup they hold the desired contents of + third columns hold the desired contents of the label and tablespace map files. </para> <para>I dislike saying 'desired' here as if it's something that we're nicely
asking but maybe isn't a big deal, and just saying 'label' isn't good
since we call it 'backup label' elsewhere and we should try hard to be
consistent and clear. How about:The second column returns the contents of the backup label file, the
third column returns the contents of the tablespace map file. These
must be stored as part of the backup and are required as part of the
restore process.
done
{ print_msg(_("WARNING: online backup mode is active\n" - "Shutdown will not complete until pg_stop_backup() is called.\n\n")); + "Shutdown will not complete until pg_backup_stop() is called.\n\n")); }print_msg(_("waiting for server to shut down...")); @@ -1145,7 +1145,7 @@ do_restart(void) get_control_dbstate() != DB_IN_ARCHIVE_RECOVERY) { print_msg(_("WARNING: online backup mode is active\n" - "Shutdown will not complete until pg_stop_backup() is called.\n\n")); + "Shutdown will not complete until pg_backup_stop() is called.\n\n")); }print_msg(_("waiting for server to shut down..."));
This... can't actually happen anymore, right? Shouldn't we just pull
all of this out?
done
On a once-over of the rest of the code, I definitely like how much we're
able to simplify things in this area and remove various hacks in things
like pg_basebackup and pg_rewind where we previously had to worry about
backup_label and tablespace_map files being in a live data directory.
I'm planning to spend more time on this and hopefully be able to get it
in for v15.
Great! Much appreciated.
--
Nathan Bossart
Amazon Web Services: https://aws.amazon.com
Attachments:
v8-0001-remove-exclusive-backup-mode.patchtext/x-diff; charset=us-asciiDownload
From 13056477b90a8e3e846f17a97088e026e05a657d Mon Sep 17 00:00:00 2001
From: Nathan Bossart <bossartn@amazon.com>
Date: Wed, 1 Dec 2021 23:50:49 +0000
Subject: [PATCH v8 1/1] remove exclusive backup mode
---
doc/src/sgml/backup.sgml | 230 +-------
doc/src/sgml/func.sgml | 111 +---
doc/src/sgml/high-availability.sgml | 6 +-
doc/src/sgml/monitoring.sgml | 4 +-
doc/src/sgml/ref/pgupgrade.sgml | 2 +-
src/backend/access/transam/xlog.c | 493 ++----------------
src/backend/access/transam/xlogfuncs.c | 253 ++-------
src/backend/access/transam/xlogrecovery.c | 2 +-
src/backend/catalog/system_functions.sql | 18 +-
src/backend/postmaster/postmaster.c | 46 +-
src/backend/replication/basebackup.c | 20 +-
src/bin/pg_basebackup/t/010_pg_basebackup.pl | 4 +
src/bin/pg_ctl/pg_ctl.c | 30 --
src/bin/pg_rewind/filemap.c | 6 +-
src/include/access/xlog.h | 7 +-
src/include/catalog/pg_control.h | 2 +-
src/include/catalog/pg_proc.dat | 28 +-
src/include/miscadmin.h | 4 -
src/test/perl/PostgreSQL/Test/Cluster.pm | 56 +-
.../t/010_logical_decoding_timelines.pl | 4 +-
20 files changed, 199 insertions(+), 1127 deletions(-)
diff --git a/doc/src/sgml/backup.sgml b/doc/src/sgml/backup.sgml
index 0d69851bb1..5b7139c7df 100644
--- a/doc/src/sgml/backup.sgml
+++ b/doc/src/sgml/backup.sgml
@@ -857,16 +857,8 @@ test ! -f /mnt/server/archivedir/00000001000000A900000065 && cp pg_wal/0
sequence, and that the success of a step is verified before
proceeding to the next step.
</para>
- <para>
- Low level base backups can be made in a non-exclusive or an exclusive
- way. The non-exclusive method is recommended and the exclusive one is
- deprecated and will eventually be removed.
- </para>
-
- <sect3 id="backup-lowlevel-base-backup-nonexclusive">
- <title>Making a Non-Exclusive Low-Level Backup</title>
<para>
- A non-exclusive low level backup is one that allows other
+ A low level backup allows other
concurrent backups to be running (both those started using
the same backup API and those started using
<xref linkend="app-pgbasebackup"/>).
@@ -881,23 +873,23 @@ test ! -f /mnt/server/archivedir/00000001000000A900000065 && cp pg_wal/0
<listitem>
<para>
Connect to the server (it does not matter which database) as a user with
- rights to run pg_start_backup (superuser, or a user who has been granted
+ rights to run pg_backup_start (superuser, or a user who has been granted
EXECUTE on the function) and issue the command:
<programlisting>
-SELECT pg_start_backup('label', false, false);
+SELECT pg_backup_start(label => 'label', fast => false);
</programlisting>
where <literal>label</literal> is any string you want to use to uniquely
identify this backup operation. The connection
- calling <function>pg_start_backup</function> must be maintained until the end of
+ calling <function>pg_backup_start</function> must be maintained until the end of
the backup, or the backup will be automatically aborted.
</para>
<para>
- By default, <function>pg_start_backup</function> can take a long time to finish.
- This is because it performs a checkpoint, and the I/O
- required for the checkpoint will be spread out over a significant
- period of time, by default half your inter-checkpoint interval
- (see the configuration parameter
+ By default, <function>pg_backup_start</function> can take a long time to finish.
+ This is because it waits for the next checkpoint to complete, and the I/O
+ required for the checkpoint might be spread out over a significant
+ period of time (see the configuration parameters
+ <xref linkend="guc-checkpoint-timeout"/> and
<xref linkend="guc-checkpoint-completion-target"/>). This is
usually what you want, because it minimizes the impact on query
processing. If you want to start the backup as soon as
@@ -905,10 +897,6 @@ SELECT pg_start_backup('label', false, false);
issue an immediate checkpoint using as much I/O as available.
</para>
- <para>
- The third parameter being <literal>false</literal> tells
- <function>pg_start_backup</function> to initiate a non-exclusive base backup.
- </para>
</listitem>
<listitem>
<para>
@@ -926,7 +914,7 @@ SELECT pg_start_backup('label', false, false);
<para>
In the same connection as before, issue the command:
<programlisting>
-SELECT * FROM pg_stop_backup(false, true);
+SELECT * FROM pg_backup_stop(wait_for_archive => true);
</programlisting>
This terminates backup mode. On a primary, it also performs an automatic
switch to the next WAL segment. On a standby, it is not possible to
@@ -937,7 +925,7 @@ SELECT * FROM pg_stop_backup(false, true);
ready to archive.
</para>
<para>
- The <function>pg_stop_backup</function> will return one row with three
+ <function>pg_backup_stop</function> will return one row with three
values. The second of these fields should be written to a file named
<filename>backup_label</filename> in the root directory of the backup. The
third field should be written to a file named
@@ -949,14 +937,14 @@ SELECT * FROM pg_stop_backup(false, true);
<listitem>
<para>
Once the WAL segment files active during the backup are archived, you are
- done. The file identified by <function>pg_stop_backup</function>'s first return
+ done. The file identified by <function>pg_backup_stop</function>'s first return
value is the last segment that is required to form a complete set of
backup files. On a primary, if <varname>archive_mode</varname> is enabled and the
<literal>wait_for_archive</literal> parameter is <literal>true</literal>,
- <function>pg_stop_backup</function> does not return until the last segment has
+ <function>pg_backup_stop</function> does not return until the last segment has
been archived.
On a standby, <varname>archive_mode</varname> must be <literal>always</literal> in order
- for <function>pg_stop_backup</function> to wait.
+ for <function>pg_backup_stop</function> to wait.
Archiving of these files happens automatically since you have
already configured <varname>archive_library</varname>. In most cases this
happens quickly, but you are advised to monitor your archive
@@ -965,9 +953,9 @@ SELECT * FROM pg_stop_backup(false, true);
because of failures of the archive library, it will keep retrying
until the archive succeeds and the backup is complete.
If you wish to place a time limit on the execution of
- <function>pg_stop_backup</function>, set an appropriate
+ <function>pg_backup_stop</function>, set an appropriate
<varname>statement_timeout</varname> value, but make note that if
- <function>pg_stop_backup</function> terminates because of this your backup
+ <function>pg_backup_stop</function> terminates because of this your backup
may not be valid.
</para>
<para>
@@ -975,8 +963,8 @@ SELECT * FROM pg_stop_backup(false, true);
required for the backup are successfully archived then the
<literal>wait_for_archive</literal> parameter (which defaults to true) can be set
to false to have
- <function>pg_stop_backup</function> return as soon as the stop backup record is
- written to the WAL. By default, <function>pg_stop_backup</function> will wait
+ <function>pg_backup_stop</function> return as soon as the stop backup record is
+ written to the WAL. By default, <function>pg_backup_stop</function> will wait
until all WAL has been archived, which can take some time. This option
must be used with caution: if WAL archiving is not monitored correctly
then the backup might not include all of the WAL files and will
@@ -985,142 +973,6 @@ SELECT * FROM pg_stop_backup(false, true);
</listitem>
</orderedlist>
</para>
- </sect3>
- <sect3 id="backup-lowlevel-base-backup-exclusive">
- <title>Making an Exclusive Low-Level Backup</title>
-
- <note>
- <para>
- The exclusive backup method is deprecated and should be avoided.
- Prior to <productname>PostgreSQL</productname> 9.6, this was the only
- low-level method available, but it is now recommended that all users
- upgrade their scripts to use non-exclusive backups.
- </para>
- </note>
-
- <para>
- The process for an exclusive backup is mostly the same as for a
- non-exclusive one, but it differs in a few key steps. This type of
- backup can only be taken on a primary and does not allow concurrent
- backups. Moreover, because it creates a backup label file, as
- described below, it can block automatic restart of the primary server
- after a crash. On the other hand, the erroneous removal of this
- file from a backup or standby is a common mistake, which can result
- in serious data corruption. If it is necessary to use this method,
- the following steps may be used.
- </para>
- <para>
- <orderedlist>
- <listitem>
- <para>
- Ensure that WAL archiving is enabled and working.
- </para>
- </listitem>
- <listitem>
- <para>
- Connect to the server (it does not matter which database) as a user with
- rights to run pg_start_backup (superuser, or a user who has been granted
- EXECUTE on the function) and issue the command:
-<programlisting>
-SELECT pg_start_backup('label');
-</programlisting>
- where <literal>label</literal> is any string you want to use to uniquely
- identify this backup operation.
- <function>pg_start_backup</function> creates a <firstterm>backup label</firstterm> file,
- called <filename>backup_label</filename>, in the cluster directory with
- information about your backup, including the start time and label string.
- The function also creates a <firstterm>tablespace map</firstterm> file,
- called <filename>tablespace_map</filename>, in the cluster directory with
- information about tablespace symbolic links in <filename>pg_tblspc/</filename> if
- one or more such link is present. Both files are critical to the
- integrity of the backup, should you need to restore from it.
- </para>
-
- <para>
- By default, <function>pg_start_backup</function> can take a long time to finish.
- This is because it performs a checkpoint, and the I/O
- required for the checkpoint will be spread out over a significant
- period of time, by default half your inter-checkpoint interval
- (see the configuration parameter
- <xref linkend="guc-checkpoint-completion-target"/>). This is
- usually what you want, because it minimizes the impact on query
- processing. If you want to start the backup as soon as
- possible, use:
-<programlisting>
-SELECT pg_start_backup('label', true);
-</programlisting>
- This forces the checkpoint to be done as quickly as possible.
- </para>
- </listitem>
- <listitem>
- <para>
- Perform the backup, using any convenient file-system-backup tool
- such as <application>tar</application> or <application>cpio</application> (not
- <application>pg_dump</application> or
- <application>pg_dumpall</application>). It is neither
- necessary nor desirable to stop normal operation of the database
- while you do this. See
- <xref linkend="backup-lowlevel-base-backup-data"/> for things to
- consider during this backup.
- </para>
- <para>
- As noted above, if the server crashes during the backup it may not be
- possible to restart until the <filename>backup_label</filename> file has
- been manually deleted from the <envar>PGDATA</envar> directory. Note
- that it is very important to never remove the
- <filename>backup_label</filename> file when restoring a backup, because
- this will result in corruption. Confusion about when it is appropriate
- to remove this file is a common cause of data corruption when using this
- method; be very certain that you remove the file only on an existing
- primary and never when building a standby or restoring a backup, even if
- you are building a standby that will subsequently be promoted to a new
- primary.
- </para>
- </listitem>
- <listitem>
- <para>
- Again connect to the database as a user with rights to run
- pg_stop_backup (superuser, or a user who has been granted EXECUTE on
- the function), and issue the command:
-<programlisting>
-SELECT pg_stop_backup();
-</programlisting>
- This function terminates backup mode and
- performs an automatic switch to the next WAL segment. The reason for the
- switch is to arrange for the last WAL segment written during the backup
- interval to be ready to archive.
- </para>
- </listitem>
- <listitem>
- <para>
- Once the WAL segment files active during the backup are archived, you are
- done. The file identified by <function>pg_stop_backup</function>'s result is
- the last segment that is required to form a complete set of backup files.
- If <varname>archive_mode</varname> is enabled,
- <function>pg_stop_backup</function> does not return until the last segment has
- been archived.
- Archiving of these files happens automatically since you have
- already configured <varname>archive_command</varname>. In most cases this
- happens quickly, but you are advised to monitor your archive
- system to ensure there are no delays.
- If the archive process has fallen behind
- because of failures of the archive command, it will keep retrying
- until the archive succeeds and the backup is complete.
- </para>
-
- <para>
- When using exclusive backup mode, it is absolutely imperative to ensure
- that <function>pg_stop_backup</function> completes successfully at the
- end of the backup. Even if the backup itself fails, for example due to
- lack of disk space, failure to call <function>pg_stop_backup</function>
- will leave the server in backup mode indefinitely, causing future backups
- to fail and increasing the risk of a restart failure during the time that
- <filename>backup_label</filename> exists.
- </para>
- </listitem>
- </orderedlist>
- </para>
- </sect3>
<sect3 id="backup-lowlevel-base-backup-data">
<title>Backing Up the Data Directory</title>
<para>
@@ -1203,8 +1055,8 @@ SELECT pg_stop_backup();
<para>
The backup label
- file includes the label string you gave to <function>pg_start_backup</function>,
- as well as the time at which <function>pg_start_backup</function> was run, and
+ file includes the label string you gave to <function>pg_backup_start</function>,
+ as well as the time at which <function>pg_backup_start</function> was run, and
the name of the starting WAL file. In case of confusion it is therefore
possible to look inside a backup file and determine exactly which
backup session the dump file came from. The tablespace map file includes
@@ -1218,7 +1070,7 @@ SELECT pg_stop_backup();
<para>
It is also possible to make a backup while the server is
stopped. In this case, you obviously cannot use
- <function>pg_start_backup</function> or <function>pg_stop_backup</function>, and
+ <function>pg_backup_start</function> or <function>pg_backup_stop</function>, and
you will therefore be left to your own devices to keep track of which
backup is which and how far back the associated WAL files go.
It is generally better to follow the continuous archiving procedure above.
@@ -1393,7 +1245,7 @@ restore_command = 'cp /mnt/server/archivedir/%f %p'
<note>
<para>
The stop point must be after the ending time of the base backup, i.e.,
- the end time of <function>pg_stop_backup</function>. You cannot use a base backup
+ the end time of <function>pg_backup_stop</function>. You cannot use a base backup
to recover to a time when that backup was in progress. (To
recover to such a time, you must go back to your previous base backup
and roll forward from there.)
@@ -1513,44 +1365,6 @@ restore_command = 'cp /mnt/server/archivedir/%f %p'
included in the backup automatically, and no special action is
required to restore the backup.
</para>
-
- <para>
- If more flexibility in copying the backup files is needed, a lower
- level process can be used for standalone hot backups as well.
- To prepare for low level standalone hot backups, make sure
- <varname>wal_level</varname> is set to
- <literal>replica</literal> or higher, <varname>archive_mode</varname> to
- <literal>on</literal>, and set up an <varname>archive_library</varname> that performs
- archiving only when a <emphasis>switch file</emphasis> exists. For example:
-<programlisting>
-archive_library = '' # use shell command
-archive_command = 'test ! -f /var/lib/pgsql/backup_in_progress || (test ! -f /var/lib/pgsql/archive/%f && cp %p /var/lib/pgsql/archive/%f)'
-</programlisting>
- This command will perform archiving when
- <filename>/var/lib/pgsql/backup_in_progress</filename> exists, and otherwise
- silently return zero exit status (allowing <productname>PostgreSQL</productname>
- to recycle the unwanted WAL file).
- </para>
-
- <para>
- With this preparation, a backup can be taken using a script like the
- following:
-<programlisting>
-touch /var/lib/pgsql/backup_in_progress
-psql -c "select pg_start_backup('hot_backup');"
-tar -cf /var/lib/pgsql/backup.tar /var/lib/pgsql/data/
-psql -c "select pg_stop_backup();"
-rm /var/lib/pgsql/backup_in_progress
-tar -rf /var/lib/pgsql/backup.tar /var/lib/pgsql/archive/
-</programlisting>
- The switch file <filename>/var/lib/pgsql/backup_in_progress</filename> is
- created first, enabling archiving of completed WAL files to occur.
- After the backup the switch file is removed. Archived WAL files are
- then added to the backup so that both base backup and all required
- WAL files are part of the same <application>tar</application> file.
- Please remember to add error handling to your backup scripts.
- </para>
-
</sect3>
<sect3 id="compressed-archive-logs">
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 3a9d62b408..f7ce1fa450 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -25587,9 +25587,8 @@ LOG: Grand total: 1651920 bytes in 201 blocks; 622360 free (88 chunks); 1029560
The functions shown in <xref
linkend="functions-admin-backup-table"/> assist in making on-line backups.
These functions cannot be executed during recovery (except
- non-exclusive <function>pg_start_backup</function>,
- non-exclusive <function>pg_stop_backup</function>,
- <function>pg_is_in_backup</function>, <function>pg_backup_start_time</function>
+ <function>pg_backup_start</function>,
+ <function>pg_backup_stop</function>,
and <function>pg_wal_lsn_diff</function>).
</para>
@@ -25678,13 +25677,12 @@ LOG: Grand total: 1651920 bytes in 201 blocks; 622360 free (88 chunks); 1029560
<row>
<entry role="func_table_entry"><para role="func_signature">
<indexterm>
- <primary>pg_start_backup</primary>
+ <primary>pg_backup_start</primary>
</indexterm>
- <function>pg_start_backup</function> (
+ <function>pg_backup_start</function> (
<parameter>label</parameter> <type>text</type>
<optional>, <parameter>fast</parameter> <type>boolean</type>
- <optional>, <parameter>exclusive</parameter> <type>boolean</type>
- </optional></optional> )
+ </optional> )
<returnvalue>pg_lsn</returnvalue>
</para>
<para>
@@ -25693,23 +25691,9 @@ LOG: Grand total: 1651920 bytes in 201 blocks; 622360 free (88 chunks); 1029560
(Typically this would be the name under which the backup dump file
will be stored.)
If the optional second parameter is given as <literal>true</literal>,
- it specifies executing <function>pg_start_backup</function> as quickly
+ it specifies executing <function>pg_backup_start</function> as quickly
as possible. This forces an immediate checkpoint which will cause a
spike in I/O operations, slowing any concurrently executing queries.
- The optional third parameter specifies whether to perform an exclusive
- or non-exclusive backup (default is exclusive).
- </para>
- <para>
- When used in exclusive mode, this function writes a backup label file
- (<filename>backup_label</filename>) and, if there are any links in
- the <filename>pg_tblspc/</filename> directory, a tablespace map file
- (<filename>tablespace_map</filename>) into the database cluster's data
- directory, then performs a checkpoint, and then returns the backup's
- starting write-ahead log location. (The user can ignore this
- result value, but it is provided in case it is useful.) When used in
- non-exclusive mode, the contents of these files are instead returned
- by the <function>pg_stop_backup</function> function, and should be
- copied to the backup area by the user.
</para>
<para>
This function is restricted to superusers by default, but other users
@@ -25720,11 +25704,10 @@ LOG: Grand total: 1651920 bytes in 201 blocks; 622360 free (88 chunks); 1029560
<row>
<entry role="func_table_entry"><para role="func_signature">
<indexterm>
- <primary>pg_stop_backup</primary>
+ <primary>pg_backup_stop</primary>
</indexterm>
- <function>pg_stop_backup</function> (
- <parameter>exclusive</parameter> <type>boolean</type>
- <optional>, <parameter>wait_for_archive</parameter> <type>boolean</type>
+ <function>pg_backup_stop</function> (
+ <optional><parameter>wait_for_archive</parameter> <type>boolean</type>
</optional> )
<returnvalue>record</returnvalue>
( <parameter>lsn</parameter> <type>pg_lsn</type>,
@@ -25732,24 +25715,21 @@ LOG: Grand total: 1651920 bytes in 201 blocks; 622360 free (88 chunks); 1029560
<parameter>spcmapfile</parameter> <type>text</type> )
</para>
<para>
- Finishes performing an exclusive or non-exclusive on-line backup.
- The <parameter>exclusive</parameter> parameter must match the
- previous <function>pg_start_backup</function> call.
- In an exclusive backup, <function>pg_stop_backup</function> removes
- the backup label file and, if it exists, the tablespace map file
- created by <function>pg_start_backup</function>. In a non-exclusive
- backup, the desired contents of these files are returned as part of
- the result of the function, and should be written to files in the
- backup area (not in the data directory).
+ Finishes performing an on-line backup. The desired contents of the
+ backup label file and the tablespace map file are returned as part of
+ the result of the function and must be written to files in the
+ backup area. These files must not be written to the live data directory
+ (doing so will cause PostgreSQL to fail to restart in the event of a
+ crash).
</para>
<para>
- There is an optional second parameter of type <type>boolean</type>.
+ There is an optional parameter of type <type>boolean</type>.
If false, the function will return immediately after the backup is
completed, without waiting for WAL to be archived. This behavior is
only useful with backup software that independently monitors WAL
archiving. Otherwise, WAL required to make the backup consistent might
be missing and make the backup useless. By default or when this
- parameter is true, <function>pg_stop_backup</function> will wait for
+ parameter is true, <function>pg_backup_stop</function> will wait for
WAL to be archived when archiving is enabled. (On a standby, this
means that it will wait only when <varname>archive_mode</varname> =
<literal>always</literal>. If write activity on the primary is low,
@@ -25759,7 +25739,7 @@ LOG: Grand total: 1651920 bytes in 201 blocks; 622360 free (88 chunks); 1029560
<para>
When executed on a primary, this function also creates a backup
history file in the write-ahead log archive area. The history file
- includes the label given to <function>pg_start_backup</function>, the
+ includes the label given to <function>pg_backup_start</function>, the
starting and ending write-ahead log locations for the backup, and the
starting and ending times of the backup. After recording the ending
location, the current write-ahead log insertion point is automatically
@@ -25770,27 +25750,11 @@ LOG: Grand total: 1651920 bytes in 201 blocks; 622360 free (88 chunks); 1029560
<para>
The result of the function is a single record.
The <parameter>lsn</parameter> column holds the backup's ending
- write-ahead log location (which again can be ignored). The second and
- third columns are <literal>NULL</literal> when ending an exclusive
- backup; after a non-exclusive backup they hold the desired contents of
- the label and tablespace map files.
- </para>
- <para>
- This function is restricted to superusers by default, but other users
- can be granted EXECUTE to run the function.
- </para></entry>
- </row>
-
- <row>
- <entry role="func_table_entry"><para role="func_signature">
- <function>pg_stop_backup</function> ()
- <returnvalue>pg_lsn</returnvalue>
- </para>
- <para>
- Finishes performing an exclusive on-line backup. This simplified
- version is equivalent to <literal>pg_stop_backup(true,
- true)</literal>, except that it only returns the <type>pg_lsn</type>
- result.
+ write-ahead log location (which again can be ignored). The second
+ column returns the contents of the backup label file, and the third
+ column returns the contents of the tablespace map file. These must be
+ stored as part of the backup and are required as part of the restore
+ process.
</para>
<para>
This function is restricted to superusers by default, but other users
@@ -25798,33 +25762,6 @@ LOG: Grand total: 1651920 bytes in 201 blocks; 622360 free (88 chunks); 1029560
</para></entry>
</row>
- <row>
- <entry role="func_table_entry"><para role="func_signature">
- <indexterm>
- <primary>pg_is_in_backup</primary>
- </indexterm>
- <function>pg_is_in_backup</function> ()
- <returnvalue>boolean</returnvalue>
- </para>
- <para>
- Returns true if an on-line exclusive backup is in progress.
- </para></entry>
- </row>
-
- <row>
- <entry role="func_table_entry"><para role="func_signature">
- <indexterm>
- <primary>pg_backup_start_time</primary>
- </indexterm>
- <function>pg_backup_start_time</function> ()
- <returnvalue>timestamp with time zone</returnvalue>
- </para>
- <para>
- Returns the start time of the current on-line exclusive backup if one
- is in progress, otherwise <literal>NULL</literal>.
- </para></entry>
- </row>
-
<row>
<entry role="func_table_entry"><para role="func_signature">
<indexterm>
@@ -25922,7 +25859,7 @@ LOG: Grand total: 1651920 bytes in 201 blocks; 622360 free (88 chunks); 1029560
corresponding write-ahead log file name and byte offset from
a <type>pg_lsn</type> value. For example:
<programlisting>
-postgres=# SELECT * FROM pg_walfile_name_offset(pg_stop_backup());
+postgres=# SELECT * FROM pg_walfile_name_offset((pg_backup_stop()).lsn);
file_name | file_offset
--------------------------+-------------
00000001000000000000000D | 4039624
diff --git a/doc/src/sgml/high-availability.sgml b/doc/src/sgml/high-availability.sgml
index 81fa26f985..3247e05666 100644
--- a/doc/src/sgml/high-availability.sgml
+++ b/doc/src/sgml/high-availability.sgml
@@ -1361,8 +1361,8 @@ synchronous_standby_names = 'ANY 2 (s1, s2, s3)'
<para>
If you need to re-create a standby server while transactions are
- waiting, make sure that the commands pg_start_backup() and
- pg_stop_backup() are run in a session with
+ waiting, make sure that the commands pg_backup_start() and
+ pg_backup_stop() are run in a session with
<varname>synchronous_commit</varname> = <literal>off</literal>, otherwise those
requests will wait forever for the standby to appear.
</para>
@@ -2159,7 +2159,7 @@ HINT: You can then restart the server after making the necessary configuration
<para>
WAL file control commands will not work during recovery,
- e.g., <function>pg_start_backup</function>, <function>pg_switch_wal</function> etc.
+ e.g., <function>pg_backup_start</function>, <function>pg_switch_wal</function> etc.
</para>
<para>
diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
index 6a6b09dc45..95f944d6e4 100644
--- a/doc/src/sgml/monitoring.sgml
+++ b/doc/src/sgml/monitoring.sgml
@@ -6670,7 +6670,7 @@ SELECT pg_stat_get_backend_pid(s.backendid) AS pid,
<entry><literal>waiting for checkpoint to finish</literal></entry>
<entry>
The WAL sender process is currently performing
- <function>pg_start_backup</function> to prepare to
+ <function>pg_backup_start</function> to prepare to
take a base backup, and waiting for the start-of-backup
checkpoint to finish.
</entry>
@@ -6693,7 +6693,7 @@ SELECT pg_stat_get_backend_pid(s.backendid) AS pid,
<entry><literal>waiting for wal archiving to finish</literal></entry>
<entry>
The WAL sender process is currently performing
- <function>pg_stop_backup</function> to finish the backup,
+ <function>pg_backup_stop</function> to finish the backup,
and waiting for all the WAL files required for the base backup
to be successfully archived.
If either <literal>--wal-method=none</literal> or
diff --git a/doc/src/sgml/ref/pgupgrade.sgml b/doc/src/sgml/ref/pgupgrade.sgml
index 729c886ac0..3fbe141456 100644
--- a/doc/src/sgml/ref/pgupgrade.sgml
+++ b/doc/src/sgml/ref/pgupgrade.sgml
@@ -618,7 +618,7 @@ rsync --archive --delete --hard-links --size-only --no-inc-recursive /vol1/pg_tb
<para>
Configure the servers for log shipping. (You do not need to run
- <function>pg_start_backup()</function> and <function>pg_stop_backup()</function>
+ <function>pg_backup_start()</function> and <function>pg_backup_stop()</function>
or take a file system backup as the standbys are still synchronized
with the primary.)
</para>
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 17a56152f1..b539d87111 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -385,29 +385,6 @@ typedef union WALInsertLockPadded
char pad[PG_CACHE_LINE_SIZE];
} WALInsertLockPadded;
-/*
- * State of an exclusive backup, necessary to control concurrent activities
- * across sessions when working on exclusive backups.
- *
- * EXCLUSIVE_BACKUP_NONE means that there is no exclusive backup actually
- * running, to be more precise pg_start_backup() is not being executed for
- * an exclusive backup and there is no exclusive backup in progress.
- * EXCLUSIVE_BACKUP_STARTING means that pg_start_backup() is starting an
- * exclusive backup.
- * EXCLUSIVE_BACKUP_IN_PROGRESS means that pg_start_backup() has finished
- * running and an exclusive backup is in progress. pg_stop_backup() is
- * needed to finish it.
- * EXCLUSIVE_BACKUP_STOPPING means that pg_stop_backup() is stopping an
- * exclusive backup.
- */
-typedef enum ExclusiveBackupState
-{
- EXCLUSIVE_BACKUP_NONE = 0,
- EXCLUSIVE_BACKUP_STARTING,
- EXCLUSIVE_BACKUP_IN_PROGRESS,
- EXCLUSIVE_BACKUP_STOPPING
-} ExclusiveBackupState;
-
/*
* Session status of running backup, used for sanity checks in SQL-callable
* functions to start and stop backups.
@@ -456,15 +433,12 @@ typedef struct XLogCtlInsert
bool fullPageWrites;
/*
- * exclusiveBackupState indicates the state of an exclusive backup (see
- * comments of ExclusiveBackupState for more details). nonExclusiveBackups
- * is a counter indicating the number of streaming base backups currently
- * in progress. forcePageWrites is set to true when either of these is
- * non-zero. lastBackupStart is the latest checkpoint redo location used
- * as a starting point for an online backup.
+ * runningBackups is a counter indicating the number of backups currently in
+ * progress. forcePageWrites is set to true when runningBackups is non-zero.
+ * lastBackupStart is the latest checkpoint redo location used as a starting
+ * point for an online backup.
*/
- ExclusiveBackupState exclusiveBackupState;
- int nonExclusiveBackups;
+ int runningBackups;
XLogRecPtr lastBackupStart;
/*
@@ -696,8 +670,7 @@ static void ReadControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow);
-static void pg_start_backup_callback(int code, Datum arg);
-static void pg_stop_backup_callback(int code, Datum arg);
+static void pg_backup_start_callback(int code, Datum arg);
static int get_sync_bit(int method);
@@ -5328,7 +5301,7 @@ StartupXLOG(void)
* Ran off end of WAL before reaching end-of-backup WAL record, or
* minRecoveryPoint. That's usually a bad sign, indicating that you
* tried to recover from an online backup but never called
- * pg_stop_backup(), or you didn't archive all the WAL up to that
+ * pg_backup_stop(), or you didn't archive all the WAL up to that
* point. However, this also happens in crash recovery, if the system
* crashes while an online backup is in progress. We must not treat
* that as an error, or the database will refuse to start up.
@@ -5342,7 +5315,7 @@ StartupXLOG(void)
else if (!XLogRecPtrIsInvalid(ControlFile->backupStartPoint))
ereport(FATAL,
(errmsg("WAL ends before end of online backup"),
- errhint("Online backup started with pg_start_backup() must be ended with pg_stop_backup(), and all WAL up to that point must be available at recovery.")));
+ errhint("Online backup started with pg_backup_start() must be ended with pg_backup_stop(), and all WAL up to that point must be available at recovery.")));
else
ereport(FATAL,
(errmsg("WAL ends before consistent recovery point")));
@@ -7036,7 +7009,7 @@ CreateRestartPoint(int flags)
* Ensure minRecoveryPoint is past the checkpoint record. Normally,
* this will have happened already while writing out dirty buffers,
* but not necessarily - e.g. because no buffers were dirtied. We do
- * this because a non-exclusive base backup uses minRecoveryPoint to
+ * this because a backup performed in recovery uses minRecoveryPoint to
* determine which WAL files must be included in the backup, and the
* file (or files) containing the checkpoint record must be included,
* at a minimum. Note that for an ordinary restart of recovery there's
@@ -7840,7 +7813,7 @@ xlog_redo(XLogReaderState *record)
/*
* Update the LSN of the last replayed XLOG_FPW_CHANGE record so that
- * do_pg_start_backup() and do_pg_stop_backup() can check whether
+ * do_pg_backup_start() and do_pg_backup_stop() can check whether
* full_page_writes has been disabled during online backup.
*/
if (!fpw)
@@ -8039,29 +8012,14 @@ issue_xlog_fsync(int fd, XLogSegNo segno, TimeLineID tli)
}
/*
- * do_pg_start_backup
- *
- * Utility function called at the start of an online backup. It creates the
- * necessary starting checkpoint and constructs the backup label file.
- *
- * There are two kind of backups: exclusive and non-exclusive. An exclusive
- * backup is started with pg_start_backup(), and there can be only one active
- * at a time. The backup and tablespace map files of an exclusive backup are
- * written to $PGDATA/backup_label and $PGDATA/tablespace_map, and they are
- * removed by pg_stop_backup().
- *
- * A non-exclusive backup is used for the streaming base backups (see
- * src/backend/replication/basebackup.c). The difference to exclusive backups
- * is that the backup label and tablespace map files are not written to disk.
- * Instead, their would-be contents are returned in *labelfile and *tblspcmapfile,
- * and the caller is responsible for including them in the backup archive as
- * 'backup_label' and 'tablespace_map'. There can be many non-exclusive backups
- * active at the same time, and they don't conflict with an exclusive backup
- * either.
- *
- * labelfile and tblspcmapfile must be passed as NULL when starting an
- * exclusive backup, and as initially-empty StringInfos for a non-exclusive
- * backup.
+ * do_pg_backup_start is the workhorse of the user-visible pg_backup_start()
+ * function. It creates the necessary starting checkpoint and constructs the
+ * backup label and tablespace map.
+ *
+ * The backup label and tablespace map contents are returned in *labelfile and
+ * *tblspcmapfile, and the caller is responsible for including them in the
+ * backup archive as 'backup_label' and 'tablespace_map'. There can be many
+ * backups active at the same time.
*
* If "tablespaces" isn't NULL, it receives a list of tablespaceinfo structs
* describing the cluster's tablespaces.
@@ -8073,18 +8031,17 @@ issue_xlog_fsync(int fd, XLogSegNo segno, TimeLineID tli)
* Returns the minimum WAL location that must be present to restore from this
* backup, and the corresponding timeline ID in *starttli_p.
*
- * Every successfully started non-exclusive backup must be stopped by calling
- * do_pg_stop_backup() or do_pg_abort_backup().
+ * Every successfully started backup must be stopped by calling
+ * do_pg_backup_stop() or do_pg_abort_backup().
*
* It is the responsibility of the caller of this function to verify the
* permissions of the calling user!
*/
XLogRecPtr
-do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
+do_pg_backup_start(const char *backupidstr, bool fast, TimeLineID *starttli_p,
StringInfo labelfile, List **tablespaces,
StringInfo tblspcmapfile)
{
- bool exclusive = (labelfile == NULL);
bool backup_started_in_recovery = false;
XLogRecPtr checkpointloc;
XLogRecPtr startpoint;
@@ -8093,20 +8050,9 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
char strfbuf[128];
char xlogfilename[MAXFNAMELEN];
XLogSegNo _logSegNo;
- struct stat stat_buf;
- FILE *fp;
backup_started_in_recovery = RecoveryInProgress();
- /*
- * Currently only non-exclusive backup can be taken during recovery.
- */
- if (backup_started_in_recovery && exclusive)
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("recovery is in progress"),
- errhint("WAL control functions cannot be executed during recovery.")));
-
/*
* During recovery, we don't need to check WAL level. Because, if WAL
* level is not sufficient, it's impossible to get here during recovery.
@@ -8145,30 +8091,12 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
* XLogInsertRecord().
*/
WALInsertLockAcquireExclusive();
- if (exclusive)
- {
- /*
- * At first, mark that we're now starting an exclusive backup, to
- * ensure that there are no other sessions currently running
- * pg_start_backup() or pg_stop_backup().
- */
- if (XLogCtl->Insert.exclusiveBackupState != EXCLUSIVE_BACKUP_NONE)
- {
- WALInsertLockRelease();
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("a backup is already in progress"),
- errhint("Run pg_stop_backup() and try again.")));
- }
- XLogCtl->Insert.exclusiveBackupState = EXCLUSIVE_BACKUP_STARTING;
- }
- else
- XLogCtl->Insert.nonExclusiveBackups++;
+ XLogCtl->Insert.runningBackups++;
XLogCtl->Insert.forcePageWrites = true;
WALInsertLockRelease();
/* Ensure we release forcePageWrites if fail below */
- PG_ENSURE_ERROR_CLEANUP(pg_start_backup_callback, (Datum) BoolGetDatum(exclusive));
+ PG_ENSURE_ERROR_CLEANUP(pg_backup_start_callback, (Datum) 0);
{
bool gotUniqueStartpoint = false;
DIR *tblspcdir;
@@ -8180,7 +8108,7 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
* Force an XLOG file switch before the checkpoint, to ensure that the
* WAL segment the checkpoint is written to doesn't contain pages with
* old timeline IDs. That would otherwise happen if you called
- * pg_start_backup() right after restoring from a PITR archive: the
+ * pg_backup_start() right after restoring from a PITR archive: the
* first WAL segment containing the startup checkpoint has pages in
* the beginning with the old timeline ID. That can cause trouble at
* recovery: we won't have a history file covering the old timeline if
@@ -8215,7 +8143,7 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
* means that two successive backup runs can have same checkpoint
* positions.
*
- * Since the fact that we are executing do_pg_start_backup()
+ * Since the fact that we are executing do_pg_backup_start()
* during recovery means that checkpointer is running, we can use
* RequestCheckpoint() to establish a restartpoint.
*
@@ -8416,122 +8344,19 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
LSN_FORMAT_ARGS(startpoint), xlogfilename);
appendStringInfo(labelfile, "CHECKPOINT LOCATION: %X/%X\n",
LSN_FORMAT_ARGS(checkpointloc));
- appendStringInfo(labelfile, "BACKUP METHOD: %s\n",
- exclusive ? "pg_start_backup" : "streamed");
+ appendStringInfo(labelfile, "BACKUP METHOD: streamed\n");
appendStringInfo(labelfile, "BACKUP FROM: %s\n",
backup_started_in_recovery ? "standby" : "primary");
appendStringInfo(labelfile, "START TIME: %s\n", strfbuf);
appendStringInfo(labelfile, "LABEL: %s\n", backupidstr);
appendStringInfo(labelfile, "START TIMELINE: %u\n", starttli);
-
- /*
- * Okay, write the file, or return its contents to caller.
- */
- if (exclusive)
- {
- /*
- * Check for existing backup label --- implies a backup is already
- * running. (XXX given that we checked exclusiveBackupState
- * above, maybe it would be OK to just unlink any such label
- * file?)
- */
- if (stat(BACKUP_LABEL_FILE, &stat_buf) != 0)
- {
- if (errno != ENOENT)
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not stat file \"%s\": %m",
- BACKUP_LABEL_FILE)));
- }
- else
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("a backup is already in progress"),
- errhint("If you're sure there is no backup in progress, remove file \"%s\" and try again.",
- BACKUP_LABEL_FILE)));
-
- fp = AllocateFile(BACKUP_LABEL_FILE, "w");
-
- if (!fp)
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not create file \"%s\": %m",
- BACKUP_LABEL_FILE)));
- if (fwrite(labelfile->data, labelfile->len, 1, fp) != 1 ||
- fflush(fp) != 0 ||
- pg_fsync(fileno(fp)) != 0 ||
- ferror(fp) ||
- FreeFile(fp))
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not write file \"%s\": %m",
- BACKUP_LABEL_FILE)));
- /* Allocated locally for exclusive backups, so free separately */
- pfree(labelfile->data);
- pfree(labelfile);
-
- /* Write backup tablespace_map file. */
- if (tblspcmapfile->len > 0)
- {
- if (stat(TABLESPACE_MAP, &stat_buf) != 0)
- {
- if (errno != ENOENT)
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not stat file \"%s\": %m",
- TABLESPACE_MAP)));
- }
- else
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("a backup is already in progress"),
- errhint("If you're sure there is no backup in progress, remove file \"%s\" and try again.",
- TABLESPACE_MAP)));
-
- fp = AllocateFile(TABLESPACE_MAP, "w");
-
- if (!fp)
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not create file \"%s\": %m",
- TABLESPACE_MAP)));
- if (fwrite(tblspcmapfile->data, tblspcmapfile->len, 1, fp) != 1 ||
- fflush(fp) != 0 ||
- pg_fsync(fileno(fp)) != 0 ||
- ferror(fp) ||
- FreeFile(fp))
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not write file \"%s\": %m",
- TABLESPACE_MAP)));
- }
-
- /* Allocated locally for exclusive backups, so free separately */
- pfree(tblspcmapfile->data);
- pfree(tblspcmapfile);
- }
}
- PG_END_ENSURE_ERROR_CLEANUP(pg_start_backup_callback, (Datum) BoolGetDatum(exclusive));
+ PG_END_ENSURE_ERROR_CLEANUP(pg_backup_start_callback, (Datum) 0);
/*
- * Mark that start phase has correctly finished for an exclusive backup.
- * Session-level locks are updated as well to reflect that state.
- *
- * Note that CHECK_FOR_INTERRUPTS() must not occur while updating backup
- * counters and session-level lock. Otherwise they can be updated
- * inconsistently, and which might cause do_pg_abort_backup() to fail.
+ * Mark that the start phase has correctly finished for the backup.
*/
- if (exclusive)
- {
- WALInsertLockAcquireExclusive();
- XLogCtl->Insert.exclusiveBackupState = EXCLUSIVE_BACKUP_IN_PROGRESS;
-
- /* Set session-level lock */
- sessionBackupState = SESSION_BACKUP_EXCLUSIVE;
- WALInsertLockRelease();
- }
- else
- sessionBackupState = SESSION_BACKUP_NON_EXCLUSIVE;
+ sessionBackupState = SESSION_BACKUP_RUNNING;
/*
* We're done. As a convenience, return the starting WAL location.
@@ -8541,47 +8366,19 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
return startpoint;
}
-/* Error cleanup callback for pg_start_backup */
+/* Error cleanup callback for pg_backup_start */
static void
-pg_start_backup_callback(int code, Datum arg)
+pg_backup_start_callback(int code, Datum arg)
{
- bool exclusive = DatumGetBool(arg);
-
/* Update backup counters and forcePageWrites on failure */
WALInsertLockAcquireExclusive();
- if (exclusive)
- {
- Assert(XLogCtl->Insert.exclusiveBackupState == EXCLUSIVE_BACKUP_STARTING);
- XLogCtl->Insert.exclusiveBackupState = EXCLUSIVE_BACKUP_NONE;
- }
- else
- {
- Assert(XLogCtl->Insert.nonExclusiveBackups > 0);
- XLogCtl->Insert.nonExclusiveBackups--;
- }
- if (XLogCtl->Insert.exclusiveBackupState == EXCLUSIVE_BACKUP_NONE &&
- XLogCtl->Insert.nonExclusiveBackups == 0)
- {
- XLogCtl->Insert.forcePageWrites = false;
- }
- WALInsertLockRelease();
-}
+ Assert(XLogCtl->Insert.runningBackups > 0);
+ XLogCtl->Insert.runningBackups--;
-/*
- * Error cleanup callback for pg_stop_backup
- */
-static void
-pg_stop_backup_callback(int code, Datum arg)
-{
- bool exclusive = DatumGetBool(arg);
-
- /* Update backup status on failure */
- WALInsertLockAcquireExclusive();
- if (exclusive)
+ if (XLogCtl->Insert.runningBackups == 0)
{
- Assert(XLogCtl->Insert.exclusiveBackupState == EXCLUSIVE_BACKUP_STOPPING);
- XLogCtl->Insert.exclusiveBackupState = EXCLUSIVE_BACKUP_IN_PROGRESS;
+ XLogCtl->Insert.forcePageWrites = false;
}
WALInsertLockRelease();
}
@@ -8596,14 +8393,11 @@ get_backup_status(void)
}
/*
- * do_pg_stop_backup
+ * do_pg_backup_stop
*
* Utility function called at the end of an online backup. It cleans up the
* backup state and can optionally wait for WAL segments to be archived.
*
- * If labelfile is NULL, this stops an exclusive backup. Otherwise this stops
- * the non-exclusive backup specified by 'labelfile'.
- *
* Returns the last WAL location that must be present to restore from this
* backup, and the corresponding timeline ID in *stoptli_p.
*
@@ -8611,9 +8405,8 @@ get_backup_status(void)
* permissions of the calling user!
*/
XLogRecPtr
-do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
+do_pg_backup_stop(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
{
- bool exclusive = (labelfile == NULL);
bool backup_started_in_recovery = false;
XLogRecPtr startpoint;
XLogRecPtr stoppoint;
@@ -8627,7 +8420,6 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
char histfilename[MAXFNAMELEN];
char backupfrom[20];
XLogSegNo _logSegNo;
- FILE *lfp;
FILE *fp;
char ch;
int seconds_before_warning;
@@ -8640,15 +8432,6 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
backup_started_in_recovery = RecoveryInProgress();
- /*
- * Currently only non-exclusive backup can be taken during recovery.
- */
- if (backup_started_in_recovery && exclusive)
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("recovery is in progress"),
- errhint("WAL control functions cannot be executed during recovery.")));
-
/*
* During recovery, we don't need to check WAL level. Because, if WAL
* level is not sufficient, it's impossible to get here during recovery.
@@ -8659,106 +8442,23 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
errmsg("WAL level not sufficient for making an online backup"),
errhint("wal_level must be set to \"replica\" or \"logical\" at server start.")));
- if (exclusive)
- {
- /*
- * At first, mark that we're now stopping an exclusive backup, to
- * ensure that there are no other sessions currently running
- * pg_start_backup() or pg_stop_backup().
- */
- WALInsertLockAcquireExclusive();
- if (XLogCtl->Insert.exclusiveBackupState != EXCLUSIVE_BACKUP_IN_PROGRESS)
- {
- WALInsertLockRelease();
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("exclusive backup not in progress")));
- }
- XLogCtl->Insert.exclusiveBackupState = EXCLUSIVE_BACKUP_STOPPING;
- WALInsertLockRelease();
-
- /*
- * Remove backup_label. In case of failure, the state for an exclusive
- * backup is switched back to in-progress.
- */
- PG_ENSURE_ERROR_CLEANUP(pg_stop_backup_callback, (Datum) BoolGetDatum(exclusive));
- {
- /*
- * Read the existing label file into memory.
- */
- struct stat statbuf;
- int r;
-
- if (stat(BACKUP_LABEL_FILE, &statbuf))
- {
- /* should not happen per the upper checks */
- if (errno != ENOENT)
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not stat file \"%s\": %m",
- BACKUP_LABEL_FILE)));
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("a backup is not in progress")));
- }
-
- lfp = AllocateFile(BACKUP_LABEL_FILE, "r");
- if (!lfp)
- {
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not read file \"%s\": %m",
- BACKUP_LABEL_FILE)));
- }
- labelfile = palloc(statbuf.st_size + 1);
- r = fread(labelfile, statbuf.st_size, 1, lfp);
- labelfile[statbuf.st_size] = '\0';
-
- /*
- * Close and remove the backup label file
- */
- if (r != 1 || ferror(lfp) || FreeFile(lfp))
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not read file \"%s\": %m",
- BACKUP_LABEL_FILE)));
- durable_unlink(BACKUP_LABEL_FILE, ERROR);
-
- /*
- * Remove tablespace_map file if present, it is created only if
- * there are tablespaces.
- */
- durable_unlink(TABLESPACE_MAP, DEBUG1);
- }
- PG_END_ENSURE_ERROR_CLEANUP(pg_stop_backup_callback, (Datum) BoolGetDatum(exclusive));
- }
-
/*
- * OK to update backup counters, forcePageWrites and session-level lock.
+ * OK to update backup counters, forcePageWrites, and session-level lock.
*
* Note that CHECK_FOR_INTERRUPTS() must not occur while updating them.
* Otherwise they can be updated inconsistently, and which might cause
* do_pg_abort_backup() to fail.
*/
WALInsertLockAcquireExclusive();
- if (exclusive)
- {
- XLogCtl->Insert.exclusiveBackupState = EXCLUSIVE_BACKUP_NONE;
- }
- else
- {
- /*
- * The user-visible pg_start/stop_backup() functions that operate on
- * exclusive backups can be called at any time, but for non-exclusive
- * backups, it is expected that each do_pg_start_backup() call is
- * matched by exactly one do_pg_stop_backup() call.
- */
- Assert(XLogCtl->Insert.nonExclusiveBackups > 0);
- XLogCtl->Insert.nonExclusiveBackups--;
- }
- if (XLogCtl->Insert.exclusiveBackupState == EXCLUSIVE_BACKUP_NONE &&
- XLogCtl->Insert.nonExclusiveBackups == 0)
+ /*
+ * It is expected that each do_pg_backup_start() call is matched by exactly
+ * one do_pg_backup_stop() call.
+ */
+ Assert(XLogCtl->Insert.runningBackups > 0);
+ XLogCtl->Insert.runningBackups--;
+
+ if (XLogCtl->Insert.runningBackups == 0)
{
XLogCtl->Insert.forcePageWrites = false;
}
@@ -9016,17 +8716,13 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
/*
* do_pg_abort_backup: abort a running backup
*
- * This does just the most basic steps of do_pg_stop_backup(), by taking the
+ * This does just the most basic steps of do_pg_backup_stop(), by taking the
* system out of backup mode, thus making it a lot more safe to call from
* an error handler.
*
* The caller can pass 'arg' as 'true' or 'false' to control whether a warning
* is emitted.
*
- * NB: This is only for aborting a non-exclusive backup that doesn't write
- * backup_label. A backup started with pg_start_backup() needs to be finished
- * with pg_stop_backup().
- *
* NB: This gets used as a before_shmem_exit handler, hence the odd-looking
* signature.
*/
@@ -9036,18 +8732,16 @@ do_pg_abort_backup(int code, Datum arg)
bool emit_warning = DatumGetBool(arg);
/*
- * Quick exit if session is not keeping around a non-exclusive backup
- * already started.
+ * Quick exit if session does not have a running backup.
*/
- if (sessionBackupState != SESSION_BACKUP_NON_EXCLUSIVE)
+ if (sessionBackupState != SESSION_BACKUP_RUNNING)
return;
WALInsertLockAcquireExclusive();
- Assert(XLogCtl->Insert.nonExclusiveBackups > 0);
- XLogCtl->Insert.nonExclusiveBackups--;
+ Assert(XLogCtl->Insert.runningBackups > 0);
+ XLogCtl->Insert.runningBackups--;
- if (XLogCtl->Insert.exclusiveBackupState == EXCLUSIVE_BACKUP_NONE &&
- XLogCtl->Insert.nonExclusiveBackups == 0)
+ if (XLogCtl->Insert.runningBackups == 0)
{
XLogCtl->Insert.forcePageWrites = false;
}
@@ -9055,7 +8749,7 @@ do_pg_abort_backup(int code, Datum arg)
if (emit_warning)
ereport(WARNING,
- (errmsg("aborting backup due to backend exiting before pg_stop_backup was called")));
+ (errmsg("aborting backup due to backend exiting before pg_backup_stop was called")));
}
/*
@@ -9115,87 +8809,6 @@ GetOldestRestartPoint(XLogRecPtr *oldrecptr, TimeLineID *oldtli)
LWLockRelease(ControlFileLock);
}
-/*
- * BackupInProgress: check if online backup mode is active
- *
- * This is done by checking for existence of the "backup_label" file.
- */
-bool
-BackupInProgress(void)
-{
- struct stat stat_buf;
-
- return (stat(BACKUP_LABEL_FILE, &stat_buf) == 0);
-}
-
-/*
- * CancelBackup: rename the "backup_label" and "tablespace_map"
- * files to cancel backup mode
- *
- * If the "backup_label" file exists, it will be renamed to "backup_label.old".
- * Similarly, if the "tablespace_map" file exists, it will be renamed to
- * "tablespace_map.old".
- *
- * Note that this will render an online backup in progress
- * useless. To correctly finish an online backup, pg_stop_backup must be
- * called.
- */
-void
-CancelBackup(void)
-{
- struct stat stat_buf;
-
- /* if the backup_label file is not there, return */
- if (stat(BACKUP_LABEL_FILE, &stat_buf) < 0)
- return;
-
- /* remove leftover file from previously canceled backup if it exists */
- unlink(BACKUP_LABEL_OLD);
-
- if (durable_rename(BACKUP_LABEL_FILE, BACKUP_LABEL_OLD, DEBUG1) != 0)
- {
- ereport(WARNING,
- (errcode_for_file_access(),
- errmsg("online backup mode was not canceled"),
- errdetail("File \"%s\" could not be renamed to \"%s\": %m.",
- BACKUP_LABEL_FILE, BACKUP_LABEL_OLD)));
- return;
- }
-
- /* if the tablespace_map file is not there, return */
- if (stat(TABLESPACE_MAP, &stat_buf) < 0)
- {
- ereport(LOG,
- (errmsg("online backup mode canceled"),
- errdetail("File \"%s\" was renamed to \"%s\".",
- BACKUP_LABEL_FILE, BACKUP_LABEL_OLD)));
- return;
- }
-
- /* remove leftover file from previously canceled backup if it exists */
- unlink(TABLESPACE_MAP_OLD);
-
- if (durable_rename(TABLESPACE_MAP, TABLESPACE_MAP_OLD, DEBUG1) == 0)
- {
- ereport(LOG,
- (errmsg("online backup mode canceled"),
- errdetail("Files \"%s\" and \"%s\" were renamed to "
- "\"%s\" and \"%s\", respectively.",
- BACKUP_LABEL_FILE, TABLESPACE_MAP,
- BACKUP_LABEL_OLD, TABLESPACE_MAP_OLD)));
- }
- else
- {
- ereport(WARNING,
- (errcode_for_file_access(),
- errmsg("online backup mode canceled"),
- errdetail("File \"%s\" was renamed to \"%s\", but "
- "file \"%s\" could not be renamed to \"%s\": %m.",
- BACKUP_LABEL_FILE, BACKUP_LABEL_OLD,
- TABLESPACE_MAP, TABLESPACE_MAP_OLD)));
- }
-}
-
/* Thin wrapper around ShutdownWalRcv(). */
void
XLogShutdownWalRcv(void)
diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c
index 2752be63c1..b61ae6c0b4 100644
--- a/src/backend/access/transam/xlogfuncs.c
+++ b/src/backend/access/transam/xlogfuncs.c
@@ -39,13 +39,13 @@
#include "utils/tuplestore.h"
/*
- * Store label file and tablespace map during non-exclusive backups.
+ * Store label file and tablespace map during backups.
*/
static StringInfo label_file;
static StringInfo tblspc_map_file;
/*
- * pg_start_backup: set up for taking an on-line backup dump
+ * pg_backup_start: set up for taking an on-line backup dump
*
* Essentially what this does is to create a backup label file in $PGDATA,
* where it will be archived as part of the backup dump. The label file
@@ -57,105 +57,44 @@ static StringInfo tblspc_map_file;
* GRANT system.
*/
Datum
-pg_start_backup(PG_FUNCTION_ARGS)
+pg_backup_start(PG_FUNCTION_ARGS)
{
text *backupid = PG_GETARG_TEXT_PP(0);
bool fast = PG_GETARG_BOOL(1);
- bool exclusive = PG_GETARG_BOOL(2);
char *backupidstr;
XLogRecPtr startpoint;
SessionBackupState status = get_backup_status();
+ MemoryContext oldcontext;
backupidstr = text_to_cstring(backupid);
- if (status == SESSION_BACKUP_NON_EXCLUSIVE)
+ if (status == SESSION_BACKUP_RUNNING)
ereport(ERROR,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("a backup is already in progress in this session")));
- if (exclusive)
- {
- startpoint = do_pg_start_backup(backupidstr, fast, NULL, NULL,
- NULL, NULL);
- }
- else
- {
- MemoryContext oldcontext;
-
- /*
- * Label file and tablespace map file need to be long-lived, since
- * they are read in pg_stop_backup.
- */
- oldcontext = MemoryContextSwitchTo(TopMemoryContext);
- label_file = makeStringInfo();
- tblspc_map_file = makeStringInfo();
- MemoryContextSwitchTo(oldcontext);
+ /*
+ * Label file and tablespace map file need to be long-lived, since
+ * they are read in pg_backup_stop.
+ */
+ oldcontext = MemoryContextSwitchTo(TopMemoryContext);
+ label_file = makeStringInfo();
+ tblspc_map_file = makeStringInfo();
+ MemoryContextSwitchTo(oldcontext);
- register_persistent_abort_backup_handler();
+ register_persistent_abort_backup_handler();
- startpoint = do_pg_start_backup(backupidstr, fast, NULL, label_file,
- NULL, tblspc_map_file);
- }
+ startpoint = do_pg_backup_start(backupidstr, fast, NULL, label_file,
+ NULL, tblspc_map_file);
PG_RETURN_LSN(startpoint);
}
-/*
- * pg_stop_backup: finish taking an on-line backup dump
- *
- * We write an end-of-backup WAL record, and remove the backup label file
- * created by pg_start_backup, creating a backup history file in pg_wal
- * instead (whence it will immediately be archived). The backup history file
- * contains the same info found in the label file, plus the backup-end time
- * and WAL location. Before 9.0, the backup-end time was read from the backup
- * history file at the beginning of archive recovery, but we now use the WAL
- * record for that and the file is for informational and debug purposes only.
- *
- * Note: different from CancelBackup which just cancels online backup mode.
- *
- * Note: this version is only called to stop an exclusive backup. The function
- * pg_stop_backup_v2 (overloaded as pg_stop_backup in SQL) is called to
- * stop non-exclusive backups.
- *
- * Permission checking for this function is managed through the normal
- * GRANT system.
- */
-Datum
-pg_stop_backup(PG_FUNCTION_ARGS)
-{
- XLogRecPtr stoppoint;
- SessionBackupState status = get_backup_status();
-
- if (status == SESSION_BACKUP_NON_EXCLUSIVE)
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("non-exclusive backup in progress"),
- errhint("Did you mean to use pg_stop_backup('f')?")));
-
- /*
- * Exclusive backups were typically started in a different connection, so
- * don't try to verify that status of backup is set to
- * SESSION_BACKUP_EXCLUSIVE in this function. Actual verification that an
- * exclusive backup is in fact running is handled inside
- * do_pg_stop_backup.
- */
- stoppoint = do_pg_stop_backup(NULL, true, NULL);
-
- PG_RETURN_LSN(stoppoint);
-}
-
/*
- * pg_stop_backup_v2: finish taking exclusive or nonexclusive on-line backup.
- *
- * Works the same as pg_stop_backup, except for non-exclusive backups it returns
- * the backup label and tablespace map files as text fields in as part of the
- * resultset.
+ * pg_backup_stop: finish taking an on-line backup.
*
- * The first parameter (variable 'exclusive') allows the user to tell us if
- * this is an exclusive or a non-exclusive backup.
- *
- * The second parameter (variable 'waitforarchive'), which is optional,
+ * The first parameter (variable 'waitforarchive'), which is optional,
* allows the user to choose if they want to wait for the WAL to be archived
* or if we should just return as soon as the WAL record is written.
*
@@ -163,15 +102,14 @@ pg_stop_backup(PG_FUNCTION_ARGS)
* GRANT system.
*/
Datum
-pg_stop_backup_v2(PG_FUNCTION_ARGS)
+pg_backup_stop(PG_FUNCTION_ARGS)
{
#define PG_STOP_BACKUP_V2_COLS 3
TupleDesc tupdesc;
Datum values[PG_STOP_BACKUP_V2_COLS];
bool nulls[PG_STOP_BACKUP_V2_COLS];
- bool exclusive = PG_GETARG_BOOL(0);
- bool waitforarchive = PG_GETARG_BOOL(1);
+ bool waitforarchive = PG_GETARG_BOOL(0);
XLogRecPtr stoppoint;
SessionBackupState status = get_backup_status();
@@ -182,51 +120,29 @@ pg_stop_backup_v2(PG_FUNCTION_ARGS)
MemSet(values, 0, sizeof(values));
MemSet(nulls, 0, sizeof(nulls));
- if (exclusive)
- {
- if (status == SESSION_BACKUP_NON_EXCLUSIVE)
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("non-exclusive backup in progress"),
- errhint("Did you mean to use pg_stop_backup('f')?")));
-
- /*
- * Stop the exclusive backup, and since we're in an exclusive backup
- * return NULL for both backup_label and tablespace_map.
- */
- stoppoint = do_pg_stop_backup(NULL, waitforarchive, NULL);
-
- nulls[1] = true;
- nulls[2] = true;
- }
- else
- {
- if (status != SESSION_BACKUP_NON_EXCLUSIVE)
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("non-exclusive backup is not in progress"),
- errhint("Did you mean to use pg_stop_backup('t')?")));
+ if (status != SESSION_BACKUP_RUNNING)
+ ereport(ERROR,
+ (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ errmsg("backup is not in progress"),
+ errhint("Did you call pg_backup_start()?")));
- /*
- * Stop the non-exclusive backup. Return a copy of the backup label
- * and tablespace map so they can be written to disk by the caller.
- */
- stoppoint = do_pg_stop_backup(label_file->data, waitforarchive, NULL);
-
- values[1] = CStringGetTextDatum(label_file->data);
- values[2] = CStringGetTextDatum(tblspc_map_file->data);
-
- /* Free structures allocated in TopMemoryContext */
- pfree(label_file->data);
- pfree(label_file);
- label_file = NULL;
- pfree(tblspc_map_file->data);
- pfree(tblspc_map_file);
- tblspc_map_file = NULL;
- }
+ /*
+ * Stop the backup. Return a copy of the backup label and tablespace map so
+ * they can be written to disk by the caller.
+ */
+ stoppoint = do_pg_backup_stop(label_file->data, waitforarchive, NULL);
- /* Stoppoint is included on both exclusive and nonexclusive backups */
values[0] = LSNGetDatum(stoppoint);
+ values[1] = CStringGetTextDatum(label_file->data);
+ values[2] = CStringGetTextDatum(tblspc_map_file->data);
+
+ /* Free structures allocated in TopMemoryContext */
+ pfree(label_file->data);
+ pfree(label_file);
+ label_file = NULL;
+ pfree(tblspc_map_file->data);
+ pfree(tblspc_map_file);
+ tblspc_map_file = NULL;
/* Returns the record as Datum */
PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
@@ -298,7 +214,7 @@ pg_create_restore_point(PG_FUNCTION_ARGS)
}
/*
- * Report the current WAL write location (same format as pg_start_backup etc)
+ * Report the current WAL write location (same format as pg_backup_start etc)
*
* This is useful for determining how much of WAL is visible to an external
* archiving process. Note that the data before this point is written out
@@ -321,7 +237,7 @@ pg_current_wal_lsn(PG_FUNCTION_ARGS)
}
/*
- * Report the current WAL insert location (same format as pg_start_backup etc)
+ * Report the current WAL insert location (same format as pg_backup_start etc)
*
* This function is mostly for debugging purposes.
*/
@@ -342,7 +258,7 @@ pg_current_wal_insert_lsn(PG_FUNCTION_ARGS)
}
/*
- * Report the current WAL flush location (same format as pg_start_backup etc)
+ * Report the current WAL flush location (same format as pg_backup_start etc)
*
* This function is mostly for debugging purposes.
*/
@@ -363,7 +279,7 @@ pg_current_wal_flush_lsn(PG_FUNCTION_ARGS)
}
/*
- * Report the last WAL receive location (same format as pg_start_backup etc)
+ * Report the last WAL receive location (same format as pg_backup_start etc)
*
* This is useful for determining how much of WAL is guaranteed to be received
* and synced to disk by walreceiver.
@@ -382,7 +298,7 @@ pg_last_wal_receive_lsn(PG_FUNCTION_ARGS)
}
/*
- * Report the last WAL replay location (same format as pg_start_backup etc)
+ * Report the last WAL replay location (same format as pg_backup_start etc)
*
* This is useful for determining how much of WAL is visible to read-only
* connections during recovery.
@@ -402,7 +318,7 @@ pg_last_wal_replay_lsn(PG_FUNCTION_ARGS)
/*
* Compute an xlog file name and decimal byte offset given a WAL location,
- * such as is returned by pg_stop_backup() or pg_switch_wal().
+ * such as is returned by pg_backup_stop() or pg_switch_wal().
*
* Note that a location exactly at a segment boundary is taken to be in
* the previous segment. This is usually the right thing, since the
@@ -470,7 +386,7 @@ pg_walfile_name_offset(PG_FUNCTION_ARGS)
/*
* Compute an xlog file name given a WAL location,
- * such as is returned by pg_stop_backup() or pg_switch_wal().
+ * such as is returned by pg_backup_stop() or pg_switch_wal().
*/
Datum
pg_walfile_name(PG_FUNCTION_ARGS)
@@ -645,81 +561,6 @@ pg_wal_lsn_diff(PG_FUNCTION_ARGS)
PG_RETURN_NUMERIC(result);
}
-/*
- * Returns bool with current on-line backup mode, a global state.
- */
-Datum
-pg_is_in_backup(PG_FUNCTION_ARGS)
-{
- PG_RETURN_BOOL(BackupInProgress());
-}
-
-/*
- * Returns start time of an online exclusive backup.
- *
- * When there's no exclusive backup in progress, the function
- * returns NULL.
- */
-Datum
-pg_backup_start_time(PG_FUNCTION_ARGS)
-{
- Datum xtime;
- FILE *lfp;
- char fline[MAXPGPATH];
- char backup_start_time[30];
-
- /*
- * See if label file is present
- */
- lfp = AllocateFile(BACKUP_LABEL_FILE, "r");
- if (lfp == NULL)
- {
- if (errno != ENOENT)
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not read file \"%s\": %m",
- BACKUP_LABEL_FILE)));
- PG_RETURN_NULL();
- }
-
- /*
- * Parse the file to find the START TIME line.
- */
- backup_start_time[0] = '\0';
- while (fgets(fline, sizeof(fline), lfp) != NULL)
- {
- if (sscanf(fline, "START TIME: %25[^\n]\n", backup_start_time) == 1)
- break;
- }
-
- /* Check for a read error. */
- if (ferror(lfp))
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not read file \"%s\": %m", BACKUP_LABEL_FILE)));
-
- /* Close the backup label file. */
- if (FreeFile(lfp))
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not close file \"%s\": %m", BACKUP_LABEL_FILE)));
-
- if (strlen(backup_start_time) == 0)
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("invalid data in file \"%s\"", BACKUP_LABEL_FILE)));
-
- /*
- * Convert the time string read from file to TimestampTz form.
- */
- xtime = DirectFunctionCall3(timestamptz_in,
- CStringGetDatum(backup_start_time),
- ObjectIdGetDatum(InvalidOid),
- Int32GetDatum(-1));
-
- PG_RETURN_DATUM(xtime);
-}
-
/*
* Promotes a standby server.
*
diff --git a/src/backend/access/transam/xlogrecovery.c b/src/backend/access/transam/xlogrecovery.c
index 8b22c4e634..9bfaa449f9 100644
--- a/src/backend/access/transam/xlogrecovery.c
+++ b/src/backend/access/transam/xlogrecovery.c
@@ -1970,7 +1970,7 @@ xlogrecovery_redo(XLogReaderState *record, TimeLineID replayTLI)
{
/*
* We have reached the end of base backup, the point where
- * pg_stop_backup() was done. The data on disk is now consistent
+ * pg_backup_stop() was done. The data on disk is now consistent
* (assuming we have also reached minRecoveryPoint). Set
* backupEndPoint to the current LSN, so that the next call to
* CheckRecoveryConsistency() will notice it and do the
diff --git a/src/backend/catalog/system_functions.sql b/src/backend/catalog/system_functions.sql
index 81bac6f581..6ae4388d3f 100644
--- a/src/backend/catalog/system_functions.sql
+++ b/src/backend/catalog/system_functions.sql
@@ -377,14 +377,14 @@ BEGIN ATOMIC
END;
CREATE OR REPLACE FUNCTION
- pg_start_backup(label text, fast boolean DEFAULT false, exclusive boolean DEFAULT true)
- RETURNS pg_lsn STRICT VOLATILE LANGUAGE internal AS 'pg_start_backup'
+ pg_backup_start(label text, fast boolean DEFAULT false)
+ RETURNS pg_lsn STRICT VOLATILE LANGUAGE internal AS 'pg_backup_start'
PARALLEL RESTRICTED;
-CREATE OR REPLACE FUNCTION pg_stop_backup (
- exclusive boolean, wait_for_archive boolean DEFAULT true,
- OUT lsn pg_lsn, OUT labelfile text, OUT spcmapfile text)
- RETURNS record STRICT VOLATILE LANGUAGE internal as 'pg_stop_backup_v2'
+CREATE OR REPLACE FUNCTION pg_backup_stop (
+ wait_for_archive boolean DEFAULT true, OUT lsn pg_lsn,
+ OUT labelfile text, OUT spcmapfile text)
+ RETURNS record STRICT VOLATILE LANGUAGE internal as 'pg_backup_stop'
PARALLEL RESTRICTED;
CREATE OR REPLACE FUNCTION
@@ -603,11 +603,9 @@ AS 'unicode_is_normalized';
-- available to superuser / cluster owner, if they choose.
--
-REVOKE EXECUTE ON FUNCTION pg_start_backup(text, boolean, boolean) FROM public;
+REVOKE EXECUTE ON FUNCTION pg_backup_start(text, boolean) FROM public;
-REVOKE EXECUTE ON FUNCTION pg_stop_backup() FROM public;
-
-REVOKE EXECUTE ON FUNCTION pg_stop_backup(boolean, boolean) FROM public;
+REVOKE EXECUTE ON FUNCTION pg_backup_stop(boolean) FROM public;
REVOKE EXECUTE ON FUNCTION pg_create_restore_point(text) FROM public;
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index 80bb269599..b6767ed72e 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -348,7 +348,6 @@ static PMState pmState = PM_INIT;
typedef enum
{
ALLOW_ALL_CONNS, /* normal not-shutting-down state */
- ALLOW_SUPERUSER_CONNS, /* only superusers can connect */
ALLOW_NO_CONNS /* no new connections allowed, period */
} ConnsAllowedState;
@@ -2546,19 +2545,11 @@ canAcceptConnections(int backend_type)
/*
* "Smart shutdown" restrictions are applied only to normal connections,
- * not to autovac workers or bgworkers. When only superusers can connect,
- * we return CAC_SUPERUSER to indicate that superuserness must be checked
- * later. Note that neither CAC_OK nor CAC_SUPERUSER can safely be
- * returned until we have checked for too many children.
+ * not to autovac workers or bgworkers.
*/
if (connsAllowed != ALLOW_ALL_CONNS &&
backend_type == BACKEND_TYPE_NORMAL)
- {
- if (connsAllowed == ALLOW_SUPERUSER_CONNS)
- result = CAC_SUPERUSER; /* allow superusers only */
- else
- return CAC_SHUTDOWN; /* shutdown is pending */
- }
+ return CAC_SHUTDOWN; /* shutdown is pending */
/*
* Don't start too many children.
@@ -2877,16 +2868,11 @@ pmdie(SIGNAL_ARGS)
#endif
/*
- * If we reached normal running, we have to wait for any online
- * backup mode to end; otherwise go straight to waiting for client
- * backends to exit. (The difference is that in the former state,
- * we'll still let in new superuser clients, so that somebody can
- * end the online backup mode.) If already in PM_STOP_BACKENDS or
+ * If we reached normal running, we go straight to waiting for
+ * client backends to exit. If already in PM_STOP_BACKENDS or
* a later state, do not change it.
*/
- if (pmState == PM_RUN)
- connsAllowed = ALLOW_SUPERUSER_CONNS;
- else if (pmState == PM_HOT_STANDBY)
+ if (pmState == PM_RUN || pmState == PM_HOT_STANDBY)
connsAllowed = ALLOW_NO_CONNS;
else if (pmState == PM_STARTUP || pmState == PM_RECOVERY)
{
@@ -3842,16 +3828,6 @@ PostmasterStateMachine(void)
/* If we're doing a smart shutdown, try to advance that state. */
if (pmState == PM_RUN || pmState == PM_HOT_STANDBY)
{
- if (connsAllowed == ALLOW_SUPERUSER_CONNS)
- {
- /*
- * ALLOW_SUPERUSER_CONNS state ends as soon as online backup mode
- * is not active.
- */
- if (!BackupInProgress())
- connsAllowed = ALLOW_NO_CONNS;
- }
-
if (connsAllowed == ALLOW_NO_CONNS)
{
/*
@@ -4044,18 +4020,6 @@ PostmasterStateMachine(void)
}
else
{
- /*
- * Terminate exclusive backup mode to avoid recovery after a clean
- * fast shutdown. Since an exclusive backup can only be taken
- * during normal running (and not, for example, while running
- * under Hot Standby) it only makes sense to do this if we reached
- * normal running. If we're still in recovery, the backup file is
- * one we're recovering *from*, and we must keep it around so that
- * recovery restarts from the right place.
- */
- if (ReachedNormalRunning)
- CancelBackup();
-
/*
* Normal exit from the postmaster is here. We don't need to log
* anything here, since the UnlinkLockFiles proc_exit callback
diff --git a/src/backend/replication/basebackup.c b/src/backend/replication/basebackup.c
index 6884cad2c0..1066f29954 100644
--- a/src/backend/replication/basebackup.c
+++ b/src/backend/replication/basebackup.c
@@ -184,10 +184,8 @@ static const struct exclude_list_item excludeFiles[] =
{RELCACHE_INIT_FILENAME, true},
/*
- * If there's a backup_label or tablespace_map file, it belongs to a
- * backup started by the user with pg_start_backup(). It is *not* correct
- * for this backup. Our backup_label/tablespace_map is injected into the
- * tar separately.
+ * backup_label and tablespace_map should not exist in in a running cluster
+ * capable of doing an online backup, but exclude then just in case.
*/
{BACKUP_LABEL_FILE, false},
{TABLESPACE_MAP, false},
@@ -264,16 +262,16 @@ perform_base_backup(basebackup_options *opt, bbsink *sink)
total_checksum_failures = 0;
basebackup_progress_wait_checkpoint();
- state.startptr = do_pg_start_backup(opt->label, opt->fastcheckpoint,
+ state.startptr = do_pg_backup_start(opt->label, opt->fastcheckpoint,
&state.starttli,
labelfile, &state.tablespaces,
tblspc_map_file);
/*
- * Once do_pg_start_backup has been called, ensure that any failure causes
+ * Once do_pg_backup_start has been called, ensure that any failure causes
* us to abort the backup so we don't "leak" a backup counter. For this
- * reason, *all* functionality between do_pg_start_backup() and the end of
- * do_pg_stop_backup() should be inside the error cleanup block!
+ * reason, *all* functionality between do_pg_backup_start() and the end of
+ * do_pg_backup_stop() should be inside the error cleanup block!
*/
PG_ENSURE_ERROR_CLEANUP(do_pg_abort_backup, BoolGetDatum(false));
@@ -394,7 +392,7 @@ perform_base_backup(basebackup_options *opt, bbsink *sink)
}
basebackup_progress_wait_wal_archive(&state);
- endptr = do_pg_stop_backup(labelfile->data, !opt->nowait, &endtli);
+ endptr = do_pg_backup_stop(labelfile->data, !opt->nowait, &endtli);
}
PG_END_ENSURE_ERROR_CLEANUP(do_pg_abort_backup, BoolGetDatum(false));
@@ -961,7 +959,7 @@ parse_basebackup_options(List *options, basebackup_options *opt)
/*
* SendBaseBackup() - send a complete base backup.
*
- * The function will put the system into backup mode like pg_start_backup()
+ * The function will put the system into backup mode like pg_backup_start()
* does, so that the backup is consistent even though we read directly from
* the filesystem, bypassing the buffer cache.
*/
@@ -1204,7 +1202,7 @@ sendDir(bbsink *sink, const char *path, int basepathlen, bool sizeonly,
* error in that case. The error handler further up will call
* do_pg_abort_backup() for us. Also check that if the backup was
* started while still in recovery, the server wasn't promoted.
- * do_pg_stop_backup() will check that too, but it's better to stop
+ * do_pg_backup_stop() will check that too, but it's better to stop
* the backup early than continue to the end and fail there.
*/
CHECK_FOR_INTERRUPTS();
diff --git a/src/bin/pg_basebackup/t/010_pg_basebackup.pl b/src/bin/pg_basebackup/t/010_pg_basebackup.pl
index 47f3d00ac4..d3d353b903 100644
--- a/src/bin/pg_basebackup/t/010_pg_basebackup.pl
+++ b/src/bin/pg_basebackup/t/010_pg_basebackup.pl
@@ -242,6 +242,10 @@ isnt(slurp_file("$tempdir/backup/backup_label"),
'DONOTCOPY', 'existing backup_label not copied');
rmtree("$tempdir/backup");
+# Now delete the bogus backup_label file since it will interfere with startup
+unlink("$pgdata/backup_label")
+ or BAIL_OUT("unable to unlink $pgdata/backup_label");
+
$node->command_ok(
[
@pg_basebackup_defs, '-D',
diff --git a/src/bin/pg_ctl/pg_ctl.c b/src/bin/pg_ctl/pg_ctl.c
index 3c182c97d4..3a9092a16a 100644
--- a/src/bin/pg_ctl/pg_ctl.c
+++ b/src/bin/pg_ctl/pg_ctl.c
@@ -1025,7 +1025,6 @@ static void
do_stop(void)
{
pgpid_t pid;
- struct stat statbuf;
pid = get_pgpid(false);
@@ -1058,20 +1057,6 @@ do_stop(void)
}
else
{
- /*
- * If backup_label exists, an online backup is running. Warn the user
- * that smart shutdown will wait for it to finish. However, if the
- * server is in archive recovery, we're recovering from an online
- * backup instead of performing one.
- */
- if (shutdown_mode == SMART_MODE &&
- stat(backup_file, &statbuf) == 0 &&
- get_control_dbstate() != DB_IN_ARCHIVE_RECOVERY)
- {
- print_msg(_("WARNING: online backup mode is active\n"
- "Shutdown will not complete until pg_stop_backup() is called.\n\n"));
- }
-
print_msg(_("waiting for server to shut down..."));
if (!wait_for_postmaster_stop())
@@ -1099,7 +1084,6 @@ static void
do_restart(void)
{
pgpid_t pid;
- struct stat statbuf;
pid = get_pgpid(false);
@@ -1134,20 +1118,6 @@ do_restart(void)
exit(1);
}
- /*
- * If backup_label exists, an online backup is running. Warn the user
- * that smart shutdown will wait for it to finish. However, if the
- * server is in archive recovery, we're recovering from an online
- * backup instead of performing one.
- */
- if (shutdown_mode == SMART_MODE &&
- stat(backup_file, &statbuf) == 0 &&
- get_control_dbstate() != DB_IN_ARCHIVE_RECOVERY)
- {
- print_msg(_("WARNING: online backup mode is active\n"
- "Shutdown will not complete until pg_stop_backup() is called.\n\n"));
- }
-
print_msg(_("waiting for server to shut down..."));
/* always wait for restart */
diff --git a/src/bin/pg_rewind/filemap.c b/src/bin/pg_rewind/filemap.c
index 7211090f47..fb52debf7a 100644
--- a/src/bin/pg_rewind/filemap.c
+++ b/src/bin/pg_rewind/filemap.c
@@ -140,9 +140,9 @@ static const struct exclude_list_item excludeFiles[] =
{"pg_internal.init", true}, /* defined as RELCACHE_INIT_FILENAME */
/*
- * If there's a backup_label or tablespace_map file, it belongs to a
- * backup started by the user with pg_start_backup(). It is *not* correct
- * for this backup. Our backup_label is written later on separately.
+ * If there is a backup_label or tablespace_map file, it indicates that
+ * a recovery failed and this cluster probably can't be rewound, but
+ * exclude them anyway if they are found.
*/
{"backup_label", false}, /* defined as BACKUP_LABEL_FILE */
{"tablespace_map", false}, /* defined as TABLESPACE_MAP */
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index 09f6464331..b81917f243 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -276,14 +276,13 @@ extern void XLogShutdownWalRcv(void);
typedef enum SessionBackupState
{
SESSION_BACKUP_NONE,
- SESSION_BACKUP_EXCLUSIVE,
- SESSION_BACKUP_NON_EXCLUSIVE
+ SESSION_BACKUP_RUNNING,
} SessionBackupState;
-extern XLogRecPtr do_pg_start_backup(const char *backupidstr, bool fast,
+extern XLogRecPtr do_pg_backup_start(const char *backupidstr, bool fast,
TimeLineID *starttli_p, StringInfo labelfile,
List **tablespaces, StringInfo tblspcmapfile);
-extern XLogRecPtr do_pg_stop_backup(char *labelfile, bool waitforarchive,
+extern XLogRecPtr do_pg_backup_stop(char *labelfile, bool waitforarchive,
TimeLineID *stoptli_p);
extern void do_pg_abort_backup(int code, Datum arg);
extern void register_persistent_abort_backup_handler(void);
diff --git a/src/include/catalog/pg_control.h b/src/include/catalog/pg_control.h
index 1f3dc24ac1..3d075fcef3 100644
--- a/src/include/catalog/pg_control.h
+++ b/src/include/catalog/pg_control.h
@@ -163,7 +163,7 @@ typedef struct ControlFileData
* from a backup, and must see a backup-end record before we can safely
* start up. If it's false, but backupStartPoint is set, a backup_label
* file was found at startup but it may have been a leftover from a stray
- * pg_start_backup() call, not accompanied by pg_stop_backup().
+ * pg_backup_start() call, not accompanied by pg_backup_stop().
*/
XLogRecPtr minRecoveryPoint;
TimeLineID minRecoveryPointTLI;
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index deb00307f6..3e869af1e9 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -6268,26 +6268,16 @@
proargtypes => 'int4 int8', proargnames => '{pid,timeout}',
prosrc => 'pg_terminate_backend' },
{ oid => '2172', descr => 'prepare for taking an online backup',
- proname => 'pg_start_backup', provolatile => 'v', proparallel => 'r',
- prorettype => 'pg_lsn', proargtypes => 'text bool bool',
- prosrc => 'pg_start_backup' },
-{ oid => '2173', descr => 'finish taking an online backup',
- proname => 'pg_stop_backup', provolatile => 'v', proparallel => 'r',
- prorettype => 'pg_lsn', proargtypes => '', prosrc => 'pg_stop_backup' },
+ proname => 'pg_backup_start', provolatile => 'v', proparallel => 'r',
+ prorettype => 'pg_lsn', proargtypes => 'text bool',
+ prosrc => 'pg_backup_start' },
{ oid => '2739', descr => 'finish taking an online backup',
- proname => 'pg_stop_backup', provolatile => 'v', proparallel => 'r',
- prorettype => 'record', proargtypes => 'bool bool',
- proallargtypes => '{bool,bool,pg_lsn,text,text}',
- proargmodes => '{i,i,o,o,o}',
- proargnames => '{exclusive,wait_for_archive,lsn,labelfile,spcmapfile}',
- prosrc => 'pg_stop_backup_v2' },
-{ oid => '3813', descr => 'true if server is in online backup',
- proname => 'pg_is_in_backup', provolatile => 'v', prorettype => 'bool',
- proargtypes => '', prosrc => 'pg_is_in_backup' },
-{ oid => '3814', descr => 'start time of an online backup',
- proname => 'pg_backup_start_time', provolatile => 's',
- prorettype => 'timestamptz', proargtypes => '',
- prosrc => 'pg_backup_start_time' },
+ proname => 'pg_backup_stop', provolatile => 'v', proparallel => 'r',
+ prorettype => 'record', proargtypes => 'bool',
+ proallargtypes => '{bool,pg_lsn,text,text}',
+ proargmodes => '{i,o,o,o}',
+ proargnames => '{wait_for_archive,lsn,labelfile,spcmapfile}',
+ prosrc => 'pg_backup_stop' },
{ oid => '3436', descr => 'promote standby server',
proname => 'pg_promote', provolatile => 'v', prorettype => 'bool',
proargtypes => 'bool int4', proargnames => '{wait,wait_seconds}',
diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h
index 0abc3ad540..9321d7f264 100644
--- a/src/include/miscadmin.h
+++ b/src/include/miscadmin.h
@@ -481,10 +481,6 @@ extern void process_session_preload_libraries(void);
extern void pg_bindtextdomain(const char *domain);
extern bool has_rolreplication(Oid roleid);
-/* in access/transam/xlog.c */
-extern bool BackupInProgress(void);
-extern void CancelBackup(void);
-
/* in executor/nodeHash.c */
extern size_t get_hash_memory_limit(void);
diff --git a/src/test/perl/PostgreSQL/Test/Cluster.pm b/src/test/perl/PostgreSQL/Test/Cluster.pm
index bee6aacf47..40857118a0 100644
--- a/src/test/perl/PostgreSQL/Test/Cluster.pm
+++ b/src/test/perl/PostgreSQL/Test/Cluster.pm
@@ -634,25 +634,6 @@ sub backup
return;
}
-=item $node->backup_fs_hot(backup_name)
-
-Create a backup with a filesystem level copy in subdirectory B<backup_name> of
-B<< $node->backup_dir >>, including WAL.
-
-Archiving must be enabled, as B<pg_start_backup()> and B<pg_stop_backup()> are
-used. This is not checked or enforced.
-
-The backup name is passed as the backup label to B<pg_start_backup()>.
-
-=cut
-
-sub backup_fs_hot
-{
- my ($self, $backup_name) = @_;
- $self->_backup_fs($backup_name, 1);
- return;
-}
-
=item $node->backup_fs_cold(backup_name)
Create a backup with a filesystem level copy in subdirectory B<backup_name> of
@@ -666,53 +647,18 @@ Use B<backup> or B<backup_fs_hot> if you want to back up a running server.
sub backup_fs_cold
{
my ($self, $backup_name) = @_;
- $self->_backup_fs($backup_name, 0);
- return;
-}
-
-
-# Common sub of backup_fs_hot and backup_fs_cold
-sub _backup_fs
-{
- my ($self, $backup_name, $hot) = @_;
- my $backup_path = $self->backup_dir . '/' . $backup_name;
- my $port = $self->port;
- my $name = $self->name;
-
- print "# Taking filesystem backup $backup_name from node \"$name\"\n";
-
- if ($hot)
- {
- my $stdout = $self->safe_psql('postgres',
- "SELECT * FROM pg_start_backup('$backup_name');");
- print "# pg_start_backup: $stdout\n";
- }
PostgreSQL::Test::RecursiveCopy::copypath(
$self->data_dir,
- $backup_path,
+ $self->backup_dir . '/' . $backup_name,
filterfn => sub {
my $src = shift;
return ($src ne 'log' and $src ne 'postmaster.pid');
});
- if ($hot)
- {
-
- # We ignore pg_stop_backup's return value. We also assume archiving
- # is enabled; otherwise the caller will have to copy the remaining
- # segments.
- my $stdout =
- $self->safe_psql('postgres', 'SELECT * FROM pg_stop_backup();');
- print "# pg_stop_backup: $stdout\n";
- }
-
- print "# Backup finished\n";
return;
}
-
-
=pod
=item $node->init_from_backup(root_node, backup_name)
diff --git a/src/test/recovery/t/010_logical_decoding_timelines.pl b/src/test/recovery/t/010_logical_decoding_timelines.pl
index 01ff31e61f..135fb1a72d 100644
--- a/src/test/recovery/t/010_logical_decoding_timelines.pl
+++ b/src/test/recovery/t/010_logical_decoding_timelines.pl
@@ -69,7 +69,9 @@ $node_primary->safe_psql('dropme',
$node_primary->safe_psql('postgres', 'CHECKPOINT;');
my $backup_name = 'b1';
-$node_primary->backup_fs_hot($backup_name);
+$node_primary->stop();
+$node_primary->backup_fs_cold($backup_name);
+$node_primary->start();
$node_primary->safe_psql('postgres',
q[SELECT pg_create_physical_replication_slot('phys_slot');]);
--
2.25.1
On 3/28/22 10:09 PM, Nathan Bossart wrote:
On Mon, Mar 28, 2022 at 04:30:27PM -0400, Stephen Frost wrote:
On a once-over of the rest of the code, I definitely like how much we're
able to simplify things in this area and remove various hacks in things
like pg_basebackup and pg_rewind where we previously had to worry about
backup_label and tablespace_map files being in a live data directory.
I'm planning to spend more time on this and hopefully be able to get it
in for v15.Great! Much appreciated.
Minor typo in the docs:
+ * capable of doing an online backup, but exclude then just in case.
Should be:
capable of doing an online backup, but exclude them just in case.
Regards,
--
-David
david@pgmasters.net
On Mon, Apr 04, 2022 at 09:56:26AM -0400, David Steele wrote:
Minor typo in the docs:
+ * capable of doing an online backup, but exclude then just in case.
Should be:
capable of doing an online backup, but exclude them just in case.
fixed
--
Nathan Bossart
Amazon Web Services: https://aws.amazon.com
Attachments:
v9-0001-remove-exclusive-backup-mode.patchtext/x-diff; charset=us-asciiDownload
From 8960a15630290e49af4906a6951eced563efce7d Mon Sep 17 00:00:00 2001
From: Nathan Bossart <bossartn@amazon.com>
Date: Wed, 1 Dec 2021 23:50:49 +0000
Subject: [PATCH v9 1/1] remove exclusive backup mode
---
doc/src/sgml/backup.sgml | 230 +-------
doc/src/sgml/func.sgml | 111 +---
doc/src/sgml/high-availability.sgml | 6 +-
doc/src/sgml/monitoring.sgml | 4 +-
doc/src/sgml/ref/pgupgrade.sgml | 2 +-
src/backend/access/transam/xlog.c | 493 ++----------------
src/backend/access/transam/xlogfuncs.c | 253 ++-------
src/backend/access/transam/xlogrecovery.c | 2 +-
src/backend/catalog/system_functions.sql | 18 +-
src/backend/postmaster/postmaster.c | 46 +-
src/backend/replication/basebackup.c | 20 +-
src/bin/pg_basebackup/t/010_pg_basebackup.pl | 4 +
src/bin/pg_ctl/pg_ctl.c | 30 --
src/bin/pg_rewind/filemap.c | 6 +-
src/include/access/xlog.h | 7 +-
src/include/catalog/pg_control.h | 2 +-
src/include/catalog/pg_proc.dat | 28 +-
src/include/miscadmin.h | 4 -
src/test/perl/PostgreSQL/Test/Cluster.pm | 56 +-
.../t/010_logical_decoding_timelines.pl | 4 +-
20 files changed, 199 insertions(+), 1127 deletions(-)
diff --git a/doc/src/sgml/backup.sgml b/doc/src/sgml/backup.sgml
index 0d69851bb1..5b7139c7df 100644
--- a/doc/src/sgml/backup.sgml
+++ b/doc/src/sgml/backup.sgml
@@ -857,16 +857,8 @@ test ! -f /mnt/server/archivedir/00000001000000A900000065 && cp pg_wal/0
sequence, and that the success of a step is verified before
proceeding to the next step.
</para>
- <para>
- Low level base backups can be made in a non-exclusive or an exclusive
- way. The non-exclusive method is recommended and the exclusive one is
- deprecated and will eventually be removed.
- </para>
-
- <sect3 id="backup-lowlevel-base-backup-nonexclusive">
- <title>Making a Non-Exclusive Low-Level Backup</title>
<para>
- A non-exclusive low level backup is one that allows other
+ A low level backup allows other
concurrent backups to be running (both those started using
the same backup API and those started using
<xref linkend="app-pgbasebackup"/>).
@@ -881,23 +873,23 @@ test ! -f /mnt/server/archivedir/00000001000000A900000065 && cp pg_wal/0
<listitem>
<para>
Connect to the server (it does not matter which database) as a user with
- rights to run pg_start_backup (superuser, or a user who has been granted
+ rights to run pg_backup_start (superuser, or a user who has been granted
EXECUTE on the function) and issue the command:
<programlisting>
-SELECT pg_start_backup('label', false, false);
+SELECT pg_backup_start(label => 'label', fast => false);
</programlisting>
where <literal>label</literal> is any string you want to use to uniquely
identify this backup operation. The connection
- calling <function>pg_start_backup</function> must be maintained until the end of
+ calling <function>pg_backup_start</function> must be maintained until the end of
the backup, or the backup will be automatically aborted.
</para>
<para>
- By default, <function>pg_start_backup</function> can take a long time to finish.
- This is because it performs a checkpoint, and the I/O
- required for the checkpoint will be spread out over a significant
- period of time, by default half your inter-checkpoint interval
- (see the configuration parameter
+ By default, <function>pg_backup_start</function> can take a long time to finish.
+ This is because it waits for the next checkpoint to complete, and the I/O
+ required for the checkpoint might be spread out over a significant
+ period of time (see the configuration parameters
+ <xref linkend="guc-checkpoint-timeout"/> and
<xref linkend="guc-checkpoint-completion-target"/>). This is
usually what you want, because it minimizes the impact on query
processing. If you want to start the backup as soon as
@@ -905,10 +897,6 @@ SELECT pg_start_backup('label', false, false);
issue an immediate checkpoint using as much I/O as available.
</para>
- <para>
- The third parameter being <literal>false</literal> tells
- <function>pg_start_backup</function> to initiate a non-exclusive base backup.
- </para>
</listitem>
<listitem>
<para>
@@ -926,7 +914,7 @@ SELECT pg_start_backup('label', false, false);
<para>
In the same connection as before, issue the command:
<programlisting>
-SELECT * FROM pg_stop_backup(false, true);
+SELECT * FROM pg_backup_stop(wait_for_archive => true);
</programlisting>
This terminates backup mode. On a primary, it also performs an automatic
switch to the next WAL segment. On a standby, it is not possible to
@@ -937,7 +925,7 @@ SELECT * FROM pg_stop_backup(false, true);
ready to archive.
</para>
<para>
- The <function>pg_stop_backup</function> will return one row with three
+ <function>pg_backup_stop</function> will return one row with three
values. The second of these fields should be written to a file named
<filename>backup_label</filename> in the root directory of the backup. The
third field should be written to a file named
@@ -949,14 +937,14 @@ SELECT * FROM pg_stop_backup(false, true);
<listitem>
<para>
Once the WAL segment files active during the backup are archived, you are
- done. The file identified by <function>pg_stop_backup</function>'s first return
+ done. The file identified by <function>pg_backup_stop</function>'s first return
value is the last segment that is required to form a complete set of
backup files. On a primary, if <varname>archive_mode</varname> is enabled and the
<literal>wait_for_archive</literal> parameter is <literal>true</literal>,
- <function>pg_stop_backup</function> does not return until the last segment has
+ <function>pg_backup_stop</function> does not return until the last segment has
been archived.
On a standby, <varname>archive_mode</varname> must be <literal>always</literal> in order
- for <function>pg_stop_backup</function> to wait.
+ for <function>pg_backup_stop</function> to wait.
Archiving of these files happens automatically since you have
already configured <varname>archive_library</varname>. In most cases this
happens quickly, but you are advised to monitor your archive
@@ -965,9 +953,9 @@ SELECT * FROM pg_stop_backup(false, true);
because of failures of the archive library, it will keep retrying
until the archive succeeds and the backup is complete.
If you wish to place a time limit on the execution of
- <function>pg_stop_backup</function>, set an appropriate
+ <function>pg_backup_stop</function>, set an appropriate
<varname>statement_timeout</varname> value, but make note that if
- <function>pg_stop_backup</function> terminates because of this your backup
+ <function>pg_backup_stop</function> terminates because of this your backup
may not be valid.
</para>
<para>
@@ -975,8 +963,8 @@ SELECT * FROM pg_stop_backup(false, true);
required for the backup are successfully archived then the
<literal>wait_for_archive</literal> parameter (which defaults to true) can be set
to false to have
- <function>pg_stop_backup</function> return as soon as the stop backup record is
- written to the WAL. By default, <function>pg_stop_backup</function> will wait
+ <function>pg_backup_stop</function> return as soon as the stop backup record is
+ written to the WAL. By default, <function>pg_backup_stop</function> will wait
until all WAL has been archived, which can take some time. This option
must be used with caution: if WAL archiving is not monitored correctly
then the backup might not include all of the WAL files and will
@@ -985,142 +973,6 @@ SELECT * FROM pg_stop_backup(false, true);
</listitem>
</orderedlist>
</para>
- </sect3>
- <sect3 id="backup-lowlevel-base-backup-exclusive">
- <title>Making an Exclusive Low-Level Backup</title>
-
- <note>
- <para>
- The exclusive backup method is deprecated and should be avoided.
- Prior to <productname>PostgreSQL</productname> 9.6, this was the only
- low-level method available, but it is now recommended that all users
- upgrade their scripts to use non-exclusive backups.
- </para>
- </note>
-
- <para>
- The process for an exclusive backup is mostly the same as for a
- non-exclusive one, but it differs in a few key steps. This type of
- backup can only be taken on a primary and does not allow concurrent
- backups. Moreover, because it creates a backup label file, as
- described below, it can block automatic restart of the primary server
- after a crash. On the other hand, the erroneous removal of this
- file from a backup or standby is a common mistake, which can result
- in serious data corruption. If it is necessary to use this method,
- the following steps may be used.
- </para>
- <para>
- <orderedlist>
- <listitem>
- <para>
- Ensure that WAL archiving is enabled and working.
- </para>
- </listitem>
- <listitem>
- <para>
- Connect to the server (it does not matter which database) as a user with
- rights to run pg_start_backup (superuser, or a user who has been granted
- EXECUTE on the function) and issue the command:
-<programlisting>
-SELECT pg_start_backup('label');
-</programlisting>
- where <literal>label</literal> is any string you want to use to uniquely
- identify this backup operation.
- <function>pg_start_backup</function> creates a <firstterm>backup label</firstterm> file,
- called <filename>backup_label</filename>, in the cluster directory with
- information about your backup, including the start time and label string.
- The function also creates a <firstterm>tablespace map</firstterm> file,
- called <filename>tablespace_map</filename>, in the cluster directory with
- information about tablespace symbolic links in <filename>pg_tblspc/</filename> if
- one or more such link is present. Both files are critical to the
- integrity of the backup, should you need to restore from it.
- </para>
-
- <para>
- By default, <function>pg_start_backup</function> can take a long time to finish.
- This is because it performs a checkpoint, and the I/O
- required for the checkpoint will be spread out over a significant
- period of time, by default half your inter-checkpoint interval
- (see the configuration parameter
- <xref linkend="guc-checkpoint-completion-target"/>). This is
- usually what you want, because it minimizes the impact on query
- processing. If you want to start the backup as soon as
- possible, use:
-<programlisting>
-SELECT pg_start_backup('label', true);
-</programlisting>
- This forces the checkpoint to be done as quickly as possible.
- </para>
- </listitem>
- <listitem>
- <para>
- Perform the backup, using any convenient file-system-backup tool
- such as <application>tar</application> or <application>cpio</application> (not
- <application>pg_dump</application> or
- <application>pg_dumpall</application>). It is neither
- necessary nor desirable to stop normal operation of the database
- while you do this. See
- <xref linkend="backup-lowlevel-base-backup-data"/> for things to
- consider during this backup.
- </para>
- <para>
- As noted above, if the server crashes during the backup it may not be
- possible to restart until the <filename>backup_label</filename> file has
- been manually deleted from the <envar>PGDATA</envar> directory. Note
- that it is very important to never remove the
- <filename>backup_label</filename> file when restoring a backup, because
- this will result in corruption. Confusion about when it is appropriate
- to remove this file is a common cause of data corruption when using this
- method; be very certain that you remove the file only on an existing
- primary and never when building a standby or restoring a backup, even if
- you are building a standby that will subsequently be promoted to a new
- primary.
- </para>
- </listitem>
- <listitem>
- <para>
- Again connect to the database as a user with rights to run
- pg_stop_backup (superuser, or a user who has been granted EXECUTE on
- the function), and issue the command:
-<programlisting>
-SELECT pg_stop_backup();
-</programlisting>
- This function terminates backup mode and
- performs an automatic switch to the next WAL segment. The reason for the
- switch is to arrange for the last WAL segment written during the backup
- interval to be ready to archive.
- </para>
- </listitem>
- <listitem>
- <para>
- Once the WAL segment files active during the backup are archived, you are
- done. The file identified by <function>pg_stop_backup</function>'s result is
- the last segment that is required to form a complete set of backup files.
- If <varname>archive_mode</varname> is enabled,
- <function>pg_stop_backup</function> does not return until the last segment has
- been archived.
- Archiving of these files happens automatically since you have
- already configured <varname>archive_command</varname>. In most cases this
- happens quickly, but you are advised to monitor your archive
- system to ensure there are no delays.
- If the archive process has fallen behind
- because of failures of the archive command, it will keep retrying
- until the archive succeeds and the backup is complete.
- </para>
-
- <para>
- When using exclusive backup mode, it is absolutely imperative to ensure
- that <function>pg_stop_backup</function> completes successfully at the
- end of the backup. Even if the backup itself fails, for example due to
- lack of disk space, failure to call <function>pg_stop_backup</function>
- will leave the server in backup mode indefinitely, causing future backups
- to fail and increasing the risk of a restart failure during the time that
- <filename>backup_label</filename> exists.
- </para>
- </listitem>
- </orderedlist>
- </para>
- </sect3>
<sect3 id="backup-lowlevel-base-backup-data">
<title>Backing Up the Data Directory</title>
<para>
@@ -1203,8 +1055,8 @@ SELECT pg_stop_backup();
<para>
The backup label
- file includes the label string you gave to <function>pg_start_backup</function>,
- as well as the time at which <function>pg_start_backup</function> was run, and
+ file includes the label string you gave to <function>pg_backup_start</function>,
+ as well as the time at which <function>pg_backup_start</function> was run, and
the name of the starting WAL file. In case of confusion it is therefore
possible to look inside a backup file and determine exactly which
backup session the dump file came from. The tablespace map file includes
@@ -1218,7 +1070,7 @@ SELECT pg_stop_backup();
<para>
It is also possible to make a backup while the server is
stopped. In this case, you obviously cannot use
- <function>pg_start_backup</function> or <function>pg_stop_backup</function>, and
+ <function>pg_backup_start</function> or <function>pg_backup_stop</function>, and
you will therefore be left to your own devices to keep track of which
backup is which and how far back the associated WAL files go.
It is generally better to follow the continuous archiving procedure above.
@@ -1393,7 +1245,7 @@ restore_command = 'cp /mnt/server/archivedir/%f %p'
<note>
<para>
The stop point must be after the ending time of the base backup, i.e.,
- the end time of <function>pg_stop_backup</function>. You cannot use a base backup
+ the end time of <function>pg_backup_stop</function>. You cannot use a base backup
to recover to a time when that backup was in progress. (To
recover to such a time, you must go back to your previous base backup
and roll forward from there.)
@@ -1513,44 +1365,6 @@ restore_command = 'cp /mnt/server/archivedir/%f %p'
included in the backup automatically, and no special action is
required to restore the backup.
</para>
-
- <para>
- If more flexibility in copying the backup files is needed, a lower
- level process can be used for standalone hot backups as well.
- To prepare for low level standalone hot backups, make sure
- <varname>wal_level</varname> is set to
- <literal>replica</literal> or higher, <varname>archive_mode</varname> to
- <literal>on</literal>, and set up an <varname>archive_library</varname> that performs
- archiving only when a <emphasis>switch file</emphasis> exists. For example:
-<programlisting>
-archive_library = '' # use shell command
-archive_command = 'test ! -f /var/lib/pgsql/backup_in_progress || (test ! -f /var/lib/pgsql/archive/%f && cp %p /var/lib/pgsql/archive/%f)'
-</programlisting>
- This command will perform archiving when
- <filename>/var/lib/pgsql/backup_in_progress</filename> exists, and otherwise
- silently return zero exit status (allowing <productname>PostgreSQL</productname>
- to recycle the unwanted WAL file).
- </para>
-
- <para>
- With this preparation, a backup can be taken using a script like the
- following:
-<programlisting>
-touch /var/lib/pgsql/backup_in_progress
-psql -c "select pg_start_backup('hot_backup');"
-tar -cf /var/lib/pgsql/backup.tar /var/lib/pgsql/data/
-psql -c "select pg_stop_backup();"
-rm /var/lib/pgsql/backup_in_progress
-tar -rf /var/lib/pgsql/backup.tar /var/lib/pgsql/archive/
-</programlisting>
- The switch file <filename>/var/lib/pgsql/backup_in_progress</filename> is
- created first, enabling archiving of completed WAL files to occur.
- After the backup the switch file is removed. Archived WAL files are
- then added to the backup so that both base backup and all required
- WAL files are part of the same <application>tar</application> file.
- Please remember to add error handling to your backup scripts.
- </para>
-
</sect3>
<sect3 id="compressed-archive-logs">
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 4001cb2bda..ac4575217b 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -25598,9 +25598,8 @@ LOG: Grand total: 1651920 bytes in 201 blocks; 622360 free (88 chunks); 1029560
The functions shown in <xref
linkend="functions-admin-backup-table"/> assist in making on-line backups.
These functions cannot be executed during recovery (except
- non-exclusive <function>pg_start_backup</function>,
- non-exclusive <function>pg_stop_backup</function>,
- <function>pg_is_in_backup</function>, <function>pg_backup_start_time</function>
+ <function>pg_backup_start</function>,
+ <function>pg_backup_stop</function>,
and <function>pg_wal_lsn_diff</function>).
</para>
@@ -25689,13 +25688,12 @@ LOG: Grand total: 1651920 bytes in 201 blocks; 622360 free (88 chunks); 1029560
<row>
<entry role="func_table_entry"><para role="func_signature">
<indexterm>
- <primary>pg_start_backup</primary>
+ <primary>pg_backup_start</primary>
</indexterm>
- <function>pg_start_backup</function> (
+ <function>pg_backup_start</function> (
<parameter>label</parameter> <type>text</type>
<optional>, <parameter>fast</parameter> <type>boolean</type>
- <optional>, <parameter>exclusive</parameter> <type>boolean</type>
- </optional></optional> )
+ </optional> )
<returnvalue>pg_lsn</returnvalue>
</para>
<para>
@@ -25704,23 +25702,9 @@ LOG: Grand total: 1651920 bytes in 201 blocks; 622360 free (88 chunks); 1029560
(Typically this would be the name under which the backup dump file
will be stored.)
If the optional second parameter is given as <literal>true</literal>,
- it specifies executing <function>pg_start_backup</function> as quickly
+ it specifies executing <function>pg_backup_start</function> as quickly
as possible. This forces an immediate checkpoint which will cause a
spike in I/O operations, slowing any concurrently executing queries.
- The optional third parameter specifies whether to perform an exclusive
- or non-exclusive backup (default is exclusive).
- </para>
- <para>
- When used in exclusive mode, this function writes a backup label file
- (<filename>backup_label</filename>) and, if there are any links in
- the <filename>pg_tblspc/</filename> directory, a tablespace map file
- (<filename>tablespace_map</filename>) into the database cluster's data
- directory, then performs a checkpoint, and then returns the backup's
- starting write-ahead log location. (The user can ignore this
- result value, but it is provided in case it is useful.) When used in
- non-exclusive mode, the contents of these files are instead returned
- by the <function>pg_stop_backup</function> function, and should be
- copied to the backup area by the user.
</para>
<para>
This function is restricted to superusers by default, but other users
@@ -25731,11 +25715,10 @@ LOG: Grand total: 1651920 bytes in 201 blocks; 622360 free (88 chunks); 1029560
<row>
<entry role="func_table_entry"><para role="func_signature">
<indexterm>
- <primary>pg_stop_backup</primary>
+ <primary>pg_backup_stop</primary>
</indexterm>
- <function>pg_stop_backup</function> (
- <parameter>exclusive</parameter> <type>boolean</type>
- <optional>, <parameter>wait_for_archive</parameter> <type>boolean</type>
+ <function>pg_backup_stop</function> (
+ <optional><parameter>wait_for_archive</parameter> <type>boolean</type>
</optional> )
<returnvalue>record</returnvalue>
( <parameter>lsn</parameter> <type>pg_lsn</type>,
@@ -25743,24 +25726,21 @@ LOG: Grand total: 1651920 bytes in 201 blocks; 622360 free (88 chunks); 1029560
<parameter>spcmapfile</parameter> <type>text</type> )
</para>
<para>
- Finishes performing an exclusive or non-exclusive on-line backup.
- The <parameter>exclusive</parameter> parameter must match the
- previous <function>pg_start_backup</function> call.
- In an exclusive backup, <function>pg_stop_backup</function> removes
- the backup label file and, if it exists, the tablespace map file
- created by <function>pg_start_backup</function>. In a non-exclusive
- backup, the desired contents of these files are returned as part of
- the result of the function, and should be written to files in the
- backup area (not in the data directory).
+ Finishes performing an on-line backup. The desired contents of the
+ backup label file and the tablespace map file are returned as part of
+ the result of the function and must be written to files in the
+ backup area. These files must not be written to the live data directory
+ (doing so will cause PostgreSQL to fail to restart in the event of a
+ crash).
</para>
<para>
- There is an optional second parameter of type <type>boolean</type>.
+ There is an optional parameter of type <type>boolean</type>.
If false, the function will return immediately after the backup is
completed, without waiting for WAL to be archived. This behavior is
only useful with backup software that independently monitors WAL
archiving. Otherwise, WAL required to make the backup consistent might
be missing and make the backup useless. By default or when this
- parameter is true, <function>pg_stop_backup</function> will wait for
+ parameter is true, <function>pg_backup_stop</function> will wait for
WAL to be archived when archiving is enabled. (On a standby, this
means that it will wait only when <varname>archive_mode</varname> =
<literal>always</literal>. If write activity on the primary is low,
@@ -25770,7 +25750,7 @@ LOG: Grand total: 1651920 bytes in 201 blocks; 622360 free (88 chunks); 1029560
<para>
When executed on a primary, this function also creates a backup
history file in the write-ahead log archive area. The history file
- includes the label given to <function>pg_start_backup</function>, the
+ includes the label given to <function>pg_backup_start</function>, the
starting and ending write-ahead log locations for the backup, and the
starting and ending times of the backup. After recording the ending
location, the current write-ahead log insertion point is automatically
@@ -25781,27 +25761,11 @@ LOG: Grand total: 1651920 bytes in 201 blocks; 622360 free (88 chunks); 1029560
<para>
The result of the function is a single record.
The <parameter>lsn</parameter> column holds the backup's ending
- write-ahead log location (which again can be ignored). The second and
- third columns are <literal>NULL</literal> when ending an exclusive
- backup; after a non-exclusive backup they hold the desired contents of
- the label and tablespace map files.
- </para>
- <para>
- This function is restricted to superusers by default, but other users
- can be granted EXECUTE to run the function.
- </para></entry>
- </row>
-
- <row>
- <entry role="func_table_entry"><para role="func_signature">
- <function>pg_stop_backup</function> ()
- <returnvalue>pg_lsn</returnvalue>
- </para>
- <para>
- Finishes performing an exclusive on-line backup. This simplified
- version is equivalent to <literal>pg_stop_backup(true,
- true)</literal>, except that it only returns the <type>pg_lsn</type>
- result.
+ write-ahead log location (which again can be ignored). The second
+ column returns the contents of the backup label file, and the third
+ column returns the contents of the tablespace map file. These must be
+ stored as part of the backup and are required as part of the restore
+ process.
</para>
<para>
This function is restricted to superusers by default, but other users
@@ -25809,33 +25773,6 @@ LOG: Grand total: 1651920 bytes in 201 blocks; 622360 free (88 chunks); 1029560
</para></entry>
</row>
- <row>
- <entry role="func_table_entry"><para role="func_signature">
- <indexterm>
- <primary>pg_is_in_backup</primary>
- </indexterm>
- <function>pg_is_in_backup</function> ()
- <returnvalue>boolean</returnvalue>
- </para>
- <para>
- Returns true if an on-line exclusive backup is in progress.
- </para></entry>
- </row>
-
- <row>
- <entry role="func_table_entry"><para role="func_signature">
- <indexterm>
- <primary>pg_backup_start_time</primary>
- </indexterm>
- <function>pg_backup_start_time</function> ()
- <returnvalue>timestamp with time zone</returnvalue>
- </para>
- <para>
- Returns the start time of the current on-line exclusive backup if one
- is in progress, otherwise <literal>NULL</literal>.
- </para></entry>
- </row>
-
<row>
<entry role="func_table_entry"><para role="func_signature">
<indexterm>
@@ -25933,7 +25870,7 @@ LOG: Grand total: 1651920 bytes in 201 blocks; 622360 free (88 chunks); 1029560
corresponding write-ahead log file name and byte offset from
a <type>pg_lsn</type> value. For example:
<programlisting>
-postgres=# SELECT * FROM pg_walfile_name_offset(pg_stop_backup());
+postgres=# SELECT * FROM pg_walfile_name_offset((pg_backup_stop()).lsn);
file_name | file_offset
--------------------------+-------------
00000001000000000000000D | 4039624
diff --git a/doc/src/sgml/high-availability.sgml b/doc/src/sgml/high-availability.sgml
index 81fa26f985..3247e05666 100644
--- a/doc/src/sgml/high-availability.sgml
+++ b/doc/src/sgml/high-availability.sgml
@@ -1361,8 +1361,8 @@ synchronous_standby_names = 'ANY 2 (s1, s2, s3)'
<para>
If you need to re-create a standby server while transactions are
- waiting, make sure that the commands pg_start_backup() and
- pg_stop_backup() are run in a session with
+ waiting, make sure that the commands pg_backup_start() and
+ pg_backup_stop() are run in a session with
<varname>synchronous_commit</varname> = <literal>off</literal>, otherwise those
requests will wait forever for the standby to appear.
</para>
@@ -2159,7 +2159,7 @@ HINT: You can then restart the server after making the necessary configuration
<para>
WAL file control commands will not work during recovery,
- e.g., <function>pg_start_backup</function>, <function>pg_switch_wal</function> etc.
+ e.g., <function>pg_backup_start</function>, <function>pg_switch_wal</function> etc.
</para>
<para>
diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
index 3b9172f65b..487331c115 100644
--- a/doc/src/sgml/monitoring.sgml
+++ b/doc/src/sgml/monitoring.sgml
@@ -6674,7 +6674,7 @@ SELECT pg_stat_get_backend_pid(s.backendid) AS pid,
<entry><literal>waiting for checkpoint to finish</literal></entry>
<entry>
The WAL sender process is currently performing
- <function>pg_start_backup</function> to prepare to
+ <function>pg_backup_start</function> to prepare to
take a base backup, and waiting for the start-of-backup
checkpoint to finish.
</entry>
@@ -6697,7 +6697,7 @@ SELECT pg_stat_get_backend_pid(s.backendid) AS pid,
<entry><literal>waiting for wal archiving to finish</literal></entry>
<entry>
The WAL sender process is currently performing
- <function>pg_stop_backup</function> to finish the backup,
+ <function>pg_backup_stop</function> to finish the backup,
and waiting for all the WAL files required for the base backup
to be successfully archived.
If either <literal>--wal-method=none</literal> or
diff --git a/doc/src/sgml/ref/pgupgrade.sgml b/doc/src/sgml/ref/pgupgrade.sgml
index 729c886ac0..3fbe141456 100644
--- a/doc/src/sgml/ref/pgupgrade.sgml
+++ b/doc/src/sgml/ref/pgupgrade.sgml
@@ -618,7 +618,7 @@ rsync --archive --delete --hard-links --size-only --no-inc-recursive /vol1/pg_tb
<para>
Configure the servers for log shipping. (You do not need to run
- <function>pg_start_backup()</function> and <function>pg_stop_backup()</function>
+ <function>pg_backup_start()</function> and <function>pg_backup_stop()</function>
or take a file system backup as the standbys are still synchronized
with the primary.)
</para>
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 17a56152f1..b539d87111 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -385,29 +385,6 @@ typedef union WALInsertLockPadded
char pad[PG_CACHE_LINE_SIZE];
} WALInsertLockPadded;
-/*
- * State of an exclusive backup, necessary to control concurrent activities
- * across sessions when working on exclusive backups.
- *
- * EXCLUSIVE_BACKUP_NONE means that there is no exclusive backup actually
- * running, to be more precise pg_start_backup() is not being executed for
- * an exclusive backup and there is no exclusive backup in progress.
- * EXCLUSIVE_BACKUP_STARTING means that pg_start_backup() is starting an
- * exclusive backup.
- * EXCLUSIVE_BACKUP_IN_PROGRESS means that pg_start_backup() has finished
- * running and an exclusive backup is in progress. pg_stop_backup() is
- * needed to finish it.
- * EXCLUSIVE_BACKUP_STOPPING means that pg_stop_backup() is stopping an
- * exclusive backup.
- */
-typedef enum ExclusiveBackupState
-{
- EXCLUSIVE_BACKUP_NONE = 0,
- EXCLUSIVE_BACKUP_STARTING,
- EXCLUSIVE_BACKUP_IN_PROGRESS,
- EXCLUSIVE_BACKUP_STOPPING
-} ExclusiveBackupState;
-
/*
* Session status of running backup, used for sanity checks in SQL-callable
* functions to start and stop backups.
@@ -456,15 +433,12 @@ typedef struct XLogCtlInsert
bool fullPageWrites;
/*
- * exclusiveBackupState indicates the state of an exclusive backup (see
- * comments of ExclusiveBackupState for more details). nonExclusiveBackups
- * is a counter indicating the number of streaming base backups currently
- * in progress. forcePageWrites is set to true when either of these is
- * non-zero. lastBackupStart is the latest checkpoint redo location used
- * as a starting point for an online backup.
+ * runningBackups is a counter indicating the number of backups currently in
+ * progress. forcePageWrites is set to true when runningBackups is non-zero.
+ * lastBackupStart is the latest checkpoint redo location used as a starting
+ * point for an online backup.
*/
- ExclusiveBackupState exclusiveBackupState;
- int nonExclusiveBackups;
+ int runningBackups;
XLogRecPtr lastBackupStart;
/*
@@ -696,8 +670,7 @@ static void ReadControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow);
-static void pg_start_backup_callback(int code, Datum arg);
-static void pg_stop_backup_callback(int code, Datum arg);
+static void pg_backup_start_callback(int code, Datum arg);
static int get_sync_bit(int method);
@@ -5328,7 +5301,7 @@ StartupXLOG(void)
* Ran off end of WAL before reaching end-of-backup WAL record, or
* minRecoveryPoint. That's usually a bad sign, indicating that you
* tried to recover from an online backup but never called
- * pg_stop_backup(), or you didn't archive all the WAL up to that
+ * pg_backup_stop(), or you didn't archive all the WAL up to that
* point. However, this also happens in crash recovery, if the system
* crashes while an online backup is in progress. We must not treat
* that as an error, or the database will refuse to start up.
@@ -5342,7 +5315,7 @@ StartupXLOG(void)
else if (!XLogRecPtrIsInvalid(ControlFile->backupStartPoint))
ereport(FATAL,
(errmsg("WAL ends before end of online backup"),
- errhint("Online backup started with pg_start_backup() must be ended with pg_stop_backup(), and all WAL up to that point must be available at recovery.")));
+ errhint("Online backup started with pg_backup_start() must be ended with pg_backup_stop(), and all WAL up to that point must be available at recovery.")));
else
ereport(FATAL,
(errmsg("WAL ends before consistent recovery point")));
@@ -7036,7 +7009,7 @@ CreateRestartPoint(int flags)
* Ensure minRecoveryPoint is past the checkpoint record. Normally,
* this will have happened already while writing out dirty buffers,
* but not necessarily - e.g. because no buffers were dirtied. We do
- * this because a non-exclusive base backup uses minRecoveryPoint to
+ * this because a backup performed in recovery uses minRecoveryPoint to
* determine which WAL files must be included in the backup, and the
* file (or files) containing the checkpoint record must be included,
* at a minimum. Note that for an ordinary restart of recovery there's
@@ -7840,7 +7813,7 @@ xlog_redo(XLogReaderState *record)
/*
* Update the LSN of the last replayed XLOG_FPW_CHANGE record so that
- * do_pg_start_backup() and do_pg_stop_backup() can check whether
+ * do_pg_backup_start() and do_pg_backup_stop() can check whether
* full_page_writes has been disabled during online backup.
*/
if (!fpw)
@@ -8039,29 +8012,14 @@ issue_xlog_fsync(int fd, XLogSegNo segno, TimeLineID tli)
}
/*
- * do_pg_start_backup
- *
- * Utility function called at the start of an online backup. It creates the
- * necessary starting checkpoint and constructs the backup label file.
- *
- * There are two kind of backups: exclusive and non-exclusive. An exclusive
- * backup is started with pg_start_backup(), and there can be only one active
- * at a time. The backup and tablespace map files of an exclusive backup are
- * written to $PGDATA/backup_label and $PGDATA/tablespace_map, and they are
- * removed by pg_stop_backup().
- *
- * A non-exclusive backup is used for the streaming base backups (see
- * src/backend/replication/basebackup.c). The difference to exclusive backups
- * is that the backup label and tablespace map files are not written to disk.
- * Instead, their would-be contents are returned in *labelfile and *tblspcmapfile,
- * and the caller is responsible for including them in the backup archive as
- * 'backup_label' and 'tablespace_map'. There can be many non-exclusive backups
- * active at the same time, and they don't conflict with an exclusive backup
- * either.
- *
- * labelfile and tblspcmapfile must be passed as NULL when starting an
- * exclusive backup, and as initially-empty StringInfos for a non-exclusive
- * backup.
+ * do_pg_backup_start is the workhorse of the user-visible pg_backup_start()
+ * function. It creates the necessary starting checkpoint and constructs the
+ * backup label and tablespace map.
+ *
+ * The backup label and tablespace map contents are returned in *labelfile and
+ * *tblspcmapfile, and the caller is responsible for including them in the
+ * backup archive as 'backup_label' and 'tablespace_map'. There can be many
+ * backups active at the same time.
*
* If "tablespaces" isn't NULL, it receives a list of tablespaceinfo structs
* describing the cluster's tablespaces.
@@ -8073,18 +8031,17 @@ issue_xlog_fsync(int fd, XLogSegNo segno, TimeLineID tli)
* Returns the minimum WAL location that must be present to restore from this
* backup, and the corresponding timeline ID in *starttli_p.
*
- * Every successfully started non-exclusive backup must be stopped by calling
- * do_pg_stop_backup() or do_pg_abort_backup().
+ * Every successfully started backup must be stopped by calling
+ * do_pg_backup_stop() or do_pg_abort_backup().
*
* It is the responsibility of the caller of this function to verify the
* permissions of the calling user!
*/
XLogRecPtr
-do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
+do_pg_backup_start(const char *backupidstr, bool fast, TimeLineID *starttli_p,
StringInfo labelfile, List **tablespaces,
StringInfo tblspcmapfile)
{
- bool exclusive = (labelfile == NULL);
bool backup_started_in_recovery = false;
XLogRecPtr checkpointloc;
XLogRecPtr startpoint;
@@ -8093,20 +8050,9 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
char strfbuf[128];
char xlogfilename[MAXFNAMELEN];
XLogSegNo _logSegNo;
- struct stat stat_buf;
- FILE *fp;
backup_started_in_recovery = RecoveryInProgress();
- /*
- * Currently only non-exclusive backup can be taken during recovery.
- */
- if (backup_started_in_recovery && exclusive)
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("recovery is in progress"),
- errhint("WAL control functions cannot be executed during recovery.")));
-
/*
* During recovery, we don't need to check WAL level. Because, if WAL
* level is not sufficient, it's impossible to get here during recovery.
@@ -8145,30 +8091,12 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
* XLogInsertRecord().
*/
WALInsertLockAcquireExclusive();
- if (exclusive)
- {
- /*
- * At first, mark that we're now starting an exclusive backup, to
- * ensure that there are no other sessions currently running
- * pg_start_backup() or pg_stop_backup().
- */
- if (XLogCtl->Insert.exclusiveBackupState != EXCLUSIVE_BACKUP_NONE)
- {
- WALInsertLockRelease();
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("a backup is already in progress"),
- errhint("Run pg_stop_backup() and try again.")));
- }
- XLogCtl->Insert.exclusiveBackupState = EXCLUSIVE_BACKUP_STARTING;
- }
- else
- XLogCtl->Insert.nonExclusiveBackups++;
+ XLogCtl->Insert.runningBackups++;
XLogCtl->Insert.forcePageWrites = true;
WALInsertLockRelease();
/* Ensure we release forcePageWrites if fail below */
- PG_ENSURE_ERROR_CLEANUP(pg_start_backup_callback, (Datum) BoolGetDatum(exclusive));
+ PG_ENSURE_ERROR_CLEANUP(pg_backup_start_callback, (Datum) 0);
{
bool gotUniqueStartpoint = false;
DIR *tblspcdir;
@@ -8180,7 +8108,7 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
* Force an XLOG file switch before the checkpoint, to ensure that the
* WAL segment the checkpoint is written to doesn't contain pages with
* old timeline IDs. That would otherwise happen if you called
- * pg_start_backup() right after restoring from a PITR archive: the
+ * pg_backup_start() right after restoring from a PITR archive: the
* first WAL segment containing the startup checkpoint has pages in
* the beginning with the old timeline ID. That can cause trouble at
* recovery: we won't have a history file covering the old timeline if
@@ -8215,7 +8143,7 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
* means that two successive backup runs can have same checkpoint
* positions.
*
- * Since the fact that we are executing do_pg_start_backup()
+ * Since the fact that we are executing do_pg_backup_start()
* during recovery means that checkpointer is running, we can use
* RequestCheckpoint() to establish a restartpoint.
*
@@ -8416,122 +8344,19 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
LSN_FORMAT_ARGS(startpoint), xlogfilename);
appendStringInfo(labelfile, "CHECKPOINT LOCATION: %X/%X\n",
LSN_FORMAT_ARGS(checkpointloc));
- appendStringInfo(labelfile, "BACKUP METHOD: %s\n",
- exclusive ? "pg_start_backup" : "streamed");
+ appendStringInfo(labelfile, "BACKUP METHOD: streamed\n");
appendStringInfo(labelfile, "BACKUP FROM: %s\n",
backup_started_in_recovery ? "standby" : "primary");
appendStringInfo(labelfile, "START TIME: %s\n", strfbuf);
appendStringInfo(labelfile, "LABEL: %s\n", backupidstr);
appendStringInfo(labelfile, "START TIMELINE: %u\n", starttli);
-
- /*
- * Okay, write the file, or return its contents to caller.
- */
- if (exclusive)
- {
- /*
- * Check for existing backup label --- implies a backup is already
- * running. (XXX given that we checked exclusiveBackupState
- * above, maybe it would be OK to just unlink any such label
- * file?)
- */
- if (stat(BACKUP_LABEL_FILE, &stat_buf) != 0)
- {
- if (errno != ENOENT)
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not stat file \"%s\": %m",
- BACKUP_LABEL_FILE)));
- }
- else
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("a backup is already in progress"),
- errhint("If you're sure there is no backup in progress, remove file \"%s\" and try again.",
- BACKUP_LABEL_FILE)));
-
- fp = AllocateFile(BACKUP_LABEL_FILE, "w");
-
- if (!fp)
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not create file \"%s\": %m",
- BACKUP_LABEL_FILE)));
- if (fwrite(labelfile->data, labelfile->len, 1, fp) != 1 ||
- fflush(fp) != 0 ||
- pg_fsync(fileno(fp)) != 0 ||
- ferror(fp) ||
- FreeFile(fp))
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not write file \"%s\": %m",
- BACKUP_LABEL_FILE)));
- /* Allocated locally for exclusive backups, so free separately */
- pfree(labelfile->data);
- pfree(labelfile);
-
- /* Write backup tablespace_map file. */
- if (tblspcmapfile->len > 0)
- {
- if (stat(TABLESPACE_MAP, &stat_buf) != 0)
- {
- if (errno != ENOENT)
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not stat file \"%s\": %m",
- TABLESPACE_MAP)));
- }
- else
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("a backup is already in progress"),
- errhint("If you're sure there is no backup in progress, remove file \"%s\" and try again.",
- TABLESPACE_MAP)));
-
- fp = AllocateFile(TABLESPACE_MAP, "w");
-
- if (!fp)
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not create file \"%s\": %m",
- TABLESPACE_MAP)));
- if (fwrite(tblspcmapfile->data, tblspcmapfile->len, 1, fp) != 1 ||
- fflush(fp) != 0 ||
- pg_fsync(fileno(fp)) != 0 ||
- ferror(fp) ||
- FreeFile(fp))
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not write file \"%s\": %m",
- TABLESPACE_MAP)));
- }
-
- /* Allocated locally for exclusive backups, so free separately */
- pfree(tblspcmapfile->data);
- pfree(tblspcmapfile);
- }
}
- PG_END_ENSURE_ERROR_CLEANUP(pg_start_backup_callback, (Datum) BoolGetDatum(exclusive));
+ PG_END_ENSURE_ERROR_CLEANUP(pg_backup_start_callback, (Datum) 0);
/*
- * Mark that start phase has correctly finished for an exclusive backup.
- * Session-level locks are updated as well to reflect that state.
- *
- * Note that CHECK_FOR_INTERRUPTS() must not occur while updating backup
- * counters and session-level lock. Otherwise they can be updated
- * inconsistently, and which might cause do_pg_abort_backup() to fail.
+ * Mark that the start phase has correctly finished for the backup.
*/
- if (exclusive)
- {
- WALInsertLockAcquireExclusive();
- XLogCtl->Insert.exclusiveBackupState = EXCLUSIVE_BACKUP_IN_PROGRESS;
-
- /* Set session-level lock */
- sessionBackupState = SESSION_BACKUP_EXCLUSIVE;
- WALInsertLockRelease();
- }
- else
- sessionBackupState = SESSION_BACKUP_NON_EXCLUSIVE;
+ sessionBackupState = SESSION_BACKUP_RUNNING;
/*
* We're done. As a convenience, return the starting WAL location.
@@ -8541,47 +8366,19 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
return startpoint;
}
-/* Error cleanup callback for pg_start_backup */
+/* Error cleanup callback for pg_backup_start */
static void
-pg_start_backup_callback(int code, Datum arg)
+pg_backup_start_callback(int code, Datum arg)
{
- bool exclusive = DatumGetBool(arg);
-
/* Update backup counters and forcePageWrites on failure */
WALInsertLockAcquireExclusive();
- if (exclusive)
- {
- Assert(XLogCtl->Insert.exclusiveBackupState == EXCLUSIVE_BACKUP_STARTING);
- XLogCtl->Insert.exclusiveBackupState = EXCLUSIVE_BACKUP_NONE;
- }
- else
- {
- Assert(XLogCtl->Insert.nonExclusiveBackups > 0);
- XLogCtl->Insert.nonExclusiveBackups--;
- }
- if (XLogCtl->Insert.exclusiveBackupState == EXCLUSIVE_BACKUP_NONE &&
- XLogCtl->Insert.nonExclusiveBackups == 0)
- {
- XLogCtl->Insert.forcePageWrites = false;
- }
- WALInsertLockRelease();
-}
+ Assert(XLogCtl->Insert.runningBackups > 0);
+ XLogCtl->Insert.runningBackups--;
-/*
- * Error cleanup callback for pg_stop_backup
- */
-static void
-pg_stop_backup_callback(int code, Datum arg)
-{
- bool exclusive = DatumGetBool(arg);
-
- /* Update backup status on failure */
- WALInsertLockAcquireExclusive();
- if (exclusive)
+ if (XLogCtl->Insert.runningBackups == 0)
{
- Assert(XLogCtl->Insert.exclusiveBackupState == EXCLUSIVE_BACKUP_STOPPING);
- XLogCtl->Insert.exclusiveBackupState = EXCLUSIVE_BACKUP_IN_PROGRESS;
+ XLogCtl->Insert.forcePageWrites = false;
}
WALInsertLockRelease();
}
@@ -8596,14 +8393,11 @@ get_backup_status(void)
}
/*
- * do_pg_stop_backup
+ * do_pg_backup_stop
*
* Utility function called at the end of an online backup. It cleans up the
* backup state and can optionally wait for WAL segments to be archived.
*
- * If labelfile is NULL, this stops an exclusive backup. Otherwise this stops
- * the non-exclusive backup specified by 'labelfile'.
- *
* Returns the last WAL location that must be present to restore from this
* backup, and the corresponding timeline ID in *stoptli_p.
*
@@ -8611,9 +8405,8 @@ get_backup_status(void)
* permissions of the calling user!
*/
XLogRecPtr
-do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
+do_pg_backup_stop(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
{
- bool exclusive = (labelfile == NULL);
bool backup_started_in_recovery = false;
XLogRecPtr startpoint;
XLogRecPtr stoppoint;
@@ -8627,7 +8420,6 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
char histfilename[MAXFNAMELEN];
char backupfrom[20];
XLogSegNo _logSegNo;
- FILE *lfp;
FILE *fp;
char ch;
int seconds_before_warning;
@@ -8640,15 +8432,6 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
backup_started_in_recovery = RecoveryInProgress();
- /*
- * Currently only non-exclusive backup can be taken during recovery.
- */
- if (backup_started_in_recovery && exclusive)
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("recovery is in progress"),
- errhint("WAL control functions cannot be executed during recovery.")));
-
/*
* During recovery, we don't need to check WAL level. Because, if WAL
* level is not sufficient, it's impossible to get here during recovery.
@@ -8659,106 +8442,23 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
errmsg("WAL level not sufficient for making an online backup"),
errhint("wal_level must be set to \"replica\" or \"logical\" at server start.")));
- if (exclusive)
- {
- /*
- * At first, mark that we're now stopping an exclusive backup, to
- * ensure that there are no other sessions currently running
- * pg_start_backup() or pg_stop_backup().
- */
- WALInsertLockAcquireExclusive();
- if (XLogCtl->Insert.exclusiveBackupState != EXCLUSIVE_BACKUP_IN_PROGRESS)
- {
- WALInsertLockRelease();
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("exclusive backup not in progress")));
- }
- XLogCtl->Insert.exclusiveBackupState = EXCLUSIVE_BACKUP_STOPPING;
- WALInsertLockRelease();
-
- /*
- * Remove backup_label. In case of failure, the state for an exclusive
- * backup is switched back to in-progress.
- */
- PG_ENSURE_ERROR_CLEANUP(pg_stop_backup_callback, (Datum) BoolGetDatum(exclusive));
- {
- /*
- * Read the existing label file into memory.
- */
- struct stat statbuf;
- int r;
-
- if (stat(BACKUP_LABEL_FILE, &statbuf))
- {
- /* should not happen per the upper checks */
- if (errno != ENOENT)
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not stat file \"%s\": %m",
- BACKUP_LABEL_FILE)));
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("a backup is not in progress")));
- }
-
- lfp = AllocateFile(BACKUP_LABEL_FILE, "r");
- if (!lfp)
- {
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not read file \"%s\": %m",
- BACKUP_LABEL_FILE)));
- }
- labelfile = palloc(statbuf.st_size + 1);
- r = fread(labelfile, statbuf.st_size, 1, lfp);
- labelfile[statbuf.st_size] = '\0';
-
- /*
- * Close and remove the backup label file
- */
- if (r != 1 || ferror(lfp) || FreeFile(lfp))
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not read file \"%s\": %m",
- BACKUP_LABEL_FILE)));
- durable_unlink(BACKUP_LABEL_FILE, ERROR);
-
- /*
- * Remove tablespace_map file if present, it is created only if
- * there are tablespaces.
- */
- durable_unlink(TABLESPACE_MAP, DEBUG1);
- }
- PG_END_ENSURE_ERROR_CLEANUP(pg_stop_backup_callback, (Datum) BoolGetDatum(exclusive));
- }
-
/*
- * OK to update backup counters, forcePageWrites and session-level lock.
+ * OK to update backup counters, forcePageWrites, and session-level lock.
*
* Note that CHECK_FOR_INTERRUPTS() must not occur while updating them.
* Otherwise they can be updated inconsistently, and which might cause
* do_pg_abort_backup() to fail.
*/
WALInsertLockAcquireExclusive();
- if (exclusive)
- {
- XLogCtl->Insert.exclusiveBackupState = EXCLUSIVE_BACKUP_NONE;
- }
- else
- {
- /*
- * The user-visible pg_start/stop_backup() functions that operate on
- * exclusive backups can be called at any time, but for non-exclusive
- * backups, it is expected that each do_pg_start_backup() call is
- * matched by exactly one do_pg_stop_backup() call.
- */
- Assert(XLogCtl->Insert.nonExclusiveBackups > 0);
- XLogCtl->Insert.nonExclusiveBackups--;
- }
- if (XLogCtl->Insert.exclusiveBackupState == EXCLUSIVE_BACKUP_NONE &&
- XLogCtl->Insert.nonExclusiveBackups == 0)
+ /*
+ * It is expected that each do_pg_backup_start() call is matched by exactly
+ * one do_pg_backup_stop() call.
+ */
+ Assert(XLogCtl->Insert.runningBackups > 0);
+ XLogCtl->Insert.runningBackups--;
+
+ if (XLogCtl->Insert.runningBackups == 0)
{
XLogCtl->Insert.forcePageWrites = false;
}
@@ -9016,17 +8716,13 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
/*
* do_pg_abort_backup: abort a running backup
*
- * This does just the most basic steps of do_pg_stop_backup(), by taking the
+ * This does just the most basic steps of do_pg_backup_stop(), by taking the
* system out of backup mode, thus making it a lot more safe to call from
* an error handler.
*
* The caller can pass 'arg' as 'true' or 'false' to control whether a warning
* is emitted.
*
- * NB: This is only for aborting a non-exclusive backup that doesn't write
- * backup_label. A backup started with pg_start_backup() needs to be finished
- * with pg_stop_backup().
- *
* NB: This gets used as a before_shmem_exit handler, hence the odd-looking
* signature.
*/
@@ -9036,18 +8732,16 @@ do_pg_abort_backup(int code, Datum arg)
bool emit_warning = DatumGetBool(arg);
/*
- * Quick exit if session is not keeping around a non-exclusive backup
- * already started.
+ * Quick exit if session does not have a running backup.
*/
- if (sessionBackupState != SESSION_BACKUP_NON_EXCLUSIVE)
+ if (sessionBackupState != SESSION_BACKUP_RUNNING)
return;
WALInsertLockAcquireExclusive();
- Assert(XLogCtl->Insert.nonExclusiveBackups > 0);
- XLogCtl->Insert.nonExclusiveBackups--;
+ Assert(XLogCtl->Insert.runningBackups > 0);
+ XLogCtl->Insert.runningBackups--;
- if (XLogCtl->Insert.exclusiveBackupState == EXCLUSIVE_BACKUP_NONE &&
- XLogCtl->Insert.nonExclusiveBackups == 0)
+ if (XLogCtl->Insert.runningBackups == 0)
{
XLogCtl->Insert.forcePageWrites = false;
}
@@ -9055,7 +8749,7 @@ do_pg_abort_backup(int code, Datum arg)
if (emit_warning)
ereport(WARNING,
- (errmsg("aborting backup due to backend exiting before pg_stop_backup was called")));
+ (errmsg("aborting backup due to backend exiting before pg_backup_stop was called")));
}
/*
@@ -9115,87 +8809,6 @@ GetOldestRestartPoint(XLogRecPtr *oldrecptr, TimeLineID *oldtli)
LWLockRelease(ControlFileLock);
}
-/*
- * BackupInProgress: check if online backup mode is active
- *
- * This is done by checking for existence of the "backup_label" file.
- */
-bool
-BackupInProgress(void)
-{
- struct stat stat_buf;
-
- return (stat(BACKUP_LABEL_FILE, &stat_buf) == 0);
-}
-
-/*
- * CancelBackup: rename the "backup_label" and "tablespace_map"
- * files to cancel backup mode
- *
- * If the "backup_label" file exists, it will be renamed to "backup_label.old".
- * Similarly, if the "tablespace_map" file exists, it will be renamed to
- * "tablespace_map.old".
- *
- * Note that this will render an online backup in progress
- * useless. To correctly finish an online backup, pg_stop_backup must be
- * called.
- */
-void
-CancelBackup(void)
-{
- struct stat stat_buf;
-
- /* if the backup_label file is not there, return */
- if (stat(BACKUP_LABEL_FILE, &stat_buf) < 0)
- return;
-
- /* remove leftover file from previously canceled backup if it exists */
- unlink(BACKUP_LABEL_OLD);
-
- if (durable_rename(BACKUP_LABEL_FILE, BACKUP_LABEL_OLD, DEBUG1) != 0)
- {
- ereport(WARNING,
- (errcode_for_file_access(),
- errmsg("online backup mode was not canceled"),
- errdetail("File \"%s\" could not be renamed to \"%s\": %m.",
- BACKUP_LABEL_FILE, BACKUP_LABEL_OLD)));
- return;
- }
-
- /* if the tablespace_map file is not there, return */
- if (stat(TABLESPACE_MAP, &stat_buf) < 0)
- {
- ereport(LOG,
- (errmsg("online backup mode canceled"),
- errdetail("File \"%s\" was renamed to \"%s\".",
- BACKUP_LABEL_FILE, BACKUP_LABEL_OLD)));
- return;
- }
-
- /* remove leftover file from previously canceled backup if it exists */
- unlink(TABLESPACE_MAP_OLD);
-
- if (durable_rename(TABLESPACE_MAP, TABLESPACE_MAP_OLD, DEBUG1) == 0)
- {
- ereport(LOG,
- (errmsg("online backup mode canceled"),
- errdetail("Files \"%s\" and \"%s\" were renamed to "
- "\"%s\" and \"%s\", respectively.",
- BACKUP_LABEL_FILE, TABLESPACE_MAP,
- BACKUP_LABEL_OLD, TABLESPACE_MAP_OLD)));
- }
- else
- {
- ereport(WARNING,
- (errcode_for_file_access(),
- errmsg("online backup mode canceled"),
- errdetail("File \"%s\" was renamed to \"%s\", but "
- "file \"%s\" could not be renamed to \"%s\": %m.",
- BACKUP_LABEL_FILE, BACKUP_LABEL_OLD,
- TABLESPACE_MAP, TABLESPACE_MAP_OLD)));
- }
-}
-
/* Thin wrapper around ShutdownWalRcv(). */
void
XLogShutdownWalRcv(void)
diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c
index 2752be63c1..b61ae6c0b4 100644
--- a/src/backend/access/transam/xlogfuncs.c
+++ b/src/backend/access/transam/xlogfuncs.c
@@ -39,13 +39,13 @@
#include "utils/tuplestore.h"
/*
- * Store label file and tablespace map during non-exclusive backups.
+ * Store label file and tablespace map during backups.
*/
static StringInfo label_file;
static StringInfo tblspc_map_file;
/*
- * pg_start_backup: set up for taking an on-line backup dump
+ * pg_backup_start: set up for taking an on-line backup dump
*
* Essentially what this does is to create a backup label file in $PGDATA,
* where it will be archived as part of the backup dump. The label file
@@ -57,105 +57,44 @@ static StringInfo tblspc_map_file;
* GRANT system.
*/
Datum
-pg_start_backup(PG_FUNCTION_ARGS)
+pg_backup_start(PG_FUNCTION_ARGS)
{
text *backupid = PG_GETARG_TEXT_PP(0);
bool fast = PG_GETARG_BOOL(1);
- bool exclusive = PG_GETARG_BOOL(2);
char *backupidstr;
XLogRecPtr startpoint;
SessionBackupState status = get_backup_status();
+ MemoryContext oldcontext;
backupidstr = text_to_cstring(backupid);
- if (status == SESSION_BACKUP_NON_EXCLUSIVE)
+ if (status == SESSION_BACKUP_RUNNING)
ereport(ERROR,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("a backup is already in progress in this session")));
- if (exclusive)
- {
- startpoint = do_pg_start_backup(backupidstr, fast, NULL, NULL,
- NULL, NULL);
- }
- else
- {
- MemoryContext oldcontext;
-
- /*
- * Label file and tablespace map file need to be long-lived, since
- * they are read in pg_stop_backup.
- */
- oldcontext = MemoryContextSwitchTo(TopMemoryContext);
- label_file = makeStringInfo();
- tblspc_map_file = makeStringInfo();
- MemoryContextSwitchTo(oldcontext);
+ /*
+ * Label file and tablespace map file need to be long-lived, since
+ * they are read in pg_backup_stop.
+ */
+ oldcontext = MemoryContextSwitchTo(TopMemoryContext);
+ label_file = makeStringInfo();
+ tblspc_map_file = makeStringInfo();
+ MemoryContextSwitchTo(oldcontext);
- register_persistent_abort_backup_handler();
+ register_persistent_abort_backup_handler();
- startpoint = do_pg_start_backup(backupidstr, fast, NULL, label_file,
- NULL, tblspc_map_file);
- }
+ startpoint = do_pg_backup_start(backupidstr, fast, NULL, label_file,
+ NULL, tblspc_map_file);
PG_RETURN_LSN(startpoint);
}
-/*
- * pg_stop_backup: finish taking an on-line backup dump
- *
- * We write an end-of-backup WAL record, and remove the backup label file
- * created by pg_start_backup, creating a backup history file in pg_wal
- * instead (whence it will immediately be archived). The backup history file
- * contains the same info found in the label file, plus the backup-end time
- * and WAL location. Before 9.0, the backup-end time was read from the backup
- * history file at the beginning of archive recovery, but we now use the WAL
- * record for that and the file is for informational and debug purposes only.
- *
- * Note: different from CancelBackup which just cancels online backup mode.
- *
- * Note: this version is only called to stop an exclusive backup. The function
- * pg_stop_backup_v2 (overloaded as pg_stop_backup in SQL) is called to
- * stop non-exclusive backups.
- *
- * Permission checking for this function is managed through the normal
- * GRANT system.
- */
-Datum
-pg_stop_backup(PG_FUNCTION_ARGS)
-{
- XLogRecPtr stoppoint;
- SessionBackupState status = get_backup_status();
-
- if (status == SESSION_BACKUP_NON_EXCLUSIVE)
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("non-exclusive backup in progress"),
- errhint("Did you mean to use pg_stop_backup('f')?")));
-
- /*
- * Exclusive backups were typically started in a different connection, so
- * don't try to verify that status of backup is set to
- * SESSION_BACKUP_EXCLUSIVE in this function. Actual verification that an
- * exclusive backup is in fact running is handled inside
- * do_pg_stop_backup.
- */
- stoppoint = do_pg_stop_backup(NULL, true, NULL);
-
- PG_RETURN_LSN(stoppoint);
-}
-
/*
- * pg_stop_backup_v2: finish taking exclusive or nonexclusive on-line backup.
- *
- * Works the same as pg_stop_backup, except for non-exclusive backups it returns
- * the backup label and tablespace map files as text fields in as part of the
- * resultset.
+ * pg_backup_stop: finish taking an on-line backup.
*
- * The first parameter (variable 'exclusive') allows the user to tell us if
- * this is an exclusive or a non-exclusive backup.
- *
- * The second parameter (variable 'waitforarchive'), which is optional,
+ * The first parameter (variable 'waitforarchive'), which is optional,
* allows the user to choose if they want to wait for the WAL to be archived
* or if we should just return as soon as the WAL record is written.
*
@@ -163,15 +102,14 @@ pg_stop_backup(PG_FUNCTION_ARGS)
* GRANT system.
*/
Datum
-pg_stop_backup_v2(PG_FUNCTION_ARGS)
+pg_backup_stop(PG_FUNCTION_ARGS)
{
#define PG_STOP_BACKUP_V2_COLS 3
TupleDesc tupdesc;
Datum values[PG_STOP_BACKUP_V2_COLS];
bool nulls[PG_STOP_BACKUP_V2_COLS];
- bool exclusive = PG_GETARG_BOOL(0);
- bool waitforarchive = PG_GETARG_BOOL(1);
+ bool waitforarchive = PG_GETARG_BOOL(0);
XLogRecPtr stoppoint;
SessionBackupState status = get_backup_status();
@@ -182,51 +120,29 @@ pg_stop_backup_v2(PG_FUNCTION_ARGS)
MemSet(values, 0, sizeof(values));
MemSet(nulls, 0, sizeof(nulls));
- if (exclusive)
- {
- if (status == SESSION_BACKUP_NON_EXCLUSIVE)
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("non-exclusive backup in progress"),
- errhint("Did you mean to use pg_stop_backup('f')?")));
-
- /*
- * Stop the exclusive backup, and since we're in an exclusive backup
- * return NULL for both backup_label and tablespace_map.
- */
- stoppoint = do_pg_stop_backup(NULL, waitforarchive, NULL);
-
- nulls[1] = true;
- nulls[2] = true;
- }
- else
- {
- if (status != SESSION_BACKUP_NON_EXCLUSIVE)
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("non-exclusive backup is not in progress"),
- errhint("Did you mean to use pg_stop_backup('t')?")));
+ if (status != SESSION_BACKUP_RUNNING)
+ ereport(ERROR,
+ (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ errmsg("backup is not in progress"),
+ errhint("Did you call pg_backup_start()?")));
- /*
- * Stop the non-exclusive backup. Return a copy of the backup label
- * and tablespace map so they can be written to disk by the caller.
- */
- stoppoint = do_pg_stop_backup(label_file->data, waitforarchive, NULL);
-
- values[1] = CStringGetTextDatum(label_file->data);
- values[2] = CStringGetTextDatum(tblspc_map_file->data);
-
- /* Free structures allocated in TopMemoryContext */
- pfree(label_file->data);
- pfree(label_file);
- label_file = NULL;
- pfree(tblspc_map_file->data);
- pfree(tblspc_map_file);
- tblspc_map_file = NULL;
- }
+ /*
+ * Stop the backup. Return a copy of the backup label and tablespace map so
+ * they can be written to disk by the caller.
+ */
+ stoppoint = do_pg_backup_stop(label_file->data, waitforarchive, NULL);
- /* Stoppoint is included on both exclusive and nonexclusive backups */
values[0] = LSNGetDatum(stoppoint);
+ values[1] = CStringGetTextDatum(label_file->data);
+ values[2] = CStringGetTextDatum(tblspc_map_file->data);
+
+ /* Free structures allocated in TopMemoryContext */
+ pfree(label_file->data);
+ pfree(label_file);
+ label_file = NULL;
+ pfree(tblspc_map_file->data);
+ pfree(tblspc_map_file);
+ tblspc_map_file = NULL;
/* Returns the record as Datum */
PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
@@ -298,7 +214,7 @@ pg_create_restore_point(PG_FUNCTION_ARGS)
}
/*
- * Report the current WAL write location (same format as pg_start_backup etc)
+ * Report the current WAL write location (same format as pg_backup_start etc)
*
* This is useful for determining how much of WAL is visible to an external
* archiving process. Note that the data before this point is written out
@@ -321,7 +237,7 @@ pg_current_wal_lsn(PG_FUNCTION_ARGS)
}
/*
- * Report the current WAL insert location (same format as pg_start_backup etc)
+ * Report the current WAL insert location (same format as pg_backup_start etc)
*
* This function is mostly for debugging purposes.
*/
@@ -342,7 +258,7 @@ pg_current_wal_insert_lsn(PG_FUNCTION_ARGS)
}
/*
- * Report the current WAL flush location (same format as pg_start_backup etc)
+ * Report the current WAL flush location (same format as pg_backup_start etc)
*
* This function is mostly for debugging purposes.
*/
@@ -363,7 +279,7 @@ pg_current_wal_flush_lsn(PG_FUNCTION_ARGS)
}
/*
- * Report the last WAL receive location (same format as pg_start_backup etc)
+ * Report the last WAL receive location (same format as pg_backup_start etc)
*
* This is useful for determining how much of WAL is guaranteed to be received
* and synced to disk by walreceiver.
@@ -382,7 +298,7 @@ pg_last_wal_receive_lsn(PG_FUNCTION_ARGS)
}
/*
- * Report the last WAL replay location (same format as pg_start_backup etc)
+ * Report the last WAL replay location (same format as pg_backup_start etc)
*
* This is useful for determining how much of WAL is visible to read-only
* connections during recovery.
@@ -402,7 +318,7 @@ pg_last_wal_replay_lsn(PG_FUNCTION_ARGS)
/*
* Compute an xlog file name and decimal byte offset given a WAL location,
- * such as is returned by pg_stop_backup() or pg_switch_wal().
+ * such as is returned by pg_backup_stop() or pg_switch_wal().
*
* Note that a location exactly at a segment boundary is taken to be in
* the previous segment. This is usually the right thing, since the
@@ -470,7 +386,7 @@ pg_walfile_name_offset(PG_FUNCTION_ARGS)
/*
* Compute an xlog file name given a WAL location,
- * such as is returned by pg_stop_backup() or pg_switch_wal().
+ * such as is returned by pg_backup_stop() or pg_switch_wal().
*/
Datum
pg_walfile_name(PG_FUNCTION_ARGS)
@@ -645,81 +561,6 @@ pg_wal_lsn_diff(PG_FUNCTION_ARGS)
PG_RETURN_NUMERIC(result);
}
-/*
- * Returns bool with current on-line backup mode, a global state.
- */
-Datum
-pg_is_in_backup(PG_FUNCTION_ARGS)
-{
- PG_RETURN_BOOL(BackupInProgress());
-}
-
-/*
- * Returns start time of an online exclusive backup.
- *
- * When there's no exclusive backup in progress, the function
- * returns NULL.
- */
-Datum
-pg_backup_start_time(PG_FUNCTION_ARGS)
-{
- Datum xtime;
- FILE *lfp;
- char fline[MAXPGPATH];
- char backup_start_time[30];
-
- /*
- * See if label file is present
- */
- lfp = AllocateFile(BACKUP_LABEL_FILE, "r");
- if (lfp == NULL)
- {
- if (errno != ENOENT)
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not read file \"%s\": %m",
- BACKUP_LABEL_FILE)));
- PG_RETURN_NULL();
- }
-
- /*
- * Parse the file to find the START TIME line.
- */
- backup_start_time[0] = '\0';
- while (fgets(fline, sizeof(fline), lfp) != NULL)
- {
- if (sscanf(fline, "START TIME: %25[^\n]\n", backup_start_time) == 1)
- break;
- }
-
- /* Check for a read error. */
- if (ferror(lfp))
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not read file \"%s\": %m", BACKUP_LABEL_FILE)));
-
- /* Close the backup label file. */
- if (FreeFile(lfp))
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not close file \"%s\": %m", BACKUP_LABEL_FILE)));
-
- if (strlen(backup_start_time) == 0)
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("invalid data in file \"%s\"", BACKUP_LABEL_FILE)));
-
- /*
- * Convert the time string read from file to TimestampTz form.
- */
- xtime = DirectFunctionCall3(timestamptz_in,
- CStringGetDatum(backup_start_time),
- ObjectIdGetDatum(InvalidOid),
- Int32GetDatum(-1));
-
- PG_RETURN_DATUM(xtime);
-}
-
/*
* Promotes a standby server.
*
diff --git a/src/backend/access/transam/xlogrecovery.c b/src/backend/access/transam/xlogrecovery.c
index 8d2395dae2..d965e584ba 100644
--- a/src/backend/access/transam/xlogrecovery.c
+++ b/src/backend/access/transam/xlogrecovery.c
@@ -1970,7 +1970,7 @@ xlogrecovery_redo(XLogReaderState *record, TimeLineID replayTLI)
{
/*
* We have reached the end of base backup, the point where
- * pg_stop_backup() was done. The data on disk is now consistent
+ * pg_backup_stop() was done. The data on disk is now consistent
* (assuming we have also reached minRecoveryPoint). Set
* backupEndPoint to the current LSN, so that the next call to
* CheckRecoveryConsistency() will notice it and do the
diff --git a/src/backend/catalog/system_functions.sql b/src/backend/catalog/system_functions.sql
index 81bac6f581..6ae4388d3f 100644
--- a/src/backend/catalog/system_functions.sql
+++ b/src/backend/catalog/system_functions.sql
@@ -377,14 +377,14 @@ BEGIN ATOMIC
END;
CREATE OR REPLACE FUNCTION
- pg_start_backup(label text, fast boolean DEFAULT false, exclusive boolean DEFAULT true)
- RETURNS pg_lsn STRICT VOLATILE LANGUAGE internal AS 'pg_start_backup'
+ pg_backup_start(label text, fast boolean DEFAULT false)
+ RETURNS pg_lsn STRICT VOLATILE LANGUAGE internal AS 'pg_backup_start'
PARALLEL RESTRICTED;
-CREATE OR REPLACE FUNCTION pg_stop_backup (
- exclusive boolean, wait_for_archive boolean DEFAULT true,
- OUT lsn pg_lsn, OUT labelfile text, OUT spcmapfile text)
- RETURNS record STRICT VOLATILE LANGUAGE internal as 'pg_stop_backup_v2'
+CREATE OR REPLACE FUNCTION pg_backup_stop (
+ wait_for_archive boolean DEFAULT true, OUT lsn pg_lsn,
+ OUT labelfile text, OUT spcmapfile text)
+ RETURNS record STRICT VOLATILE LANGUAGE internal as 'pg_backup_stop'
PARALLEL RESTRICTED;
CREATE OR REPLACE FUNCTION
@@ -603,11 +603,9 @@ AS 'unicode_is_normalized';
-- available to superuser / cluster owner, if they choose.
--
-REVOKE EXECUTE ON FUNCTION pg_start_backup(text, boolean, boolean) FROM public;
+REVOKE EXECUTE ON FUNCTION pg_backup_start(text, boolean) FROM public;
-REVOKE EXECUTE ON FUNCTION pg_stop_backup() FROM public;
-
-REVOKE EXECUTE ON FUNCTION pg_stop_backup(boolean, boolean) FROM public;
+REVOKE EXECUTE ON FUNCTION pg_backup_stop(boolean) FROM public;
REVOKE EXECUTE ON FUNCTION pg_create_restore_point(text) FROM public;
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index 80bb269599..b6767ed72e 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -348,7 +348,6 @@ static PMState pmState = PM_INIT;
typedef enum
{
ALLOW_ALL_CONNS, /* normal not-shutting-down state */
- ALLOW_SUPERUSER_CONNS, /* only superusers can connect */
ALLOW_NO_CONNS /* no new connections allowed, period */
} ConnsAllowedState;
@@ -2546,19 +2545,11 @@ canAcceptConnections(int backend_type)
/*
* "Smart shutdown" restrictions are applied only to normal connections,
- * not to autovac workers or bgworkers. When only superusers can connect,
- * we return CAC_SUPERUSER to indicate that superuserness must be checked
- * later. Note that neither CAC_OK nor CAC_SUPERUSER can safely be
- * returned until we have checked for too many children.
+ * not to autovac workers or bgworkers.
*/
if (connsAllowed != ALLOW_ALL_CONNS &&
backend_type == BACKEND_TYPE_NORMAL)
- {
- if (connsAllowed == ALLOW_SUPERUSER_CONNS)
- result = CAC_SUPERUSER; /* allow superusers only */
- else
- return CAC_SHUTDOWN; /* shutdown is pending */
- }
+ return CAC_SHUTDOWN; /* shutdown is pending */
/*
* Don't start too many children.
@@ -2877,16 +2868,11 @@ pmdie(SIGNAL_ARGS)
#endif
/*
- * If we reached normal running, we have to wait for any online
- * backup mode to end; otherwise go straight to waiting for client
- * backends to exit. (The difference is that in the former state,
- * we'll still let in new superuser clients, so that somebody can
- * end the online backup mode.) If already in PM_STOP_BACKENDS or
+ * If we reached normal running, we go straight to waiting for
+ * client backends to exit. If already in PM_STOP_BACKENDS or
* a later state, do not change it.
*/
- if (pmState == PM_RUN)
- connsAllowed = ALLOW_SUPERUSER_CONNS;
- else if (pmState == PM_HOT_STANDBY)
+ if (pmState == PM_RUN || pmState == PM_HOT_STANDBY)
connsAllowed = ALLOW_NO_CONNS;
else if (pmState == PM_STARTUP || pmState == PM_RECOVERY)
{
@@ -3842,16 +3828,6 @@ PostmasterStateMachine(void)
/* If we're doing a smart shutdown, try to advance that state. */
if (pmState == PM_RUN || pmState == PM_HOT_STANDBY)
{
- if (connsAllowed == ALLOW_SUPERUSER_CONNS)
- {
- /*
- * ALLOW_SUPERUSER_CONNS state ends as soon as online backup mode
- * is not active.
- */
- if (!BackupInProgress())
- connsAllowed = ALLOW_NO_CONNS;
- }
-
if (connsAllowed == ALLOW_NO_CONNS)
{
/*
@@ -4044,18 +4020,6 @@ PostmasterStateMachine(void)
}
else
{
- /*
- * Terminate exclusive backup mode to avoid recovery after a clean
- * fast shutdown. Since an exclusive backup can only be taken
- * during normal running (and not, for example, while running
- * under Hot Standby) it only makes sense to do this if we reached
- * normal running. If we're still in recovery, the backup file is
- * one we're recovering *from*, and we must keep it around so that
- * recovery restarts from the right place.
- */
- if (ReachedNormalRunning)
- CancelBackup();
-
/*
* Normal exit from the postmaster is here. We don't need to log
* anything here, since the UnlinkLockFiles proc_exit callback
diff --git a/src/backend/replication/basebackup.c b/src/backend/replication/basebackup.c
index 6884cad2c0..815681ada7 100644
--- a/src/backend/replication/basebackup.c
+++ b/src/backend/replication/basebackup.c
@@ -184,10 +184,8 @@ static const struct exclude_list_item excludeFiles[] =
{RELCACHE_INIT_FILENAME, true},
/*
- * If there's a backup_label or tablespace_map file, it belongs to a
- * backup started by the user with pg_start_backup(). It is *not* correct
- * for this backup. Our backup_label/tablespace_map is injected into the
- * tar separately.
+ * backup_label and tablespace_map should not exist in in a running cluster
+ * capable of doing an online backup, but exclude them just in case.
*/
{BACKUP_LABEL_FILE, false},
{TABLESPACE_MAP, false},
@@ -264,16 +262,16 @@ perform_base_backup(basebackup_options *opt, bbsink *sink)
total_checksum_failures = 0;
basebackup_progress_wait_checkpoint();
- state.startptr = do_pg_start_backup(opt->label, opt->fastcheckpoint,
+ state.startptr = do_pg_backup_start(opt->label, opt->fastcheckpoint,
&state.starttli,
labelfile, &state.tablespaces,
tblspc_map_file);
/*
- * Once do_pg_start_backup has been called, ensure that any failure causes
+ * Once do_pg_backup_start has been called, ensure that any failure causes
* us to abort the backup so we don't "leak" a backup counter. For this
- * reason, *all* functionality between do_pg_start_backup() and the end of
- * do_pg_stop_backup() should be inside the error cleanup block!
+ * reason, *all* functionality between do_pg_backup_start() and the end of
+ * do_pg_backup_stop() should be inside the error cleanup block!
*/
PG_ENSURE_ERROR_CLEANUP(do_pg_abort_backup, BoolGetDatum(false));
@@ -394,7 +392,7 @@ perform_base_backup(basebackup_options *opt, bbsink *sink)
}
basebackup_progress_wait_wal_archive(&state);
- endptr = do_pg_stop_backup(labelfile->data, !opt->nowait, &endtli);
+ endptr = do_pg_backup_stop(labelfile->data, !opt->nowait, &endtli);
}
PG_END_ENSURE_ERROR_CLEANUP(do_pg_abort_backup, BoolGetDatum(false));
@@ -961,7 +959,7 @@ parse_basebackup_options(List *options, basebackup_options *opt)
/*
* SendBaseBackup() - send a complete base backup.
*
- * The function will put the system into backup mode like pg_start_backup()
+ * The function will put the system into backup mode like pg_backup_start()
* does, so that the backup is consistent even though we read directly from
* the filesystem, bypassing the buffer cache.
*/
@@ -1204,7 +1202,7 @@ sendDir(bbsink *sink, const char *path, int basepathlen, bool sizeonly,
* error in that case. The error handler further up will call
* do_pg_abort_backup() for us. Also check that if the backup was
* started while still in recovery, the server wasn't promoted.
- * do_pg_stop_backup() will check that too, but it's better to stop
+ * do_pg_backup_stop() will check that too, but it's better to stop
* the backup early than continue to the end and fail there.
*/
CHECK_FOR_INTERRUPTS();
diff --git a/src/bin/pg_basebackup/t/010_pg_basebackup.pl b/src/bin/pg_basebackup/t/010_pg_basebackup.pl
index 5ba84c2250..7309ebddea 100644
--- a/src/bin/pg_basebackup/t/010_pg_basebackup.pl
+++ b/src/bin/pg_basebackup/t/010_pg_basebackup.pl
@@ -247,6 +247,10 @@ isnt(slurp_file("$tempdir/backup/backup_label"),
'DONOTCOPY', 'existing backup_label not copied');
rmtree("$tempdir/backup");
+# Now delete the bogus backup_label file since it will interfere with startup
+unlink("$pgdata/backup_label")
+ or BAIL_OUT("unable to unlink $pgdata/backup_label");
+
$node->command_ok(
[
@pg_basebackup_defs, '-D',
diff --git a/src/bin/pg_ctl/pg_ctl.c b/src/bin/pg_ctl/pg_ctl.c
index 3c182c97d4..3a9092a16a 100644
--- a/src/bin/pg_ctl/pg_ctl.c
+++ b/src/bin/pg_ctl/pg_ctl.c
@@ -1025,7 +1025,6 @@ static void
do_stop(void)
{
pgpid_t pid;
- struct stat statbuf;
pid = get_pgpid(false);
@@ -1058,20 +1057,6 @@ do_stop(void)
}
else
{
- /*
- * If backup_label exists, an online backup is running. Warn the user
- * that smart shutdown will wait for it to finish. However, if the
- * server is in archive recovery, we're recovering from an online
- * backup instead of performing one.
- */
- if (shutdown_mode == SMART_MODE &&
- stat(backup_file, &statbuf) == 0 &&
- get_control_dbstate() != DB_IN_ARCHIVE_RECOVERY)
- {
- print_msg(_("WARNING: online backup mode is active\n"
- "Shutdown will not complete until pg_stop_backup() is called.\n\n"));
- }
-
print_msg(_("waiting for server to shut down..."));
if (!wait_for_postmaster_stop())
@@ -1099,7 +1084,6 @@ static void
do_restart(void)
{
pgpid_t pid;
- struct stat statbuf;
pid = get_pgpid(false);
@@ -1134,20 +1118,6 @@ do_restart(void)
exit(1);
}
- /*
- * If backup_label exists, an online backup is running. Warn the user
- * that smart shutdown will wait for it to finish. However, if the
- * server is in archive recovery, we're recovering from an online
- * backup instead of performing one.
- */
- if (shutdown_mode == SMART_MODE &&
- stat(backup_file, &statbuf) == 0 &&
- get_control_dbstate() != DB_IN_ARCHIVE_RECOVERY)
- {
- print_msg(_("WARNING: online backup mode is active\n"
- "Shutdown will not complete until pg_stop_backup() is called.\n\n"));
- }
-
print_msg(_("waiting for server to shut down..."));
/* always wait for restart */
diff --git a/src/bin/pg_rewind/filemap.c b/src/bin/pg_rewind/filemap.c
index 7211090f47..fb52debf7a 100644
--- a/src/bin/pg_rewind/filemap.c
+++ b/src/bin/pg_rewind/filemap.c
@@ -140,9 +140,9 @@ static const struct exclude_list_item excludeFiles[] =
{"pg_internal.init", true}, /* defined as RELCACHE_INIT_FILENAME */
/*
- * If there's a backup_label or tablespace_map file, it belongs to a
- * backup started by the user with pg_start_backup(). It is *not* correct
- * for this backup. Our backup_label is written later on separately.
+ * If there is a backup_label or tablespace_map file, it indicates that
+ * a recovery failed and this cluster probably can't be rewound, but
+ * exclude them anyway if they are found.
*/
{"backup_label", false}, /* defined as BACKUP_LABEL_FILE */
{"tablespace_map", false}, /* defined as TABLESPACE_MAP */
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index 09f6464331..b81917f243 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -276,14 +276,13 @@ extern void XLogShutdownWalRcv(void);
typedef enum SessionBackupState
{
SESSION_BACKUP_NONE,
- SESSION_BACKUP_EXCLUSIVE,
- SESSION_BACKUP_NON_EXCLUSIVE
+ SESSION_BACKUP_RUNNING,
} SessionBackupState;
-extern XLogRecPtr do_pg_start_backup(const char *backupidstr, bool fast,
+extern XLogRecPtr do_pg_backup_start(const char *backupidstr, bool fast,
TimeLineID *starttli_p, StringInfo labelfile,
List **tablespaces, StringInfo tblspcmapfile);
-extern XLogRecPtr do_pg_stop_backup(char *labelfile, bool waitforarchive,
+extern XLogRecPtr do_pg_backup_stop(char *labelfile, bool waitforarchive,
TimeLineID *stoptli_p);
extern void do_pg_abort_backup(int code, Datum arg);
extern void register_persistent_abort_backup_handler(void);
diff --git a/src/include/catalog/pg_control.h b/src/include/catalog/pg_control.h
index 1f3dc24ac1..3d075fcef3 100644
--- a/src/include/catalog/pg_control.h
+++ b/src/include/catalog/pg_control.h
@@ -163,7 +163,7 @@ typedef struct ControlFileData
* from a backup, and must see a backup-end record before we can safely
* start up. If it's false, but backupStartPoint is set, a backup_label
* file was found at startup but it may have been a leftover from a stray
- * pg_start_backup() call, not accompanied by pg_stop_backup().
+ * pg_backup_start() call, not accompanied by pg_backup_stop().
*/
XLogRecPtr minRecoveryPoint;
TimeLineID minRecoveryPointTLI;
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 25304430f4..361a40a191 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -6274,26 +6274,16 @@
proargtypes => 'int4 int8', proargnames => '{pid,timeout}',
prosrc => 'pg_terminate_backend' },
{ oid => '2172', descr => 'prepare for taking an online backup',
- proname => 'pg_start_backup', provolatile => 'v', proparallel => 'r',
- prorettype => 'pg_lsn', proargtypes => 'text bool bool',
- prosrc => 'pg_start_backup' },
-{ oid => '2173', descr => 'finish taking an online backup',
- proname => 'pg_stop_backup', provolatile => 'v', proparallel => 'r',
- prorettype => 'pg_lsn', proargtypes => '', prosrc => 'pg_stop_backup' },
+ proname => 'pg_backup_start', provolatile => 'v', proparallel => 'r',
+ prorettype => 'pg_lsn', proargtypes => 'text bool',
+ prosrc => 'pg_backup_start' },
{ oid => '2739', descr => 'finish taking an online backup',
- proname => 'pg_stop_backup', provolatile => 'v', proparallel => 'r',
- prorettype => 'record', proargtypes => 'bool bool',
- proallargtypes => '{bool,bool,pg_lsn,text,text}',
- proargmodes => '{i,i,o,o,o}',
- proargnames => '{exclusive,wait_for_archive,lsn,labelfile,spcmapfile}',
- prosrc => 'pg_stop_backup_v2' },
-{ oid => '3813', descr => 'true if server is in online backup',
- proname => 'pg_is_in_backup', provolatile => 'v', prorettype => 'bool',
- proargtypes => '', prosrc => 'pg_is_in_backup' },
-{ oid => '3814', descr => 'start time of an online backup',
- proname => 'pg_backup_start_time', provolatile => 's',
- prorettype => 'timestamptz', proargtypes => '',
- prosrc => 'pg_backup_start_time' },
+ proname => 'pg_backup_stop', provolatile => 'v', proparallel => 'r',
+ prorettype => 'record', proargtypes => 'bool',
+ proallargtypes => '{bool,pg_lsn,text,text}',
+ proargmodes => '{i,o,o,o}',
+ proargnames => '{wait_for_archive,lsn,labelfile,spcmapfile}',
+ prosrc => 'pg_backup_stop' },
{ oid => '3436', descr => 'promote standby server',
proname => 'pg_promote', provolatile => 'v', prorettype => 'bool',
proargtypes => 'bool int4', proargnames => '{wait,wait_seconds}',
diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h
index 0abc3ad540..9321d7f264 100644
--- a/src/include/miscadmin.h
+++ b/src/include/miscadmin.h
@@ -481,10 +481,6 @@ extern void process_session_preload_libraries(void);
extern void pg_bindtextdomain(const char *domain);
extern bool has_rolreplication(Oid roleid);
-/* in access/transam/xlog.c */
-extern bool BackupInProgress(void);
-extern void CancelBackup(void);
-
/* in executor/nodeHash.c */
extern size_t get_hash_memory_limit(void);
diff --git a/src/test/perl/PostgreSQL/Test/Cluster.pm b/src/test/perl/PostgreSQL/Test/Cluster.pm
index b4ebc99935..1452297210 100644
--- a/src/test/perl/PostgreSQL/Test/Cluster.pm
+++ b/src/test/perl/PostgreSQL/Test/Cluster.pm
@@ -638,25 +638,6 @@ sub backup
return;
}
-=item $node->backup_fs_hot(backup_name)
-
-Create a backup with a filesystem level copy in subdirectory B<backup_name> of
-B<< $node->backup_dir >>, including WAL.
-
-Archiving must be enabled, as B<pg_start_backup()> and B<pg_stop_backup()> are
-used. This is not checked or enforced.
-
-The backup name is passed as the backup label to B<pg_start_backup()>.
-
-=cut
-
-sub backup_fs_hot
-{
- my ($self, $backup_name) = @_;
- $self->_backup_fs($backup_name, 1);
- return;
-}
-
=item $node->backup_fs_cold(backup_name)
Create a backup with a filesystem level copy in subdirectory B<backup_name> of
@@ -670,53 +651,18 @@ Use B<backup> or B<backup_fs_hot> if you want to back up a running server.
sub backup_fs_cold
{
my ($self, $backup_name) = @_;
- $self->_backup_fs($backup_name, 0);
- return;
-}
-
-
-# Common sub of backup_fs_hot and backup_fs_cold
-sub _backup_fs
-{
- my ($self, $backup_name, $hot) = @_;
- my $backup_path = $self->backup_dir . '/' . $backup_name;
- my $port = $self->port;
- my $name = $self->name;
-
- print "# Taking filesystem backup $backup_name from node \"$name\"\n";
-
- if ($hot)
- {
- my $stdout = $self->safe_psql('postgres',
- "SELECT * FROM pg_start_backup('$backup_name');");
- print "# pg_start_backup: $stdout\n";
- }
PostgreSQL::Test::RecursiveCopy::copypath(
$self->data_dir,
- $backup_path,
+ $self->backup_dir . '/' . $backup_name,
filterfn => sub {
my $src = shift;
return ($src ne 'log' and $src ne 'postmaster.pid');
});
- if ($hot)
- {
-
- # We ignore pg_stop_backup's return value. We also assume archiving
- # is enabled; otherwise the caller will have to copy the remaining
- # segments.
- my $stdout =
- $self->safe_psql('postgres', 'SELECT * FROM pg_stop_backup();');
- print "# pg_stop_backup: $stdout\n";
- }
-
- print "# Backup finished\n";
return;
}
-
-
=pod
=item $node->init_from_backup(root_node, backup_name)
diff --git a/src/test/recovery/t/010_logical_decoding_timelines.pl b/src/test/recovery/t/010_logical_decoding_timelines.pl
index 01ff31e61f..135fb1a72d 100644
--- a/src/test/recovery/t/010_logical_decoding_timelines.pl
+++ b/src/test/recovery/t/010_logical_decoding_timelines.pl
@@ -69,7 +69,9 @@ $node_primary->safe_psql('dropme',
$node_primary->safe_psql('postgres', 'CHECKPOINT;');
my $backup_name = 'b1';
-$node_primary->backup_fs_hot($backup_name);
+$node_primary->stop();
+$node_primary->backup_fs_cold($backup_name);
+$node_primary->start();
$node_primary->safe_psql('postgres',
q[SELECT pg_create_physical_replication_slot('phys_slot');]);
--
2.25.1
I noticed a couple of other things that can be removed. Since we no longer
wait on exclusive backup mode during smart shutdown, we can change
connsAllowed (in postmaster.c) to a boolean and remove CAC_SUPERUSER. We
can also remove a couple of related notes in the documentation. I've done
all this in the attached patch.
--
Nathan Bossart
Amazon Web Services: https://aws.amazon.com
Attachments:
v10-0001-remove-exclusive-backup-mode.patchtext/x-diff; charset=us-asciiDownload
From 5d79d79472252207eea5b7dcc52010736da10296 Mon Sep 17 00:00:00 2001
From: Nathan Bossart <bossartn@amazon.com>
Date: Wed, 1 Dec 2021 23:50:49 +0000
Subject: [PATCH v10 1/1] remove exclusive backup mode
---
doc/src/sgml/backup.sgml | 230 +-------
doc/src/sgml/func.sgml | 111 +---
doc/src/sgml/high-availability.sgml | 6 +-
doc/src/sgml/monitoring.sgml | 4 +-
doc/src/sgml/ref/pg_ctl-ref.sgml | 6 +-
doc/src/sgml/ref/pgupgrade.sgml | 2 +-
doc/src/sgml/runtime.sgml | 8 +-
src/backend/access/transam/xlog.c | 493 ++----------------
src/backend/access/transam/xlogfuncs.c | 253 ++-------
src/backend/access/transam/xlogrecovery.c | 2 +-
src/backend/catalog/system_functions.sql | 18 +-
src/backend/postmaster/postmaster.c | 75 +--
src/backend/replication/basebackup.c | 20 +-
src/backend/utils/init/postinit.c | 18 -
src/bin/pg_basebackup/t/010_pg_basebackup.pl | 4 +
src/bin/pg_ctl/pg_ctl.c | 30 --
src/bin/pg_rewind/filemap.c | 6 +-
src/include/access/xlog.h | 7 +-
src/include/catalog/pg_control.h | 2 +-
src/include/catalog/pg_proc.dat | 28 +-
src/include/libpq/libpq-be.h | 3 +-
src/include/miscadmin.h | 4 -
src/test/perl/PostgreSQL/Test/Cluster.pm | 56 +-
.../t/010_logical_decoding_timelines.pl | 4 +-
24 files changed, 213 insertions(+), 1177 deletions(-)
diff --git a/doc/src/sgml/backup.sgml b/doc/src/sgml/backup.sgml
index 0d69851bb1..5b7139c7df 100644
--- a/doc/src/sgml/backup.sgml
+++ b/doc/src/sgml/backup.sgml
@@ -857,16 +857,8 @@ test ! -f /mnt/server/archivedir/00000001000000A900000065 && cp pg_wal/0
sequence, and that the success of a step is verified before
proceeding to the next step.
</para>
- <para>
- Low level base backups can be made in a non-exclusive or an exclusive
- way. The non-exclusive method is recommended and the exclusive one is
- deprecated and will eventually be removed.
- </para>
-
- <sect3 id="backup-lowlevel-base-backup-nonexclusive">
- <title>Making a Non-Exclusive Low-Level Backup</title>
<para>
- A non-exclusive low level backup is one that allows other
+ A low level backup allows other
concurrent backups to be running (both those started using
the same backup API and those started using
<xref linkend="app-pgbasebackup"/>).
@@ -881,23 +873,23 @@ test ! -f /mnt/server/archivedir/00000001000000A900000065 && cp pg_wal/0
<listitem>
<para>
Connect to the server (it does not matter which database) as a user with
- rights to run pg_start_backup (superuser, or a user who has been granted
+ rights to run pg_backup_start (superuser, or a user who has been granted
EXECUTE on the function) and issue the command:
<programlisting>
-SELECT pg_start_backup('label', false, false);
+SELECT pg_backup_start(label => 'label', fast => false);
</programlisting>
where <literal>label</literal> is any string you want to use to uniquely
identify this backup operation. The connection
- calling <function>pg_start_backup</function> must be maintained until the end of
+ calling <function>pg_backup_start</function> must be maintained until the end of
the backup, or the backup will be automatically aborted.
</para>
<para>
- By default, <function>pg_start_backup</function> can take a long time to finish.
- This is because it performs a checkpoint, and the I/O
- required for the checkpoint will be spread out over a significant
- period of time, by default half your inter-checkpoint interval
- (see the configuration parameter
+ By default, <function>pg_backup_start</function> can take a long time to finish.
+ This is because it waits for the next checkpoint to complete, and the I/O
+ required for the checkpoint might be spread out over a significant
+ period of time (see the configuration parameters
+ <xref linkend="guc-checkpoint-timeout"/> and
<xref linkend="guc-checkpoint-completion-target"/>). This is
usually what you want, because it minimizes the impact on query
processing. If you want to start the backup as soon as
@@ -905,10 +897,6 @@ SELECT pg_start_backup('label', false, false);
issue an immediate checkpoint using as much I/O as available.
</para>
- <para>
- The third parameter being <literal>false</literal> tells
- <function>pg_start_backup</function> to initiate a non-exclusive base backup.
- </para>
</listitem>
<listitem>
<para>
@@ -926,7 +914,7 @@ SELECT pg_start_backup('label', false, false);
<para>
In the same connection as before, issue the command:
<programlisting>
-SELECT * FROM pg_stop_backup(false, true);
+SELECT * FROM pg_backup_stop(wait_for_archive => true);
</programlisting>
This terminates backup mode. On a primary, it also performs an automatic
switch to the next WAL segment. On a standby, it is not possible to
@@ -937,7 +925,7 @@ SELECT * FROM pg_stop_backup(false, true);
ready to archive.
</para>
<para>
- The <function>pg_stop_backup</function> will return one row with three
+ <function>pg_backup_stop</function> will return one row with three
values. The second of these fields should be written to a file named
<filename>backup_label</filename> in the root directory of the backup. The
third field should be written to a file named
@@ -949,14 +937,14 @@ SELECT * FROM pg_stop_backup(false, true);
<listitem>
<para>
Once the WAL segment files active during the backup are archived, you are
- done. The file identified by <function>pg_stop_backup</function>'s first return
+ done. The file identified by <function>pg_backup_stop</function>'s first return
value is the last segment that is required to form a complete set of
backup files. On a primary, if <varname>archive_mode</varname> is enabled and the
<literal>wait_for_archive</literal> parameter is <literal>true</literal>,
- <function>pg_stop_backup</function> does not return until the last segment has
+ <function>pg_backup_stop</function> does not return until the last segment has
been archived.
On a standby, <varname>archive_mode</varname> must be <literal>always</literal> in order
- for <function>pg_stop_backup</function> to wait.
+ for <function>pg_backup_stop</function> to wait.
Archiving of these files happens automatically since you have
already configured <varname>archive_library</varname>. In most cases this
happens quickly, but you are advised to monitor your archive
@@ -965,9 +953,9 @@ SELECT * FROM pg_stop_backup(false, true);
because of failures of the archive library, it will keep retrying
until the archive succeeds and the backup is complete.
If you wish to place a time limit on the execution of
- <function>pg_stop_backup</function>, set an appropriate
+ <function>pg_backup_stop</function>, set an appropriate
<varname>statement_timeout</varname> value, but make note that if
- <function>pg_stop_backup</function> terminates because of this your backup
+ <function>pg_backup_stop</function> terminates because of this your backup
may not be valid.
</para>
<para>
@@ -975,8 +963,8 @@ SELECT * FROM pg_stop_backup(false, true);
required for the backup are successfully archived then the
<literal>wait_for_archive</literal> parameter (which defaults to true) can be set
to false to have
- <function>pg_stop_backup</function> return as soon as the stop backup record is
- written to the WAL. By default, <function>pg_stop_backup</function> will wait
+ <function>pg_backup_stop</function> return as soon as the stop backup record is
+ written to the WAL. By default, <function>pg_backup_stop</function> will wait
until all WAL has been archived, which can take some time. This option
must be used with caution: if WAL archiving is not monitored correctly
then the backup might not include all of the WAL files and will
@@ -985,142 +973,6 @@ SELECT * FROM pg_stop_backup(false, true);
</listitem>
</orderedlist>
</para>
- </sect3>
- <sect3 id="backup-lowlevel-base-backup-exclusive">
- <title>Making an Exclusive Low-Level Backup</title>
-
- <note>
- <para>
- The exclusive backup method is deprecated and should be avoided.
- Prior to <productname>PostgreSQL</productname> 9.6, this was the only
- low-level method available, but it is now recommended that all users
- upgrade their scripts to use non-exclusive backups.
- </para>
- </note>
-
- <para>
- The process for an exclusive backup is mostly the same as for a
- non-exclusive one, but it differs in a few key steps. This type of
- backup can only be taken on a primary and does not allow concurrent
- backups. Moreover, because it creates a backup label file, as
- described below, it can block automatic restart of the primary server
- after a crash. On the other hand, the erroneous removal of this
- file from a backup or standby is a common mistake, which can result
- in serious data corruption. If it is necessary to use this method,
- the following steps may be used.
- </para>
- <para>
- <orderedlist>
- <listitem>
- <para>
- Ensure that WAL archiving is enabled and working.
- </para>
- </listitem>
- <listitem>
- <para>
- Connect to the server (it does not matter which database) as a user with
- rights to run pg_start_backup (superuser, or a user who has been granted
- EXECUTE on the function) and issue the command:
-<programlisting>
-SELECT pg_start_backup('label');
-</programlisting>
- where <literal>label</literal> is any string you want to use to uniquely
- identify this backup operation.
- <function>pg_start_backup</function> creates a <firstterm>backup label</firstterm> file,
- called <filename>backup_label</filename>, in the cluster directory with
- information about your backup, including the start time and label string.
- The function also creates a <firstterm>tablespace map</firstterm> file,
- called <filename>tablespace_map</filename>, in the cluster directory with
- information about tablespace symbolic links in <filename>pg_tblspc/</filename> if
- one or more such link is present. Both files are critical to the
- integrity of the backup, should you need to restore from it.
- </para>
-
- <para>
- By default, <function>pg_start_backup</function> can take a long time to finish.
- This is because it performs a checkpoint, and the I/O
- required for the checkpoint will be spread out over a significant
- period of time, by default half your inter-checkpoint interval
- (see the configuration parameter
- <xref linkend="guc-checkpoint-completion-target"/>). This is
- usually what you want, because it minimizes the impact on query
- processing. If you want to start the backup as soon as
- possible, use:
-<programlisting>
-SELECT pg_start_backup('label', true);
-</programlisting>
- This forces the checkpoint to be done as quickly as possible.
- </para>
- </listitem>
- <listitem>
- <para>
- Perform the backup, using any convenient file-system-backup tool
- such as <application>tar</application> or <application>cpio</application> (not
- <application>pg_dump</application> or
- <application>pg_dumpall</application>). It is neither
- necessary nor desirable to stop normal operation of the database
- while you do this. See
- <xref linkend="backup-lowlevel-base-backup-data"/> for things to
- consider during this backup.
- </para>
- <para>
- As noted above, if the server crashes during the backup it may not be
- possible to restart until the <filename>backup_label</filename> file has
- been manually deleted from the <envar>PGDATA</envar> directory. Note
- that it is very important to never remove the
- <filename>backup_label</filename> file when restoring a backup, because
- this will result in corruption. Confusion about when it is appropriate
- to remove this file is a common cause of data corruption when using this
- method; be very certain that you remove the file only on an existing
- primary and never when building a standby or restoring a backup, even if
- you are building a standby that will subsequently be promoted to a new
- primary.
- </para>
- </listitem>
- <listitem>
- <para>
- Again connect to the database as a user with rights to run
- pg_stop_backup (superuser, or a user who has been granted EXECUTE on
- the function), and issue the command:
-<programlisting>
-SELECT pg_stop_backup();
-</programlisting>
- This function terminates backup mode and
- performs an automatic switch to the next WAL segment. The reason for the
- switch is to arrange for the last WAL segment written during the backup
- interval to be ready to archive.
- </para>
- </listitem>
- <listitem>
- <para>
- Once the WAL segment files active during the backup are archived, you are
- done. The file identified by <function>pg_stop_backup</function>'s result is
- the last segment that is required to form a complete set of backup files.
- If <varname>archive_mode</varname> is enabled,
- <function>pg_stop_backup</function> does not return until the last segment has
- been archived.
- Archiving of these files happens automatically since you have
- already configured <varname>archive_command</varname>. In most cases this
- happens quickly, but you are advised to monitor your archive
- system to ensure there are no delays.
- If the archive process has fallen behind
- because of failures of the archive command, it will keep retrying
- until the archive succeeds and the backup is complete.
- </para>
-
- <para>
- When using exclusive backup mode, it is absolutely imperative to ensure
- that <function>pg_stop_backup</function> completes successfully at the
- end of the backup. Even if the backup itself fails, for example due to
- lack of disk space, failure to call <function>pg_stop_backup</function>
- will leave the server in backup mode indefinitely, causing future backups
- to fail and increasing the risk of a restart failure during the time that
- <filename>backup_label</filename> exists.
- </para>
- </listitem>
- </orderedlist>
- </para>
- </sect3>
<sect3 id="backup-lowlevel-base-backup-data">
<title>Backing Up the Data Directory</title>
<para>
@@ -1203,8 +1055,8 @@ SELECT pg_stop_backup();
<para>
The backup label
- file includes the label string you gave to <function>pg_start_backup</function>,
- as well as the time at which <function>pg_start_backup</function> was run, and
+ file includes the label string you gave to <function>pg_backup_start</function>,
+ as well as the time at which <function>pg_backup_start</function> was run, and
the name of the starting WAL file. In case of confusion it is therefore
possible to look inside a backup file and determine exactly which
backup session the dump file came from. The tablespace map file includes
@@ -1218,7 +1070,7 @@ SELECT pg_stop_backup();
<para>
It is also possible to make a backup while the server is
stopped. In this case, you obviously cannot use
- <function>pg_start_backup</function> or <function>pg_stop_backup</function>, and
+ <function>pg_backup_start</function> or <function>pg_backup_stop</function>, and
you will therefore be left to your own devices to keep track of which
backup is which and how far back the associated WAL files go.
It is generally better to follow the continuous archiving procedure above.
@@ -1393,7 +1245,7 @@ restore_command = 'cp /mnt/server/archivedir/%f %p'
<note>
<para>
The stop point must be after the ending time of the base backup, i.e.,
- the end time of <function>pg_stop_backup</function>. You cannot use a base backup
+ the end time of <function>pg_backup_stop</function>. You cannot use a base backup
to recover to a time when that backup was in progress. (To
recover to such a time, you must go back to your previous base backup
and roll forward from there.)
@@ -1513,44 +1365,6 @@ restore_command = 'cp /mnt/server/archivedir/%f %p'
included in the backup automatically, and no special action is
required to restore the backup.
</para>
-
- <para>
- If more flexibility in copying the backup files is needed, a lower
- level process can be used for standalone hot backups as well.
- To prepare for low level standalone hot backups, make sure
- <varname>wal_level</varname> is set to
- <literal>replica</literal> or higher, <varname>archive_mode</varname> to
- <literal>on</literal>, and set up an <varname>archive_library</varname> that performs
- archiving only when a <emphasis>switch file</emphasis> exists. For example:
-<programlisting>
-archive_library = '' # use shell command
-archive_command = 'test ! -f /var/lib/pgsql/backup_in_progress || (test ! -f /var/lib/pgsql/archive/%f && cp %p /var/lib/pgsql/archive/%f)'
-</programlisting>
- This command will perform archiving when
- <filename>/var/lib/pgsql/backup_in_progress</filename> exists, and otherwise
- silently return zero exit status (allowing <productname>PostgreSQL</productname>
- to recycle the unwanted WAL file).
- </para>
-
- <para>
- With this preparation, a backup can be taken using a script like the
- following:
-<programlisting>
-touch /var/lib/pgsql/backup_in_progress
-psql -c "select pg_start_backup('hot_backup');"
-tar -cf /var/lib/pgsql/backup.tar /var/lib/pgsql/data/
-psql -c "select pg_stop_backup();"
-rm /var/lib/pgsql/backup_in_progress
-tar -rf /var/lib/pgsql/backup.tar /var/lib/pgsql/archive/
-</programlisting>
- The switch file <filename>/var/lib/pgsql/backup_in_progress</filename> is
- created first, enabling archiving of completed WAL files to occur.
- After the backup the switch file is removed. Archived WAL files are
- then added to the backup so that both base backup and all required
- WAL files are part of the same <application>tar</application> file.
- Please remember to add error handling to your backup scripts.
- </para>
-
</sect3>
<sect3 id="compressed-archive-logs">
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 4001cb2bda..ac4575217b 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -25598,9 +25598,8 @@ LOG: Grand total: 1651920 bytes in 201 blocks; 622360 free (88 chunks); 1029560
The functions shown in <xref
linkend="functions-admin-backup-table"/> assist in making on-line backups.
These functions cannot be executed during recovery (except
- non-exclusive <function>pg_start_backup</function>,
- non-exclusive <function>pg_stop_backup</function>,
- <function>pg_is_in_backup</function>, <function>pg_backup_start_time</function>
+ <function>pg_backup_start</function>,
+ <function>pg_backup_stop</function>,
and <function>pg_wal_lsn_diff</function>).
</para>
@@ -25689,13 +25688,12 @@ LOG: Grand total: 1651920 bytes in 201 blocks; 622360 free (88 chunks); 1029560
<row>
<entry role="func_table_entry"><para role="func_signature">
<indexterm>
- <primary>pg_start_backup</primary>
+ <primary>pg_backup_start</primary>
</indexterm>
- <function>pg_start_backup</function> (
+ <function>pg_backup_start</function> (
<parameter>label</parameter> <type>text</type>
<optional>, <parameter>fast</parameter> <type>boolean</type>
- <optional>, <parameter>exclusive</parameter> <type>boolean</type>
- </optional></optional> )
+ </optional> )
<returnvalue>pg_lsn</returnvalue>
</para>
<para>
@@ -25704,23 +25702,9 @@ LOG: Grand total: 1651920 bytes in 201 blocks; 622360 free (88 chunks); 1029560
(Typically this would be the name under which the backup dump file
will be stored.)
If the optional second parameter is given as <literal>true</literal>,
- it specifies executing <function>pg_start_backup</function> as quickly
+ it specifies executing <function>pg_backup_start</function> as quickly
as possible. This forces an immediate checkpoint which will cause a
spike in I/O operations, slowing any concurrently executing queries.
- The optional third parameter specifies whether to perform an exclusive
- or non-exclusive backup (default is exclusive).
- </para>
- <para>
- When used in exclusive mode, this function writes a backup label file
- (<filename>backup_label</filename>) and, if there are any links in
- the <filename>pg_tblspc/</filename> directory, a tablespace map file
- (<filename>tablespace_map</filename>) into the database cluster's data
- directory, then performs a checkpoint, and then returns the backup's
- starting write-ahead log location. (The user can ignore this
- result value, but it is provided in case it is useful.) When used in
- non-exclusive mode, the contents of these files are instead returned
- by the <function>pg_stop_backup</function> function, and should be
- copied to the backup area by the user.
</para>
<para>
This function is restricted to superusers by default, but other users
@@ -25731,11 +25715,10 @@ LOG: Grand total: 1651920 bytes in 201 blocks; 622360 free (88 chunks); 1029560
<row>
<entry role="func_table_entry"><para role="func_signature">
<indexterm>
- <primary>pg_stop_backup</primary>
+ <primary>pg_backup_stop</primary>
</indexterm>
- <function>pg_stop_backup</function> (
- <parameter>exclusive</parameter> <type>boolean</type>
- <optional>, <parameter>wait_for_archive</parameter> <type>boolean</type>
+ <function>pg_backup_stop</function> (
+ <optional><parameter>wait_for_archive</parameter> <type>boolean</type>
</optional> )
<returnvalue>record</returnvalue>
( <parameter>lsn</parameter> <type>pg_lsn</type>,
@@ -25743,24 +25726,21 @@ LOG: Grand total: 1651920 bytes in 201 blocks; 622360 free (88 chunks); 1029560
<parameter>spcmapfile</parameter> <type>text</type> )
</para>
<para>
- Finishes performing an exclusive or non-exclusive on-line backup.
- The <parameter>exclusive</parameter> parameter must match the
- previous <function>pg_start_backup</function> call.
- In an exclusive backup, <function>pg_stop_backup</function> removes
- the backup label file and, if it exists, the tablespace map file
- created by <function>pg_start_backup</function>. In a non-exclusive
- backup, the desired contents of these files are returned as part of
- the result of the function, and should be written to files in the
- backup area (not in the data directory).
+ Finishes performing an on-line backup. The desired contents of the
+ backup label file and the tablespace map file are returned as part of
+ the result of the function and must be written to files in the
+ backup area. These files must not be written to the live data directory
+ (doing so will cause PostgreSQL to fail to restart in the event of a
+ crash).
</para>
<para>
- There is an optional second parameter of type <type>boolean</type>.
+ There is an optional parameter of type <type>boolean</type>.
If false, the function will return immediately after the backup is
completed, without waiting for WAL to be archived. This behavior is
only useful with backup software that independently monitors WAL
archiving. Otherwise, WAL required to make the backup consistent might
be missing and make the backup useless. By default or when this
- parameter is true, <function>pg_stop_backup</function> will wait for
+ parameter is true, <function>pg_backup_stop</function> will wait for
WAL to be archived when archiving is enabled. (On a standby, this
means that it will wait only when <varname>archive_mode</varname> =
<literal>always</literal>. If write activity on the primary is low,
@@ -25770,7 +25750,7 @@ LOG: Grand total: 1651920 bytes in 201 blocks; 622360 free (88 chunks); 1029560
<para>
When executed on a primary, this function also creates a backup
history file in the write-ahead log archive area. The history file
- includes the label given to <function>pg_start_backup</function>, the
+ includes the label given to <function>pg_backup_start</function>, the
starting and ending write-ahead log locations for the backup, and the
starting and ending times of the backup. After recording the ending
location, the current write-ahead log insertion point is automatically
@@ -25781,27 +25761,11 @@ LOG: Grand total: 1651920 bytes in 201 blocks; 622360 free (88 chunks); 1029560
<para>
The result of the function is a single record.
The <parameter>lsn</parameter> column holds the backup's ending
- write-ahead log location (which again can be ignored). The second and
- third columns are <literal>NULL</literal> when ending an exclusive
- backup; after a non-exclusive backup they hold the desired contents of
- the label and tablespace map files.
- </para>
- <para>
- This function is restricted to superusers by default, but other users
- can be granted EXECUTE to run the function.
- </para></entry>
- </row>
-
- <row>
- <entry role="func_table_entry"><para role="func_signature">
- <function>pg_stop_backup</function> ()
- <returnvalue>pg_lsn</returnvalue>
- </para>
- <para>
- Finishes performing an exclusive on-line backup. This simplified
- version is equivalent to <literal>pg_stop_backup(true,
- true)</literal>, except that it only returns the <type>pg_lsn</type>
- result.
+ write-ahead log location (which again can be ignored). The second
+ column returns the contents of the backup label file, and the third
+ column returns the contents of the tablespace map file. These must be
+ stored as part of the backup and are required as part of the restore
+ process.
</para>
<para>
This function is restricted to superusers by default, but other users
@@ -25809,33 +25773,6 @@ LOG: Grand total: 1651920 bytes in 201 blocks; 622360 free (88 chunks); 1029560
</para></entry>
</row>
- <row>
- <entry role="func_table_entry"><para role="func_signature">
- <indexterm>
- <primary>pg_is_in_backup</primary>
- </indexterm>
- <function>pg_is_in_backup</function> ()
- <returnvalue>boolean</returnvalue>
- </para>
- <para>
- Returns true if an on-line exclusive backup is in progress.
- </para></entry>
- </row>
-
- <row>
- <entry role="func_table_entry"><para role="func_signature">
- <indexterm>
- <primary>pg_backup_start_time</primary>
- </indexterm>
- <function>pg_backup_start_time</function> ()
- <returnvalue>timestamp with time zone</returnvalue>
- </para>
- <para>
- Returns the start time of the current on-line exclusive backup if one
- is in progress, otherwise <literal>NULL</literal>.
- </para></entry>
- </row>
-
<row>
<entry role="func_table_entry"><para role="func_signature">
<indexterm>
@@ -25933,7 +25870,7 @@ LOG: Grand total: 1651920 bytes in 201 blocks; 622360 free (88 chunks); 1029560
corresponding write-ahead log file name and byte offset from
a <type>pg_lsn</type> value. For example:
<programlisting>
-postgres=# SELECT * FROM pg_walfile_name_offset(pg_stop_backup());
+postgres=# SELECT * FROM pg_walfile_name_offset((pg_backup_stop()).lsn);
file_name | file_offset
--------------------------+-------------
00000001000000000000000D | 4039624
diff --git a/doc/src/sgml/high-availability.sgml b/doc/src/sgml/high-availability.sgml
index 81fa26f985..3247e05666 100644
--- a/doc/src/sgml/high-availability.sgml
+++ b/doc/src/sgml/high-availability.sgml
@@ -1361,8 +1361,8 @@ synchronous_standby_names = 'ANY 2 (s1, s2, s3)'
<para>
If you need to re-create a standby server while transactions are
- waiting, make sure that the commands pg_start_backup() and
- pg_stop_backup() are run in a session with
+ waiting, make sure that the commands pg_backup_start() and
+ pg_backup_stop() are run in a session with
<varname>synchronous_commit</varname> = <literal>off</literal>, otherwise those
requests will wait forever for the standby to appear.
</para>
@@ -2159,7 +2159,7 @@ HINT: You can then restart the server after making the necessary configuration
<para>
WAL file control commands will not work during recovery,
- e.g., <function>pg_start_backup</function>, <function>pg_switch_wal</function> etc.
+ e.g., <function>pg_backup_start</function>, <function>pg_switch_wal</function> etc.
</para>
<para>
diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
index 3b9172f65b..487331c115 100644
--- a/doc/src/sgml/monitoring.sgml
+++ b/doc/src/sgml/monitoring.sgml
@@ -6674,7 +6674,7 @@ SELECT pg_stat_get_backend_pid(s.backendid) AS pid,
<entry><literal>waiting for checkpoint to finish</literal></entry>
<entry>
The WAL sender process is currently performing
- <function>pg_start_backup</function> to prepare to
+ <function>pg_backup_start</function> to prepare to
take a base backup, and waiting for the start-of-backup
checkpoint to finish.
</entry>
@@ -6697,7 +6697,7 @@ SELECT pg_stat_get_backend_pid(s.backendid) AS pid,
<entry><literal>waiting for wal archiving to finish</literal></entry>
<entry>
The WAL sender process is currently performing
- <function>pg_stop_backup</function> to finish the backup,
+ <function>pg_backup_stop</function> to finish the backup,
and waiting for all the WAL files required for the base backup
to be successfully archived.
If either <literal>--wal-method=none</literal> or
diff --git a/doc/src/sgml/ref/pg_ctl-ref.sgml b/doc/src/sgml/ref/pg_ctl-ref.sgml
index 3946fa52ea..46906966eb 100644
--- a/doc/src/sgml/ref/pg_ctl-ref.sgml
+++ b/doc/src/sgml/ref/pg_ctl-ref.sgml
@@ -186,11 +186,11 @@ PostgreSQL documentation
the specified data directory. Three different
shutdown methods can be selected with the <option>-m</option>
option. <quote>Smart</quote> mode disallows new connections, then waits
- for all existing clients to disconnect and any online backup to finish.
+ for all existing clients to disconnect.
If the server is in hot standby, recovery and streaming replication
will be terminated once all clients have disconnected.
- <quote>Fast</quote> mode (the default) does not wait for clients to disconnect and
- will terminate an online backup in progress. All active transactions are
+ <quote>Fast</quote> mode (the default) does not wait for clients to disconnect.
+ All active transactions are
rolled back and clients are forcibly disconnected, then the
server is shut down. <quote>Immediate</quote> mode will abort
all server processes immediately, without a clean shutdown. This choice
diff --git a/doc/src/sgml/ref/pgupgrade.sgml b/doc/src/sgml/ref/pgupgrade.sgml
index 729c886ac0..3fbe141456 100644
--- a/doc/src/sgml/ref/pgupgrade.sgml
+++ b/doc/src/sgml/ref/pgupgrade.sgml
@@ -618,7 +618,7 @@ rsync --archive --delete --hard-links --size-only --no-inc-recursive /vol1/pg_tb
<para>
Configure the servers for log shipping. (You do not need to run
- <function>pg_start_backup()</function> and <function>pg_stop_backup()</function>
+ <function>pg_backup_start()</function> and <function>pg_backup_stop()</function>
or take a file system backup as the standbys are still synchronized
with the primary.)
</para>
diff --git a/doc/src/sgml/runtime.sgml b/doc/src/sgml/runtime.sgml
index 1f021ea116..f5f4e3fab5 100644
--- a/doc/src/sgml/runtime.sgml
+++ b/doc/src/sgml/runtime.sgml
@@ -1552,11 +1552,7 @@ $ <userinput>cat /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages</userinp
After receiving <systemitem>SIGTERM</systemitem>, the server
disallows new connections, but lets existing sessions end their
work normally. It shuts down only after all of the sessions terminate.
- If the server is in online backup mode, it additionally waits
- until online backup mode is no longer active. While backup mode is
- active, new connections will still be allowed, but only to superusers
- (this exception allows a superuser to connect to terminate
- online backup mode). If the server is in recovery when a smart
+ If the server is in recovery when a smart
shutdown is requested, recovery and streaming replication will be
stopped only after all regular sessions have terminated.
</para>
@@ -1572,8 +1568,6 @@ $ <userinput>cat /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages</userinp
server processes <systemitem>SIGTERM</systemitem>, which will cause them
to abort their current transactions and exit promptly. It then
waits for all server processes to exit and finally shuts down.
- If the server is in online backup mode, backup mode will be
- terminated, rendering the backup useless.
</para>
</listitem>
</varlistentry>
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 17a56152f1..b539d87111 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -385,29 +385,6 @@ typedef union WALInsertLockPadded
char pad[PG_CACHE_LINE_SIZE];
} WALInsertLockPadded;
-/*
- * State of an exclusive backup, necessary to control concurrent activities
- * across sessions when working on exclusive backups.
- *
- * EXCLUSIVE_BACKUP_NONE means that there is no exclusive backup actually
- * running, to be more precise pg_start_backup() is not being executed for
- * an exclusive backup and there is no exclusive backup in progress.
- * EXCLUSIVE_BACKUP_STARTING means that pg_start_backup() is starting an
- * exclusive backup.
- * EXCLUSIVE_BACKUP_IN_PROGRESS means that pg_start_backup() has finished
- * running and an exclusive backup is in progress. pg_stop_backup() is
- * needed to finish it.
- * EXCLUSIVE_BACKUP_STOPPING means that pg_stop_backup() is stopping an
- * exclusive backup.
- */
-typedef enum ExclusiveBackupState
-{
- EXCLUSIVE_BACKUP_NONE = 0,
- EXCLUSIVE_BACKUP_STARTING,
- EXCLUSIVE_BACKUP_IN_PROGRESS,
- EXCLUSIVE_BACKUP_STOPPING
-} ExclusiveBackupState;
-
/*
* Session status of running backup, used for sanity checks in SQL-callable
* functions to start and stop backups.
@@ -456,15 +433,12 @@ typedef struct XLogCtlInsert
bool fullPageWrites;
/*
- * exclusiveBackupState indicates the state of an exclusive backup (see
- * comments of ExclusiveBackupState for more details). nonExclusiveBackups
- * is a counter indicating the number of streaming base backups currently
- * in progress. forcePageWrites is set to true when either of these is
- * non-zero. lastBackupStart is the latest checkpoint redo location used
- * as a starting point for an online backup.
+ * runningBackups is a counter indicating the number of backups currently in
+ * progress. forcePageWrites is set to true when runningBackups is non-zero.
+ * lastBackupStart is the latest checkpoint redo location used as a starting
+ * point for an online backup.
*/
- ExclusiveBackupState exclusiveBackupState;
- int nonExclusiveBackups;
+ int runningBackups;
XLogRecPtr lastBackupStart;
/*
@@ -696,8 +670,7 @@ static void ReadControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow);
-static void pg_start_backup_callback(int code, Datum arg);
-static void pg_stop_backup_callback(int code, Datum arg);
+static void pg_backup_start_callback(int code, Datum arg);
static int get_sync_bit(int method);
@@ -5328,7 +5301,7 @@ StartupXLOG(void)
* Ran off end of WAL before reaching end-of-backup WAL record, or
* minRecoveryPoint. That's usually a bad sign, indicating that you
* tried to recover from an online backup but never called
- * pg_stop_backup(), or you didn't archive all the WAL up to that
+ * pg_backup_stop(), or you didn't archive all the WAL up to that
* point. However, this also happens in crash recovery, if the system
* crashes while an online backup is in progress. We must not treat
* that as an error, or the database will refuse to start up.
@@ -5342,7 +5315,7 @@ StartupXLOG(void)
else if (!XLogRecPtrIsInvalid(ControlFile->backupStartPoint))
ereport(FATAL,
(errmsg("WAL ends before end of online backup"),
- errhint("Online backup started with pg_start_backup() must be ended with pg_stop_backup(), and all WAL up to that point must be available at recovery.")));
+ errhint("Online backup started with pg_backup_start() must be ended with pg_backup_stop(), and all WAL up to that point must be available at recovery.")));
else
ereport(FATAL,
(errmsg("WAL ends before consistent recovery point")));
@@ -7036,7 +7009,7 @@ CreateRestartPoint(int flags)
* Ensure minRecoveryPoint is past the checkpoint record. Normally,
* this will have happened already while writing out dirty buffers,
* but not necessarily - e.g. because no buffers were dirtied. We do
- * this because a non-exclusive base backup uses minRecoveryPoint to
+ * this because a backup performed in recovery uses minRecoveryPoint to
* determine which WAL files must be included in the backup, and the
* file (or files) containing the checkpoint record must be included,
* at a minimum. Note that for an ordinary restart of recovery there's
@@ -7840,7 +7813,7 @@ xlog_redo(XLogReaderState *record)
/*
* Update the LSN of the last replayed XLOG_FPW_CHANGE record so that
- * do_pg_start_backup() and do_pg_stop_backup() can check whether
+ * do_pg_backup_start() and do_pg_backup_stop() can check whether
* full_page_writes has been disabled during online backup.
*/
if (!fpw)
@@ -8039,29 +8012,14 @@ issue_xlog_fsync(int fd, XLogSegNo segno, TimeLineID tli)
}
/*
- * do_pg_start_backup
- *
- * Utility function called at the start of an online backup. It creates the
- * necessary starting checkpoint and constructs the backup label file.
- *
- * There are two kind of backups: exclusive and non-exclusive. An exclusive
- * backup is started with pg_start_backup(), and there can be only one active
- * at a time. The backup and tablespace map files of an exclusive backup are
- * written to $PGDATA/backup_label and $PGDATA/tablespace_map, and they are
- * removed by pg_stop_backup().
- *
- * A non-exclusive backup is used for the streaming base backups (see
- * src/backend/replication/basebackup.c). The difference to exclusive backups
- * is that the backup label and tablespace map files are not written to disk.
- * Instead, their would-be contents are returned in *labelfile and *tblspcmapfile,
- * and the caller is responsible for including them in the backup archive as
- * 'backup_label' and 'tablespace_map'. There can be many non-exclusive backups
- * active at the same time, and they don't conflict with an exclusive backup
- * either.
- *
- * labelfile and tblspcmapfile must be passed as NULL when starting an
- * exclusive backup, and as initially-empty StringInfos for a non-exclusive
- * backup.
+ * do_pg_backup_start is the workhorse of the user-visible pg_backup_start()
+ * function. It creates the necessary starting checkpoint and constructs the
+ * backup label and tablespace map.
+ *
+ * The backup label and tablespace map contents are returned in *labelfile and
+ * *tblspcmapfile, and the caller is responsible for including them in the
+ * backup archive as 'backup_label' and 'tablespace_map'. There can be many
+ * backups active at the same time.
*
* If "tablespaces" isn't NULL, it receives a list of tablespaceinfo structs
* describing the cluster's tablespaces.
@@ -8073,18 +8031,17 @@ issue_xlog_fsync(int fd, XLogSegNo segno, TimeLineID tli)
* Returns the minimum WAL location that must be present to restore from this
* backup, and the corresponding timeline ID in *starttli_p.
*
- * Every successfully started non-exclusive backup must be stopped by calling
- * do_pg_stop_backup() or do_pg_abort_backup().
+ * Every successfully started backup must be stopped by calling
+ * do_pg_backup_stop() or do_pg_abort_backup().
*
* It is the responsibility of the caller of this function to verify the
* permissions of the calling user!
*/
XLogRecPtr
-do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
+do_pg_backup_start(const char *backupidstr, bool fast, TimeLineID *starttli_p,
StringInfo labelfile, List **tablespaces,
StringInfo tblspcmapfile)
{
- bool exclusive = (labelfile == NULL);
bool backup_started_in_recovery = false;
XLogRecPtr checkpointloc;
XLogRecPtr startpoint;
@@ -8093,20 +8050,9 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
char strfbuf[128];
char xlogfilename[MAXFNAMELEN];
XLogSegNo _logSegNo;
- struct stat stat_buf;
- FILE *fp;
backup_started_in_recovery = RecoveryInProgress();
- /*
- * Currently only non-exclusive backup can be taken during recovery.
- */
- if (backup_started_in_recovery && exclusive)
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("recovery is in progress"),
- errhint("WAL control functions cannot be executed during recovery.")));
-
/*
* During recovery, we don't need to check WAL level. Because, if WAL
* level is not sufficient, it's impossible to get here during recovery.
@@ -8145,30 +8091,12 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
* XLogInsertRecord().
*/
WALInsertLockAcquireExclusive();
- if (exclusive)
- {
- /*
- * At first, mark that we're now starting an exclusive backup, to
- * ensure that there are no other sessions currently running
- * pg_start_backup() or pg_stop_backup().
- */
- if (XLogCtl->Insert.exclusiveBackupState != EXCLUSIVE_BACKUP_NONE)
- {
- WALInsertLockRelease();
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("a backup is already in progress"),
- errhint("Run pg_stop_backup() and try again.")));
- }
- XLogCtl->Insert.exclusiveBackupState = EXCLUSIVE_BACKUP_STARTING;
- }
- else
- XLogCtl->Insert.nonExclusiveBackups++;
+ XLogCtl->Insert.runningBackups++;
XLogCtl->Insert.forcePageWrites = true;
WALInsertLockRelease();
/* Ensure we release forcePageWrites if fail below */
- PG_ENSURE_ERROR_CLEANUP(pg_start_backup_callback, (Datum) BoolGetDatum(exclusive));
+ PG_ENSURE_ERROR_CLEANUP(pg_backup_start_callback, (Datum) 0);
{
bool gotUniqueStartpoint = false;
DIR *tblspcdir;
@@ -8180,7 +8108,7 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
* Force an XLOG file switch before the checkpoint, to ensure that the
* WAL segment the checkpoint is written to doesn't contain pages with
* old timeline IDs. That would otherwise happen if you called
- * pg_start_backup() right after restoring from a PITR archive: the
+ * pg_backup_start() right after restoring from a PITR archive: the
* first WAL segment containing the startup checkpoint has pages in
* the beginning with the old timeline ID. That can cause trouble at
* recovery: we won't have a history file covering the old timeline if
@@ -8215,7 +8143,7 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
* means that two successive backup runs can have same checkpoint
* positions.
*
- * Since the fact that we are executing do_pg_start_backup()
+ * Since the fact that we are executing do_pg_backup_start()
* during recovery means that checkpointer is running, we can use
* RequestCheckpoint() to establish a restartpoint.
*
@@ -8416,122 +8344,19 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
LSN_FORMAT_ARGS(startpoint), xlogfilename);
appendStringInfo(labelfile, "CHECKPOINT LOCATION: %X/%X\n",
LSN_FORMAT_ARGS(checkpointloc));
- appendStringInfo(labelfile, "BACKUP METHOD: %s\n",
- exclusive ? "pg_start_backup" : "streamed");
+ appendStringInfo(labelfile, "BACKUP METHOD: streamed\n");
appendStringInfo(labelfile, "BACKUP FROM: %s\n",
backup_started_in_recovery ? "standby" : "primary");
appendStringInfo(labelfile, "START TIME: %s\n", strfbuf);
appendStringInfo(labelfile, "LABEL: %s\n", backupidstr);
appendStringInfo(labelfile, "START TIMELINE: %u\n", starttli);
-
- /*
- * Okay, write the file, or return its contents to caller.
- */
- if (exclusive)
- {
- /*
- * Check for existing backup label --- implies a backup is already
- * running. (XXX given that we checked exclusiveBackupState
- * above, maybe it would be OK to just unlink any such label
- * file?)
- */
- if (stat(BACKUP_LABEL_FILE, &stat_buf) != 0)
- {
- if (errno != ENOENT)
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not stat file \"%s\": %m",
- BACKUP_LABEL_FILE)));
- }
- else
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("a backup is already in progress"),
- errhint("If you're sure there is no backup in progress, remove file \"%s\" and try again.",
- BACKUP_LABEL_FILE)));
-
- fp = AllocateFile(BACKUP_LABEL_FILE, "w");
-
- if (!fp)
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not create file \"%s\": %m",
- BACKUP_LABEL_FILE)));
- if (fwrite(labelfile->data, labelfile->len, 1, fp) != 1 ||
- fflush(fp) != 0 ||
- pg_fsync(fileno(fp)) != 0 ||
- ferror(fp) ||
- FreeFile(fp))
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not write file \"%s\": %m",
- BACKUP_LABEL_FILE)));
- /* Allocated locally for exclusive backups, so free separately */
- pfree(labelfile->data);
- pfree(labelfile);
-
- /* Write backup tablespace_map file. */
- if (tblspcmapfile->len > 0)
- {
- if (stat(TABLESPACE_MAP, &stat_buf) != 0)
- {
- if (errno != ENOENT)
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not stat file \"%s\": %m",
- TABLESPACE_MAP)));
- }
- else
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("a backup is already in progress"),
- errhint("If you're sure there is no backup in progress, remove file \"%s\" and try again.",
- TABLESPACE_MAP)));
-
- fp = AllocateFile(TABLESPACE_MAP, "w");
-
- if (!fp)
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not create file \"%s\": %m",
- TABLESPACE_MAP)));
- if (fwrite(tblspcmapfile->data, tblspcmapfile->len, 1, fp) != 1 ||
- fflush(fp) != 0 ||
- pg_fsync(fileno(fp)) != 0 ||
- ferror(fp) ||
- FreeFile(fp))
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not write file \"%s\": %m",
- TABLESPACE_MAP)));
- }
-
- /* Allocated locally for exclusive backups, so free separately */
- pfree(tblspcmapfile->data);
- pfree(tblspcmapfile);
- }
}
- PG_END_ENSURE_ERROR_CLEANUP(pg_start_backup_callback, (Datum) BoolGetDatum(exclusive));
+ PG_END_ENSURE_ERROR_CLEANUP(pg_backup_start_callback, (Datum) 0);
/*
- * Mark that start phase has correctly finished for an exclusive backup.
- * Session-level locks are updated as well to reflect that state.
- *
- * Note that CHECK_FOR_INTERRUPTS() must not occur while updating backup
- * counters and session-level lock. Otherwise they can be updated
- * inconsistently, and which might cause do_pg_abort_backup() to fail.
+ * Mark that the start phase has correctly finished for the backup.
*/
- if (exclusive)
- {
- WALInsertLockAcquireExclusive();
- XLogCtl->Insert.exclusiveBackupState = EXCLUSIVE_BACKUP_IN_PROGRESS;
-
- /* Set session-level lock */
- sessionBackupState = SESSION_BACKUP_EXCLUSIVE;
- WALInsertLockRelease();
- }
- else
- sessionBackupState = SESSION_BACKUP_NON_EXCLUSIVE;
+ sessionBackupState = SESSION_BACKUP_RUNNING;
/*
* We're done. As a convenience, return the starting WAL location.
@@ -8541,47 +8366,19 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
return startpoint;
}
-/* Error cleanup callback for pg_start_backup */
+/* Error cleanup callback for pg_backup_start */
static void
-pg_start_backup_callback(int code, Datum arg)
+pg_backup_start_callback(int code, Datum arg)
{
- bool exclusive = DatumGetBool(arg);
-
/* Update backup counters and forcePageWrites on failure */
WALInsertLockAcquireExclusive();
- if (exclusive)
- {
- Assert(XLogCtl->Insert.exclusiveBackupState == EXCLUSIVE_BACKUP_STARTING);
- XLogCtl->Insert.exclusiveBackupState = EXCLUSIVE_BACKUP_NONE;
- }
- else
- {
- Assert(XLogCtl->Insert.nonExclusiveBackups > 0);
- XLogCtl->Insert.nonExclusiveBackups--;
- }
- if (XLogCtl->Insert.exclusiveBackupState == EXCLUSIVE_BACKUP_NONE &&
- XLogCtl->Insert.nonExclusiveBackups == 0)
- {
- XLogCtl->Insert.forcePageWrites = false;
- }
- WALInsertLockRelease();
-}
+ Assert(XLogCtl->Insert.runningBackups > 0);
+ XLogCtl->Insert.runningBackups--;
-/*
- * Error cleanup callback for pg_stop_backup
- */
-static void
-pg_stop_backup_callback(int code, Datum arg)
-{
- bool exclusive = DatumGetBool(arg);
-
- /* Update backup status on failure */
- WALInsertLockAcquireExclusive();
- if (exclusive)
+ if (XLogCtl->Insert.runningBackups == 0)
{
- Assert(XLogCtl->Insert.exclusiveBackupState == EXCLUSIVE_BACKUP_STOPPING);
- XLogCtl->Insert.exclusiveBackupState = EXCLUSIVE_BACKUP_IN_PROGRESS;
+ XLogCtl->Insert.forcePageWrites = false;
}
WALInsertLockRelease();
}
@@ -8596,14 +8393,11 @@ get_backup_status(void)
}
/*
- * do_pg_stop_backup
+ * do_pg_backup_stop
*
* Utility function called at the end of an online backup. It cleans up the
* backup state and can optionally wait for WAL segments to be archived.
*
- * If labelfile is NULL, this stops an exclusive backup. Otherwise this stops
- * the non-exclusive backup specified by 'labelfile'.
- *
* Returns the last WAL location that must be present to restore from this
* backup, and the corresponding timeline ID in *stoptli_p.
*
@@ -8611,9 +8405,8 @@ get_backup_status(void)
* permissions of the calling user!
*/
XLogRecPtr
-do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
+do_pg_backup_stop(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
{
- bool exclusive = (labelfile == NULL);
bool backup_started_in_recovery = false;
XLogRecPtr startpoint;
XLogRecPtr stoppoint;
@@ -8627,7 +8420,6 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
char histfilename[MAXFNAMELEN];
char backupfrom[20];
XLogSegNo _logSegNo;
- FILE *lfp;
FILE *fp;
char ch;
int seconds_before_warning;
@@ -8640,15 +8432,6 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
backup_started_in_recovery = RecoveryInProgress();
- /*
- * Currently only non-exclusive backup can be taken during recovery.
- */
- if (backup_started_in_recovery && exclusive)
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("recovery is in progress"),
- errhint("WAL control functions cannot be executed during recovery.")));
-
/*
* During recovery, we don't need to check WAL level. Because, if WAL
* level is not sufficient, it's impossible to get here during recovery.
@@ -8659,106 +8442,23 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
errmsg("WAL level not sufficient for making an online backup"),
errhint("wal_level must be set to \"replica\" or \"logical\" at server start.")));
- if (exclusive)
- {
- /*
- * At first, mark that we're now stopping an exclusive backup, to
- * ensure that there are no other sessions currently running
- * pg_start_backup() or pg_stop_backup().
- */
- WALInsertLockAcquireExclusive();
- if (XLogCtl->Insert.exclusiveBackupState != EXCLUSIVE_BACKUP_IN_PROGRESS)
- {
- WALInsertLockRelease();
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("exclusive backup not in progress")));
- }
- XLogCtl->Insert.exclusiveBackupState = EXCLUSIVE_BACKUP_STOPPING;
- WALInsertLockRelease();
-
- /*
- * Remove backup_label. In case of failure, the state for an exclusive
- * backup is switched back to in-progress.
- */
- PG_ENSURE_ERROR_CLEANUP(pg_stop_backup_callback, (Datum) BoolGetDatum(exclusive));
- {
- /*
- * Read the existing label file into memory.
- */
- struct stat statbuf;
- int r;
-
- if (stat(BACKUP_LABEL_FILE, &statbuf))
- {
- /* should not happen per the upper checks */
- if (errno != ENOENT)
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not stat file \"%s\": %m",
- BACKUP_LABEL_FILE)));
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("a backup is not in progress")));
- }
-
- lfp = AllocateFile(BACKUP_LABEL_FILE, "r");
- if (!lfp)
- {
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not read file \"%s\": %m",
- BACKUP_LABEL_FILE)));
- }
- labelfile = palloc(statbuf.st_size + 1);
- r = fread(labelfile, statbuf.st_size, 1, lfp);
- labelfile[statbuf.st_size] = '\0';
-
- /*
- * Close and remove the backup label file
- */
- if (r != 1 || ferror(lfp) || FreeFile(lfp))
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not read file \"%s\": %m",
- BACKUP_LABEL_FILE)));
- durable_unlink(BACKUP_LABEL_FILE, ERROR);
-
- /*
- * Remove tablespace_map file if present, it is created only if
- * there are tablespaces.
- */
- durable_unlink(TABLESPACE_MAP, DEBUG1);
- }
- PG_END_ENSURE_ERROR_CLEANUP(pg_stop_backup_callback, (Datum) BoolGetDatum(exclusive));
- }
-
/*
- * OK to update backup counters, forcePageWrites and session-level lock.
+ * OK to update backup counters, forcePageWrites, and session-level lock.
*
* Note that CHECK_FOR_INTERRUPTS() must not occur while updating them.
* Otherwise they can be updated inconsistently, and which might cause
* do_pg_abort_backup() to fail.
*/
WALInsertLockAcquireExclusive();
- if (exclusive)
- {
- XLogCtl->Insert.exclusiveBackupState = EXCLUSIVE_BACKUP_NONE;
- }
- else
- {
- /*
- * The user-visible pg_start/stop_backup() functions that operate on
- * exclusive backups can be called at any time, but for non-exclusive
- * backups, it is expected that each do_pg_start_backup() call is
- * matched by exactly one do_pg_stop_backup() call.
- */
- Assert(XLogCtl->Insert.nonExclusiveBackups > 0);
- XLogCtl->Insert.nonExclusiveBackups--;
- }
- if (XLogCtl->Insert.exclusiveBackupState == EXCLUSIVE_BACKUP_NONE &&
- XLogCtl->Insert.nonExclusiveBackups == 0)
+ /*
+ * It is expected that each do_pg_backup_start() call is matched by exactly
+ * one do_pg_backup_stop() call.
+ */
+ Assert(XLogCtl->Insert.runningBackups > 0);
+ XLogCtl->Insert.runningBackups--;
+
+ if (XLogCtl->Insert.runningBackups == 0)
{
XLogCtl->Insert.forcePageWrites = false;
}
@@ -9016,17 +8716,13 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
/*
* do_pg_abort_backup: abort a running backup
*
- * This does just the most basic steps of do_pg_stop_backup(), by taking the
+ * This does just the most basic steps of do_pg_backup_stop(), by taking the
* system out of backup mode, thus making it a lot more safe to call from
* an error handler.
*
* The caller can pass 'arg' as 'true' or 'false' to control whether a warning
* is emitted.
*
- * NB: This is only for aborting a non-exclusive backup that doesn't write
- * backup_label. A backup started with pg_start_backup() needs to be finished
- * with pg_stop_backup().
- *
* NB: This gets used as a before_shmem_exit handler, hence the odd-looking
* signature.
*/
@@ -9036,18 +8732,16 @@ do_pg_abort_backup(int code, Datum arg)
bool emit_warning = DatumGetBool(arg);
/*
- * Quick exit if session is not keeping around a non-exclusive backup
- * already started.
+ * Quick exit if session does not have a running backup.
*/
- if (sessionBackupState != SESSION_BACKUP_NON_EXCLUSIVE)
+ if (sessionBackupState != SESSION_BACKUP_RUNNING)
return;
WALInsertLockAcquireExclusive();
- Assert(XLogCtl->Insert.nonExclusiveBackups > 0);
- XLogCtl->Insert.nonExclusiveBackups--;
+ Assert(XLogCtl->Insert.runningBackups > 0);
+ XLogCtl->Insert.runningBackups--;
- if (XLogCtl->Insert.exclusiveBackupState == EXCLUSIVE_BACKUP_NONE &&
- XLogCtl->Insert.nonExclusiveBackups == 0)
+ if (XLogCtl->Insert.runningBackups == 0)
{
XLogCtl->Insert.forcePageWrites = false;
}
@@ -9055,7 +8749,7 @@ do_pg_abort_backup(int code, Datum arg)
if (emit_warning)
ereport(WARNING,
- (errmsg("aborting backup due to backend exiting before pg_stop_backup was called")));
+ (errmsg("aborting backup due to backend exiting before pg_backup_stop was called")));
}
/*
@@ -9115,87 +8809,6 @@ GetOldestRestartPoint(XLogRecPtr *oldrecptr, TimeLineID *oldtli)
LWLockRelease(ControlFileLock);
}
-/*
- * BackupInProgress: check if online backup mode is active
- *
- * This is done by checking for existence of the "backup_label" file.
- */
-bool
-BackupInProgress(void)
-{
- struct stat stat_buf;
-
- return (stat(BACKUP_LABEL_FILE, &stat_buf) == 0);
-}
-
-/*
- * CancelBackup: rename the "backup_label" and "tablespace_map"
- * files to cancel backup mode
- *
- * If the "backup_label" file exists, it will be renamed to "backup_label.old".
- * Similarly, if the "tablespace_map" file exists, it will be renamed to
- * "tablespace_map.old".
- *
- * Note that this will render an online backup in progress
- * useless. To correctly finish an online backup, pg_stop_backup must be
- * called.
- */
-void
-CancelBackup(void)
-{
- struct stat stat_buf;
-
- /* if the backup_label file is not there, return */
- if (stat(BACKUP_LABEL_FILE, &stat_buf) < 0)
- return;
-
- /* remove leftover file from previously canceled backup if it exists */
- unlink(BACKUP_LABEL_OLD);
-
- if (durable_rename(BACKUP_LABEL_FILE, BACKUP_LABEL_OLD, DEBUG1) != 0)
- {
- ereport(WARNING,
- (errcode_for_file_access(),
- errmsg("online backup mode was not canceled"),
- errdetail("File \"%s\" could not be renamed to \"%s\": %m.",
- BACKUP_LABEL_FILE, BACKUP_LABEL_OLD)));
- return;
- }
-
- /* if the tablespace_map file is not there, return */
- if (stat(TABLESPACE_MAP, &stat_buf) < 0)
- {
- ereport(LOG,
- (errmsg("online backup mode canceled"),
- errdetail("File \"%s\" was renamed to \"%s\".",
- BACKUP_LABEL_FILE, BACKUP_LABEL_OLD)));
- return;
- }
-
- /* remove leftover file from previously canceled backup if it exists */
- unlink(TABLESPACE_MAP_OLD);
-
- if (durable_rename(TABLESPACE_MAP, TABLESPACE_MAP_OLD, DEBUG1) == 0)
- {
- ereport(LOG,
- (errmsg("online backup mode canceled"),
- errdetail("Files \"%s\" and \"%s\" were renamed to "
- "\"%s\" and \"%s\", respectively.",
- BACKUP_LABEL_FILE, TABLESPACE_MAP,
- BACKUP_LABEL_OLD, TABLESPACE_MAP_OLD)));
- }
- else
- {
- ereport(WARNING,
- (errcode_for_file_access(),
- errmsg("online backup mode canceled"),
- errdetail("File \"%s\" was renamed to \"%s\", but "
- "file \"%s\" could not be renamed to \"%s\": %m.",
- BACKUP_LABEL_FILE, BACKUP_LABEL_OLD,
- TABLESPACE_MAP, TABLESPACE_MAP_OLD)));
- }
-}
-
/* Thin wrapper around ShutdownWalRcv(). */
void
XLogShutdownWalRcv(void)
diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c
index 2752be63c1..b61ae6c0b4 100644
--- a/src/backend/access/transam/xlogfuncs.c
+++ b/src/backend/access/transam/xlogfuncs.c
@@ -39,13 +39,13 @@
#include "utils/tuplestore.h"
/*
- * Store label file and tablespace map during non-exclusive backups.
+ * Store label file and tablespace map during backups.
*/
static StringInfo label_file;
static StringInfo tblspc_map_file;
/*
- * pg_start_backup: set up for taking an on-line backup dump
+ * pg_backup_start: set up for taking an on-line backup dump
*
* Essentially what this does is to create a backup label file in $PGDATA,
* where it will be archived as part of the backup dump. The label file
@@ -57,105 +57,44 @@ static StringInfo tblspc_map_file;
* GRANT system.
*/
Datum
-pg_start_backup(PG_FUNCTION_ARGS)
+pg_backup_start(PG_FUNCTION_ARGS)
{
text *backupid = PG_GETARG_TEXT_PP(0);
bool fast = PG_GETARG_BOOL(1);
- bool exclusive = PG_GETARG_BOOL(2);
char *backupidstr;
XLogRecPtr startpoint;
SessionBackupState status = get_backup_status();
+ MemoryContext oldcontext;
backupidstr = text_to_cstring(backupid);
- if (status == SESSION_BACKUP_NON_EXCLUSIVE)
+ if (status == SESSION_BACKUP_RUNNING)
ereport(ERROR,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("a backup is already in progress in this session")));
- if (exclusive)
- {
- startpoint = do_pg_start_backup(backupidstr, fast, NULL, NULL,
- NULL, NULL);
- }
- else
- {
- MemoryContext oldcontext;
-
- /*
- * Label file and tablespace map file need to be long-lived, since
- * they are read in pg_stop_backup.
- */
- oldcontext = MemoryContextSwitchTo(TopMemoryContext);
- label_file = makeStringInfo();
- tblspc_map_file = makeStringInfo();
- MemoryContextSwitchTo(oldcontext);
+ /*
+ * Label file and tablespace map file need to be long-lived, since
+ * they are read in pg_backup_stop.
+ */
+ oldcontext = MemoryContextSwitchTo(TopMemoryContext);
+ label_file = makeStringInfo();
+ tblspc_map_file = makeStringInfo();
+ MemoryContextSwitchTo(oldcontext);
- register_persistent_abort_backup_handler();
+ register_persistent_abort_backup_handler();
- startpoint = do_pg_start_backup(backupidstr, fast, NULL, label_file,
- NULL, tblspc_map_file);
- }
+ startpoint = do_pg_backup_start(backupidstr, fast, NULL, label_file,
+ NULL, tblspc_map_file);
PG_RETURN_LSN(startpoint);
}
-/*
- * pg_stop_backup: finish taking an on-line backup dump
- *
- * We write an end-of-backup WAL record, and remove the backup label file
- * created by pg_start_backup, creating a backup history file in pg_wal
- * instead (whence it will immediately be archived). The backup history file
- * contains the same info found in the label file, plus the backup-end time
- * and WAL location. Before 9.0, the backup-end time was read from the backup
- * history file at the beginning of archive recovery, but we now use the WAL
- * record for that and the file is for informational and debug purposes only.
- *
- * Note: different from CancelBackup which just cancels online backup mode.
- *
- * Note: this version is only called to stop an exclusive backup. The function
- * pg_stop_backup_v2 (overloaded as pg_stop_backup in SQL) is called to
- * stop non-exclusive backups.
- *
- * Permission checking for this function is managed through the normal
- * GRANT system.
- */
-Datum
-pg_stop_backup(PG_FUNCTION_ARGS)
-{
- XLogRecPtr stoppoint;
- SessionBackupState status = get_backup_status();
-
- if (status == SESSION_BACKUP_NON_EXCLUSIVE)
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("non-exclusive backup in progress"),
- errhint("Did you mean to use pg_stop_backup('f')?")));
-
- /*
- * Exclusive backups were typically started in a different connection, so
- * don't try to verify that status of backup is set to
- * SESSION_BACKUP_EXCLUSIVE in this function. Actual verification that an
- * exclusive backup is in fact running is handled inside
- * do_pg_stop_backup.
- */
- stoppoint = do_pg_stop_backup(NULL, true, NULL);
-
- PG_RETURN_LSN(stoppoint);
-}
-
/*
- * pg_stop_backup_v2: finish taking exclusive or nonexclusive on-line backup.
- *
- * Works the same as pg_stop_backup, except for non-exclusive backups it returns
- * the backup label and tablespace map files as text fields in as part of the
- * resultset.
+ * pg_backup_stop: finish taking an on-line backup.
*
- * The first parameter (variable 'exclusive') allows the user to tell us if
- * this is an exclusive or a non-exclusive backup.
- *
- * The second parameter (variable 'waitforarchive'), which is optional,
+ * The first parameter (variable 'waitforarchive'), which is optional,
* allows the user to choose if they want to wait for the WAL to be archived
* or if we should just return as soon as the WAL record is written.
*
@@ -163,15 +102,14 @@ pg_stop_backup(PG_FUNCTION_ARGS)
* GRANT system.
*/
Datum
-pg_stop_backup_v2(PG_FUNCTION_ARGS)
+pg_backup_stop(PG_FUNCTION_ARGS)
{
#define PG_STOP_BACKUP_V2_COLS 3
TupleDesc tupdesc;
Datum values[PG_STOP_BACKUP_V2_COLS];
bool nulls[PG_STOP_BACKUP_V2_COLS];
- bool exclusive = PG_GETARG_BOOL(0);
- bool waitforarchive = PG_GETARG_BOOL(1);
+ bool waitforarchive = PG_GETARG_BOOL(0);
XLogRecPtr stoppoint;
SessionBackupState status = get_backup_status();
@@ -182,51 +120,29 @@ pg_stop_backup_v2(PG_FUNCTION_ARGS)
MemSet(values, 0, sizeof(values));
MemSet(nulls, 0, sizeof(nulls));
- if (exclusive)
- {
- if (status == SESSION_BACKUP_NON_EXCLUSIVE)
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("non-exclusive backup in progress"),
- errhint("Did you mean to use pg_stop_backup('f')?")));
-
- /*
- * Stop the exclusive backup, and since we're in an exclusive backup
- * return NULL for both backup_label and tablespace_map.
- */
- stoppoint = do_pg_stop_backup(NULL, waitforarchive, NULL);
-
- nulls[1] = true;
- nulls[2] = true;
- }
- else
- {
- if (status != SESSION_BACKUP_NON_EXCLUSIVE)
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("non-exclusive backup is not in progress"),
- errhint("Did you mean to use pg_stop_backup('t')?")));
+ if (status != SESSION_BACKUP_RUNNING)
+ ereport(ERROR,
+ (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ errmsg("backup is not in progress"),
+ errhint("Did you call pg_backup_start()?")));
- /*
- * Stop the non-exclusive backup. Return a copy of the backup label
- * and tablespace map so they can be written to disk by the caller.
- */
- stoppoint = do_pg_stop_backup(label_file->data, waitforarchive, NULL);
-
- values[1] = CStringGetTextDatum(label_file->data);
- values[2] = CStringGetTextDatum(tblspc_map_file->data);
-
- /* Free structures allocated in TopMemoryContext */
- pfree(label_file->data);
- pfree(label_file);
- label_file = NULL;
- pfree(tblspc_map_file->data);
- pfree(tblspc_map_file);
- tblspc_map_file = NULL;
- }
+ /*
+ * Stop the backup. Return a copy of the backup label and tablespace map so
+ * they can be written to disk by the caller.
+ */
+ stoppoint = do_pg_backup_stop(label_file->data, waitforarchive, NULL);
- /* Stoppoint is included on both exclusive and nonexclusive backups */
values[0] = LSNGetDatum(stoppoint);
+ values[1] = CStringGetTextDatum(label_file->data);
+ values[2] = CStringGetTextDatum(tblspc_map_file->data);
+
+ /* Free structures allocated in TopMemoryContext */
+ pfree(label_file->data);
+ pfree(label_file);
+ label_file = NULL;
+ pfree(tblspc_map_file->data);
+ pfree(tblspc_map_file);
+ tblspc_map_file = NULL;
/* Returns the record as Datum */
PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
@@ -298,7 +214,7 @@ pg_create_restore_point(PG_FUNCTION_ARGS)
}
/*
- * Report the current WAL write location (same format as pg_start_backup etc)
+ * Report the current WAL write location (same format as pg_backup_start etc)
*
* This is useful for determining how much of WAL is visible to an external
* archiving process. Note that the data before this point is written out
@@ -321,7 +237,7 @@ pg_current_wal_lsn(PG_FUNCTION_ARGS)
}
/*
- * Report the current WAL insert location (same format as pg_start_backup etc)
+ * Report the current WAL insert location (same format as pg_backup_start etc)
*
* This function is mostly for debugging purposes.
*/
@@ -342,7 +258,7 @@ pg_current_wal_insert_lsn(PG_FUNCTION_ARGS)
}
/*
- * Report the current WAL flush location (same format as pg_start_backup etc)
+ * Report the current WAL flush location (same format as pg_backup_start etc)
*
* This function is mostly for debugging purposes.
*/
@@ -363,7 +279,7 @@ pg_current_wal_flush_lsn(PG_FUNCTION_ARGS)
}
/*
- * Report the last WAL receive location (same format as pg_start_backup etc)
+ * Report the last WAL receive location (same format as pg_backup_start etc)
*
* This is useful for determining how much of WAL is guaranteed to be received
* and synced to disk by walreceiver.
@@ -382,7 +298,7 @@ pg_last_wal_receive_lsn(PG_FUNCTION_ARGS)
}
/*
- * Report the last WAL replay location (same format as pg_start_backup etc)
+ * Report the last WAL replay location (same format as pg_backup_start etc)
*
* This is useful for determining how much of WAL is visible to read-only
* connections during recovery.
@@ -402,7 +318,7 @@ pg_last_wal_replay_lsn(PG_FUNCTION_ARGS)
/*
* Compute an xlog file name and decimal byte offset given a WAL location,
- * such as is returned by pg_stop_backup() or pg_switch_wal().
+ * such as is returned by pg_backup_stop() or pg_switch_wal().
*
* Note that a location exactly at a segment boundary is taken to be in
* the previous segment. This is usually the right thing, since the
@@ -470,7 +386,7 @@ pg_walfile_name_offset(PG_FUNCTION_ARGS)
/*
* Compute an xlog file name given a WAL location,
- * such as is returned by pg_stop_backup() or pg_switch_wal().
+ * such as is returned by pg_backup_stop() or pg_switch_wal().
*/
Datum
pg_walfile_name(PG_FUNCTION_ARGS)
@@ -645,81 +561,6 @@ pg_wal_lsn_diff(PG_FUNCTION_ARGS)
PG_RETURN_NUMERIC(result);
}
-/*
- * Returns bool with current on-line backup mode, a global state.
- */
-Datum
-pg_is_in_backup(PG_FUNCTION_ARGS)
-{
- PG_RETURN_BOOL(BackupInProgress());
-}
-
-/*
- * Returns start time of an online exclusive backup.
- *
- * When there's no exclusive backup in progress, the function
- * returns NULL.
- */
-Datum
-pg_backup_start_time(PG_FUNCTION_ARGS)
-{
- Datum xtime;
- FILE *lfp;
- char fline[MAXPGPATH];
- char backup_start_time[30];
-
- /*
- * See if label file is present
- */
- lfp = AllocateFile(BACKUP_LABEL_FILE, "r");
- if (lfp == NULL)
- {
- if (errno != ENOENT)
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not read file \"%s\": %m",
- BACKUP_LABEL_FILE)));
- PG_RETURN_NULL();
- }
-
- /*
- * Parse the file to find the START TIME line.
- */
- backup_start_time[0] = '\0';
- while (fgets(fline, sizeof(fline), lfp) != NULL)
- {
- if (sscanf(fline, "START TIME: %25[^\n]\n", backup_start_time) == 1)
- break;
- }
-
- /* Check for a read error. */
- if (ferror(lfp))
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not read file \"%s\": %m", BACKUP_LABEL_FILE)));
-
- /* Close the backup label file. */
- if (FreeFile(lfp))
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not close file \"%s\": %m", BACKUP_LABEL_FILE)));
-
- if (strlen(backup_start_time) == 0)
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("invalid data in file \"%s\"", BACKUP_LABEL_FILE)));
-
- /*
- * Convert the time string read from file to TimestampTz form.
- */
- xtime = DirectFunctionCall3(timestamptz_in,
- CStringGetDatum(backup_start_time),
- ObjectIdGetDatum(InvalidOid),
- Int32GetDatum(-1));
-
- PG_RETURN_DATUM(xtime);
-}
-
/*
* Promotes a standby server.
*
diff --git a/src/backend/access/transam/xlogrecovery.c b/src/backend/access/transam/xlogrecovery.c
index 8d2395dae2..d965e584ba 100644
--- a/src/backend/access/transam/xlogrecovery.c
+++ b/src/backend/access/transam/xlogrecovery.c
@@ -1970,7 +1970,7 @@ xlogrecovery_redo(XLogReaderState *record, TimeLineID replayTLI)
{
/*
* We have reached the end of base backup, the point where
- * pg_stop_backup() was done. The data on disk is now consistent
+ * pg_backup_stop() was done. The data on disk is now consistent
* (assuming we have also reached minRecoveryPoint). Set
* backupEndPoint to the current LSN, so that the next call to
* CheckRecoveryConsistency() will notice it and do the
diff --git a/src/backend/catalog/system_functions.sql b/src/backend/catalog/system_functions.sql
index 81bac6f581..6ae4388d3f 100644
--- a/src/backend/catalog/system_functions.sql
+++ b/src/backend/catalog/system_functions.sql
@@ -377,14 +377,14 @@ BEGIN ATOMIC
END;
CREATE OR REPLACE FUNCTION
- pg_start_backup(label text, fast boolean DEFAULT false, exclusive boolean DEFAULT true)
- RETURNS pg_lsn STRICT VOLATILE LANGUAGE internal AS 'pg_start_backup'
+ pg_backup_start(label text, fast boolean DEFAULT false)
+ RETURNS pg_lsn STRICT VOLATILE LANGUAGE internal AS 'pg_backup_start'
PARALLEL RESTRICTED;
-CREATE OR REPLACE FUNCTION pg_stop_backup (
- exclusive boolean, wait_for_archive boolean DEFAULT true,
- OUT lsn pg_lsn, OUT labelfile text, OUT spcmapfile text)
- RETURNS record STRICT VOLATILE LANGUAGE internal as 'pg_stop_backup_v2'
+CREATE OR REPLACE FUNCTION pg_backup_stop (
+ wait_for_archive boolean DEFAULT true, OUT lsn pg_lsn,
+ OUT labelfile text, OUT spcmapfile text)
+ RETURNS record STRICT VOLATILE LANGUAGE internal as 'pg_backup_stop'
PARALLEL RESTRICTED;
CREATE OR REPLACE FUNCTION
@@ -603,11 +603,9 @@ AS 'unicode_is_normalized';
-- available to superuser / cluster owner, if they choose.
--
-REVOKE EXECUTE ON FUNCTION pg_start_backup(text, boolean, boolean) FROM public;
+REVOKE EXECUTE ON FUNCTION pg_backup_start(text, boolean) FROM public;
-REVOKE EXECUTE ON FUNCTION pg_stop_backup() FROM public;
-
-REVOKE EXECUTE ON FUNCTION pg_stop_backup(boolean, boolean) FROM public;
+REVOKE EXECUTE ON FUNCTION pg_backup_stop(boolean) FROM public;
REVOKE EXECUTE ON FUNCTION pg_create_restore_point(text) FROM public;
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index 80bb269599..9f7034df11 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -345,14 +345,7 @@ static PMState pmState = PM_INIT;
* connsAllowed is a sub-state indicator showing the active restriction.
* It is of no interest unless pmState is PM_RUN or PM_HOT_STANDBY.
*/
-typedef enum
-{
- ALLOW_ALL_CONNS, /* normal not-shutting-down state */
- ALLOW_SUPERUSER_CONNS, /* only superusers can connect */
- ALLOW_NO_CONNS /* no new connections allowed, period */
-} ConnsAllowedState;
-
-static ConnsAllowedState connsAllowed = ALLOW_ALL_CONNS;
+static bool connsAllowed = true;
/* Start time of SIGKILL timeout during immediate shutdown or child crash */
/* Zero means timeout is not running */
@@ -2409,9 +2402,6 @@ retry1:
(errcode(ERRCODE_TOO_MANY_CONNECTIONS),
errmsg("sorry, too many clients already")));
break;
- case CAC_SUPERUSER:
- /* OK for now, will check in InitPostgres */
- break;
case CAC_OK:
break;
}
@@ -2546,19 +2536,10 @@ canAcceptConnections(int backend_type)
/*
* "Smart shutdown" restrictions are applied only to normal connections,
- * not to autovac workers or bgworkers. When only superusers can connect,
- * we return CAC_SUPERUSER to indicate that superuserness must be checked
- * later. Note that neither CAC_OK nor CAC_SUPERUSER can safely be
- * returned until we have checked for too many children.
+ * not to autovac workers or bgworkers.
*/
- if (connsAllowed != ALLOW_ALL_CONNS &&
- backend_type == BACKEND_TYPE_NORMAL)
- {
- if (connsAllowed == ALLOW_SUPERUSER_CONNS)
- result = CAC_SUPERUSER; /* allow superusers only */
- else
- return CAC_SHUTDOWN; /* shutdown is pending */
- }
+ if (!connsAllowed && backend_type == BACKEND_TYPE_NORMAL)
+ return CAC_SHUTDOWN; /* shutdown is pending */
/*
* Don't start too many children.
@@ -2877,17 +2858,12 @@ pmdie(SIGNAL_ARGS)
#endif
/*
- * If we reached normal running, we have to wait for any online
- * backup mode to end; otherwise go straight to waiting for client
- * backends to exit. (The difference is that in the former state,
- * we'll still let in new superuser clients, so that somebody can
- * end the online backup mode.) If already in PM_STOP_BACKENDS or
+ * If we reached normal running, we go straight to waiting for
+ * client backends to exit. If already in PM_STOP_BACKENDS or
* a later state, do not change it.
*/
- if (pmState == PM_RUN)
- connsAllowed = ALLOW_SUPERUSER_CONNS;
- else if (pmState == PM_HOT_STANDBY)
- connsAllowed = ALLOW_NO_CONNS;
+ if (pmState == PM_RUN || pmState == PM_HOT_STANDBY)
+ connsAllowed = false;
else if (pmState == PM_STARTUP || pmState == PM_RECOVERY)
{
/* There should be no clients, so proceed to stop children */
@@ -3099,7 +3075,7 @@ reaper(SIGNAL_ARGS)
AbortStartTime = 0;
ReachedNormalRunning = true;
pmState = PM_RUN;
- connsAllowed = ALLOW_ALL_CONNS;
+ connsAllowed = true;
/*
* Crank up the background tasks, if we didn't do that already
@@ -3842,21 +3818,11 @@ PostmasterStateMachine(void)
/* If we're doing a smart shutdown, try to advance that state. */
if (pmState == PM_RUN || pmState == PM_HOT_STANDBY)
{
- if (connsAllowed == ALLOW_SUPERUSER_CONNS)
+ if (!connsAllowed)
{
/*
- * ALLOW_SUPERUSER_CONNS state ends as soon as online backup mode
- * is not active.
- */
- if (!BackupInProgress())
- connsAllowed = ALLOW_NO_CONNS;
- }
-
- if (connsAllowed == ALLOW_NO_CONNS)
- {
- /*
- * ALLOW_NO_CONNS state ends when we have no normal client
- * backends running. Then we're ready to stop other children.
+ * This state ends when we have no normal client backends running.
+ * Then we're ready to stop other children.
*/
if (CountChildren(BACKEND_TYPE_NORMAL) == 0)
pmState = PM_STOP_BACKENDS;
@@ -4044,18 +4010,6 @@ PostmasterStateMachine(void)
}
else
{
- /*
- * Terminate exclusive backup mode to avoid recovery after a clean
- * fast shutdown. Since an exclusive backup can only be taken
- * during normal running (and not, for example, while running
- * under Hot Standby) it only makes sense to do this if we reached
- * normal running. If we're still in recovery, the backup file is
- * one we're recovering *from*, and we must keep it around so that
- * recovery restarts from the right place.
- */
- if (ReachedNormalRunning)
- CancelBackup();
-
/*
* Normal exit from the postmaster is here. We don't need to log
* anything here, since the UnlinkLockFiles proc_exit callback
@@ -4277,8 +4231,7 @@ BackendStartup(Port *port)
/* Pass down canAcceptConnections state */
port->canAcceptConnections = canAcceptConnections(BACKEND_TYPE_NORMAL);
- bn->dead_end = (port->canAcceptConnections != CAC_OK &&
- port->canAcceptConnections != CAC_SUPERUSER);
+ bn->dead_end = (port->canAcceptConnections != CAC_OK);
/*
* Unless it's a dead_end child, assign it a child slot number
@@ -5287,7 +5240,7 @@ sigusr1_handler(SIGNAL_ARGS)
#endif
pmState = PM_HOT_STANDBY;
- connsAllowed = ALLOW_ALL_CONNS;
+ connsAllowed = true;
/* Some workers may be scheduled to start now */
StartWorkerNeeded = true;
diff --git a/src/backend/replication/basebackup.c b/src/backend/replication/basebackup.c
index 6884cad2c0..815681ada7 100644
--- a/src/backend/replication/basebackup.c
+++ b/src/backend/replication/basebackup.c
@@ -184,10 +184,8 @@ static const struct exclude_list_item excludeFiles[] =
{RELCACHE_INIT_FILENAME, true},
/*
- * If there's a backup_label or tablespace_map file, it belongs to a
- * backup started by the user with pg_start_backup(). It is *not* correct
- * for this backup. Our backup_label/tablespace_map is injected into the
- * tar separately.
+ * backup_label and tablespace_map should not exist in in a running cluster
+ * capable of doing an online backup, but exclude them just in case.
*/
{BACKUP_LABEL_FILE, false},
{TABLESPACE_MAP, false},
@@ -264,16 +262,16 @@ perform_base_backup(basebackup_options *opt, bbsink *sink)
total_checksum_failures = 0;
basebackup_progress_wait_checkpoint();
- state.startptr = do_pg_start_backup(opt->label, opt->fastcheckpoint,
+ state.startptr = do_pg_backup_start(opt->label, opt->fastcheckpoint,
&state.starttli,
labelfile, &state.tablespaces,
tblspc_map_file);
/*
- * Once do_pg_start_backup has been called, ensure that any failure causes
+ * Once do_pg_backup_start has been called, ensure that any failure causes
* us to abort the backup so we don't "leak" a backup counter. For this
- * reason, *all* functionality between do_pg_start_backup() and the end of
- * do_pg_stop_backup() should be inside the error cleanup block!
+ * reason, *all* functionality between do_pg_backup_start() and the end of
+ * do_pg_backup_stop() should be inside the error cleanup block!
*/
PG_ENSURE_ERROR_CLEANUP(do_pg_abort_backup, BoolGetDatum(false));
@@ -394,7 +392,7 @@ perform_base_backup(basebackup_options *opt, bbsink *sink)
}
basebackup_progress_wait_wal_archive(&state);
- endptr = do_pg_stop_backup(labelfile->data, !opt->nowait, &endtli);
+ endptr = do_pg_backup_stop(labelfile->data, !opt->nowait, &endtli);
}
PG_END_ENSURE_ERROR_CLEANUP(do_pg_abort_backup, BoolGetDatum(false));
@@ -961,7 +959,7 @@ parse_basebackup_options(List *options, basebackup_options *opt)
/*
* SendBaseBackup() - send a complete base backup.
*
- * The function will put the system into backup mode like pg_start_backup()
+ * The function will put the system into backup mode like pg_backup_start()
* does, so that the backup is consistent even though we read directly from
* the filesystem, bypassing the buffer cache.
*/
@@ -1204,7 +1202,7 @@ sendDir(bbsink *sink, const char *path, int basepathlen, bool sizeonly,
* error in that case. The error handler further up will call
* do_pg_abort_backup() for us. Also check that if the backup was
* started while still in recovery, the server wasn't promoted.
- * do_pg_stop_backup() will check that too, but it's better to stop
+ * do_pg_backup_stop() will check that too, but it's better to stop
* the backup early than continue to the end and fail there.
*/
CHECK_FOR_INTERRUPTS();
diff --git a/src/backend/utils/init/postinit.c b/src/backend/utils/init/postinit.c
index 6452b42dbf..342169b195 100644
--- a/src/backend/utils/init/postinit.c
+++ b/src/backend/utils/init/postinit.c
@@ -871,24 +871,6 @@ InitPostgres(const char *in_dbname, Oid dboid, const char *username,
am_superuser = superuser();
}
- /*
- * If we're trying to shut down, only superusers can connect, and new
- * replication connections are not allowed.
- */
- if ((!am_superuser || am_walsender) &&
- MyProcPort != NULL &&
- MyProcPort->canAcceptConnections == CAC_SUPERUSER)
- {
- if (am_walsender)
- ereport(FATAL,
- (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
- errmsg("new replication connections are not allowed during database shutdown")));
- else
- ereport(FATAL,
- (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
- errmsg("must be superuser to connect during database shutdown")));
- }
-
/*
* Binary upgrades only allowed super-user connections
*/
diff --git a/src/bin/pg_basebackup/t/010_pg_basebackup.pl b/src/bin/pg_basebackup/t/010_pg_basebackup.pl
index 5ba84c2250..7309ebddea 100644
--- a/src/bin/pg_basebackup/t/010_pg_basebackup.pl
+++ b/src/bin/pg_basebackup/t/010_pg_basebackup.pl
@@ -247,6 +247,10 @@ isnt(slurp_file("$tempdir/backup/backup_label"),
'DONOTCOPY', 'existing backup_label not copied');
rmtree("$tempdir/backup");
+# Now delete the bogus backup_label file since it will interfere with startup
+unlink("$pgdata/backup_label")
+ or BAIL_OUT("unable to unlink $pgdata/backup_label");
+
$node->command_ok(
[
@pg_basebackup_defs, '-D',
diff --git a/src/bin/pg_ctl/pg_ctl.c b/src/bin/pg_ctl/pg_ctl.c
index 3c182c97d4..3a9092a16a 100644
--- a/src/bin/pg_ctl/pg_ctl.c
+++ b/src/bin/pg_ctl/pg_ctl.c
@@ -1025,7 +1025,6 @@ static void
do_stop(void)
{
pgpid_t pid;
- struct stat statbuf;
pid = get_pgpid(false);
@@ -1058,20 +1057,6 @@ do_stop(void)
}
else
{
- /*
- * If backup_label exists, an online backup is running. Warn the user
- * that smart shutdown will wait for it to finish. However, if the
- * server is in archive recovery, we're recovering from an online
- * backup instead of performing one.
- */
- if (shutdown_mode == SMART_MODE &&
- stat(backup_file, &statbuf) == 0 &&
- get_control_dbstate() != DB_IN_ARCHIVE_RECOVERY)
- {
- print_msg(_("WARNING: online backup mode is active\n"
- "Shutdown will not complete until pg_stop_backup() is called.\n\n"));
- }
-
print_msg(_("waiting for server to shut down..."));
if (!wait_for_postmaster_stop())
@@ -1099,7 +1084,6 @@ static void
do_restart(void)
{
pgpid_t pid;
- struct stat statbuf;
pid = get_pgpid(false);
@@ -1134,20 +1118,6 @@ do_restart(void)
exit(1);
}
- /*
- * If backup_label exists, an online backup is running. Warn the user
- * that smart shutdown will wait for it to finish. However, if the
- * server is in archive recovery, we're recovering from an online
- * backup instead of performing one.
- */
- if (shutdown_mode == SMART_MODE &&
- stat(backup_file, &statbuf) == 0 &&
- get_control_dbstate() != DB_IN_ARCHIVE_RECOVERY)
- {
- print_msg(_("WARNING: online backup mode is active\n"
- "Shutdown will not complete until pg_stop_backup() is called.\n\n"));
- }
-
print_msg(_("waiting for server to shut down..."));
/* always wait for restart */
diff --git a/src/bin/pg_rewind/filemap.c b/src/bin/pg_rewind/filemap.c
index 7211090f47..fb52debf7a 100644
--- a/src/bin/pg_rewind/filemap.c
+++ b/src/bin/pg_rewind/filemap.c
@@ -140,9 +140,9 @@ static const struct exclude_list_item excludeFiles[] =
{"pg_internal.init", true}, /* defined as RELCACHE_INIT_FILENAME */
/*
- * If there's a backup_label or tablespace_map file, it belongs to a
- * backup started by the user with pg_start_backup(). It is *not* correct
- * for this backup. Our backup_label is written later on separately.
+ * If there is a backup_label or tablespace_map file, it indicates that
+ * a recovery failed and this cluster probably can't be rewound, but
+ * exclude them anyway if they are found.
*/
{"backup_label", false}, /* defined as BACKUP_LABEL_FILE */
{"tablespace_map", false}, /* defined as TABLESPACE_MAP */
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index 09f6464331..b81917f243 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -276,14 +276,13 @@ extern void XLogShutdownWalRcv(void);
typedef enum SessionBackupState
{
SESSION_BACKUP_NONE,
- SESSION_BACKUP_EXCLUSIVE,
- SESSION_BACKUP_NON_EXCLUSIVE
+ SESSION_BACKUP_RUNNING,
} SessionBackupState;
-extern XLogRecPtr do_pg_start_backup(const char *backupidstr, bool fast,
+extern XLogRecPtr do_pg_backup_start(const char *backupidstr, bool fast,
TimeLineID *starttli_p, StringInfo labelfile,
List **tablespaces, StringInfo tblspcmapfile);
-extern XLogRecPtr do_pg_stop_backup(char *labelfile, bool waitforarchive,
+extern XLogRecPtr do_pg_backup_stop(char *labelfile, bool waitforarchive,
TimeLineID *stoptli_p);
extern void do_pg_abort_backup(int code, Datum arg);
extern void register_persistent_abort_backup_handler(void);
diff --git a/src/include/catalog/pg_control.h b/src/include/catalog/pg_control.h
index 1f3dc24ac1..3d075fcef3 100644
--- a/src/include/catalog/pg_control.h
+++ b/src/include/catalog/pg_control.h
@@ -163,7 +163,7 @@ typedef struct ControlFileData
* from a backup, and must see a backup-end record before we can safely
* start up. If it's false, but backupStartPoint is set, a backup_label
* file was found at startup but it may have been a leftover from a stray
- * pg_start_backup() call, not accompanied by pg_stop_backup().
+ * pg_backup_start() call, not accompanied by pg_backup_stop().
*/
XLogRecPtr minRecoveryPoint;
TimeLineID minRecoveryPointTLI;
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 25304430f4..361a40a191 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -6274,26 +6274,16 @@
proargtypes => 'int4 int8', proargnames => '{pid,timeout}',
prosrc => 'pg_terminate_backend' },
{ oid => '2172', descr => 'prepare for taking an online backup',
- proname => 'pg_start_backup', provolatile => 'v', proparallel => 'r',
- prorettype => 'pg_lsn', proargtypes => 'text bool bool',
- prosrc => 'pg_start_backup' },
-{ oid => '2173', descr => 'finish taking an online backup',
- proname => 'pg_stop_backup', provolatile => 'v', proparallel => 'r',
- prorettype => 'pg_lsn', proargtypes => '', prosrc => 'pg_stop_backup' },
+ proname => 'pg_backup_start', provolatile => 'v', proparallel => 'r',
+ prorettype => 'pg_lsn', proargtypes => 'text bool',
+ prosrc => 'pg_backup_start' },
{ oid => '2739', descr => 'finish taking an online backup',
- proname => 'pg_stop_backup', provolatile => 'v', proparallel => 'r',
- prorettype => 'record', proargtypes => 'bool bool',
- proallargtypes => '{bool,bool,pg_lsn,text,text}',
- proargmodes => '{i,i,o,o,o}',
- proargnames => '{exclusive,wait_for_archive,lsn,labelfile,spcmapfile}',
- prosrc => 'pg_stop_backup_v2' },
-{ oid => '3813', descr => 'true if server is in online backup',
- proname => 'pg_is_in_backup', provolatile => 'v', prorettype => 'bool',
- proargtypes => '', prosrc => 'pg_is_in_backup' },
-{ oid => '3814', descr => 'start time of an online backup',
- proname => 'pg_backup_start_time', provolatile => 's',
- prorettype => 'timestamptz', proargtypes => '',
- prosrc => 'pg_backup_start_time' },
+ proname => 'pg_backup_stop', provolatile => 'v', proparallel => 'r',
+ prorettype => 'record', proargtypes => 'bool',
+ proallargtypes => '{bool,pg_lsn,text,text}',
+ proargmodes => '{i,o,o,o}',
+ proargnames => '{wait_for_archive,lsn,labelfile,spcmapfile}',
+ prosrc => 'pg_backup_stop' },
{ oid => '3436', descr => 'promote standby server',
proname => 'pg_promote', provolatile => 'v', prorettype => 'bool',
proargtypes => 'bool int4', proargnames => '{wait,wait_seconds}',
diff --git a/src/include/libpq/libpq-be.h b/src/include/libpq/libpq-be.h
index dd3e5efba3..c3bf514652 100644
--- a/src/include/libpq/libpq-be.h
+++ b/src/include/libpq/libpq-be.h
@@ -75,8 +75,7 @@ typedef enum CAC_state
CAC_SHUTDOWN,
CAC_RECOVERY,
CAC_NOTCONSISTENT,
- CAC_TOOMANY,
- CAC_SUPERUSER
+ CAC_TOOMANY
} CAC_state;
diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h
index 0abc3ad540..9321d7f264 100644
--- a/src/include/miscadmin.h
+++ b/src/include/miscadmin.h
@@ -481,10 +481,6 @@ extern void process_session_preload_libraries(void);
extern void pg_bindtextdomain(const char *domain);
extern bool has_rolreplication(Oid roleid);
-/* in access/transam/xlog.c */
-extern bool BackupInProgress(void);
-extern void CancelBackup(void);
-
/* in executor/nodeHash.c */
extern size_t get_hash_memory_limit(void);
diff --git a/src/test/perl/PostgreSQL/Test/Cluster.pm b/src/test/perl/PostgreSQL/Test/Cluster.pm
index b4ebc99935..1452297210 100644
--- a/src/test/perl/PostgreSQL/Test/Cluster.pm
+++ b/src/test/perl/PostgreSQL/Test/Cluster.pm
@@ -638,25 +638,6 @@ sub backup
return;
}
-=item $node->backup_fs_hot(backup_name)
-
-Create a backup with a filesystem level copy in subdirectory B<backup_name> of
-B<< $node->backup_dir >>, including WAL.
-
-Archiving must be enabled, as B<pg_start_backup()> and B<pg_stop_backup()> are
-used. This is not checked or enforced.
-
-The backup name is passed as the backup label to B<pg_start_backup()>.
-
-=cut
-
-sub backup_fs_hot
-{
- my ($self, $backup_name) = @_;
- $self->_backup_fs($backup_name, 1);
- return;
-}
-
=item $node->backup_fs_cold(backup_name)
Create a backup with a filesystem level copy in subdirectory B<backup_name> of
@@ -670,53 +651,18 @@ Use B<backup> or B<backup_fs_hot> if you want to back up a running server.
sub backup_fs_cold
{
my ($self, $backup_name) = @_;
- $self->_backup_fs($backup_name, 0);
- return;
-}
-
-
-# Common sub of backup_fs_hot and backup_fs_cold
-sub _backup_fs
-{
- my ($self, $backup_name, $hot) = @_;
- my $backup_path = $self->backup_dir . '/' . $backup_name;
- my $port = $self->port;
- my $name = $self->name;
-
- print "# Taking filesystem backup $backup_name from node \"$name\"\n";
-
- if ($hot)
- {
- my $stdout = $self->safe_psql('postgres',
- "SELECT * FROM pg_start_backup('$backup_name');");
- print "# pg_start_backup: $stdout\n";
- }
PostgreSQL::Test::RecursiveCopy::copypath(
$self->data_dir,
- $backup_path,
+ $self->backup_dir . '/' . $backup_name,
filterfn => sub {
my $src = shift;
return ($src ne 'log' and $src ne 'postmaster.pid');
});
- if ($hot)
- {
-
- # We ignore pg_stop_backup's return value. We also assume archiving
- # is enabled; otherwise the caller will have to copy the remaining
- # segments.
- my $stdout =
- $self->safe_psql('postgres', 'SELECT * FROM pg_stop_backup();');
- print "# pg_stop_backup: $stdout\n";
- }
-
- print "# Backup finished\n";
return;
}
-
-
=pod
=item $node->init_from_backup(root_node, backup_name)
diff --git a/src/test/recovery/t/010_logical_decoding_timelines.pl b/src/test/recovery/t/010_logical_decoding_timelines.pl
index 01ff31e61f..135fb1a72d 100644
--- a/src/test/recovery/t/010_logical_decoding_timelines.pl
+++ b/src/test/recovery/t/010_logical_decoding_timelines.pl
@@ -69,7 +69,9 @@ $node_primary->safe_psql('dropme',
$node_primary->safe_psql('postgres', 'CHECKPOINT;');
my $backup_name = 'b1';
-$node_primary->backup_fs_hot($backup_name);
+$node_primary->stop();
+$node_primary->backup_fs_cold($backup_name);
+$node_primary->start();
$node_primary->safe_psql('postgres',
q[SELECT pg_create_physical_replication_slot('phys_slot');]);
--
2.25.1
On 4/4/22 11:42 AM, Nathan Bossart wrote:
I noticed a couple of other things that can be removed. Since we no longer
wait on exclusive backup mode during smart shutdown, we can change
connsAllowed (in postmaster.c) to a boolean and remove CAC_SUPERUSER. We
can also remove a couple of related notes in the documentation. I've done
all this in the attached patch.
These changes look good to me. IMV it is a real bonus how much the state
machine has been simplified.
I've also run this patch through the pgbackrest regression tests without
any problems.
Regards,
--
-David
david@pgmasters.net
Greetings,
* David Steele (david@pgmasters.net) wrote:
On 4/4/22 11:42 AM, Nathan Bossart wrote:
I noticed a couple of other things that can be removed. Since we no longer
wait on exclusive backup mode during smart shutdown, we can change
connsAllowed (in postmaster.c) to a boolean and remove CAC_SUPERUSER. We
can also remove a couple of related notes in the documentation. I've done
all this in the attached patch.These changes look good to me. IMV it is a real bonus how much the state
machine has been simplified.
Yeah, agreed.
I've also run this patch through the pgbackrest regression tests without any
problems.
Fantastic.
Please find attached an updated patch + commit message. Mostly, I just
went through and did a bit more in terms of updating the documentation
and improving the comments (there were some places that were still
worrying about the chance of a 'stray' backup_label file existing, which
isn't possible any longer), along with some additional testing and
review. This is looking pretty good to me, but other thoughts are
certainly welcome. Otherwise, I'm hoping to commit this tomorrow.
Thanks!
Stephen
Attachments:
v11-0001-remove-exclusive-backup-mode.patchtext/x-diff; charset=us-asciiDownload
From 4e53c8252fb1ee32bf9688b553cf1f5876ab234b Mon Sep 17 00:00:00 2001
From: Stephen Frost <sfrost@snowman.net>
Date: Mon, 4 Apr 2022 13:05:13 -0400
Subject: [PATCH] Remove exclusive backup mode
Exclusive-mode backups have been deprecated since 9.6 (when
non-exclusive backups were introduced) due to the issues
they can cause should the system crash while one is running and
generally because non-exclusive provides a much better interface.
Further, exclusive backup mode wasn't really being tested (nor was most
of the related code- like being able to log in just to stop an exclusive
backup and the bits of the state machine related to that) and having to
possibly deal with an exclusive backup and the backup_label file
existing during pg_basebackup, pg_rewind, etc, added other complexities
that we are better off without.
This patch removes the exclusive backup mode, the various special cases
for dealing with it, and greatly simplifies the online backup code and
documentation.
Authors: David Steele, Nathan Bossart
Reviewed-by: Chapman Flack
Discussion: https://postgr.es/m/ac7339ca-3718-3c93-929f-99e725d1172c@pgmasters.net
https://postgr.es/m/CAHg+QDfiM+WU61tF6=nPZocMZvHDzCK47Kneyb0ZRULYzV5sKQ@mail.gmail.com
---
doc/src/sgml/backup.sgml | 241 +-------
doc/src/sgml/func.sgml | 111 +---
doc/src/sgml/high-availability.sgml | 6 +-
doc/src/sgml/monitoring.sgml | 4 +-
doc/src/sgml/ref/pg_ctl-ref.sgml | 6 +-
doc/src/sgml/ref/pgupgrade.sgml | 2 +-
doc/src/sgml/runtime.sgml | 8 +-
src/backend/access/transam/xlog.c | 519 +++---------------
src/backend/access/transam/xlogfuncs.c | 253 ++-------
src/backend/access/transam/xlogrecovery.c | 20 +-
src/backend/catalog/system_functions.sql | 18 +-
src/backend/postmaster/postmaster.c | 75 +--
src/backend/replication/basebackup.c | 20 +-
src/backend/utils/init/postinit.c | 18 -
src/bin/pg_basebackup/t/010_pg_basebackup.pl | 4 +
src/bin/pg_ctl/pg_ctl.c | 30 -
src/bin/pg_rewind/filemap.c | 6 +-
src/include/access/xlog.h | 7 +-
src/include/catalog/pg_control.h | 4 +-
src/include/catalog/pg_proc.dat | 28 +-
src/include/libpq/libpq-be.h | 3 +-
src/include/miscadmin.h | 4 -
src/test/perl/PostgreSQL/Test/Cluster.pm | 56 +-
.../t/010_logical_decoding_timelines.pl | 4 +-
24 files changed, 247 insertions(+), 1200 deletions(-)
diff --git a/doc/src/sgml/backup.sgml b/doc/src/sgml/backup.sgml
index 0d69851bb1..fc2ec68758 100644
--- a/doc/src/sgml/backup.sgml
+++ b/doc/src/sgml/backup.sgml
@@ -857,18 +857,9 @@ test ! -f /mnt/server/archivedir/00000001000000A900000065 && cp pg_wal/0
sequence, and that the success of a step is verified before
proceeding to the next step.
</para>
- <para>
- Low level base backups can be made in a non-exclusive or an exclusive
- way. The non-exclusive method is recommended and the exclusive one is
- deprecated and will eventually be removed.
- </para>
-
- <sect3 id="backup-lowlevel-base-backup-nonexclusive">
- <title>Making a Non-Exclusive Low-Level Backup</title>
<para>
- A non-exclusive low level backup is one that allows other
- concurrent backups to be running (both those started using
- the same backup API and those started using
+ Multiple backups are able to be run concurrently (both those
+ started using this backup API and those started using
<xref linkend="app-pgbasebackup"/>).
</para>
<para>
@@ -881,34 +872,30 @@ test ! -f /mnt/server/archivedir/00000001000000A900000065 && cp pg_wal/0
<listitem>
<para>
Connect to the server (it does not matter which database) as a user with
- rights to run pg_start_backup (superuser, or a user who has been granted
+ rights to run pg_backup_start (superuser, or a user who has been granted
EXECUTE on the function) and issue the command:
<programlisting>
-SELECT pg_start_backup('label', false, false);
+SELECT pg_backup_start(label => 'label', fast => false);
</programlisting>
where <literal>label</literal> is any string you want to use to uniquely
identify this backup operation. The connection
- calling <function>pg_start_backup</function> must be maintained until the end of
+ calling <function>pg_backup_start</function> must be maintained until the end of
the backup, or the backup will be automatically aborted.
</para>
<para>
- By default, <function>pg_start_backup</function> can take a long time to finish.
- This is because it performs a checkpoint, and the I/O
- required for the checkpoint will be spread out over a significant
- period of time, by default half your inter-checkpoint interval
- (see the configuration parameter
+ Online backups are always started at the beginning of a checkpoint.
+ By default, <function>pg_backup_start</function> will wait for the next
+ regularly scheduled checkpoint to complete, which may take a long time (see the
+ configuration parameters <xref linkend="guc-checkpoint-timeout"/> and
<xref linkend="guc-checkpoint-completion-target"/>). This is
- usually what you want, because it minimizes the impact on query
- processing. If you want to start the backup as soon as
- possible, change the second parameter to <literal>true</literal>, which will
- issue an immediate checkpoint using as much I/O as available.
+ usually preferrable as it minimizes the impact on the running system. If you
+ want to start the backup as soon as possible, pass <literal>true</literal> as
+ the second parameter to <function>pg_backup_start</function> and it will
+ request an immediate checkpoint, which will finish as fast as possible using
+ as much I/O as possible.
</para>
- <para>
- The third parameter being <literal>false</literal> tells
- <function>pg_start_backup</function> to initiate a non-exclusive base backup.
- </para>
</listitem>
<listitem>
<para>
@@ -926,7 +913,7 @@ SELECT pg_start_backup('label', false, false);
<para>
In the same connection as before, issue the command:
<programlisting>
-SELECT * FROM pg_stop_backup(false, true);
+SELECT * FROM pg_backup_stop(wait_for_archive => true);
</programlisting>
This terminates backup mode. On a primary, it also performs an automatic
switch to the next WAL segment. On a standby, it is not possible to
@@ -937,7 +924,7 @@ SELECT * FROM pg_stop_backup(false, true);
ready to archive.
</para>
<para>
- The <function>pg_stop_backup</function> will return one row with three
+ <function>pg_backup_stop</function> will return one row with three
values. The second of these fields should be written to a file named
<filename>backup_label</filename> in the root directory of the backup. The
third field should be written to a file named
@@ -949,14 +936,14 @@ SELECT * FROM pg_stop_backup(false, true);
<listitem>
<para>
Once the WAL segment files active during the backup are archived, you are
- done. The file identified by <function>pg_stop_backup</function>'s first return
+ done. The file identified by <function>pg_backup_stop</function>'s first return
value is the last segment that is required to form a complete set of
backup files. On a primary, if <varname>archive_mode</varname> is enabled and the
<literal>wait_for_archive</literal> parameter is <literal>true</literal>,
- <function>pg_stop_backup</function> does not return until the last segment has
+ <function>pg_backup_stop</function> does not return until the last segment has
been archived.
On a standby, <varname>archive_mode</varname> must be <literal>always</literal> in order
- for <function>pg_stop_backup</function> to wait.
+ for <function>pg_backup_stop</function> to wait.
Archiving of these files happens automatically since you have
already configured <varname>archive_library</varname>. In most cases this
happens quickly, but you are advised to monitor your archive
@@ -965,9 +952,9 @@ SELECT * FROM pg_stop_backup(false, true);
because of failures of the archive library, it will keep retrying
until the archive succeeds and the backup is complete.
If you wish to place a time limit on the execution of
- <function>pg_stop_backup</function>, set an appropriate
+ <function>pg_backup_stop</function>, set an appropriate
<varname>statement_timeout</varname> value, but make note that if
- <function>pg_stop_backup</function> terminates because of this your backup
+ <function>pg_backup_stop</function> terminates because of this your backup
may not be valid.
</para>
<para>
@@ -975,8 +962,8 @@ SELECT * FROM pg_stop_backup(false, true);
required for the backup are successfully archived then the
<literal>wait_for_archive</literal> parameter (which defaults to true) can be set
to false to have
- <function>pg_stop_backup</function> return as soon as the stop backup record is
- written to the WAL. By default, <function>pg_stop_backup</function> will wait
+ <function>pg_backup_stop</function> return as soon as the stop backup record is
+ written to the WAL. By default, <function>pg_backup_stop</function> will wait
until all WAL has been archived, which can take some time. This option
must be used with caution: if WAL archiving is not monitored correctly
then the backup might not include all of the WAL files and will
@@ -985,142 +972,6 @@ SELECT * FROM pg_stop_backup(false, true);
</listitem>
</orderedlist>
</para>
- </sect3>
- <sect3 id="backup-lowlevel-base-backup-exclusive">
- <title>Making an Exclusive Low-Level Backup</title>
-
- <note>
- <para>
- The exclusive backup method is deprecated and should be avoided.
- Prior to <productname>PostgreSQL</productname> 9.6, this was the only
- low-level method available, but it is now recommended that all users
- upgrade their scripts to use non-exclusive backups.
- </para>
- </note>
-
- <para>
- The process for an exclusive backup is mostly the same as for a
- non-exclusive one, but it differs in a few key steps. This type of
- backup can only be taken on a primary and does not allow concurrent
- backups. Moreover, because it creates a backup label file, as
- described below, it can block automatic restart of the primary server
- after a crash. On the other hand, the erroneous removal of this
- file from a backup or standby is a common mistake, which can result
- in serious data corruption. If it is necessary to use this method,
- the following steps may be used.
- </para>
- <para>
- <orderedlist>
- <listitem>
- <para>
- Ensure that WAL archiving is enabled and working.
- </para>
- </listitem>
- <listitem>
- <para>
- Connect to the server (it does not matter which database) as a user with
- rights to run pg_start_backup (superuser, or a user who has been granted
- EXECUTE on the function) and issue the command:
-<programlisting>
-SELECT pg_start_backup('label');
-</programlisting>
- where <literal>label</literal> is any string you want to use to uniquely
- identify this backup operation.
- <function>pg_start_backup</function> creates a <firstterm>backup label</firstterm> file,
- called <filename>backup_label</filename>, in the cluster directory with
- information about your backup, including the start time and label string.
- The function also creates a <firstterm>tablespace map</firstterm> file,
- called <filename>tablespace_map</filename>, in the cluster directory with
- information about tablespace symbolic links in <filename>pg_tblspc/</filename> if
- one or more such link is present. Both files are critical to the
- integrity of the backup, should you need to restore from it.
- </para>
-
- <para>
- By default, <function>pg_start_backup</function> can take a long time to finish.
- This is because it performs a checkpoint, and the I/O
- required for the checkpoint will be spread out over a significant
- period of time, by default half your inter-checkpoint interval
- (see the configuration parameter
- <xref linkend="guc-checkpoint-completion-target"/>). This is
- usually what you want, because it minimizes the impact on query
- processing. If you want to start the backup as soon as
- possible, use:
-<programlisting>
-SELECT pg_start_backup('label', true);
-</programlisting>
- This forces the checkpoint to be done as quickly as possible.
- </para>
- </listitem>
- <listitem>
- <para>
- Perform the backup, using any convenient file-system-backup tool
- such as <application>tar</application> or <application>cpio</application> (not
- <application>pg_dump</application> or
- <application>pg_dumpall</application>). It is neither
- necessary nor desirable to stop normal operation of the database
- while you do this. See
- <xref linkend="backup-lowlevel-base-backup-data"/> for things to
- consider during this backup.
- </para>
- <para>
- As noted above, if the server crashes during the backup it may not be
- possible to restart until the <filename>backup_label</filename> file has
- been manually deleted from the <envar>PGDATA</envar> directory. Note
- that it is very important to never remove the
- <filename>backup_label</filename> file when restoring a backup, because
- this will result in corruption. Confusion about when it is appropriate
- to remove this file is a common cause of data corruption when using this
- method; be very certain that you remove the file only on an existing
- primary and never when building a standby or restoring a backup, even if
- you are building a standby that will subsequently be promoted to a new
- primary.
- </para>
- </listitem>
- <listitem>
- <para>
- Again connect to the database as a user with rights to run
- pg_stop_backup (superuser, or a user who has been granted EXECUTE on
- the function), and issue the command:
-<programlisting>
-SELECT pg_stop_backup();
-</programlisting>
- This function terminates backup mode and
- performs an automatic switch to the next WAL segment. The reason for the
- switch is to arrange for the last WAL segment written during the backup
- interval to be ready to archive.
- </para>
- </listitem>
- <listitem>
- <para>
- Once the WAL segment files active during the backup are archived, you are
- done. The file identified by <function>pg_stop_backup</function>'s result is
- the last segment that is required to form a complete set of backup files.
- If <varname>archive_mode</varname> is enabled,
- <function>pg_stop_backup</function> does not return until the last segment has
- been archived.
- Archiving of these files happens automatically since you have
- already configured <varname>archive_command</varname>. In most cases this
- happens quickly, but you are advised to monitor your archive
- system to ensure there are no delays.
- If the archive process has fallen behind
- because of failures of the archive command, it will keep retrying
- until the archive succeeds and the backup is complete.
- </para>
-
- <para>
- When using exclusive backup mode, it is absolutely imperative to ensure
- that <function>pg_stop_backup</function> completes successfully at the
- end of the backup. Even if the backup itself fails, for example due to
- lack of disk space, failure to call <function>pg_stop_backup</function>
- will leave the server in backup mode indefinitely, causing future backups
- to fail and increasing the risk of a restart failure during the time that
- <filename>backup_label</filename> exists.
- </para>
- </listitem>
- </orderedlist>
- </para>
- </sect3>
<sect3 id="backup-lowlevel-base-backup-data">
<title>Backing Up the Data Directory</title>
<para>
@@ -1203,8 +1054,8 @@ SELECT pg_stop_backup();
<para>
The backup label
- file includes the label string you gave to <function>pg_start_backup</function>,
- as well as the time at which <function>pg_start_backup</function> was run, and
+ file includes the label string you gave to <function>pg_backup_start</function>,
+ as well as the time at which <function>pg_backup_start</function> was run, and
the name of the starting WAL file. In case of confusion it is therefore
possible to look inside a backup file and determine exactly which
backup session the dump file came from. The tablespace map file includes
@@ -1218,7 +1069,7 @@ SELECT pg_stop_backup();
<para>
It is also possible to make a backup while the server is
stopped. In this case, you obviously cannot use
- <function>pg_start_backup</function> or <function>pg_stop_backup</function>, and
+ <function>pg_backup_start</function> or <function>pg_backup_stop</function>, and
you will therefore be left to your own devices to keep track of which
backup is which and how far back the associated WAL files go.
It is generally better to follow the continuous archiving procedure above.
@@ -1393,7 +1244,7 @@ restore_command = 'cp /mnt/server/archivedir/%f %p'
<note>
<para>
The stop point must be after the ending time of the base backup, i.e.,
- the end time of <function>pg_stop_backup</function>. You cannot use a base backup
+ the end time of <function>pg_backup_stop</function>. You cannot use a base backup
to recover to a time when that backup was in progress. (To
recover to such a time, you must go back to your previous base backup
and roll forward from there.)
@@ -1513,44 +1364,6 @@ restore_command = 'cp /mnt/server/archivedir/%f %p'
included in the backup automatically, and no special action is
required to restore the backup.
</para>
-
- <para>
- If more flexibility in copying the backup files is needed, a lower
- level process can be used for standalone hot backups as well.
- To prepare for low level standalone hot backups, make sure
- <varname>wal_level</varname> is set to
- <literal>replica</literal> or higher, <varname>archive_mode</varname> to
- <literal>on</literal>, and set up an <varname>archive_library</varname> that performs
- archiving only when a <emphasis>switch file</emphasis> exists. For example:
-<programlisting>
-archive_library = '' # use shell command
-archive_command = 'test ! -f /var/lib/pgsql/backup_in_progress || (test ! -f /var/lib/pgsql/archive/%f && cp %p /var/lib/pgsql/archive/%f)'
-</programlisting>
- This command will perform archiving when
- <filename>/var/lib/pgsql/backup_in_progress</filename> exists, and otherwise
- silently return zero exit status (allowing <productname>PostgreSQL</productname>
- to recycle the unwanted WAL file).
- </para>
-
- <para>
- With this preparation, a backup can be taken using a script like the
- following:
-<programlisting>
-touch /var/lib/pgsql/backup_in_progress
-psql -c "select pg_start_backup('hot_backup');"
-tar -cf /var/lib/pgsql/backup.tar /var/lib/pgsql/data/
-psql -c "select pg_stop_backup();"
-rm /var/lib/pgsql/backup_in_progress
-tar -rf /var/lib/pgsql/backup.tar /var/lib/pgsql/archive/
-</programlisting>
- The switch file <filename>/var/lib/pgsql/backup_in_progress</filename> is
- created first, enabling archiving of completed WAL files to occur.
- After the backup the switch file is removed. Archived WAL files are
- then added to the backup so that both base backup and all required
- WAL files are part of the same <application>tar</application> file.
- Please remember to add error handling to your backup scripts.
- </para>
-
</sect3>
<sect3 id="compressed-archive-logs">
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 4001cb2bda..ac4575217b 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -25598,9 +25598,8 @@ LOG: Grand total: 1651920 bytes in 201 blocks; 622360 free (88 chunks); 1029560
The functions shown in <xref
linkend="functions-admin-backup-table"/> assist in making on-line backups.
These functions cannot be executed during recovery (except
- non-exclusive <function>pg_start_backup</function>,
- non-exclusive <function>pg_stop_backup</function>,
- <function>pg_is_in_backup</function>, <function>pg_backup_start_time</function>
+ <function>pg_backup_start</function>,
+ <function>pg_backup_stop</function>,
and <function>pg_wal_lsn_diff</function>).
</para>
@@ -25689,13 +25688,12 @@ LOG: Grand total: 1651920 bytes in 201 blocks; 622360 free (88 chunks); 1029560
<row>
<entry role="func_table_entry"><para role="func_signature">
<indexterm>
- <primary>pg_start_backup</primary>
+ <primary>pg_backup_start</primary>
</indexterm>
- <function>pg_start_backup</function> (
+ <function>pg_backup_start</function> (
<parameter>label</parameter> <type>text</type>
<optional>, <parameter>fast</parameter> <type>boolean</type>
- <optional>, <parameter>exclusive</parameter> <type>boolean</type>
- </optional></optional> )
+ </optional> )
<returnvalue>pg_lsn</returnvalue>
</para>
<para>
@@ -25704,23 +25702,9 @@ LOG: Grand total: 1651920 bytes in 201 blocks; 622360 free (88 chunks); 1029560
(Typically this would be the name under which the backup dump file
will be stored.)
If the optional second parameter is given as <literal>true</literal>,
- it specifies executing <function>pg_start_backup</function> as quickly
+ it specifies executing <function>pg_backup_start</function> as quickly
as possible. This forces an immediate checkpoint which will cause a
spike in I/O operations, slowing any concurrently executing queries.
- The optional third parameter specifies whether to perform an exclusive
- or non-exclusive backup (default is exclusive).
- </para>
- <para>
- When used in exclusive mode, this function writes a backup label file
- (<filename>backup_label</filename>) and, if there are any links in
- the <filename>pg_tblspc/</filename> directory, a tablespace map file
- (<filename>tablespace_map</filename>) into the database cluster's data
- directory, then performs a checkpoint, and then returns the backup's
- starting write-ahead log location. (The user can ignore this
- result value, but it is provided in case it is useful.) When used in
- non-exclusive mode, the contents of these files are instead returned
- by the <function>pg_stop_backup</function> function, and should be
- copied to the backup area by the user.
</para>
<para>
This function is restricted to superusers by default, but other users
@@ -25731,11 +25715,10 @@ LOG: Grand total: 1651920 bytes in 201 blocks; 622360 free (88 chunks); 1029560
<row>
<entry role="func_table_entry"><para role="func_signature">
<indexterm>
- <primary>pg_stop_backup</primary>
+ <primary>pg_backup_stop</primary>
</indexterm>
- <function>pg_stop_backup</function> (
- <parameter>exclusive</parameter> <type>boolean</type>
- <optional>, <parameter>wait_for_archive</parameter> <type>boolean</type>
+ <function>pg_backup_stop</function> (
+ <optional><parameter>wait_for_archive</parameter> <type>boolean</type>
</optional> )
<returnvalue>record</returnvalue>
( <parameter>lsn</parameter> <type>pg_lsn</type>,
@@ -25743,24 +25726,21 @@ LOG: Grand total: 1651920 bytes in 201 blocks; 622360 free (88 chunks); 1029560
<parameter>spcmapfile</parameter> <type>text</type> )
</para>
<para>
- Finishes performing an exclusive or non-exclusive on-line backup.
- The <parameter>exclusive</parameter> parameter must match the
- previous <function>pg_start_backup</function> call.
- In an exclusive backup, <function>pg_stop_backup</function> removes
- the backup label file and, if it exists, the tablespace map file
- created by <function>pg_start_backup</function>. In a non-exclusive
- backup, the desired contents of these files are returned as part of
- the result of the function, and should be written to files in the
- backup area (not in the data directory).
+ Finishes performing an on-line backup. The desired contents of the
+ backup label file and the tablespace map file are returned as part of
+ the result of the function and must be written to files in the
+ backup area. These files must not be written to the live data directory
+ (doing so will cause PostgreSQL to fail to restart in the event of a
+ crash).
</para>
<para>
- There is an optional second parameter of type <type>boolean</type>.
+ There is an optional parameter of type <type>boolean</type>.
If false, the function will return immediately after the backup is
completed, without waiting for WAL to be archived. This behavior is
only useful with backup software that independently monitors WAL
archiving. Otherwise, WAL required to make the backup consistent might
be missing and make the backup useless. By default or when this
- parameter is true, <function>pg_stop_backup</function> will wait for
+ parameter is true, <function>pg_backup_stop</function> will wait for
WAL to be archived when archiving is enabled. (On a standby, this
means that it will wait only when <varname>archive_mode</varname> =
<literal>always</literal>. If write activity on the primary is low,
@@ -25770,7 +25750,7 @@ LOG: Grand total: 1651920 bytes in 201 blocks; 622360 free (88 chunks); 1029560
<para>
When executed on a primary, this function also creates a backup
history file in the write-ahead log archive area. The history file
- includes the label given to <function>pg_start_backup</function>, the
+ includes the label given to <function>pg_backup_start</function>, the
starting and ending write-ahead log locations for the backup, and the
starting and ending times of the backup. After recording the ending
location, the current write-ahead log insertion point is automatically
@@ -25781,27 +25761,11 @@ LOG: Grand total: 1651920 bytes in 201 blocks; 622360 free (88 chunks); 1029560
<para>
The result of the function is a single record.
The <parameter>lsn</parameter> column holds the backup's ending
- write-ahead log location (which again can be ignored). The second and
- third columns are <literal>NULL</literal> when ending an exclusive
- backup; after a non-exclusive backup they hold the desired contents of
- the label and tablespace map files.
- </para>
- <para>
- This function is restricted to superusers by default, but other users
- can be granted EXECUTE to run the function.
- </para></entry>
- </row>
-
- <row>
- <entry role="func_table_entry"><para role="func_signature">
- <function>pg_stop_backup</function> ()
- <returnvalue>pg_lsn</returnvalue>
- </para>
- <para>
- Finishes performing an exclusive on-line backup. This simplified
- version is equivalent to <literal>pg_stop_backup(true,
- true)</literal>, except that it only returns the <type>pg_lsn</type>
- result.
+ write-ahead log location (which again can be ignored). The second
+ column returns the contents of the backup label file, and the third
+ column returns the contents of the tablespace map file. These must be
+ stored as part of the backup and are required as part of the restore
+ process.
</para>
<para>
This function is restricted to superusers by default, but other users
@@ -25809,33 +25773,6 @@ LOG: Grand total: 1651920 bytes in 201 blocks; 622360 free (88 chunks); 1029560
</para></entry>
</row>
- <row>
- <entry role="func_table_entry"><para role="func_signature">
- <indexterm>
- <primary>pg_is_in_backup</primary>
- </indexterm>
- <function>pg_is_in_backup</function> ()
- <returnvalue>boolean</returnvalue>
- </para>
- <para>
- Returns true if an on-line exclusive backup is in progress.
- </para></entry>
- </row>
-
- <row>
- <entry role="func_table_entry"><para role="func_signature">
- <indexterm>
- <primary>pg_backup_start_time</primary>
- </indexterm>
- <function>pg_backup_start_time</function> ()
- <returnvalue>timestamp with time zone</returnvalue>
- </para>
- <para>
- Returns the start time of the current on-line exclusive backup if one
- is in progress, otherwise <literal>NULL</literal>.
- </para></entry>
- </row>
-
<row>
<entry role="func_table_entry"><para role="func_signature">
<indexterm>
@@ -25933,7 +25870,7 @@ LOG: Grand total: 1651920 bytes in 201 blocks; 622360 free (88 chunks); 1029560
corresponding write-ahead log file name and byte offset from
a <type>pg_lsn</type> value. For example:
<programlisting>
-postgres=# SELECT * FROM pg_walfile_name_offset(pg_stop_backup());
+postgres=# SELECT * FROM pg_walfile_name_offset((pg_backup_stop()).lsn);
file_name | file_offset
--------------------------+-------------
00000001000000000000000D | 4039624
diff --git a/doc/src/sgml/high-availability.sgml b/doc/src/sgml/high-availability.sgml
index 81fa26f985..3247e05666 100644
--- a/doc/src/sgml/high-availability.sgml
+++ b/doc/src/sgml/high-availability.sgml
@@ -1361,8 +1361,8 @@ synchronous_standby_names = 'ANY 2 (s1, s2, s3)'
<para>
If you need to re-create a standby server while transactions are
- waiting, make sure that the commands pg_start_backup() and
- pg_stop_backup() are run in a session with
+ waiting, make sure that the commands pg_backup_start() and
+ pg_backup_stop() are run in a session with
<varname>synchronous_commit</varname> = <literal>off</literal>, otherwise those
requests will wait forever for the standby to appear.
</para>
@@ -2159,7 +2159,7 @@ HINT: You can then restart the server after making the necessary configuration
<para>
WAL file control commands will not work during recovery,
- e.g., <function>pg_start_backup</function>, <function>pg_switch_wal</function> etc.
+ e.g., <function>pg_backup_start</function>, <function>pg_switch_wal</function> etc.
</para>
<para>
diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
index 3b9172f65b..487331c115 100644
--- a/doc/src/sgml/monitoring.sgml
+++ b/doc/src/sgml/monitoring.sgml
@@ -6674,7 +6674,7 @@ SELECT pg_stat_get_backend_pid(s.backendid) AS pid,
<entry><literal>waiting for checkpoint to finish</literal></entry>
<entry>
The WAL sender process is currently performing
- <function>pg_start_backup</function> to prepare to
+ <function>pg_backup_start</function> to prepare to
take a base backup, and waiting for the start-of-backup
checkpoint to finish.
</entry>
@@ -6697,7 +6697,7 @@ SELECT pg_stat_get_backend_pid(s.backendid) AS pid,
<entry><literal>waiting for wal archiving to finish</literal></entry>
<entry>
The WAL sender process is currently performing
- <function>pg_stop_backup</function> to finish the backup,
+ <function>pg_backup_stop</function> to finish the backup,
and waiting for all the WAL files required for the base backup
to be successfully archived.
If either <literal>--wal-method=none</literal> or
diff --git a/doc/src/sgml/ref/pg_ctl-ref.sgml b/doc/src/sgml/ref/pg_ctl-ref.sgml
index 3946fa52ea..46906966eb 100644
--- a/doc/src/sgml/ref/pg_ctl-ref.sgml
+++ b/doc/src/sgml/ref/pg_ctl-ref.sgml
@@ -186,11 +186,11 @@ PostgreSQL documentation
the specified data directory. Three different
shutdown methods can be selected with the <option>-m</option>
option. <quote>Smart</quote> mode disallows new connections, then waits
- for all existing clients to disconnect and any online backup to finish.
+ for all existing clients to disconnect.
If the server is in hot standby, recovery and streaming replication
will be terminated once all clients have disconnected.
- <quote>Fast</quote> mode (the default) does not wait for clients to disconnect and
- will terminate an online backup in progress. All active transactions are
+ <quote>Fast</quote> mode (the default) does not wait for clients to disconnect.
+ All active transactions are
rolled back and clients are forcibly disconnected, then the
server is shut down. <quote>Immediate</quote> mode will abort
all server processes immediately, without a clean shutdown. This choice
diff --git a/doc/src/sgml/ref/pgupgrade.sgml b/doc/src/sgml/ref/pgupgrade.sgml
index 729c886ac0..3fbe141456 100644
--- a/doc/src/sgml/ref/pgupgrade.sgml
+++ b/doc/src/sgml/ref/pgupgrade.sgml
@@ -618,7 +618,7 @@ rsync --archive --delete --hard-links --size-only --no-inc-recursive /vol1/pg_tb
<para>
Configure the servers for log shipping. (You do not need to run
- <function>pg_start_backup()</function> and <function>pg_stop_backup()</function>
+ <function>pg_backup_start()</function> and <function>pg_backup_stop()</function>
or take a file system backup as the standbys are still synchronized
with the primary.)
</para>
diff --git a/doc/src/sgml/runtime.sgml b/doc/src/sgml/runtime.sgml
index 1f021ea116..f5f4e3fab5 100644
--- a/doc/src/sgml/runtime.sgml
+++ b/doc/src/sgml/runtime.sgml
@@ -1552,11 +1552,7 @@ $ <userinput>cat /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages</userinp
After receiving <systemitem>SIGTERM</systemitem>, the server
disallows new connections, but lets existing sessions end their
work normally. It shuts down only after all of the sessions terminate.
- If the server is in online backup mode, it additionally waits
- until online backup mode is no longer active. While backup mode is
- active, new connections will still be allowed, but only to superusers
- (this exception allows a superuser to connect to terminate
- online backup mode). If the server is in recovery when a smart
+ If the server is in recovery when a smart
shutdown is requested, recovery and streaming replication will be
stopped only after all regular sessions have terminated.
</para>
@@ -1572,8 +1568,6 @@ $ <userinput>cat /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages</userinp
server processes <systemitem>SIGTERM</systemitem>, which will cause them
to abort their current transactions and exit promptly. It then
waits for all server processes to exit and finally shuts down.
- If the server is in online backup mode, backup mode will be
- terminated, rendering the backup useless.
</para>
</listitem>
</varlistentry>
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 17a56152f1..8ae0a0ba53 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -385,29 +385,6 @@ typedef union WALInsertLockPadded
char pad[PG_CACHE_LINE_SIZE];
} WALInsertLockPadded;
-/*
- * State of an exclusive backup, necessary to control concurrent activities
- * across sessions when working on exclusive backups.
- *
- * EXCLUSIVE_BACKUP_NONE means that there is no exclusive backup actually
- * running, to be more precise pg_start_backup() is not being executed for
- * an exclusive backup and there is no exclusive backup in progress.
- * EXCLUSIVE_BACKUP_STARTING means that pg_start_backup() is starting an
- * exclusive backup.
- * EXCLUSIVE_BACKUP_IN_PROGRESS means that pg_start_backup() has finished
- * running and an exclusive backup is in progress. pg_stop_backup() is
- * needed to finish it.
- * EXCLUSIVE_BACKUP_STOPPING means that pg_stop_backup() is stopping an
- * exclusive backup.
- */
-typedef enum ExclusiveBackupState
-{
- EXCLUSIVE_BACKUP_NONE = 0,
- EXCLUSIVE_BACKUP_STARTING,
- EXCLUSIVE_BACKUP_IN_PROGRESS,
- EXCLUSIVE_BACKUP_STOPPING
-} ExclusiveBackupState;
-
/*
* Session status of running backup, used for sanity checks in SQL-callable
* functions to start and stop backups.
@@ -456,15 +433,12 @@ typedef struct XLogCtlInsert
bool fullPageWrites;
/*
- * exclusiveBackupState indicates the state of an exclusive backup (see
- * comments of ExclusiveBackupState for more details). nonExclusiveBackups
- * is a counter indicating the number of streaming base backups currently
- * in progress. forcePageWrites is set to true when either of these is
- * non-zero. lastBackupStart is the latest checkpoint redo location used
- * as a starting point for an online backup.
+ * runningBackups is a counter indicating the number of backups currently in
+ * progress. forcePageWrites is set to true when runningBackups is non-zero.
+ * lastBackupStart is the latest checkpoint redo location used as a starting
+ * point for an online backup.
*/
- ExclusiveBackupState exclusiveBackupState;
- int nonExclusiveBackups;
+ int runningBackups;
XLogRecPtr lastBackupStart;
/*
@@ -696,8 +670,7 @@ static void ReadControlFile(void);
static void UpdateControlFile(void);
static char *str_time(pg_time_t tnow);
-static void pg_start_backup_callback(int code, Datum arg);
-static void pg_stop_backup_callback(int code, Datum arg);
+static void pg_backup_start_callback(int code, Datum arg);
static int get_sync_bit(int method);
@@ -5314,8 +5287,19 @@ StartupXLOG(void)
missingContrecPtr = endOfRecoveryInfo->missingContrecPtr;
/*
- * Complain if we did not roll forward far enough to render the backup
- * dump consistent. Note: it is indeed okay to look at the local variable
+ * When recovering from a backup (we are in recovery, and archive recovery
+ * was requested), complain if we did not roll forward far enough to reach
+ * the point where the database is consistent. For regular online
+ * backup-from-primary, that means reaching the end-of-backup WAL record (at
+ * which point we reset backupStartPoint to be Invalid), for
+ * backup-from-replica (which can't inject records into the WAL stream),
+ * that point is when we reach the minRecoveryPoint in pg_control (which
+ * we purposfully copy last when backing up from a replica). For pg_rewind
+ * (which creates a backup_label with a method of "pg_rewind") or
+ * snapshot-style backups (which don't), backupEndRequired will be set to
+ * false.
+ *
+ * Note: it is indeed okay to look at the local variable
* LocalMinRecoveryPoint here, even though ControlFile->minRecoveryPoint
* might be further ahead --- ControlFile->minRecoveryPoint cannot have
* been advanced beyond the WAL we processed.
@@ -5326,23 +5310,16 @@ StartupXLOG(void)
{
/*
* Ran off end of WAL before reaching end-of-backup WAL record, or
- * minRecoveryPoint. That's usually a bad sign, indicating that you
- * tried to recover from an online backup but never called
- * pg_stop_backup(), or you didn't archive all the WAL up to that
- * point. However, this also happens in crash recovery, if the system
- * crashes while an online backup is in progress. We must not treat
- * that as an error, or the database will refuse to start up.
+ * minRecoveryPoint. That's a bad sign, indicating that you tried to
+ * recover from an online backup but never called pg_backup_stop(),
+ * or you didn't archive all the WAL needed.
*/
if (ArchiveRecoveryRequested || ControlFile->backupEndRequired)
{
- if (ControlFile->backupEndRequired)
+ if (!XLogRecPtrIsInvalid(ControlFile->backupStartPoint) || ControlFile->backupEndRequired)
ereport(FATAL,
(errmsg("WAL ends before end of online backup"),
errhint("All WAL generated while online backup was taken must be available at recovery.")));
- else if (!XLogRecPtrIsInvalid(ControlFile->backupStartPoint))
- ereport(FATAL,
- (errmsg("WAL ends before end of online backup"),
- errhint("Online backup started with pg_start_backup() must be ended with pg_stop_backup(), and all WAL up to that point must be available at recovery.")));
else
ereport(FATAL,
(errmsg("WAL ends before consistent recovery point")));
@@ -7036,7 +7013,7 @@ CreateRestartPoint(int flags)
* Ensure minRecoveryPoint is past the checkpoint record. Normally,
* this will have happened already while writing out dirty buffers,
* but not necessarily - e.g. because no buffers were dirtied. We do
- * this because a non-exclusive base backup uses minRecoveryPoint to
+ * this because a backup performed in recovery uses minRecoveryPoint to
* determine which WAL files must be included in the backup, and the
* file (or files) containing the checkpoint record must be included,
* at a minimum. Note that for an ordinary restart of recovery there's
@@ -7840,7 +7817,7 @@ xlog_redo(XLogReaderState *record)
/*
* Update the LSN of the last replayed XLOG_FPW_CHANGE record so that
- * do_pg_start_backup() and do_pg_stop_backup() can check whether
+ * do_pg_backup_start() and do_pg_backup_stop() can check whether
* full_page_writes has been disabled during online backup.
*/
if (!fpw)
@@ -8039,29 +8016,14 @@ issue_xlog_fsync(int fd, XLogSegNo segno, TimeLineID tli)
}
/*
- * do_pg_start_backup
- *
- * Utility function called at the start of an online backup. It creates the
- * necessary starting checkpoint and constructs the backup label file.
- *
- * There are two kind of backups: exclusive and non-exclusive. An exclusive
- * backup is started with pg_start_backup(), and there can be only one active
- * at a time. The backup and tablespace map files of an exclusive backup are
- * written to $PGDATA/backup_label and $PGDATA/tablespace_map, and they are
- * removed by pg_stop_backup().
- *
- * A non-exclusive backup is used for the streaming base backups (see
- * src/backend/replication/basebackup.c). The difference to exclusive backups
- * is that the backup label and tablespace map files are not written to disk.
- * Instead, their would-be contents are returned in *labelfile and *tblspcmapfile,
- * and the caller is responsible for including them in the backup archive as
- * 'backup_label' and 'tablespace_map'. There can be many non-exclusive backups
- * active at the same time, and they don't conflict with an exclusive backup
- * either.
- *
- * labelfile and tblspcmapfile must be passed as NULL when starting an
- * exclusive backup, and as initially-empty StringInfos for a non-exclusive
- * backup.
+ * do_pg_backup_start is the workhorse of the user-visible pg_backup_start()
+ * function. It creates the necessary starting checkpoint and constructs the
+ * backup label and tablespace map.
+ *
+ * The backup label and tablespace map contents are returned in *labelfile and
+ * *tblspcmapfile, and the caller is responsible for including them in the
+ * backup archive as 'backup_label' and 'tablespace_map'. There can be many
+ * backups active at the same time.
*
* If "tablespaces" isn't NULL, it receives a list of tablespaceinfo structs
* describing the cluster's tablespaces.
@@ -8073,18 +8035,17 @@ issue_xlog_fsync(int fd, XLogSegNo segno, TimeLineID tli)
* Returns the minimum WAL location that must be present to restore from this
* backup, and the corresponding timeline ID in *starttli_p.
*
- * Every successfully started non-exclusive backup must be stopped by calling
- * do_pg_stop_backup() or do_pg_abort_backup().
+ * Every successfully started backup must be stopped by calling
+ * do_pg_backup_stop() or do_pg_abort_backup().
*
* It is the responsibility of the caller of this function to verify the
* permissions of the calling user!
*/
XLogRecPtr
-do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
+do_pg_backup_start(const char *backupidstr, bool fast, TimeLineID *starttli_p,
StringInfo labelfile, List **tablespaces,
StringInfo tblspcmapfile)
{
- bool exclusive = (labelfile == NULL);
bool backup_started_in_recovery = false;
XLogRecPtr checkpointloc;
XLogRecPtr startpoint;
@@ -8093,20 +8054,9 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
char strfbuf[128];
char xlogfilename[MAXFNAMELEN];
XLogSegNo _logSegNo;
- struct stat stat_buf;
- FILE *fp;
backup_started_in_recovery = RecoveryInProgress();
- /*
- * Currently only non-exclusive backup can be taken during recovery.
- */
- if (backup_started_in_recovery && exclusive)
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("recovery is in progress"),
- errhint("WAL control functions cannot be executed during recovery.")));
-
/*
* During recovery, we don't need to check WAL level. Because, if WAL
* level is not sufficient, it's impossible to get here during recovery.
@@ -8145,30 +8095,12 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
* XLogInsertRecord().
*/
WALInsertLockAcquireExclusive();
- if (exclusive)
- {
- /*
- * At first, mark that we're now starting an exclusive backup, to
- * ensure that there are no other sessions currently running
- * pg_start_backup() or pg_stop_backup().
- */
- if (XLogCtl->Insert.exclusiveBackupState != EXCLUSIVE_BACKUP_NONE)
- {
- WALInsertLockRelease();
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("a backup is already in progress"),
- errhint("Run pg_stop_backup() and try again.")));
- }
- XLogCtl->Insert.exclusiveBackupState = EXCLUSIVE_BACKUP_STARTING;
- }
- else
- XLogCtl->Insert.nonExclusiveBackups++;
+ XLogCtl->Insert.runningBackups++;
XLogCtl->Insert.forcePageWrites = true;
WALInsertLockRelease();
/* Ensure we release forcePageWrites if fail below */
- PG_ENSURE_ERROR_CLEANUP(pg_start_backup_callback, (Datum) BoolGetDatum(exclusive));
+ PG_ENSURE_ERROR_CLEANUP(pg_backup_start_callback, (Datum) 0);
{
bool gotUniqueStartpoint = false;
DIR *tblspcdir;
@@ -8180,7 +8112,7 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
* Force an XLOG file switch before the checkpoint, to ensure that the
* WAL segment the checkpoint is written to doesn't contain pages with
* old timeline IDs. That would otherwise happen if you called
- * pg_start_backup() right after restoring from a PITR archive: the
+ * pg_backup_start() right after restoring from a PITR archive: the
* first WAL segment containing the startup checkpoint has pages in
* the beginning with the old timeline ID. That can cause trouble at
* recovery: we won't have a history file covering the old timeline if
@@ -8215,7 +8147,7 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
* means that two successive backup runs can have same checkpoint
* positions.
*
- * Since the fact that we are executing do_pg_start_backup()
+ * Since the fact that we are executing do_pg_backup_start()
* during recovery means that checkpointer is running, we can use
* RequestCheckpoint() to establish a restartpoint.
*
@@ -8416,122 +8348,19 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
LSN_FORMAT_ARGS(startpoint), xlogfilename);
appendStringInfo(labelfile, "CHECKPOINT LOCATION: %X/%X\n",
LSN_FORMAT_ARGS(checkpointloc));
- appendStringInfo(labelfile, "BACKUP METHOD: %s\n",
- exclusive ? "pg_start_backup" : "streamed");
+ appendStringInfo(labelfile, "BACKUP METHOD: streamed\n");
appendStringInfo(labelfile, "BACKUP FROM: %s\n",
backup_started_in_recovery ? "standby" : "primary");
appendStringInfo(labelfile, "START TIME: %s\n", strfbuf);
appendStringInfo(labelfile, "LABEL: %s\n", backupidstr);
appendStringInfo(labelfile, "START TIMELINE: %u\n", starttli);
-
- /*
- * Okay, write the file, or return its contents to caller.
- */
- if (exclusive)
- {
- /*
- * Check for existing backup label --- implies a backup is already
- * running. (XXX given that we checked exclusiveBackupState
- * above, maybe it would be OK to just unlink any such label
- * file?)
- */
- if (stat(BACKUP_LABEL_FILE, &stat_buf) != 0)
- {
- if (errno != ENOENT)
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not stat file \"%s\": %m",
- BACKUP_LABEL_FILE)));
- }
- else
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("a backup is already in progress"),
- errhint("If you're sure there is no backup in progress, remove file \"%s\" and try again.",
- BACKUP_LABEL_FILE)));
-
- fp = AllocateFile(BACKUP_LABEL_FILE, "w");
-
- if (!fp)
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not create file \"%s\": %m",
- BACKUP_LABEL_FILE)));
- if (fwrite(labelfile->data, labelfile->len, 1, fp) != 1 ||
- fflush(fp) != 0 ||
- pg_fsync(fileno(fp)) != 0 ||
- ferror(fp) ||
- FreeFile(fp))
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not write file \"%s\": %m",
- BACKUP_LABEL_FILE)));
- /* Allocated locally for exclusive backups, so free separately */
- pfree(labelfile->data);
- pfree(labelfile);
-
- /* Write backup tablespace_map file. */
- if (tblspcmapfile->len > 0)
- {
- if (stat(TABLESPACE_MAP, &stat_buf) != 0)
- {
- if (errno != ENOENT)
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not stat file \"%s\": %m",
- TABLESPACE_MAP)));
- }
- else
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("a backup is already in progress"),
- errhint("If you're sure there is no backup in progress, remove file \"%s\" and try again.",
- TABLESPACE_MAP)));
-
- fp = AllocateFile(TABLESPACE_MAP, "w");
-
- if (!fp)
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not create file \"%s\": %m",
- TABLESPACE_MAP)));
- if (fwrite(tblspcmapfile->data, tblspcmapfile->len, 1, fp) != 1 ||
- fflush(fp) != 0 ||
- pg_fsync(fileno(fp)) != 0 ||
- ferror(fp) ||
- FreeFile(fp))
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not write file \"%s\": %m",
- TABLESPACE_MAP)));
- }
-
- /* Allocated locally for exclusive backups, so free separately */
- pfree(tblspcmapfile->data);
- pfree(tblspcmapfile);
- }
}
- PG_END_ENSURE_ERROR_CLEANUP(pg_start_backup_callback, (Datum) BoolGetDatum(exclusive));
+ PG_END_ENSURE_ERROR_CLEANUP(pg_backup_start_callback, (Datum) 0);
/*
- * Mark that start phase has correctly finished for an exclusive backup.
- * Session-level locks are updated as well to reflect that state.
- *
- * Note that CHECK_FOR_INTERRUPTS() must not occur while updating backup
- * counters and session-level lock. Otherwise they can be updated
- * inconsistently, and which might cause do_pg_abort_backup() to fail.
+ * Mark that the start phase has correctly finished for the backup.
*/
- if (exclusive)
- {
- WALInsertLockAcquireExclusive();
- XLogCtl->Insert.exclusiveBackupState = EXCLUSIVE_BACKUP_IN_PROGRESS;
-
- /* Set session-level lock */
- sessionBackupState = SESSION_BACKUP_EXCLUSIVE;
- WALInsertLockRelease();
- }
- else
- sessionBackupState = SESSION_BACKUP_NON_EXCLUSIVE;
+ sessionBackupState = SESSION_BACKUP_RUNNING;
/*
* We're done. As a convenience, return the starting WAL location.
@@ -8541,47 +8370,19 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
return startpoint;
}
-/* Error cleanup callback for pg_start_backup */
+/* Error cleanup callback for pg_backup_start */
static void
-pg_start_backup_callback(int code, Datum arg)
+pg_backup_start_callback(int code, Datum arg)
{
- bool exclusive = DatumGetBool(arg);
-
/* Update backup counters and forcePageWrites on failure */
WALInsertLockAcquireExclusive();
- if (exclusive)
- {
- Assert(XLogCtl->Insert.exclusiveBackupState == EXCLUSIVE_BACKUP_STARTING);
- XLogCtl->Insert.exclusiveBackupState = EXCLUSIVE_BACKUP_NONE;
- }
- else
- {
- Assert(XLogCtl->Insert.nonExclusiveBackups > 0);
- XLogCtl->Insert.nonExclusiveBackups--;
- }
- if (XLogCtl->Insert.exclusiveBackupState == EXCLUSIVE_BACKUP_NONE &&
- XLogCtl->Insert.nonExclusiveBackups == 0)
- {
- XLogCtl->Insert.forcePageWrites = false;
- }
- WALInsertLockRelease();
-}
-
-/*
- * Error cleanup callback for pg_stop_backup
- */
-static void
-pg_stop_backup_callback(int code, Datum arg)
-{
- bool exclusive = DatumGetBool(arg);
+ Assert(XLogCtl->Insert.runningBackups > 0);
+ XLogCtl->Insert.runningBackups--;
- /* Update backup status on failure */
- WALInsertLockAcquireExclusive();
- if (exclusive)
+ if (XLogCtl->Insert.runningBackups == 0)
{
- Assert(XLogCtl->Insert.exclusiveBackupState == EXCLUSIVE_BACKUP_STOPPING);
- XLogCtl->Insert.exclusiveBackupState = EXCLUSIVE_BACKUP_IN_PROGRESS;
+ XLogCtl->Insert.forcePageWrites = false;
}
WALInsertLockRelease();
}
@@ -8596,14 +8397,11 @@ get_backup_status(void)
}
/*
- * do_pg_stop_backup
+ * do_pg_backup_stop
*
* Utility function called at the end of an online backup. It cleans up the
* backup state and can optionally wait for WAL segments to be archived.
*
- * If labelfile is NULL, this stops an exclusive backup. Otherwise this stops
- * the non-exclusive backup specified by 'labelfile'.
- *
* Returns the last WAL location that must be present to restore from this
* backup, and the corresponding timeline ID in *stoptli_p.
*
@@ -8611,9 +8409,8 @@ get_backup_status(void)
* permissions of the calling user!
*/
XLogRecPtr
-do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
+do_pg_backup_stop(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
{
- bool exclusive = (labelfile == NULL);
bool backup_started_in_recovery = false;
XLogRecPtr startpoint;
XLogRecPtr stoppoint;
@@ -8627,7 +8424,6 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
char histfilename[MAXFNAMELEN];
char backupfrom[20];
XLogSegNo _logSegNo;
- FILE *lfp;
FILE *fp;
char ch;
int seconds_before_warning;
@@ -8640,15 +8436,6 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
backup_started_in_recovery = RecoveryInProgress();
- /*
- * Currently only non-exclusive backup can be taken during recovery.
- */
- if (backup_started_in_recovery && exclusive)
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("recovery is in progress"),
- errhint("WAL control functions cannot be executed during recovery.")));
-
/*
* During recovery, we don't need to check WAL level. Because, if WAL
* level is not sufficient, it's impossible to get here during recovery.
@@ -8659,106 +8446,23 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
errmsg("WAL level not sufficient for making an online backup"),
errhint("wal_level must be set to \"replica\" or \"logical\" at server start.")));
- if (exclusive)
- {
- /*
- * At first, mark that we're now stopping an exclusive backup, to
- * ensure that there are no other sessions currently running
- * pg_start_backup() or pg_stop_backup().
- */
- WALInsertLockAcquireExclusive();
- if (XLogCtl->Insert.exclusiveBackupState != EXCLUSIVE_BACKUP_IN_PROGRESS)
- {
- WALInsertLockRelease();
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("exclusive backup not in progress")));
- }
- XLogCtl->Insert.exclusiveBackupState = EXCLUSIVE_BACKUP_STOPPING;
- WALInsertLockRelease();
-
- /*
- * Remove backup_label. In case of failure, the state for an exclusive
- * backup is switched back to in-progress.
- */
- PG_ENSURE_ERROR_CLEANUP(pg_stop_backup_callback, (Datum) BoolGetDatum(exclusive));
- {
- /*
- * Read the existing label file into memory.
- */
- struct stat statbuf;
- int r;
-
- if (stat(BACKUP_LABEL_FILE, &statbuf))
- {
- /* should not happen per the upper checks */
- if (errno != ENOENT)
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not stat file \"%s\": %m",
- BACKUP_LABEL_FILE)));
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("a backup is not in progress")));
- }
-
- lfp = AllocateFile(BACKUP_LABEL_FILE, "r");
- if (!lfp)
- {
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not read file \"%s\": %m",
- BACKUP_LABEL_FILE)));
- }
- labelfile = palloc(statbuf.st_size + 1);
- r = fread(labelfile, statbuf.st_size, 1, lfp);
- labelfile[statbuf.st_size] = '\0';
-
- /*
- * Close and remove the backup label file
- */
- if (r != 1 || ferror(lfp) || FreeFile(lfp))
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not read file \"%s\": %m",
- BACKUP_LABEL_FILE)));
- durable_unlink(BACKUP_LABEL_FILE, ERROR);
-
- /*
- * Remove tablespace_map file if present, it is created only if
- * there are tablespaces.
- */
- durable_unlink(TABLESPACE_MAP, DEBUG1);
- }
- PG_END_ENSURE_ERROR_CLEANUP(pg_stop_backup_callback, (Datum) BoolGetDatum(exclusive));
- }
-
/*
- * OK to update backup counters, forcePageWrites and session-level lock.
+ * OK to update backup counters, forcePageWrites, and session-level lock.
*
* Note that CHECK_FOR_INTERRUPTS() must not occur while updating them.
* Otherwise they can be updated inconsistently, and which might cause
* do_pg_abort_backup() to fail.
*/
WALInsertLockAcquireExclusive();
- if (exclusive)
- {
- XLogCtl->Insert.exclusiveBackupState = EXCLUSIVE_BACKUP_NONE;
- }
- else
- {
- /*
- * The user-visible pg_start/stop_backup() functions that operate on
- * exclusive backups can be called at any time, but for non-exclusive
- * backups, it is expected that each do_pg_start_backup() call is
- * matched by exactly one do_pg_stop_backup() call.
- */
- Assert(XLogCtl->Insert.nonExclusiveBackups > 0);
- XLogCtl->Insert.nonExclusiveBackups--;
- }
- if (XLogCtl->Insert.exclusiveBackupState == EXCLUSIVE_BACKUP_NONE &&
- XLogCtl->Insert.nonExclusiveBackups == 0)
+ /*
+ * It is expected that each do_pg_backup_start() call is matched by exactly
+ * one do_pg_backup_stop() call.
+ */
+ Assert(XLogCtl->Insert.runningBackups > 0);
+ XLogCtl->Insert.runningBackups--;
+
+ if (XLogCtl->Insert.runningBackups == 0)
{
XLogCtl->Insert.forcePageWrites = false;
}
@@ -9016,17 +8720,13 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
/*
* do_pg_abort_backup: abort a running backup
*
- * This does just the most basic steps of do_pg_stop_backup(), by taking the
+ * This does just the most basic steps of do_pg_backup_stop(), by taking the
* system out of backup mode, thus making it a lot more safe to call from
* an error handler.
*
* The caller can pass 'arg' as 'true' or 'false' to control whether a warning
* is emitted.
*
- * NB: This is only for aborting a non-exclusive backup that doesn't write
- * backup_label. A backup started with pg_start_backup() needs to be finished
- * with pg_stop_backup().
- *
* NB: This gets used as a before_shmem_exit handler, hence the odd-looking
* signature.
*/
@@ -9036,18 +8736,16 @@ do_pg_abort_backup(int code, Datum arg)
bool emit_warning = DatumGetBool(arg);
/*
- * Quick exit if session is not keeping around a non-exclusive backup
- * already started.
+ * Quick exit if session does not have a running backup.
*/
- if (sessionBackupState != SESSION_BACKUP_NON_EXCLUSIVE)
+ if (sessionBackupState != SESSION_BACKUP_RUNNING)
return;
WALInsertLockAcquireExclusive();
- Assert(XLogCtl->Insert.nonExclusiveBackups > 0);
- XLogCtl->Insert.nonExclusiveBackups--;
+ Assert(XLogCtl->Insert.runningBackups > 0);
+ XLogCtl->Insert.runningBackups--;
- if (XLogCtl->Insert.exclusiveBackupState == EXCLUSIVE_BACKUP_NONE &&
- XLogCtl->Insert.nonExclusiveBackups == 0)
+ if (XLogCtl->Insert.runningBackups == 0)
{
XLogCtl->Insert.forcePageWrites = false;
}
@@ -9055,7 +8753,7 @@ do_pg_abort_backup(int code, Datum arg)
if (emit_warning)
ereport(WARNING,
- (errmsg("aborting backup due to backend exiting before pg_stop_backup was called")));
+ (errmsg("aborting backup due to backend exiting before pg_backup_stop was called")));
}
/*
@@ -9115,87 +8813,6 @@ GetOldestRestartPoint(XLogRecPtr *oldrecptr, TimeLineID *oldtli)
LWLockRelease(ControlFileLock);
}
-/*
- * BackupInProgress: check if online backup mode is active
- *
- * This is done by checking for existence of the "backup_label" file.
- */
-bool
-BackupInProgress(void)
-{
- struct stat stat_buf;
-
- return (stat(BACKUP_LABEL_FILE, &stat_buf) == 0);
-}
-
-/*
- * CancelBackup: rename the "backup_label" and "tablespace_map"
- * files to cancel backup mode
- *
- * If the "backup_label" file exists, it will be renamed to "backup_label.old".
- * Similarly, if the "tablespace_map" file exists, it will be renamed to
- * "tablespace_map.old".
- *
- * Note that this will render an online backup in progress
- * useless. To correctly finish an online backup, pg_stop_backup must be
- * called.
- */
-void
-CancelBackup(void)
-{
- struct stat stat_buf;
-
- /* if the backup_label file is not there, return */
- if (stat(BACKUP_LABEL_FILE, &stat_buf) < 0)
- return;
-
- /* remove leftover file from previously canceled backup if it exists */
- unlink(BACKUP_LABEL_OLD);
-
- if (durable_rename(BACKUP_LABEL_FILE, BACKUP_LABEL_OLD, DEBUG1) != 0)
- {
- ereport(WARNING,
- (errcode_for_file_access(),
- errmsg("online backup mode was not canceled"),
- errdetail("File \"%s\" could not be renamed to \"%s\": %m.",
- BACKUP_LABEL_FILE, BACKUP_LABEL_OLD)));
- return;
- }
-
- /* if the tablespace_map file is not there, return */
- if (stat(TABLESPACE_MAP, &stat_buf) < 0)
- {
- ereport(LOG,
- (errmsg("online backup mode canceled"),
- errdetail("File \"%s\" was renamed to \"%s\".",
- BACKUP_LABEL_FILE, BACKUP_LABEL_OLD)));
- return;
- }
-
- /* remove leftover file from previously canceled backup if it exists */
- unlink(TABLESPACE_MAP_OLD);
-
- if (durable_rename(TABLESPACE_MAP, TABLESPACE_MAP_OLD, DEBUG1) == 0)
- {
- ereport(LOG,
- (errmsg("online backup mode canceled"),
- errdetail("Files \"%s\" and \"%s\" were renamed to "
- "\"%s\" and \"%s\", respectively.",
- BACKUP_LABEL_FILE, TABLESPACE_MAP,
- BACKUP_LABEL_OLD, TABLESPACE_MAP_OLD)));
- }
- else
- {
- ereport(WARNING,
- (errcode_for_file_access(),
- errmsg("online backup mode canceled"),
- errdetail("File \"%s\" was renamed to \"%s\", but "
- "file \"%s\" could not be renamed to \"%s\": %m.",
- BACKUP_LABEL_FILE, BACKUP_LABEL_OLD,
- TABLESPACE_MAP, TABLESPACE_MAP_OLD)));
- }
-}
-
/* Thin wrapper around ShutdownWalRcv(). */
void
XLogShutdownWalRcv(void)
diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c
index 2752be63c1..b61ae6c0b4 100644
--- a/src/backend/access/transam/xlogfuncs.c
+++ b/src/backend/access/transam/xlogfuncs.c
@@ -39,13 +39,13 @@
#include "utils/tuplestore.h"
/*
- * Store label file and tablespace map during non-exclusive backups.
+ * Store label file and tablespace map during backups.
*/
static StringInfo label_file;
static StringInfo tblspc_map_file;
/*
- * pg_start_backup: set up for taking an on-line backup dump
+ * pg_backup_start: set up for taking an on-line backup dump
*
* Essentially what this does is to create a backup label file in $PGDATA,
* where it will be archived as part of the backup dump. The label file
@@ -57,105 +57,44 @@ static StringInfo tblspc_map_file;
* GRANT system.
*/
Datum
-pg_start_backup(PG_FUNCTION_ARGS)
+pg_backup_start(PG_FUNCTION_ARGS)
{
text *backupid = PG_GETARG_TEXT_PP(0);
bool fast = PG_GETARG_BOOL(1);
- bool exclusive = PG_GETARG_BOOL(2);
char *backupidstr;
XLogRecPtr startpoint;
SessionBackupState status = get_backup_status();
+ MemoryContext oldcontext;
backupidstr = text_to_cstring(backupid);
- if (status == SESSION_BACKUP_NON_EXCLUSIVE)
+ if (status == SESSION_BACKUP_RUNNING)
ereport(ERROR,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("a backup is already in progress in this session")));
- if (exclusive)
- {
- startpoint = do_pg_start_backup(backupidstr, fast, NULL, NULL,
- NULL, NULL);
- }
- else
- {
- MemoryContext oldcontext;
-
- /*
- * Label file and tablespace map file need to be long-lived, since
- * they are read in pg_stop_backup.
- */
- oldcontext = MemoryContextSwitchTo(TopMemoryContext);
- label_file = makeStringInfo();
- tblspc_map_file = makeStringInfo();
- MemoryContextSwitchTo(oldcontext);
+ /*
+ * Label file and tablespace map file need to be long-lived, since
+ * they are read in pg_backup_stop.
+ */
+ oldcontext = MemoryContextSwitchTo(TopMemoryContext);
+ label_file = makeStringInfo();
+ tblspc_map_file = makeStringInfo();
+ MemoryContextSwitchTo(oldcontext);
- register_persistent_abort_backup_handler();
+ register_persistent_abort_backup_handler();
- startpoint = do_pg_start_backup(backupidstr, fast, NULL, label_file,
- NULL, tblspc_map_file);
- }
+ startpoint = do_pg_backup_start(backupidstr, fast, NULL, label_file,
+ NULL, tblspc_map_file);
PG_RETURN_LSN(startpoint);
}
-/*
- * pg_stop_backup: finish taking an on-line backup dump
- *
- * We write an end-of-backup WAL record, and remove the backup label file
- * created by pg_start_backup, creating a backup history file in pg_wal
- * instead (whence it will immediately be archived). The backup history file
- * contains the same info found in the label file, plus the backup-end time
- * and WAL location. Before 9.0, the backup-end time was read from the backup
- * history file at the beginning of archive recovery, but we now use the WAL
- * record for that and the file is for informational and debug purposes only.
- *
- * Note: different from CancelBackup which just cancels online backup mode.
- *
- * Note: this version is only called to stop an exclusive backup. The function
- * pg_stop_backup_v2 (overloaded as pg_stop_backup in SQL) is called to
- * stop non-exclusive backups.
- *
- * Permission checking for this function is managed through the normal
- * GRANT system.
- */
-Datum
-pg_stop_backup(PG_FUNCTION_ARGS)
-{
- XLogRecPtr stoppoint;
- SessionBackupState status = get_backup_status();
-
- if (status == SESSION_BACKUP_NON_EXCLUSIVE)
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("non-exclusive backup in progress"),
- errhint("Did you mean to use pg_stop_backup('f')?")));
-
- /*
- * Exclusive backups were typically started in a different connection, so
- * don't try to verify that status of backup is set to
- * SESSION_BACKUP_EXCLUSIVE in this function. Actual verification that an
- * exclusive backup is in fact running is handled inside
- * do_pg_stop_backup.
- */
- stoppoint = do_pg_stop_backup(NULL, true, NULL);
-
- PG_RETURN_LSN(stoppoint);
-}
-
/*
- * pg_stop_backup_v2: finish taking exclusive or nonexclusive on-line backup.
- *
- * Works the same as pg_stop_backup, except for non-exclusive backups it returns
- * the backup label and tablespace map files as text fields in as part of the
- * resultset.
+ * pg_backup_stop: finish taking an on-line backup.
*
- * The first parameter (variable 'exclusive') allows the user to tell us if
- * this is an exclusive or a non-exclusive backup.
- *
- * The second parameter (variable 'waitforarchive'), which is optional,
+ * The first parameter (variable 'waitforarchive'), which is optional,
* allows the user to choose if they want to wait for the WAL to be archived
* or if we should just return as soon as the WAL record is written.
*
@@ -163,15 +102,14 @@ pg_stop_backup(PG_FUNCTION_ARGS)
* GRANT system.
*/
Datum
-pg_stop_backup_v2(PG_FUNCTION_ARGS)
+pg_backup_stop(PG_FUNCTION_ARGS)
{
#define PG_STOP_BACKUP_V2_COLS 3
TupleDesc tupdesc;
Datum values[PG_STOP_BACKUP_V2_COLS];
bool nulls[PG_STOP_BACKUP_V2_COLS];
- bool exclusive = PG_GETARG_BOOL(0);
- bool waitforarchive = PG_GETARG_BOOL(1);
+ bool waitforarchive = PG_GETARG_BOOL(0);
XLogRecPtr stoppoint;
SessionBackupState status = get_backup_status();
@@ -182,51 +120,29 @@ pg_stop_backup_v2(PG_FUNCTION_ARGS)
MemSet(values, 0, sizeof(values));
MemSet(nulls, 0, sizeof(nulls));
- if (exclusive)
- {
- if (status == SESSION_BACKUP_NON_EXCLUSIVE)
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("non-exclusive backup in progress"),
- errhint("Did you mean to use pg_stop_backup('f')?")));
-
- /*
- * Stop the exclusive backup, and since we're in an exclusive backup
- * return NULL for both backup_label and tablespace_map.
- */
- stoppoint = do_pg_stop_backup(NULL, waitforarchive, NULL);
-
- nulls[1] = true;
- nulls[2] = true;
- }
- else
- {
- if (status != SESSION_BACKUP_NON_EXCLUSIVE)
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("non-exclusive backup is not in progress"),
- errhint("Did you mean to use pg_stop_backup('t')?")));
+ if (status != SESSION_BACKUP_RUNNING)
+ ereport(ERROR,
+ (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ errmsg("backup is not in progress"),
+ errhint("Did you call pg_backup_start()?")));
- /*
- * Stop the non-exclusive backup. Return a copy of the backup label
- * and tablespace map so they can be written to disk by the caller.
- */
- stoppoint = do_pg_stop_backup(label_file->data, waitforarchive, NULL);
-
- values[1] = CStringGetTextDatum(label_file->data);
- values[2] = CStringGetTextDatum(tblspc_map_file->data);
-
- /* Free structures allocated in TopMemoryContext */
- pfree(label_file->data);
- pfree(label_file);
- label_file = NULL;
- pfree(tblspc_map_file->data);
- pfree(tblspc_map_file);
- tblspc_map_file = NULL;
- }
+ /*
+ * Stop the backup. Return a copy of the backup label and tablespace map so
+ * they can be written to disk by the caller.
+ */
+ stoppoint = do_pg_backup_stop(label_file->data, waitforarchive, NULL);
- /* Stoppoint is included on both exclusive and nonexclusive backups */
values[0] = LSNGetDatum(stoppoint);
+ values[1] = CStringGetTextDatum(label_file->data);
+ values[2] = CStringGetTextDatum(tblspc_map_file->data);
+
+ /* Free structures allocated in TopMemoryContext */
+ pfree(label_file->data);
+ pfree(label_file);
+ label_file = NULL;
+ pfree(tblspc_map_file->data);
+ pfree(tblspc_map_file);
+ tblspc_map_file = NULL;
/* Returns the record as Datum */
PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
@@ -298,7 +214,7 @@ pg_create_restore_point(PG_FUNCTION_ARGS)
}
/*
- * Report the current WAL write location (same format as pg_start_backup etc)
+ * Report the current WAL write location (same format as pg_backup_start etc)
*
* This is useful for determining how much of WAL is visible to an external
* archiving process. Note that the data before this point is written out
@@ -321,7 +237,7 @@ pg_current_wal_lsn(PG_FUNCTION_ARGS)
}
/*
- * Report the current WAL insert location (same format as pg_start_backup etc)
+ * Report the current WAL insert location (same format as pg_backup_start etc)
*
* This function is mostly for debugging purposes.
*/
@@ -342,7 +258,7 @@ pg_current_wal_insert_lsn(PG_FUNCTION_ARGS)
}
/*
- * Report the current WAL flush location (same format as pg_start_backup etc)
+ * Report the current WAL flush location (same format as pg_backup_start etc)
*
* This function is mostly for debugging purposes.
*/
@@ -363,7 +279,7 @@ pg_current_wal_flush_lsn(PG_FUNCTION_ARGS)
}
/*
- * Report the last WAL receive location (same format as pg_start_backup etc)
+ * Report the last WAL receive location (same format as pg_backup_start etc)
*
* This is useful for determining how much of WAL is guaranteed to be received
* and synced to disk by walreceiver.
@@ -382,7 +298,7 @@ pg_last_wal_receive_lsn(PG_FUNCTION_ARGS)
}
/*
- * Report the last WAL replay location (same format as pg_start_backup etc)
+ * Report the last WAL replay location (same format as pg_backup_start etc)
*
* This is useful for determining how much of WAL is visible to read-only
* connections during recovery.
@@ -402,7 +318,7 @@ pg_last_wal_replay_lsn(PG_FUNCTION_ARGS)
/*
* Compute an xlog file name and decimal byte offset given a WAL location,
- * such as is returned by pg_stop_backup() or pg_switch_wal().
+ * such as is returned by pg_backup_stop() or pg_switch_wal().
*
* Note that a location exactly at a segment boundary is taken to be in
* the previous segment. This is usually the right thing, since the
@@ -470,7 +386,7 @@ pg_walfile_name_offset(PG_FUNCTION_ARGS)
/*
* Compute an xlog file name given a WAL location,
- * such as is returned by pg_stop_backup() or pg_switch_wal().
+ * such as is returned by pg_backup_stop() or pg_switch_wal().
*/
Datum
pg_walfile_name(PG_FUNCTION_ARGS)
@@ -645,81 +561,6 @@ pg_wal_lsn_diff(PG_FUNCTION_ARGS)
PG_RETURN_NUMERIC(result);
}
-/*
- * Returns bool with current on-line backup mode, a global state.
- */
-Datum
-pg_is_in_backup(PG_FUNCTION_ARGS)
-{
- PG_RETURN_BOOL(BackupInProgress());
-}
-
-/*
- * Returns start time of an online exclusive backup.
- *
- * When there's no exclusive backup in progress, the function
- * returns NULL.
- */
-Datum
-pg_backup_start_time(PG_FUNCTION_ARGS)
-{
- Datum xtime;
- FILE *lfp;
- char fline[MAXPGPATH];
- char backup_start_time[30];
-
- /*
- * See if label file is present
- */
- lfp = AllocateFile(BACKUP_LABEL_FILE, "r");
- if (lfp == NULL)
- {
- if (errno != ENOENT)
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not read file \"%s\": %m",
- BACKUP_LABEL_FILE)));
- PG_RETURN_NULL();
- }
-
- /*
- * Parse the file to find the START TIME line.
- */
- backup_start_time[0] = '\0';
- while (fgets(fline, sizeof(fline), lfp) != NULL)
- {
- if (sscanf(fline, "START TIME: %25[^\n]\n", backup_start_time) == 1)
- break;
- }
-
- /* Check for a read error. */
- if (ferror(lfp))
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not read file \"%s\": %m", BACKUP_LABEL_FILE)));
-
- /* Close the backup label file. */
- if (FreeFile(lfp))
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not close file \"%s\": %m", BACKUP_LABEL_FILE)));
-
- if (strlen(backup_start_time) == 0)
- ereport(ERROR,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("invalid data in file \"%s\"", BACKUP_LABEL_FILE)));
-
- /*
- * Convert the time string read from file to TimestampTz form.
- */
- xtime = DirectFunctionCall3(timestamptz_in,
- CStringGetDatum(backup_start_time),
- ObjectIdGetDatum(InvalidOid),
- Int32GetDatum(-1));
-
- PG_RETURN_DATUM(xtime);
-}
-
/*
* Promotes a standby server.
*
diff --git a/src/backend/access/transam/xlogrecovery.c b/src/backend/access/transam/xlogrecovery.c
index 8d2395dae2..1b7bae387a 100644
--- a/src/backend/access/transam/xlogrecovery.c
+++ b/src/backend/access/transam/xlogrecovery.c
@@ -1183,9 +1183,14 @@ read_backup_label(XLogRecPtr *checkPointLoc, TimeLineID *backupLabelTLI,
*backupLabelTLI = tli_from_walseg;
/*
- * BACKUP METHOD and BACKUP FROM lines are new in 9.2. We can't restore
- * from an older backup anyway, but since the information on it is not
- * strictly required, don't error out if it's missing for some reason.
+ * BACKUP METHOD lets us know if this was a typical backup ("streamed",
+ * which could mean either pg_basebackup or the pg_backup_start/stop
+ * method was used) or if this label came from somewhere else (the only
+ * other option today being from pg_rewind). If this was a streamed
+ * backup then we know that we need to play through until we get to the
+ * end of the WAL which was generated during the backup (at which point
+ * we will have reached consistency and backupEndRequired will be reset
+ * to be false).
*/
if (fscanf(lfp, "BACKUP METHOD: %19s\n", backuptype) == 1)
{
@@ -1193,6 +1198,11 @@ read_backup_label(XLogRecPtr *checkPointLoc, TimeLineID *backupLabelTLI,
*backupEndRequired = true;
}
+ /*
+ * BACKUP FROM lets us know if this was from a primary or a standby. If
+ * it was from a standby, we'll double-check that the control file state
+ * matches that of a standby.
+ */
if (fscanf(lfp, "BACKUP FROM: %19s\n", backupfrom) == 1)
{
if (strcmp(backupfrom, "standby") == 0)
@@ -1970,7 +1980,7 @@ xlogrecovery_redo(XLogReaderState *record, TimeLineID replayTLI)
{
/*
* We have reached the end of base backup, the point where
- * pg_stop_backup() was done. The data on disk is now consistent
+ * pg_backup_stop() was done. The data on disk is now consistent
* (assuming we have also reached minRecoveryPoint). Set
* backupEndPoint to the current LSN, so that the next call to
* CheckRecoveryConsistency() will notice it and do the
@@ -2033,7 +2043,7 @@ CheckRecoveryConsistency(void)
/*
* Have we passed our safe starting point? Note that minRecoveryPoint is
- * known to be incorrectly set if ControlFile->backupEndRequired, until
+ * known to be incorrectly set if recovering from a backup, until
* the XLOG_BACKUP_END arrives to advise us of the correct
* minRecoveryPoint. All we know prior to that is that we're not
* consistent yet.
diff --git a/src/backend/catalog/system_functions.sql b/src/backend/catalog/system_functions.sql
index 81bac6f581..6ae4388d3f 100644
--- a/src/backend/catalog/system_functions.sql
+++ b/src/backend/catalog/system_functions.sql
@@ -377,14 +377,14 @@ BEGIN ATOMIC
END;
CREATE OR REPLACE FUNCTION
- pg_start_backup(label text, fast boolean DEFAULT false, exclusive boolean DEFAULT true)
- RETURNS pg_lsn STRICT VOLATILE LANGUAGE internal AS 'pg_start_backup'
+ pg_backup_start(label text, fast boolean DEFAULT false)
+ RETURNS pg_lsn STRICT VOLATILE LANGUAGE internal AS 'pg_backup_start'
PARALLEL RESTRICTED;
-CREATE OR REPLACE FUNCTION pg_stop_backup (
- exclusive boolean, wait_for_archive boolean DEFAULT true,
- OUT lsn pg_lsn, OUT labelfile text, OUT spcmapfile text)
- RETURNS record STRICT VOLATILE LANGUAGE internal as 'pg_stop_backup_v2'
+CREATE OR REPLACE FUNCTION pg_backup_stop (
+ wait_for_archive boolean DEFAULT true, OUT lsn pg_lsn,
+ OUT labelfile text, OUT spcmapfile text)
+ RETURNS record STRICT VOLATILE LANGUAGE internal as 'pg_backup_stop'
PARALLEL RESTRICTED;
CREATE OR REPLACE FUNCTION
@@ -603,11 +603,9 @@ AS 'unicode_is_normalized';
-- available to superuser / cluster owner, if they choose.
--
-REVOKE EXECUTE ON FUNCTION pg_start_backup(text, boolean, boolean) FROM public;
+REVOKE EXECUTE ON FUNCTION pg_backup_start(text, boolean) FROM public;
-REVOKE EXECUTE ON FUNCTION pg_stop_backup() FROM public;
-
-REVOKE EXECUTE ON FUNCTION pg_stop_backup(boolean, boolean) FROM public;
+REVOKE EXECUTE ON FUNCTION pg_backup_stop(boolean) FROM public;
REVOKE EXECUTE ON FUNCTION pg_create_restore_point(text) FROM public;
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index 80bb269599..9f7034df11 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -345,14 +345,7 @@ static PMState pmState = PM_INIT;
* connsAllowed is a sub-state indicator showing the active restriction.
* It is of no interest unless pmState is PM_RUN or PM_HOT_STANDBY.
*/
-typedef enum
-{
- ALLOW_ALL_CONNS, /* normal not-shutting-down state */
- ALLOW_SUPERUSER_CONNS, /* only superusers can connect */
- ALLOW_NO_CONNS /* no new connections allowed, period */
-} ConnsAllowedState;
-
-static ConnsAllowedState connsAllowed = ALLOW_ALL_CONNS;
+static bool connsAllowed = true;
/* Start time of SIGKILL timeout during immediate shutdown or child crash */
/* Zero means timeout is not running */
@@ -2409,9 +2402,6 @@ retry1:
(errcode(ERRCODE_TOO_MANY_CONNECTIONS),
errmsg("sorry, too many clients already")));
break;
- case CAC_SUPERUSER:
- /* OK for now, will check in InitPostgres */
- break;
case CAC_OK:
break;
}
@@ -2546,19 +2536,10 @@ canAcceptConnections(int backend_type)
/*
* "Smart shutdown" restrictions are applied only to normal connections,
- * not to autovac workers or bgworkers. When only superusers can connect,
- * we return CAC_SUPERUSER to indicate that superuserness must be checked
- * later. Note that neither CAC_OK nor CAC_SUPERUSER can safely be
- * returned until we have checked for too many children.
+ * not to autovac workers or bgworkers.
*/
- if (connsAllowed != ALLOW_ALL_CONNS &&
- backend_type == BACKEND_TYPE_NORMAL)
- {
- if (connsAllowed == ALLOW_SUPERUSER_CONNS)
- result = CAC_SUPERUSER; /* allow superusers only */
- else
- return CAC_SHUTDOWN; /* shutdown is pending */
- }
+ if (!connsAllowed && backend_type == BACKEND_TYPE_NORMAL)
+ return CAC_SHUTDOWN; /* shutdown is pending */
/*
* Don't start too many children.
@@ -2877,17 +2858,12 @@ pmdie(SIGNAL_ARGS)
#endif
/*
- * If we reached normal running, we have to wait for any online
- * backup mode to end; otherwise go straight to waiting for client
- * backends to exit. (The difference is that in the former state,
- * we'll still let in new superuser clients, so that somebody can
- * end the online backup mode.) If already in PM_STOP_BACKENDS or
+ * If we reached normal running, we go straight to waiting for
+ * client backends to exit. If already in PM_STOP_BACKENDS or
* a later state, do not change it.
*/
- if (pmState == PM_RUN)
- connsAllowed = ALLOW_SUPERUSER_CONNS;
- else if (pmState == PM_HOT_STANDBY)
- connsAllowed = ALLOW_NO_CONNS;
+ if (pmState == PM_RUN || pmState == PM_HOT_STANDBY)
+ connsAllowed = false;
else if (pmState == PM_STARTUP || pmState == PM_RECOVERY)
{
/* There should be no clients, so proceed to stop children */
@@ -3099,7 +3075,7 @@ reaper(SIGNAL_ARGS)
AbortStartTime = 0;
ReachedNormalRunning = true;
pmState = PM_RUN;
- connsAllowed = ALLOW_ALL_CONNS;
+ connsAllowed = true;
/*
* Crank up the background tasks, if we didn't do that already
@@ -3842,21 +3818,11 @@ PostmasterStateMachine(void)
/* If we're doing a smart shutdown, try to advance that state. */
if (pmState == PM_RUN || pmState == PM_HOT_STANDBY)
{
- if (connsAllowed == ALLOW_SUPERUSER_CONNS)
+ if (!connsAllowed)
{
/*
- * ALLOW_SUPERUSER_CONNS state ends as soon as online backup mode
- * is not active.
- */
- if (!BackupInProgress())
- connsAllowed = ALLOW_NO_CONNS;
- }
-
- if (connsAllowed == ALLOW_NO_CONNS)
- {
- /*
- * ALLOW_NO_CONNS state ends when we have no normal client
- * backends running. Then we're ready to stop other children.
+ * This state ends when we have no normal client backends running.
+ * Then we're ready to stop other children.
*/
if (CountChildren(BACKEND_TYPE_NORMAL) == 0)
pmState = PM_STOP_BACKENDS;
@@ -4044,18 +4010,6 @@ PostmasterStateMachine(void)
}
else
{
- /*
- * Terminate exclusive backup mode to avoid recovery after a clean
- * fast shutdown. Since an exclusive backup can only be taken
- * during normal running (and not, for example, while running
- * under Hot Standby) it only makes sense to do this if we reached
- * normal running. If we're still in recovery, the backup file is
- * one we're recovering *from*, and we must keep it around so that
- * recovery restarts from the right place.
- */
- if (ReachedNormalRunning)
- CancelBackup();
-
/*
* Normal exit from the postmaster is here. We don't need to log
* anything here, since the UnlinkLockFiles proc_exit callback
@@ -4277,8 +4231,7 @@ BackendStartup(Port *port)
/* Pass down canAcceptConnections state */
port->canAcceptConnections = canAcceptConnections(BACKEND_TYPE_NORMAL);
- bn->dead_end = (port->canAcceptConnections != CAC_OK &&
- port->canAcceptConnections != CAC_SUPERUSER);
+ bn->dead_end = (port->canAcceptConnections != CAC_OK);
/*
* Unless it's a dead_end child, assign it a child slot number
@@ -5287,7 +5240,7 @@ sigusr1_handler(SIGNAL_ARGS)
#endif
pmState = PM_HOT_STANDBY;
- connsAllowed = ALLOW_ALL_CONNS;
+ connsAllowed = true;
/* Some workers may be scheduled to start now */
StartWorkerNeeded = true;
diff --git a/src/backend/replication/basebackup.c b/src/backend/replication/basebackup.c
index 6884cad2c0..815681ada7 100644
--- a/src/backend/replication/basebackup.c
+++ b/src/backend/replication/basebackup.c
@@ -184,10 +184,8 @@ static const struct exclude_list_item excludeFiles[] =
{RELCACHE_INIT_FILENAME, true},
/*
- * If there's a backup_label or tablespace_map file, it belongs to a
- * backup started by the user with pg_start_backup(). It is *not* correct
- * for this backup. Our backup_label/tablespace_map is injected into the
- * tar separately.
+ * backup_label and tablespace_map should not exist in in a running cluster
+ * capable of doing an online backup, but exclude them just in case.
*/
{BACKUP_LABEL_FILE, false},
{TABLESPACE_MAP, false},
@@ -264,16 +262,16 @@ perform_base_backup(basebackup_options *opt, bbsink *sink)
total_checksum_failures = 0;
basebackup_progress_wait_checkpoint();
- state.startptr = do_pg_start_backup(opt->label, opt->fastcheckpoint,
+ state.startptr = do_pg_backup_start(opt->label, opt->fastcheckpoint,
&state.starttli,
labelfile, &state.tablespaces,
tblspc_map_file);
/*
- * Once do_pg_start_backup has been called, ensure that any failure causes
+ * Once do_pg_backup_start has been called, ensure that any failure causes
* us to abort the backup so we don't "leak" a backup counter. For this
- * reason, *all* functionality between do_pg_start_backup() and the end of
- * do_pg_stop_backup() should be inside the error cleanup block!
+ * reason, *all* functionality between do_pg_backup_start() and the end of
+ * do_pg_backup_stop() should be inside the error cleanup block!
*/
PG_ENSURE_ERROR_CLEANUP(do_pg_abort_backup, BoolGetDatum(false));
@@ -394,7 +392,7 @@ perform_base_backup(basebackup_options *opt, bbsink *sink)
}
basebackup_progress_wait_wal_archive(&state);
- endptr = do_pg_stop_backup(labelfile->data, !opt->nowait, &endtli);
+ endptr = do_pg_backup_stop(labelfile->data, !opt->nowait, &endtli);
}
PG_END_ENSURE_ERROR_CLEANUP(do_pg_abort_backup, BoolGetDatum(false));
@@ -961,7 +959,7 @@ parse_basebackup_options(List *options, basebackup_options *opt)
/*
* SendBaseBackup() - send a complete base backup.
*
- * The function will put the system into backup mode like pg_start_backup()
+ * The function will put the system into backup mode like pg_backup_start()
* does, so that the backup is consistent even though we read directly from
* the filesystem, bypassing the buffer cache.
*/
@@ -1204,7 +1202,7 @@ sendDir(bbsink *sink, const char *path, int basepathlen, bool sizeonly,
* error in that case. The error handler further up will call
* do_pg_abort_backup() for us. Also check that if the backup was
* started while still in recovery, the server wasn't promoted.
- * do_pg_stop_backup() will check that too, but it's better to stop
+ * do_pg_backup_stop() will check that too, but it's better to stop
* the backup early than continue to the end and fail there.
*/
CHECK_FOR_INTERRUPTS();
diff --git a/src/backend/utils/init/postinit.c b/src/backend/utils/init/postinit.c
index 6452b42dbf..342169b195 100644
--- a/src/backend/utils/init/postinit.c
+++ b/src/backend/utils/init/postinit.c
@@ -871,24 +871,6 @@ InitPostgres(const char *in_dbname, Oid dboid, const char *username,
am_superuser = superuser();
}
- /*
- * If we're trying to shut down, only superusers can connect, and new
- * replication connections are not allowed.
- */
- if ((!am_superuser || am_walsender) &&
- MyProcPort != NULL &&
- MyProcPort->canAcceptConnections == CAC_SUPERUSER)
- {
- if (am_walsender)
- ereport(FATAL,
- (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
- errmsg("new replication connections are not allowed during database shutdown")));
- else
- ereport(FATAL,
- (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
- errmsg("must be superuser to connect during database shutdown")));
- }
-
/*
* Binary upgrades only allowed super-user connections
*/
diff --git a/src/bin/pg_basebackup/t/010_pg_basebackup.pl b/src/bin/pg_basebackup/t/010_pg_basebackup.pl
index 5ba84c2250..7309ebddea 100644
--- a/src/bin/pg_basebackup/t/010_pg_basebackup.pl
+++ b/src/bin/pg_basebackup/t/010_pg_basebackup.pl
@@ -247,6 +247,10 @@ isnt(slurp_file("$tempdir/backup/backup_label"),
'DONOTCOPY', 'existing backup_label not copied');
rmtree("$tempdir/backup");
+# Now delete the bogus backup_label file since it will interfere with startup
+unlink("$pgdata/backup_label")
+ or BAIL_OUT("unable to unlink $pgdata/backup_label");
+
$node->command_ok(
[
@pg_basebackup_defs, '-D',
diff --git a/src/bin/pg_ctl/pg_ctl.c b/src/bin/pg_ctl/pg_ctl.c
index 3c182c97d4..3a9092a16a 100644
--- a/src/bin/pg_ctl/pg_ctl.c
+++ b/src/bin/pg_ctl/pg_ctl.c
@@ -1025,7 +1025,6 @@ static void
do_stop(void)
{
pgpid_t pid;
- struct stat statbuf;
pid = get_pgpid(false);
@@ -1058,20 +1057,6 @@ do_stop(void)
}
else
{
- /*
- * If backup_label exists, an online backup is running. Warn the user
- * that smart shutdown will wait for it to finish. However, if the
- * server is in archive recovery, we're recovering from an online
- * backup instead of performing one.
- */
- if (shutdown_mode == SMART_MODE &&
- stat(backup_file, &statbuf) == 0 &&
- get_control_dbstate() != DB_IN_ARCHIVE_RECOVERY)
- {
- print_msg(_("WARNING: online backup mode is active\n"
- "Shutdown will not complete until pg_stop_backup() is called.\n\n"));
- }
-
print_msg(_("waiting for server to shut down..."));
if (!wait_for_postmaster_stop())
@@ -1099,7 +1084,6 @@ static void
do_restart(void)
{
pgpid_t pid;
- struct stat statbuf;
pid = get_pgpid(false);
@@ -1134,20 +1118,6 @@ do_restart(void)
exit(1);
}
- /*
- * If backup_label exists, an online backup is running. Warn the user
- * that smart shutdown will wait for it to finish. However, if the
- * server is in archive recovery, we're recovering from an online
- * backup instead of performing one.
- */
- if (shutdown_mode == SMART_MODE &&
- stat(backup_file, &statbuf) == 0 &&
- get_control_dbstate() != DB_IN_ARCHIVE_RECOVERY)
- {
- print_msg(_("WARNING: online backup mode is active\n"
- "Shutdown will not complete until pg_stop_backup() is called.\n\n"));
- }
-
print_msg(_("waiting for server to shut down..."));
/* always wait for restart */
diff --git a/src/bin/pg_rewind/filemap.c b/src/bin/pg_rewind/filemap.c
index 7211090f47..fb52debf7a 100644
--- a/src/bin/pg_rewind/filemap.c
+++ b/src/bin/pg_rewind/filemap.c
@@ -140,9 +140,9 @@ static const struct exclude_list_item excludeFiles[] =
{"pg_internal.init", true}, /* defined as RELCACHE_INIT_FILENAME */
/*
- * If there's a backup_label or tablespace_map file, it belongs to a
- * backup started by the user with pg_start_backup(). It is *not* correct
- * for this backup. Our backup_label is written later on separately.
+ * If there is a backup_label or tablespace_map file, it indicates that
+ * a recovery failed and this cluster probably can't be rewound, but
+ * exclude them anyway if they are found.
*/
{"backup_label", false}, /* defined as BACKUP_LABEL_FILE */
{"tablespace_map", false}, /* defined as TABLESPACE_MAP */
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index 09f6464331..b81917f243 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -276,14 +276,13 @@ extern void XLogShutdownWalRcv(void);
typedef enum SessionBackupState
{
SESSION_BACKUP_NONE,
- SESSION_BACKUP_EXCLUSIVE,
- SESSION_BACKUP_NON_EXCLUSIVE
+ SESSION_BACKUP_RUNNING,
} SessionBackupState;
-extern XLogRecPtr do_pg_start_backup(const char *backupidstr, bool fast,
+extern XLogRecPtr do_pg_backup_start(const char *backupidstr, bool fast,
TimeLineID *starttli_p, StringInfo labelfile,
List **tablespaces, StringInfo tblspcmapfile);
-extern XLogRecPtr do_pg_stop_backup(char *labelfile, bool waitforarchive,
+extern XLogRecPtr do_pg_backup_stop(char *labelfile, bool waitforarchive,
TimeLineID *stoptli_p);
extern void do_pg_abort_backup(int code, Datum arg);
extern void register_persistent_abort_backup_handler(void);
diff --git a/src/include/catalog/pg_control.h b/src/include/catalog/pg_control.h
index 1f3dc24ac1..06368e2366 100644
--- a/src/include/catalog/pg_control.h
+++ b/src/include/catalog/pg_control.h
@@ -161,9 +161,7 @@ typedef struct ControlFileData
*
* If backupEndRequired is true, we know for sure that we're restoring
* from a backup, and must see a backup-end record before we can safely
- * start up. If it's false, but backupStartPoint is set, a backup_label
- * file was found at startup but it may have been a leftover from a stray
- * pg_start_backup() call, not accompanied by pg_stop_backup().
+ * start up.
*/
XLogRecPtr minRecoveryPoint;
TimeLineID minRecoveryPointTLI;
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 25304430f4..361a40a191 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -6274,26 +6274,16 @@
proargtypes => 'int4 int8', proargnames => '{pid,timeout}',
prosrc => 'pg_terminate_backend' },
{ oid => '2172', descr => 'prepare for taking an online backup',
- proname => 'pg_start_backup', provolatile => 'v', proparallel => 'r',
- prorettype => 'pg_lsn', proargtypes => 'text bool bool',
- prosrc => 'pg_start_backup' },
-{ oid => '2173', descr => 'finish taking an online backup',
- proname => 'pg_stop_backup', provolatile => 'v', proparallel => 'r',
- prorettype => 'pg_lsn', proargtypes => '', prosrc => 'pg_stop_backup' },
+ proname => 'pg_backup_start', provolatile => 'v', proparallel => 'r',
+ prorettype => 'pg_lsn', proargtypes => 'text bool',
+ prosrc => 'pg_backup_start' },
{ oid => '2739', descr => 'finish taking an online backup',
- proname => 'pg_stop_backup', provolatile => 'v', proparallel => 'r',
- prorettype => 'record', proargtypes => 'bool bool',
- proallargtypes => '{bool,bool,pg_lsn,text,text}',
- proargmodes => '{i,i,o,o,o}',
- proargnames => '{exclusive,wait_for_archive,lsn,labelfile,spcmapfile}',
- prosrc => 'pg_stop_backup_v2' },
-{ oid => '3813', descr => 'true if server is in online backup',
- proname => 'pg_is_in_backup', provolatile => 'v', prorettype => 'bool',
- proargtypes => '', prosrc => 'pg_is_in_backup' },
-{ oid => '3814', descr => 'start time of an online backup',
- proname => 'pg_backup_start_time', provolatile => 's',
- prorettype => 'timestamptz', proargtypes => '',
- prosrc => 'pg_backup_start_time' },
+ proname => 'pg_backup_stop', provolatile => 'v', proparallel => 'r',
+ prorettype => 'record', proargtypes => 'bool',
+ proallargtypes => '{bool,pg_lsn,text,text}',
+ proargmodes => '{i,o,o,o}',
+ proargnames => '{wait_for_archive,lsn,labelfile,spcmapfile}',
+ prosrc => 'pg_backup_stop' },
{ oid => '3436', descr => 'promote standby server',
proname => 'pg_promote', provolatile => 'v', prorettype => 'bool',
proargtypes => 'bool int4', proargnames => '{wait,wait_seconds}',
diff --git a/src/include/libpq/libpq-be.h b/src/include/libpq/libpq-be.h
index dd3e5efba3..c3bf514652 100644
--- a/src/include/libpq/libpq-be.h
+++ b/src/include/libpq/libpq-be.h
@@ -75,8 +75,7 @@ typedef enum CAC_state
CAC_SHUTDOWN,
CAC_RECOVERY,
CAC_NOTCONSISTENT,
- CAC_TOOMANY,
- CAC_SUPERUSER
+ CAC_TOOMANY
} CAC_state;
diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h
index 0abc3ad540..9321d7f264 100644
--- a/src/include/miscadmin.h
+++ b/src/include/miscadmin.h
@@ -481,10 +481,6 @@ extern void process_session_preload_libraries(void);
extern void pg_bindtextdomain(const char *domain);
extern bool has_rolreplication(Oid roleid);
-/* in access/transam/xlog.c */
-extern bool BackupInProgress(void);
-extern void CancelBackup(void);
-
/* in executor/nodeHash.c */
extern size_t get_hash_memory_limit(void);
diff --git a/src/test/perl/PostgreSQL/Test/Cluster.pm b/src/test/perl/PostgreSQL/Test/Cluster.pm
index b4ebc99935..1452297210 100644
--- a/src/test/perl/PostgreSQL/Test/Cluster.pm
+++ b/src/test/perl/PostgreSQL/Test/Cluster.pm
@@ -638,25 +638,6 @@ sub backup
return;
}
-=item $node->backup_fs_hot(backup_name)
-
-Create a backup with a filesystem level copy in subdirectory B<backup_name> of
-B<< $node->backup_dir >>, including WAL.
-
-Archiving must be enabled, as B<pg_start_backup()> and B<pg_stop_backup()> are
-used. This is not checked or enforced.
-
-The backup name is passed as the backup label to B<pg_start_backup()>.
-
-=cut
-
-sub backup_fs_hot
-{
- my ($self, $backup_name) = @_;
- $self->_backup_fs($backup_name, 1);
- return;
-}
-
=item $node->backup_fs_cold(backup_name)
Create a backup with a filesystem level copy in subdirectory B<backup_name> of
@@ -670,53 +651,18 @@ Use B<backup> or B<backup_fs_hot> if you want to back up a running server.
sub backup_fs_cold
{
my ($self, $backup_name) = @_;
- $self->_backup_fs($backup_name, 0);
- return;
-}
-
-
-# Common sub of backup_fs_hot and backup_fs_cold
-sub _backup_fs
-{
- my ($self, $backup_name, $hot) = @_;
- my $backup_path = $self->backup_dir . '/' . $backup_name;
- my $port = $self->port;
- my $name = $self->name;
-
- print "# Taking filesystem backup $backup_name from node \"$name\"\n";
-
- if ($hot)
- {
- my $stdout = $self->safe_psql('postgres',
- "SELECT * FROM pg_start_backup('$backup_name');");
- print "# pg_start_backup: $stdout\n";
- }
PostgreSQL::Test::RecursiveCopy::copypath(
$self->data_dir,
- $backup_path,
+ $self->backup_dir . '/' . $backup_name,
filterfn => sub {
my $src = shift;
return ($src ne 'log' and $src ne 'postmaster.pid');
});
- if ($hot)
- {
-
- # We ignore pg_stop_backup's return value. We also assume archiving
- # is enabled; otherwise the caller will have to copy the remaining
- # segments.
- my $stdout =
- $self->safe_psql('postgres', 'SELECT * FROM pg_stop_backup();');
- print "# pg_stop_backup: $stdout\n";
- }
-
- print "# Backup finished\n";
return;
}
-
-
=pod
=item $node->init_from_backup(root_node, backup_name)
diff --git a/src/test/recovery/t/010_logical_decoding_timelines.pl b/src/test/recovery/t/010_logical_decoding_timelines.pl
index 01ff31e61f..135fb1a72d 100644
--- a/src/test/recovery/t/010_logical_decoding_timelines.pl
+++ b/src/test/recovery/t/010_logical_decoding_timelines.pl
@@ -69,7 +69,9 @@ $node_primary->safe_psql('dropme',
$node_primary->safe_psql('postgres', 'CHECKPOINT;');
my $backup_name = 'b1';
-$node_primary->backup_fs_hot($backup_name);
+$node_primary->stop();
+$node_primary->backup_fs_cold($backup_name);
+$node_primary->start();
$node_primary->safe_psql('postgres',
q[SELECT pg_create_physical_replication_slot('phys_slot');]);
--
2.30.2
On 4/5/22 11:25 AM, Stephen Frost wrote:
Please find attached an updated patch + commit message. Mostly, I just
went through and did a bit more in terms of updating the documentation
and improving the comments (there were some places that were still
worrying about the chance of a 'stray' backup_label file existing, which
isn't possible any longer), along with some additional testing and
review. This is looking pretty good to me, but other thoughts are
certainly welcome. Otherwise, I'm hoping to commit this tomorrow.
I have reviewed the changes and they look good. I also ran the new patch
through pgbackrest regression with no issues.
Regards,
--
-David
david@pgmasters.net
On Tue, Apr 5, 2022 at 5:25 PM Stephen Frost <sfrost@snowman.net> wrote:
Greetings,
* David Steele (david@pgmasters.net) wrote:
On 4/4/22 11:42 AM, Nathan Bossart wrote:
I noticed a couple of other things that can be removed. Since we no
longer
wait on exclusive backup mode during smart shutdown, we can change
connsAllowed (in postmaster.c) to a boolean and remove CAC_SUPERUSER.We
can also remove a couple of related notes in the documentation. I've
done
all this in the attached patch.
These changes look good to me. IMV it is a real bonus how much the state
machine has been simplified.Yeah, agreed.
Definitely.
I've also run this patch through the pgbackrest regression tests without
any
problems.
Fantastic.
Please find attached an updated patch + commit message. Mostly, I just
went through and did a bit more in terms of updating the documentation
and improving the comments (there were some places that were still
worrying about the chance of a 'stray' backup_label file existing, which
isn't possible any longer), along with some additional testing and
review. This is looking pretty good to me, but other thoughts are
certainly welcome. Otherwise, I'm hoping to commit this tomorrow.
+1. LGTM.
I'm not sure I love the renaming of the functions, but I have also yet to
come up with a better idea for how to avoid silent breakage, so go with it.
--
Magnus Hagander
Me: https://www.hagander.net/ <http://www.hagander.net/>
Work: https://www.redpill-linpro.com/ <http://www.redpill-linpro.com/>
On Tue, Apr 05, 2022 at 11:25:36AM -0400, Stephen Frost wrote:
Please find attached an updated patch + commit message. Mostly, I just
went through and did a bit more in terms of updating the documentation
and improving the comments (there were some places that were still
worrying about the chance of a 'stray' backup_label file existing, which
isn't possible any longer), along with some additional testing and
review. This is looking pretty good to me, but other thoughts are
certainly welcome. Otherwise, I'm hoping to commit this tomorrow.
LGTM!
--
Nathan Bossart
Amazon Web Services: https://aws.amazon.com
On Tue, 2022-04-05 at 13:06 -0700, Nathan Bossart wrote:
On Tue, Apr 05, 2022 at 11:25:36AM -0400, Stephen Frost wrote:
Please find attached an updated patch + commit message. Mostly, I just
went through and did a bit more in terms of updating the documentation
and improving the comments (there were some places that were still
worrying about the chance of a 'stray' backup_label file existing, which
isn't possible any longer), along with some additional testing and
review. This is looking pretty good to me, but other thoughts are
certainly welcome. Otherwise, I'm hoping to commit this tomorrow.LGTM!
Cassandra (not the software) from the sidelines predicts that we will
get some fire from users for this, although I concede the theoretical
sanity of the change.
Yours,
Laurenz Albe
Greetings,
* Laurenz Albe (laurenz.albe@cybertec.at) wrote:
On Tue, 2022-04-05 at 13:06 -0700, Nathan Bossart wrote:
On Tue, Apr 05, 2022 at 11:25:36AM -0400, Stephen Frost wrote:
Please find attached an updated patch + commit message. Mostly, I just
went through and did a bit more in terms of updating the documentation
and improving the comments (there were some places that were still
worrying about the chance of a 'stray' backup_label file existing, which
isn't possible any longer), along with some additional testing and
review. This is looking pretty good to me, but other thoughts are
certainly welcome. Otherwise, I'm hoping to commit this tomorrow.LGTM!
Cassandra (not the software) from the sidelines predicts that we will
get some fire from users for this, although I concede the theoretical
sanity of the change.
Great, thanks for that.
This has now been committed- thanks again to everyone for their help!
Stephen
On Wed, Apr 06, 2022 at 03:29:15PM -0400, Stephen Frost wrote:
This has now been committed- thanks again to everyone for their help!
Thanks!
--
Nathan Bossart
Amazon Web Services: https://aws.amazon.com
Hi,
I was looking at the commit for this patch and noticed this small typo
in the comment in `basebackup.c`:
```
diff --git a/src/backend/replication/basebackup.c
b/src/backend/replication/basebackup.c
index 6884cad2c00af1632eacec07903098e7e1874393..815681ada7dd0c135af584ad5da2dd13c9a12465
100644 (file)
--- a/src/backend/replication/basebackup.c
+++ b/src/backend/replication/basebackup.c
@@ -184,10 +184,8 @@ static const struct exclude_list_item excludeFiles[] =
{RELCACHE_INIT_FILENAME, true},
/*
- * If there's a backup_label or tablespace_map file, it belongs to a
- * backup started by the user with pg_start_backup(). It is *not* correct
- * for this backup. Our backup_label/tablespace_map is injected into the
- * tar separately.
+ * backup_label and tablespace_map should not exist in in a running cluster
+ * capable of doing an online backup, but exclude them just in case.
*/
{BACKUP_LABEL_FILE, false},
{TABLESPACE_MAP, false},
```
The typo is in `exist in in a running cluster`. There's two `in` in a row.
P.D.: I was looking at this just because I was looking at an issue
where someone bumped their head with this "problem", so great that
we're in a better place now. Hopefully one day everyone will be
running PG15 or better :)
Kind regards, Martín
El mié, 6 abr 2022 a las 16:29, Stephen Frost (<sfrost@snowman.net>) escribió:
Greetings,
* Laurenz Albe (laurenz.albe@cybertec.at) wrote:
On Tue, 2022-04-05 at 13:06 -0700, Nathan Bossart wrote:
On Tue, Apr 05, 2022 at 11:25:36AM -0400, Stephen Frost wrote:
Please find attached an updated patch + commit message. Mostly, I just
went through and did a bit more in terms of updating the documentation
and improving the comments (there were some places that were still
worrying about the chance of a 'stray' backup_label file existing, which
isn't possible any longer), along with some additional testing and
review. This is looking pretty good to me, but other thoughts are
certainly welcome. Otherwise, I'm hoping to commit this tomorrow.LGTM!
Cassandra (not the software) from the sidelines predicts that we will
get some fire from users for this, although I concede the theoretical
sanity of the change.Great, thanks for that.
This has now been committed- thanks again to everyone for their help!
Stephen
--
Martín Marqués
It’s not that I have something to hide,
it’s that I have nothing I want you to see
On Tue, Apr 19, 2022 at 10:12:32PM -0300, Martín Marqués wrote:
The typo is in `exist in in a running cluster`. There's two `in` in a row.
Thanks, fixed.
--
Michael
Greetings,
* Martín Marqués (martin.marques@gmail.com) wrote:
The typo is in `exist in in a running cluster`. There's two `in` in a row.
Oops, thanks for catching (and thanks to Michael for committing the
fix!).
P.D.: I was looking at this just because I was looking at an issue
where someone bumped their head with this "problem", so great that
we're in a better place now. Hopefully one day everyone will be
running PG15 or better :)
Agreed! Does make me wonder just how often folks run into this issue..
Glad that we were able to get the change in for v15.
Thanks again!
Stephen