github.com/pyroscope-io/pyroscope@v0.37.3-0.20230725203016-5f6947968bd0/pkg/storage/segment/segment_test.go (about)

     1  package segment
     2  
     3  import (
     4  	"bufio"
     5  	"log"
     6  	"math/big"
     7  	"math/rand"
     8  	"os"
     9  	"strconv"
    10  	"strings"
    11  	"time"
    12  
    13  	. "github.com/onsi/ginkgo/v2"
    14  	. "github.com/onsi/gomega"
    15  
    16  	"github.com/pyroscope-io/pyroscope/pkg/testing"
    17  )
    18  
    19  var putNoOp = func(depth int, t time.Time, r *big.Rat, addons []Addon) {}
    20  
    21  func doGet(s *Segment, st, et time.Time) []time.Time {
    22  	res := []time.Time{}
    23  	s.Get(st, et, func(d int, samples, writes uint64, t time.Time, r *big.Rat) {
    24  		res = append(res, t)
    25  	})
    26  	return res
    27  }
    28  
    29  func strip(val string) string {
    30  	ret := ""
    31  	scanner := bufio.NewScanner(strings.NewReader(val))
    32  	for scanner.Scan() {
    33  		line := strings.TrimSpace(scanner.Text())
    34  		if len(line) > 0 {
    35  			ret += line + "\n"
    36  		}
    37  	}
    38  	return ret
    39  }
    40  
    41  func expectChildrenSamplesAddUpToParentSamples(tn *streeNode) {
    42  	childrenSum := uint64(0)
    43  	if len(tn.children) == 0 {
    44  		return
    45  	}
    46  	for _, v := range tn.children {
    47  		if v != nil {
    48  			expectChildrenSamplesAddUpToParentSamples(v)
    49  			childrenSum += v.samples
    50  		}
    51  	}
    52  	Expect(childrenSum).To(Equal(tn.samples))
    53  }
    54  
    55  var _ = Describe("stree", func() {
    56  	Context("Get", func() {
    57  		Context("When there's no root", func() {
    58  			It("get doesn't fail", func() {
    59  				s := New()
    60  				Expect(doGet(s, testing.SimpleTime(0), testing.SimpleTime(39))).To(HaveLen(0))
    61  			})
    62  		})
    63  	})
    64  
    65  	Context("StartTime", func() {
    66  		Context("empty segment", func() {
    67  			It("returns zero time", func() {
    68  				s := New()
    69  				Expect(s.StartTime().IsZero()).To(BeTrue())
    70  			})
    71  		})
    72  
    73  		Context("fuzz test", func() {
    74  			It("always returns the right values", func() {
    75  				r := rand.New(rand.NewSource(6231912))
    76  
    77  				// doesn't work with minTime = 0
    78  				minTime := 1023886146
    79  				maxTime := 1623886146
    80  
    81  				runs := 100
    82  				maxInsertionsPerTree := 100
    83  
    84  				for i := 0; i < runs; i++ {
    85  					s := New()
    86  					minSt := maxTime
    87  					for j := 0; j < 1+r.Intn(maxInsertionsPerTree); j++ {
    88  						st := (minTime + r.Intn(maxTime-minTime)) / 10 * 10
    89  						if st < minSt {
    90  							minSt = st
    91  						}
    92  						et := st + 10 + r.Intn(1000)
    93  						s.Put(testing.SimpleTime(st), testing.SimpleTime(et), 1, func(de int, t time.Time, r *big.Rat, a []Addon) {})
    94  					}
    95  
    96  					Expect(s.StartTime()).To(Equal(testing.SimpleTime(minSt)))
    97  				}
    98  			})
    99  		})
   100  	})
   101  
   102  	Context("DeleteDataBefore", func() {
   103  		Context("empty segment", func() {
   104  			It("returns true and no keys", func() {
   105  				s := New()
   106  
   107  				keys := []string{}
   108  				rp := &RetentionPolicy{AbsoluteTime: testing.SimpleTime(19)}
   109  				r, _ := s.WalkNodesToDelete(rp, func(depth int, t time.Time) error {
   110  					keys = append(keys, strconv.Itoa(depth)+":"+strconv.Itoa(int(t.Unix())))
   111  					return nil
   112  				})
   113  
   114  				Expect(r).To(BeTrue())
   115  				Expect(keys).To(BeEmpty())
   116  			})
   117  		})
   118  
   119  		Context("simple test 1", func() {
   120  			It("correctly deletes data", func() {
   121  				s := New()
   122  				s.Put(testing.SimpleUTime(10), testing.SimpleUTime(19), 1, func(de int, t time.Time, r *big.Rat, a []Addon) {})
   123  				s.Put(testing.SimpleUTime(20), testing.SimpleUTime(29), 1, func(de int, t time.Time, r *big.Rat, a []Addon) {})
   124  
   125  				keys := []string{}
   126  				rp := &RetentionPolicy{AbsoluteTime: testing.SimpleUTime(21)}
   127  				r, _ := s.WalkNodesToDelete(rp, func(depth int, t time.Time) error {
   128  					keys = append(keys, strconv.Itoa(depth)+":"+strconv.Itoa(int(t.Unix())))
   129  					return nil
   130  				})
   131  
   132  				Expect(r).To(BeFalse())
   133  				Expect(keys).To(ConsistOf([]string{
   134  					"0:10",
   135  				}))
   136  			})
   137  		})
   138  
   139  		Context("simple test 3", func() {
   140  			It("correctly deletes data", func() {
   141  				s := New()
   142  				s.Put(testing.SimpleUTime(10), testing.SimpleUTime(19), 1, func(de int, t time.Time, r *big.Rat, a []Addon) {})
   143  				s.Put(testing.SimpleUTime(1020), testing.SimpleUTime(1029), 1, func(de int, t time.Time, r *big.Rat, a []Addon) {})
   144  
   145  				keys := []string{}
   146  				rp := &RetentionPolicy{AbsoluteTime: testing.SimpleUTime(21)}
   147  				r, _ := s.WalkNodesToDelete(rp, func(depth int, t time.Time) error {
   148  					keys = append(keys, strconv.Itoa(depth)+":"+strconv.Itoa(int(t.Unix())))
   149  					return nil
   150  				})
   151  
   152  				Expect(r).To(BeFalse())
   153  				Expect(keys).To(ConsistOf([]string{
   154  					"0:10",
   155  				}))
   156  			})
   157  		})
   158  
   159  		Context("simple test 2", func() {
   160  			It("correctly deletes data", func() {
   161  				s := New()
   162  				s.Put(testing.SimpleUTime(10), testing.SimpleUTime(19), 1, func(de int, t time.Time, r *big.Rat, a []Addon) {})
   163  				s.Put(testing.SimpleUTime(20), testing.SimpleUTime(29), 1, func(de int, t time.Time, r *big.Rat, a []Addon) {})
   164  
   165  				keys := []string{}
   166  				rp := &RetentionPolicy{AbsoluteTime: testing.SimpleUTime(200)}
   167  				r, _ := s.WalkNodesToDelete(rp, func(depth int, t time.Time) error {
   168  					keys = append(keys, strconv.Itoa(depth)+":"+strconv.Itoa(int(t.Unix())))
   169  					return nil
   170  				})
   171  
   172  				Expect(r).To(BeTrue())
   173  				Expect(keys).To(ConsistOf([]string{
   174  					"1:0",
   175  					"0:10",
   176  					"0:20",
   177  				}))
   178  			})
   179  		})
   180  
   181  		Context("level-based retention", func() {
   182  			It("correctly deletes data partially", func() {
   183  				s := New()
   184  				s.Put(testing.SimpleUTime(10), testing.SimpleUTime(19), 1, func(de int, t time.Time, r *big.Rat, a []Addon) {})
   185  				s.Put(testing.SimpleUTime(20), testing.SimpleUTime(29), 1, func(de int, t time.Time, r *big.Rat, a []Addon) {})
   186  
   187  				keys := []string{}
   188  				rp := &RetentionPolicy{Levels: map[int]time.Time{0: time.Now()}}
   189  				r, _ := s.WalkNodesToDelete(rp, func(depth int, t time.Time) error {
   190  					keys = append(keys, strconv.Itoa(depth)+":"+strconv.Itoa(int(t.Unix())))
   191  					return nil
   192  				})
   193  
   194  				Expect(r).To(BeFalse())
   195  				Expect(s.root).ToNot(BeNil())
   196  				Expect(keys).To(ConsistOf([]string{
   197  					"0:10",
   198  					"0:20",
   199  				}))
   200  
   201  				removed, err := s.DeleteNodesBefore(rp)
   202  				Expect(err).ToNot(HaveOccurred())
   203  				Expect(removed).To(BeFalse())
   204  			})
   205  
   206  			It("correctly deletes data completely", func() {
   207  				s := New()
   208  				s.Put(testing.SimpleUTime(10), testing.SimpleUTime(19), 1, func(de int, t time.Time, r *big.Rat, a []Addon) {})
   209  				s.Put(testing.SimpleUTime(20), testing.SimpleUTime(29), 1, func(de int, t time.Time, r *big.Rat, a []Addon) {})
   210  
   211  				var keys []string
   212  				rp := &RetentionPolicy{Levels: map[int]time.Time{0: time.Now(), 1: time.Now()}}
   213  				r, _ := s.WalkNodesToDelete(rp, func(depth int, t time.Time) error {
   214  					keys = append(keys, strconv.Itoa(depth)+":"+strconv.Itoa(int(t.Unix())))
   215  					return nil
   216  				})
   217  
   218  				Expect(r).To(BeTrue())
   219  				Expect(keys).To(ConsistOf([]string{
   220  					"1:0",
   221  					"0:10",
   222  					"0:20",
   223  				}))
   224  
   225  				removed, err := s.DeleteNodesBefore(rp)
   226  				Expect(err).ToNot(HaveOccurred())
   227  				Expect(removed).To(BeTrue())
   228  			})
   229  
   230  			Context("Issue 715", func() {
   231  				// See https://github.com/pyroscope-io/pyroscope/issues/715
   232  				It("does not return nodes affected by retention policy", func() {
   233  					b, err := os.Open("testdata/issue_715")
   234  					Expect(err).ToNot(HaveOccurred())
   235  					s, err := Deserialize(b)
   236  					Expect(err).ToNot(HaveOccurred())
   237  
   238  					var keys []string
   239  					st := time.Date(2022, time.January, 12, 9, 40, 0, 0, time.UTC)
   240  					et := time.Date(2022, time.January, 12, 10, 40, 0, 0, time.UTC)
   241  					s.Get(st, et, func(depth int, samples, writes uint64, t time.Time, r *big.Rat) {
   242  						keys = append(keys, strconv.Itoa(depth)+":"+strconv.Itoa(int(t.Unix()))+":"+r.String())
   243  					})
   244  
   245  					Expect(keys).To(BeEmpty())
   246  				})
   247  
   248  				It("correctly samples data", func() {
   249  					s := New()
   250  					st := time.Date(2021, time.December, 1, 0, 0, 0, 0, time.UTC)
   251  					et := time.Date(2022, time.January, 1, 0, 0, 0, 0, time.UTC)
   252  					rp := &RetentionPolicy{AbsoluteTime: et}
   253  
   254  					c := st
   255  					for c.Before(et) {
   256  						e := c.Add(time.Second * time.Duration(10))
   257  						err := s.Put(c, e, 100, func(int, time.Time, *big.Rat, []Addon) {})
   258  						Expect(err).ToNot(HaveOccurred())
   259  						c = e
   260  					}
   261  
   262  					r, err := s.DeleteNodesBefore(rp)
   263  					Expect(r).To(BeFalse())
   264  					Expect(err).ToNot(HaveOccurred())
   265  
   266  					gSt := st.Add(-time.Hour)
   267  					gEt := et.Add(time.Hour)
   268  
   269  					var keys []string
   270  					s.Get(gSt, gEt, func(depth int, samples, writes uint64, t time.Time, r *big.Rat) {
   271  						keys = append(keys, strconv.Itoa(depth)+":"+strconv.Itoa(int(t.Unix()))+":"+r.String())
   272  					})
   273  
   274  					Expect(keys).To(BeEmpty())
   275  				})
   276  
   277  				It("correctly samples data with level retention period", func() {
   278  					s := New()
   279  					st := time.Date(2021, time.December, 1, 0, 0, 0, 0, time.UTC)
   280  					et := time.Date(2021, time.December, 2, 0, 0, 0, 0, time.UTC)
   281  
   282  					c := st
   283  					for c.Before(et) {
   284  						e := c.Add(time.Second * time.Duration(10))
   285  						err := s.Put(c, e, 100, func(int, time.Time, *big.Rat, []Addon) {})
   286  						Expect(err).ToNot(HaveOccurred())
   287  						c = e
   288  					}
   289  
   290  					r, err := s.DeleteNodesBefore(&RetentionPolicy{Levels: map[int]time.Time{0: et}})
   291  					Expect(r).To(BeFalse())
   292  					Expect(err).ToNot(HaveOccurred())
   293  
   294  					gSt := time.Date(2021, time.December, 1, 10, 0, 0, 0, time.UTC)
   295  					gEt := gSt.Add(time.Second * 30)
   296  
   297  					var keys []string
   298  					s.Get(gSt, gEt, func(depth int, samples, writes uint64, t time.Time, r *big.Rat) {
   299  						keys = append(keys, strconv.Itoa(depth)+":"+strconv.Itoa(int(t.Unix()))+":"+r.String())
   300  					})
   301  
   302  					Expect(keys).To(ConsistOf([]string{
   303  						"1:1638352800:3/10",
   304  					}))
   305  				})
   306  			})
   307  		})
   308  	})
   309  
   310  	Context("Put", func() {
   311  		Context("When inserts are far apart", func() {
   312  			Context("When second insert is far in the future", func() {
   313  				It("sets root properly", func() {
   314  					log.Println("---")
   315  					s := New()
   316  					s.Put(testing.SimpleTime(1330),
   317  						testing.SimpleTime(1339), 1, func(de int, t time.Time, r *big.Rat, a []Addon) {})
   318  					Expect(s.root).ToNot(BeNil())
   319  					Expect(s.root.depth).To(Equal(0))
   320  					s.Put(testing.SimpleTime(1110),
   321  						testing.SimpleTime(1119), 1, func(de int, t time.Time, r *big.Rat, a []Addon) {})
   322  					expectChildrenSamplesAddUpToParentSamples(s.root)
   323  				})
   324  			})
   325  			Context("When second insert is far in the past", func() {
   326  				It("sets root properly", func() {
   327  					log.Println("---")
   328  					s := New()
   329  					s.Put(testing.SimpleTime(2030),
   330  						testing.SimpleTime(2039), 1, func(de int, t time.Time, r *big.Rat, a []Addon) {})
   331  					Expect(s.root).ToNot(BeNil())
   332  					Expect(s.root.depth).To(Equal(0))
   333  					s.Put(testing.SimpleTime(0),
   334  						testing.SimpleTime(9), 1, func(de int, t time.Time, r *big.Rat, a []Addon) {})
   335  					expectChildrenSamplesAddUpToParentSamples(s.root)
   336  				})
   337  			})
   338  		})
   339  
   340  		Context("When empty", func() {
   341  			It("sets root properly", func() {
   342  				s := New()
   343  				s.Put(testing.SimpleTime(0),
   344  					testing.SimpleTime(9), 1, func(de int, t time.Time, r *big.Rat, a []Addon) {})
   345  				Expect(s.root).ToNot(BeNil())
   346  				Expect(s.root.depth).To(Equal(0))
   347  			})
   348  
   349  			It("sets root properly", func() {
   350  				s := New()
   351  				s.Put(testing.SimpleTime(0),
   352  					testing.SimpleTime(49), 1, func(de int, t time.Time, r *big.Rat, a []Addon) {})
   353  				Expect(s.root).ToNot(BeNil())
   354  				Expect(s.root.depth).To(Equal(1))
   355  			})
   356  
   357  			It("sets root properly", func() {
   358  				s := New()
   359  				s.Put(testing.SimpleTime(10),
   360  					testing.SimpleTime(109), 1, func(de int, t time.Time, r *big.Rat, a []Addon) {})
   361  				Expect(s.root).ToNot(BeNil())
   362  				Expect(s.root.depth).To(Equal(2))
   363  			})
   364  
   365  			It("sets root properly", func() {
   366  				s := New()
   367  				s.Put(testing.SimpleTime(10),
   368  					testing.SimpleTime(19), 1, func(de int, t time.Time, r *big.Rat, a []Addon) {})
   369  				Expect(s.root).ToNot(BeNil())
   370  				Expect(s.root.depth).To(Equal(0))
   371  				s.Put(testing.SimpleTime(10),
   372  					testing.SimpleTime(19), 1, func(de int, t time.Time, r *big.Rat, a []Addon) {})
   373  				expectChildrenSamplesAddUpToParentSamples(s.root)
   374  			})
   375  
   376  			It("sets root properly", func() {
   377  				s := New()
   378  				s.Put(testing.SimpleTime(10),
   379  					testing.SimpleTime(19), 1, func(de int, t time.Time, r *big.Rat, a []Addon) {})
   380  				Expect(s.root).ToNot(BeNil())
   381  				Expect(s.root.depth).To(Equal(0))
   382  				s.Put(testing.SimpleTime(20),
   383  					testing.SimpleTime(29), 1, func(de int, t time.Time, r *big.Rat, a []Addon) {})
   384  				Expect(s.root).ToNot(BeNil())
   385  				Expect(s.root.depth).To(Equal(1))
   386  				expectChildrenSamplesAddUpToParentSamples(s.root)
   387  			})
   388  
   389  			It("sets root properly", func() {
   390  				s := New()
   391  				s.Put(testing.SimpleTime(10),
   392  					testing.SimpleTime(19), 10, func(de int, t time.Time, r *big.Rat, a []Addon) {})
   393  				Expect(s.root).ToNot(BeNil())
   394  				Expect(s.root.depth).To(Equal(0))
   395  				s.Put(testing.SimpleTime(20),
   396  					testing.SimpleTime(39), 10, func(de int, t time.Time, r *big.Rat, a []Addon) {})
   397  				Expect(s.root).ToNot(BeNil())
   398  				Expect(s.root.depth).To(Equal(1))
   399  				expectChildrenSamplesAddUpToParentSamples(s.root)
   400  			})
   401  
   402  			It("sets root properly", func() {
   403  				s := New()
   404  				s.Put(testing.SimpleTime(10),
   405  					testing.SimpleTime(19), 1, func(de int, t time.Time, r *big.Rat, a []Addon) {})
   406  				Expect(s.root).ToNot(BeNil())
   407  				Expect(s.root.depth).To(Equal(0))
   408  
   409  				s.Put(testing.SimpleTime(20),
   410  					testing.SimpleTime(29), 1, func(de int, t time.Time, r *big.Rat, a []Addon) {})
   411  				Expect(s.root).ToNot(BeNil())
   412  				Expect(s.root.depth).To(Equal(1))
   413  
   414  				s.Put(testing.SimpleTime(30),
   415  					testing.SimpleTime(39), 1, func(de int, t time.Time, r *big.Rat, a []Addon) {})
   416  				Expect(s.root).ToNot(BeNil())
   417  				Expect(s.root.depth).To(Equal(1))
   418  				expectChildrenSamplesAddUpToParentSamples(s.root)
   419  			})
   420  
   421  			It("sets root properly", func() {
   422  				s := New()
   423  				s.Put(testing.SimpleTime(30),
   424  					testing.SimpleTime(39), 1, func(de int, t time.Time, r *big.Rat, a []Addon) {})
   425  				Expect(s.root).ToNot(BeNil())
   426  				Expect(s.root.depth).To(Equal(0))
   427  
   428  				s.Put(testing.SimpleTime(20),
   429  					testing.SimpleTime(29), 1, func(de int, t time.Time, r *big.Rat, a []Addon) {})
   430  				Expect(s.root).ToNot(BeNil())
   431  				Expect(s.root.depth).To(Equal(1))
   432  
   433  				s.Put(testing.SimpleTime(10),
   434  					testing.SimpleTime(19), 1, func(de int, t time.Time, r *big.Rat, a []Addon) {})
   435  				Expect(s.root).ToNot(BeNil())
   436  				Expect(s.root.depth).To(Equal(1))
   437  
   438  				Expect(doGet(s, testing.SimpleTime(0), testing.SimpleTime(39))).To(HaveLen(3))
   439  			})
   440  
   441  			It("works with 3 mins", func() {
   442  				s := New()
   443  				s.Put(testing.SimpleTime(10),
   444  					testing.SimpleTime(70), 1, func(de int, t time.Time, r *big.Rat, a []Addon) {})
   445  				Expect(s.root).ToNot(BeNil())
   446  				Expect(s.root.depth).To(Equal(1))
   447  				// Expect(doGet(s, testing.SimpleTime(20, testing.SimpleTime(49))).To(HaveLen(3))
   448  			})
   449  
   450  			It("sets trie properly, gets work", func() {
   451  				s := New()
   452  
   453  				s.Put(testing.SimpleTime(0),
   454  					testing.SimpleTime(9), 1, func(de int, t time.Time, r *big.Rat, a []Addon) {})
   455  				Expect(s.root).ToNot(BeNil())
   456  				Expect(s.root.depth).To(Equal(0))
   457  
   458  				s.Put(testing.SimpleTime(100),
   459  					testing.SimpleTime(109), 1, func(de int, t time.Time, r *big.Rat, a []Addon) {})
   460  				expectChildrenSamplesAddUpToParentSamples(s.root)
   461  				Expect(s.root).ToNot(BeNil())
   462  				Expect(s.root.depth).To(Equal(2))
   463  				Expect(s.root.present).To(BeTrue())
   464  				Expect(s.root.children[0]).ToNot(BeNil())
   465  				Expect(s.root.children[0].present).ToNot(BeTrue())
   466  				Expect(s.root.children[1]).ToNot(BeNil())
   467  				Expect(s.root.children[1].present).ToNot(BeTrue())
   468  				Expect(s.root.children[0].children[0].present).To(BeTrue())
   469  				Expect(s.root.children[1].children[0].present).To(BeTrue())
   470  
   471  				Expect(doGet(s, testing.SimpleTime(0), testing.SimpleTime(9))).To(HaveLen(1))
   472  				Expect(doGet(s, testing.SimpleTime(10), testing.SimpleTime(19))).To(HaveLen(0))
   473  				Expect(doGet(s, testing.SimpleTime(100), testing.SimpleTime(109))).To(HaveLen(1))
   474  				Expect(doGet(s, testing.SimpleTime(0), testing.SimpleTime(109))).To(HaveLen(2))
   475  				Expect(doGet(s, testing.SimpleTime(0), testing.SimpleTime(999))).To(HaveLen(1))
   476  				Expect(doGet(s, testing.SimpleTime(0), testing.SimpleTime(1000))).To(HaveLen(1))
   477  				Expect(doGet(s, testing.SimpleTime(0), testing.SimpleTime(1001))).To(HaveLen(1))
   478  				Expect(doGet(s, testing.SimpleTime(0), testing.SimpleTime(989))).To(HaveLen(2))
   479  			})
   480  		})
   481  	})
   482  })