mirror of
https://github.com/postgrespro/pg_probackup.git
synced 2024-11-24 08:52:38 +02:00
Remove un-needed WAL segments from archive at backup deletion
During the execution of the "delete" command, the oldest start LSN is saved and used to determine what is the oldest WAL segment that needs to be kept for the existing backups. Like pg_archivecleanup, the implemented logic ignores the timeline part of the WAL segment name, ensuring that a segment from a parent timeline will not be removed prematurely. This logic could be made more complicated regarding this matter, but in order to take backups from a node on a given timeline this is far enough.
This commit is contained in:
parent
a5afc8758e
commit
f2c523b1ee
91
delete.c
91
delete.c
@ -9,15 +9,20 @@
|
||||
|
||||
#include "pg_arman.h"
|
||||
|
||||
#include <dirent.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static int pgBackupDeleteFiles(pgBackup *backup);
|
||||
|
||||
int
|
||||
do_delete(pgBackupRange *range)
|
||||
{
|
||||
int i;
|
||||
int ret;
|
||||
parray *backup_list;
|
||||
bool do_delete = false;
|
||||
int i;
|
||||
int ret;
|
||||
parray *backup_list;
|
||||
bool do_delete = false;
|
||||
XLogRecPtr oldest_lsn = InvalidXLogRecPtr;
|
||||
TimeLineID oldest_tli;
|
||||
|
||||
/* DATE are always required */
|
||||
if (!pgBackupRangeIsValid(range))
|
||||
@ -56,7 +61,11 @@ do_delete(pgBackupRange *range)
|
||||
if (backup->backup_mode >= BACKUP_MODE_FULL &&
|
||||
backup->status == BACKUP_STATUS_OK &&
|
||||
backup->start_time <= range->begin)
|
||||
{
|
||||
do_delete = true;
|
||||
oldest_lsn = backup->start_lsn;
|
||||
oldest_tli = backup->tli;
|
||||
}
|
||||
}
|
||||
|
||||
/* release catalog lock */
|
||||
@ -65,6 +74,80 @@ do_delete(pgBackupRange *range)
|
||||
/* cleanup */
|
||||
parray_walk(backup_list, pgBackupFree);
|
||||
parray_free(backup_list);
|
||||
|
||||
/*
|
||||
* Delete in archive WAL segments that are not needed anymore. The oldest
|
||||
* segment to be kept is the first segment that the oldest full backup
|
||||
* found around needs to keep.
|
||||
*/
|
||||
if (!XLogRecPtrIsInvalid(oldest_lsn))
|
||||
{
|
||||
XLogSegNo targetSegNo;
|
||||
char oldestSegmentNeeded[MAXFNAMELEN];
|
||||
DIR *arcdir;
|
||||
struct dirent *arcde;
|
||||
char wal_file[MAXPGPATH];
|
||||
int rc;
|
||||
|
||||
XLByteToSeg(oldest_lsn, targetSegNo);
|
||||
XLogFileName(oldestSegmentNeeded, oldest_tli, targetSegNo);
|
||||
elog(LOG, "Removing segments older than %s", oldestSegmentNeeded);
|
||||
|
||||
/*
|
||||
* Now is time to do the actual work and to remove all the segments
|
||||
* not needed anymore.
|
||||
*/
|
||||
if ((arcdir = opendir(arclog_path)) != NULL)
|
||||
{
|
||||
while (errno = 0, (arcde = readdir(arcdir)) != NULL)
|
||||
{
|
||||
/*
|
||||
* We ignore the timeline part of the XLOG segment identifiers in
|
||||
* deciding whether a segment is still needed. This ensures that
|
||||
* we won't prematurely remove a segment from a parent timeline.
|
||||
* We could probably be a little more proactive about removing
|
||||
* segments of non-parent timelines, but that would be a whole lot
|
||||
* more complicated.
|
||||
*
|
||||
* We use the alphanumeric sorting property of the filenames to
|
||||
* decide which ones are earlier than the exclusiveCleanupFileName
|
||||
* file. Note that this means files are not removed in the order
|
||||
* they were originally written, in case this worries you.
|
||||
*/
|
||||
if ((IsXLogFileName(arcde->d_name) ||
|
||||
IsPartialXLogFileName(arcde->d_name)) &&
|
||||
strcmp(arcde->d_name + 8, oldestSegmentNeeded + 8) < 0)
|
||||
{
|
||||
/*
|
||||
* Use the original file name again now, including any
|
||||
* extension that might have been chopped off before testing
|
||||
* the sequence.
|
||||
*/
|
||||
snprintf(wal_file, MAXPGPATH, "%s/%s",
|
||||
arclog_path, arcde->d_name);
|
||||
|
||||
rc = unlink(wal_file);
|
||||
if (rc != 0)
|
||||
{
|
||||
elog(WARNING, "could not remove file \"%s\": %s",
|
||||
wal_file, strerror(errno));
|
||||
break;
|
||||
}
|
||||
elog(LOG, "removed WAL segment \"%s\"", wal_file);
|
||||
}
|
||||
}
|
||||
if (errno)
|
||||
elog(WARNING, "could not read archive location \"%s\": %s",
|
||||
arclog_path, strerror(errno));
|
||||
if (closedir(arcdir))
|
||||
elog(WARNING, "could not close archive location \"%s\": %s",
|
||||
arclog_path, strerror(errno));
|
||||
}
|
||||
else
|
||||
elog(WARNING, "could not open archive location \"%s\": %s",
|
||||
arclog_path, strerror(errno));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -178,7 +178,9 @@ You can check the "RECOVERY_XID" and "RECOVERY_TIME" which are used for
|
||||
restore option "--recovery-target-xid", "--recovery-target-time".
|
||||
|
||||
The delete command deletes backup files not required by recovery after
|
||||
the specified date.
|
||||
the specified date. This command also cleans up in the WAL archive the
|
||||
WAL segments that are no longer needed to restore from the remaining
|
||||
backups.
|
||||
|
||||
== OPTIONS ==
|
||||
|
||||
|
@ -72,37 +72,42 @@ ERROR: invalid backup-mode "bad"
|
||||
12
|
||||
|
||||
###### COMMAND OPTION TEST-0006 ######
|
||||
###### delete failure without archive path ######
|
||||
ERROR: delete command needs ARCLOG_PATH (-A, --arclog-path) to be set
|
||||
12
|
||||
|
||||
###### COMMAND OPTION TEST-0007 ######
|
||||
###### delete failure without DATE ######
|
||||
ERROR: required delete range option not specified: delete DATE
|
||||
12
|
||||
|
||||
###### COMMAND OPTION TEST-0007 ######
|
||||
###### COMMAND OPTION TEST-0008 ######
|
||||
###### syntax error in pg_arman.ini ######
|
||||
WARNING: syntax error in " = INFINITE"
|
||||
ERROR: Required parameter not specified: BACKUP_MODE (-b, --backup-mode)
|
||||
12
|
||||
|
||||
###### COMMAND OPTION TEST-0008 ######
|
||||
###### COMMAND OPTION TEST-0009 ######
|
||||
###### invalid value in pg_arman.ini ######
|
||||
ERROR: invalid backup-mode ""
|
||||
12
|
||||
|
||||
###### COMMAND OPTION TEST-0009 ######
|
||||
###### COMMAND OPTION TEST-0010 ######
|
||||
###### invalid value in pg_arman.ini ######
|
||||
ERROR: option --keep-data-generations should be a 32bit signed integer: 'TRUE'
|
||||
12
|
||||
|
||||
###### COMMAND OPTION TEST-0010 ######
|
||||
###### COMMAND OPTION TEST-0011 ######
|
||||
###### invalid value in pg_arman.ini ######
|
||||
ERROR: option -C, --smooth-checkpoint should be a boolean: 'FOO'
|
||||
12
|
||||
|
||||
###### COMMAND OPTION TEST-0011 ######
|
||||
###### COMMAND OPTION TEST-0012 ######
|
||||
###### invalid option in pg_arman.ini ######
|
||||
ERROR: invalid option "TIMELINEID"
|
||||
12
|
||||
|
||||
###### COMMAND OPTION TEST-0012 ######
|
||||
###### COMMAND OPTION TEST-0013 ######
|
||||
###### check priority of several pg_arman.ini files ######
|
||||
ERROR: invalid backup-mode "ENV_PATH"
|
||||
12
|
||||
|
@ -148,6 +148,10 @@ main(int argc, char *argv[])
|
||||
if (arclog_path != NULL && !is_absolute_path(arclog_path))
|
||||
elog(ERROR_ARGS, "-A, --arclog-path must be an absolute path");
|
||||
|
||||
/* Sanity checks with commands */
|
||||
if (pg_strcasecmp(cmd, "delete") == 0 && arclog_path == NULL)
|
||||
elog(ERROR_ARGS, "delete command needs ARCLOG_PATH (-A, --arclog-path) to be set");
|
||||
|
||||
/* setup exclusion list for file search */
|
||||
for (i = 0; pgdata_exclude[i]; i++) /* find first empty slot */
|
||||
;
|
||||
|
@ -35,47 +35,52 @@ pg_arman backup -B ${BACKUP_PATH} -A ${ARCLOG_PATH} -b bad -p ${TEST_PGPORT};ech
|
||||
echo ''
|
||||
|
||||
echo '###### COMMAND OPTION TEST-0006 ######'
|
||||
echo '###### delete failure without DATE ######'
|
||||
echo '###### delete failure without archive path ######'
|
||||
pg_arman delete -B ${BACKUP_PATH};echo $?
|
||||
echo ''
|
||||
|
||||
echo '###### COMMAND OPTION TEST-0007 ######'
|
||||
echo '###### delete failure without DATE ######'
|
||||
pg_arman delete -B ${BACKUP_PATH} -A ${ARCLOG_PATH};echo $?
|
||||
echo ''
|
||||
|
||||
init_backup
|
||||
|
||||
echo '###### COMMAND OPTION TEST-0007 ######'
|
||||
echo '###### COMMAND OPTION TEST-0008 ######'
|
||||
echo '###### syntax error in pg_arman.ini ######'
|
||||
echo " = INFINITE" >> ${BACKUP_PATH}/pg_arman.ini
|
||||
pg_arman backup -B ${BACKUP_PATH} -A ${ARCLOG_PATH} -p ${TEST_PGPORT};echo $?
|
||||
echo ''
|
||||
|
||||
echo '###### COMMAND OPTION TEST-0008 ######'
|
||||
echo '###### invalid value in pg_arman.ini ######'
|
||||
init_catalog
|
||||
echo "BACKUP_MODE=" >> ${BACKUP_PATH}/pg_arman.ini
|
||||
pg_arman backup -B ${BACKUP_PATH} -A ${ARCLOG_PATH} -p ${TEST_PGPORT};echo $?
|
||||
echo ''
|
||||
|
||||
echo '###### COMMAND OPTION TEST-0009 ######'
|
||||
echo '###### invalid value in pg_arman.ini ######'
|
||||
init_catalog
|
||||
echo "BACKUP_MODE=" >> ${BACKUP_PATH}/pg_arman.ini
|
||||
pg_arman backup -B ${BACKUP_PATH} -A ${ARCLOG_PATH} -p ${TEST_PGPORT};echo $?
|
||||
echo ''
|
||||
|
||||
echo '###### COMMAND OPTION TEST-0010 ######'
|
||||
echo '###### invalid value in pg_arman.ini ######'
|
||||
init_catalog
|
||||
echo "KEEP_DATA_GENERATIONS=TRUE" >> ${BACKUP_PATH}/pg_arman.ini
|
||||
pg_arman backup -B ${BACKUP_PATH} -A ${ARCLOG_PATH} -b full -p ${TEST_PGPORT};echo $?
|
||||
echo ''
|
||||
|
||||
echo '###### COMMAND OPTION TEST-0010 ######'
|
||||
echo '###### COMMAND OPTION TEST-0011 ######'
|
||||
echo '###### invalid value in pg_arman.ini ######'
|
||||
init_catalog
|
||||
echo "SMOOTH_CHECKPOINT=FOO" >> ${BACKUP_PATH}/pg_arman.ini
|
||||
pg_arman backup -B ${BACKUP_PATH} -A ${ARCLOG_PATH} -b full -p ${TEST_PGPORT};echo $?
|
||||
echo ''
|
||||
|
||||
echo '###### COMMAND OPTION TEST-0011 ######'
|
||||
echo '###### COMMAND OPTION TEST-0012 ######'
|
||||
echo '###### invalid option in pg_arman.ini ######'
|
||||
init_catalog
|
||||
echo "TIMELINEID=1" >> ${BACKUP_PATH}/pg_arman.ini
|
||||
pg_arman backup -B ${BACKUP_PATH} -A ${ARCLOG_PATH} -b full -p ${TEST_PGPORT};echo $?
|
||||
echo ''
|
||||
|
||||
echo '###### COMMAND OPTION TEST-0012 ######'
|
||||
echo '###### COMMAND OPTION TEST-0013 ######'
|
||||
echo '###### check priority of several pg_arman.ini files ######'
|
||||
init_catalog
|
||||
mkdir -p ${BACKUP_PATH}/conf_path_a
|
||||
|
Loading…
Reference in New Issue
Block a user