use communities pools
This commit is contained in:
parent
b10634d666
commit
6a45a4d961
@ -7,20 +7,22 @@ import (
|
|||||||
"github.com/alice-lg/alice-lg/pkg/api"
|
"github.com/alice-lg/alice-lg/pkg/api"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Communities is a pool for deduplicating a list of BGP communities
|
// CommunitiesPool is for deduplicating a list of BGP communities
|
||||||
// (Large and default. The ext communities representation right now
|
// (Large and default. The ext communities representation right now
|
||||||
// makes problems and need to be fixed. TODO.)
|
// makes problems and need to be fixed. TODO.)
|
||||||
type Communities struct {
|
type CommunitiesPool struct {
|
||||||
communities *IntList
|
communitiesRoot *Node
|
||||||
root *Node
|
root *Node
|
||||||
sync.Mutex
|
sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewCommunities creates a new pool for lists
|
// NewCommunitiesPool creates a new pool for lists
|
||||||
// of BGP communities.
|
// of BGP communities.
|
||||||
func NewCommunities() *Communities {
|
func NewCommunitiesPool() *CommunitiesPool {
|
||||||
return &Communities{
|
return &CommunitiesPool{
|
||||||
communities: NewIntList(),
|
communitiesRoot: &Node{
|
||||||
|
ptr: []int{},
|
||||||
|
},
|
||||||
root: &Node{
|
root: &Node{
|
||||||
ptr: []api.Community{},
|
ptr: []api.Community{},
|
||||||
},
|
},
|
||||||
@ -28,18 +30,19 @@ func NewCommunities() *Communities {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Acquire a list of bgp communities
|
// Acquire a list of bgp communities
|
||||||
func (p *Communities) Acquire(communities []api.Community) []api.Community {
|
func (p *CommunitiesPool) Acquire(communities []api.Community) []api.Community {
|
||||||
|
p.Lock()
|
||||||
|
defer p.Unlock()
|
||||||
|
// Make identification list by using the pointer address
|
||||||
|
// of the deduplicated community as ID
|
||||||
ids := make([]int, len(communities))
|
ids := make([]int, len(communities))
|
||||||
for i, comm := range communities {
|
for i, comm := range communities {
|
||||||
commPtr := p.communities.Acquire(comm)
|
commPtr := p.communitiesRoot.traverse(comm, comm)
|
||||||
addr := reflect.ValueOf(commPtr).UnsafePointer()
|
addr := reflect.ValueOf(commPtr).UnsafePointer()
|
||||||
ids[i] = int(uintptr(addr))
|
ids[i] = int(uintptr(addr))
|
||||||
}
|
}
|
||||||
p.Lock()
|
|
||||||
defer p.Unlock()
|
|
||||||
if len(ids) == 0 {
|
if len(ids) == 0 {
|
||||||
return p.root.ptr.([]api.Community)
|
return p.root.ptr.([]api.Community)
|
||||||
}
|
}
|
||||||
|
|
||||||
return p.root.traverse(communities, ids).([]api.Community)
|
return p.root.traverse(communities, ids).([]api.Community)
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@ func TestAcquireCommunities(t *testing.T) {
|
|||||||
{2341, 1, 1},
|
{2341, 1, 1},
|
||||||
}
|
}
|
||||||
|
|
||||||
p := NewCommunities()
|
p := NewCommunitiesPool()
|
||||||
|
|
||||||
pc1 := p.Acquire(c1)
|
pc1 := p.Acquire(c1)
|
||||||
pc2 := p.Acquire(c2)
|
pc2 := p.Acquire(c2)
|
||||||
|
@ -46,18 +46,18 @@ func (n *Node) traverse(list interface{}, tail []int) interface{} {
|
|||||||
return child.traverse(list, tail)
|
return child.traverse(list, tail)
|
||||||
}
|
}
|
||||||
|
|
||||||
// A IntList pool can be used to deduplicate
|
// A IntListPool can be used to deduplicate
|
||||||
// lists of integers. Like an AS path.
|
// lists of integers. Like an AS path or BGP communities.
|
||||||
//
|
//
|
||||||
// A Tree datastructure is used.
|
// A Tree datastructure is used.
|
||||||
type IntList struct {
|
type IntListPool struct {
|
||||||
root *Node
|
root *Node
|
||||||
sync.Mutex
|
sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewIntList creates a new int list pool
|
// NewIntListPool creates a new int list pool
|
||||||
func NewIntList() *IntList {
|
func NewIntListPool() *IntListPool {
|
||||||
return &IntList{
|
return &IntListPool{
|
||||||
root: &Node{
|
root: &Node{
|
||||||
ptr: []int{},
|
ptr: []int{},
|
||||||
},
|
},
|
||||||
@ -65,7 +65,7 @@ func NewIntList() *IntList {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Acquire int list from pool
|
// Acquire int list from pool
|
||||||
func (p *IntList) Acquire(list []int) []int {
|
func (p *IntListPool) Acquire(list []int) []int {
|
||||||
p.Lock()
|
p.Lock()
|
||||||
defer p.Unlock()
|
defer p.Unlock()
|
||||||
|
|
||||||
@ -75,19 +75,19 @@ func (p *IntList) Acquire(list []int) []int {
|
|||||||
return p.root.traverse(list, list).([]int)
|
return p.root.traverse(list, list).([]int)
|
||||||
}
|
}
|
||||||
|
|
||||||
// A StringList pool can be used for deduplicating lists
|
// A StringListPool can be used for deduplicating lists
|
||||||
// of strings. (This is a variant of an int list, as string
|
// of strings. (This is a variant of an int list, as string
|
||||||
// values are converted to int.
|
// values are converted to int.
|
||||||
type StringList struct {
|
type StringListPool struct {
|
||||||
root *Node
|
root *Node
|
||||||
values map[string]int
|
values map[string]int
|
||||||
head int
|
head int
|
||||||
sync.Mutex
|
sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewStringList creates a new string list.
|
// NewStringListPool creates a new string list.
|
||||||
func NewStringList() *StringList {
|
func NewStringListPool() *StringListPool {
|
||||||
return &StringList{
|
return &StringListPool{
|
||||||
head: 1,
|
head: 1,
|
||||||
values: map[string]int{},
|
values: map[string]int{},
|
||||||
root: &Node{
|
root: &Node{
|
||||||
@ -97,7 +97,7 @@ func NewStringList() *StringList {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Acquire the string list pointer from the pool
|
// Acquire the string list pointer from the pool
|
||||||
func (p *StringList) Acquire(list []string) []string {
|
func (p *StringListPool) Acquire(list []string) []string {
|
||||||
if len(list) == 0 {
|
if len(list) == 0 {
|
||||||
return p.root.ptr.([]string) // root
|
return p.root.ptr.([]string) // root
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@ func TestAcquireIntList(t *testing.T) {
|
|||||||
b := []int{23, 42, 1337, 65535, 1}
|
b := []int{23, 42, 1337, 65535, 1}
|
||||||
c := []int{23, 42, 1338, 65535, 2}
|
c := []int{23, 42, 1338, 65535, 2}
|
||||||
|
|
||||||
p := NewIntList()
|
p := NewIntListPool()
|
||||||
|
|
||||||
r1 := p.Acquire(a)
|
r1 := p.Acquire(a)
|
||||||
p.Acquire(c)
|
p.Acquire(c)
|
||||||
@ -49,7 +49,7 @@ func TestAcquireStringList(t *testing.T) {
|
|||||||
w := []string{"foo", "bar", "bgp"}
|
w := []string{"foo", "bar", "bgp"}
|
||||||
e := []string{"foo", "bpf"}
|
e := []string{"foo", "bpf"}
|
||||||
|
|
||||||
p2 := NewStringList()
|
p2 := NewStringListPool()
|
||||||
x1 := p2.Acquire(q)
|
x1 := p2.Acquire(q)
|
||||||
x2 := p2.Acquire(w)
|
x2 := p2.Acquire(w)
|
||||||
x3 := p2.Acquire(e)
|
x3 := p2.Acquire(e)
|
||||||
|
@ -8,43 +8,51 @@ import "log"
|
|||||||
// and are defined per intended usage
|
// and are defined per intended usage
|
||||||
|
|
||||||
// Neighbors stores neighbor IDs
|
// Neighbors stores neighbor IDs
|
||||||
var Neighbors *String
|
var Neighbors *StringPool
|
||||||
|
|
||||||
// Networks4 stores network ip v4 addresses
|
// Networks4 stores network ip v4 addresses
|
||||||
var Networks4 *String
|
var Networks4 *StringPool
|
||||||
|
|
||||||
// Networks6 stores network ip v6 addresses
|
// Networks6 stores network ip v6 addresses
|
||||||
var Networks6 *String
|
var Networks6 *StringPool
|
||||||
|
|
||||||
// Interfaces stores interfaces like: eth0, bond0 etc...
|
// Interfaces stores interfaces like: eth0, bond0 etc...
|
||||||
var Interfaces *String
|
var Interfaces *StringPool
|
||||||
|
|
||||||
// Gateways4 store ip v4 gateway addresses
|
// Gateways4 store ip v4 gateway addresses
|
||||||
var Gateways4 *String
|
var Gateways4 *StringPool
|
||||||
|
|
||||||
// Gateways6 store ip v6 gateway addresses
|
// Gateways6 store ip v6 gateway addresses
|
||||||
var Gateways6 *String
|
var Gateways6 *StringPool
|
||||||
|
|
||||||
// Origins is a store for 'IGP'
|
// Origins is a store for 'IGP'
|
||||||
var Origins *String
|
var Origins *StringPool
|
||||||
|
|
||||||
// ASPaths stores lists of ASNs
|
// ASPaths stores lists of ASNs
|
||||||
var ASPaths *IntList
|
var ASPaths *IntListPool
|
||||||
|
|
||||||
// Types stores a list of types (['BGP', 'univ'])
|
// Types stores a list of types (['BGP', 'univ'])
|
||||||
var Types *StringList
|
var Types *StringListPool
|
||||||
|
|
||||||
|
// Communities store a list of BGP communities
|
||||||
|
var Communities *CommunitiesPool
|
||||||
|
|
||||||
|
// LargeCommunities store a list of large BGP communities
|
||||||
|
var LargeCommunities *CommunitiesPool
|
||||||
|
|
||||||
// Initialize global pools
|
// Initialize global pools
|
||||||
func init() {
|
func init() {
|
||||||
log.Println("initializing memory pools")
|
log.Println("initializing memory pools")
|
||||||
|
|
||||||
Neighbors = NewString()
|
Neighbors = NewStringPool()
|
||||||
Networks4 = NewString()
|
Networks4 = NewStringPool()
|
||||||
Networks6 = NewString()
|
Networks6 = NewStringPool()
|
||||||
Interfaces = NewString()
|
Interfaces = NewStringPool()
|
||||||
Gateways4 = NewString()
|
Gateways4 = NewStringPool()
|
||||||
Gateways6 = NewString()
|
Gateways6 = NewStringPool()
|
||||||
Origins = NewString()
|
Origins = NewStringPool()
|
||||||
ASPaths = NewIntList()
|
ASPaths = NewIntListPool()
|
||||||
Types = NewStringList()
|
Types = NewStringListPool()
|
||||||
|
Communities = NewCommunitiesPool()
|
||||||
|
LargeCommunities = NewCommunitiesPool()
|
||||||
}
|
}
|
||||||
|
@ -2,9 +2,9 @@ package pools
|
|||||||
|
|
||||||
import "sync"
|
import "sync"
|
||||||
|
|
||||||
// String is a pool for strings.
|
// StringPool is a pool for strings.
|
||||||
// This will most likely be a pool for IP addresses.
|
// This will most likely be a pool for IP addresses.
|
||||||
type String struct {
|
type StringPool struct {
|
||||||
values map[string]*string
|
values map[string]*string
|
||||||
|
|
||||||
counter map[string]uint
|
counter map[string]uint
|
||||||
@ -13,16 +13,16 @@ type String struct {
|
|||||||
sync.Mutex
|
sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewString creates a new string pool
|
// NewStringPool creates a new string pool
|
||||||
func NewString() *String {
|
func NewStringPool() *StringPool {
|
||||||
return &String{
|
return &StringPool{
|
||||||
values: map[string]*string{},
|
values: map[string]*string{},
|
||||||
counter: map[string]uint{},
|
counter: map[string]uint{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Acquire a pointer to a string value
|
// Acquire a pointer to a string value
|
||||||
func (p *String) Acquire(s string) *string {
|
func (p *StringPool) Acquire(s string) *string {
|
||||||
p.Lock()
|
p.Lock()
|
||||||
defer p.Unlock()
|
defer p.Unlock()
|
||||||
// Deduplicate value
|
// Deduplicate value
|
||||||
@ -37,7 +37,7 @@ func (p *String) Acquire(s string) *string {
|
|||||||
|
|
||||||
// GarbageCollect releases all values, which have not been seen
|
// GarbageCollect releases all values, which have not been seen
|
||||||
// again.
|
// again.
|
||||||
func (p *String) GarbageCollect() uint {
|
func (p *StringPool) GarbageCollect() uint {
|
||||||
p.Lock()
|
p.Lock()
|
||||||
defer p.Unlock()
|
defer p.Unlock()
|
||||||
var released uint = 0
|
var released uint = 0
|
||||||
|
@ -6,7 +6,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestAcquireString(t *testing.T) {
|
func TestAcquireString(t *testing.T) {
|
||||||
p := NewString()
|
p := NewStringPool()
|
||||||
s1 := p.Acquire("hello")
|
s1 := p.Acquire("hello")
|
||||||
s2 := p.Acquire("hello")
|
s2 := p.Acquire("hello")
|
||||||
s3 := p.Acquire("world")
|
s3 := p.Acquire("world")
|
||||||
@ -24,7 +24,7 @@ func TestAcquireString(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestGarbageCollectString(t *testing.T) {
|
func TestGarbageCollectString(t *testing.T) {
|
||||||
p := NewString()
|
p := NewStringPool()
|
||||||
|
|
||||||
// Gen 1
|
// Gen 1
|
||||||
p.Acquire("hello")
|
p.Acquire("hello")
|
||||||
|
@ -247,6 +247,13 @@ func parseRouteBgpInfo(data interface{}) *api.BGPInfo {
|
|||||||
localPref, _ := strconv.Atoi(decoders.String(bgpData["local_pref"], "0"))
|
localPref, _ := strconv.Atoi(decoders.String(bgpData["local_pref"], "0"))
|
||||||
med, _ := strconv.Atoi(decoders.String(bgpData["med"], "0"))
|
med, _ := strconv.Atoi(decoders.String(bgpData["med"], "0"))
|
||||||
|
|
||||||
|
// Testing and benchmarks show: Deduplicating communities has
|
||||||
|
// quite a performance impact:
|
||||||
|
// Without using pools, parsing 600000 routes
|
||||||
|
// takes roughly 16 seconds, with pools for strings
|
||||||
|
// and AS paths: 18 seconds.
|
||||||
|
// With communities: 46 seconds. This is quite long.
|
||||||
|
|
||||||
bgp := &api.BGPInfo{
|
bgp := &api.BGPInfo{
|
||||||
Origin: pools.Origins.Acquire(
|
Origin: pools.Origins.Acquire(
|
||||||
decoders.String(bgpData["origin"], "unknown")),
|
decoders.String(bgpData["origin"], "unknown")),
|
||||||
@ -255,9 +262,9 @@ func parseRouteBgpInfo(data interface{}) *api.BGPInfo {
|
|||||||
decoders.String(bgpData["next_hop"], "unknown")),
|
decoders.String(bgpData["next_hop"], "unknown")),
|
||||||
LocalPref: localPref,
|
LocalPref: localPref,
|
||||||
Med: med,
|
Med: med,
|
||||||
Communities: communities,
|
Communities: pools.Communities.Acquire(communities),
|
||||||
ExtCommunities: extCommunities,
|
ExtCommunities: extCommunities,
|
||||||
LargeCommunities: largeCommunities,
|
LargeCommunities: pools.LargeCommunities.Acquire(largeCommunities),
|
||||||
}
|
}
|
||||||
return bgp
|
return bgp
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user