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  }