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"
|
import "sync"
|
||||||
|
|
||||||
// String is a pool for strings.
|
// String is a pool for strings.
|
||||||
|
// This will most likely be a pool for IP addresses.
|
||||||
type String struct {
|
type String struct {
|
||||||
values map[string]*string
|
values map[string]*string
|
||||||
|
|
||||||
counter map[string]uint
|
counter map[string]uint
|
||||||
top uint
|
top uint
|
||||||
|
|
||||||
sync.Mutex
|
sync.Mutex
|
||||||
}
|
}
|
||||||
@ -14,7 +16,8 @@ type String struct {
|
|||||||
// NewString creates a new string pool
|
// NewString creates a new string pool
|
||||||
func NewString() *String {
|
func NewString() *String {
|
||||||
return &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
|
p.values[s] = &s
|
||||||
ptr = &s
|
ptr = &s
|
||||||
}
|
}
|
||||||
// Increment counter and top value
|
p.counter[s] = p.top
|
||||||
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
|
|
||||||
}
|
|
||||||
return ptr
|
return ptr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 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 *String) GarbageCollect() uint {
|
||||||
p.Lock()
|
p.Lock()
|
||||||
defer p.Unlock()
|
defer p.Unlock()
|
||||||
@ -57,5 +48,6 @@ func (p *String) GarbageCollect() uint {
|
|||||||
released++
|
released++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
p.top++ // Next generation
|
||||||
return released
|
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