Change LabelValuesFor() to accept index.Postings ()

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")
} }