diff --git a/doc/src/sgml/backup.sgml b/doc/src/sgml/backup.sgml index a73fd4d044..6f45f2e177 100644 --- a/doc/src/sgml/backup.sgml +++ b/doc/src/sgml/backup.sgml @@ -819,15 +819,8 @@ test ! -f /mnt/server/archivedir/00000001000000A900000065 && cp pg_wal/0 sequence, and that the success of a step is verified before proceeding to the next step. - - 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. - - - Making a non-exclusive low level backup - 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 ). @@ -845,7 +838,7 @@ test ! -f /mnt/server/archivedir/00000001000000A900000065 && cp pg_wal/0 rights to run pg_start_backup (superuser, or a user who has been granted EXECUTE on the function) and issue the command: -SELECT pg_start_backup('label', false, false); +SELECT pg_start_backup('label', false); where label is any string you want to use to uniquely identify this backup operation. The connection @@ -866,10 +859,6 @@ SELECT pg_start_backup('label', false, false); issue an immediate checkpoint using as much I/O as available. - - The third parameter being false tells - pg_start_backup to initiate a non-exclusive base backup. - @@ -887,7 +876,7 @@ SELECT pg_start_backup('label', false, false); In the same connection as before, issue the command: -SELECT * FROM pg_stop_backup(false, true); +SELECT * FROM pg_stop_backup(true); This terminates backup mode. On a primary, it also performs an automatic switch to the next WAL segment. On a standby, it is not possible to @@ -945,116 +934,6 @@ SELECT * FROM pg_stop_backup(false, true); - - - Making an exclusive low level backup - - 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. - Prior to PostgreSQL 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 if possible. - - - - - - Ensure that WAL archiving is enabled and working. - - - - - 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: - -SELECT pg_start_backup('label'); - - where label is any string you want to use to uniquely - identify this backup operation. - pg_start_backup creates a backup label file, - called backup_label, in the cluster directory with - information about your backup, including the start time and label string. - The function also creates a tablespace map file, - called tablespace_map, in the cluster directory with - information about tablespace symbolic links in pg_tblspc/ 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. - - - - By default, pg_start_backup 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 - ). 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: - -SELECT pg_start_backup('label', true); - - This forces the checkpoint to be done as quickly as possible. - - - - - Perform the backup, using any convenient file-system-backup tool - such as tar or cpio (not - pg_dump or - pg_dumpall). It is neither - necessary nor desirable to stop normal operation of the database - while you do this. See - for things to - consider during this backup. - - - Note that if the server crashes during the backup it may not be - possible to restart until the backup_label file has been - manually deleted from the PGDATA directory. - - - - - 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: - -SELECT pg_stop_backup(); - - 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. - - - - - Once the WAL segment files active during the backup are archived, you are - done. The file identified by pg_stop_backup's result is - the last segment that is required to form a complete set of backup files. - If archive_mode is enabled, - pg_stop_backup does not return until the last segment has - been archived. - Archiving of these files happens automatically since you have - already configured archive_command. 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. - If you wish to place a time limit on the execution of - pg_stop_backup, set an appropriate - statement_timeout value, but make note that if - pg_stop_backup terminates because of this your backup - may not be valid. - - - - - Backing up the data directory diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml index b3336ea9be..ae7722bb12 100644 --- a/doc/src/sgml/func.sgml +++ b/doc/src/sgml/func.sgml @@ -18945,38 +18945,17 @@ SELECT set_config('log_statement_stats', 'off', false); - pg_start_backup(label text , fast boolean , exclusive boolean ) + pg_start_backup(label text , fast boolean ) pg_lsn Prepare for performing on-line backup (restricted to superusers by default, but other users can be granted EXECUTE to run the function) - pg_stop_backup() - - pg_lsn - Finish performing exclusive on-line backup (restricted to superusers by default, but other users can be granted EXECUTE to run the function) - - - - pg_stop_backup(exclusive boolean , wait_for_archive boolean ) + pg_stop_backup( wait_for_archive boolean ) setof record - Finish performing exclusive or non-exclusive on-line backup (restricted to superusers by default, but other users can be granted EXECUTE to run the function) - - - - pg_is_in_backup() - - bool - True if an on-line exclusive backup is still in progress. - - - - pg_backup_start_time() - - timestamp with time zone - Get start time of an on-line exclusive backup in progress. + Finish performing on-line backup (restricted to superusers by default, but other users can be granted EXECUTE to run the function) @@ -19013,16 +18992,9 @@ SELECT set_config('log_statement_stats', 'off', false); pg_start_backup accepts an arbitrary user-defined label for the backup. (Typically this would be the name under which the backup dump - file will be stored.) When used in exclusive mode, the function writes a - backup label file (backup_label) and, if there are any links - in the pg_tblspc/ directory, a tablespace map file - (tablespace_map) into the database cluster's data directory, - performs a checkpoint, and then returns the backup's starting write-ahead - log location as text. 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 - pg_stop_backup function, and should be written to the backup - by the caller. + file will be stored.) It returns the backup's starting write-ahead + log location as a pg_lsn which can be ignored by the user, but is + provided in case it is useful. postgres=# select pg_start_backup('label_goes_here'); @@ -19038,12 +19010,10 @@ postgres=# select pg_start_backup('label_goes_here'); - In an exclusive backup, pg_stop_backup removes the label file - and, if it exists, the tablespace_map file created by - pg_start_backup. In a non-exclusive backup, the contents of - the backup_label and tablespace_map are returned - in the result of the function, and should be written to files in the - backup (and not in the data directory). There is an optional second + The contents of the backup_label and + tablespace_map are returned in the result of + pg_stop_backup, and should be written to files in the + backup (and not in the data directory). There is an optional parameter of type boolean. If false, the pg_stop_backup will return immediately after the backup is completed without waiting for WAL to be archived. This behavior is only useful for backup diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index c80b14ed97..5807616289 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -493,29 +493,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. @@ -563,15 +540,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; /* @@ -916,7 +890,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); @@ -9208,7 +9181,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 @@ -10165,36 +10138,25 @@ XLogFileNameP(TimeLineID tli, XLogSegNo segno) /* * 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 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. + * 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. * * tblspcmapfile is required mainly for tar format in windows as native windows * 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 @@ -10206,7 +10168,6 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p, StringInfo tblspcmapfile, bool infotbssize, bool needtblspcmapfile) { - bool exclusive = (labelfile == NULL); bool backup_started_in_recovery = false; XLogRecPtr checkpointloc; XLogRecPtr startpoint; @@ -10215,20 +10176,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. @@ -10267,30 +10217,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; @@ -10417,11 +10349,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 */ @@ -10511,11 +10440,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), @@ -10525,122 +10451,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. @@ -10654,43 +10477,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(); } @@ -10708,9 +10503,6 @@ get_backup_status(void) * do_pg_stop_backup is the workhorse of the user-visible pg_stop_backup() * function. * - * 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. * @@ -10720,7 +10512,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; @@ -10734,7 +10525,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; @@ -10747,15 +10537,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. @@ -10766,106 +10547,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; } @@ -11117,28 +10815,21 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p) * This does just the most basic steps of do_pg_stop_backup(), by taking the * system out of backup mode, thus making it a lot more safe to call from * an error handler. - * - * 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(). */ void do_pg_abort_backup(void) { /* - * 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_NONE) return; WALInsertLockAcquireExclusive(); - Assert(XLogCtl->Insert.nonExclusiveBackups > 0); - Assert(sessionBackupState == SESSION_BACKUP_NON_EXCLUSIVE); - 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; } @@ -11441,87 +11132,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 f139eeff9f..469d5e41c1 100644 --- a/src/backend/access/transam/xlogfuncs.c +++ b/src/backend/access/transam/xlogfuncs.c @@ -40,17 +40,16 @@ /* - * 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; /* - * Called when the backend exits with a running non-exclusive base backup, - * to clean up state. + * Called when the backend exits with a running base backup to clean up state. */ static void -nonexclusive_base_backup_cleanup(int code, Datum arg) +base_backup_cleanup(int code, Datum arg) { do_pg_abort_backup(); ereport(WARNING, @@ -74,101 +73,40 @@ pg_start_backup(PG_FUNCTION_ARGS) { text *backupid = PG_GETARG_TEXT_PP(0); bool fast = PG_GETARG_BOOL(1); - bool exclusive = PG_GETARG_BOOL(2); char *backupidstr; XLogRecPtr startpoint; SessionBackupState status = get_backup_status(); + MemoryContext oldcontext; backupidstr = text_to_cstring(backupid); - if (status == SESSION_BACKUP_NON_EXCLUSIVE) + if (status == SESSION_BACKUP_RUNNING) ereport(ERROR, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), errmsg("a backup is already in progress in this session"))); - if (exclusive) - { - startpoint = do_pg_start_backup(backupidstr, fast, NULL, NULL, - NULL, NULL, false, 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); + /* + * 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); - startpoint = do_pg_start_backup(backupidstr, fast, NULL, label_file, - NULL, tblspc_map_file, false, true); + startpoint = do_pg_start_backup(backupidstr, fast, NULL, label_file, + NULL, tblspc_map_file, false, true); - before_shmem_exit(nonexclusive_base_backup_cleanup, (Datum) 0); - } + before_shmem_exit(base_backup_cleanup, (Datum) 0); 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. + * 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. * @@ -176,7 +114,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; @@ -186,8 +124,7 @@ pg_stop_backup_v2(PG_FUNCTION_ARGS) Datum values[3]; bool nulls[3]; - bool exclusive = PG_GETARG_BOOL(0); - bool waitforarchive = PG_GETARG_BOOL(1); + bool waitforarchive = PG_GETARG_BOOL(0); XLogRecPtr stoppoint; SessionBackupState status = get_backup_status(); @@ -219,52 +156,30 @@ 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')?"))); - - /* - * 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); - cancel_before_shmem_exit(nonexclusive_base_backup_cleanup, (Datum) 0); - - 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; - } + 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 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); + cancel_before_shmem_exit(base_backup_cleanup, (Datum) 0); - /* 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(typstore); @@ -626,81 +541,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 8630542bb3..bf30693f23 100644 --- a/src/backend/catalog/system_views.sql +++ b/src/backend/catalog/system_views.sql @@ -1018,14 +1018,14 @@ COMMENT ON FUNCTION ts_debug(text) IS -- CREATE OR REPLACE FUNCTION - pg_start_backup(label text, fast boolean DEFAULT false, exclusive boolean DEFAULT true) + pg_start_backup(label text, fast boolean DEFAULT false) RETURNS pg_lsn STRICT VOLATILE LANGUAGE internal AS 'pg_start_backup' PARALLEL RESTRICTED; CREATE OR REPLACE FUNCTION pg_stop_backup ( - exclusive boolean, wait_for_archive boolean DEFAULT true, - OUT lsn pg_lsn, OUT labelfile text, OUT spcmapfile text) - RETURNS SETOF record STRICT VOLATILE LANGUAGE internal as 'pg_stop_backup_v2' + wait_for_archive boolean DEFAULT true, OUT lsn pg_lsn, OUT labelfile text, + OUT spcmapfile text) + RETURNS SETOF record STRICT VOLATILE LANGUAGE internal as 'pg_stop_backup' PARALLEL RESTRICTED; CREATE OR REPLACE FUNCTION @@ -1133,9 +1133,8 @@ AS 'jsonb_insert'; -- can later change who can access these functions, or leave them as only -- 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_start_backup(text, boolean) FROM public; +REVOKE EXECUTE ON FUNCTION pg_stop_backup(boolean) FROM public; REVOKE EXECUTE ON FUNCTION pg_create_restore_point(text) FROM public; REVOKE EXECUTE ON FUNCTION pg_switch_wal() FROM public; REVOKE EXECUTE ON FUNCTION pg_wal_replay_pause() FROM public; diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c index a33a131182..3a8653ab4d 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 @@ -2241,9 +2239,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; } @@ -2352,18 +2347,10 @@ canAcceptConnections(void) /* * Can't start backends when in startup/shutdown/inconsistent recovery * state. - * - * 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) { - 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 || @@ -2704,7 +2691,7 @@ pmdie(SIGNAL_ARGS) * and walreceiver processes. */ pmState = (pmState == PM_RUN) ? - PM_WAIT_BACKUP : PM_WAIT_READONLY; + PM_WAIT_BACKENDS : PM_WAIT_READONLY; } /* @@ -2754,7 +2741,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) @@ -3571,7 +3557,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; @@ -3663,15 +3648,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) { /* @@ -3841,18 +3817,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); } @@ -4054,8 +4018,7 @@ BackendStartup(Port *port) /* Pass down canAcceptConnections state */ port->canAcceptConnections = canAcceptConnections(); - 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 @@ -5182,7 +5145,7 @@ sigusr1_handler(SIGNAL_ARGS) } if (CheckPostmasterSignal(PMSIGNAL_ADVANCE_STATE_MACHINE) && - (pmState == PM_WAIT_BACKUP || pmState == PM_WAIT_BACKENDS)) + pmState == PM_WAIT_BACKENDS) { /* Advance postmaster's state machine */ PostmasterStateMachine(); @@ -5775,7 +5738,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 78ed6cf797..448556d7c3 100644 --- a/src/backend/replication/basebackup.c +++ b/src/backend/replication/basebackup.c @@ -172,10 +172,8 @@ static const char *excludeFiles[] = 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/tablespace_map is injected into the - * tar separately. + * backup_label and tablespace_map should not exist in in a running cluster + * capable of doing an online backup, but exclude then just in case. */ BACKUP_LABEL_FILE, TABLESPACE_MAP, diff --git a/src/backend/utils/init/postinit.c b/src/backend/utils/init/postinit.c index b636b1e262..d868c21fdc 100644 --- a/src/backend/utils/init/postinit.c +++ b/src/backend/utils/init/postinit.c @@ -788,7 +788,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 3e1c3863c4..04eea9bfeb 100644 --- a/src/bin/pg_basebackup/t/010_pg_basebackup.pl +++ b/src/bin/pg_basebackup/t/010_pg_basebackup.pl @@ -158,6 +158,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', "$tempdir/backup2", '--waldir', diff --git a/src/bin/pg_rewind/filemap.c b/src/bin/pg_rewind/filemap.c index 222b56f58a..084ea06597 100644 --- a/src/bin/pg_rewind/filemap.c +++ b/src/bin/pg_rewind/filemap.c @@ -94,9 +94,9 @@ static const char *excludeFiles[] = "pg_internal.init", /* 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", /* defined as BACKUP_LABEL_FILE */ "tablespace_map", /* defined as TABLESPACE_MAP */ diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index f3a7ba4d42..7d0f45ff99 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -338,8 +338,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 f79fcfe029..4a4c49cf99 100644 --- a/src/include/catalog/pg_proc.dat +++ b/src/include/catalog/pg_proc.dat @@ -5814,25 +5814,15 @@ proargtypes => 'int4', prosrc => 'pg_terminate_backend' }, { oid => '2172', descr => 'prepare for taking an online backup', proname => 'pg_start_backup', provolatile => 'v', proparallel => 'r', - prorettype => 'pg_lsn', proargtypes => 'text bool bool', + prorettype => 'pg_lsn', proargtypes => 'text bool', prosrc => 'pg_start_backup' }, -{ oid => '2173', descr => 'finish taking an online backup', - proname => 'pg_stop_backup', provolatile => 'v', proparallel => 'r', - prorettype => 'pg_lsn', proargtypes => '', prosrc => 'pg_stop_backup' }, { oid => '2739', descr => 'finish taking an online backup', proname => 'pg_stop_backup', prorows => '1', proretset => 't', provolatile => 'v', proparallel => 'r', prorettype => 'record', - proargtypes => 'bool bool', proallargtypes => '{bool,bool,pg_lsn,text,text}', - proargmodes => '{i,i,o,o,o}', - proargnames => '{exclusive,wait_for_archive,lsn,labelfile,spcmapfile}', - prosrc => 'pg_stop_backup_v2' }, -{ oid => '3813', descr => 'true if server is in online backup', - proname => 'pg_is_in_backup', provolatile => 'v', prorettype => 'bool', - proargtypes => '', prosrc => 'pg_is_in_backup' }, -{ oid => '3814', descr => 'start time of an online backup', - proname => 'pg_backup_start_time', provolatile => 's', - prorettype => 'timestamptz', proargtypes => '', - prosrc => 'pg_backup_start_time' }, + proargtypes => 'bool', proallargtypes => '{bool,pg_lsn,text,text}', + proargmodes => '{i,o,o,o}', + proargnames => '{wait_for_archive,lsn,labelfile,spcmapfile}', + prosrc => 'pg_stop_backup' }, { oid => '3436', descr => 'promote standby server', proname => 'pg_promote', provolatile => 'v', prorettype => 'bool', proargtypes => 'bool int4', proargnames => '{wait,wait_seconds}', diff --git a/src/include/libpq/libpq-be.h b/src/include/libpq/libpq-be.h index b2c59df54e..3d7b831599 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 d6b32c070c..687056ba55 100644 --- a/src/include/miscadmin.h +++ b/src/include/miscadmin.h @@ -447,8 +447,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 8a2c6fc122..4c27a7d362 100644 --- a/src/test/perl/PostgresNode.pm +++ b/src/test/perl/PostgresNode.pm @@ -546,25 +546,6 @@ sub backup return; } -=item $node->backup_fs_hot(backup_name) - -Create a backup with a filesystem level copy in subdirectory B of -B<< $node->backup_dir >>, including WAL. - -Archiving must be enabled, as B and B are -used. This is not checked or enforced. - -The backup name is passed as the backup label to B. - -=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 of @@ -578,53 +559,18 @@ Use B or B 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 e582b20005..32dfda454c 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');]);