git.frostfs.info/TrueCloudLab/frostfs-sdk-go@v0.0.0-20241022124111-5361f0ecebd3/netmap/context.go (about)

     1  package netmap
     2  
     3  import (
     4  	"errors"
     5  
     6  	"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/netmap"
     7  	"git.frostfs.info/TrueCloudLab/hrw"
     8  )
     9  
    10  // context of a placement build process.
    11  type context struct {
    12  	// network map to operate on
    13  	netMap NetMap
    14  
    15  	// cache of processed filters
    16  	processedFilters map[string]*netmap.Filter
    17  
    18  	// cache of processed selectors
    19  	processedSelectors map[string]*netmap.Selector
    20  
    21  	// stores results of selector processing
    22  	selections map[string][]nodes
    23  
    24  	// cache of parsed numeric values
    25  	numCache map[string]uint64
    26  
    27  	hrwSeed []byte
    28  
    29  	// hrw.Hash of hrwSeed
    30  	hrwSeedHash uint64
    31  
    32  	// weightFunc is a weighting function for determining node priority
    33  	// which combines low price and high performance
    34  	weightFunc weightFunc
    35  
    36  	// container backup factor
    37  	cbf uint32
    38  
    39  	// nodes already used in previous selections, which is needed when the placement
    40  	// policy uses the UNIQUE flag. Nodes marked as used are not used in subsequent
    41  	// base selections.
    42  	usedNodes map[uint64]bool
    43  
    44  	// If true, returns an error when netmap does not contain enough nodes for selection.
    45  	// By default best effort is taken.
    46  	strict bool
    47  }
    48  
    49  // Various validation errors.
    50  var (
    51  	errInvalidFilterName = errors.New("filter name is invalid")
    52  	errInvalidNumber     = errors.New("invalid number")
    53  	errInvalidFilterOp   = errors.New("invalid filter operation")
    54  	errFilterNotFound    = errors.New("filter not found")
    55  	errNonEmptyFilters   = errors.New("simple filter contains sub-filters")
    56  	errNotEnoughNodes    = errors.New("not enough nodes to SELECT from")
    57  	errUnnamedTopFilter  = errors.New("unnamed top-level filter")
    58  )
    59  
    60  // newContext returns initialized context.
    61  func newContext(nm NetMap) *context {
    62  	return &context{
    63  		netMap:             nm,
    64  		processedFilters:   make(map[string]*netmap.Filter),
    65  		processedSelectors: make(map[string]*netmap.Selector),
    66  		selections:         make(map[string][]nodes),
    67  
    68  		numCache:   make(map[string]uint64),
    69  		weightFunc: defaultWeightFunc(nm.nodes),
    70  		usedNodes:  make(map[uint64]bool),
    71  	}
    72  }
    73  
    74  func (c *context) setPivot(pivot []byte) {
    75  	if len(pivot) != 0 {
    76  		c.hrwSeed = pivot
    77  		c.hrwSeedHash = hrw.Hash(pivot)
    78  	}
    79  }
    80  
    81  func (c *context) setCBF(cbf uint32) {
    82  	if cbf == 0 {
    83  		c.cbf = 3
    84  	} else {
    85  		c.cbf = cbf
    86  	}
    87  }
    88  
    89  func (c *context) addUsedNodes(ns ...NodeInfo) {
    90  	for _, n := range ns {
    91  		c.usedNodes[n.hash] = true
    92  	}
    93  }
    94  
    95  func defaultWeightFunc(ns nodes) weightFunc {
    96  	mean := newMeanAgg()
    97  	minV := newMinAgg()
    98  
    99  	for i := range ns {
   100  		mean.Add(float64(ns[i].capacity()))
   101  		minV.Add(float64(ns[i].Price()))
   102  	}
   103  
   104  	return newWeightFunc(
   105  		newSigmoidNorm(mean.Compute()),
   106  		newReverseMinNorm(minV.Compute()))
   107  }