@@ -20,7 +20,6 @@ package atree
2020
2121import (
2222 "encoding/binary"
23- "errors"
2423 "fmt"
2524 "sort"
2625 "strings"
@@ -1013,233 +1012,6 @@ func (s *PersistentSlabStorage) DeltasSizeWithoutTempAddresses() uint64 {
10131012 return size
10141013}
10151014
1016- // FixLoadedBrokenReferences traverses loaded slabs and fixes broken references in maps.
1017- // A broken reference is a SlabID referencing a non-existent slab.
1018- // To fix a map containing broken references, this function replaces broken map with
1019- // empty map having the same SlabID and also removes all slabs in the old map.
1020- // Limitations:
1021- // - only fix broken references in map
1022- // - only traverse loaded slabs in deltas and cache
1023- // NOTE: The intended use case is to enable migration programs in onflow/flow-go to
1024- // fix broken references. As of April 2024, only 10 registers in testnet (not mainnet)
1025- // were found to have broken references and they seem to have resulted from a bug
1026- // that was fixed 2 years ago by https://github.com/onflow/cadence/pull/1565.
1027- func (s * PersistentSlabStorage ) FixLoadedBrokenReferences (needToFix func (old Value ) bool ) (
1028- fixedSlabIDs map [SlabID ][]SlabID , // key: root slab ID, value: slab IDs containing broken refs
1029- skippedSlabIDs map [SlabID ][]SlabID , // key: root slab ID, value: slab IDs containing broken refs
1030- err error ,
1031- ) {
1032-
1033- // parentOf is used to find root slab from non-root slab.
1034- // Broken reference can be in non-root slab, and we need SlabID of root slab
1035- // to replace broken map by creating an empty new map with same SlabID.
1036- parentOf := make (map [SlabID ]SlabID )
1037-
1038- getRootSlabID := func (id SlabID ) SlabID {
1039- for {
1040- parentID , ok := parentOf [id ]
1041- if ok {
1042- id = parentID
1043- } else {
1044- return id
1045- }
1046- }
1047- }
1048-
1049- hasBrokenReferenceInSlab := func (id SlabID , slab Slab ) bool {
1050- if slab == nil {
1051- return false
1052- }
1053-
1054- switch slab .(type ) {
1055- case * ArrayMetaDataSlab , * MapMetaDataSlab : // metadata slabs
1056- var foundBrokenRef bool
1057-
1058- for _ , childStorable := range slab .ChildStorables () {
1059-
1060- if slabIDStorable , ok := childStorable .(SlabIDStorable ); ok {
1061-
1062- childID := SlabID (slabIDStorable )
1063-
1064- // Track parent-child relationship of root slabs and non-root slabs.
1065- parentOf [childID ] = id
1066-
1067- if ! s .existIfLoaded (childID ) {
1068- foundBrokenRef = true
1069- }
1070-
1071- // Continue with remaining child storables to track parent-child relationship.
1072- }
1073- }
1074-
1075- return foundBrokenRef
1076-
1077- default : // data slabs
1078- childStorables := slab .ChildStorables ()
1079-
1080- for len (childStorables ) > 0 {
1081-
1082- var nextChildStorables []Storable
1083-
1084- for _ , childStorable := range childStorables {
1085-
1086- if slabIDStorable , ok := childStorable .(SlabIDStorable ); ok {
1087-
1088- if ! s .existIfLoaded (SlabID (slabIDStorable )) {
1089- return true
1090- }
1091-
1092- continue
1093- }
1094-
1095- // Append child storables of this childStorable to
1096- // handle nested SlabIDStorable, such as Cadence SomeValue.
1097- nextChildStorables = append (
1098- nextChildStorables ,
1099- childStorable .ChildStorables ()... ,
1100- )
1101- }
1102-
1103- childStorables = nextChildStorables
1104- }
1105-
1106- return false
1107- }
1108- }
1109-
1110- var brokenSlabIDs []SlabID
1111-
1112- // Iterate delta slabs.
1113- for id , slab := range s .deltas {
1114- if hasBrokenReferenceInSlab (id , slab ) {
1115- brokenSlabIDs = append (brokenSlabIDs , id )
1116- }
1117- }
1118-
1119- // Iterate cache slabs.
1120- for id , slab := range s .cache {
1121- if _ , ok := s .deltas [id ]; ok {
1122- continue
1123- }
1124- if hasBrokenReferenceInSlab (id , slab ) {
1125- brokenSlabIDs = append (brokenSlabIDs , id )
1126- }
1127- }
1128-
1129- if len (brokenSlabIDs ) == 0 {
1130- return nil , nil , nil
1131- }
1132-
1133- rootSlabIDsWithBrokenData := make (map [SlabID ][]SlabID )
1134- var errs []error
1135-
1136- // Find SlabIDs of root slab for slabs containing broken references.
1137- for _ , id := range brokenSlabIDs {
1138- rootID := getRootSlabID (id )
1139- if rootID == SlabIDUndefined {
1140- errs = append (errs , fmt .Errorf ("failed to get root slab id for slab %s" , id ))
1141- continue
1142- }
1143- rootSlabIDsWithBrokenData [rootID ] = append (rootSlabIDsWithBrokenData [rootID ], id )
1144- }
1145-
1146- for rootSlabID , brokenSlabIDs := range rootSlabIDsWithBrokenData {
1147- rootSlab := s .RetrieveIfLoaded (rootSlabID )
1148- if rootSlab == nil {
1149- errs = append (errs , fmt .Errorf ("failed to retrieve loaded root slab %s" , rootSlabID ))
1150- continue
1151- }
1152-
1153- switch rootSlab := rootSlab .(type ) {
1154- case MapSlab :
1155- value , err := rootSlab .StoredValue (s )
1156- if err != nil {
1157- errs = append (errs , fmt .Errorf ("failed to convert slab %s into value" , rootSlab .SlabID ()))
1158- continue
1159- }
1160-
1161- if needToFix (value ) {
1162- err := s .fixBrokenReferencesInMap (rootSlab )
1163- if err != nil {
1164- errs = append (errs , err )
1165- continue
1166- }
1167- } else {
1168- if skippedSlabIDs == nil {
1169- skippedSlabIDs = make (map [SlabID ][]SlabID )
1170- }
1171- skippedSlabIDs [rootSlabID ] = brokenSlabIDs
1172- }
1173-
1174- default :
1175- // IMPORTANT: Only handle map slabs for now. DO NOT silently fix currently unknown problems.
1176- errs = append (errs , fmt .Errorf ("failed to fix broken references in non-map slab %s (%T)" , rootSlab .SlabID (), rootSlab ))
1177- }
1178- }
1179-
1180- for id := range skippedSlabIDs {
1181- delete (rootSlabIDsWithBrokenData , id )
1182- }
1183-
1184- return rootSlabIDsWithBrokenData , skippedSlabIDs , errors .Join (errs ... )
1185- }
1186-
1187- // fixBrokenReferencesInMap replaces replaces broken map with empty map
1188- // having the same SlabID and also removes all slabs in the old map.
1189- func (s * PersistentSlabStorage ) fixBrokenReferencesInMap (old MapSlab ) error {
1190- id := old .SlabID ()
1191-
1192- oldExtraData := old .ExtraData ()
1193-
1194- // Create an empty map with the same StorgeID, type, and seed as the old map.
1195- newMap := & MapDataSlab {
1196- header : MapSlabHeader {
1197- slabID : id ,
1198- size : mapRootDataSlabPrefixSize + hkeyElementsPrefixSize ,
1199- },
1200- extraData : & MapExtraData {
1201- TypeInfo : oldExtraData .TypeInfo ,
1202- Seed : oldExtraData .Seed ,
1203- },
1204- elements : newHkeyElements (0 ),
1205- }
1206-
1207- // Store new empty map with the same SlabID.
1208- err := s .Store (id , newMap )
1209- if err != nil {
1210- return err
1211- }
1212-
1213- // Remove all slabs and references in old map.
1214- references , _ , err := s .getAllChildReferences (old )
1215- if err != nil {
1216- return err
1217- }
1218-
1219- for _ , childID := range references {
1220- err = s .Remove (childID )
1221- if err != nil {
1222- return err
1223- }
1224- }
1225-
1226- return nil
1227- }
1228-
1229- func (s * PersistentSlabStorage ) existIfLoaded (id SlabID ) bool {
1230- // Check deltas.
1231- if slab , ok := s .deltas [id ]; ok {
1232- return slab != nil
1233- }
1234-
1235- // Check read cache.
1236- if slab , ok := s .cache [id ]; ok {
1237- return slab != nil
1238- }
1239-
1240- return false
1241- }
1242-
12431015// GetAllChildReferences returns child references of given slab (all levels),
12441016// including nested container and theirs child references.
12451017func (s * PersistentSlabStorage ) GetAllChildReferences (id SlabID ) (
0 commit comments