0b02a48a10
Current node selection logic (in case of using SelectBySubnet): 1. selects one subnet randomly 2. selects one node randomly from the subnet 3. applies the placement NodeFilters to the node and ignore it, if doesn't match This logic is wrong: 1. Imagine that we have a subnet with two DE and one GB nodes. 2. We would like to select DE nodes 2. In case of GB node is selected (randomly) in step2, step3 will ignore the subnet, even if there are good (DE) nodes in there. Change-Id: I7673f52c89b46e0cc7b20a9b74137dc689d6c17e
98 lines
2.2 KiB
Go
98 lines
2.2 KiB
Go
// Copyright (C) 2020 Storj Labs, Inc.
|
|
// See LICENSE for copying information.
|
|
|
|
package nodeselection
|
|
|
|
import (
|
|
mathrand "math/rand" // Using mathrand here because crypto-graphic randomness is not required and simplifies code.
|
|
)
|
|
|
|
// SelectByID implements selection from nodes with every node having equal probability.
|
|
type SelectByID []*SelectedNode
|
|
|
|
var _ Selector = (SelectByID)(nil)
|
|
|
|
// Count returns the number of maximum number of nodes that it can return.
|
|
func (nodes SelectByID) Count() int { return len(nodes) }
|
|
|
|
// Select selects upto n nodes.
|
|
func (nodes SelectByID) Select(n int, nodeFilter NodeFilter) []*SelectedNode {
|
|
if n <= 0 {
|
|
return nil
|
|
}
|
|
|
|
selected := []*SelectedNode{}
|
|
for _, idx := range mathrand.Perm(len(nodes)) {
|
|
node := nodes[idx]
|
|
|
|
if !nodeFilter.MatchInclude(node) {
|
|
continue
|
|
}
|
|
|
|
selected = append(selected, node.Clone())
|
|
if len(selected) >= n {
|
|
break
|
|
}
|
|
}
|
|
|
|
return selected
|
|
}
|
|
|
|
// SelectBySubnet implements selection from nodes with every subnet having equal probability.
|
|
type SelectBySubnet []Subnet
|
|
|
|
var _ Selector = (SelectBySubnet)(nil)
|
|
|
|
// Subnet groups together nodes with the same subnet.
|
|
type Subnet struct {
|
|
Net string
|
|
Nodes []*SelectedNode
|
|
}
|
|
|
|
// SelectBySubnetFromNodes creates SelectBySubnet selector from nodes.
|
|
func SelectBySubnetFromNodes(nodes []*SelectedNode) SelectBySubnet {
|
|
bynet := map[string][]*SelectedNode{}
|
|
for _, node := range nodes {
|
|
bynet[node.LastNet] = append(bynet[node.LastNet], node)
|
|
}
|
|
|
|
var subnets SelectBySubnet
|
|
for net, nodes := range bynet {
|
|
subnets = append(subnets, Subnet{
|
|
Net: net,
|
|
Nodes: nodes,
|
|
})
|
|
}
|
|
|
|
return subnets
|
|
}
|
|
|
|
// Count returns the number of maximum number of nodes that it can return.
|
|
func (subnets SelectBySubnet) Count() int { return len(subnets) }
|
|
|
|
// Select selects upto n nodes.
|
|
func (subnets SelectBySubnet) Select(n int, filter NodeFilter) []*SelectedNode {
|
|
if n <= 0 {
|
|
return nil
|
|
}
|
|
|
|
selected := []*SelectedNode{}
|
|
r := NewRandomOrder(len(subnets))
|
|
for r.Next() {
|
|
subnet := subnets[r.At()]
|
|
|
|
rs := NewRandomOrder(len(subnet.Nodes))
|
|
for rs.Next() {
|
|
if filter.MatchInclude(subnet.Nodes[rs.At()]) {
|
|
selected = append(selected, subnet.Nodes[rs.At()].Clone())
|
|
break
|
|
}
|
|
}
|
|
if len(selected) >= n {
|
|
break
|
|
}
|
|
}
|
|
|
|
return selected
|
|
}
|