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  }