github.com/filecoin-project/specs-actors/v4@v4.0.2/actors/builtin/miner/bitfield_queue.go (about) 1 package miner 2 3 import ( 4 "fmt" 5 "sort" 6 7 "github.com/filecoin-project/go-bitfield" 8 "github.com/filecoin-project/go-state-types/abi" 9 "github.com/ipfs/go-cid" 10 "golang.org/x/xerrors" 11 12 "github.com/filecoin-project/specs-actors/v4/actors/util/adt" 13 ) 14 15 // Wrapper for working with an AMT[ChainEpoch]*Bitfield functioning as a queue, bucketed by epoch. 16 // Keys in the queue are quantized (upwards), modulo some offset, to reduce the cardinality of keys. 17 type BitfieldQueue struct { 18 *adt.Array 19 quant QuantSpec 20 } 21 22 func LoadBitfieldQueue(store adt.Store, root cid.Cid, quant QuantSpec, bitwidth int) (BitfieldQueue, error) { 23 arr, err := adt.AsArray(store, root, bitwidth) 24 if err != nil { 25 return BitfieldQueue{}, xerrors.Errorf("failed to load epoch queue %v: %w", root, err) 26 } 27 return BitfieldQueue{arr, quant}, nil 28 } 29 30 // Adds values to the queue entry for an epoch. 31 func (q BitfieldQueue) AddToQueue(rawEpoch abi.ChainEpoch, values bitfield.BitField) error { 32 if isEmpty, err := values.IsEmpty(); err != nil { 33 return xerrors.Errorf("failed to decode early termination bitfield: %w", err) 34 } else if isEmpty { 35 // nothing to do. 36 return nil 37 } 38 epoch := q.quant.QuantizeUp(rawEpoch) 39 var bf bitfield.BitField 40 if _, err := q.Array.Get(uint64(epoch), &bf); err != nil { 41 return xerrors.Errorf("failed to lookup queue epoch %v: %w", epoch, err) 42 } 43 44 bf, err := bitfield.MergeBitFields(bf, values) 45 if err != nil { 46 return xerrors.Errorf("failed to merge bitfields for queue epoch %v: %w", epoch, err) 47 } 48 49 if err = q.Array.Set(uint64(epoch), bf); err != nil { 50 return xerrors.Errorf("failed to set queue epoch %v: %w", epoch, err) 51 } 52 return nil 53 } 54 55 func (q BitfieldQueue) AddToQueueValues(epoch abi.ChainEpoch, values ...uint64) error { 56 if len(values) == 0 { 57 return nil 58 } 59 return q.AddToQueue(epoch, bitfield.NewFromSet(values)) 60 } 61 62 // Cut cuts the elements from the bits in the given bitfield out of the queue, 63 // shifting other bits down and removing any newly empty entries. 64 // 65 // See the docs on BitField.Cut to better understand what it does. 66 func (q BitfieldQueue) Cut(toCut bitfield.BitField) error { 67 var epochsToRemove []uint64 68 if err := q.ForEach(func(epoch abi.ChainEpoch, bf bitfield.BitField) error { 69 bf, err := bitfield.CutBitField(bf, toCut) 70 if err != nil { 71 return err 72 } 73 if empty, err := bf.IsEmpty(); err != nil { 74 return err 75 } else if !empty { 76 return q.Set(uint64(epoch), bf) 77 } 78 epochsToRemove = append(epochsToRemove, uint64(epoch)) 79 return nil 80 }); err != nil { 81 return xerrors.Errorf("failed to cut from bitfield queue: %w", err) 82 } 83 if err := q.BatchDelete(epochsToRemove, true); err != nil { 84 return xerrors.Errorf("failed to remove empty epochs from bitfield queue: %w", err) 85 } 86 return nil 87 } 88 89 func (q BitfieldQueue) AddManyToQueueValues(values map[abi.ChainEpoch][]uint64) error { 90 // Pre-quantize to reduce the number of updates. 91 quantizedValues := make(map[abi.ChainEpoch][]uint64, len(values)) 92 for rawEpoch, entries := range values { // nolint:nomaprange // subsequently sorted 93 epoch := q.quant.QuantizeUp(rawEpoch) 94 quantizedValues[epoch] = append(quantizedValues[epoch], entries...) 95 } 96 97 // Update each epoch in-order to be deterministic. 98 updatedEpochs := make([]abi.ChainEpoch, 0, len(quantizedValues)) 99 for epoch := range quantizedValues { // nolint:nomaprange // subsequently sorted 100 updatedEpochs = append(updatedEpochs, epoch) 101 } 102 103 sort.Slice(updatedEpochs, func(i, j int) bool { 104 return updatedEpochs[i] < updatedEpochs[j] 105 }) 106 107 for _, epoch := range updatedEpochs { 108 if err := q.AddToQueueValues(epoch, quantizedValues[epoch]...); err != nil { 109 return err 110 } 111 } 112 return nil 113 } 114 115 // Removes and returns all values with keys less than or equal to until. 116 // Modified return value indicates whether this structure has been changed by the call. 117 func (q BitfieldQueue) PopUntil(until abi.ChainEpoch) (values bitfield.BitField, modified bool, err error) { 118 var poppedValues []bitfield.BitField 119 var poppedKeys []uint64 120 121 stopErr := fmt.Errorf("stop") 122 if err = q.ForEach(func(epoch abi.ChainEpoch, bf bitfield.BitField) error { 123 if epoch > until { 124 return stopErr 125 } 126 poppedKeys = append(poppedKeys, uint64(epoch)) 127 poppedValues = append(poppedValues, bf) 128 return err 129 }); err != nil && err != stopErr { 130 return bitfield.BitField{}, false, err 131 } 132 133 // Nothing expired. 134 if len(poppedKeys) == 0 { 135 return bitfield.New(), false, nil 136 } 137 138 if err = q.BatchDelete(poppedKeys, true); err != nil { 139 return bitfield.BitField{}, false, err 140 } 141 merged, err := bitfield.MultiMerge(poppedValues...) 142 if err != nil { 143 return bitfield.BitField{}, false, err 144 } 145 146 return merged, true, nil 147 } 148 149 // Iterates the queue. 150 func (q BitfieldQueue) ForEach(cb func(epoch abi.ChainEpoch, bf bitfield.BitField) error) error { 151 var bf bitfield.BitField 152 return q.Array.ForEach(&bf, func(i int64) error { 153 cpy, err := bf.Copy() 154 if err != nil { 155 return xerrors.Errorf("failed to copy bitfield in queue: %w", err) 156 } 157 return cb(abi.ChainEpoch(i), cpy) 158 }) 159 }