initial string deduplication and integer list
This commit is contained in:
parent
f97a4a7bc8
commit
59f3141f2a
42
pkg/store/pools/int_list.go
Normal file
42
pkg/store/pools/int_list.go
Normal file
@ -0,0 +1,42 @@
|
||||
package pools
|
||||
|
||||
import "sync"
|
||||
|
||||
// IntNode is a node in the tree.
|
||||
type IntNode struct {
|
||||
children []*IntNode
|
||||
value int
|
||||
ptr any
|
||||
}
|
||||
|
||||
// IntTree is a tree structure for deduplicating
|
||||
// lists of integers.
|
||||
type IntTree struct {
|
||||
children []*IntNode
|
||||
}
|
||||
|
||||
// Acquire int list
|
||||
func (t *IntTree) Acquire(list []int) []int {
|
||||
if len(list) == 0 {
|
||||
return nil
|
||||
}
|
||||
v := list[0]
|
||||
var node *IntNode
|
||||
// TODO
|
||||
for _, c := range t.children {
|
||||
if c.value == v {
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
counter *IntTree
|
||||
|
||||
sync.Mutex
|
||||
}
|
@ -3,10 +3,12 @@ package pools
|
||||
import "sync"
|
||||
|
||||
// String is a pool for strings.
|
||||
// This will most likely be a pool for IP addresses.
|
||||
type String struct {
|
||||
values map[string]*string
|
||||
|
||||
counter map[string]uint
|
||||
top uint
|
||||
top uint
|
||||
|
||||
sync.Mutex
|
||||
}
|
||||
@ -14,7 +16,8 @@ type String struct {
|
||||
// NewString creates a new string pool
|
||||
func NewString() *String {
|
||||
return &String{
|
||||
values: map[string]*string{},
|
||||
values: map[string]*string{},
|
||||
counter: map[string]uint{},
|
||||
}
|
||||
}
|
||||
|
||||
@ -28,24 +31,12 @@ func (p *String) Acquire(s string) *string {
|
||||
p.values[s] = &s
|
||||
ptr = &s
|
||||
}
|
||||
// Increment counter and top value
|
||||
cnt, ok := p.counter[s]
|
||||
if !ok {
|
||||
cnt = p.top + 1
|
||||
} else {
|
||||
cnt = cnt + 1
|
||||
}
|
||||
p.counter[s] = cnt
|
||||
if p.top < cnt {
|
||||
p.top = cnt
|
||||
}
|
||||
p.counter[s] = p.top
|
||||
return ptr
|
||||
}
|
||||
|
||||
|
||||
|
||||
// GarbageCollect releases all values, which have not been seen
|
||||
// again.
|
||||
// again.
|
||||
func (p *String) GarbageCollect() uint {
|
||||
p.Lock()
|
||||
defer p.Unlock()
|
||||
@ -57,5 +48,6 @@ func (p *String) GarbageCollect() uint {
|
||||
released++
|
||||
}
|
||||
}
|
||||
p.top++ // Next generation
|
||||
return released
|
||||
}
|
||||
|
52
pkg/store/pools/string_test.go
Normal file
52
pkg/store/pools/string_test.go
Normal file
@ -0,0 +1,52 @@
|
||||
package pools
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestAcquireString(t *testing.T) {
|
||||
p := NewString()
|
||||
s1 := p.Acquire("hello")
|
||||
s2 := p.Acquire("hello")
|
||||
s3 := p.Acquire("world")
|
||||
s1 = p.Acquire("hello")
|
||||
|
||||
if s1 != s2 {
|
||||
t.Error("expected s1 == s2")
|
||||
}
|
||||
t.Log(fmt.Sprintf("s1, s2: %x %x", s1, s2))
|
||||
|
||||
if s2 == s3 {
|
||||
t.Error("expected s2 !== s3")
|
||||
}
|
||||
t.Log(fmt.Sprintf("s1, s2: %x %x", s1, s2))
|
||||
}
|
||||
|
||||
func TestGarbageCollectString(t *testing.T) {
|
||||
p := NewString()
|
||||
|
||||
// Gen 1
|
||||
p.Acquire("hello")
|
||||
p.Acquire("world")
|
||||
|
||||
r := p.GarbageCollect()
|
||||
if r > 0 {
|
||||
t.Error("first run should not collect anything.")
|
||||
}
|
||||
|
||||
p.Acquire("hello")
|
||||
p.Acquire("foo")
|
||||
r = p.GarbageCollect()
|
||||
if r != 1 {
|
||||
t.Error("expected 1 released value")
|
||||
}
|
||||
|
||||
for k := range p.values {
|
||||
if k == "world" {
|
||||
t.Error("did not expect to find world here")
|
||||
}
|
||||
}
|
||||
t.Log(p.values)
|
||||
t.Log(p.counter)
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user