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 }