github.com/filecoin-project/specs-actors/v4@v4.0.2/actors/builtin/market/set_multimap.go (about) 1 package market 2 3 import ( 4 "reflect" 5 6 "github.com/filecoin-project/go-state-types/abi" 7 cid "github.com/ipfs/go-cid" 8 "github.com/pkg/errors" 9 cbg "github.com/whyrusleeping/cbor-gen" 10 "golang.org/x/xerrors" 11 12 "github.com/filecoin-project/specs-actors/v4/actors/util/adt" 13 ) 14 15 type SetMultimap struct { 16 mp *adt.Map 17 store adt.Store 18 innerBitwidth int 19 } 20 21 // Interprets a store as a HAMT-based map of HAMT-based sets with root `r`. 22 // Both inner and outer HAMTs are interpreted with branching factor 2^bitwidth. 23 func AsSetMultimap(s adt.Store, r cid.Cid, outerBitwidth, innerBitwidth int) (*SetMultimap, error) { 24 m, err := adt.AsMap(s, r, outerBitwidth) 25 if err != nil { 26 return nil, err 27 } 28 return &SetMultimap{mp: m, store: s, innerBitwidth: innerBitwidth}, nil 29 } 30 31 // Creates a new map backed by an empty HAMT and flushes it to the store. 32 // Both inner and outer HAMTs have branching factor 2^bitwidth. 33 func MakeEmptySetMultimap(s adt.Store, bitwidth int) (*SetMultimap, error) { 34 m, err := adt.MakeEmptyMap(s, bitwidth) 35 if err != nil { 36 return nil, err 37 } 38 return &SetMultimap{mp: m, store: s, innerBitwidth: bitwidth}, nil 39 } 40 41 // Writes a new empty map to the store and returns its CID. 42 func StoreEmptySetMultimap(s adt.Store, bitwidth int) (cid.Cid, error){ 43 mm, err := MakeEmptySetMultimap(s, bitwidth) 44 if err != nil { 45 return cid.Undef, err 46 } 47 return mm.Root() 48 } 49 50 // Returns the root cid of the underlying HAMT. 51 func (mm *SetMultimap) Root() (cid.Cid, error) { 52 return mm.mp.Root() 53 } 54 55 func (mm *SetMultimap) Put(epoch abi.ChainEpoch, v abi.DealID) error { 56 // Load the hamt under key, or initialize a new empty one if not found. 57 k := abi.UIntKey(uint64(epoch)) 58 set, found, err := mm.get(k) 59 if err != nil { 60 return err 61 } 62 if !found { 63 set, err = adt.MakeEmptySet(mm.store, mm.innerBitwidth) 64 if err != nil { 65 return err 66 } 67 } 68 69 // Add to the set. 70 if err = set.Put(dealKey(v)); err != nil { 71 return errors.Wrapf(err, "failed to add key to set %v", epoch) 72 } 73 74 src, err := set.Root() 75 if err != nil { 76 return xerrors.Errorf("failed to flush set root: %w", err) 77 } 78 // Store the new set root under key. 79 newSetRoot := cbg.CborCid(src) 80 err = mm.mp.Put(k, &newSetRoot) 81 if err != nil { 82 return errors.Wrapf(err, "failed to store set") 83 } 84 return nil 85 } 86 87 func (mm *SetMultimap) PutMany(epoch abi.ChainEpoch, vs []abi.DealID) error { 88 // Load the hamt under key, or initialize a new empty one if not found. 89 k := abi.UIntKey(uint64(epoch)) 90 set, found, err := mm.get(k) 91 if err != nil { 92 return err 93 } 94 if !found { 95 set, err = adt.MakeEmptySet(mm.store, mm.innerBitwidth) 96 if err != nil { 97 return err 98 } 99 } 100 101 // Add to the set. 102 for _, v := range vs { 103 if err = set.Put(dealKey(v)); err != nil { 104 return errors.Wrapf(err, "failed to add key to set %v", epoch) 105 } 106 } 107 108 src, err := set.Root() 109 if err != nil { 110 return xerrors.Errorf("failed to flush set root: %w", err) 111 } 112 // Store the new set root under key. 113 newSetRoot := cbg.CborCid(src) 114 err = mm.mp.Put(k, &newSetRoot) 115 if err != nil { 116 return errors.Wrapf(err, "failed to store set") 117 } 118 return nil 119 } 120 121 // Removes all values for a key. 122 func (mm *SetMultimap) RemoveAll(key abi.ChainEpoch) error { 123 if _, err := mm.mp.TryDelete(abi.UIntKey(uint64(key))); err != nil { 124 return xerrors.Errorf("failed to delete set key %v: %w", key, err) 125 } 126 return nil 127 } 128 129 // Iterates all entries for a key, iteration halts if the function returns an error. 130 func (mm *SetMultimap) ForEach(epoch abi.ChainEpoch, fn func(id abi.DealID) error) error { 131 set, found, err := mm.get(abi.UIntKey(uint64(epoch))) 132 if err != nil { 133 return err 134 } 135 if found { 136 return set.ForEach(func(k string) error { 137 v, err := parseDealKey(k) 138 if err != nil { 139 return err 140 } 141 return fn(v) 142 }) 143 } 144 return nil 145 } 146 147 func (mm *SetMultimap) get(key abi.Keyer) (*adt.Set, bool, error) { 148 var setRoot cbg.CborCid 149 found, err := mm.mp.Get(key, &setRoot) 150 if err != nil { 151 return nil, false, errors.Wrapf(err, "failed to load set key %v", key) 152 } 153 var set *adt.Set 154 if found { 155 set, err = adt.AsSet(mm.store, cid.Cid(setRoot), mm.innerBitwidth) 156 if err != nil { 157 return nil, false, err 158 } 159 } 160 return set, found, nil 161 } 162 163 func dealKey(e abi.DealID) abi.Keyer { 164 return abi.UIntKey(uint64(e)) 165 } 166 167 func parseDealKey(s string) (abi.DealID, error) { 168 key, err := abi.ParseUIntKey(s) 169 return abi.DealID(key), err 170 } 171 172 func init() { 173 // Check that DealID is indeed an unsigned integer to confirm that dealKey is making the right interpretation. 174 var e abi.DealID 175 if reflect.TypeOf(e).Kind() != reflect.Uint64 { 176 panic("incorrect sector number encoding") 177 } 178 }