Skip to content

Commit 7f573d7

Browse files
committed
Merge branch 'pgpro_428_v1'
2 parents f508308 + 2fac44e commit 7f573d7

File tree

4 files changed

+126
-55
lines changed

4 files changed

+126
-55
lines changed

src/catalog.c

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,7 @@ catalog_get_backup_list(time_t requested_backup_id)
254254
struct dirent *data_ent = NULL;
255255
parray *backups = NULL;
256256
pgBackup *backup = NULL;
257+
int i;
257258

258259
/* open backup instance backups directory */
259260
data_dir = opendir(backup_instance_path);
@@ -282,6 +283,7 @@ catalog_get_backup_list(time_t requested_backup_id)
282283
/* read backup information from BACKUP_CONTROL_FILE */
283284
snprintf(backup_conf_path, MAXPGPATH, "%s/%s", data_path, BACKUP_CONTROL_FILE);
284285
backup = readBackupControlFile(backup_conf_path);
286+
backup->backup_id = backup->start_time;
285287

286288
/* ignore corrupted backups */
287289
if (backup)
@@ -315,6 +317,30 @@ catalog_get_backup_list(time_t requested_backup_id)
315317

316318
parray_qsort(backups, pgBackupCompareIdDesc);
317319

320+
/* Link incremental backups with their ancestors.*/
321+
for (i = 0; i < parray_num(backups); i++)
322+
{
323+
pgBackup *curr = parray_get(backups, i);
324+
325+
int j;
326+
327+
if (curr->backup_mode == BACKUP_MODE_FULL)
328+
continue;
329+
330+
for (j = i+1; j < parray_num(backups); j++)
331+
{
332+
pgBackup *ancestor = parray_get(backups, j);
333+
334+
if (ancestor->start_time == curr->parent_backup)
335+
{
336+
curr->parent_backup_link = ancestor;
337+
/* elog(INFO, "curr %s, ancestor %s j=%d", base36enc_dup(curr->start_time),
338+
base36enc_dup(ancestor->start_time), j); */
339+
break;
340+
}
341+
}
342+
}
343+
318344
return backups;
319345

320346
err_proc:
@@ -757,6 +783,7 @@ pgBackupInit(pgBackup *backup)
757783
backup->stream = false;
758784
backup->from_replica = false;
759785
backup->parent_backup = INVALID_BACKUP_ID;
786+
backup->parent_backup_link = NULL;
760787
backup->primary_conninfo = NULL;
761788
backup->program_version[0] = '\0';
762789
backup->server_version[0] = '\0';
@@ -840,3 +867,48 @@ pgBackupGetPath2(const pgBackup *backup, char *path, size_t len,
840867

841868
make_native_path(path);
842869
}
870+
871+
/* Find parent base FULL backup for current backup using parent_backup_link,
872+
* return NULL if not found
873+
*/
874+
pgBackup*
875+
find_parent_backup(pgBackup *current_backup)
876+
{
877+
pgBackup *base_full_backup = NULL;
878+
base_full_backup = current_backup;
879+
880+
while (base_full_backup->backup_mode != BACKUP_MODE_FULL)
881+
{
882+
/*
883+
* If we haven't found parent for incremental backup,
884+
* mark it and all depending backups as orphaned
885+
*/
886+
if (base_full_backup->parent_backup_link == NULL
887+
|| (base_full_backup->status != BACKUP_STATUS_OK
888+
&& base_full_backup->status != BACKUP_STATUS_DONE))
889+
{
890+
pgBackup *orphaned_backup = current_backup;
891+
892+
while (orphaned_backup != NULL)
893+
{
894+
orphaned_backup->status = BACKUP_STATUS_ORPHAN;
895+
pgBackupWriteBackupControlFile(orphaned_backup);
896+
if (base_full_backup->parent_backup_link == NULL)
897+
elog(WARNING, "Backup %s is orphaned because its parent backup is not found",
898+
base36enc(orphaned_backup->start_time));
899+
else
900+
elog(WARNING, "Backup %s is orphaned because its parent backup is corrupted",
901+
base36enc(orphaned_backup->start_time));
902+
903+
orphaned_backup = orphaned_backup->parent_backup_link;
904+
}
905+
906+
base_full_backup = NULL;
907+
break;
908+
}
909+
910+
base_full_backup = base_full_backup->parent_backup_link;
911+
}
912+
913+
return base_full_backup;
914+
}

src/pg_probackup.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,8 @@ typedef struct pgBackupConfig
203203
int compress_level;
204204
} pgBackupConfig;
205205

206+
typedef struct pgBackup pgBackup;
207+
206208
/* Information about single backup stored in backup.conf */
207209
typedef struct pgBackup
208210
{
@@ -250,8 +252,9 @@ typedef struct pgBackup
250252
time_t parent_backup; /* Identifier of the previous backup.
251253
* Which is basic backup for this
252254
* incremental backup. */
253-
char *primary_conninfo; /* Connection parameters of the backup
254-
* in the format suitable for recovery.conf */
255+
pgBackup *parent_backup_link;
256+
char *primary_conninfo; /* Connection parameters of the backup
257+
* in the format suitable for recovery.conf */
255258
} pgBackup;
256259

257260
/* Recovery target for restore and validate subcommands */
@@ -486,6 +489,8 @@ extern void pgBackupFree(void *backup);
486489
extern int pgBackupCompareId(const void *f1, const void *f2);
487490
extern int pgBackupCompareIdDesc(const void *f1, const void *f2);
488491

492+
extern pgBackup* find_parent_backup(pgBackup *current_backup);
493+
489494
/* in dir.c */
490495
extern void dir_list_file(parray *files, const char *root, bool exclude,
491496
bool omit_symlink, bool add_root);

src/restore.c

Lines changed: 33 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ int
4747
do_restore_or_validate(time_t target_backup_id, pgRecoveryTarget *rt,
4848
bool is_restore)
4949
{
50-
int i;
50+
int i = 0;
5151
parray *backups;
5252
pgBackup *current_backup = NULL;
5353
pgBackup *dest_backup = NULL;
@@ -79,9 +79,10 @@ do_restore_or_validate(time_t target_backup_id, pgRecoveryTarget *rt,
7979
backups = catalog_get_backup_list(INVALID_BACKUP_ID);
8080

8181
/* Find backup range we should restore or validate. */
82-
for (i = 0; i < parray_num(backups); i++)
82+
while ((i < parray_num(backups)) && !dest_backup)
8383
{
8484
current_backup = (pgBackup *) parray_get(backups, i);
85+
i++;
8586

8687
/* Skip all backups which started after target backup */
8788
if (target_backup_id && current_backup->start_time > target_backup_id)
@@ -93,7 +94,6 @@ do_restore_or_validate(time_t target_backup_id, pgRecoveryTarget *rt,
9394
*/
9495

9596
if (is_restore &&
96-
!dest_backup &&
9797
target_backup_id == INVALID_BACKUP_ID &&
9898
current_backup->status != BACKUP_STATUS_OK)
9999
{
@@ -107,8 +107,7 @@ do_restore_or_validate(time_t target_backup_id, pgRecoveryTarget *rt,
107107
* ensure that it satisfies recovery target.
108108
*/
109109
if ((target_backup_id == current_backup->start_time
110-
|| target_backup_id == INVALID_BACKUP_ID)
111-
&& !dest_backup)
110+
|| target_backup_id == INVALID_BACKUP_ID))
112111
{
113112

114113
/* backup is not ok,
@@ -161,37 +160,42 @@ do_restore_or_validate(time_t target_backup_id, pgRecoveryTarget *rt,
161160
* Save it as dest_backup
162161
*/
163162
dest_backup = current_backup;
164-
dest_backup_index = i;
163+
dest_backup_index = i-1;
164+
}
165+
}
166+
167+
if (dest_backup == NULL)
168+
elog(ERROR, "Backup satisfying target options is not found.");
169+
170+
/* If we already found dest_backup, look for full backup. */
171+
if (dest_backup)
172+
{
173+
base_full_backup = current_backup;
174+
175+
if (current_backup->backup_mode != BACKUP_MODE_FULL)
176+
{
177+
base_full_backup = find_parent_backup(current_backup);
178+
179+
if (base_full_backup == NULL)
180+
elog(ERROR, "Valid full backup for backup %s is not found.",
181+
base36enc(current_backup->start_time));
165182
}
166183

167-
/* If we already found dest_backup, look for full backup. */
168-
if (dest_backup)
184+
/*
185+
* We have found full backup by link,
186+
* now we need to walk the list to find its index.
187+
*
188+
* TODO I think we should rewrite it someday to use double linked list
189+
* and avoid relying on sort order anymore.
190+
*/
191+
for (i = dest_backup_index; i < parray_num(backups); i++)
169192
{
170-
if (current_backup->backup_mode == BACKUP_MODE_FULL)
193+
pgBackup * temp_backup = (pgBackup *) parray_get(backups, i);
194+
if (temp_backup->start_time == base_full_backup->start_time)
171195
{
172-
if (current_backup->status != BACKUP_STATUS_OK)
173-
{
174-
/* Full backup revalidation can be done only for DONE and CORRUPT */
175-
if (current_backup->status == BACKUP_STATUS_DONE ||
176-
current_backup->status == BACKUP_STATUS_CORRUPT)
177-
elog(WARNING, "base backup %s for given backup %s is in %s status, trying to revalidate",
178-
base36enc_dup(current_backup->start_time),
179-
base36enc_dup(dest_backup->start_time),
180-
status2str(current_backup->status));
181-
else
182-
elog(ERROR, "base backup %s for given backup %s is in %s status",
183-
base36enc_dup(current_backup->start_time),
184-
base36enc_dup(dest_backup->start_time),
185-
status2str(current_backup->status));
186-
}
187-
/* We found both dest and base backups. */
188-
base_full_backup = current_backup;
189196
base_full_backup_index = i;
190197
break;
191198
}
192-
else
193-
/* It`s ok to skip incremental backup */
194-
continue;
195199
}
196200
}
197201

src/validate.c

Lines changed: 14 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -291,43 +291,33 @@ do_validate_instance(void)
291291
/* Get list of all backups sorted in order of descending start time */
292292
backups = catalog_get_backup_list(INVALID_BACKUP_ID);
293293

294-
/* Valiate each backup along with its xlog files. */
294+
/* Examine backups one by one and validate them */
295295
for (i = 0; i < parray_num(backups); i++)
296296
{
297-
pgBackup *base_full_backup = NULL;
298-
299297
current_backup = (pgBackup *) parray_get(backups, i);
300298

301-
if (current_backup->backup_mode != BACKUP_MODE_FULL)
299+
/* Valiate each backup along with its xlog files. */
300+
pgBackupValidate(current_backup);
301+
302+
/* Ensure that the backup has valid list of parent backups */
303+
if (current_backup->status == BACKUP_STATUS_OK)
302304
{
303-
int j;
305+
pgBackup *base_full_backup = current_backup;
304306

305-
for (j = i + 1; j < parray_num(backups); j++)
307+
if (current_backup->backup_mode != BACKUP_MODE_FULL)
306308
{
307-
pgBackup *backup = (pgBackup *) parray_get(backups, j);
309+
base_full_backup = find_parent_backup(current_backup);
308310

309-
if (backup->backup_mode == BACKUP_MODE_FULL)
310-
{
311-
base_full_backup = backup;
312-
break;
313-
}
311+
if (base_full_backup == NULL)
312+
elog(ERROR, "Valid full backup for backup %s is not found.",
313+
base36enc(current_backup->start_time));
314314
}
315-
}
316-
else
317-
base_full_backup = current_backup;
318-
319-
pgBackupValidate(current_backup);
320315

321-
/* There is no point in wal validation for corrupted backup */
322-
if (current_backup->status == BACKUP_STATUS_OK)
323-
{
324-
if (base_full_backup == NULL)
325-
elog(ERROR, "Valid full backup for backup %s is not found.",
326-
base36enc(current_backup->start_time));
327316
/* Validate corresponding WAL files */
328317
validate_wal(current_backup, arclog_path, 0,
329-
0, 0, base_full_backup->tli);
318+
0, 0, base_full_backup->tli);
330319
}
320+
331321
/* Mark every incremental backup between corrupted backup and nearest FULL backup as orphans */
332322
if (current_backup->status == BACKUP_STATUS_CORRUPT)
333323
{

0 commit comments

Comments
 (0)