1
0
mirror of https://github.com/postgrespro/pg_probackup.git synced 2024-11-24 08:52:38 +02:00

Rewrite delete backup logic.

This commit is contained in:
stalkerg 2016-11-09 17:29:48 +03:00
parent ed3e7a5551
commit c1f1627c0b
8 changed files with 73 additions and 68 deletions

View File

@ -18,11 +18,12 @@ int
do_delete(time_t backup_id) do_delete(time_t backup_id)
{ {
int i; int i;
int b_index;
int ret; int ret;
parray *backup_list; parray *backup_list;
bool do_delete = false;
XLogRecPtr oldest_lsn = InvalidXLogRecPtr; XLogRecPtr oldest_lsn = InvalidXLogRecPtr;
TimeLineID oldest_tli; TimeLineID oldest_tli;
pgBackup *last_backup;
/* DATE are always required */ /* DATE are always required */
if (backup_id == 0) if (backup_id == 0)
@ -41,31 +42,38 @@ do_delete(time_t backup_id)
if (!backup_list) if (!backup_list)
elog(ERROR, "No backup list found, can't process any more."); elog(ERROR, "No backup list found, can't process any more.");
/* Find backups to be deleted */ /* Find backup to be deleted */
for (i = 0; i < parray_num(backup_list); i++) for (i = 0; i < parray_num(backup_list); i++)
{
last_backup = (pgBackup *) parray_get(backup_list, i);
if (last_backup->status == BACKUP_STATUS_OK &&
last_backup->start_time == backup_id
)
goto found_backup;
}
elog(ERROR, "no backup found, cannot delete.");
found_backup:
b_index = i;
/* check for interrupt */
if (interrupted)
elog(ERROR, "interrupted during delete backup");
/* just do it */
pgBackupDeleteFiles(last_backup);
/* remove all increments after removed backup */
for (i = b_index - 1; i >= 0; i--)
{ {
pgBackup *backup = (pgBackup *) parray_get(backup_list, i); pgBackup *backup = (pgBackup *) parray_get(backup_list, i);
if (backup->backup_mode >= BACKUP_MODE_FULL)
/* delete backup and update status to DELETED */ break;
if (do_delete) if (backup->status == BACKUP_STATUS_OK ||
{ backup->backup_mode == BACKUP_MODE_DIFF_PAGE ||
/* check for interrupt */ backup->backup_mode == BACKUP_MODE_DIFF_PTRACK
if (interrupted) )
elog(ERROR, "interrupted during delete backup");
pgBackupDeleteFiles(backup); pgBackupDeleteFiles(backup);
continue;
}
/* Found the latest full backup */
if (backup->backup_mode >= BACKUP_MODE_FULL &&
backup->status == BACKUP_STATUS_OK &&
backup->start_time <= backup_id)
{
do_delete = true;
oldest_lsn = backup->start_lsn;
oldest_tli = backup->tli;
}
} }
/* release catalog lock */ /* release catalog lock */
@ -74,13 +82,37 @@ do_delete(time_t backup_id)
/* cleanup */ /* cleanup */
parray_walk(backup_list, pgBackupFree); parray_walk(backup_list, pgBackupFree);
parray_free(backup_list); parray_free(backup_list);
/* /*
* Delete in archive WAL segments that are not needed anymore. The oldest * 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 * segment to be kept is the first segment that the oldest full backup
* found around needs to keep. * found around needs to keep.
*/ */
if (!XLogRecPtrIsInvalid(oldest_lsn)) if (delete_wal)
{
/* Lock backup catalog */
ret = catalog_lock();
if (ret == -1)
elog(ERROR, "can't lock backup catalog.");
else if (ret == 1)
elog(ERROR,
"another pg_arman is running, stop delete.");
backup_list = catalog_get_backup_list(0);
for (i = 0; i < parray_num(backup_list); i++)
{
last_backup = (pgBackup *) parray_get(backup_list, i);
if (last_backup->status == BACKUP_STATUS_OK)
{
oldest_lsn = last_backup->start_lsn;
oldest_tli = last_backup->tli;
}
}
catalog_unlock();
parray_walk(backup_list, pgBackupFree);
parray_free(backup_list);
}
if (delete_wal && !XLogRecPtrIsInvalid(oldest_lsn))
{ {
XLogSegNo targetSegNo; XLogSegNo targetSegNo;
char oldestSegmentNeeded[MAXFNAMELEN]; char oldestSegmentNeeded[MAXFNAMELEN];
@ -263,7 +295,8 @@ pgBackupDeleteFiles(pgBackup *backup)
time2iso(timestamp, lengthof(timestamp), backup->start_time); time2iso(timestamp, lengthof(timestamp), backup->start_time);
elog(INFO, "delete: %s", timestamp); elog(INFO, "delete: %s %s", base36enc(backup->start_time), timestamp);
/* /*
* Update STATUS to BACKUP_STATUS_DELETING in preparation for the case which * Update STATUS to BACKUP_STATUS_DELETING in preparation for the case which
@ -277,7 +310,7 @@ pgBackupDeleteFiles(pgBackup *backup)
/* list files to be deleted */ /* list files to be deleted */
files = parray_new(); files = parray_new();
pgBackupGetPath(backup, path, lengthof(path), DATABASE_DIR); pgBackupGetPath(backup, path, lengthof(path), NULL);
dir_list_file(files, path, NULL, true, true); dir_list_file(files, path, NULL, true, true);
/* delete leaf node first */ /* delete leaf node first */
@ -304,16 +337,6 @@ pgBackupDeleteFiles(pgBackup *backup)
} }
} }
/*
* After deleting all of the backup files, update STATUS to
* BACKUP_STATUS_DELETED.
*/
if (!check)
{
backup->status = BACKUP_STATUS_DELETED;
pgBackupWriteIni(backup);
}
parray_walk(files, pgFileFree); parray_walk(files, pgFileFree);
parray_free(files); parray_free(files);

View File

@ -24,7 +24,7 @@ OK. Let's try to test --keep-data-generations=1.
9 9
0 0
Number of remaining full backups validated: 2 Number of remaining full backups validated: 2
Number of deleted backups : 2 Number of deleted backups : 0
6 6
###### BACKUP COMMAND TEST-0005 ###### ###### BACKUP COMMAND TEST-0005 ######
###### switch backup mode from page to full ###### ###### switch backup mode from page to full ######

View File

@ -3,11 +3,11 @@
###### delete full backups ###### ###### delete full backups ######
try to delete the oldest backup try to delete the oldest backup
2 2
1 0
Number of deleted backups should be 1, is it so?: 1 Number of deleted backups should be 1, is it so?: 0
###### DELETE COMMAND TEST-0002 ###### ###### DELETE COMMAND TEST-0002 ######
###### keep backups which are necessary for recovery ###### ###### keep backups which are necessary for recovery ######
try to delete before third backup try to delete before third backup
3 3
1 0
Number of deleted backups should be 1, is it so?: 1 Number of deleted backups should be 1, is it so?: 0

View File

@ -36,6 +36,9 @@ Restore options:
Catalog options: Catalog options:
-a, --show-all show deleted backup too -a, --show-all show deleted backup too
Delete options:
--wal remove unnecessary wal archives also
Connection options: Connection options:
-d, --dbname=DBNAME database to connect -d, --dbname=DBNAME database to connect
-h, --host=HOSTNAME database server host or socket directory -h, --host=HOSTNAME database server host or socket directory

View File

@ -17,12 +17,3 @@ remove a file from backup intentionally
0 0
NG: CORRUPT status is not shown. NG: CORRUPT status is not shown.
###### SHOW COMMAND TEST-0004 ######
###### Status DELETED ######
0
0
0
0
0
OK: DELETED status is shown properly.

View File

@ -39,6 +39,7 @@ bool stream_wal = false;
bool from_replica = false; bool from_replica = false;
static bool backup_logs = false; static bool backup_logs = false;
bool progress = false; bool progress = false;
bool delete_wal = false;
/* restore configuration */ /* restore configuration */
static char *target_time; static char *target_time;
@ -76,6 +77,8 @@ static pgut_option options[] =
{ 'u', 6, "recovery-target-timeline", &target_tli, SOURCE_ENV }, { 'u', 6, "recovery-target-timeline", &target_tli, SOURCE_ENV },
/* catalog options */ /* catalog options */
{ 'b', 'a', "show-all", &show_all }, { 'b', 'a', "show-all", &show_all },
/* delete options */
{ 'b', 12, "wal", &delete_wal },
{ 0 } { 0 }
}; };
@ -248,6 +251,8 @@ pgut_help(bool details)
printf(_(" --recovery-target-timeline recovering into a particular timeline\n")); printf(_(" --recovery-target-timeline recovering into a particular timeline\n"));
printf(_("\nCatalog options:\n")); printf(_("\nCatalog options:\n"));
printf(_(" -a, --show-all show deleted backup too\n")); printf(_(" -a, --show-all show deleted backup too\n"));
printf(_("\nDelete options:\n"));
printf(_(" --wal remove unnecessary wal archives also\n"));
} }
static void static void

View File

@ -204,6 +204,7 @@ extern int num_threads;
extern bool stream_wal; extern bool stream_wal;
extern bool from_replica; extern bool from_replica;
extern bool progress; extern bool progress;
extern bool delete_wal;
/* in backup.c */ /* in backup.c */
extern int do_backup(pgBackupOption bkupopt); extern int do_backup(pgBackupOption bkupopt);

View File

@ -65,24 +65,6 @@ else
fi fi
echo '' echo ''
echo '###### SHOW COMMAND TEST-0004 ######'
echo '###### Status DELETED ######'
init_catalog
pg_arman backup -B ${BACKUP_PATH} -b full -p ${TEST_PGPORT} -d postgres --quiet;echo $?
pg_arman validate -B ${BACKUP_PATH} --quiet > /dev/null 2>&1;echo $?
pg_arman backup -B ${BACKUP_PATH} -b full -p ${TEST_PGPORT} -d postgres --quiet;echo $?
DELETE_DATE=$(get_time_last_backup)
pg_arman validate -B ${BACKUP_PATH} --quiet > /dev/null 2>&1;echo $?
pg_arman delete ${DELETE_DATE} -B ${BACKUP_PATH} > /dev/null 2>&1;echo $?
pg_arman show -B ${BACKUP_PATH} > ${TEST_BASE}/TEST-0004-show.out 2>&1
pg_arman show -a -B ${BACKUP_PATH} > ${TEST_BASE}/TEST-0004-show-all.out 2>&1
if ! grep "DELETED" ${TEST_BASE}/TEST-0004-show.out > /dev/null && grep "DELETED" ${TEST_BASE}/TEST-0004-show-all.out > /dev/null ; then
echo 'OK: DELETED status is shown properly.'
else
echo 'NG: DELETED status is not shown.'
fi
echo ''
# clean up the temporal test data # clean up the temporal test data
pg_ctl stop -D ${PGDATA_PATH} -m immediate > /dev/null 2>&1 pg_ctl stop -D ${PGDATA_PATH} -m immediate > /dev/null 2>&1
rm -fr ${PGDATA_PATH} rm -fr ${PGDATA_PATH}