Change LabelValuesFor() to accept index.Postings (#14280)

The only call we have to LabelValuesFor() has an index.Postings, and we
expand it to pass to this method, which will iterate over the values.

That's a waste of resources: we can iterate on the index.Postings
directly.

If there's any downstream implementation that has a slice of series,
they can always do an index.ListPostings from them: doing that is
cheaper than expanding an abstract index.Postings.

Signed-off-by: Oleg Zaytsev <mail@olegzaytsev.com>
This commit is contained in:
Oleg Zaytsev 2024-06-11 15:36:46 +02:00 committed by GitHub
parent 7f0caf7229
commit 64a9abb8be
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 31 additions and 29 deletions

View File

@ -103,9 +103,9 @@ type IndexReader interface {
// storage.ErrNotFound is returned as error. // storage.ErrNotFound is returned as error.
LabelValueFor(ctx context.Context, id storage.SeriesRef, label string) (string, error) LabelValueFor(ctx context.Context, id storage.SeriesRef, label string) (string, error)
// LabelNamesFor returns all the label names for the series referred to by IDs. // LabelNamesFor returns all the label names for the series referred to by the postings.
// The names returned are sorted. // The names returned are sorted.
LabelNamesFor(ctx context.Context, ids ...storage.SeriesRef) ([]string, error) LabelNamesFor(ctx context.Context, postings index.Postings) ([]string, error)
// Close releases the underlying resources of the reader. // Close releases the underlying resources of the reader.
Close() error Close() error
@ -551,10 +551,10 @@ func (r blockIndexReader) LabelValueFor(ctx context.Context, id storage.SeriesRe
return r.ir.LabelValueFor(ctx, id, label) return r.ir.LabelValueFor(ctx, id, label)
} }
// LabelNamesFor returns all the label names for the series referred to by IDs. // LabelNamesFor returns all the label names for the series referred to by the postings.
// The names returned are sorted. // The names returned are sorted.
func (r blockIndexReader) LabelNamesFor(ctx context.Context, ids ...storage.SeriesRef) ([]string, error) { func (r blockIndexReader) LabelNamesFor(ctx context.Context, postings index.Postings) ([]string, error) {
return r.ir.LabelNamesFor(ctx, ids...) return r.ir.LabelNamesFor(ctx, postings)
} }
type blockTombstoneReader struct { type blockTombstoneReader struct {

View File

@ -267,15 +267,17 @@ func (h *headIndexReader) LabelValueFor(_ context.Context, id storage.SeriesRef,
return value, nil return value, nil
} }
// LabelNamesFor returns all the label names for the series referred to by IDs. // LabelNamesFor returns all the label names for the series referred to by the postings.
// The names returned are sorted. // The names returned are sorted.
func (h *headIndexReader) LabelNamesFor(ctx context.Context, ids ...storage.SeriesRef) ([]string, error) { func (h *headIndexReader) LabelNamesFor(ctx context.Context, series index.Postings) ([]string, error) {
namesMap := make(map[string]struct{}) namesMap := make(map[string]struct{})
for _, id := range ids { i := 0
if ctx.Err() != nil { for series.Next() {
i++
if i%checkContextEveryNIterations == 0 && ctx.Err() != nil {
return nil, ctx.Err() return nil, ctx.Err()
} }
memSeries := h.head.series.getByID(chunks.HeadSeriesRef(id)) memSeries := h.head.series.getByID(chunks.HeadSeriesRef(series.At()))
if memSeries == nil { if memSeries == nil {
// Series not found, this happens during compaction, // Series not found, this happens during compaction,
// when series was garbage collected after the caller got the series IDs. // when series was garbage collected after the caller got the series IDs.
@ -285,6 +287,9 @@ func (h *headIndexReader) LabelNamesFor(ctx context.Context, ids ...storage.Seri
namesMap[lbl.Name] = struct{}{} namesMap[lbl.Name] = struct{}{}
}) })
} }
if err := series.Err(); err != nil {
return nil, err
}
names := make([]string, 0, len(namesMap)) names := make([]string, 0, len(namesMap))
for name := range namesMap { for name := range namesMap {
names = append(names, name) names = append(names, name)

View File

@ -1551,11 +1551,14 @@ func (r *Reader) LabelValues(ctx context.Context, name string, matchers ...*labe
// LabelNamesFor returns all the label names for the series referred to by IDs. // LabelNamesFor returns all the label names for the series referred to by IDs.
// The names returned are sorted. // The names returned are sorted.
func (r *Reader) LabelNamesFor(ctx context.Context, ids ...storage.SeriesRef) ([]string, error) { func (r *Reader) LabelNamesFor(ctx context.Context, postings Postings) ([]string, error) {
// Gather offsetsMap the name offsetsMap in the symbol table first // Gather offsetsMap the name offsetsMap in the symbol table first
offsetsMap := make(map[uint32]struct{}) offsetsMap := make(map[uint32]struct{})
for _, id := range ids { i := 0
if ctx.Err() != nil { for postings.Next() {
id := postings.At()
if i%checkContextEveryNIterations == 0 && ctx.Err() != nil {
return nil, ctx.Err() return nil, ctx.Err()
} }

View File

@ -483,7 +483,7 @@ func (ir *OOOCompactionHeadIndexReader) LabelValueFor(context.Context, storage.S
return "", errors.New("not implemented") return "", errors.New("not implemented")
} }
func (ir *OOOCompactionHeadIndexReader) LabelNamesFor(ctx context.Context, ids ...storage.SeriesRef) ([]string, error) { func (ir *OOOCompactionHeadIndexReader) LabelNamesFor(ctx context.Context, postings index.Postings) ([]string, error) {
return nil, errors.New("not implemented") return nil, errors.New("not implemented")
} }

View File

@ -447,16 +447,7 @@ func labelNamesWithMatchers(ctx context.Context, r IndexReader, matchers ...*lab
if err != nil { if err != nil {
return nil, err return nil, err
} }
return r.LabelNamesFor(ctx, p)
var postings []storage.SeriesRef
for p.Next() {
postings = append(postings, p.At())
}
if err := p.Err(); err != nil {
return nil, fmt.Errorf("postings for label names with matchers: %w", err)
}
return r.LabelNamesFor(ctx, postings...)
} }
// seriesData, used inside other iterators, are updated when we move from one series to another. // seriesData, used inside other iterators, are updated when we move from one series to another.

View File

@ -2292,13 +2292,16 @@ func (m mockIndex) LabelValueFor(_ context.Context, id storage.SeriesRef, label
return m.series[id].l.Get(label), nil return m.series[id].l.Get(label), nil
} }
func (m mockIndex) LabelNamesFor(ctx context.Context, ids ...storage.SeriesRef) ([]string, error) { func (m mockIndex) LabelNamesFor(_ context.Context, postings index.Postings) ([]string, error) {
namesMap := make(map[string]bool) namesMap := make(map[string]bool)
for _, id := range ids { for postings.Next() {
m.series[id].l.Range(func(lbl labels.Label) { m.series[postings.At()].l.Range(func(lbl labels.Label) {
namesMap[lbl.Name] = true namesMap[lbl.Name] = true
}) })
} }
if err := postings.Err(); err != nil {
return nil, err
}
names := make([]string, 0, len(namesMap)) names := make([]string, 0, len(namesMap))
for name := range namesMap { for name := range namesMap {
names = append(names, name) names = append(names, name)
@ -3232,7 +3235,7 @@ func (m mockMatcherIndex) LabelValueFor(context.Context, storage.SeriesRef, stri
return "", errors.New("label value for called") return "", errors.New("label value for called")
} }
func (m mockMatcherIndex) LabelNamesFor(ctx context.Context, ids ...storage.SeriesRef) ([]string, error) { func (m mockMatcherIndex) LabelNamesFor(ctx context.Context, postings index.Postings) ([]string, error) {
return nil, errors.New("label names for for called") return nil, errors.New("label names for for called")
} }
@ -3693,7 +3696,7 @@ func (m mockReaderOfLabels) LabelNames(context.Context, ...*labels.Matcher) ([]s
panic("LabelNames called") panic("LabelNames called")
} }
func (m mockReaderOfLabels) LabelNamesFor(context.Context, ...storage.SeriesRef) ([]string, error) { func (m mockReaderOfLabels) LabelNamesFor(context.Context, index.Postings) ([]string, error) {
panic("LabelNamesFor called") panic("LabelNamesFor called")
} }