github.com/filecoin-project/specs-actors/v4@v4.0.2/actors/builtin/miner/sector_map.go (about) 1 package miner 2 3 import ( 4 "math" 5 "sort" 6 7 "github.com/filecoin-project/go-bitfield" 8 "golang.org/x/xerrors" 9 ) 10 11 // Maps deadlines to partition maps. 12 type DeadlineSectorMap map[uint64]PartitionSectorMap 13 14 // Maps partitions to sector bitfields. 15 type PartitionSectorMap map[uint64]bitfield.BitField 16 17 // Check validates all bitfields and counts the number of partitions & sectors 18 // contained within the map, and returns an error if they exceed the given 19 // maximums. 20 func (dm DeadlineSectorMap) Check(maxPartitions, maxSectors uint64) error { 21 partitionCount, sectorCount, err := dm.Count() 22 if err != nil { 23 return xerrors.Errorf("failed to count sectors: %w", err) 24 } 25 if partitionCount > maxPartitions { 26 return xerrors.Errorf("too many partitions %d, max %d", partitionCount, maxPartitions) 27 } 28 29 if sectorCount > maxSectors { 30 return xerrors.Errorf("too many sectors %d, max %d", sectorCount, maxSectors) 31 } 32 33 return nil 34 } 35 36 // Count counts the number of partitions & sectors within the map. 37 func (dm DeadlineSectorMap) Count() (partitions, sectors uint64, err error) { 38 for dlIdx, pm := range dm { //nolint:nomaprange 39 partCount, sectorCount, err := pm.Count() 40 if err != nil { 41 return 0, 0, xerrors.Errorf("when counting deadline %d: %w", dlIdx, err) 42 } 43 if partCount > math.MaxUint64-partitions { 44 return 0, 0, xerrors.Errorf("uint64 overflow when counting partitions") 45 } 46 47 if sectorCount > math.MaxUint64-sectors { 48 return 0, 0, xerrors.Errorf("uint64 overflow when counting sectors") 49 } 50 sectors += sectorCount 51 partitions += partCount 52 } 53 return partitions, sectors, nil 54 } 55 56 // Add records the given sector bitfield at the given deadline/partition index. 57 func (dm DeadlineSectorMap) Add(dlIdx, partIdx uint64, sectorNos bitfield.BitField) error { 58 if dlIdx >= WPoStPeriodDeadlines { 59 return xerrors.Errorf("invalid deadline %d", dlIdx) 60 } 61 dl, ok := dm[dlIdx] 62 if !ok { 63 dl = make(PartitionSectorMap) 64 dm[dlIdx] = dl 65 } 66 return dl.Add(partIdx, sectorNos) 67 } 68 69 // AddValues records the given sectors at the given deadline/partition index. 70 func (dm DeadlineSectorMap) AddValues(dlIdx, partIdx uint64, sectorNos ...uint64) error { 71 return dm.Add(dlIdx, partIdx, bitfield.NewFromSet(sectorNos)) 72 } 73 74 // Deadlines returns a sorted slice of deadlines in the map. 75 func (dm DeadlineSectorMap) Deadlines() []uint64 { 76 deadlines := make([]uint64, 0, len(dm)) 77 for dlIdx := range dm { //nolint:nomaprange 78 deadlines = append(deadlines, dlIdx) 79 } 80 sort.Slice(deadlines, func(i, j int) bool { 81 return deadlines[i] < deadlines[j] 82 }) 83 return deadlines 84 } 85 86 // ForEach walks the deadlines in deadline order. 87 func (dm DeadlineSectorMap) ForEach(cb func(dlIdx uint64, pm PartitionSectorMap) error) error { 88 for _, dlIdx := range dm.Deadlines() { 89 if err := cb(dlIdx, dm[dlIdx]); err != nil { 90 return err 91 } 92 } 93 return nil 94 } 95 96 // AddValues records the given sectors at the given partition. 97 func (pm PartitionSectorMap) AddValues(partIdx uint64, sectorNos ...uint64) error { 98 return pm.Add(partIdx, bitfield.NewFromSet(sectorNos)) 99 } 100 101 // Add records the given sector bitfield at the given partition index, merging 102 // it with any existing bitfields if necessary. 103 func (pm PartitionSectorMap) Add(partIdx uint64, sectorNos bitfield.BitField) error { 104 if oldSectorNos, ok := pm[partIdx]; ok { 105 var err error 106 sectorNos, err = bitfield.MergeBitFields(sectorNos, oldSectorNos) 107 if err != nil { 108 return xerrors.Errorf("failed to merge sector bitfields: %w", err) 109 } 110 } 111 pm[partIdx] = sectorNos 112 return nil 113 } 114 115 // Count counts the number of partitions & sectors within the map. 116 func (pm PartitionSectorMap) Count() (partitions, sectors uint64, err error) { 117 for partIdx, bf := range pm { //nolint:nomaprange 118 count, err := bf.Count() 119 if err != nil { 120 return 0, 0, xerrors.Errorf("failed to parse bitmap for partition %d: %w", partIdx, err) 121 } 122 if count > math.MaxUint64-sectors { 123 return 0, 0, xerrors.Errorf("uint64 overflow when counting sectors") 124 } 125 sectors += count 126 } 127 return uint64(len(pm)), sectors, nil 128 } 129 130 // Partitions returns a sorted slice of partitions in the map. 131 func (pm PartitionSectorMap) Partitions() []uint64 { 132 partitions := make([]uint64, 0, len(pm)) 133 for partIdx := range pm { //nolint:nomaprange 134 partitions = append(partitions, partIdx) 135 } 136 sort.Slice(partitions, func(i, j int) bool { 137 return partitions[i] < partitions[j] 138 }) 139 return partitions 140 } 141 142 // ForEach walks the partitions in the map, in order of increasing index. 143 func (pm PartitionSectorMap) ForEach(cb func(partIdx uint64, sectorNos bitfield.BitField) error) error { 144 for _, partIdx := range pm.Partitions() { 145 if err := cb(partIdx, pm[partIdx]); err != nil { 146 return err 147 } 148 } 149 return nil 150 }