aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/access/transam/xlog.c519
-rw-r--r--src/backend/access/transam/xlogfuncs.c253
-rw-r--r--src/backend/access/transam/xlogrecovery.c20
-rw-r--r--src/backend/catalog/system_functions.sql18
-rw-r--r--src/backend/postmaster/postmaster.c75
-rw-r--r--src/backend/replication/basebackup.c20
-rw-r--r--src/backend/utils/init/postinit.c18
-rw-r--r--src/bin/pg_basebackup/t/010_pg_basebackup.pl4
-rw-r--r--src/bin/pg_ctl/pg_ctl.c30
-rw-r--r--src/bin/pg_rewind/filemap.c6
-rw-r--r--src/include/access/xlog.h7
-rw-r--r--src/include/catalog/pg_control.h4
-rw-r--r--src/include/catalog/pg_proc.dat28
-rw-r--r--src/include/libpq/libpq-be.h3
-rw-r--r--src/include/miscadmin.h4
-rw-r--r--src/test/perl/PostgreSQL/Test/Cluster.pm56
-rw-r--r--src/test/recovery/t/010_logical_decoding_timelines.pl4
17 files changed, 186 insertions, 883 deletions
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 17a56152f17..8ae0a0ba537 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -386,29 +386,6 @@ typedef union WALInsertLockPadded
} 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,21 +8054,10 @@ 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;
@@ -8641,15 +8437,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 2752be63c10..b61ae6c0b4a 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)
@@ -646,81 +562,6 @@ pg_wal_lsn_diff(PG_FUNCTION_ARGS)
}
/*
- * 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.
*
* A result of "true" means that promotion has been completed if "wait" is
diff --git a/src/backend/access/transam/xlogrecovery.c b/src/backend/access/transam/xlogrecovery.c
index 8d2395dae25..1b7bae387a0 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 81bac6f5812..6ae4388d3f8 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 80bb2695998..9f7034df112 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;
@@ -4045,18 +4011,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
* will do so, and that should be the last user-visible action.
@@ -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 6884cad2c00..815681ada7d 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 6452b42dbff..342169b1958 100644
--- a/src/backend/utils/init/postinit.c
+++ b/src/backend/utils/init/postinit.c
@@ -872,24 +872,6 @@ InitPostgres(const char *in_dbname, Oid dboid, const char *username,
}
/*
- * 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
*/
if (IsBinaryUpgrade && !am_superuser)
diff --git a/src/bin/pg_basebackup/t/010_pg_basebackup.pl b/src/bin/pg_basebackup/t/010_pg_basebackup.pl
index 5ba84c22509..7309ebddea6 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 3c182c97d47..3a9092a16a6 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 7211090f471..fb52debf7a6 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 09f6464331b..b81917f243d 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 1f3dc24ac11..06368e23667 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 4d285ece8bf..e8f89a7b180 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 dd3e5efba3a..c3bf5146528 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 0abc3ad5405..9321d7f264b 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 b4ebc999356..1452297210e 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 01ff31e61f5..135fb1a72d5 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');]);