@@ -875,6 +875,7 @@ func GetLocalityInfo(
875
875
return info , nil
876
876
}
877
877
878
+ // TODO (kev-cao): Remove in v26.2
878
879
type BackupTreeEntry struct {
879
880
// The URI to the backup manifest.
880
881
Uri string
@@ -884,11 +885,45 @@ type BackupTreeEntry struct {
884
885
LocalityInfo jobspb.RestoreDetails_BackupLocalityInfo
885
886
}
886
887
887
- // zipBackupTreeEntries zips the default URIs, main backup manifests, and
888
+ func (b BackupTreeEntry ) Start () hlc.Timestamp {
889
+ return b .Manifest .StartTime
890
+ }
891
+
892
+ func (b BackupTreeEntry ) End () hlc.Timestamp {
893
+ return b .Manifest .EndTime
894
+ }
895
+
896
+ func (b BackupTreeEntry ) Compacted () bool {
897
+ return b .Manifest .IsCompacted
898
+ }
899
+
900
+ func (b BackupTreeEntry ) MVCC () backuppb.MVCCFilter {
901
+ return b .Manifest .MVCCFilter
902
+ }
903
+
904
+ func (b BackupTreeEntry ) RevisionStart () hlc.Timestamp {
905
+ return b .Manifest .RevisionStartTime
906
+ }
907
+
908
+ // This interface is used as a stop-gap during the transitional period where
909
+ // some restorable backups will not have backup indexes and some will.
910
+ // Afterwards, we can remove this interface and replace instances of
911
+ // ManifestLike with BackupIndexMetadata.
912
+ // TODO (kev-cao): Remove in v26.2
913
+ type ManifestLike interface {
914
+ Start () hlc.Timestamp
915
+ End () hlc.Timestamp
916
+ Compacted () bool
917
+ MVCC () backuppb.MVCCFilter
918
+ RevisionStart () hlc.Timestamp
919
+ }
920
+
921
+ // ZipBackupTreeEntries zips the default URIs, main backup manifests, and
888
922
// locality information into a slice of backupChainEntry structs. It assumes
889
923
// that the passed in slices are of the same length and that each entry at the
890
924
// same index in each slice corresponds to the same backup.
891
- func zipBackupTreeEntries (
925
+ // TODO (kev-cao): Remove in v26.2
926
+ func ZipBackupTreeEntries (
892
927
defaultURIs []string ,
893
928
mainBackupManifests []backuppb.BackupManifest ,
894
929
localityInfo []jobspb.RestoreDetails_BackupLocalityInfo ,
@@ -912,10 +947,11 @@ func zipBackupTreeEntries(
912
947
return entries , nil
913
948
}
914
949
915
- // unzipBackupTreeEntries unzips a slice of backupChainEntry structs into
950
+ // UnzipBackupTreeEntries unzips a slice of backupChainEntry structs into
916
951
// slices of their constituent parts: default URIs, main backup manifests, and
917
952
// locality info and returns the individual slices.
918
- func unzipBackupTreeEntries (
953
+ // TODO (kev-cao): Remove in v26.2
954
+ func UnzipBackupTreeEntries (
919
955
entries []BackupTreeEntry ,
920
956
) ([]string , []backuppb.BackupManifest , []jobspb.RestoreDetails_BackupLocalityInfo ) {
921
957
defaultURIs := make ([]string , len (entries ))
@@ -935,85 +971,70 @@ func unzipBackupTreeEntries(
935
971
// The method also performs additional sanity checks to ensure the backups cover
936
972
// the requested time.
937
973
//
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.
941
- func ValidateEndTimeAndTruncate (
942
- defaultURIs []string ,
943
- mainBackupManifests []backuppb.BackupManifest ,
944
- localityInfo []jobspb.RestoreDetails_BackupLocalityInfo ,
945
- endTime hlc.Timestamp ,
946
- includeSkipped bool ,
947
- includeCompacted bool ,
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
-
974
+ // Note: This function assumes that the manifests in the chain are sorted by end
975
+ // time in ascending order and ties are broken by start time in ascending order.
976
+ func ValidateEndTimeAndTruncate [E ManifestLike ](
977
+ manifests []E , endTime hlc.Timestamp , includeSkipped bool , includeCompacted bool ,
978
+ ) ([]E , error ) {
954
979
if ! includeCompacted {
955
- backupEntries = skipCompactedBackups (backupEntries )
980
+ manifests = skipCompactedBackups (manifests )
956
981
}
957
982
958
983
if endTime .IsEmpty () {
959
984
if includeSkipped {
960
- uris , manifests , locality := unzipBackupTreeEntries (backupEntries )
961
- return uris , manifests , locality , nil
985
+ return manifests , nil
962
986
}
963
- backupEntries = elideSkippedLayers (backupEntries )
964
- if err := validateContinuity (backupEntries ); err != nil {
965
- return nil , nil , nil , err
987
+ manifests = elideSkippedLayers (manifests )
988
+ if err := validateContinuity (manifests ); err != nil {
989
+ return nil , err
966
990
}
967
- uris , manifests , locality := unzipBackupTreeEntries (backupEntries )
968
- return uris , manifests , locality , nil
991
+ return manifests , nil
969
992
}
970
- for i , b := range backupEntries {
993
+ for i , b := range manifests {
971
994
// Find the backup that covers the requested time.
972
- if ! (b .Manifest . StartTime . Less (endTime ) && endTime .LessEq (b .Manifest . EndTime )) {
995
+ if ! (b .Start (). Less (endTime ) && endTime .LessEq (b .End () )) {
973
996
continue
974
997
}
975
998
976
999
// Ensure that the backup actually has revision history.
977
- if ! endTime .Equal (b .Manifest . EndTime ) {
978
- if b .Manifest . MVCCFilter != backuppb .MVCCFilter_All {
1000
+ if ! endTime .Equal (b .End () ) {
1001
+ if b .MVCC () != backuppb .MVCCFilter_All {
979
1002
const errPrefix = "invalid RESTORE timestamp: restoring to arbitrary time requires that BACKUP for requested time be created with 'revision_history' option."
980
1003
if i == 0 {
981
- return nil , nil , nil , errors .Errorf (
1004
+ return nil , errors .Errorf (
982
1005
errPrefix + " nearest backup time is %s" ,
983
- timeutil .Unix (0 , b .Manifest . EndTime .WallTime ).UTC (),
1006
+ timeutil .Unix (0 , b .End () .WallTime ).UTC (),
984
1007
)
985
1008
}
986
- return nil , nil , nil , errors .Errorf (
1009
+ return nil , errors .Errorf (
987
1010
errPrefix + " nearest BACKUP times are %s or %s" ,
988
- timeutil .Unix (0 , mainBackupManifests [i - 1 ].EndTime .WallTime ).UTC (),
989
- timeutil .Unix (0 , b .Manifest . EndTime .WallTime ).UTC (),
1011
+ timeutil .Unix (0 , manifests [i - 1 ].End () .WallTime ).UTC (),
1012
+ timeutil .Unix (0 , b .End () .WallTime ).UTC (),
990
1013
)
991
1014
}
992
1015
// Ensure that the revision history actually covers the requested time -
993
1016
// while the BACKUP's start and end might contain the requested time for
994
1017
// example if start time is 0 (full backup), the revision history was
995
1018
// only captured since the GC window. Note that the RevisionStartTime is
996
1019
// the latest for ranges backed up.
997
- if endTime .LessEq (b .Manifest . RevisionStartTime ) {
998
- return nil , nil , nil , errors .Errorf (
1020
+ if endTime .LessEq (b .RevisionStart () ) {
1021
+ return nil , errors .Errorf (
999
1022
"invalid RESTORE timestamp: BACKUP for requested time only has revision history" +
1000
- " from %v" , timeutil .Unix (0 , b .Manifest . RevisionStartTime .WallTime ).UTC (),
1023
+ " from %v" , timeutil .Unix (0 , b .RevisionStart () .WallTime ).UTC (),
1001
1024
)
1002
1025
}
1003
1026
}
1004
1027
if includeSkipped {
1005
- uris , manifests , locality := unzipBackupTreeEntries (backupEntries [:i + 1 ])
1006
- return uris , manifests , locality , nil
1028
+ return manifests [:i + 1 ], nil
1007
1029
}
1008
- backupEntries = elideSkippedLayers (backupEntries [:i + 1 ])
1009
- if err := validateContinuity (backupEntries ); err != nil {
1010
- return nil , nil , nil , err
1030
+ manifests = elideSkippedLayers (manifests [:i + 1 ])
1031
+ if err := validateContinuity (manifests ); err != nil {
1032
+ return nil , err
1011
1033
}
1012
- uris , manifests , locality := unzipBackupTreeEntries (backupEntries )
1013
- return uris , manifests , locality , nil
1034
+ return manifests , nil
1014
1035
}
1015
1036
1016
- return nil , nil , nil , errors .Errorf (
1037
+ return nil , errors .Errorf (
1017
1038
"invalid RESTORE timestamp: supplied backups do not cover requested time" ,
1018
1039
)
1019
1040
}
@@ -1022,26 +1043,30 @@ func ValidateEndTimeAndTruncate(
1022
1043
// backups and returns the updated list backup entries.
1023
1044
//
1024
1045
// NOTE: This function modifies the underlying memory of the slices passed in.
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 )
1046
+ func skipCompactedBackups [ E ManifestLike ]( manifests []E ) []E {
1047
+ for i := len (manifests ) - 1 ; i >= 0 ; i -- {
1048
+ if manifests [i ].Compacted () {
1049
+ manifests = slices .Delete (manifests , i , i + 1 )
1029
1050
}
1030
1051
}
1031
- return backupEntries
1052
+ return manifests
1032
1053
}
1033
1054
1034
1055
// validateContinuity checks that the backups are continuous.
1035
- func validateContinuity (backupEntries []BackupTreeEntry ) error {
1036
- if len (backupEntries ) == 0 {
1056
+ //
1057
+ // Note: This fucntion assumes the backups are sorted by end time in ascending
1058
+ // order.
1059
+ func validateContinuity [E ManifestLike ](manifests []E ) error {
1060
+ if len (manifests ) == 0 {
1037
1061
return errors .AssertionFailedf ("an empty chain of backups cannot cover an end time" )
1038
1062
}
1039
- for i := range len (backupEntries ) - 1 {
1040
- if ! backupEntries [i ].Manifest .EndTime .Equal (backupEntries [i + 1 ].Manifest .StartTime ) {
1063
+ for i := range len (manifests ) - 1 {
1064
+ end := manifests [i ].End ()
1065
+ if ! end .Equal (manifests [i + 1 ].Start ()) {
1041
1066
return errors .AssertionFailedf (
1042
1067
"backups are not continuous: %dth backup ends at %+v, %dth backup starts at %+v" ,
1043
- i , backupEntries [i ].Manifest . EndTime ,
1044
- i + 1 , backupEntries [i + 1 ].Manifest . StartTime ,
1068
+ i , manifests [i ].End () ,
1069
+ i + 1 , manifests [i + 1 ].Start () ,
1045
1070
)
1046
1071
}
1047
1072
}
@@ -1051,49 +1076,53 @@ func validateContinuity(backupEntries []BackupTreeEntry) error {
1051
1076
// elideSkippedLayers removes backups that are skipped in the backup chain and
1052
1077
// ensures only backups that will be used in the restore are returned.
1053
1078
//
1054
- // Note: This assumes that the provided backups are sorted in increasing order
1055
- // by end time, and then sorted in increasing order by start time to break ties .
1056
- func elideSkippedLayers ( backupEntries []BackupTreeEntry ) []BackupTreeEntry {
1057
- backupEntries = elideDuplicateEndTimes (backupEntries )
1058
- i := len (backupEntries ) - 1
1079
+ // Note: This function assumes that the manifests in the chain are sorted by end
1080
+ // time in ascending order and ties are broken by start time in ascending order .
1081
+ func elideSkippedLayers [ E ManifestLike ]( manifests []E ) []E {
1082
+ manifests = elideDuplicateEndTimes (manifests )
1083
+ i := len (manifests ) - 1
1059
1084
for i > 0 {
1060
1085
// Find j such that backups[j] is parent of backups[i].
1061
1086
j := i - 1
1062
- for j >= 0 && ! backupEntries [i ].Manifest .StartTime .Equal (backupEntries [j ].Manifest .EndTime ) {
1087
+ start := manifests [i ].Start ()
1088
+ for j >= 0 && ! start .Equal (manifests [j ].End ()) {
1063
1089
j --
1064
1090
}
1065
1091
// If there are backups between i and j, remove them.
1066
1092
// If j is less than 0, then no parent was found so nothing to skip.
1067
1093
if j != i - 1 && j >= 0 {
1068
- backupEntries = slices .Delete (backupEntries , j + 1 , i )
1094
+ manifests = slices .Delete (manifests , j + 1 , i )
1069
1095
}
1070
1096
// Move up to check the chain from j now.
1071
1097
i = j
1072
1098
}
1073
- return backupEntries
1099
+ return manifests
1074
1100
}
1075
1101
1076
1102
// elideDuplicateEndTimes ensures that backups in a list of backups are
1077
1103
// functionally unique by removing any duplicates that have the same end time,
1078
1104
// choosing backups with earlier start times and eliding the rest.
1079
1105
//
1080
- // Note: This assumes that the provided backups are sorted in increasing order
1081
- // by end time, and then sorted in increasing order by start time to break ties.
1082
- func elideDuplicateEndTimes (backupEntries []BackupTreeEntry ) []BackupTreeEntry {
1083
- for i := range len (backupEntries ) - 1 {
1106
+ // Note: This function assumes that the manifests in the chain are sorted by end
1107
+ // time in ascending order and ties are broken by start time in ascending order.
1108
+ func elideDuplicateEndTimes [E ManifestLike ](manifests []E ) []E {
1109
+ for i := range len (manifests ) - 1 {
1110
+ if i >= len (manifests ) {
1111
+ break
1112
+ }
1084
1113
j := i + 1
1085
1114
// Find j such that backups[j] no longer shares the same end time as
1086
1115
// backups[i].
1087
- for j < len ( backupEntries ) &&
1088
- backupEntries [ i ]. Manifest . EndTime . Equal (backupEntries [j ].Manifest . EndTime ) {
1116
+ end := manifests [ i ]. End ()
1117
+ for j < len ( manifests ) && end . Equal (manifests [j ].End () ) {
1089
1118
j ++
1090
1119
}
1091
1120
// If there exists backups between i and j, remove them.
1092
1121
if j > i + 1 {
1093
- backupEntries = slices .Delete (backupEntries , i + 1 , j )
1122
+ manifests = slices .Delete (manifests , i + 1 , j )
1094
1123
}
1095
1124
}
1096
- return backupEntries
1125
+ return manifests
1097
1126
}
1098
1127
1099
1128
// GetBackupIndexAtTime returns the index of the latest backup in
0 commit comments