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  })