1
0
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:
Michael Paquier 2016-01-18 16:11:47 +09:00
parent a5afc8758e
commit f2c523b1ee
5 changed files with 122 additions and 23 deletions

View File

@ -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;
}

View File

@ -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 ==

View File

@ -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

View File

@ -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 */
;

View File

@ -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