@ -385,29 +385,6 @@ typedef union WALInsertLockPadded
char pad [ PG_CACHE_LINE_SIZE ] ;
} WALInsertLockPadded ;
/*
* State of an exclusive backup , necessary to control concurrent activities
* across sessions when working on exclusive backups .
*
* EXCLUSIVE_BACKUP_NONE means that there is no exclusive backup actually
* running , to be more precise pg_start_backup ( ) is not being executed for
* an exclusive backup and there is no exclusive backup in progress .
* EXCLUSIVE_BACKUP_STARTING means that pg_start_backup ( ) is starting an
* exclusive backup .
* EXCLUSIVE_BACKUP_IN_PROGRESS means that pg_start_backup ( ) has finished
* running and an exclusive backup is in progress . pg_stop_backup ( ) is
* needed to finish it .
* EXCLUSIVE_BACKUP_STOPPING means that pg_stop_backup ( ) is stopping an
* exclusive backup .
*/
typedef enum ExclusiveBackupState
{
EXCLUSIVE_BACKUP_NONE = 0 ,
EXCLUSIVE_BACKUP_STARTING ,
EXCLUSIVE_BACKUP_IN_PROGRESS ,
EXCLUSIVE_BACKUP_STOPPING
} ExclusiveBackupState ;
/*
* Session status of running backup , used for sanity checks in SQL - callable
* functions to start and stop backups .
@ -456,15 +433,12 @@ typedef struct XLogCtlInsert
bool fullPageWrites ;
/*
* exclusiveBackupState indicates the state of an exclusive backup ( see
* comments of ExclusiveBackupState for more details ) . nonExclusiveBackups
* is a counter indicating the number of streaming base backups currently
* in progress . forcePageWrites is set to true when either of these is
* non - zero . lastBackupStart is the latest checkpoint redo location used
* as a starting point for an online backup .
* runningBackups is a counter indicating the number of backups currently in
* progress . forcePageWrites is set to true when runningBackups is non - zero .
* lastBackupStart is the latest checkpoint redo location used as a starting
* point for an online backup .
*/
ExclusiveBackupState exclusiveBackupState ;
int nonExclusiveBackups ;
int runningBackups ;
XLogRecPtr lastBackupStart ;
/*
@ -696,8 +670,7 @@ static void ReadControlFile(void);
static void UpdateControlFile ( void ) ;
static char * str_time ( pg_time_t tnow ) ;
static void pg_start_backup_callback ( int code , Datum arg ) ;
static void pg_stop_backup_callback ( int code , Datum arg ) ;
static void pg_backup_start_callback ( int code , Datum arg ) ;
static int get_sync_bit ( int method ) ;
@ -5314,8 +5287,19 @@ StartupXLOG(void)
missingContrecPtr = endOfRecoveryInfo - > missingContrecPtr ;
/*
* Complain if we did not roll forward far enough to render the backup
* dump consistent . Note : it is indeed okay to look at the local variable
* When recovering from a backup ( we are in recovery , and archive recovery
* was requested ) , complain if we did not roll forward far enough to reach
* the point where the database is consistent . For regular online
* backup - from - primary , that means reaching the end - of - backup WAL record ( at
* which point we reset backupStartPoint to be Invalid ) , for
* backup - from - replica ( which can ' t inject records into the WAL stream ) ,
* that point is when we reach the minRecoveryPoint in pg_control ( which
* we purposfully copy last when backing up from a replica ) . For pg_rewind
* ( which creates a backup_label with a method of " pg_rewind " ) or
* snapshot - style backups ( which don ' t ) , backupEndRequired will be set to
* false .
*
* Note : it is indeed okay to look at the local variable
* LocalMinRecoveryPoint here , even though ControlFile - > minRecoveryPoint
* might be further ahead - - - ControlFile - > minRecoveryPoint cannot have
* been advanced beyond the WAL we processed .
@ -5326,23 +5310,16 @@ StartupXLOG(void)
{
/*
* Ran off end of WAL before reaching end - of - backup WAL record , or
* minRecoveryPoint . That ' s usually a bad sign , indicating that you
* tried to recover from an online backup but never called
* pg_stop_backup ( ) , or you didn ' t archive all the WAL up to that
* point . However , this also happens in crash recovery , if the system
* crashes while an online backup is in progress . We must not treat
* that as an error , or the database will refuse to start up .
* minRecoveryPoint . That ' s a bad sign , indicating that you tried to
* recover from an online backup but never called pg_backup_stop ( ) ,
* or you didn ' t archive all the WAL needed .
*/
if ( ArchiveRecoveryRequested | | ControlFile - > backupEndRequired )
{
if ( ControlFile - > backupEndRequired )
if ( ! XLogRecPtrIsInvalid ( ControlFile - > backupStartPoint ) | | ControlFile - > backupEndRequired )
ereport ( FATAL ,
( errmsg ( " WAL ends before end of online backup " ) ,
errhint ( " All WAL generated while online backup was taken must be available at recovery. " ) ) ) ;
else if ( ! XLogRecPtrIsInvalid ( ControlFile - > backupStartPoint ) )
ereport ( FATAL ,
( errmsg ( " WAL ends before end of online backup " ) ,
errhint ( " Online backup started with pg_start_backup() must be ended with pg_stop_backup(), and all WAL up to that point must be available at recovery. " ) ) ) ;
else
ereport ( FATAL ,
( errmsg ( " WAL ends before consistent recovery point " ) ) ) ;
@ -7036,7 +7013,7 @@ CreateRestartPoint(int flags)
* Ensure minRecoveryPoint is past the checkpoint record . Normally ,
* this will have happened already while writing out dirty buffers ,
* but not necessarily - e . g . because no buffers were dirtied . We do
* this because a non - exclusive base backup uses minRecoveryPoint to
* this because a backup performed in recovery uses minRecoveryPoint to
* determine which WAL files must be included in the backup , and the
* file ( or files ) containing the checkpoint record must be included ,
* at a minimum . Note that for an ordinary restart of recovery there ' s
@ -7840,7 +7817,7 @@ xlog_redo(XLogReaderState *record)
/*
* Update the LSN of the last replayed XLOG_FPW_CHANGE record so that
* do_pg_start_ backup ( ) and do_pg_stop_ backup ( ) can check whether
* do_pg_backup_start ( ) and do_pg_backup_sto p ( ) 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_sto p ( ) or do_pg_abort_backup ( ) .
*
* It is the responsibility of the caller of this function to verify the
* permissions of the calling user !
*/
XLogRecPtr
do_pg_start_ backup ( const char * backupidstr , bool fast , TimeLineID * starttli_p ,
do_pg_backup_start ( const char * backupidstr , bool fast , TimeLineID * starttli_p ,
StringInfo labelfile , List * * tablespaces ,
StringInfo tblspcmapfile )
{
bool exclusive = ( labelfile = = NULL ) ;
bool backup_started_in_recovery = false ;
XLogRecPtr checkpointloc ;
XLogRecPtr startpoint ;
@ -8093,20 +8054,9 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
char strfbuf [ 128 ] ;
char xlogfilename [ MAXFNAMELEN ] ;
XLogSegNo _logSegNo ;
struct stat stat_buf ;
FILE * fp ;
backup_started_in_recovery = RecoveryInProgress ( ) ;
/*
* Currently only non - exclusive backup can be taken during recovery .
*/
if ( backup_started_in_recovery & & exclusive )
ereport ( ERROR ,
( errcode ( ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE ) ,
errmsg ( " recovery is in progress " ) ,
errhint ( " WAL control functions cannot be executed during recovery. " ) ) ) ;
/*
* During recovery , we don ' t need to check WAL level . Because , if WAL
* level is not sufficient , it ' s impossible to get here during recovery .
@ -8145,30 +8095,12 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
* XLogInsertRecord ( ) .
*/
WALInsertLockAcquireExclusive ( ) ;
if ( exclusive )
{
/*
* At first , mark that we ' re now starting an exclusive backup , to
* ensure that there are no other sessions currently running
* pg_start_backup ( ) or pg_stop_backup ( ) .
*/
if ( XLogCtl - > Insert . exclusiveBackupState ! = EXCLUSIVE_BACKUP_NONE )
{
WALInsertLockRelease ( ) ;
ereport ( ERROR ,
( errcode ( ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE ) ,
errmsg ( " a backup is already in progress " ) ,
errhint ( " Run pg_stop_backup() and try again. " ) ) ) ;
}
XLogCtl - > Insert . exclusiveBackupState = EXCLUSIVE_BACKUP_STARTING ;
}
else
XLogCtl - > Insert . nonExclusiveBackups + + ;
XLogCtl - > Insert . runningBackups + + ;
XLogCtl - > Insert . forcePageWrites = true ;
WALInsertLockRelease ( ) ;
/* Ensure we release forcePageWrites if fail below */
PG_ENSURE_ERROR_CLEANUP ( pg_start_ backup_callback , ( Datum ) BoolGetDatum ( exclusive ) ) ;
PG_ENSURE_ERROR_CLEANUP ( pg_backup_start_callback , ( Datum ) 0 ) ;
{
bool gotUniqueStartpoint = false ;
DIR * tblspcdir ;
@ -8180,7 +8112,7 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
* Force an XLOG file switch before the checkpoint , to ensure that the
* WAL segment the checkpoint is written to doesn ' t contain pages with
* old timeline IDs . That would otherwise happen if you called
* pg_start_ backup ( ) right after restoring from a PITR archive : the
* pg_backup_start ( ) right after restoring from a PITR archive : the
* first WAL segment containing the startup checkpoint has pages in
* the beginning with the old timeline ID . That can cause trouble at
* recovery : we won ' t have a history file covering the old timeline if
@ -8215,7 +8147,7 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
* means that two successive backup runs can have same checkpoint
* positions .
*
* Since the fact that we are executing do_pg_start_ backup ( )
* Since the fact that we are executing do_pg_backup_start ( )
* during recovery means that checkpointer is running , we can use
* RequestCheckpoint ( ) to establish a restartpoint .
*
@ -8416,122 +8348,19 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
LSN_FORMAT_ARGS ( startpoint ) , xlogfilename ) ;
appendStringInfo ( labelfile , " CHECKPOINT LOCATION: %X/%X \n " ,
LSN_FORMAT_ARGS ( checkpointloc ) ) ;
appendStringInfo ( labelfile , " BACKUP METHOD: %s \n " ,
exclusive ? " pg_start_backup " : " streamed " ) ;
appendStringInfo ( labelfile , " BACKUP METHOD: streamed \n " ) ;
appendStringInfo ( labelfile , " BACKUP FROM: %s \n " ,
backup_started_in_recovery ? " standby " : " primary " ) ;
appendStringInfo ( labelfile , " START TIME: %s \n " , strfbuf ) ;
appendStringInfo ( labelfile , " LABEL: %s \n " , backupidstr ) ;
appendStringInfo ( labelfile , " START TIMELINE: %u \n " , starttli ) ;
/*
* Okay , write the file , or return its contents to caller .
*/
if ( exclusive )
{
/*
* Check for existing backup label - - - implies a backup is already
* running . ( XXX given that we checked exclusiveBackupState
* above , maybe it would be OK to just unlink any such label
* file ? )
*/
if ( stat ( BACKUP_LABEL_FILE , & stat_buf ) ! = 0 )
{
if ( errno ! = ENOENT )
ereport ( ERROR ,
( errcode_for_file_access ( ) ,
errmsg ( " could not stat file \" %s \" : %m " ,
BACKUP_LABEL_FILE ) ) ) ;
}
else
ereport ( ERROR ,
( errcode ( ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE ) ,
errmsg ( " a backup is already in progress " ) ,
errhint ( " If you're sure there is no backup in progress, remove file \" %s \" and try again. " ,
BACKUP_LABEL_FILE ) ) ) ;
fp = AllocateFile ( BACKUP_LABEL_FILE , " w " ) ;
if ( ! fp )
ereport ( ERROR ,
( errcode_for_file_access ( ) ,
errmsg ( " could not create file \" %s \" : %m " ,
BACKUP_LABEL_FILE ) ) ) ;
if ( fwrite ( labelfile - > data , labelfile - > len , 1 , fp ) ! = 1 | |
fflush ( fp ) ! = 0 | |
pg_fsync ( fileno ( fp ) ) ! = 0 | |
ferror ( fp ) | |
FreeFile ( fp ) )
ereport ( ERROR ,
( errcode_for_file_access ( ) ,
errmsg ( " could not write file \" %s \" : %m " ,
BACKUP_LABEL_FILE ) ) ) ;
/* Allocated locally for exclusive backups, so free separately */
pfree ( labelfile - > data ) ;
pfree ( labelfile ) ;
/* Write backup tablespace_map file. */
if ( tblspcmapfile - > len > 0 )
{
if ( stat ( TABLESPACE_MAP , & stat_buf ) ! = 0 )
{
if ( errno ! = ENOENT )
ereport ( ERROR ,
( errcode_for_file_access ( ) ,
errmsg ( " could not stat file \" %s \" : %m " ,
TABLESPACE_MAP ) ) ) ;
}
else
ereport ( ERROR ,
( errcode ( ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE ) ,
errmsg ( " a backup is already in progress " ) ,
errhint ( " If you're sure there is no backup in progress, remove file \" %s \" and try again. " ,
TABLESPACE_MAP ) ) ) ;
fp = AllocateFile ( TABLESPACE_MAP , " w " ) ;
if ( ! fp )
ereport ( ERROR ,
( errcode_for_file_access ( ) ,
errmsg ( " could not create file \" %s \" : %m " ,
TABLESPACE_MAP ) ) ) ;
if ( fwrite ( tblspcmapfile - > data , tblspcmapfile - > len , 1 , fp ) ! = 1 | |
fflush ( fp ) ! = 0 | |
pg_fsync ( fileno ( fp ) ) ! = 0 | |
ferror ( fp ) | |
FreeFile ( fp ) )
ereport ( ERROR ,
( errcode_for_file_access ( ) ,
errmsg ( " could not write file \" %s \" : %m " ,
TABLESPACE_MAP ) ) ) ;
}
/* Allocated locally for exclusive backups, so free separately */
pfree ( tblspcmapfile - > data ) ;
pfree ( tblspcmapfile ) ;
}
}
PG_END_ENSURE_ERROR_CLEANUP ( pg_start_ backup_callback , ( Datum ) BoolGetDatum ( exclusive ) ) ;
PG_END_ENSURE_ERROR_CLEANUP ( pg_backup_start_callback , ( Datum ) 0 ) ;
/*
* Mark that start phase has correctly finished for an exclusive backup .
* Session - level locks are updated as well to reflect that state .
*
* Note that CHECK_FOR_INTERRUPTS ( ) must not occur while updating backup
* counters and session - level lock . Otherwise they can be updated
* inconsistently , and which might cause do_pg_abort_backup ( ) to fail .
* Mark that the start phase has correctly finished for the backup .
*/
if ( exclusive )
{
WALInsertLockAcquireExclusive ( ) ;
XLogCtl - > Insert . exclusiveBackupState = EXCLUSIVE_BACKUP_IN_PROGRESS ;
/* Set session-level lock */
sessionBackupState = SESSION_BACKUP_EXCLUSIVE ;
WALInsertLockRelease ( ) ;
}
else
sessionBackupState = SESSION_BACKUP_NON_EXCLUSIVE ;
sessionBackupState = SESSION_BACKUP_RUNNING ;
/*
* We ' re done . As a convenience , return the starting WAL location .
@ -8541,47 +8370,19 @@ do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
return startpoint ;
}
/* Error cleanup callback for pg_start_ backup */
/* Error cleanup callback for pg_backup_start */
static void
pg_start_ backup_callback ( int code , Datum arg )
pg_backup_start _callback ( int code , Datum arg )
{
bool exclusive = DatumGetBool ( arg ) ;
/* Update backup counters and forcePageWrites on failure */
WALInsertLockAcquireExclusive ( ) ;
if ( exclusive )
{
Assert ( XLogCtl - > Insert . exclusiveBackupState = = EXCLUSIVE_BACKUP_STARTING ) ;
XLogCtl - > Insert . exclusiveBackupState = EXCLUSIVE_BACKUP_NONE ;
}
else
{
Assert ( XLogCtl - > Insert . nonExclusiveBackups > 0 ) ;
XLogCtl - > Insert . nonExclusiveBackups - - ;
}
if ( XLogCtl - > Insert . exclusiveBackupState = = EXCLUSIVE_BACKUP_NONE & &
XLogCtl - > Insert . nonExclusiveBackups = = 0 )
{
XLogCtl - > Insert . forcePageWrites = false ;
}
WALInsertLockRelease ( ) ;
}
/*
* Error cleanup callback for pg_stop_backup
*/
static void
pg_stop_backup_callback ( int code , Datum arg )
{
bool exclusive = DatumGetBool ( arg ) ;
Assert ( XLogCtl - > Insert . runningBackups > 0 ) ;
XLogCtl - > Insert . runningBackups - - ;
/* Update backup status on failure */
WALInsertLockAcquireExclusive ( ) ;
if ( exclusive )
if ( XLogCtl - > Insert . runningBackups = = 0 )
{
Assert ( XLogCtl - > Insert . exclusiveBackupState = = EXCLUSIVE_BACKUP_STOPPING ) ;
XLogCtl - > Insert . exclusiveBackupState = EXCLUSIVE_BACKUP_IN_PROGRESS ;
XLogCtl - > Insert . forcePageWrites = false ;
}
WALInsertLockRelease ( ) ;
}
@ -8596,14 +8397,11 @@ get_backup_status(void)
}
/*
* do_pg_stop_ backup
* do_pg_backup_sto p
*
* 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_sto p ( char * labelfile , bool waitforarchive , TimeLineID * stoptli_p )
{
bool exclusive = ( labelfile = = NULL ) ;
bool backup_started_in_recovery = false ;
XLogRecPtr startpoint ;
XLogRecPtr stoppoint ;
@ -8627,7 +8424,6 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
char histfilename [ MAXFNAMELEN ] ;
char backupfrom [ 20 ] ;
XLogSegNo _logSegNo ;
FILE * lfp ;
FILE * fp ;
char ch ;
int seconds_before_warning ;
@ -8640,15 +8436,6 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
backup_started_in_recovery = RecoveryInProgress ( ) ;
/*
* Currently only non - exclusive backup can be taken during recovery .
*/
if ( backup_started_in_recovery & & exclusive )
ereport ( ERROR ,
( errcode ( ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE ) ,
errmsg ( " recovery is in progress " ) ,
errhint ( " WAL control functions cannot be executed during recovery. " ) ) ) ;
/*
* During recovery , we don ' t need to check WAL level . Because , if WAL
* level is not sufficient , it ' s impossible to get here during recovery .
@ -8659,106 +8446,23 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
errmsg ( " WAL level not sufficient for making an online backup " ) ,
errhint ( " wal_level must be set to \" replica \" or \" logical \" at server start. " ) ) ) ;
if ( exclusive )
{
/*
* At first , mark that we ' re now stopping an exclusive backup , to
* ensure that there are no other sessions currently running
* pg_start_backup ( ) or pg_stop_backup ( ) .
*/
WALInsertLockAcquireExclusive ( ) ;
if ( XLogCtl - > Insert . exclusiveBackupState ! = EXCLUSIVE_BACKUP_IN_PROGRESS )
{
WALInsertLockRelease ( ) ;
ereport ( ERROR ,
( errcode ( ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE ) ,
errmsg ( " exclusive backup not in progress " ) ) ) ;
}
XLogCtl - > Insert . exclusiveBackupState = EXCLUSIVE_BACKUP_STOPPING ;
WALInsertLockRelease ( ) ;
/*
* Remove backup_label . In case of failure , the state for an exclusive
* backup is switched back to in - progress .
*/
PG_ENSURE_ERROR_CLEANUP ( pg_stop_backup_callback , ( Datum ) BoolGetDatum ( exclusive ) ) ;
{
/*
* Read the existing label file into memory .
*/
struct stat statbuf ;
int r ;
if ( stat ( BACKUP_LABEL_FILE , & statbuf ) )
{
/* should not happen per the upper checks */
if ( errno ! = ENOENT )
ereport ( ERROR ,
( errcode_for_file_access ( ) ,
errmsg ( " could not stat file \" %s \" : %m " ,
BACKUP_LABEL_FILE ) ) ) ;
ereport ( ERROR ,
( errcode ( ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE ) ,
errmsg ( " a backup is not in progress " ) ) ) ;
}
lfp = AllocateFile ( BACKUP_LABEL_FILE , " r " ) ;
if ( ! lfp )
{
ereport ( ERROR ,
( errcode_for_file_access ( ) ,
errmsg ( " could not read file \" %s \" : %m " ,
BACKUP_LABEL_FILE ) ) ) ;
}
labelfile = palloc ( statbuf . st_size + 1 ) ;
r = fread ( labelfile , statbuf . st_size , 1 , lfp ) ;
labelfile [ statbuf . st_size ] = ' \0 ' ;
/*
* Close and remove the backup label file
*/
if ( r ! = 1 | | ferror ( lfp ) | | FreeFile ( lfp ) )
ereport ( ERROR ,
( errcode_for_file_access ( ) ,
errmsg ( " could not read file \" %s \" : %m " ,
BACKUP_LABEL_FILE ) ) ) ;
durable_unlink ( BACKUP_LABEL_FILE , ERROR ) ;
/*
* Remove tablespace_map file if present , it is created only if
* there are tablespaces .
*/
durable_unlink ( TABLESPACE_MAP , DEBUG1 ) ;
}
PG_END_ENSURE_ERROR_CLEANUP ( pg_stop_backup_callback , ( Datum ) BoolGetDatum ( exclusive ) ) ;
}
/*
* OK to update backup counters , forcePageWrites and session - level lock .
* OK to update backup counters , forcePageWrites , and session - level lock .
*
* Note that CHECK_FOR_INTERRUPTS ( ) must not occur while updating them .
* Otherwise they can be updated inconsistently , and which might cause
* do_pg_abort_backup ( ) to fail .
*/
WALInsertLockAcquireExclusive ( ) ;
if ( exclusive )
{
XLogCtl - > Insert . exclusiveBackupState = EXCLUSIVE_BACKUP_NONE ;
}
else
{
/*
* The user - visible pg_start / stop_backup ( ) functions that operate on
* exclusive backups can be called at any time , but for non - exclusive
* backups , it is expected that each do_pg_start_backup ( ) call is
* matched by exactly one do_pg_stop_backup ( ) call .
*/
Assert ( XLogCtl - > Insert . nonExclusiveBackups > 0 ) ;
XLogCtl - > Insert . nonExclusiveBackups - - ;
}
if ( XLogCtl - > Insert . exclusiveBackupState = = EXCLUSIVE_BACKUP_NONE & &
XLogCtl - > Insert . nonExclusiveBackups = = 0 )
/*
* It is expected that each do_pg_backup_start ( ) call is matched by exactly
* one do_pg_backup_stop ( ) call .
*/
Assert ( XLogCtl - > Insert . runningBackups > 0 ) ;
XLogCtl - > Insert . runningBackups - - ;
if ( XLogCtl - > Insert . runningBackups = = 0 )
{
XLogCtl - > Insert . forcePageWrites = false ;
}
@ -9016,17 +8720,13 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
/*
* do_pg_abort_backup : abort a running backup
*
* This does just the most basic steps of do_pg_stop_ backup ( ) , by taking the
* This does just the most basic steps of do_pg_backup_sto p ( ) , 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 . nonExclusive Backups > 0 ) ;
XLogCtl - > Insert . nonExclusive Backups- - ;
Assert ( XLogCtl - > Insert . running Backups > 0 ) ;
XLogCtl - > Insert . running Backups- - ;
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_sto p 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 )