Skip to content

Commit d94ee60

Browse files
authored
perf(tsdb): don't fetch labels in TSDBIndex.GetChunkRefs (#20970)
Signed-off-by: Bryan Boreham <bjboreham@gmail.com>
1 parent 6b58156 commit d94ee60

File tree

3 files changed

+81
-56
lines changed

3 files changed

+81
-56
lines changed

pkg/storage/stores/shipper/indexshipper/tsdb/head_read.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,14 +111,17 @@ func (h *headIndexReader) Postings(name string, fpFilter index.FingerprintFilter
111111
}
112112

113113
// Series returns the series for the given reference.
114+
// lbls can be nil, to indicate that just the chunks are needed.
114115
func (h *headIndexReader) Series(ref storage.SeriesRef, from int64, through int64, lbls *labels.Labels, chks *[]index.ChunkMeta) (uint64, error) {
115116
s := h.head.series.getByID(uint64(ref))
116117

117118
if s == nil {
118119
h.head.metrics.seriesNotFound.Inc()
119120
return 0, storage.ErrNotFound
120121
}
121-
lbls.CopyFrom(s.ls)
122+
if lbls != nil {
123+
lbls.CopyFrom(s.ls)
124+
}
122125

123126
queryBounds := newBounds(model.Time(from), model.Time(through))
124127

pkg/storage/stores/shipper/indexshipper/tsdb/index/index.go

Lines changed: 29 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -2135,14 +2135,12 @@ func buildChunkSamples(d encoding.Decbuf, numChunks int, info *chunkSamples) err
21352135
return d.Err()
21362136
}
21372137

2138-
func (dec *Decoder) prepSeries(b []byte, lbls *labels.Labels, chks *[]ChunkMeta) (*encoding.Decbuf, uint64, error) {
2138+
// prepSeries returns series labels for a series, only returning selected `by` label names.
2139+
// If `by` is nil, it returns all labels for the series.
2140+
func (dec *Decoder) prepSeries(b []byte, lbls *labels.Labels, by map[string]struct{}) (*encoding.Decbuf, uint64, error) {
21392141
builder := labelpool.Get()
21402142
defer labelpool.Put(builder)
21412143

2142-
if chks != nil {
2143-
*chks = (*chks)[:0]
2144-
}
2145-
21462144
d := encoding.DecWrap(tsdb_enc.Decbuf{B: b})
21472145

21482146
fprint := d.Be64()
@@ -2160,6 +2158,13 @@ func (dec *Decoder) prepSeries(b []byte, lbls *labels.Labels, chks *[]ChunkMeta)
21602158
if err != nil {
21612159
return nil, 0, errors.Wrap(err, "lookup label name")
21622160
}
2161+
2162+
if by != nil {
2163+
if _, ok := by[ln]; !ok {
2164+
continue
2165+
}
2166+
}
2167+
21632168
lv, err := dec.LookupSymbol(lvo)
21642169
if err != nil {
21652170
return nil, 0, errors.Wrap(err, "lookup label value")
@@ -2171,62 +2176,30 @@ func (dec *Decoder) prepSeries(b []byte, lbls *labels.Labels, chks *[]ChunkMeta)
21712176
// Commit built labels.
21722177
builder.Sort()
21732178
*lbls = builder.Labels()
2174-
21752179
return &d, fprint, nil
21762180
}
21772181

2178-
// prepSeriesBy returns series labels and chunks for a series and only returning selected `by` label names.
2179-
// If `by` is empty, it returns all labels for the series.
2180-
func (dec *Decoder) prepSeriesBy(b []byte, lbls *labels.Labels, chks *[]ChunkMeta, by map[string]struct{}) (*encoding.Decbuf, uint64, error) {
2181-
if by == nil {
2182-
return dec.prepSeries(b, lbls, chks)
2183-
}
2184-
2185-
builder := labelpool.Get()
2186-
defer labelpool.Put(builder)
2187-
2188-
if chks != nil {
2189-
*chks = (*chks)[:0]
2190-
}
2191-
2182+
// skipSeriesLabels reads past the label section in buffer b, ready to read chunks after that.
2183+
func (dec *Decoder) skipSeriesLabels(b []byte) (*encoding.Decbuf, uint64, error) {
21922184
d := encoding.DecWrap(tsdb_enc.Decbuf{B: b})
21932185

21942186
fprint := d.Be64()
21952187
k := d.Uvarint()
21962188

2197-
for i := 0; i < k; i++ {
2198-
lno := uint32(d.Uvarint())
2199-
lvo := uint32(d.Uvarint())
2189+
for range k {
2190+
_ = d.Uvarint()
2191+
_ = d.Uvarint()
22002192

22012193
if d.Err() != nil {
22022194
return nil, 0, errors.Wrap(d.Err(), "read series label offsets")
22032195
}
2204-
// todo(cyriltovena): we could cache this by user requests spanning multiple prepSeries calls.
2205-
ln, err := dec.LookupSymbol(lno)
2206-
if err != nil {
2207-
return nil, 0, errors.Wrap(err, "lookup label name")
2208-
}
2209-
if _, ok := by[ln]; !ok {
2210-
continue
2211-
}
2212-
2213-
lv, err := dec.LookupSymbol(lvo)
2214-
if err != nil {
2215-
return nil, 0, errors.Wrap(err, "lookup label value")
2216-
}
2217-
2218-
builder.Add(ln, lv)
22192196
}
22202197

2221-
// Commit built labels.
2222-
builder.Sort()
2223-
*lbls = builder.Labels()
2224-
22252198
return &d, fprint, nil
22262199
}
22272200

22282201
func (dec *Decoder) ChunkStats(version int, b []byte, seriesRef storage.SeriesRef, from, through int64, lbls *labels.Labels, by map[string]struct{}) (uint64, ChunkStats, error) {
2229-
d, fp, err := dec.prepSeriesBy(b, lbls, nil, by)
2202+
d, fp, err := dec.prepSeries(b, lbls, by)
22302203
if err != nil {
22312204
return 0, ChunkStats{}, err
22322205
}
@@ -2368,15 +2341,25 @@ func (dec *Decoder) readChunkStatsPriorV3(d *encoding.Decbuf, seriesRef storage.
23682341
return res, nil
23692342
}
23702343

2371-
// Series decodes a series entry from the given byte slice into lset and chks.
2372-
func (dec *Decoder) Series(version int, b []byte, seriesRef storage.SeriesRef, from int64, through int64, lbls *labels.Labels, chks *[]ChunkMeta) (uint64, error) {
2373-
d, fprint, err := dec.prepSeries(b, lbls, chks)
2344+
// Series decodes a series entry from the given byte slice into lbls and chks.
2345+
// lbls can be nil, indicating the caller only wants the chunks.
2346+
func (dec *Decoder) Series(version int, b []byte, seriesRef storage.SeriesRef, from int64, through int64, lbls *labels.Labels, chks *[]ChunkMeta) (fprint uint64, err error) {
2347+
var d *encoding.Decbuf
2348+
if lbls == nil {
2349+
d, fprint, err = dec.skipSeriesLabels(b)
2350+
} else {
2351+
d, fprint, err = dec.prepSeries(b, lbls, nil)
2352+
}
23742353
if err != nil {
23752354
return 0, err
23762355
}
23772356

2357+
*chks = (*chks)[:0]
23782358
// read chunks based on fmt
23792359
if err := dec.readChunks(version, d, seriesRef, from, through, chks); err != nil {
2360+
if lbls == nil {
2361+
return 0, errors.Wrapf(err, "series footprint %x", fprint)
2362+
}
23802363
return 0, errors.Wrapf(err, "series %s", lbls.String())
23812364
}
23822365
return fprint, nil

pkg/storage/stores/shipper/indexshipper/tsdb/single_file_index.go

Lines changed: 48 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -162,17 +162,20 @@ func (i *TSDBIndex) SetChunkFilterer(chunkFilter chunk.RequestChunkFilterer) {
162162
// Accepts a userID argument in order to implement `Index` interface, but since this is a single tenant index,
163163
// it is ignored (it's enforced elsewhere in index selection)
164164
func (i *TSDBIndex) ForSeries(ctx context.Context, _ string, fpFilter index.FingerprintFilter, from model.Time, through model.Time, fn func(labels.Labels, model.Fingerprint, []index.ChunkMeta) (stop bool), matchers ...*labels.Matcher) error {
165+
var filterer chunk.Filterer
166+
if i.chunkFilter != nil {
167+
filterer = i.chunkFilter.ForRequest(ctx)
168+
}
169+
return i.forSeriesAndLabels(ctx, fpFilter, filterer, from, through, fn, matchers...)
170+
}
171+
172+
func (i *TSDBIndex) forSeriesAndLabels(ctx context.Context, fpFilter index.FingerprintFilter, filterer chunk.Filterer, from model.Time, through model.Time, fn func(labels.Labels, model.Fingerprint, []index.ChunkMeta) (stop bool), matchers ...*labels.Matcher) error {
165173
// TODO(owen-d): use pool
166174

167175
var ls labels.Labels
168176
chks := ChunkMetasPool.Get()
169177
defer func() { ChunkMetasPool.Put(chks) }()
170178

171-
var filterer chunk.Filterer
172-
if i.chunkFilter != nil {
173-
filterer = i.chunkFilter.ForRequest(ctx)
174-
}
175-
176179
return i.forPostings(ctx, fpFilter, from, through, matchers, func(p index.Postings) error {
177180
for p.Next() {
178181
hash, err := i.reader.Series(p.At(), int64(from), int64(through), &ls, &chks)
@@ -198,6 +201,31 @@ func (i *TSDBIndex) ForSeries(ctx context.Context, _ string, fpFilter index.Fing
198201

199202
}
200203

204+
// Same as ForSeries, but the callback fn does not take a Labels parameter.
205+
func (i *TSDBIndex) forSeriesNoLabels(ctx context.Context, fpFilter index.FingerprintFilter, from model.Time, through model.Time, fn func(model.Fingerprint, []index.ChunkMeta) (stop bool), matchers ...*labels.Matcher) error {
206+
chks := ChunkMetasPool.Get()
207+
defer ChunkMetasPool.Put(chks)
208+
209+
return i.forPostings(ctx, fpFilter, from, through, matchers, func(p index.Postings) error {
210+
for p.Next() {
211+
hash, err := i.reader.Series(p.At(), int64(from), int64(through), nil, &chks)
212+
if err != nil {
213+
return err
214+
}
215+
216+
// skip series that belong to different shards
217+
if fpFilter != nil && !fpFilter.Match(model.Fingerprint(hash)) {
218+
continue
219+
}
220+
221+
if stop := fn(model.Fingerprint(hash), chks); stop {
222+
break
223+
}
224+
}
225+
return p.Err()
226+
})
227+
}
228+
201229
func (i *TSDBIndex) forPostings(
202230
_ context.Context,
203231
fpFilter index.FingerprintFilter,
@@ -218,7 +246,7 @@ func (i *TSDBIndex) GetChunkRefs(ctx context.Context, userID string, from, throu
218246
}
219247
res = res[:0]
220248

221-
if err := i.ForSeries(ctx, "", fpFilter, from, through, func(_ labels.Labels, fp model.Fingerprint, chks []index.ChunkMeta) (stop bool) {
249+
addChunksToResult := func(fp model.Fingerprint, chks []index.ChunkMeta) (stop bool) {
222250
for _, chk := range chks {
223251
res = append(res, logproto.ChunkRefWithSizingInfo{
224252
ChunkRef: logproto.ChunkRef{
@@ -233,11 +261,22 @@ func (i *TSDBIndex) GetChunkRefs(ctx context.Context, userID string, from, throu
233261
})
234262
}
235263
return false
236-
}, matchers...); err != nil {
237-
return nil, err
238264
}
239265

240-
return res, nil
266+
var filterer chunk.Filterer
267+
if i.chunkFilter != nil {
268+
filterer = i.chunkFilter.ForRequest(ctx)
269+
}
270+
var err error
271+
if filterer != nil {
272+
// We need to fetch labels to pass to the filterer, even though we don't look at them in the callback.
273+
err = i.forSeriesAndLabels(ctx, fpFilter, filterer, from, through, func(_ labels.Labels, fp model.Fingerprint, chks []index.ChunkMeta) (stop bool) {
274+
return addChunksToResult(fp, chks)
275+
}, matchers...)
276+
} else {
277+
err = i.forSeriesNoLabels(ctx, fpFilter, from, through, addChunksToResult, matchers...)
278+
}
279+
return res, err
241280
}
242281

243282
func (i *TSDBIndex) Series(ctx context.Context, _ string, from, through model.Time, res []Series, fpFilter index.FingerprintFilter, matchers ...*labels.Matcher) ([]Series, error) {

0 commit comments

Comments
 (0)