Skip to content

Commit 5b38c73

Browse files
committed
Minor refactoring of WAL timelines constructor
1 parent a363405 commit 5b38c73

File tree

5 files changed

+301
-250
lines changed

5 files changed

+301
-250
lines changed

src/catalog.c

+288
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
*/
1010

1111
#include "pg_probackup.h"
12+
#include "access/timeline.h"
1213

1314
#include <dirent.h>
1415
#include <signal.h>
@@ -18,12 +19,25 @@
1819
#include "utils/file.h"
1920
#include "utils/configuration.h"
2021

22+
static pgBackup* get_closest_backup(timelineInfo *tlinfo, parray *backup_list);
23+
static pgBackup* get_oldest_backup(timelineInfo *tlinfo, parray *backup_list);
2124
static const char *backupModes[] = {"", "PAGE", "PTRACK", "DELTA", "FULL"};
2225
static pgBackup *readBackupControlFile(const char *path);
2326

2427
static bool exit_hook_registered = false;
2528
static parray *lock_files = NULL;
2629

30+
static timelineInfo *
31+
timelineInfoNew(TimeLineID tli)
32+
{
33+
timelineInfo *tlinfo = (timelineInfo *) pgut_malloc(sizeof(timelineInfo));
34+
MemSet(tlinfo, 0, sizeof(timelineInfo));
35+
tlinfo->tli = tli;
36+
tlinfo->switchpoint = InvalidXLogRecPtr;
37+
tlinfo->parent_link = NULL;
38+
return tlinfo;
39+
}
40+
2741
/* Iterate over locked backups and delete locks files */
2842
static void
2943
unlink_lock_atexit(void)
@@ -665,6 +679,280 @@ pgBackupCreateDir(pgBackup *backup)
665679
return 0;
666680
}
667681

682+
/*
683+
* Create list of timelines
684+
*/
685+
parray *
686+
catalog_get_timelines(InstanceConfig *instance)
687+
{
688+
parray *xlog_files_list = parray_new();
689+
parray *timelineinfos;
690+
parray *backups;
691+
timelineInfo *tlinfo;
692+
char arclog_path[MAXPGPATH];
693+
694+
/* read all xlog files that belong to this archive */
695+
sprintf(arclog_path, "%s/%s/%s", backup_path, "wal", instance->name);
696+
dir_list_file(xlog_files_list, arclog_path, false, false, false, 0, FIO_BACKUP_HOST);
697+
parray_qsort(xlog_files_list, pgFileComparePath);
698+
699+
timelineinfos = parray_new();
700+
tlinfo = NULL;
701+
702+
/* walk through files and collect info about timelines */
703+
for (int i = 0; i < parray_num(xlog_files_list); i++)
704+
{
705+
pgFile *file = (pgFile *) parray_get(xlog_files_list, i);
706+
TimeLineID tli;
707+
parray *timelines;
708+
709+
/* regular WAL file */
710+
if (strspn(file->name, "0123456789ABCDEF") == XLOG_FNAME_LEN)
711+
{
712+
int result = 0;
713+
uint32 log, seg;
714+
XLogSegNo segno;
715+
char suffix[MAXPGPATH];
716+
717+
result = sscanf(file->name, "%08X%08X%08X.%s",
718+
&tli, &log, &seg, (char *) &suffix);
719+
720+
if (result < 3)
721+
{
722+
elog(WARNING, "unexpected WAL file name \"%s\"", file->name);
723+
continue;
724+
}
725+
726+
segno = log * instance->xlog_seg_size + seg;
727+
728+
/* regular WAL file with suffix */
729+
if (result == 4)
730+
{
731+
/* backup history file. Currently we don't use them */
732+
if (IsBackupHistoryFileName(file->name))
733+
{
734+
elog(VERBOSE, "backup history file \"%s\". do nothing", file->name);
735+
continue;
736+
}
737+
/* we only expect compressed wal files with .gz suffix */
738+
else if (strcmp(suffix, "gz") != 0)
739+
{
740+
elog(WARNING, "unexpected WAL file name \"%s\"", file->name);
741+
continue;
742+
}
743+
}
744+
745+
/* new file belongs to new timeline */
746+
if (!tlinfo || tlinfo->tli != tli)
747+
{
748+
tlinfo = timelineInfoNew(tli);
749+
parray_append(timelineinfos, tlinfo);
750+
}
751+
/*
752+
* As it is impossible to detect if segments before segno are lost,
753+
* or just do not exist, do not report them as lost.
754+
*/
755+
else if (tlinfo->n_xlog_files != 0)
756+
{
757+
/* check, if segments are consequent */
758+
XLogSegNo expected_segno = tlinfo->end_segno + 1;
759+
760+
/* some segments are missing. remember them in lost_segments to report */
761+
if (segno != expected_segno)
762+
{
763+
xlogInterval *interval = palloc(sizeof(xlogInterval));;
764+
interval->begin_segno = expected_segno;
765+
interval->end_segno = segno - 1;
766+
767+
if (tlinfo->lost_segments == NULL)
768+
tlinfo->lost_segments = parray_new();
769+
770+
parray_append(tlinfo->lost_segments, interval);
771+
}
772+
}
773+
774+
if (tlinfo->begin_segno == 0)
775+
tlinfo->begin_segno = segno;
776+
777+
/* this file is the last for this timeline so far */
778+
tlinfo->end_segno = segno;
779+
/* update counters */
780+
tlinfo->n_xlog_files++;
781+
tlinfo->size += file->size;
782+
}
783+
/* timeline history file */
784+
else if (IsTLHistoryFileName(file->name))
785+
{
786+
TimeLineHistoryEntry *tln;
787+
788+
sscanf(file->name, "%08X.history", &tli);
789+
timelines = read_timeline_history(arclog_path, tli);
790+
791+
if (!tlinfo || tlinfo->tli != tli)
792+
{
793+
tlinfo = timelineInfoNew(tli);
794+
parray_append(timelineinfos, tlinfo);
795+
/*
796+
* 1 is the latest timeline in the timelines list.
797+
* 0 - is our timeline, which is of no interest here
798+
*/
799+
tln = (TimeLineHistoryEntry *) parray_get(timelines, 1);
800+
tlinfo->switchpoint = tln->end;
801+
tlinfo->parent_tli = tln->tli;
802+
803+
/* find parent timeline to link it with this one */
804+
for (int i = 0; i < parray_num(timelineinfos); i++)
805+
{
806+
timelineInfo *cur = (timelineInfo *) parray_get(timelineinfos, i);
807+
if (cur->tli == tlinfo->parent_tli)
808+
{
809+
tlinfo->parent_link = cur;
810+
break;
811+
}
812+
}
813+
}
814+
815+
parray_walk(timelines, pfree);
816+
parray_free(timelines);
817+
}
818+
else
819+
elog(WARNING, "unexpected WAL file name \"%s\"", file->name);
820+
}
821+
822+
/* save information about backups belonging to each timeline */
823+
backups = catalog_get_backup_list(instance->name, INVALID_BACKUP_ID);
824+
825+
for (int i = 0; i < parray_num(timelineinfos); i++)
826+
{
827+
timelineInfo *tlinfo = parray_get(timelineinfos, i);
828+
for (int j = 0; j < parray_num(backups); j++)
829+
{
830+
pgBackup *backup = parray_get(backups, j);
831+
if (tlinfo->tli == backup->tli)
832+
{
833+
if (tlinfo->backups == NULL)
834+
tlinfo->backups = parray_new();
835+
836+
parray_append(tlinfo->backups, backup);
837+
}
838+
}
839+
}
840+
841+
/* determine oldest backup and closest backup for every timeline */
842+
for (int i = 0; i < parray_num(timelineinfos); i++)
843+
{
844+
timelineInfo *tlinfo = parray_get(timelineinfos, i);
845+
846+
tlinfo->oldest_backup = get_oldest_backup(tlinfo, backups);
847+
tlinfo->closest_backup = get_closest_backup(tlinfo, backups);
848+
}
849+
850+
parray_walk(xlog_files_list, pfree);
851+
parray_free(xlog_files_list);
852+
853+
return timelineinfos;
854+
}
855+
856+
/*
857+
* Iterate over parent timelines of a given timeline and look
858+
* for valid backup closest to given timeline switchpoint.
859+
*
860+
* Returns NULL if such backup is not found.
861+
*/
862+
pgBackup*
863+
get_closest_backup(timelineInfo *tlinfo, parray *backup_list)
864+
{
865+
pgBackup *closest_backup = NULL;
866+
int i;
867+
868+
/* Only timeline with switchpoint can possibly have closest backup */
869+
if (XLogRecPtrIsInvalid(tlinfo->switchpoint))
870+
return NULL;
871+
872+
/* Only timeline with parent timeline can possibly have closest backup */
873+
if (!tlinfo->parent_link)
874+
return NULL;
875+
876+
while (tlinfo->parent_link)
877+
{
878+
/*
879+
* Iterate over backups belonging to parent timeline and look
880+
* for candidates.
881+
*/
882+
for (i = 0; i < parray_num(backup_list); i++)
883+
{
884+
pgBackup *backup = parray_get(backup_list, i);
885+
886+
/* Backups belonging to timelines other than parent timeline can be safely skipped */
887+
if (backup->tli != tlinfo->parent_tli)
888+
continue;
889+
890+
/* Backups in future can be safely skipped */
891+
if (backup->stop_lsn > tlinfo->switchpoint)
892+
continue;
893+
894+
/* Backups with invalid STOP LSN can be safely skipped */
895+
if (XLogRecPtrIsInvalid(backup->stop_lsn) ||
896+
!XRecOffIsValid(backup->stop_lsn))
897+
continue;
898+
899+
/* Only valid backups closest to switchpoint should be considered */
900+
if (backup->stop_lsn <= tlinfo->switchpoint &&
901+
(backup->status == BACKUP_STATUS_OK ||
902+
backup->status == BACKUP_STATUS_DONE))
903+
{
904+
/* Check if backup is closer to switchpoint than current candidate */
905+
if (!closest_backup || backup->stop_lsn > closest_backup->stop_lsn)
906+
closest_backup = backup;
907+
}
908+
}
909+
910+
/* Closest backup is found */
911+
if (closest_backup)
912+
break;
913+
914+
/* Switch to parent */
915+
tlinfo = tlinfo->parent_link;
916+
}
917+
918+
return closest_backup;
919+
}
920+
921+
/*
922+
* Iterate over timelines and look for oldest backup on each timeline
923+
* Returns NULL if such backup is not found.
924+
*/
925+
pgBackup*
926+
get_oldest_backup(timelineInfo *tlinfo, parray *backup_list)
927+
{
928+
pgBackup *oldest_backup = NULL;
929+
int i;
930+
931+
/*
932+
* Iterate over backups belonging to timeline and look
933+
* for candidates.
934+
*/
935+
for (i = 0; i < parray_num(backup_list); i++)
936+
{
937+
pgBackup *backup = parray_get(backup_list, i);
938+
939+
/* Backups belonging to other timelines can be safely skipped */
940+
if (backup->tli != tlinfo->tli)
941+
continue;
942+
943+
/* Backups with invalid START LSN can be safely skipped */
944+
if (XLogRecPtrIsInvalid(backup->start_lsn) ||
945+
!XRecOffIsValid(backup->start_lsn))
946+
continue;
947+
948+
/* Check if backup is older than current candidate */
949+
if (!oldest_backup || backup->start_lsn < oldest_backup->start_lsn)
950+
oldest_backup = backup;
951+
}
952+
953+
return oldest_backup;
954+
}
955+
668956
/*
669957
* Write information about backup.in to stream "out".
670958
*/

src/help.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -548,7 +548,7 @@ help_show(void)
548548
printf(_(" -B, --backup-path=backup-path location of the backup storage area\n"));
549549
printf(_(" --instance=instance_name show info about specific instance\n"));
550550
printf(_(" -i, --backup-id=backup-id show info about specific backups\n"));
551-
printf(_(" --archive show WAL archive\n"));
551+
printf(_(" --archive show WAL archive information\n"));
552552
printf(_(" --format=format show format=PLAIN|JSON\n\n"));
553553
}
554554

src/pg_probackup.c

+3
Original file line numberDiff line numberDiff line change
@@ -440,6 +440,9 @@ main(int argc, char *argv[])
440440
backup_subcmd != VALIDATE_CMD && backup_subcmd != CHECKDB_CMD)
441441
elog(ERROR, "required parameter not specified: --instance");
442442
}
443+
else
444+
/* Set instance name */
445+
instance_config.name = pgut_strdup(instance_name);
443446

444447
/*
445448
* If --instance option was passed, construct paths for backup data and

src/pg_probackup.h

+8
Original file line numberDiff line numberDiff line change
@@ -405,8 +405,15 @@ struct timelineInfo {
405405
* about backups belonging to this timeline */
406406
parray *lost_segments; /* array of intervals of lost segments */
407407
pgBackup *closest_backup; /* link to backup, closest to timeline */
408+
pgBackup *oldest_backup; /* link to oldest backup on timeline */
408409
};
409410

411+
typedef struct xlogInterval
412+
{
413+
XLogSegNo begin_segno;
414+
XLogSegNo end_segno;
415+
} xlogInterval;
416+
410417

411418
/*
412419
* When copying datafiles to backup we validate and compress them block
@@ -617,6 +624,7 @@ extern void catalog_lock_backup_list(parray *backup_list, int from_idx,
617624
extern pgBackup *catalog_get_last_data_backup(parray *backup_list,
618625
TimeLineID tli,
619626
time_t current_start_time);
627+
extern parray *catalog_get_timelines(InstanceConfig *instance);
620628
extern void pgBackupWriteControl(FILE *out, pgBackup *backup);
621629
extern void write_backup_filelist(pgBackup *backup, parray *files,
622630
const char *root, parray *external_list);

0 commit comments

Comments
 (0)