Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[pkg/stanza/fileconsumer] Add trie and test cases #24982

Merged
merged 12 commits into from
Aug 8, 2023
104 changes: 104 additions & 0 deletions pkg/stanza/fileconsumer/internal/trie/trie.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

// TRIE data structure inspired by https://github.com/dghubble/trie
/*
This differs from the original trie.
This has been modified to detect partial matches as well.
For eg.
If we add "ABCD" to this trie, and try to check if "ABCDEF" is in the trie,
it will return true because that's how fingerprint matching works in current implementation.
*/

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

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

// NewTrie allocates and returns a new *Trie.
func NewTrie() *Trie {
return &Trie{}
}

func (trie *Trie) HasKey(key []byte) bool {
node := trie
isEnd := false
for _, r := range key {
node = node.children[r]
if node == nil {
return isEnd
}
// 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
}
// check for any ending node in our current path
isEnd = isEnd || node.isEnd
}
return isEnd
}

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

// 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
node := trie
for _, b := range key {
path = append(path, node)
node = node.children[b]
if node == nil {
// node does not exist
return false
}
}

// someonce called Delete() on the node which is not end of current path
if !node.isEnd {
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
}
}
}
return true // node (internal or not) existed and its value was nil'd
}

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