1
0
mirror of https://github.com/postgrespro/pg_probackup.git synced 2025-02-09 14:33:17 +02:00

code cleanup for wal_delete refactoring

This commit is contained in:
Anastasia 2019-09-23 13:14:57 +03:00
parent c9d3c5845a
commit 1f67593175
2 changed files with 106 additions and 111 deletions

View File

@ -19,8 +19,8 @@
#include "utils/file.h"
#include "utils/configuration.h"
static pgBackup* get_closest_backup(timelineInfo *tlinfo, parray *backup_list);
static pgBackup* get_oldest_backup(timelineInfo *tlinfo, parray *backup_list);
static pgBackup* get_closest_backup(timelineInfo *tlinfo);
static pgBackup* get_oldest_backup(timelineInfo *tlinfo);
static const char *backupModes[] = {"", "PAGE", "PTRACK", "DELTA", "FULL"};
static pgBackup *readBackupControlFile(const char *path);
@ -891,75 +891,57 @@ catalog_get_timelines(InstanceConfig *instance)
{
timelineInfo *tlinfo = parray_get(timelineinfos, i);
tlinfo->oldest_backup = get_oldest_backup(tlinfo, backups);
tlinfo->closest_backup = get_closest_backup(tlinfo, backups);
tlinfo->oldest_backup = get_oldest_backup(tlinfo);
tlinfo->closest_backup = get_closest_backup(tlinfo);
}
//parray_walk(xlog_files_list, pfree);
//parray_free(xlog_files_list);
return timelineinfos;
}
/*
* Iterate over parent timelines of a given timeline and look
* for valid backup closest to given timeline switchpoint.
* Iterate over parent timelines and look for valid backup
* closest to given timeline switchpoint.
*
* Returns NULL if such backup is not found.
* If such backup doesn't exist, it means that
* timeline is unreachable. Return NULL.
*/
pgBackup*
get_closest_backup(timelineInfo *tlinfo, parray *backup_list)
get_closest_backup(timelineInfo *tlinfo)
{
pgBackup *closest_backup = NULL;
int i;
/* Only timeline with switchpoint can possibly have closest backup */
if (XLogRecPtrIsInvalid(tlinfo->switchpoint))
return NULL;
/* Only timeline with parent timeline can possibly have closest backup */
if (!tlinfo->parent_link)
return NULL;
while (tlinfo->parent_link)
/*
* Iterate over backups belonging to parent timelines
* and look for candidates.
*/
while (tlinfo->parent_link && !closest_backup)
{
/*
* Iterate over backups belonging to parent timeline and look
* for candidates.
*/
for (i = 0; i < parray_num(backup_list); i++)
parray *backup_list = tlinfo->parent_link->backups;
if (backup_list != NULL)
{
pgBackup *backup = parray_get(backup_list, i);
/* Backups belonging to timelines other than parent timeline can be safely skipped */
if (backup->tli != tlinfo->parent_tli)
continue;
/* Backups in future can be safely skipped */
if (backup->stop_lsn > tlinfo->switchpoint)
continue;
/* Backups with invalid STOP LSN can be safely skipped */
if (XLogRecPtrIsInvalid(backup->stop_lsn) ||
!XRecOffIsValid(backup->stop_lsn))
continue;
/* Only valid backups closest to switchpoint should be considered */
if (backup->stop_lsn <= tlinfo->switchpoint &&
(backup->status == BACKUP_STATUS_OK ||
backup->status == BACKUP_STATUS_DONE))
for (i = 0; i < parray_num(backup_list); i++)
{
/* Check if backup is closer to switchpoint than current candidate */
if (!closest_backup || backup->stop_lsn > closest_backup->stop_lsn)
closest_backup = backup;
pgBackup *backup = parray_get(backup_list, i);
/*
* Only valid backups made before switchpoint
* should be considered.
*/
if (!XLogRecPtrIsInvalid(backup->stop_lsn) &&
!XRecOffIsValid(backup->stop_lsn) &&
backup->stop_lsn <= tlinfo->switchpoint &&
(backup->status == BACKUP_STATUS_OK ||
backup->status == BACKUP_STATUS_DONE))
{
/* Check if backup is closer to switchpoint than current candidate */
if (!closest_backup || backup->stop_lsn > closest_backup->stop_lsn)
closest_backup = backup;
}
}
}
/* Closest backup is found */
if (closest_backup)
break;
/* Switch to parent */
/* Continue with parent */
tlinfo = tlinfo->parent_link;
}
@ -967,35 +949,38 @@ get_closest_backup(timelineInfo *tlinfo, parray *backup_list)
}
/*
* Iterate over timelines and look for oldest backup on each timeline
* Find oldest backup in given timeline
* to determine what WAL segments belonging to this timeline,
* are not reachable from any backup.
*
* Returns NULL if such backup is not found.
*/
pgBackup*
get_oldest_backup(timelineInfo *tlinfo, parray *backup_list)
get_oldest_backup(timelineInfo *tlinfo)
{
pgBackup *oldest_backup = NULL;
int i;
parray *backup_list = tlinfo->backups;
/*
* Iterate over backups belonging to timeline and look
* for candidates.
*/
for (i = 0; i < parray_num(backup_list); i++)
if (backup_list != NULL)
{
pgBackup *backup = parray_get(backup_list, i);
for (i = 0; i < parray_num(backup_list); i++)
{
pgBackup *backup = parray_get(backup_list, i);
/* Backups belonging to other timelines can be safely skipped */
if (backup->tli != tlinfo->tli)
continue;
/* Backups with invalid START LSN can be safely skipped */
if (XLogRecPtrIsInvalid(backup->start_lsn) ||
!XRecOffIsValid(backup->start_lsn))
continue;
/* Backups with invalid START LSN can be safely skipped */
if (XLogRecPtrIsInvalid(backup->start_lsn) ||
!XRecOffIsValid(backup->start_lsn))
continue;
/* Check if backup is older than current candidate */
if (!oldest_backup || backup->start_lsn < oldest_backup->start_lsn)
oldest_backup = backup;
/*
* Check if backup is older than current candidate.
* Here we use start_lsn for comparison, because backup that
* started earlier needs more WAL.
*/
if (!oldest_backup || backup->start_lsn < oldest_backup->start_lsn)
oldest_backup = backup;
}
}
return oldest_backup;

View File

@ -14,7 +14,7 @@
#include <time.h>
#include <unistd.h>
static void delete_walfiles(XLogRecPtr keep_lsn, timelineInfo *tli,
static void delete_walfiles_in_tli(XLogRecPtr keep_lsn, timelineInfo *tli,
uint32 xlog_seg_size, bool dry_run);
static void do_retention_internal(parray *backup_list, parray *to_keep_list,
parray *to_purge_list);
@ -607,10 +607,11 @@ do_retention_purge(parray *to_keep_list, parray *to_purge_list)
}
}
/* Purge WAL
/*
* Purge WAL
* Iterate over timelines
* Look for closest_backup, if exists, goto next timelime
* if not exists, look for oldest backup on timeline
* Look for WAL segment not reachable from existing backups
* and delete them.
*/
static void
do_retention_wal(bool dry_run)
@ -624,25 +625,32 @@ do_retention_wal(bool dry_run)
{
timelineInfo *tlinfo = (timelineInfo *) parray_get(tli_list, i);
/* Empty timeline can be safely skipped */
if (tlinfo->n_xlog_files == 0 &&
parray_num(tlinfo->xlog_filelist) == 0)
/*
* Empty timeline (only mentioned in timeline history file)
* has nothing to cleanup.
*/
if (tlinfo->n_xlog_files == 0 && parray_num(tlinfo->xlog_filelist) == 0)
continue;
/* If closest backup is exists, then timeline can be safely skipped */
/*
* If closest backup exists, then timeline is reachable from
* at least one backup and none files should not be removed.
*/
if (tlinfo->closest_backup)
continue;
/*
* Purge all WAL segments before START LSN of oldest backup.
* If there is no backups on timeline, then whole timeline
* If timeline doesn't have a backup, then whole timeline
* can be safely purged.
* Note, that oldest_backup is not necessarily valid here,
* but still we keep wal for it.
*/
if (tlinfo->oldest_backup)
delete_walfiles(tlinfo->oldest_backup->start_lsn,
delete_walfiles_in_tli(tlinfo->oldest_backup->start_lsn,
tlinfo, instance_config.xlog_seg_size, dry_run);
else
delete_walfiles(InvalidXLogRecPtr,
delete_walfiles_in_tli(InvalidXLogRecPtr,
tlinfo, instance_config.xlog_seg_size, dry_run);
}
}
@ -710,7 +718,8 @@ delete_backup_files(pgBackup *backup)
return;
}
/* Purge WAL archive.
/*
* Purge WAL archive. One timeline at a time.
* If 'keep_lsn' is InvalidXLogRecPtr, then whole timeline can be purged
* If 'keep_lsn' is valid LSN, then every lesser segment can be purged.
* If 'dry_run' is set, then don`t actually delete anything.
@ -720,7 +729,8 @@ delete_backup_files(pgBackup *backup)
* Case 2:
* archive is not empty, 'keep_lsn' is valid and prevening us from deleting anything.
* Case 3:
* archive is not empty, 'keep_lsn' is invalid, drop everyhing in archive.
* archive is not empty, 'keep_lsn' is invalid, drop all WAL files in archive,
* belonging to the timeline.
* Case 4:
* archive is empty, 'keep_lsn' is valid, assume corruption of WAL archive.
* Case 5:
@ -730,11 +740,11 @@ delete_backup_files(pgBackup *backup)
* Q: Maybe we should stop treating partial WAL segments as second-class citizens?
*/
static void
delete_walfiles(XLogRecPtr keep_lsn, timelineInfo *tlinfo,
delete_walfiles_in_tli(XLogRecPtr keep_lsn, timelineInfo *tlinfo,
uint32 xlog_seg_size, bool dry_run)
{
XLogSegNo StartSegNo; /* First segment to delete */
XLogSegNo EndSegNo = 0; /* Oldest segment to keep */
XLogSegNo FirstToDeleteSegNo;
XLogSegNo OldestToKeepSegNo = 0;
int rc;
int i;
int wal_size_logical = 0;
@ -752,32 +762,32 @@ delete_walfiles(XLogRecPtr keep_lsn, timelineInfo *tlinfo,
if (XLogRecPtrIsInvalid(keep_lsn))
{
/* Drop all files in timeline */
elog(INFO, "All files on timeline %i will be removed", tlinfo->tli);
StartSegNo = tlinfo->begin_segno;
EndSegNo = tlinfo->end_segno;
elog(INFO, "All files on timeline %i %s be removed", tlinfo->tli,
dry_run?"can":"will");
FirstToDeleteSegNo = tlinfo->begin_segno;
OldestToKeepSegNo = tlinfo->end_segno;
purge_all = true;
}
else
{
/* Drop all segments between begin_segno and segment with keep_lsn (excluding) */
StartSegNo = tlinfo->begin_segno;
GetXLogSegNo(keep_lsn, EndSegNo, xlog_seg_size);
FirstToDeleteSegNo = tlinfo->begin_segno;
GetXLogSegNo(keep_lsn, OldestToKeepSegNo, xlog_seg_size);
}
if (EndSegNo > 0 && EndSegNo > StartSegNo)
elog(INFO, "WAL segments between %08X%08X and %08X%08X on timeline %i will be removed",
(uint32) StartSegNo / xlog_seg_size, (uint32) StartSegNo % xlog_seg_size,
(uint32) (EndSegNo - 1) / xlog_seg_size,
(uint32) (EndSegNo - 1) % xlog_seg_size,
tlinfo->tli);
if (OldestToKeepSegNo > 0 && OldestToKeepSegNo > FirstToDeleteSegNo)
elog(INFO, "WAL segments between %08X%08X and %08X%08X on timeline %i %s be removed",
(uint32) FirstToDeleteSegNo / xlog_seg_size, (uint32) FirstToDeleteSegNo % xlog_seg_size,
(uint32) (OldestToKeepSegNo - 1) / xlog_seg_size,
(uint32) (OldestToKeepSegNo - 1) % xlog_seg_size,
tlinfo->tli, dry_run?"can":"will");
/* sanity */
if (EndSegNo > StartSegNo)
/* typical scenario */
wal_size_logical = (EndSegNo-StartSegNo) * xlog_seg_size;
else if (EndSegNo < StartSegNo)
if (OldestToKeepSegNo > FirstToDeleteSegNo)
wal_size_logical = (OldestToKeepSegNo - FirstToDeleteSegNo) * xlog_seg_size;
else if (OldestToKeepSegNo < FirstToDeleteSegNo)
{
/* It is actually possible for EndSegNo to be less than StartSegNo
/* It is actually possible for OldestToKeepSegNo to be less than FirstToDeleteSegNo
* in case of :
* 1. WAL archive corruption.
* 2. There is no actual WAL archive to speak of and
@ -785,14 +795,14 @@ delete_walfiles(XLogRecPtr keep_lsn, timelineInfo *tlinfo,
*
* Assume the worst.
*/
if (StartSegNo > 0 && EndSegNo > 0)
if (FirstToDeleteSegNo > 0 && OldestToKeepSegNo > 0)
elog(WARNING, "On timeline %i first segment %08X%08X is greater than "
"oldest segment to keep %08X%08X. Possible WAL archive corruption!",
tlinfo->tli,
(uint32) StartSegNo / xlog_seg_size, (uint32) StartSegNo % xlog_seg_size,
(uint32) EndSegNo / xlog_seg_size, (uint32) EndSegNo % xlog_seg_size);
(uint32) FirstToDeleteSegNo / xlog_seg_size, (uint32) FirstToDeleteSegNo % xlog_seg_size,
(uint32) OldestToKeepSegNo / xlog_seg_size, (uint32) OldestToKeepSegNo % xlog_seg_size);
}
else if (EndSegNo == StartSegNo && !purge_all)
else if (OldestToKeepSegNo == FirstToDeleteSegNo && !purge_all)
{
/* 'Nothing to delete' scenario because of 'keep_lsn'
* with possible exception of partial and backup history files.
@ -804,7 +814,7 @@ delete_walfiles(XLogRecPtr keep_lsn, timelineInfo *tlinfo,
if (wal_size_logical > 0)
{
pretty_size(wal_size_logical, wal_pretty_size, lengthof(wal_pretty_size));
elog(INFO, "WAL size to remove on timeline %i: %s",
elog(INFO, "Logical WAL size to remove on timeline %i : %s",
tlinfo->tli, wal_pretty_size);
}
@ -813,7 +823,7 @@ delete_walfiles(XLogRecPtr keep_lsn, timelineInfo *tlinfo,
{
xlogFile *wal_file = (xlogFile *) parray_get(tlinfo->xlog_filelist, i);
if (purge_all || wal_file->segno < EndSegNo)
if (purge_all || wal_file->segno < OldestToKeepSegNo)
wal_size_actual += wal_file->file.size;
}
@ -821,7 +831,7 @@ delete_walfiles(XLogRecPtr keep_lsn, timelineInfo *tlinfo,
if (wal_size_actual > 0)
{
pretty_size(wal_size_actual, wal_pretty_size, lengthof(wal_pretty_size));
elog(INFO, "Resident data size to free on timeline %i: %s",
elog(INFO, "Resident data size to free on timeline %i : %s",
tlinfo->tli, wal_pretty_size);
}
@ -838,7 +848,7 @@ delete_walfiles(XLogRecPtr keep_lsn, timelineInfo *tlinfo,
/* Any segment equal or greater than EndSegNo must be kept
* unless it`s a 'purge all' scenario.
*/
if (purge_all || wal_file->segno < EndSegNo)
if (purge_all || wal_file->segno < OldestToKeepSegNo)
{
/* unlink segment */
rc = unlink(wal_file->file.path);