@@ -875,11 +875,69 @@ func GetLocalityInfo(
875
875
return info , nil
876
876
}
877
877
878
+ type BackupTreeEntry struct {
879
+ // The URI to the backup manifest.
880
+ Uri string
881
+ // The contents of the backup Manifest.
882
+ Manifest backuppb.BackupManifest
883
+ // The locality information for the backup.
884
+ LocalityInfo jobspb.RestoreDetails_BackupLocalityInfo
885
+ }
886
+
887
+ // zipBackupTreeEntries zips the default URIs, main backup manifests, and
888
+ // locality information into a slice of backupChainEntry structs. It assumes
889
+ // that the passed in slices are of the same length and that each entry at the
890
+ // same index in each slice corresponds to the same backup.
891
+ func zipBackupTreeEntries (
892
+ defaultURIs []string ,
893
+ mainBackupManifests []backuppb.BackupManifest ,
894
+ localityInfo []jobspb.RestoreDetails_BackupLocalityInfo ,
895
+ ) ([]BackupTreeEntry , error ) {
896
+ if len (defaultURIs ) != len (mainBackupManifests ) || len (defaultURIs ) != len (localityInfo ) {
897
+ return nil , errors .AssertionFailedf (
898
+ "length mismatch: defaultURIs %d, mainBackupManifests %d, localityInfo %d" ,
899
+ len (defaultURIs ), len (mainBackupManifests ), len (localityInfo ),
900
+ )
901
+ }
902
+
903
+ entries := make ([]BackupTreeEntry , len (mainBackupManifests ))
904
+ for i := range mainBackupManifests {
905
+ entries [i ] = BackupTreeEntry {
906
+ Uri : defaultURIs [i ],
907
+ Manifest : mainBackupManifests [i ],
908
+ LocalityInfo : localityInfo [i ],
909
+ }
910
+ }
911
+
912
+ return entries , nil
913
+ }
914
+
915
+ // unzipBackupTreeEntries unzips a slice of backupChainEntry structs into
916
+ // slices of their constituent parts: default URIs, main backup manifests, and
917
+ // locality info and returns the individual slices.
918
+ func unzipBackupTreeEntries (
919
+ entries []BackupTreeEntry ,
920
+ ) ([]string , []backuppb.BackupManifest , []jobspb.RestoreDetails_BackupLocalityInfo ) {
921
+ defaultURIs := make ([]string , len (entries ))
922
+ mainBackupManifests := make ([]backuppb.BackupManifest , len (entries ))
923
+ localityInfo := make ([]jobspb.RestoreDetails_BackupLocalityInfo , len (entries ))
924
+ for i := range entries {
925
+ defaultURIs [i ] = entries [i ].Uri
926
+ mainBackupManifests [i ] = entries [i ].Manifest
927
+ localityInfo [i ] = entries [i ].LocalityInfo
928
+ }
929
+ return defaultURIs , mainBackupManifests , localityInfo
930
+ }
931
+
878
932
// ValidateEndTimeAndTruncate checks that the requested target time, if
879
933
// specified, is valid for the list of incremental backups resolved, truncating
880
934
// the results to the backup that contains the target time.
881
935
// The method also performs additional sanity checks to ensure the backups cover
882
936
// the requested time.
937
+ //
938
+ // TODO (kev-cao): Refactor this function to accept/return the BackupTreeEntry
939
+ // type and update surrounding caller logic to use it. This will allow us to
940
+ // refactor out the zipping and unzipping logic.
883
941
func ValidateEndTimeAndTruncate (
884
942
defaultURIs []string ,
885
943
mainBackupManifests []backuppb.BackupManifest ,
@@ -888,71 +946,70 @@ func ValidateEndTimeAndTruncate(
888
946
includeSkipped bool ,
889
947
includeCompacted bool ,
890
948
) ([]string , []backuppb.BackupManifest , []jobspb.RestoreDetails_BackupLocalityInfo , error ) {
949
+ backupEntries , err := zipBackupTreeEntries (defaultURIs , mainBackupManifests , localityInfo )
950
+ if err != nil {
951
+ return nil , nil , nil , err
952
+ }
953
+
891
954
if ! includeCompacted {
892
- defaultURIs , mainBackupManifests , localityInfo = skipCompactedBackups (
893
- defaultURIs , mainBackupManifests , localityInfo ,
894
- )
955
+ backupEntries = skipCompactedBackups (backupEntries )
895
956
}
896
957
897
958
if endTime .IsEmpty () {
898
959
if includeSkipped {
899
- return defaultURIs , mainBackupManifests , localityInfo , nil
960
+ uris , manifests , locality := unzipBackupTreeEntries (backupEntries )
961
+ return uris , manifests , locality , nil
900
962
}
901
- uris , manifests , locality , err := ElideSkippedLayers (defaultURIs , mainBackupManifests , localityInfo )
902
- if err != nil {
903
- return nil , nil , nil , err
904
- }
905
- if err := validateContinuity (manifests ); err != nil {
963
+ backupEntries = elideSkippedLayers (backupEntries )
964
+ if err := validateContinuity (backupEntries ); err != nil {
906
965
return nil , nil , nil , err
907
966
}
967
+ uris , manifests , locality := unzipBackupTreeEntries (backupEntries )
908
968
return uris , manifests , locality , nil
909
969
}
910
- for i , b := range mainBackupManifests {
970
+ for i , b := range backupEntries {
911
971
// Find the backup that covers the requested time.
912
- if ! (b .StartTime .Less (endTime ) && endTime .LessEq (b .EndTime )) {
972
+ if ! (b .Manifest . StartTime .Less (endTime ) && endTime .LessEq (b . Manifest .EndTime )) {
913
973
continue
914
974
}
915
975
916
976
// Ensure that the backup actually has revision history.
917
- if ! endTime .Equal (b .EndTime ) {
918
- if b .MVCCFilter != backuppb .MVCCFilter_All {
977
+ if ! endTime .Equal (b .Manifest . EndTime ) {
978
+ if b .Manifest . MVCCFilter != backuppb .MVCCFilter_All {
919
979
const errPrefix = "invalid RESTORE timestamp: restoring to arbitrary time requires that BACKUP for requested time be created with 'revision_history' option."
920
980
if i == 0 {
921
981
return nil , nil , nil , errors .Errorf (
922
982
errPrefix + " nearest backup time is %s" ,
923
- timeutil .Unix (0 , b .EndTime .WallTime ).UTC (),
983
+ timeutil .Unix (0 , b .Manifest . EndTime .WallTime ).UTC (),
924
984
)
925
985
}
926
986
return nil , nil , nil , errors .Errorf (
927
987
errPrefix + " nearest BACKUP times are %s or %s" ,
928
988
timeutil .Unix (0 , mainBackupManifests [i - 1 ].EndTime .WallTime ).UTC (),
929
- timeutil .Unix (0 , b .EndTime .WallTime ).UTC (),
989
+ timeutil .Unix (0 , b .Manifest . EndTime .WallTime ).UTC (),
930
990
)
931
991
}
932
992
// Ensure that the revision history actually covers the requested time -
933
993
// while the BACKUP's start and end might contain the requested time for
934
994
// example if start time is 0 (full backup), the revision history was
935
995
// only captured since the GC window. Note that the RevisionStartTime is
936
996
// the latest for ranges backed up.
937
- if endTime .LessEq (b .RevisionStartTime ) {
997
+ if endTime .LessEq (b .Manifest . RevisionStartTime ) {
938
998
return nil , nil , nil , errors .Errorf (
939
999
"invalid RESTORE timestamp: BACKUP for requested time only has revision history" +
940
- " from %v" , timeutil .Unix (0 , b .RevisionStartTime .WallTime ).UTC (),
1000
+ " from %v" , timeutil .Unix (0 , b .Manifest . RevisionStartTime .WallTime ).UTC (),
941
1001
)
942
1002
}
943
1003
}
944
1004
if includeSkipped {
945
- return defaultURIs [:i + 1 ], mainBackupManifests [:i + 1 ], localityInfo [:i + 1 ], nil
946
- }
947
- uris , manifests , locality , err := ElideSkippedLayers (
948
- defaultURIs [:i + 1 ], mainBackupManifests [:i + 1 ], localityInfo [:i + 1 ],
949
- )
950
- if err != nil {
951
- return nil , nil , nil , err
1005
+ uris , manifests , locality := unzipBackupTreeEntries (backupEntries [:i + 1 ])
1006
+ return uris , manifests , locality , nil
952
1007
}
953
- if err := validateContinuity (manifests ); err != nil {
1008
+ backupEntries = elideSkippedLayers (backupEntries [:i + 1 ])
1009
+ if err := validateContinuity (backupEntries ); err != nil {
954
1010
return nil , nil , nil , err
955
1011
}
1012
+ uris , manifests , locality := unzipBackupTreeEntries (backupEntries )
956
1013
return uris , manifests , locality , nil
957
1014
}
958
1015
@@ -962,68 +1019,58 @@ func ValidateEndTimeAndTruncate(
962
1019
}
963
1020
964
1021
// skipCompactedBackups removes any compacted backups from the list of
965
- // backups and returns the updated list of URIs, manifests, and locality info .
1022
+ // backups and returns the updated list backup entries .
966
1023
//
967
1024
// NOTE: This function modifies the underlying memory of the slices passed in.
968
- func skipCompactedBackups (
969
- defaultURIs []string ,
970
- manifests []backuppb.BackupManifest ,
971
- localityInfo []jobspb.RestoreDetails_BackupLocalityInfo ,
972
- ) ([]string , []backuppb.BackupManifest , []jobspb.RestoreDetails_BackupLocalityInfo ) {
973
- for i := len (manifests ) - 1 ; i >= 0 ; i -- {
974
- if manifests [i ].IsCompacted {
975
- defaultURIs = slices .Delete (defaultURIs , i , i + 1 )
976
- manifests = slices .Delete (manifests , i , i + 1 )
977
- localityInfo = slices .Delete (localityInfo , i , i + 1 )
1025
+ func skipCompactedBackups (backupEntries []BackupTreeEntry ) []BackupTreeEntry {
1026
+ for i := len (backupEntries ) - 1 ; i >= 0 ; i -- {
1027
+ if backupEntries [i ].Manifest .IsCompacted {
1028
+ backupEntries = slices .Delete (backupEntries , i , i + 1 )
978
1029
}
979
1030
}
980
- return defaultURIs , manifests , localityInfo
1031
+ return backupEntries
981
1032
}
982
1033
983
1034
// validateContinuity checks that the backups are continuous.
984
- func validateContinuity (manifests []backuppb. BackupManifest ) error {
985
- if len (manifests ) == 0 {
1035
+ func validateContinuity (backupEntries []BackupTreeEntry ) error {
1036
+ if len (backupEntries ) == 0 {
986
1037
return errors .AssertionFailedf ("an empty chain of backups cannot cover an end time" )
987
1038
}
988
- for i := range len (manifests ) - 1 {
989
- if ! manifests [i ].EndTime .Equal (manifests [i + 1 ].StartTime ) {
1039
+ for i := range len (backupEntries ) - 1 {
1040
+ if ! backupEntries [i ].Manifest . EndTime .Equal (backupEntries [i + 1 ]. Manifest .StartTime ) {
990
1041
return errors .AssertionFailedf (
991
1042
"backups are not continuous: %dth backup ends at %+v, %dth backup starts at %+v" ,
992
- i , manifests [i ].EndTime ,
993
- i + 1 , manifests [i + 1 ].StartTime ,
1043
+ i , backupEntries [i ]. Manifest .EndTime ,
1044
+ i + 1 , backupEntries [i + 1 ]. Manifest .StartTime ,
994
1045
)
995
1046
}
996
1047
}
997
1048
return nil
998
1049
}
999
1050
1000
- // ElideSkippedLayers removes backups that are skipped in the backup chain and
1051
+ // elideSkippedLayers removes backups that are skipped in the backup chain and
1001
1052
// ensures only backups that will be used in the restore are returned.
1002
1053
//
1003
1054
// Note: This assumes that the provided backups are sorted in increasing order
1004
1055
// by end time, and then sorted in increasing order by start time to break ties.
1005
- func ElideSkippedLayers (
1006
- uris []string , backups []backuppb.BackupManifest , loc []jobspb.RestoreDetails_BackupLocalityInfo ,
1007
- ) ([]string , []backuppb.BackupManifest , []jobspb.RestoreDetails_BackupLocalityInfo , error ) {
1008
- uris , backups , loc = elideDuplicateEndTimes (uris , backups , loc )
1009
- i := len (backups ) - 1
1056
+ func elideSkippedLayers (backupEntries []BackupTreeEntry ) []BackupTreeEntry {
1057
+ backupEntries = elideDuplicateEndTimes (backupEntries )
1058
+ i := len (backupEntries ) - 1
1010
1059
for i > 0 {
1011
1060
// Find j such that backups[j] is parent of backups[i].
1012
1061
j := i - 1
1013
- for j >= 0 && ! backups [i ].StartTime .Equal (backups [j ].EndTime ) {
1062
+ for j >= 0 && ! backupEntries [i ].Manifest . StartTime .Equal (backupEntries [j ]. Manifest .EndTime ) {
1014
1063
j --
1015
1064
}
1016
1065
// If there are backups between i and j, remove them.
1017
1066
// If j is less than 0, then no parent was found so nothing to skip.
1018
1067
if j != i - 1 && j >= 0 {
1019
- uris = slices .Delete (uris , j + 1 , i )
1020
- backups = slices .Delete (backups , j + 1 , i )
1021
- loc = slices .Delete (loc , j + 1 , i )
1068
+ backupEntries = slices .Delete (backupEntries , j + 1 , i )
1022
1069
}
1023
1070
// Move up to check the chain from j now.
1024
1071
i = j
1025
1072
}
1026
- return uris , backups , loc , nil
1073
+ return backupEntries
1027
1074
}
1028
1075
1029
1076
// elideDuplicateEndTimes ensures that backups in a list of backups are
@@ -1034,24 +1081,21 @@ func ElideSkippedLayers(
1034
1081
// by end time, and then sorted in increasing order by start time to break ties.
1035
1082
// This is the case for backups being returned by storage clients due to us
1036
1083
// encoding backup paths in a way that ensures this order.
1037
- func elideDuplicateEndTimes (
1038
- uris []string , backups []backuppb.BackupManifest , loc []jobspb.RestoreDetails_BackupLocalityInfo ,
1039
- ) ([]string , []backuppb.BackupManifest , []jobspb.RestoreDetails_BackupLocalityInfo ) {
1040
- for i := range len (backups ) - 1 {
1084
+ func elideDuplicateEndTimes (backupEntries []BackupTreeEntry ) []BackupTreeEntry {
1085
+ for i := range len (backupEntries ) - 1 {
1041
1086
j := i + 1
1042
1087
// Find j such that backups[j] no longer shares the same end time as
1043
1088
// backups[i].
1044
- for j < len (backups ) && backups [i ].EndTime .Equal (backups [j ].EndTime ) {
1089
+ for j < len (backupEntries ) &&
1090
+ backupEntries [i ].Manifest .EndTime .Equal (backupEntries [j ].Manifest .EndTime ) {
1045
1091
j ++
1046
1092
}
1047
1093
// If there exists backups between i and j, remove them.
1048
1094
if j > i + 1 {
1049
- uris = slices .Delete (uris , i + 1 , j )
1050
- backups = slices .Delete (backups , i + 1 , j )
1051
- loc = slices .Delete (loc , i + 1 , j )
1095
+ backupEntries = slices .Delete (backupEntries , i + 1 , j )
1052
1096
}
1053
1097
}
1054
- return uris , backups , loc
1098
+ return backupEntries
1055
1099
}
1056
1100
1057
1101
// GetBackupIndexAtTime returns the index of the latest backup in
0 commit comments