diff --git a/src/catalog.c b/src/catalog.c index 86b51c87..e1aa0afa 100644 --- a/src/catalog.c +++ b/src/catalog.c @@ -393,7 +393,7 @@ catalog_get_backup_list(time_t requested_backup_id) if (curr->backup_mode == BACKUP_MODE_FULL) continue; - for (j = i+1; j < parray_num(backups); j++) + for (j = 0; j < parray_num(backups); j++) { pgBackup *ancestor = parray_get(backups, j); @@ -1034,8 +1034,12 @@ find_parent_full_backup(pgBackup *current_backup) } if (base_full_backup->backup_mode != BACKUP_MODE_FULL) - elog(ERROR, "Failed to find FULL backup parent for %s", - base36enc(current_backup->start_time)); + { + + elog(WARNING, "Backup %s is missing", + base36enc(base_full_backup->parent_backup)); + return NULL; + } return base_full_backup; } diff --git a/src/merge.c b/src/merge.c index 5726e36c..e5861b39 100644 --- a/src/merge.c +++ b/src/merge.c @@ -53,12 +53,10 @@ void do_merge(time_t backup_id) { parray *backups; + parray *merge_list = parray_new(); pgBackup *dest_backup = NULL; pgBackup *full_backup = NULL; - time_t prev_parent = INVALID_BACKUP_ID; int i; - int dest_backup_idx = 0; - int full_backup_idx = 0; if (backup_id == INVALID_BACKUP_ID) elog(ERROR, "required parameter is not specified: --backup-id"); @@ -71,73 +69,79 @@ do_merge(time_t backup_id) /* Get list of all backups sorted in order of descending start time */ backups = catalog_get_backup_list(INVALID_BACKUP_ID); - /* Find destination and parent backups */ + /* Find destination backup first */ for (i = 0; i < parray_num(backups); i++) { pgBackup *backup = (pgBackup *) parray_get(backups, i); - if (backup->start_time > backup_id) - continue; - else if (backup->start_time == backup_id && !dest_backup) + /* found target */ + if (backup->start_time == backup_id) { + /* sanity */ if (backup->status != BACKUP_STATUS_OK && /* It is possible that previous merging was interrupted */ backup->status != BACKUP_STATUS_MERGING && backup->status != BACKUP_STATUS_DELETING) - elog(ERROR, "Backup %s has status: %s", - base36enc(backup->start_time), status2str(backup->status)); + elog(ERROR, "Backup %s has status: %s", + base36enc(backup->start_time), status2str(backup->status)); if (backup->backup_mode == BACKUP_MODE_FULL) elog(ERROR, "Backup %s is full backup", base36enc(backup->start_time)); dest_backup = backup; - dest_backup_idx = i; + break; } - else - { - if (dest_backup == NULL) - elog(ERROR, "Target backup %s was not found", base36enc(backup_id)); - - if (backup->start_time != prev_parent) - continue; - - if (backup->status != BACKUP_STATUS_OK && - /* It is possible that previous merging was interrupted */ - backup->status != BACKUP_STATUS_MERGING) - elog(ERROR, "Backup %s has status: %s", - base36enc(backup->start_time), status2str(backup->status)); - - /* If we already found dest_backup, look for full backup */ - if (dest_backup && backup->backup_mode == BACKUP_MODE_FULL) - { - full_backup = backup; - full_backup_idx = i; - - /* Found target and full backups, so break the loop */ - break; - } - } - - prev_parent = backup->parent_backup; } + /* sanity */ if (dest_backup == NULL) elog(ERROR, "Target backup %s was not found", base36enc(backup_id)); + + /* get full backup */ + full_backup = find_parent_full_backup(dest_backup); + + /* sanity */ if (full_backup == NULL) elog(ERROR, "Parent full backup for the given backup %s was not found", base36enc(backup_id)); - Assert(full_backup_idx != dest_backup_idx); + /* sanity */ + if (full_backup->status != BACKUP_STATUS_OK && + /* It is possible that previous merging was interrupted */ + full_backup->status != BACKUP_STATUS_MERGING) + elog(ERROR, "Backup %s has status: %s", + base36enc(full_backup->start_time), status2str(full_backup->status)); - catalog_lock_backup_list(backups, full_backup_idx, dest_backup_idx); + //Assert(full_backup_idx != dest_backup_idx); + + /* form merge list */ + while(dest_backup->parent_backup_link) + { + /* sanity */ + if (dest_backup->status != BACKUP_STATUS_OK && + /* It is possible that previous merging was interrupted */ + dest_backup->status != BACKUP_STATUS_MERGING && + dest_backup->status != BACKUP_STATUS_DELETING) + elog(ERROR, "Backup %s has status: %s", + base36enc(dest_backup->start_time), status2str(dest_backup->status)); + + parray_append(merge_list, dest_backup); + dest_backup = dest_backup->parent_backup_link; + } + + /* Add FULL backup for easy locking */ + parray_append(merge_list, full_backup); + + /* Lock merge chain */ + catalog_lock_backup_list(merge_list, parray_num(merge_list) - 1, 0); /* * Found target and full backups, merge them and intermediate backups */ - for (i = full_backup_idx; i > dest_backup_idx; i--) + for (i = parray_num(merge_list) - 2; i >= 0; i--) { - pgBackup *from_backup = (pgBackup *) parray_get(backups, i - 1); + pgBackup *from_backup = (pgBackup *) parray_get(merge_list, i); merge_backups(full_backup, from_backup); } @@ -149,6 +153,7 @@ do_merge(time_t backup_id) /* cleanup */ parray_walk(backups, pgBackupFree); parray_free(backups); + parray_free(merge_list); elog(INFO, "Merge of backup %s completed", base36enc(backup_id)); } diff --git a/src/restore.c b/src/restore.c index c8477774..38fa11ed 100644 --- a/src/restore.c +++ b/src/restore.c @@ -55,9 +55,6 @@ do_restore_or_validate(time_t target_backup_id, pgRecoveryTarget *rt, pgBackup *dest_backup = NULL; pgBackup *base_full_backup = NULL; pgBackup *corrupted_backup = NULL; - int dest_backup_index = 0; - int base_full_backup_index = 0; - int corrupted_backup_index = 0; char *action = is_restore ? "Restore":"Validate"; parray *parent_chain = NULL; @@ -179,8 +176,6 @@ do_restore_or_validate(time_t target_backup_id, pgRecoveryTarget *rt, if (dest_backup == NULL) elog(ERROR, "Backup satisfying target options is not found."); - dest_backup_index = get_backup_index_number(backups, dest_backup); - /* If we already found dest_backup, look for full backup. */ if (dest_backup->backup_mode == BACKUP_MODE_FULL) base_full_backup = dest_backup; @@ -201,7 +196,7 @@ do_restore_or_validate(time_t target_backup_id, pgRecoveryTarget *rt, missing_backup_start_time = tmp_backup->parent_backup; missing_backup_id = base36enc_dup(tmp_backup->parent_backup); - for (j = get_backup_index_number(backups, tmp_backup); j >= 0; j--) + for (j = 0; j < parray_num(backups); j++) { pgBackup *backup = (pgBackup *) parray_get(backups, j); @@ -235,7 +230,7 @@ do_restore_or_validate(time_t target_backup_id, pgRecoveryTarget *rt, /* parent_backup_id contain human-readable backup ID of oldest invalid backup */ parent_backup_id = base36enc_dup(tmp_backup->start_time); - for (j = get_backup_index_number(backups, tmp_backup) - 1; j >= 0; j--) + for (j = 0; j < parray_num(backups); j++) { pgBackup *backup = (pgBackup *) parray_get(backups, j); @@ -261,6 +256,11 @@ do_restore_or_validate(time_t target_backup_id, pgRecoveryTarget *rt, } } tmp_backup = find_parent_full_backup(dest_backup); + + /* sanity */ + if (!tmp_backup) + elog(ERROR, "Parent full backup for the given backup %s was not found", + base36enc(dest_backup->start_time)); } /* @@ -276,8 +276,6 @@ do_restore_or_validate(time_t target_backup_id, pgRecoveryTarget *rt, if (base_full_backup == NULL) elog(ERROR, "Full backup satisfying target options is not found."); - base_full_backup_index = get_backup_index_number(backups, base_full_backup); - /* * Ensure that directories provided in tablespace mapping are valid * i.e. empty or not exist. @@ -297,17 +295,16 @@ do_restore_or_validate(time_t target_backup_id, pgRecoveryTarget *rt, /* Take every backup that is a child of base_backup AND parent of dest_backup * including base_backup and dest_backup */ - for (i = base_full_backup_index; i >= dest_backup_index; i--) - { - tmp_backup = (pgBackup *) parray_get(backups, i); - if (is_parent(base_full_backup->start_time, tmp_backup, true) && - is_parent(tmp_backup->start_time, dest_backup, true)) - { - parray_append(parent_chain, tmp_backup); - } + tmp_backup = dest_backup; + while(tmp_backup->parent_backup_link) + { + parray_append(parent_chain, tmp_backup); + tmp_backup = tmp_backup->parent_backup_link; } + parray_append(parent_chain, base_full_backup); + /* for validation or restore with enabled validation */ if (!is_restore || !rt->restore_no_validate) { @@ -317,7 +314,7 @@ do_restore_or_validate(time_t target_backup_id, pgRecoveryTarget *rt, /* * Validate backups from base_full_backup to dest_backup. */ - for (i = 0; i < parray_num(parent_chain); i++) + for (i = parray_num(parent_chain) - 1; i >= 0; i--) { tmp_backup = (pgBackup *) parray_get(parent_chain, i); @@ -344,10 +341,6 @@ do_restore_or_validate(time_t target_backup_id, pgRecoveryTarget *rt, if (tmp_backup->status != BACKUP_STATUS_OK) { corrupted_backup = tmp_backup; - /* we need corrupted backup index from 'backups' not parent_chain - * so we can properly orphanize all its descendants - */ - corrupted_backup_index = get_backup_index_number(backups, corrupted_backup); break; } /* We do not validate WAL files of intermediate backups @@ -373,7 +366,7 @@ do_restore_or_validate(time_t target_backup_id, pgRecoveryTarget *rt, char *corrupted_backup_id; corrupted_backup_id = base36enc_dup(corrupted_backup->start_time); - for (j = corrupted_backup_index - 1; j >= 0; j--) + for (j = 0; j < parray_num(backups); j++) { pgBackup *backup = (pgBackup *) parray_get(backups, j); @@ -418,7 +411,7 @@ do_restore_or_validate(time_t target_backup_id, pgRecoveryTarget *rt, */ if (is_restore) { - for (i = 0; i < parray_num(parent_chain); i++) + for (i = parray_num(parent_chain) - 1; i >= 0; i--) { pgBackup *backup = (pgBackup *) parray_get(parent_chain, i); diff --git a/src/validate.c b/src/validate.c index 7d5e94f4..040ea793 100644 --- a/src/validate.c +++ b/src/validate.c @@ -452,6 +452,11 @@ do_validate_instance(void) continue; } base_full_backup = find_parent_full_backup(current_backup); + + /* sanity */ + if (!base_full_backup) + elog(ERROR, "Parent full backup for the given backup %s was not found", + base36enc(current_backup->start_time)); } /* chain is whole, all parents are valid at first glance, * current backup validation can proceed @@ -568,7 +573,7 @@ do_validate_instance(void) if (backup->status == BACKUP_STATUS_OK) { - //tmp_backup = find_parent_full_backup(dest_backup); + /* Revalidation successful, validate corresponding WAL files */ validate_wal(backup, arclog_path, 0, 0, 0, current_backup->tli,