github.com/pyroscope-io/pyroscope@v0.37.3-0.20230725203016-5f6947968bd0/pkg/structs/transporttrie/trie.go (about)

     1  package transporttrie
     2  
     3  import (
     4  	"bytes"
     5  	"sort"
     6  	"sync"
     7  )
     8  
     9  type trieNode struct {
    10  	name     []byte
    11  	value    uint64
    12  	children []*trieNode
    13  }
    14  
    15  func mergeFunc(a, b uint64, t1, t2 *Trie) uint64 {
    16  	return a*uint64(t1.Multiplier)/uint64(t1.Divider) + b*uint64(t2.Multiplier)/uint64(t2.Divider)
    17  }
    18  
    19  // func MergeSumVarintsWithWeights(t1, t2 *Trie) mergeFunc {
    20  // 	f := func(a, b uint64) uint64 {
    21  // 		return a*uint64(t1.Multiplier)/uint64(t1.Divider) + b*uint64(t2.Multiplier)/uint64(t2.Divider)
    22  // 	}
    23  // 	return f
    24  // }
    25  
    26  func newTrieNode(name []byte) *trieNode {
    27  	return &trieNode{
    28  		name:     name,
    29  		children: make([]*trieNode, 0),
    30  	}
    31  }
    32  
    33  func (tn *trieNode) clone() *trieNode {
    34  	newTn := &trieNode{
    35  		name:     tn.name,
    36  		value:    tn.value,
    37  		children: make([]*trieNode, len(tn.children)),
    38  	}
    39  
    40  	for i, c := range tn.children {
    41  		newTn.children[i] = c.clone()
    42  	}
    43  
    44  	return newTn
    45  }
    46  
    47  func (tn *trieNode) insert(t2 *trieNode) {
    48  	key := t2.name
    49  	i := sort.Search(len(tn.children), func(i int) bool { return bytes.Compare(tn.children[i].name, key) >= 0 })
    50  
    51  	tn.children = append(tn.children, &trieNode{})
    52  	copy(tn.children[i+1:], tn.children[i:])
    53  	tn.children[i] = t2
    54  }
    55  
    56  // TODO: Refactor
    57  func (tn *trieNode) findNodeAt(key []byte, fn func(*trieNode)) {
    58  	key2 := make([]byte, len(key))
    59  	// TODO: remove
    60  	copy(key2, key)
    61  	key = key2
    62  OuterLoop:
    63  	for {
    64  		// log.Debug("findNodeAt, key", string(key))
    65  
    66  		if len(key) == 0 {
    67  			fn(tn)
    68  			return
    69  		}
    70  
    71  		// 4 options:
    72  		// trie:
    73  		// foo -> bar
    74  		// 1) no leads (baz)
    75  		//    create a new child, call fn with it
    76  		// 2) lead, key matches (foo)
    77  		//    call fn with existing child
    78  		// 3) lead, key matches, shorter (fo / fop)
    79  		//    split existing child, set that as tn
    80  		// 4) lead, key matches, longer (fooo)
    81  		//    go to existing child, set that as tn
    82  
    83  		leadIndex := -1
    84  		for k, v := range tn.children {
    85  			if v.name[0] == key[0] {
    86  				leadIndex = k
    87  			}
    88  		}
    89  
    90  		if leadIndex == -1 { // 1
    91  			// log.Debug("case 1")
    92  			newTn := newTrieNode(key)
    93  			tn.insert(newTn)
    94  			fn(newTn)
    95  			return
    96  		}
    97  
    98  		leadKey := tn.children[leadIndex].name
    99  		// log.Debug("lead key", string(leadKey))
   100  		lk := len(key)
   101  		llk := len(leadKey)
   102  		for i := 0; i < lk; i++ {
   103  			if i == llk { // 4 fooo / foo i = 3 llk = 3
   104  				// log.Debug("case 4")
   105  				tn = tn.children[leadIndex]
   106  				key = key[llk:]
   107  				continue OuterLoop
   108  			}
   109  			if leadKey[i] != key[i] { // 3
   110  				// log.Debug("case 3")
   111  				// leadKey = abc
   112  				// key = abd
   113  				a := leadKey[:i] // ab
   114  				b := leadKey[i:] // c
   115  				// log.Debug("children ", string(a), string(b))
   116  				// tn.childrenKeys[leadIndex] = a
   117  				newTn := newTrieNode(a)
   118  				// newTn.childrenKeys = [][]byte{b}
   119  				newTn.children = []*trieNode{tn.children[leadIndex]}
   120  				tn.children[leadIndex].name = b
   121  				tn.children[leadIndex] = newTn
   122  				// newTn.value = tn.value
   123  				// tn.value = nil
   124  				tn = newTn
   125  				key = key[i:]
   126  				continue OuterLoop
   127  			}
   128  		}
   129  		// lk < llk
   130  		if !bytes.Equal(key, leadKey) { // 3
   131  			// log.Debug("case 3.2")
   132  			a := leadKey[:lk] // ab
   133  			b := leadKey[lk:] // c
   134  			// tn.childrenKeys[leadIndex] = a
   135  			newTn := newTrieNode(a)
   136  			// newTn.childrenKeys = [][]byte{b}
   137  			newTn.children = []*trieNode{tn.children[leadIndex]}
   138  			tn.children[leadIndex].name = b
   139  			tn.children[leadIndex] = newTn
   140  			tn = newTn
   141  			key = key[lk:]
   142  			continue OuterLoop
   143  		}
   144  
   145  		// 2
   146  		// log.Debug("case 2 —", lk, llk, bytes.Equal(key, leadKey), string(key), string(leadKey))
   147  		fn(tn.children[leadIndex])
   148  		return
   149  	}
   150  }
   151  
   152  type Trie struct {
   153  	mutex      sync.Mutex
   154  	I          byte // debugging
   155  	metadata   map[string]string
   156  	Multiplier int
   157  	Divider    int
   158  	root       *trieNode
   159  }
   160  
   161  // New returns a new initialized empty Trie.
   162  func New() *Trie {
   163  	return &Trie{
   164  		metadata:   make(map[string]string),
   165  		root:       newTrieNode([]byte{}),
   166  		Multiplier: 1,
   167  		Divider:    1,
   168  	}
   169  }
   170  
   171  func (t *Trie) Clone(m, d int) *Trie {
   172  	return &Trie{
   173  		I:          t.I,
   174  		metadata:   t.metadata,
   175  		Multiplier: m,
   176  		Divider:    d,
   177  		root:       t.root,
   178  	}
   179  }
   180  
   181  func (t *Trie) Insert(key []byte, value uint64, merge ...bool) {
   182  	t.mutex.Lock()
   183  	defer t.mutex.Unlock()
   184  
   185  	isMerge := false
   186  	if len(merge) > 0 && merge[0] {
   187  		isMerge = true
   188  	}
   189  	if isMerge {
   190  		t.root.findNodeAt(key, func(tn *trieNode) {
   191  			tn.value += value
   192  		})
   193  	} else {
   194  		t.root.findNodeAt(key, func(tn *trieNode) {
   195  			tn.value = value
   196  		})
   197  	}
   198  }
   199  
   200  func (t *Trie) Iterate(cb func(name []byte, val uint64)) {
   201  	t.mutex.Lock()
   202  	defer t.mutex.Unlock()
   203  
   204  	nodes := []*trieNode{t.root}
   205  	prefixes := make([][]byte, 1)
   206  	prefixes[0] = make([]byte, 0)
   207  	for len(nodes) > 0 {
   208  		tn := nodes[0]
   209  		nodes = nodes[1:]
   210  
   211  		prefix := prefixes[0]
   212  		prefixes = prefixes[1:]
   213  
   214  		name := append(prefix, tn.name...)
   215  		if tn.value > 0 {
   216  			cb(name, tn.value)
   217  		}
   218  		// log.Debug("name", bytes.Index(name, []byte("\n")))
   219  
   220  		nodes = append(tn.children, nodes...)
   221  		for i := 0; i < len(tn.children); i++ {
   222  			prefixes = append([][]byte{name}, prefixes...)
   223  		}
   224  	}
   225  }
   226  
   227  func (t *Trie) IsEmpty() bool {
   228  	t.mutex.Lock()
   229  	defer t.mutex.Unlock()
   230  
   231  	return len(t.root.children) == 0
   232  }