From 9da371065dedc2fc2bb173b2cda9c7837cc26fc7 Mon Sep 17 00:00:00 2001 From: Annika Hannig Date: Tue, 15 Nov 2022 15:36:14 +0100 Subject: [PATCH] added string and int lists --- pkg/api/response_routes.go | 12 +- pkg/store/pools/int_list.go | 93 -------------- pkg/store/pools/int_list_list.go | 41 ------ pkg/store/pools/lists.go | 119 ++++++++++++++++++ .../pools/{int_list_test.go => lists_test.go} | 13 ++ 5 files changed, 138 insertions(+), 140 deletions(-) delete mode 100644 pkg/store/pools/int_list.go delete mode 100644 pkg/store/pools/int_list_list.go create mode 100644 pkg/store/pools/lists.go rename pkg/store/pools/{int_list_test.go => lists_test.go} (76%) diff --git a/pkg/api/response_routes.go b/pkg/api/response_routes.go index bd2b4bc..78c2420 100644 --- a/pkg/api/response_routes.go +++ b/pkg/api/response_routes.go @@ -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"` } diff --git a/pkg/store/pools/int_list.go b/pkg/store/pools/int_list.go deleted file mode 100644 index fed5175..0000000 --- a/pkg/store/pools/int_list.go +++ /dev/null @@ -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) -} diff --git a/pkg/store/pools/int_list_list.go b/pkg/store/pools/int_list_list.go deleted file mode 100644 index 575931d..0000000 --- a/pkg/store/pools/int_list_list.go +++ /dev/null @@ -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{} -} diff --git a/pkg/store/pools/lists.go b/pkg/store/pools/lists.go new file mode 100644 index 0000000..536da70 --- /dev/null +++ b/pkg/store/pools/lists.go @@ -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) +} diff --git a/pkg/store/pools/int_list_test.go b/pkg/store/pools/lists_test.go similarity index 76% rename from pkg/store/pools/int_list_test.go rename to pkg/store/pools/lists_test.go index cf8baff..fda7b58 100644 --- a/pkg/store/pools/int_list_test.go +++ b/pkg/store/pools/lists_test.go @@ -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) +}