@@ -868,47 +868,132 @@ pgBackupGetPath2(const pgBackup *backup, char *path, size_t len,
868868 make_native_path (path );
869869}
870870
871- /* Find parent base FULL backup for current backup using parent_backup_link,
872- * return NULL if not found
871+ /*
872+ * Find parent base FULL backup for current backup using parent_backup_link
873873 */
874874pgBackup *
875- find_parent_backup (pgBackup * current_backup )
875+ find_parent_full_backup (pgBackup * current_backup )
876876{
877877 pgBackup * base_full_backup = NULL ;
878878 base_full_backup = current_backup ;
879879
880- while (base_full_backup -> backup_mode != BACKUP_MODE_FULL )
880+ if (!current_backup )
881+ elog (ERROR , "Target backup cannot be NULL" );
882+
883+ while (base_full_backup -> parent_backup_link != NULL )
881884 {
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 ;
885+ base_full_backup = base_full_backup -> parent_backup_link ;
886+ }
891887
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- }
888+ if (base_full_backup -> backup_mode != BACKUP_MODE_FULL )
889+ elog (ERROR , "Failed to find FULL backup parent for %s" ,
890+ base36enc (current_backup -> start_time ));
905891
906- base_full_backup = NULL ;
907- break ;
908- }
892+ return base_full_backup ;
893+ }
909894
910- base_full_backup = base_full_backup -> parent_backup_link ;
895+ /*
896+ * Interate over parent chain and look for any problems.
897+ * Return 0 if chain is broken.
898+ * result_backup must contain oldest existing backup after missing backup.
899+ * we have no way to know if there is multiple missing backups.
900+ * Return 1 if chain is intact, but some backup is !OK.
901+ * result_backup must contain oldest !OK backup.
902+ * Return 2 if chain is intact and all backup are OK.
903+ * result_backup must contain FULL backup on which chain is based.
904+ */
905+ int
906+ scan_parent_chain (pgBackup * current_backup , pgBackup * * result_backup )
907+ {
908+ pgBackup * target_backup = NULL ;
909+ pgBackup * invalid_backup = NULL ;
910+
911+ if (!current_backup )
912+ elog (ERROR , "Target backup cannot be NULL" );
913+
914+ target_backup = current_backup ;
915+
916+ while (target_backup -> parent_backup_link )
917+ {
918+ if (target_backup -> status != BACKUP_STATUS_OK &&
919+ target_backup -> status != BACKUP_STATUS_DONE )
920+ /* oldest invalid backup in parent chain */
921+ invalid_backup = target_backup ;
922+
923+
924+ target_backup = target_backup -> parent_backup_link ;
911925 }
912926
913- return base_full_backup ;
927+ /* Prevous loop will skip FULL backup because his parent_backup_link is NULL */
928+ if (target_backup -> backup_mode == BACKUP_MODE_FULL &&
929+ (target_backup -> status != BACKUP_STATUS_OK &&
930+ target_backup -> status != BACKUP_STATUS_DONE ))
931+ {
932+ invalid_backup = target_backup ;
933+ }
934+
935+ /* found chain end and oldest backup is not FULL */
936+ if (target_backup -> backup_mode != BACKUP_MODE_FULL )
937+ {
938+ /* Set oldest child backup in chain */
939+ * result_backup = target_backup ;
940+ return 0 ;
941+ }
942+
943+ /* chain is ok, but some backups are invalid */
944+ if (invalid_backup )
945+ {
946+ * result_backup = invalid_backup ;
947+ return 1 ;
948+ }
949+
950+ * result_backup = target_backup ;
951+ return 2 ;
952+ }
953+
954+ /*
955+ * Determine if child_backup descend from parent_backup
956+ * This check DO NOT(!!!) guarantee that parent chain is intact, because parent_backup
957+ * can be missing.
958+ * If inclusive is true, then full backup counts as a child of himself.
959+ */
960+ bool
961+ is_parent (time_t parent_backup_time , pgBackup * child_backup , bool inclusive )
962+ {
963+ if (!child_backup )
964+ elog (ERROR , "Target backup cannot be NULL" );
965+
966+ while (child_backup -> parent_backup_link &&
967+ child_backup -> parent_backup != parent_backup_time )
968+ {
969+ child_backup = child_backup -> parent_backup_link ;
970+ }
971+
972+ if (child_backup -> parent_backup == parent_backup_time )
973+ return true;
974+
975+ if (inclusive && child_backup -> start_time == parent_backup_time )
976+ return true;
977+
978+ return false;
979+ }
980+
981+ /*
982+ * return backup index number.
983+ * Note: this index number holds true until new sorting of backup list
984+ */
985+ int
986+ get_backup_index_number (parray * backup_list , pgBackup * backup )
987+ {
988+ int i ;
989+
990+ for (i = 0 ; i < parray_num (backup_list ); i ++ )
991+ {
992+ pgBackup * tmp_backup = (pgBackup * ) parray_get (backup_list , i );
993+
994+ if (tmp_backup -> start_time == backup -> start_time )
995+ return i ;
996+ }
997+ elog (ERROR , "Failed to find backup %s" , base36enc (backup -> start_time ));
998+ return 0 ;
914999}
0 commit comments