github.com/pyroscope-io/pyroscope@v0.37.3-0.20230725203016-5f6947968bd0/pkg/structs/transporttrie/trie_test.go (about) 1 package transporttrie 2 3 import ( 4 "bytes" 5 "fmt" 6 "hash" 7 "hash/fnv" 8 "math/rand" 9 10 . "github.com/onsi/ginkgo/v2" 11 . "github.com/onsi/gomega" 12 "github.com/sirupsen/logrus" 13 14 "github.com/pyroscope-io/pyroscope/pkg/structs/merge" 15 "github.com/pyroscope-io/pyroscope/pkg/util/varint" 16 ) 17 18 func randStr(l int) []byte { 19 buf := make([]byte, l) 20 for i := 0; i < l; i++ { 21 buf[i] = byte(97) + byte(rand.Uint32()%10) 22 } 23 // rand.Read(buf) 24 25 return buf 26 } 27 28 type trieHash struct { 29 w varint.Writer 30 h hash.Hash64 31 } 32 33 func newTrieHash() trieHash { 34 return trieHash{ 35 w: varint.NewWriter(), 36 h: fnv.New64a(), 37 } 38 } 39 40 func (t *trieHash) addUint64(k []byte, v uint64) { 41 _, _ = t.h.Write(k) 42 _, _ = t.w.Write(t.h, v) 43 } 44 45 func (t *trieHash) addInt(k []byte, v int) { 46 t.addUint64(k, uint64(v)) 47 } 48 49 func (t trieHash) sum() uint64 { 50 return t.h.Sum64() 51 } 52 53 var _ = Describe("trie package", func() { 54 serializationExample := []byte("\x00\x00\x01\x02ab\x00\x02\x01c\x01\x00\x01d\x02\x00") 55 Context("trie.Serialize()", func() { 56 trie := New() 57 trie.Insert([]byte("abc"), 1) 58 trie.Insert([]byte("abd"), 2) 59 logrus.Debug("trie abc abd", trie) 60 61 It("returns correct results", func() { 62 var buf bytes.Buffer 63 trie.Serialize(&buf) 64 Expect(buf.Bytes()).To(Equal(serializationExample)) 65 }) 66 67 Context("Ran 1000000 times", func() { 68 var buf1 bytes.Buffer 69 trie.Serialize(&buf1) 70 It("returns the same result", func() { 71 var buf2 bytes.Buffer 72 trie.Serialize(&buf2) 73 Expect(buf2).To(Equal(buf1)) 74 }) 75 }) 76 }) 77 78 Context("Ser/Deserialize()", func() { 79 It("returns correct results", func() { 80 for j := 0; j < 10; j++ { 81 // logrus.Debug("---") 82 trie := New() 83 // trie.Insert([]byte("acc"), []byte{1}) 84 // trie.Insert([]byte("abc"), []byte{2}) 85 // trie.Insert([]byte("abd"), []byte{3}) 86 // trie.Insert([]byte("ab"), []byte{4}) 87 for i := 0; i < 10; i++ { 88 trie.Insert(randStr(10), uint64(i)) 89 } 90 // trie.Insert([]byte("abc"), []byte{1}, true) 91 // trie.Insert([]byte("abc"), []byte{3}, true) 92 // trie.Insert([]byte("bar"), []byte{5}) 93 // trie.Insert([]byte("abd"), []byte{2}) 94 // trie.Insert([]byte("abce"), []byte{3}) 95 // trie.Insert([]byte("ab"), []byte{4}) 96 // trie.Insert([]byte("abc"), []byte{2}) 97 98 // trie.Insert([]byte("baze"), []byte{1}) 99 // trie.Insert([]byte("baz"), []byte{2}) 100 // trie.Insert([]byte("bat"), []byte{3}) 101 // trie.Insert([]byte("bata"), []byte{4}) 102 // trie.Insert([]byte("batb"), []byte{5}) 103 // trie.Insert([]byte("bad"), []byte{6}) 104 // trie.Insert([]byte("bae"), []byte{7}) 105 // trie.Insert([]byte("zyx"), []byte{1}) 106 // trie.Insert([]byte("zy"), []byte{2}) 107 // trie.Insert([]byte(""), []byte{1}) 108 // trie.Insert([]byte("a"), []byte{2}) 109 // trie.Insert([]byte("b"), []byte{3}) 110 111 // trie.Insert([]byte("1234567"), []byte{1}) 112 // trie.Insert([]byte("1234667"), []byte{2}) 113 // trie.Insert([]byte("1234767"), []byte{3}) 114 logrus.Debug("a", trie.String()) 115 strA := "" 116 trie.Iterate(func(k []byte, v uint64) { 117 strA += fmt.Sprintf("%q %d\n", k, v) 118 }) 119 logrus.Debug("strA", strA) 120 121 var buf bytes.Buffer 122 trie.Serialize(&buf) 123 124 r := bytes.NewReader(buf.Bytes()) 125 t, e := Deserialize(r) 126 strB := "" 127 t.Iterate(func(k []byte, v uint64) { 128 strB += fmt.Sprintf("%q %d\n", k, v) 129 }) 130 logrus.Debug("b", t.String()) 131 logrus.Debug("strB", strB) 132 Expect(e).To(BeNil()) 133 Expect(trie.String()).To(Equal(t.String())) 134 Expect(strA).To(Equal(strB)) 135 logrus.Debug("---/") 136 } 137 }) 138 }) 139 140 Context("IterateRaw()", func() { 141 compareWithRawIterator := func(t *Trie) { 142 h1 := newTrieHash() 143 t.Iterate(h1.addUint64) 144 var buf bytes.Buffer 145 Expect(t.Serialize(&buf)).ToNot(HaveOccurred()) 146 147 r := bytes.NewReader(buf.Bytes()) 148 h2 := newTrieHash() 149 tmpBuf := make([]byte, 0, 256) 150 Expect(IterateRaw(r, tmpBuf, h2.addInt)).ToNot(HaveOccurred()) 151 152 Expect(h2.sum()).To(Equal(h1.sum())) 153 } 154 155 It("returns correct results", func() { 156 type value struct { 157 k string 158 v uint64 159 } 160 161 values := []value{ 162 {"foo;bar;baz", 1}, 163 {"foo;bar;baz;a", 1}, 164 {"foo;bar;baz;b", 1}, 165 {"foo;bar;baz;c", 1}, 166 {"foo;bar;bar", 1}, 167 {"foo;bar;qux", 1}, 168 {"foo;bax;bar", 1}, 169 {"zoo;boo", 1}, 170 {"zoo;bao", 1}, 171 } 172 173 trie := New() 174 for _, v := range values { 175 trie.Insert([]byte(v.k), v.v) 176 } 177 178 compareWithRawIterator(trie) 179 }) 180 181 It("handles random tries properly", func() { 182 for j := 0; j < 10; j++ { 183 trie := New() 184 for i := 0; i < 10; i++ { 185 trie.Insert(randStr(10), uint64(i)) 186 } 187 188 h1 := newTrieHash() 189 trie.Iterate(h1.addUint64) 190 191 var buf bytes.Buffer 192 err := trie.Serialize(&buf) 193 Expect(err).To(BeNil()) 194 195 r := bytes.NewReader(buf.Bytes()) 196 h2 := newTrieHash() 197 err = IterateRaw(r, nil, h2.addInt) 198 Expect(err).To(BeNil()) 199 200 Expect(h2.sum()).To(Equal(h1.sum())) 201 } 202 }) 203 }) 204 205 Context("Deserialize()", func() { 206 trie := New() 207 trie.Insert([]byte("abc"), 1) 208 trie.Insert([]byte("ab"), 2) 209 logrus.Debug(trie.String()) 210 211 It("returns correct results", func() { 212 r := bytes.NewReader(serializationExample) 213 t, e := Deserialize(r) 214 logrus.Debug(t.String()) 215 Expect(e).To(BeNil()) 216 var buf bytes.Buffer 217 t.Serialize(&buf) 218 Expect(buf.Bytes()).To(Equal(serializationExample)) 219 }) 220 221 Context("Ran 1000000 times", func() { 222 var buf1 bytes.Buffer 223 trie.Serialize(&buf1) 224 It("returns the same result", func() { 225 var buf2 bytes.Buffer 226 trie.Serialize(&buf2) 227 Expect(buf2).To(Equal(buf1)) 228 }) 229 }) 230 }) 231 232 Context("MergeTriesConcurrently()", func() { 233 It("merges 2 tries", func(done Done) { 234 for s := 0; s < 1000; s++ { 235 rand.Seed(int64(s)) 236 // logrus.Debug(s) 237 t1 := New() 238 t2 := New() 239 t3 := New() 240 // logrus.Debug("---") 241 n := 2 242 n2 := 4 243 for i := 0; i < n; i++ { 244 str := randStr(n2) 245 t1.Insert(str, uint64(i)) 246 t3.Insert(str, uint64(i)) 247 } 248 for i := 0; i < n; i++ { 249 str := randStr(n2) 250 t2.Insert(str, uint64(n+i)) 251 t3.Insert(str, uint64(n+i), true) 252 } 253 254 // t1 := New() 255 // t1.Insert([]byte("abc"), []byte{1}) 256 // t1.Insert([]byte("abd"), []byte{2}) 257 // t1.Insert([]byte("abe"), []byte{2}) 258 259 // t2 := New() 260 // t2.Insert([]byte("abc"), []byte{1}) 261 // t2.Insert([]byte("abd"), []byte{2}) 262 // t2.Insert([]byte("abf"), []byte{3}) 263 // t2.Insert([]byte("abef"), []byte{5}) 264 // t2.Insert([]byte("a"), []byte{6}) 265 // t2.Insert([]byte("ac"), []byte{7}) 266 // t2.Insert([]byte("aa"), []byte{8}) 267 268 // t3 := New() 269 // t3.Insert([]byte("a"), []byte{6}) 270 // t3.Insert([]byte("ac"), []byte{7}) 271 // t3.Insert([]byte("aa"), []byte{8}) 272 // t3.Insert([]byte("abc"), []byte{2}) 273 // t3.Insert([]byte("abd"), []byte{4}) 274 // t3.Insert([]byte("abe"), []byte{2}) 275 // t3.Insert([]byte("abf"), []byte{3}) 276 // t3.Insert([]byte("abef"), []byte{5}) 277 278 var buf1 bytes.Buffer 279 var buf2 bytes.Buffer 280 t1.Serialize(&buf1) 281 t2.Serialize(&buf2) 282 283 // logrus.Debug("t1\n", t1.String()) 284 // logrus.Debug("t2\n", t2.String()) 285 // logrus.Debug("t3\n", t3.String()) 286 287 // Expect(buf1.Bytes()).To(Equal(buf2.Bytes())) 288 tries := []merge.Merger{t1, t2} 289 rand.Shuffle(len(tries), func(i, j int) { 290 tries[i], tries[j] = tries[j], tries[i] 291 }) 292 t1I := merge.MergeTriesSerially(1, tries...) 293 t1 = t1I.(*Trie) 294 // logrus.Debug("t1m\n", t1.String()) 295 296 var buf3 bytes.Buffer 297 var buf4 bytes.Buffer 298 t3.Serialize(&buf3) 299 t1.Serialize(&buf4) 300 Expect(buf4).To(Equal(buf3)) 301 } 302 close(done) 303 }, 1.0) 304 }) 305 })