github.com/thanos-io/thanos@v0.32.5/pkg/compact/downsample/aggr.go (about) 1 // Copyright (c) The Thanos Authors. 2 // Licensed under the Apache License 2.0. 3 4 package downsample 5 6 import ( 7 "encoding/binary" 8 9 "github.com/pkg/errors" 10 "github.com/prometheus/prometheus/tsdb/chunkenc" 11 ) 12 13 // ChunkEncAggr is the top level encoding byte for the AggrChunk. 14 // It picks the highest number possible to prevent future collisions with wrapped encodings. 15 const ChunkEncAggr = chunkenc.Encoding(0xff) 16 17 // AggrChunk is a chunk that is composed of a set of aggregates for the same underlying data. 18 // Not all aggregates must be present. 19 type AggrChunk []byte 20 21 // EncodeAggrChunk encodes a new aggregate chunk from the array of chunks for each aggregate. 22 // Each array entry corresponds to the respective AggrType number. 23 func EncodeAggrChunk(chks [5]chunkenc.Chunk) *AggrChunk { 24 var b []byte 25 buf := [8]byte{} 26 27 for _, c := range chks { 28 // Unset aggregates are marked with a zero length entry. 29 if c == nil { 30 n := binary.PutUvarint(buf[:], 0) 31 b = append(b, buf[:n]...) 32 continue 33 } 34 l := len(c.Bytes()) 35 n := binary.PutUvarint(buf[:], uint64(l)) 36 b = append(b, buf[:n]...) 37 b = append(b, byte(c.Encoding())) 38 b = append(b, c.Bytes()...) 39 } 40 chk := AggrChunk(b) 41 return &chk 42 } 43 44 func (c AggrChunk) Bytes() []byte { 45 return []byte(c) 46 } 47 48 func (c AggrChunk) Appender() (chunkenc.Appender, error) { 49 return nil, errors.New("not implemented") 50 } 51 52 func (c AggrChunk) Iterator(_ chunkenc.Iterator) chunkenc.Iterator { 53 return chunkenc.NewNopIterator() 54 } 55 56 func (c AggrChunk) NumSamples() int { 57 x, err := c.Get(AggrCount) 58 if err != nil { 59 return 0 60 } 61 return x.NumSamples() 62 } 63 64 // ErrAggrNotExist is returned if a requested aggregation is not present in an AggrChunk. 65 var ErrAggrNotExist = errors.New("aggregate does not exist") 66 67 func (c AggrChunk) Encoding() chunkenc.Encoding { 68 return ChunkEncAggr 69 } 70 71 func (c AggrChunk) Compact() {} 72 73 // Get returns the sub-chunk for the given aggregate type if it exists. 74 func (c AggrChunk) Get(t AggrType) (chunkenc.Chunk, error) { 75 b := c[:] 76 var x []byte 77 78 for i := AggrType(0); i <= t; i++ { 79 l, n := binary.Uvarint(b) 80 if n < 1 || len(b[n:]) < int(l)+1 { 81 return nil, errors.New("invalid size") 82 } 83 b = b[n:] 84 // If length is set to zero explicitly, that means the aggregate is unset. 85 if l == 0 { 86 if i == t { 87 return nil, ErrAggrNotExist 88 } 89 continue 90 } 91 x = b[:int(l)+1] 92 b = b[int(l)+1:] 93 } 94 return chunkenc.FromData(chunkenc.Encoding(x[0]), x[1:]) 95 } 96 97 // AggrType represents an aggregation type. 98 type AggrType uint8 99 100 // Valid aggregations. 101 const ( 102 AggrCount AggrType = iota 103 AggrSum 104 AggrMin 105 AggrMax 106 AggrCounter 107 ) 108 109 func (t AggrType) String() string { 110 switch t { 111 case AggrCount: 112 return "count" 113 case AggrSum: 114 return "sum" 115 case AggrMin: 116 return "min" 117 case AggrMax: 118 return "max" 119 case AggrCounter: 120 return "counter" 121 } 122 return "<unknown>" 123 }