Skip to content

Commit

Permalink
[chore][pkg/stanza] Allow trie to store a value (open-telemetry#28592)
Browse files Browse the repository at this point in the history
This PR enhances the internal `trie` struct (which is not yet in use
anywhere in the codebase) such that a node may contain any value.

The motivation for this is that I believe we may soon be able to migrate
`knownFiles` and `previousPollFiles` to tries, which will prove out the
functionality of the trie and also should improve efficiency of the
package overall.
  • Loading branch information
djaglowski authored and RoryCrispin committed Nov 24, 2023
1 parent fa5080b commit a0addfc
Show file tree
Hide file tree
Showing 2 changed files with 119 additions and 319 deletions.
97 changes: 39 additions & 58 deletions pkg/stanza/fileconsumer/internal/trie/trie.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,93 +12,74 @@

package trie // import "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/stanza/fileconsumer/internal/trie"

type Trie struct {
isEnd bool
children map[byte]*Trie
type Trie[T any] struct {
value *T
children map[byte]*Trie[T]
}

// NewTrie allocates and returns a new *Trie.
func NewTrie() *Trie {
return &Trie{}
func NewTrie[T any]() *Trie[T] {
return &Trie[T]{children: make(map[byte]*Trie[T])}
}

func (trie *Trie) HasKey(key []byte) bool {
func (trie *Trie[T]) Get(key []byte) T {
node := trie
isEnd := false
for _, r := range key {
node = node.children[r]
var value T
for _, b := range key {
node = node.children[b]
if node == nil {
return isEnd
return value // end of trie
}
// We have reached end of the current path and all the previous characters have matched
// Return if current node is leaf and it is not root
if node.isLeaf() && node != trie {
return true
if node.value != nil {
value = *node.value
}
// check for any ending node in our current path
isEnd = isEnd || node.isEnd
}
return isEnd
return value // end of fingerprint
}

// Put inserts the key into the trie
func (trie *Trie) Put(key []byte) {
// TODO []byte, T value parameters
// Put inserts a value into the trie
func (trie *Trie[T]) Put(key []byte, v T) {
node := trie
for _, r := range key {
child, ok := node.children[r]
for _, b := range key {
_, ok := node.children[b]
if !ok {
if node.children == nil {
node.children = map[byte]*Trie{}
}
child = NewTrie()
node.children[r] = child
node.children[b] = NewTrie[T]()
}
node = child
node = node.children[b]
}
node.isEnd = true
node.value = &v
}

// Delete removes keys from the Trie. Returns true if node was found for the given key.
// If the node or any of its ancestors
// becomes childless as a result, it is removed from the trie.
func (trie *Trie) Delete(key []byte) bool {
var path []*Trie // record ancestors to check later
// Delete removes a value from the Trie. Returns true if the value was found.
// Any empty nodes which become childless as a result are removed from the trie.
func (trie *Trie[T]) Delete(key []byte) bool {
var path []*Trie[T] // record ancestors to check later
node := trie
for _, b := range key {
path = append(path, node)
node = node.children[b]
if node == nil {
// node does not exist
return false
}
path = append(path, node)
}

// someonce called Delete() on the node which is not end of current path
if !node.isEnd {
if node.value == nil {
return false
}
node.isEnd = false
// if leaf, remove it from its parent's children map. Repeat for ancestor path.
if node.isLeaf() {
// iterate backwards over path
for i := len(path) - 1; i >= 0; i-- {
parent := path[i]
b := key[i]
delete(parent.children, b)
if !parent.isLeaf() {
// parent has other children, stop
break
}
parent.children = nil
if parent.isEnd {
// Parent has a value, stop
break
}

// Remove the value
node.value = nil

// Iterate back up the path and remove empty nodes
for i := len(path) - 1; i >= 0; i-- {
node := path[i]
b := key[i]
delete(node.children, b)
if len(node.children) > 0 || node.value != nil {
break // node has other children or a value, leave it
}
}
return true // node (internal or not) existed and its value was nil'd
}

func (trie *Trie) isLeaf() bool {
return len(trie.children) == 0
return true
}
Loading

0 comments on commit a0addfc

Please sign in to comment.