github.com/grafana/pyroscope@v1.18.0/pkg/phlaredb/tsdb/index/chunk.go (about) 1 package index 2 3 import ( 4 "sort" 5 6 "github.com/prometheus/common/model" 7 ) 8 9 // Meta holds information about a chunk of data. 10 type ChunkMeta struct { 11 Checksum uint32 12 13 MinTime, MaxTime int64 14 15 // Bytes stored, rounded to nearest KB 16 KB uint32 17 18 SeriesIndex uint32 19 } 20 21 func (c ChunkMeta) From() model.Time { return model.Time(c.MinTime) } 22 func (c ChunkMeta) Through() model.Time { return model.Time(c.MaxTime) } 23 func (c ChunkMeta) Bounds() (model.Time, model.Time) { return c.From(), c.Through() } 24 25 type ChunkMetas []ChunkMeta 26 27 func (c ChunkMetas) Len() int { return len(c) } 28 func (c ChunkMetas) Swap(i, j int) { c[i], c[j] = c[j], c[i] } 29 func (c ChunkMetas) Bounds() (mint, maxt model.Time) { 30 ln := len(c) 31 if ln == 0 { 32 return 33 } 34 35 mint, maxt = model.Time(c[0].MinTime), model.Time(c[ln-1].MaxTime) 36 // even when sorted, we need to check all chunks for maxt 37 // since we sort by (min, max, checksum). Therefore 38 // check mint here as well to ensure this works on unordered ChunkMetas too 39 for _, chk := range c { 40 from, through := chk.Bounds() 41 if mint > from { 42 mint = from 43 } 44 45 if maxt < through { 46 maxt = through 47 } 48 } 49 return 50 } 51 52 // Sort by (MinTime, MaxTime, Checksum) 53 func (c ChunkMetas) Less(i, j int) bool { 54 a, b := c[i], c[j] 55 if a.MinTime != b.MinTime { 56 return a.MinTime < b.MinTime 57 } 58 59 if a.MaxTime != b.MaxTime { 60 return a.MaxTime < b.MaxTime 61 } 62 63 return a.Checksum < b.Checksum 64 } 65 66 // Finalize sorts and dedupes 67 // TODO(owen-d): can we remove the need for this by ensuring we only push 68 // in order and without duplicates? 69 func (c ChunkMetas) Finalize() ChunkMetas { 70 sort.Sort(c) 71 72 if len(c) == 0 { 73 return c 74 } 75 76 res := ChunkMetasPool.Get() 77 lastDuplicate := -1 78 prior := c[0] 79 80 // minimize reslicing costs due to duplicates 81 for i := 1; i < len(c); i++ { 82 x := c[i] 83 if x.MinTime == prior.MinTime && x.MaxTime == prior.MaxTime && x.Checksum == prior.Checksum { 84 res = append(res, c[lastDuplicate+1:i]...) 85 lastDuplicate = i 86 } 87 prior = x 88 } 89 90 // no duplicates were found, short circuit 91 // by returning unmodified underlying slice 92 if len(res) == 0 { 93 ChunkMetasPool.Put(res) // release unused slice to pool 94 return c 95 } 96 97 // otherwise, append any remaining values 98 res = append(res, c[lastDuplicate+1:]...) 99 // release self to pool; res will be returned instead 100 ChunkMetasPool.Put(c) 101 return res 102 }