frostfs-api-go/pkg/netmap/netmap.go
Alex Vanin c35e15a758 [#249] pkg/netmap: Add CBF field in placement context
If CBF value is not set, then netmap package uses default CBF
value. However it modifies placement policy structure in
`GetContainerNodes()` because policy passed as a pointer.

Instead package can store CBF value in internal context and use
it without policy modification.

Signed-off-by: Alex Vanin <alexey@nspcc.ru>
2021-01-27 15:47:06 +03:00

100 lines
2.2 KiB
Go

package netmap
import (
"fmt"
"github.com/nspcc-dev/hrw"
)
const defaultCBF = 3
// Netmap represents netmap which contains preprocessed nodes.
type Netmap struct {
Nodes Nodes
}
// NewNetmap constructs netmap from the list of raw nodes.
func NewNetmap(nodes Nodes) (*Netmap, error) {
return &Netmap{
Nodes: nodes,
}, nil
}
func flattenNodes(ns []Nodes) Nodes {
result := make(Nodes, 0, len(ns))
for i := range ns {
result = append(result, ns[i]...)
}
return result
}
// GetPlacementVectors returns placement vectors for an object given containerNodes cnt.
func (m *Netmap) GetPlacementVectors(cnt ContainerNodes, pivot []byte) ([]Nodes, error) {
h := hrw.Hash(pivot)
wf := GetDefaultWeightFunc(m.Nodes)
result := make([]Nodes, len(cnt.Replicas()))
for i, rep := range cnt.Replicas() {
result[i] = make(Nodes, len(rep))
copy(result[i], rep)
hrw.SortSliceByWeightValue(result[i], result[i].Weights(wf), h)
}
return result, nil
}
// GetContainerNodes returns nodes corresponding to each replica.
// Order of returned nodes corresponds to order of replicas in p.
// pivot is a seed for HRW sorting.
func (m *Netmap) GetContainerNodes(p *PlacementPolicy, pivot []byte) (ContainerNodes, error) {
c := NewContext(m)
c.setPivot(pivot)
c.setCBF(p.ContainerBackupFactor())
if err := c.processFilters(p); err != nil {
return nil, err
}
if err := c.processSelectors(p); err != nil {
return nil, err
}
result := make([]Nodes, len(p.Replicas()))
for i, r := range p.Replicas() {
if r == nil {
return nil, fmt.Errorf("%w: REPLICA", ErrMissingField)
}
if r.Selector() == "" {
if len(p.Selectors()) == 0 {
s := new(Selector)
s.SetCount(r.Count())
s.SetFilter(MainFilterName)
nodes, err := c.getSelection(p, s)
if err != nil {
return nil, err
}
result[i] = flattenNodes(nodes)
}
for _, s := range p.Selectors() {
result[i] = append(result[i], flattenNodes(c.Selections[s.Name()])...)
}
continue
}
nodes, ok := c.Selections[r.Selector()]
if !ok {
return nil, fmt.Errorf("%w: REPLICA '%s'", ErrSelectorNotFound, r.Selector())
}
result[i] = append(result[i], flattenNodes(nodes)...)
}
return containerNodes(result), nil
}