improved add filter performance

This commit is contained in:
Annika Hannig 2022-11-25 15:38:38 +01:00
parent cbdc1f5d67
commit bf95c539ce
3 changed files with 57 additions and 25 deletions

View File

@ -1,7 +1,7 @@
package api package api
import ( import (
"fmt" "strconv"
"time" "time"
) )
@ -163,20 +163,26 @@ type RouteServersResponse struct {
type Community []int type Community []int
func (com Community) String() string { func (com Community) String() string {
res := ""
if len(com) < 1 { if len(com) < 1 {
return "" return ""
} }
for _, v := range com { s := ""
res += fmt.Sprintf(":%d", v) for i, v := range com {
if i > 0 {
s += ":"
}
s += strconv.Itoa(v)
} }
return res[1:] return s
} }
// Communities is a collection of bgp communities // Communities is a collection of bgp communities
type Communities []Community type Communities []Community
// Unique deduplicates communities // Unique deduplicates communities.
/*
We can skip this. Worst case is, that the
cardinality is off.
func (communities Communities) Unique() Communities { func (communities Communities) Unique() Communities {
seen := map[string]bool{} seen := map[string]bool{}
result := make(Communities, 0, len(communities)) result := make(Communities, 0, len(communities))
@ -192,25 +198,34 @@ func (communities Communities) Unique() Communities {
return result return result
} }
*/
// ExtCommunity is a BGP extended community // ExtCommunity is a BGP extended community
type ExtCommunity []interface{} type ExtCommunity []interface{}
func (com ExtCommunity) String() string { func (com ExtCommunity) String() string {
res := ""
if len(com) < 1 { if len(com) < 1 {
return "" return ""
} }
for _, v := range com { res := ""
res += fmt.Sprintf(":%v", v) for i, v := range com {
if i == 0 {
res += v.(string)
continue
}
if i > 0 {
res += ":"
}
res += strconv.Itoa(v.(int))
} }
return res[1:] return res
} }
// ExtCommunities is a collection of extended bgp communities. // ExtCommunities is a collection of extended bgp communities.
type ExtCommunities []ExtCommunity type ExtCommunities []ExtCommunity
// Unique deduplicates extended communities. // Unique deduplicates extended communities.
/*
func (communities ExtCommunities) Unique() ExtCommunities { func (communities ExtCommunities) Unique() ExtCommunities {
seen := map[string]bool{} seen := map[string]bool{}
result := make(ExtCommunities, 0, len(communities)) result := make(ExtCommunities, 0, len(communities))
@ -226,6 +241,7 @@ func (communities ExtCommunities) Unique() ExtCommunities {
return result return result
} }
*/
// BGPInfo is a set of BGP attributes // BGPInfo is a set of BGP attributes
type BGPInfo struct { type BGPInfo struct {

View File

@ -74,7 +74,7 @@ func TestCommunityStringify(t *testing.T) {
t.Error("Expected 23:42, got:", com.String()) t.Error("Expected 23:42, got:", com.String())
} }
extCom := ExtCommunity{"ro", "42", "123"} extCom := ExtCommunity{"ro", 42, 123}
if extCom.String() != "ro:42:123" { if extCom.String() != "ro:42:123" {
t.Error("Expected ro:42:123, but got:", extCom.String()) t.Error("Expected ro:42:123, but got:", extCom.String())
} }
@ -134,6 +134,7 @@ func TestHasCommunity(t *testing.T) {
} }
} }
/*
func TestUniqueCommunities(t *testing.T) { func TestUniqueCommunities(t *testing.T) {
all := Communities{Community{23, 42}, Community{42, 123}, Community{23, 42}} all := Communities{Community{23, 42}, Community{42, 123}, Community{23, 42}}
unique := all.Unique() unique := all.Unique()
@ -154,3 +155,4 @@ func TestUniqueExtCommunities(t *testing.T) {
} }
t.Log("All:", all, "Unique:", unique) t.Log("All:", all, "Unique:", unique)
} }
*/

View File

@ -1,7 +1,6 @@
package api package api
import ( import (
"fmt"
"log" "log"
"net/url" "net/url"
"strconv" "strconv"
@ -131,14 +130,27 @@ func (g *SearchFilterGroup) Contains(filter *SearchFilter) bool {
return g.FindFilter(filter) != nil return g.FindFilter(filter) != nil
} }
// filterValueAsString gets the string representation
// from a filter value
func filterValueAsString(value interface{}) string {
switch v := value.(type) {
case int:
return strconv.Itoa(v)
case string:
return v
case Community:
return v.String()
case ExtCommunity:
return v.String()
}
panic("unexpected filter value")
}
// GetFilterByValue retrieves a filter by matching // GetFilterByValue retrieves a filter by matching
// a string representation of it's filter value. // a string representation of it's filter value.
func (g *SearchFilterGroup) GetFilterByValue(value interface{}) *SearchFilter { func (g *SearchFilterGroup) GetFilterByValue(value interface{}) *SearchFilter {
// I've tried it with .(fmt.Stringer), but int does not implement this... ref := filterValueAsString(value)
// So whatever. I'm using the trick of letting Sprintf choose the right idx, ok := g.filtersIdx[ref]
// conversion. If this is too expensive, we need to refactor this.
// TODO: profile this.
idx, ok := g.filtersIdx[fmt.Sprintf("%v", value)]
if !ok { if !ok {
return nil // We don't have this particular filter return nil // We don't have this particular filter
} }
@ -158,7 +170,8 @@ func (g *SearchFilterGroup) AddFilter(filter *SearchFilter) {
idx := len(g.Filters) idx := len(g.Filters)
filter.Cardinality = 1 filter.Cardinality = 1
g.Filters = append(g.Filters, filter) g.Filters = append(g.Filters, filter)
g.filtersIdx[fmt.Sprintf("%v", filter.Value)] = idx ref := filterValueAsString(filter.Value)
g.filtersIdx[ref] = idx
} }
// AddFilters adds a list of filters to a group. // AddFilters adds a list of filters to a group.
@ -172,7 +185,8 @@ func (g *SearchFilterGroup) AddFilters(filters []*SearchFilter) {
func (g *SearchFilterGroup) rebuildIndex() { func (g *SearchFilterGroup) rebuildIndex() {
idx := make(map[string]int) idx := make(map[string]int)
for i, filter := range g.Filters { for i, filter := range g.Filters {
idx[fmt.Sprintf("%v", filter.Value)] = i ref := filterValueAsString(filter.Value)
idx[ref] = i
} }
g.filtersIdx = idx // replace index g.filtersIdx = idx // replace index
} }
@ -368,21 +382,21 @@ func (s *SearchFilters) UpdateFromLookupRoute(r *LookupRoute) {
// Add communities // Add communities
communities := s.GetGroupByKey(SearchKeyCommunities) communities := s.GetGroupByKey(SearchKeyCommunities)
for _, c := range r.Route.BGP.Communities.Unique() { for _, c := range r.Route.BGP.Communities {
communities.AddFilter(&SearchFilter{ communities.AddFilter(&SearchFilter{
Name: c.String(), Name: c.String(),
Value: c, Value: c,
}) })
} }
extCommunities := s.GetGroupByKey(SearchKeyExtCommunities) extCommunities := s.GetGroupByKey(SearchKeyExtCommunities)
for _, c := range r.Route.BGP.ExtCommunities.Unique() { for _, c := range r.Route.BGP.ExtCommunities {
extCommunities.AddFilter(&SearchFilter{ extCommunities.AddFilter(&SearchFilter{
Name: c.String(), Name: c.String(),
Value: c, Value: c,
}) })
} }
largeCommunities := s.GetGroupByKey(SearchKeyLargeCommunities) largeCommunities := s.GetGroupByKey(SearchKeyLargeCommunities)
for _, c := range r.Route.BGP.LargeCommunities.Unique() { for _, c := range r.Route.BGP.LargeCommunities {
largeCommunities.AddFilter(&SearchFilter{ largeCommunities.AddFilter(&SearchFilter{
Name: c.String(), Name: c.String(),
Value: c, Value: c,
@ -398,21 +412,21 @@ func (s *SearchFilters) UpdateFromRoute(r *Route) {
// Add communities // Add communities
communities := s.GetGroupByKey(SearchKeyCommunities) communities := s.GetGroupByKey(SearchKeyCommunities)
for _, c := range r.BGP.Communities.Unique() { for _, c := range r.BGP.Communities {
communities.AddFilter(&SearchFilter{ communities.AddFilter(&SearchFilter{
Name: c.String(), Name: c.String(),
Value: c, Value: c,
}) })
} }
extCommunities := s.GetGroupByKey(SearchKeyExtCommunities) extCommunities := s.GetGroupByKey(SearchKeyExtCommunities)
for _, c := range r.BGP.ExtCommunities.Unique() { for _, c := range r.BGP.ExtCommunities {
extCommunities.AddFilter(&SearchFilter{ extCommunities.AddFilter(&SearchFilter{
Name: c.String(), Name: c.String(),
Value: c, Value: c,
}) })
} }
largeCommunities := s.GetGroupByKey(SearchKeyLargeCommunities) largeCommunities := s.GetGroupByKey(SearchKeyLargeCommunities)
for _, c := range r.BGP.LargeCommunities.Unique() { for _, c := range r.BGP.LargeCommunities {
largeCommunities.AddFilter(&SearchFilter{ largeCommunities.AddFilter(&SearchFilter{
Name: c.String(), Name: c.String(),
Value: c, Value: c,