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  }