On 12/11/18 5:24 PM, David Steele wrote:
Attached is the patch.
I was a bit surprised by how much code went away. There was a lot of
code dedicated to making sure that backup_label got renamed on shutdown,
that there was not an exclusive backup running, etc.
There were no tests for exclusive backup so the test changes were minimal.
I did have to replace one "hot backup" in
010_logical_decoding_timelines.pl. I'm not sure why the backup was
being done this way, or why the standby needs a copy of pg_replslot
(which is not copied by pg_basebackup). It might be worth looking at
but it seemed out of scope for this patch.
Rebased patch is attached.
I also fixed the issue that Robert pointed out with regard to changing
the function signatures. It's a bit weird that there are optional
parameters when the last parameter is really not optional (i.e. the
default will lead to an error). Any suggestions are appreciated.
Reading back through the thread, the major objection to the original
patch was that it was submitted too soon. Hopefully the elapsed time
addresses that concern.
Another common objection is that the new API is hard to use from bash
scripts. This is arguably still true, but Laurenz has demonstrated that
bash is capable of this feat:
https://github.com/cybertec-postgresql/safe-backup
Lastly, there is some concern about getting the backup label too late
when doing snapshots or using traditional backup software. It would
certainly be possible to return the backup_label and tablespace_map from
pg_start_backup() and let the user make the choice about what to do with
them. Any of these methods will require some scripting so I don't see
why the files couldn't be written as, for example, backup_label.snap and
tablespace_map.snap and then renamed by the restore script. The patch
does not currently make this change, but it could be added pretty easily
if that overcomes this objection.
Regards,
--
-David
da...@pgmasters.net
From 035153589f47047d38cbb2ffef89d7f1f67e85cc Mon Sep 17 00:00:00 2001
From: David Steele <da...@pgmasters.net>
Date: Tue, 30 Jun 2020 17:23:51 -0400
Subject: [PATCH] Remove Deprecated Exclusive Backup Mode.
Remove the exclusive backup mode which has been deprecated since
PostgreSQL 9.6.
---
doc/src/sgml/backup.sgml | 150 +-----
doc/src/sgml/func.sgml | 82 +--
src/backend/access/transam/xlog.c | 476 ++----------------
src/backend/access/transam/xlogfuncs.c | 245 ++-------
src/backend/catalog/system_views.sql | 3 +-
src/backend/postmaster/postmaster.c | 46 +-
src/backend/replication/basebackup.c | 6 +-
src/backend/utils/init/postinit.c | 2 +-
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 | 12 +-
src/include/libpq/libpq-be.h | 3 +-
src/include/miscadmin.h | 4 -
src/test/perl/PostgresNode.pm | 56 +--
.../t/010_logical_decoding_timelines.pl | 4 +-
16 files changed, 128 insertions(+), 974 deletions(-)
diff --git a/doc/src/sgml/backup.sgml b/doc/src/sgml/backup.sgml
index bdc9026c62..c544d79a1b 100644
--- a/doc/src/sgml/backup.sgml
+++ b/doc/src/sgml/backup.sgml
@@ -819,16 +819,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
+ 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"/>).
@@ -868,8 +861,9 @@ SELECT pg_start_backup('label', false, false);
</para>
<para>
- The third parameter being <literal>false</literal> tells
- <function>pg_start_backup</function> to initiate a non-exclusive base
backup.
+ The third parameter must always be set to <literal>false</literal>. The
+ default of <literal>true</literal> requests an exclusive backup, which is
+ no longer supported.
</para>
</listitem>
<listitem>
@@ -946,142 +940,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 master 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
- master 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
- master.
- </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 f065856535..9e262fab3b 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -23990,9 +23990,7 @@ SELECT collation for ('foo' COLLATE "de_DE");
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_start_backup</function>, <function>pg_stop_backup</function>,
and <function>pg_wal_lsn_diff</function>).
</para>
@@ -24099,20 +24097,9 @@ SELECT collation for ('foo' COLLATE "de_DE");
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.
+ The third parameter must be set explicitly <literal>false</literal>.
+ The default of <literal>true</literal> for an exclusive backup is no
+ longer supported.
</para>
<para>
This function is restricted to superusers by default, but other users
@@ -24135,15 +24122,10 @@ SELECT collation for ('foo' COLLATE "de_DE");
<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
+ Finishes performing an on-line backup. The
+ <parameter>exclusive</parameter> parameter must be
+ <literal>false</literal> false to 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).
</para>
<para>
There is an optional second parameter of type <type>boolean</type>.
@@ -24174,9 +24156,9 @@ SELECT collation for ('foo' COLLATE "de_DE");
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.
+ third columns hold the contents of the label and tablespace map files,
+ which should be written to files in the backup area (not in the data
+ directory).
</para>
<para>
This function is restricted to superusers by default, but other users
@@ -24184,50 +24166,6 @@ SELECT collation for ('foo' COLLATE "de_DE");
</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>
diff --git a/src/backend/access/transam/xlog.c
b/src/backend/access/transam/xlog.c
index fd93bcfaeb..3f3902fddf 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -506,29 +506,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.
@@ -576,15 +553,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;
/*
@@ -944,7 +918,6 @@ static void xlog_outrec(StringInfo buf, XLogReaderState
*record);
#endif
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,
bool
*backupEndRequired, bool *backupFromStandby);
static bool read_tablespace_map(List **tablespaces);
@@ -9371,7 +9344,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
@@ -10444,25 +10417,14 @@ issue_xlog_fsync(int fd, XLogSegNo segno)
}
/*
- * 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.
+ * 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.
*
* tablespaces is required only when this function is called while
* the streaming base backup requested by pg_basebackup is running.
@@ -10472,15 +10434,14 @@ issue_xlog_fsync(int fd, XLogSegNo segno)
* utilities are not able to create symlinks while extracting files from tar.
* However for consistency, the same is used for all platforms.
*
- * needtblspcmapfile is true for the cases (exclusive backup and for
- * non-exclusive backup only when tar format is used for taking backup)
- * when backup needs to generate tablespace_map file, it is used to
- * embed escape character before newline character in tablespace path.
+ * needtblspcmapfile is true for the cases (only when tar format is used for
+ * taking backup) when backup needs to generate tablespace_map file, it is used
+ * to embed escape character before newline character in tablespace path.
*
* 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
@@ -10491,7 +10452,6 @@ do_pg_start_backup(const char *backupidstr, bool fast,
TimeLineID *starttli_p,
StringInfo labelfile, List **tablespaces,
StringInfo tblspcmapfile, bool
needtblspcmapfile)
{
- bool exclusive = (labelfile == NULL);
bool backup_started_in_recovery = false;
XLogRecPtr checkpointloc;
XLogRecPtr startpoint;
@@ -10500,20 +10460,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.
@@ -10552,30 +10501,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;
@@ -10702,11 +10633,8 @@ do_pg_start_backup(const char *backupidstr, bool fast,
TimeLineID *starttli_p,
XLogFileName(xlogfilename, starttli, _logSegNo,
wal_segment_size);
/*
- * Construct tablespace_map file
+ * Construct tablespace_map
*/
- if (exclusive)
- tblspcmapfile = makeStringInfo();
-
datadirpathlen = strlen(DataDir);
/* Collect information about all tablespaces */
@@ -10796,11 +10724,8 @@ do_pg_start_backup(const char *backupidstr, bool fast,
TimeLineID *starttli_p,
FreeDir(tblspcdir);
/*
- * Construct backup label file
+ * Construct backup_label
*/
- if (exclusive)
- labelfile = makeStringInfo();
-
/* Use the log timezone here, not the session timezone */
stamp_time = (pg_time_t) time(NULL);
pg_strftime(strfbuf, sizeof(strfbuf),
@@ -10810,122 +10735,19 @@ do_pg_start_backup(const char *backupidstr, bool
fast, TimeLineID *starttli_p,
(uint32) (startpoint >> 32),
(uint32) startpoint, xlogfilename);
appendStringInfo(labelfile, "CHECKPOINT LOCATION: %X/%X\n",
(uint32) (checkpointloc >>
32), (uint32) 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" : "master");
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.
@@ -10939,43 +10761,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();
-}
+ 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();
}
@@ -10995,9 +10789,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.
*
@@ -11007,7 +10798,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;
@@ -11021,7 +10811,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;
@@ -11034,15 +10823,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.
@@ -11053,106 +10833,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;
}
@@ -11410,10 +11107,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.
*/
@@ -11423,18 +11116,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;
}
@@ -11756,87 +11447,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 290658b22c..ec3669b4ae 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,46 @@ 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)
+ /* Error if exclusive backup mode is requested */
+ if (PG_GETARG_BOOL(2))
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, true);
- }
- 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);
-
- register_persistent_abort_backup_handler();
-
- startpoint = do_pg_start_backup(backupidstr, fast, NULL,
label_file,
-
NULL, tblspc_map_file, true);
- }
-
- 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();
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("exclusive backup mode is no longer
supported")));
- if (status == SESSION_BACKUP_NON_EXCLUSIVE)
+ if (status == SESSION_BACKUP_RUNNING)
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')?")));
+ errmsg("a backup is already in progress in
this session")));
/*
- * 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.
+ * Label file and tablespace map file need to be long-lived, since
+ * they are read in pg_stop_backup.
*/
- stoppoint = do_pg_stop_backup(NULL, true, NULL);
+ oldcontext = MemoryContextSwitchTo(TopMemoryContext);
+ label_file = makeStringInfo();
+ tblspc_map_file = makeStringInfo();
+ MemoryContextSwitchTo(oldcontext);
- PG_RETURN_LSN(stoppoint);
+ register_persistent_abort_backup_handler();
+
+ startpoint = do_pg_start_backup(backupidstr, fast, NULL, label_file,
+ NULL,
tblspc_map_file, true);
+
+ PG_RETURN_LSN(startpoint);
}
/*
- * pg_stop_backup_v2: finish taking exclusive or nonexclusive on-line backup.
+ * pg_stop_backup: finish taking an 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.
- *
- * 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 +108,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,11 +118,16 @@ 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);
XLogRecPtr stoppoint;
SessionBackupState status = get_backup_status();
+ /* Error if exclusive backup mode is requested */
+ if (PG_GETARG_BOOL(0))
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("exclusive backup mode is no longer
supported")));
+
/* check to see if caller supports us returning a tuplestore */
if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
ereport(ERROR,
@@ -205,51 +155,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);
@@ -627,81 +555,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_views.sql
b/src/backend/catalog/system_views.sql
index 5314e9348f..cce0e504a0 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -1214,7 +1214,7 @@ CREATE OR REPLACE FUNCTION
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'
+ RETURNS SETOF record STRICT VOLATILE LANGUAGE internal as 'pg_stop_backup'
PARALLEL RESTRICTED;
CREATE OR REPLACE FUNCTION
@@ -1427,7 +1427,6 @@ 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_stop_backup() FROM public;
REVOKE EXECUTE ON FUNCTION pg_stop_backup(boolean, boolean) FROM public;
REVOKE EXECUTE ON FUNCTION pg_create_restore_point(text) FROM public;
REVOKE EXECUTE ON FUNCTION pg_switch_wal() FROM public;
diff --git a/src/backend/postmaster/postmaster.c
b/src/backend/postmaster/postmaster.c
index b4d475bb0b..05c44c7ec3 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -300,8 +300,7 @@ static bool FatalError = false; /* T if recovering from
backend crash */
* and we switch to PM_RUN state.
*
* Normal child backends can only be launched when we are in PM_RUN or
- * PM_HOT_STANDBY state. (We also allow launch of normal
- * child backends in PM_WAIT_BACKUP state, but only for superusers.)
+ * PM_HOT_STANDBY state.
* In other states we handle connection requests by launching "dead_end"
* child processes, which will simply send the client an error message and
* quit. (We track these in the BackendList so that we can know when they
@@ -327,7 +326,6 @@ typedef enum
PM_RECOVERY, /* in archive recovery mode */
PM_HOT_STANDBY, /* in hot standby mode */
PM_RUN, /* normal "database is
alive" state */
- PM_WAIT_BACKUP, /* waiting for online backup
mode to end */
PM_WAIT_READONLY, /* waiting for read only
backends to exit */
PM_WAIT_BACKENDS, /* waiting for live backends to
exit */
PM_SHUTDOWN, /* waiting for checkpointer to
do shutdown
@@ -2320,9 +2318,6 @@ retry1:
(errcode(ERRCODE_TOO_MANY_CONNECTIONS),
errmsg("sorry, too many clients
already")));
break;
- case CAC_WAITBACKUP:
- /* OK for now, will check in InitPostgres */
- break;
case CAC_OK:
break;
}
@@ -2440,19 +2435,11 @@ canAcceptConnections(int backend_type)
* state. We treat autovac workers the same as user backends for this
* purpose. However, bgworkers are excluded from this test; we expect
* bgworker_should_start_now() decided whether the DB state allows them.
- *
- * In state PM_WAIT_BACKUP only superusers can connect (this must be
- * allowed so that a superuser can end online backup mode); we return
- * CAC_WAITBACKUP code to indicate that this must be checked later. Note
- * that neither CAC_OK nor CAC_WAITBACKUP can safely be returned until
we
- * have checked for too many children.
*/
if (pmState != PM_RUN &&
backend_type != BACKEND_TYPE_BGWORKER)
{
- if (pmState == PM_WAIT_BACKUP)
- result = CAC_WAITBACKUP; /* allow superusers
only */
- else if (Shutdown > NoShutdown)
+ if (Shutdown > NoShutdown)
return CAC_SHUTDOWN; /* shutdown is pending */
else if (!FatalError &&
(pmState == PM_STARTUP ||
@@ -2817,7 +2804,7 @@ pmdie(SIGNAL_ARGS)
* and walreceiver processes.
*/
pmState = (pmState == PM_RUN) ?
- PM_WAIT_BACKUP : PM_WAIT_READONLY;
+ PM_WAIT_BACKENDS : PM_WAIT_READONLY;
}
/*
@@ -2867,7 +2854,6 @@ pmdie(SIGNAL_ARGS)
pmState = PM_WAIT_BACKENDS;
}
else if (pmState == PM_RUN ||
- pmState == PM_WAIT_BACKUP ||
pmState == PM_WAIT_READONLY ||
pmState == PM_WAIT_BACKENDS ||
pmState == PM_HOT_STANDBY)
@@ -3709,7 +3695,6 @@ HandleChildCrash(int pid, int exitstatus, const char
*procname)
if (pmState == PM_RECOVERY ||
pmState == PM_HOT_STANDBY ||
pmState == PM_RUN ||
- pmState == PM_WAIT_BACKUP ||
pmState == PM_WAIT_READONLY ||
pmState == PM_SHUTDOWN)
pmState = PM_WAIT_BACKENDS;
@@ -3793,15 +3778,6 @@ LogChildExit(int lev, const char *procname, int pid, int
exitstatus)
static void
PostmasterStateMachine(void)
{
- if (pmState == PM_WAIT_BACKUP)
- {
- /*
- * PM_WAIT_BACKUP state ends when online backup mode is not
active.
- */
- if (!BackupInProgress())
- pmState = PM_WAIT_BACKENDS;
- }
-
if (pmState == PM_WAIT_READONLY)
{
/*
@@ -3967,18 +3943,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 */
ExitPostmaster(0);
}
@@ -4180,8 +4144,7 @@ BackendStartup(Port *port)
/* Pass down canAcceptConnections state */
port->canAcceptConnections = canAcceptConnections(BACKEND_TYPE_NORMAL);
- bn->dead_end = (port->canAcceptConnections != CAC_OK &&
- port->canAcceptConnections !=
CAC_WAITBACKUP);
+ bn->dead_end = port->canAcceptConnections != CAC_OK;
/*
* Unless it's a dead_end child, assign it a child slot number
@@ -5898,7 +5861,6 @@ bgworker_should_start_now(BgWorkerStartTime start_time)
case PM_SHUTDOWN:
case PM_WAIT_BACKENDS:
case PM_WAIT_READONLY:
- case PM_WAIT_BACKUP:
break;
case PM_RUN:
diff --git a/src/backend/replication/basebackup.c
b/src/backend/replication/basebackup.c
index 096b0fcef0..1440180cc4 100644
--- a/src/backend/replication/basebackup.c
+++ b/src/backend/replication/basebackup.c
@@ -206,10 +206,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},
diff --git a/src/backend/utils/init/postinit.c
b/src/backend/utils/init/postinit.c
index f4247ea70d..2e1d4e1c40 100644
--- a/src/backend/utils/init/postinit.c
+++ b/src/backend/utils/init/postinit.c
@@ -791,7 +791,7 @@ InitPostgres(const char *in_dbname, Oid dboid, const char
*username,
*/
if ((!am_superuser || am_walsender) &&
MyProcPort != NULL &&
- MyProcPort->canAcceptConnections == CAC_WAITBACKUP)
+ MyProcPort->canAcceptConnections == CAC_SHUTDOWN)
{
if (am_walsender)
ereport(FATAL,
diff --git a/src/bin/pg_basebackup/t/010_pg_basebackup.pl
b/src/bin/pg_basebackup/t/010_pg_basebackup.pl
index 208df557b8..90af0d6272 100644
--- a/src/bin/pg_basebackup/t/010_pg_basebackup.pl
+++ b/src/bin/pg_basebackup/t/010_pg_basebackup.pl
@@ -159,6 +159,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 36a2d62341..1485eff3e1 100644
--- a/src/bin/pg_rewind/filemap.c
+++ b/src/bin/pg_rewind/filemap.c
@@ -106,9 +106,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 77ac4e785f..b99ef3ecb4 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -368,8 +368,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 61f2c2f5b4..4135e588fd 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -6051,23 +6051,13 @@
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' },
{ 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' },
+ 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/libpq/libpq-be.h b/src/include/libpq/libpq-be.h
index 179ebaa104..66e527dec8 100644
--- a/src/include/libpq/libpq-be.h
+++ b/src/include/libpq/libpq-be.h
@@ -70,8 +70,7 @@ typedef struct
typedef enum CAC_state
{
- CAC_OK, CAC_STARTUP, CAC_SHUTDOWN, CAC_RECOVERY, CAC_TOOMANY,
- CAC_WAITBACKUP
+ CAC_OK, CAC_STARTUP, CAC_SHUTDOWN, CAC_RECOVERY, CAC_TOOMANY
} CAC_state;
diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h
index 18bc8a7b90..ddea0c9f33 100644
--- a/src/include/miscadmin.h
+++ b/src/include/miscadmin.h
@@ -465,8 +465,4 @@ 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);
-
#endif /* MISCADMIN_H */
diff --git a/src/test/perl/PostgresNode.pm b/src/test/perl/PostgresNode.pm
index 1407359aef..f580090e9a 100644
--- a/src/test/perl/PostgresNode.pm
+++ b/src/test/perl/PostgresNode.pm
@@ -557,25 +557,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
@@ -589,53 +570,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";
- }
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 11f5595e2b..b556d7a654 100644
--- a/src/test/recovery/t/010_logical_decoding_timelines.pl
+++ b/src/test/recovery/t/010_logical_decoding_timelines.pl
@@ -66,7 +66,9 @@ $node_master->safe_psql('dropme',
$node_master->safe_psql('postgres', 'CHECKPOINT;');
my $backup_name = 'b1';
-$node_master->backup_fs_hot($backup_name);
+$node_master->stop();
+$node_master->backup_fs_cold($backup_name);
+$node_master->start();
$node_master->safe_psql('postgres',
q[SELECT pg_create_physical_replication_slot('phys_slot');]);
--
2.21.0 (Apple Git-122.2)