satellite/nodeselection: remove AutoExcludeSubnet filter

It's statefull, therefore it can hit naive users. (NodeFilters couldn't be reused for more than one iterations).

But looks like we don't need it, as `SelectBySubnet` doest the same job.

Change-Id: Ie85b7f9c2bd9a47293f4e3b359f8b619215c7649
This commit is contained in:
Márton Elek 2023-08-17 11:53:05 +02:00 committed by Elek, Márton
parent db13e3ef15
commit 5522423871
6 changed files with 55 additions and 80 deletions

View File

@ -45,6 +45,13 @@ func GetAnnotation(filter NodeFilter, name string) string {
if annotated, ok := filter.(AnnotatedNodeFilter); ok { if annotated, ok := filter.(AnnotatedNodeFilter); ok {
return annotated.Annotations[name] return annotated.Annotations[name]
} }
if filters, ok := filter.(NodeFilters); ok {
for _, filter := range filters {
if annotated, ok := filter.(AnnotatedNodeFilter); ok {
return annotated.Annotations[name]
}
}
}
return "" return ""
} }
@ -82,11 +89,6 @@ func (n NodeFilters) WithCountryFilter(permit location.Set) NodeFilters {
return append(n, NewCountryFilter(permit)) return append(n, NewCountryFilter(permit))
} }
// WithAutoExcludeSubnets is a helper to create a new filter with additional AutoExcludeSubnets.
func (n NodeFilters) WithAutoExcludeSubnets() NodeFilters {
return append(n, NewAutoExcludeSubnets())
}
// WithExcludedIDs is a helper to create a new filter with additional WithExcludedIDs. // WithExcludedIDs is a helper to create a new filter with additional WithExcludedIDs.
func (n NodeFilters) WithExcludedIDs(ds []storj.NodeID) NodeFilters { func (n NodeFilters) WithExcludedIDs(ds []storj.NodeID) NodeFilters {
return append(n, ExcludedIDs(ds)) return append(n, ExcludedIDs(ds))
@ -113,32 +115,6 @@ func (p *CountryFilter) MatchInclude(node *SelectedNode) bool {
var _ NodeFilter = &CountryFilter{} var _ NodeFilter = &CountryFilter{}
// AutoExcludeSubnets pick at most one node from network.
//
// Stateful!!! should be re-created for each new selection request.
// It should only be used as the last filter.
type AutoExcludeSubnets struct {
seenSubnets map[string]struct{}
}
// NewAutoExcludeSubnets creates an initialized AutoExcludeSubnets.
func NewAutoExcludeSubnets() *AutoExcludeSubnets {
return &AutoExcludeSubnets{
seenSubnets: map[string]struct{}{},
}
}
// MatchInclude implements NodeFilter interface.
func (a *AutoExcludeSubnets) MatchInclude(node *SelectedNode) bool {
if _, found := a.seenSubnets[node.LastNet]; found {
return false
}
a.seenSubnets[node.LastNet] = struct{}{}
return true
}
var _ NodeFilter = &AutoExcludeSubnets{}
// ExcludedNetworks will exclude nodes with specified networks. // ExcludedNetworks will exclude nodes with specified networks.
type ExcludedNetworks []string type ExcludedNetworks []string
@ -154,6 +130,21 @@ func (e ExcludedNetworks) MatchInclude(node *SelectedNode) bool {
var _ NodeFilter = ExcludedNetworks{} var _ NodeFilter = ExcludedNetworks{}
// ExcludedNodeNetworks exclude nodes which has same net as the one of the specified.
type ExcludedNodeNetworks []*SelectedNode
// MatchInclude implements NodeFilter interface.
func (e ExcludedNodeNetworks) MatchInclude(node *SelectedNode) bool {
for _, n := range e {
if node.LastNet == n.LastNet {
return false
}
}
return true
}
var _ NodeFilter = ExcludedNodeNetworks{}
// ExcludedIDs can blacklist NodeIDs. // ExcludedIDs can blacklist NodeIDs.
type ExcludedIDs []storj.NodeID type ExcludedIDs []storj.NodeID

View File

@ -17,23 +17,6 @@ import (
"storj.io/common/testrand" "storj.io/common/testrand"
) )
func TestNodeFilter_AutoExcludeSubnet(t *testing.T) {
criteria := NodeFilters{}.WithAutoExcludeSubnets()
assert.True(t, criteria.MatchInclude(&SelectedNode{
LastNet: "192.168.0.1",
}))
assert.False(t, criteria.MatchInclude(&SelectedNode{
LastNet: "192.168.0.1",
}))
assert.True(t, criteria.MatchInclude(&SelectedNode{
LastNet: "192.168.1.1",
}))
}
func TestCriteria_ExcludeNodeID(t *testing.T) { func TestCriteria_ExcludeNodeID(t *testing.T) {
included := testrand.NodeID() included := testrand.NodeID()
excluded := testrand.NodeID() excluded := testrand.NodeID()
@ -47,29 +30,29 @@ func TestCriteria_ExcludeNodeID(t *testing.T) {
assert.True(t, criteria.MatchInclude(&SelectedNode{ assert.True(t, criteria.MatchInclude(&SelectedNode{
ID: included, ID: included,
})) }))
} }
func TestCriteria_NodeIDAndSubnet(t *testing.T) { func TestCriteria_ExcludedNodeNetworks(t *testing.T) {
excluded := testrand.NodeID() criteria := NodeFilters{}
criteria = append(criteria, ExcludedNodeNetworks{
&SelectedNode{
LastNet: "192.168.1.0",
}, &SelectedNode{
LastNet: "192.168.2.0",
},
})
criteria := NodeFilters{}.
WithExcludedIDs([]storj.NodeID{excluded}).
WithAutoExcludeSubnets()
// due to node id criteria
assert.False(t, criteria.MatchInclude(&SelectedNode{ assert.False(t, criteria.MatchInclude(&SelectedNode{
ID: excluded, LastNet: "192.168.1.0",
LastNet: "192.168.0.1", }))
assert.False(t, criteria.MatchInclude(&SelectedNode{
LastNet: "192.168.2.0",
})) }))
// should be included as previous one excluded and
// not stored for subnet exclusion
assert.True(t, criteria.MatchInclude(&SelectedNode{ assert.True(t, criteria.MatchInclude(&SelectedNode{
ID: testrand.NodeID(), LastNet: "192.168.3.0",
LastNet: "192.168.0.2",
})) }))
} }
func TestCriteria_Geofencing(t *testing.T) { func TestCriteria_Geofencing(t *testing.T) {
@ -135,7 +118,6 @@ func BenchmarkNodeFilterFullTable(b *testing.B) {
filters = append(filters, NodeFilterFunc(func(node *SelectedNode) bool { filters = append(filters, NodeFilterFunc(func(node *SelectedNode) bool {
return true return true
})) }))
filters = filters.WithAutoExcludeSubnets()
benchmarkFilter(b, filters) benchmarkFilter(b, filters)
} }

View File

@ -248,12 +248,9 @@ func TestSelectFiltered(t *testing.T) {
selector := nodeselection.SelectByID(nodes) selector := nodeselection.SelectByID(nodes)
assert.Len(t, selector.Select(3, nodeselection.NodeFilters{}), 3) assert.Len(t, selector.Select(3, nodeselection.NodeFilters{}), 3)
assert.Len(t, selector.Select(3, nodeselection.NodeFilters{}.WithAutoExcludeSubnets()), 2)
assert.Len(t, selector.Select(3, nodeselection.NodeFilters{}), 3) assert.Len(t, selector.Select(3, nodeselection.NodeFilters{}), 3)
assert.Len(t, selector.Select(3, nodeselection.NodeFilters{}.WithExcludedIDs([]storj.NodeID{firstID, secondID})), 1) assert.Len(t, selector.Select(3, nodeselection.NodeFilters{}.WithExcludedIDs([]storj.NodeID{firstID, secondID})), 1)
assert.Len(t, selector.Select(3, nodeselection.NodeFilters{}.WithAutoExcludeSubnets()), 2)
assert.Len(t, selector.Select(3, nodeselection.NodeFilters{}.WithExcludedIDs([]storj.NodeID{thirdID}).WithAutoExcludeSubnets()), 1)
} }
func TestSelectFilteredMulti(t *testing.T) { func TestSelectFilteredMulti(t *testing.T) {

View File

@ -12,6 +12,14 @@ import (
"storj.io/common/storj" "storj.io/common/storj"
) )
const (
// AutoExcludeSubnet is placement annotation key to turn off subnet restrictions.
AutoExcludeSubnet = "autoExcludeSubnet"
// AutoExcludeSubnetOFF is the value of AutoExcludeSubnet to disable subnet restrictions.
AutoExcludeSubnetOFF = "off"
)
// ErrNotEnoughNodes is when selecting nodes failed with the given parameters. // ErrNotEnoughNodes is when selecting nodes failed with the given parameters.
var ErrNotEnoughNodes = errs.Class("not enough nodes") var ErrNotEnoughNodes = errs.Class("not enough nodes")
@ -114,8 +122,13 @@ func (state *State) Select(ctx context.Context, request Request) (_ []*SelectedN
// Get all the remaining reputable nodes. // Get all the remaining reputable nodes.
reputableCount := totalCount - len(selected) reputableCount := totalCount - len(selected)
selected = append(selected,
reputableNodes.Select(reputableCount, request.NodeFilters)...) filters := request.NodeFilters
if GetAnnotation(filters, AutoExcludeSubnet) != AutoExcludeSubnetOFF {
filters = append(append(NodeFilters{}, request.NodeFilters...), ExcludedNodeNetworks(selected))
}
selected = append(selected, reputableNodes.Select(reputableCount, filters)...)
if len(selected) < totalCount { if len(selected) < totalCount {
return selected, ErrNotEnoughNodes.New("requested from cache %d, found %d", totalCount, len(selected)) return selected, ErrNotEnoughNodes.New("requested from cache %d, found %d", totalCount, len(selected))

View File

@ -13,14 +13,6 @@ import (
"storj.io/storj/satellite/nodeselection" "storj.io/storj/satellite/nodeselection"
) )
const (
// AutoExcludeSubnet is placement annotation key to turn off subnet restrictions.
AutoExcludeSubnet = "autoExcludeSubnet"
// AutoExcludeSubnetOFF is the value of AutoExcludeSubnet to disable subnet restrictions.
AutoExcludeSubnetOFF = "off"
)
// UploadSelectionDB implements the database for upload selection cache. // UploadSelectionDB implements the database for upload selection cache.
// //
// architecture: Database // architecture: Database
@ -105,7 +97,7 @@ func (cache *UploadSelectionCache) GetNodes(ctx context.Context, req FindStorage
} }
placementRules := cache.placementRules(req.Placement) placementRules := cache.placementRules(req.Placement)
useSubnetExclusion := nodeselection.GetAnnotation(placementRules, AutoExcludeSubnet) != AutoExcludeSubnetOFF useSubnetExclusion := nodeselection.GetAnnotation(placementRules, nodeselection.AutoExcludeSubnet) != nodeselection.AutoExcludeSubnetOFF
filters := nodeselection.NodeFilters{placementRules} filters := nodeselection.NodeFilters{placementRules}
if len(req.ExcludedIDs) > 0 { if len(req.ExcludedIDs) > 0 {

View File

@ -215,7 +215,7 @@ func TestGetNodes(t *testing.T) {
} }
placementRules := overlay.NewPlacementRules() placementRules := overlay.NewPlacementRules()
placementRules.AddPlacementRule(storj.PlacementConstraint(5), nodeselection.NodeFilters{}.WithCountryFilter(location.NewSet(location.Germany))) placementRules.AddPlacementRule(storj.PlacementConstraint(5), nodeselection.NodeFilters{}.WithCountryFilter(location.NewSet(location.Germany)))
placementRules.AddPlacementRule(storj.PlacementConstraint(6), nodeselection.WithAnnotation(nodeselection.NodeFilters{}.WithCountryFilter(location.NewSet(location.Germany)), overlay.AutoExcludeSubnet, overlay.AutoExcludeSubnetOFF)) placementRules.AddPlacementRule(storj.PlacementConstraint(6), nodeselection.WithAnnotation(nodeselection.NodeFilters{}.WithCountryFilter(location.NewSet(location.Germany)), nodeselection.AutoExcludeSubnet, nodeselection.AutoExcludeSubnetOFF))
cache, err := overlay.NewUploadSelectionCache(zap.NewNop(), cache, err := overlay.NewUploadSelectionCache(zap.NewNop(),
db.OverlayCache(), db.OverlayCache(),
@ -526,7 +526,7 @@ func TestGetNodesDistinct(t *testing.T) {
&mockDB, &mockDB,
highStaleness, highStaleness,
config, config,
nodeselection.NodeFilters{}.WithAutoExcludeSubnets(), nodeselection.NodeFilters{},
overlay.NewPlacementRules().CreateFilters, overlay.NewPlacementRules().CreateFilters,
) )
require.NoError(t, err) require.NoError(t, err)