2021-10-25 13:27:59 +01:00
|
|
|
// Copyright (C) 2020 Storj Labs, Inc.
|
2020-05-15 15:32:28 +01:00
|
|
|
// See LICENSE for copying information.
|
|
|
|
|
2023-07-07 09:31:58 +01:00
|
|
|
package nodeselection
|
2020-05-15 15:32:28 +01:00
|
|
|
|
|
|
|
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.
|
2023-06-30 11:35:07 +01:00
|
|
|
type SelectByID []*SelectedNode
|
2020-05-15 15:32:28 +01:00
|
|
|
|
|
|
|
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.
|
2023-06-30 11:13:18 +01:00
|
|
|
func (nodes SelectByID) Select(n int, nodeFilter NodeFilter) []*SelectedNode {
|
2020-05-15 15:32:28 +01:00
|
|
|
if n <= 0 {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2023-06-30 11:35:07 +01:00
|
|
|
selected := []*SelectedNode{}
|
2020-05-15 15:32:28 +01:00
|
|
|
for _, idx := range mathrand.Perm(len(nodes)) {
|
|
|
|
node := nodes[idx]
|
|
|
|
|
2023-06-30 11:13:18 +01:00
|
|
|
if !nodeFilter.MatchInclude(node) {
|
2020-05-15 15:32:28 +01:00
|
|
|
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
|
2023-06-30 11:35:07 +01:00
|
|
|
Nodes []*SelectedNode
|
2020-05-15 15:32:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// SelectBySubnetFromNodes creates SelectBySubnet selector from nodes.
|
2023-06-30 11:35:07 +01:00
|
|
|
func SelectBySubnetFromNodes(nodes []*SelectedNode) SelectBySubnet {
|
|
|
|
bynet := map[string][]*SelectedNode{}
|
2020-05-15 15:32:28 +01:00
|
|
|
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.
|
2023-06-30 11:13:18 +01:00
|
|
|
func (subnets SelectBySubnet) Select(n int, filter NodeFilter) []*SelectedNode {
|
2020-05-15 15:32:28 +01:00
|
|
|
if n <= 0 {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2023-06-30 11:35:07 +01:00
|
|
|
selected := []*SelectedNode{}
|
2023-08-01 12:01:47 +01:00
|
|
|
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
|
|
|
|
}
|
2020-05-15 15:32:28 +01:00
|
|
|
}
|
|
|
|
if len(selected) >= n {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return selected
|
|
|
|
}
|