diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index e4645a3..fa37ff1 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -8739,8 +8739,10 @@ CreateRestartPoint(int flags) * immediate shutdown, though. * * We don't explicitly advance minRecoveryPoint when we do create a - * restartpoint. It's assumed that flushing the buffers will do that as a - * side-effect. + * restartpoint as it is assumed that flushing the buffers will do that as + * a side-effect except when a backup is running to ensure that the start + * LSN location of a backup is not newer than minRecoveryPoint which is + * used as the stop location of a backup. */ if (XLogRecPtrIsInvalid(lastCheckPointRecPtr) || lastCheckPoint.redo <= ControlFile->checkPointCopy.redo) @@ -8762,6 +8764,8 @@ CreateRestartPoint(int flags) LWLockRelease(CheckpointLock); return false; } + else if (BackupInProgress(false)) + UpdateMinRecoveryPoint(InvalidXLogRecPtr, true); /* * Update the shared RedoRecPtr so that the startup process can calculate @@ -10866,14 +10870,28 @@ rm_redo_error_callback(void *arg) /* * BackupInProgress: check if online backup mode is active * - * This is done by checking for existence of the "backup_label" file. + * This is done by checking for existence of the "backup_label" file or by + * looking at the shared memory status of backups. */ bool -BackupInProgress(void) +BackupInProgress(bool label_check) { - struct stat stat_buf; + bool res; + + if (label_check) + { + struct stat stat_buf; + res = (stat(BACKUP_LABEL_FILE, &stat_buf) == 0); + } + else + { + WALInsertLockAcquireExclusive(); + res = XLogCtl->Insert.nonExclusiveBackups > 0 || + XLogCtl->Insert.exclusiveBackup; + WALInsertLockRelease(); + } - return (stat(BACKUP_LABEL_FILE, &stat_buf) == 0); + return res; } /* diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c index 33383b4..2f381cd 100644 --- a/src/backend/access/transam/xlogfuncs.c +++ b/src/backend/access/transam/xlogfuncs.c @@ -636,7 +636,7 @@ pg_xlog_location_diff(PG_FUNCTION_ARGS) Datum pg_is_in_backup(PG_FUNCTION_ARGS) { - PG_RETURN_BOOL(BackupInProgress()); + PG_RETURN_BOOL(BackupInProgress(true)); } /* diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c index 19d11e0..6795c69 100644 --- a/src/backend/postmaster/postmaster.c +++ b/src/backend/postmaster/postmaster.c @@ -3527,7 +3527,7 @@ PostmasterStateMachine(void) /* * PM_WAIT_BACKUP state ends when online backup mode is not active. */ - if (!BackupInProgress()) + if (!BackupInProgress(true)) pmState = PM_WAIT_BACKENDS; } diff --git a/src/include/catalog/pg_control.h b/src/include/catalog/pg_control.h index fefcac8..56a270f 100644 --- a/src/include/catalog/pg_control.h +++ b/src/include/catalog/pg_control.h @@ -143,7 +143,10 @@ typedef struct ControlFileData * starting archive recovery, aborting it, and restarting with an earlier * stop location. If we've already flushed data changes from WAL record X * to disk, we mustn't start up until we reach X again. Zero when not - * doing archive recovery. + * doing archive recovery. It gets updated as well when a backup is running + * to allow the stop location of a backup which is based on + * minRecoveryPoint to be newer than its start location to get a consistent + * backup. * * backupStartPoint is the redo pointer of the backup start checkpoint, if * we are recovering from an online backup and haven't reached the end of diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h index 78545da..b2b7d4f 100644 --- a/src/include/miscadmin.h +++ b/src/include/miscadmin.h @@ -463,7 +463,7 @@ extern void pg_bindtextdomain(const char *domain); extern bool has_rolreplication(Oid roleid); /* in access/transam/xlog.c */ -extern bool BackupInProgress(void); +extern bool BackupInProgress(bool label_check); extern void CancelBackup(void); #endif /* MISCADMIN_H */ diff --git a/src/test/recovery/t/001_stream_rep.pl b/src/test/recovery/t/001_stream_rep.pl index 7b42f21..cee4768 100644 --- a/src/test/recovery/t/001_stream_rep.pl +++ b/src/test/recovery/t/001_stream_rep.pl @@ -24,6 +24,11 @@ $node_standby_1->start; # pg_basebackup works on a standby). $node_standby_1->backup($backup_name); +# Take a second backup of the standby while the master is offline. +$node_master->stop; +$node_standby_1->backup('my_backup_2'); +$node_master->start; + # Create second standby node linking to standby 1 my $node_standby_2 = get_new_node('standby_2'); $node_standby_2->init_from_backup($node_standby_1, $backup_name,