forked from TrueCloudLab/frostfs-api-go
[#157] netmap: Fallback to using minimal backup factor
Use CBF=1 when strict policy can't be satisfied. Signed-off-by: Evgenii Stratonikov <evgeniy@nspcc.ru>
This commit is contained in:
parent
c01024b553
commit
ea6b6adfe0
2 changed files with 45 additions and 9 deletions
|
@ -36,14 +36,14 @@ func (c *Context) processSelectors(p *PlacementPolicy) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetNodesCount returns amount of buckets and nodes in every bucket
|
// GetNodesCount returns amount of buckets and minimum number of nodes in every bucket
|
||||||
// for a given placement policy.
|
// for the given selector.
|
||||||
func GetNodesCount(p *PlacementPolicy, s *Selector) (int, int) {
|
func GetNodesCount(_ *PlacementPolicy, s *Selector) (int, int) {
|
||||||
switch s.Clause() {
|
switch s.Clause() {
|
||||||
case ClauseSame:
|
case ClauseSame:
|
||||||
return 1, int(p.ContainerBackupFactor() * s.Count())
|
return 1, int(s.Count())
|
||||||
default:
|
default:
|
||||||
return int(s.Count()), int(p.ContainerBackupFactor())
|
return int(s.Count()), 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,18 +69,26 @@ func (c *Context) getSelection(p *PlacementPolicy, s *Selector) ([]Nodes, error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
maxNodesInBucket := nodesInBucket * int(p.ContainerBackupFactor())
|
||||||
nodes := make([]Nodes, 0, len(buckets))
|
nodes := make([]Nodes, 0, len(buckets))
|
||||||
|
fallback := make([]Nodes, 0, len(buckets))
|
||||||
|
|
||||||
for i := range buckets {
|
for i := range buckets {
|
||||||
ns := buckets[i].nodes
|
ns := buckets[i].nodes
|
||||||
if len(ns) >= nodesInBucket {
|
if len(ns) >= maxNodesInBucket {
|
||||||
nodes = append(nodes, ns[:nodesInBucket])
|
nodes = append(nodes, ns[:maxNodesInBucket])
|
||||||
|
} else if len(ns) >= nodesInBucket {
|
||||||
|
fallback = append(fallback, ns)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(nodes) < bucketCount {
|
||||||
|
// Fallback to using minimum allowed backup factor (1).
|
||||||
|
nodes = append(nodes, fallback...)
|
||||||
if len(nodes) < bucketCount {
|
if len(nodes) < bucketCount {
|
||||||
return nil, fmt.Errorf("%w: '%s'", ErrNotEnoughNodes, s.Name())
|
return nil, fmt.Errorf("%w: '%s'", ErrNotEnoughNodes, s.Name())
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if len(c.pivot) != 0 {
|
if len(c.pivot) != 0 {
|
||||||
weights := make([]float64, len(nodes))
|
weights := make([]float64, len(nodes))
|
||||||
|
|
|
@ -92,6 +92,33 @@ func TestPlacementPolicy_GetPlacementVectors(t *testing.T) {
|
||||||
require.Equal(t, len(v.Replicas()[1]), len(ids), "not all nodes we distinct")
|
require.Equal(t, len(v.Replicas()[1]), len(ids), "not all nodes we distinct")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestPlacementPolicy_LowerBound(t *testing.T) {
|
||||||
|
p := newPlacementPolicy(
|
||||||
|
2, // backup factor
|
||||||
|
[]*Replica{
|
||||||
|
newReplica(1, "X"),
|
||||||
|
},
|
||||||
|
[]*Selector{
|
||||||
|
newSelector("X", "Country", ClauseSame, 2, "*"),
|
||||||
|
},
|
||||||
|
nil, // filters
|
||||||
|
)
|
||||||
|
|
||||||
|
nodes := []NodeInfo{
|
||||||
|
nodeInfoFromAttributes("ID", "1", "Country", "DE"),
|
||||||
|
nodeInfoFromAttributes("ID", "2", "Country", "DE"),
|
||||||
|
nodeInfoFromAttributes("ID", "3", "Country", "DE"),
|
||||||
|
}
|
||||||
|
|
||||||
|
nm, err := NewNetmap(NodesFromInfo(nodes))
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
v, err := nm.GetContainerNodes(p, nil)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
require.Equal(t, 3, len(v.Flatten()))
|
||||||
|
}
|
||||||
|
|
||||||
func TestPlacementPolicy_ProcessSelectors(t *testing.T) {
|
func TestPlacementPolicy_ProcessSelectors(t *testing.T) {
|
||||||
p := newPlacementPolicy(2, nil,
|
p := newPlacementPolicy(2, nil,
|
||||||
[]*Selector{
|
[]*Selector{
|
||||||
|
@ -128,6 +155,7 @@ func TestPlacementPolicy_ProcessSelectors(t *testing.T) {
|
||||||
sel := c.Selections[s.Name()]
|
sel := c.Selections[s.Name()]
|
||||||
s := c.Selectors[s.Name()]
|
s := c.Selectors[s.Name()]
|
||||||
bucketCount, nodesInBucket := GetNodesCount(p, s)
|
bucketCount, nodesInBucket := GetNodesCount(p, s)
|
||||||
|
nodesInBucket *= int(p.ContainerBackupFactor())
|
||||||
targ := fmt.Sprintf("selector '%s'", s.Name())
|
targ := fmt.Sprintf("selector '%s'", s.Name())
|
||||||
require.Equal(t, bucketCount, len(sel), targ)
|
require.Equal(t, bucketCount, len(sel), targ)
|
||||||
for _, res := range sel {
|
for _, res := range sel {
|
||||||
|
@ -216,7 +244,7 @@ func TestPlacementPolicy_ProcessSelectorsInvalid(t *testing.T) {
|
||||||
{
|
{
|
||||||
"NotEnoughNodes (backup factor)",
|
"NotEnoughNodes (backup factor)",
|
||||||
newPlacementPolicy(2, nil,
|
newPlacementPolicy(2, nil,
|
||||||
[]*Selector{newSelector("MyStore", "Country", ClauseDistinct, 1, "FromRU")},
|
[]*Selector{newSelector("MyStore", "Country", ClauseDistinct, 2, "FromRU")},
|
||||||
[]*Filter{newFilter("FromRU", "Country", "Russia", OpEQ)}),
|
[]*Filter{newFilter("FromRU", "Country", "Russia", OpEQ)}),
|
||||||
ErrNotEnoughNodes,
|
ErrNotEnoughNodes,
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in a new issue