frostfs-sdk-go/netmap/context.go
Evgenii Stratonikov 555ccc63b2 [#167] netmap: Allow to select insufficient number of nodes
Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
2023-09-15 14:47:54 +03:00

107 lines
2.6 KiB
Go

package netmap
import (
"errors"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/netmap"
"git.frostfs.info/TrueCloudLab/hrw"
)
// context of a placement build process.
type context struct {
// network map to operate on
netMap NetMap
// cache of processed filters
processedFilters map[string]*netmap.Filter
// cache of processed selectors
processedSelectors map[string]*netmap.Selector
// stores results of selector processing
selections map[string][]nodes
// cache of parsed numeric values
numCache map[string]uint64
hrwSeed []byte
// hrw.Hash of hrwSeed
hrwSeedHash uint64
// weightFunc is a weighting function for determining node priority
// which combines low price and high performance
weightFunc weightFunc
// container backup factor
cbf uint32
// nodes already used in previous selections, which is needed when the placement
// policy uses the UNIQUE flag. Nodes marked as used are not used in subsequent
// base selections.
usedNodes map[uint64]bool
// If true, returns an error when netmap does not contain enough nodes for selection.
// By default best effort is taken.
strict bool
}
// Various validation errors.
var (
errInvalidFilterName = errors.New("filter name is invalid")
errInvalidNumber = errors.New("invalid number")
errInvalidFilterOp = errors.New("invalid filter operation")
errFilterNotFound = errors.New("filter not found")
errNonEmptyFilters = errors.New("simple filter contains sub-filters")
errNotEnoughNodes = errors.New("not enough nodes to SELECT from")
errUnnamedTopFilter = errors.New("unnamed top-level filter")
)
// newContext returns initialized context.
func newContext(nm NetMap) *context {
return &context{
netMap: nm,
processedFilters: make(map[string]*netmap.Filter),
processedSelectors: make(map[string]*netmap.Selector),
selections: make(map[string][]nodes),
numCache: make(map[string]uint64),
weightFunc: defaultWeightFunc(nm.nodes),
usedNodes: make(map[uint64]bool),
}
}
func (c *context) setPivot(pivot []byte) {
if len(pivot) != 0 {
c.hrwSeed = pivot
c.hrwSeedHash = hrw.Hash(pivot)
}
}
func (c *context) setCBF(cbf uint32) {
if cbf == 0 {
c.cbf = 3
} else {
c.cbf = cbf
}
}
func (c *context) addUsedNodes(ns ...NodeInfo) {
for _, n := range ns {
c.usedNodes[n.hash] = true
}
}
func defaultWeightFunc(ns nodes) weightFunc {
mean := newMeanAgg()
min := newMinAgg()
for i := range ns {
mean.Add(float64(ns[i].capacity()))
min.Add(float64(ns[i].Price()))
}
return newWeightFunc(
newSigmoidNorm(mean.Compute()),
newReverseMinNorm(min.Compute()))
}