added string and int lists

This commit is contained in:
Annika Hannig 2022-11-15 15:36:14 +01:00
parent 9622f5745b
commit 9da371065d
5 changed files with 138 additions and 140 deletions

View File

@ -8,18 +8,18 @@ import (
// Route is a prefix with BGP information.
type Route struct {
ID string `json:"id"`
NeighborID string `json:"neighbor_id"`
ID string `json:"id"`
NeighborID *string `json:"neighbor_id"`
Network string `json:"network"`
Interface string `json:"interface"`
Gateway string `json:"gateway"`
Network *string `json:"network"`
Interface *string `json:"interface"`
Gateway *string `json:"gateway"`
Metric int `json:"metric"`
BGP *BGPInfo `json:"bgp"`
Age time.Duration `json:"age"`
Type []string `json:"type"` // [BGP, unicast, univ]
Primary bool `json:"primary"`
LearntFrom string `json:"learnt_from"`
LearntFrom *string `json:"learnt_from"`
Details *json.RawMessage `json:"details"`
}

View File

@ -1,93 +0,0 @@
package pools
import (
"sync"
)
// IntNode is a node in the tree.
type IntNode struct {
children []*IntNode
value int
counter int
ptr []int
}
// Internally acquire list by traversing the tree and
// creating nodes if required.
func (n *IntNode) traverse(list, tail []int) []int {
head := tail[0]
tail = tail[1:]
// Seek for value in children
var child *IntNode
for _, c := range n.children {
if c.value == head {
child = c
}
}
if child == nil {
// Insert child
child = &IntNode{
children: []*IntNode{},
value: head,
ptr: nil,
}
n.children = append(n.children, child)
}
// Set list ptr if required
if len(tail) == 0 {
if child.ptr == nil {
child.ptr = list
}
return child.ptr
}
return child.traverse(list, tail)
}
// IntTree is a tree structure for deduplicating
// lists of integers.
type IntTree struct {
root *IntNode
}
// NewIntTree initializes an empty int tree
func NewIntTree() *IntTree {
return &IntTree{
root: &IntNode{
ptr: []int{},
},
}
}
// Acquire int list element
func (t *IntTree) Acquire(list []int) []int {
if len(list) == 0 {
return t.root.ptr // root
}
return t.root.traverse(list, list)
}
// A IntList pool can be used to deduplicate
// lists of integers. Like an AS path.
//
// A Tree datastructure is used.
type IntList struct {
values *IntTree
sync.Mutex
}
// NewIntList creates a new int list pool
func NewIntList() *IntList {
return &IntList{
values: NewIntTree(),
}
}
// Acquire int list from pool
func (p *IntList) Acquire(list []int) []int {
p.Lock()
defer p.Unlock()
return p.values.Acquire(list)
}

View File

@ -1,41 +0,0 @@
package pools
import (
"reflect"
"sync"
)
// A IntListList pool can be used to deduplicate
// lists of lists of integers. Like a list of large
// BGP communities.
//
// A Tree datastructure is used.
type IntListList struct {
lists *IntTree
ptrs *IntTree
sync.Mutex
}
// NewIntListList creates a new int list pool
func NewIntListList() *IntListList {
return &IntListList{
lists: NewIntTree(),
ptrs: NewIntTree(),
}
}
// Acquire int list from pool
func (p *IntListList) Acquire(list [][]int) [][]int {
p.Lock()
defer p.Unlock()
// Convert list of list to list of ptrs
ptrList := make([]int, len(list))
for i, v := range list {
ptr := p.ptrs.Acquire(v)
ptrV := int(uintptr(reflect.ValueOf(ptr).UnsafePointer()))
ptrList[i] = ptrV
}
return []int{}
}

119
pkg/store/pools/lists.go Normal file
View File

@ -0,0 +1,119 @@
package pools
import (
"sync"
)
// Node is a node in the tree.
type Node struct {
children []*Node
value int
counter int
ptr interface{}
}
// Internally acquire list by traversing the tree and
// creating nodes if required.
func (n *Node) traverse(list interface{}, tail []int) interface{} {
head := tail[0]
tail = tail[1:]
// Seek for value in children
var child *Node
for _, c := range n.children {
if c.value == head {
child = c
}
}
if child == nil {
// Insert child
child = &Node{
children: []*Node{},
value: head,
ptr: nil,
}
n.children = append(n.children, child)
}
// Set list ptr if required
if len(tail) == 0 {
if child.ptr == nil {
child.ptr = list
}
return child.ptr
}
return child.traverse(list, tail)
}
// A IntList pool can be used to deduplicate
// lists of integers. Like an AS path.
//
// A Tree datastructure is used.
type IntList struct {
root *Node
sync.Mutex
}
// NewIntList creates a new int list pool
func NewIntList() *IntList {
return &IntList{
root: &Node{
ptr: []int{},
},
}
}
// Acquire int list from pool
func (p *IntList) Acquire(list []int) []int {
p.Lock()
defer p.Unlock()
if len(list) == 0 {
return p.root.ptr.([]int) // root
}
return p.root.traverse(list, list).([]int)
}
// A StringList pool can be used for deduplicating lists
// of strings. (This is a variant of an int list, as string
// values are converted to int.
type StringList struct {
root *Node
values map[string]int
head int
sync.Mutex
}
// NewStringList creates a new string list.
func NewStringList() *StringList {
return &StringList{
head: 1,
values: map[string]int{},
root: &Node{
ptr: []string{},
},
}
}
// Acquire the string list pointer from the pool
func (p *StringList) Acquire(list []string) []string {
if len(list) == 0 {
return p.root.ptr.([]string) // root
}
// Make idenfier list
id := make([]int, len(list))
for i, s := range list {
// Resolve string value into int
v, ok := p.values[s]
if !ok {
p.head++
p.values[s] = p.head
v = p.head
}
id[i] = v
}
return p.root.traverse(list, id).([]string)
}

View File

@ -43,3 +43,16 @@ func TestPtrIntList(t *testing.T) {
t.Log(fmt.Sprintf("P: %x %x %v", int(uintptr(ra)), rb, ra == rb))
}
func TestAcquireStringList(t *testing.T) {
q := []string{"foo", "bar", "bgp"}
w := []string{"foo", "bar", "bgp"}
e := []string{"foo", "bpf"}
p2 := NewStringList()
x1 := p2.Acquire(q)
x2 := p2.Acquire(w)
x3 := p2.Acquire(e)
fmt.Printf("Ptr: %p %p => %p %p\n", q, w, x1, x2)
fmt.Printf("Ptr: %p => %p\n", e, x3)
}