github.com/filecoin-project/specs-actors/v4@v4.0.2/actors/migration/nv10/util.go (about) 1 package nv10 2 3 import ( 4 "bytes" 5 "context" 6 "sync" 7 "testing" 8 9 amt2 "github.com/filecoin-project/go-amt-ipld/v2" 10 amt3 "github.com/filecoin-project/go-amt-ipld/v3" 11 hamt2 "github.com/filecoin-project/go-hamt-ipld/v2" 12 hamt3 "github.com/filecoin-project/go-hamt-ipld/v3" 13 "github.com/filecoin-project/go-state-types/rt" 14 adt2 "github.com/filecoin-project/specs-actors/v2/actors/util/adt" 15 cid "github.com/ipfs/go-cid" 16 cbor "github.com/ipfs/go-ipld-cbor" 17 cbg "github.com/whyrusleeping/cbor-gen" 18 "golang.org/x/xerrors" 19 20 adt3 "github.com/filecoin-project/specs-actors/v4/actors/util/adt" 21 ) 22 23 // Migrates a HAMT from v2 to v3 without re-encoding keys or values. 24 func migrateHAMTRaw(ctx context.Context, store cbor.IpldStore, root cid.Cid, newBitwidth int) (cid.Cid, error) { 25 inRootNode, err := hamt2.LoadNode(ctx, store, root, adt2.HamtOptions...) 26 if err != nil { 27 return cid.Undef, err 28 } 29 30 newOpts := append(adt3.DefaultHamtOptions, hamt3.UseTreeBitWidth(newBitwidth)) 31 outRootNode, err := hamt3.NewNode(store, newOpts...) 32 if err != nil { 33 return cid.Undef, err 34 } 35 36 if err = inRootNode.ForEach(ctx, func(k string, val interface{}) error { 37 return outRootNode.SetRaw(ctx, k, val.(*cbg.Deferred).Raw) 38 }); err != nil { 39 return cid.Undef, err 40 } 41 42 err = outRootNode.Flush(ctx) 43 if err != nil { 44 return cid.Undef, err 45 } 46 return store.Put(ctx, outRootNode) 47 } 48 49 // Migrates an AMT from v2 to v3 without re-encoding values. 50 func migrateAMTRaw(ctx context.Context, store cbor.IpldStore, root cid.Cid, newBitwidth int) (cid.Cid, error) { 51 inRootNode, err := amt2.LoadAMT(ctx, store, root) 52 if err != nil { 53 return cid.Undef, err 54 } 55 56 newOpts := append(adt3.DefaultAmtOptions, amt3.UseTreeBitWidth(uint(newBitwidth))) 57 outRootNode, err := amt3.NewAMT(store, newOpts...) 58 if err != nil { 59 return cid.Undef, err 60 } 61 62 if err = inRootNode.ForEach(ctx, func(k uint64, d *cbg.Deferred) error { 63 return outRootNode.Set(ctx, k, d) 64 }); err != nil { 65 return cid.Undef, err 66 } 67 68 return outRootNode.Flush(ctx) 69 } 70 71 // Migrates a HAMT of HAMTs from v2 to v3 without re-encoding leaf keys or values. 72 func migrateHAMTHAMTRaw(ctx context.Context, store cbor.IpldStore, root cid.Cid, newOuterBitwidth, newInnerBitwidth int) (cid.Cid, error) { 73 inRootNodeOuter, err := hamt2.LoadNode(ctx, store, root) 74 if err != nil { 75 return cid.Undef, err 76 } 77 78 newOptsOuter := append(adt3.DefaultHamtOptions, hamt3.UseTreeBitWidth(newOuterBitwidth)) 79 outRootNodeOuter, err := hamt3.NewNode(store, newOptsOuter...) 80 if err != nil { 81 return cid.Undef, err 82 } 83 84 if err = inRootNodeOuter.ForEach(ctx, func(k string, val interface{}) error { 85 var inInner cbg.CborCid 86 if err := inInner.UnmarshalCBOR(bytes.NewReader(val.(*cbg.Deferred).Raw)); err != nil { 87 return err 88 } 89 outInner, err := migrateHAMTRaw(ctx, store, cid.Cid(inInner), newInnerBitwidth) 90 if err != nil { 91 return err 92 } 93 c := cbg.CborCid(outInner) 94 return outRootNodeOuter.Set(ctx, k, &c) 95 }); err != nil { 96 return cid.Undef, err 97 } 98 99 if err := outRootNodeOuter.Flush(ctx); err != nil { 100 return cid.Undef, err 101 } 102 return store.Put(ctx, outRootNodeOuter) 103 } 104 105 // Migrates a HAMT of AMTs from v2 to v3 without re-encoding values. 106 func migrateHAMTAMTRaw(ctx context.Context, store cbor.IpldStore, root cid.Cid, newOuterBitwidth, newInnerBitwidth int) (cid.Cid, error) { 107 inRootNodeOuter, err := hamt2.LoadNode(ctx, store, root) 108 if err != nil { 109 return cid.Undef, err 110 } 111 newOptsOuter := append(adt3.DefaultHamtOptions, hamt3.UseTreeBitWidth(newOuterBitwidth)) 112 outRootNodeOuter, err := hamt3.NewNode(store, newOptsOuter...) 113 if err != nil { 114 return cid.Undef, err 115 } 116 117 if err = inRootNodeOuter.ForEach(ctx, func(k string, val interface{}) error { 118 var inInner cbg.CborCid 119 if err := inInner.UnmarshalCBOR(bytes.NewReader(val.(*cbg.Deferred).Raw)); err != nil { 120 return err 121 } 122 outInner, err := migrateAMTRaw(ctx, store, cid.Cid(inInner), newInnerBitwidth) 123 if err != nil { 124 return err 125 } 126 c := cbg.CborCid(outInner) 127 return outRootNodeOuter.Set(ctx, k, &c) 128 }); err != nil { 129 return cid.Undef, err 130 } 131 132 if err := outRootNodeOuter.Flush(ctx); err != nil { 133 return cid.Undef, err 134 } 135 return store.Put(ctx, outRootNodeOuter) 136 } 137 138 type MemMigrationCache struct { 139 MigrationMap sync.Map 140 } 141 142 func NewMemMigrationCache() *MemMigrationCache { 143 return new(MemMigrationCache) 144 } 145 146 func (m *MemMigrationCache) Write(key string, c cid.Cid) error { 147 m.MigrationMap.Store(key, c) 148 return nil 149 } 150 151 func (m *MemMigrationCache) Read(key string) (bool, cid.Cid, error) { 152 val, found := m.MigrationMap.Load(key) 153 if !found { 154 return false, cid.Undef, nil 155 } 156 c, ok := val.(cid.Cid) 157 if !ok { 158 return false, cid.Undef, xerrors.Errorf("non cid value in cache") 159 } 160 161 return true, c, nil 162 } 163 164 func (m *MemMigrationCache) Load(key string, loadFunc func() (cid.Cid, error)) (cid.Cid, error) { 165 found, c, err := m.Read(key) 166 if err != nil { 167 return cid.Undef, err 168 } 169 if found { 170 return c, nil 171 } 172 c, err = loadFunc() 173 if err != nil { 174 return cid.Undef, err 175 } 176 m.MigrationMap.Store(key, c) 177 return c, nil 178 } 179 180 func (m *MemMigrationCache) Clone() *MemMigrationCache { 181 newCache := NewMemMigrationCache() 182 newCache.Update(m) 183 return newCache 184 } 185 186 func (m *MemMigrationCache) Update(other *MemMigrationCache) { 187 other.MigrationMap.Range(func(key, value interface{}) bool { 188 m.MigrationMap.Store(key, value) 189 return true 190 }) 191 } 192 193 type TestLogger struct { 194 TB testing.TB 195 } 196 197 func (t TestLogger) Log(_ rt.LogLevel, msg string, args ...interface{}) { 198 t.TB.Logf(msg, args...) 199 }