Skip to content

Commit 6c81039

Browse files
committed
Avoid unnecessary conversions between model.Metric and labels.Labels
Signed-off-by: Xiaochao Dong (@damnever) <[email protected]>
1 parent 6d1bd1b commit 6c81039

File tree

7 files changed

+135
-46
lines changed

7 files changed

+135
-46
lines changed

Diff for: pkg/cortexpb/signature.go

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package cortexpb
2+
3+
import (
4+
"github.com/prometheus/common/model"
5+
"github.com/prometheus/prometheus/model/labels"
6+
)
7+
8+
// Inline and byte-free variant of hash/fnv's fnv64a.
9+
// Ref: https://github.com/prometheus/common/blob/main/model/fnv.go
10+
11+
func LabelsToFingerprint(lset labels.Labels) model.Fingerprint {
12+
if len(lset) == 0 {
13+
return model.Fingerprint(hashNew())
14+
}
15+
16+
sum := hashNew()
17+
for _, l := range lset {
18+
sum = hashAdd(sum, string(l.Name))
19+
sum = hashAddByte(sum, model.SeparatorByte)
20+
sum = hashAdd(sum, string(l.Value))
21+
sum = hashAddByte(sum, model.SeparatorByte)
22+
}
23+
return model.Fingerprint(sum)
24+
}
25+
26+
const (
27+
offset64 = 14695981039346656037
28+
prime64 = 1099511628211
29+
)
30+
31+
// hashNew initializes a new fnv64a hash value.
32+
func hashNew() uint64 {
33+
return offset64
34+
}
35+
36+
// hashAdd adds a string to a fnv64a hash value, returning the updated hash.
37+
func hashAdd(h uint64, s string) uint64 {
38+
for i := 0; i < len(s); i++ {
39+
h ^= uint64(s[i])
40+
h *= prime64
41+
}
42+
return h
43+
}
44+
45+
// hashAddByte adds a byte to a fnv64a hash value, returning the updated hash.
46+
func hashAddByte(h uint64, b byte) uint64 {
47+
h ^= uint64(b)
48+
h *= prime64
49+
return h
50+
}

Diff for: pkg/distributor/distributor.go

+11-11
Original file line numberDiff line numberDiff line change
@@ -1367,8 +1367,8 @@ func (d *Distributor) LabelNames(ctx context.Context, from, to model.Time, hint
13671367
}
13681368

13691369
// MetricsForLabelMatchers gets the metrics that match said matchers
1370-
func (d *Distributor) MetricsForLabelMatchers(ctx context.Context, from, through model.Time, hint *storage.SelectHints, partialDataEnabled bool, matchers ...*labels.Matcher) ([]model.Metric, error) {
1371-
return d.metricsForLabelMatchersCommon(ctx, from, through, hint, func(ctx context.Context, rs ring.ReplicationSet, req *ingester_client.MetricsForLabelMatchersRequest, metrics *map[model.Fingerprint]model.Metric, mutex *sync.Mutex, queryLimiter *limiter.QueryLimiter) error {
1370+
func (d *Distributor) MetricsForLabelMatchers(ctx context.Context, from, through model.Time, hint *storage.SelectHints, partialDataEnabled bool, matchers ...*labels.Matcher) ([]labels.Labels, error) {
1371+
return d.metricsForLabelMatchersCommon(ctx, from, through, hint, func(ctx context.Context, rs ring.ReplicationSet, req *ingester_client.MetricsForLabelMatchersRequest, metrics *map[model.Fingerprint]labels.Labels, mutex *sync.Mutex, queryLimiter *limiter.QueryLimiter) error {
13721372
_, err := d.ForReplicationSet(ctx, rs, false, partialDataEnabled, func(ctx context.Context, client ingester_client.IngesterClient) (interface{}, error) {
13731373
resp, err := client.MetricsForLabelMatchers(ctx, req)
13741374
if err != nil {
@@ -1380,8 +1380,8 @@ func (d *Distributor) MetricsForLabelMatchers(ctx context.Context, from, through
13801380
s := make([][]cortexpb.LabelAdapter, 0, len(resp.Metric))
13811381
for _, m := range resp.Metric {
13821382
s = append(s, m.Labels)
1383-
m := cortexpb.FromLabelAdaptersToMetric(m.Labels)
1384-
fingerprint := m.Fingerprint()
1383+
m := cortexpb.FromLabelAdaptersToLabels(m.Labels)
1384+
fingerprint := cortexpb.LabelsToFingerprint(m)
13851385
mutex.Lock()
13861386
(*metrics)[fingerprint] = m
13871387
mutex.Unlock()
@@ -1396,8 +1396,8 @@ func (d *Distributor) MetricsForLabelMatchers(ctx context.Context, from, through
13961396
}, matchers...)
13971397
}
13981398

1399-
func (d *Distributor) MetricsForLabelMatchersStream(ctx context.Context, from, through model.Time, hint *storage.SelectHints, partialDataEnabled bool, matchers ...*labels.Matcher) ([]model.Metric, error) {
1400-
return d.metricsForLabelMatchersCommon(ctx, from, through, hint, func(ctx context.Context, rs ring.ReplicationSet, req *ingester_client.MetricsForLabelMatchersRequest, metrics *map[model.Fingerprint]model.Metric, mutex *sync.Mutex, queryLimiter *limiter.QueryLimiter) error {
1399+
func (d *Distributor) MetricsForLabelMatchersStream(ctx context.Context, from, through model.Time, hint *storage.SelectHints, partialDataEnabled bool, matchers ...*labels.Matcher) ([]labels.Labels, error) {
1400+
return d.metricsForLabelMatchersCommon(ctx, from, through, hint, func(ctx context.Context, rs ring.ReplicationSet, req *ingester_client.MetricsForLabelMatchersRequest, metrics *map[model.Fingerprint]labels.Labels, mutex *sync.Mutex, queryLimiter *limiter.QueryLimiter) error {
14011401
_, err := d.ForReplicationSet(ctx, rs, false, partialDataEnabled, func(ctx context.Context, client ingester_client.IngesterClient) (interface{}, error) {
14021402
stream, err := client.MetricsForLabelMatchersStream(ctx, req)
14031403
if err != nil {
@@ -1417,9 +1417,9 @@ func (d *Distributor) MetricsForLabelMatchersStream(ctx context.Context, from, t
14171417

14181418
s := make([][]cortexpb.LabelAdapter, 0, len(resp.Metric))
14191419
for _, metric := range resp.Metric {
1420-
m := cortexpb.FromLabelAdaptersToMetricWithCopy(metric.Labels)
1420+
m := cortexpb.FromLabelAdaptersToLabels(metric.Labels)
14211421
s = append(s, metric.Labels)
1422-
fingerprint := m.Fingerprint()
1422+
fingerprint := cortexpb.LabelsToFingerprint(m)
14231423
mutex.Lock()
14241424
(*metrics)[fingerprint] = m
14251425
mutex.Unlock()
@@ -1436,7 +1436,7 @@ func (d *Distributor) MetricsForLabelMatchersStream(ctx context.Context, from, t
14361436
}, matchers...)
14371437
}
14381438

1439-
func (d *Distributor) metricsForLabelMatchersCommon(ctx context.Context, from, through model.Time, hints *storage.SelectHints, f func(context.Context, ring.ReplicationSet, *ingester_client.MetricsForLabelMatchersRequest, *map[model.Fingerprint]model.Metric, *sync.Mutex, *limiter.QueryLimiter) error, matchers ...*labels.Matcher) ([]model.Metric, error) {
1439+
func (d *Distributor) metricsForLabelMatchersCommon(ctx context.Context, from, through model.Time, hints *storage.SelectHints, f func(context.Context, ring.ReplicationSet, *ingester_client.MetricsForLabelMatchersRequest, *map[model.Fingerprint]labels.Labels, *sync.Mutex, *limiter.QueryLimiter) error, matchers ...*labels.Matcher) ([]labels.Labels, error) {
14401440
replicationSet, err := d.GetIngestersForMetadata(ctx)
14411441
queryLimiter := limiter.QueryLimiterFromContextWithFallback(ctx)
14421442
if err != nil {
@@ -1448,7 +1448,7 @@ func (d *Distributor) metricsForLabelMatchersCommon(ctx context.Context, from, t
14481448
return nil, err
14491449
}
14501450
mutex := sync.Mutex{}
1451-
metrics := map[model.Fingerprint]model.Metric{}
1451+
metrics := map[model.Fingerprint]labels.Labels{}
14521452

14531453
err = f(ctx, replicationSet, req, &metrics, &mutex, queryLimiter)
14541454

@@ -1457,7 +1457,7 @@ func (d *Distributor) metricsForLabelMatchersCommon(ctx context.Context, from, t
14571457
}
14581458

14591459
mutex.Lock()
1460-
result := make([]model.Metric, 0, len(metrics))
1460+
result := make([]labels.Labels, 0, len(metrics))
14611461
for _, m := range metrics {
14621462
result = append(result, m)
14631463
}

Diff for: pkg/distributor/distributor_test.go

+19-19
Original file line numberDiff line numberDiff line change
@@ -502,7 +502,7 @@ func TestDistributor_MetricsCleanup(t *testing.T) {
502502
# HELP cortex_distributor_exemplars_in_total The total number of exemplars that have come in to the distributor, including rejected or deduped exemplars.
503503
# TYPE cortex_distributor_exemplars_in_total counter
504504
cortex_distributor_exemplars_in_total{user="userA"} 5
505-
505+
506506
# HELP cortex_distributor_ingester_append_failures_total The total number of failed batch appends sent to ingesters.
507507
# TYPE cortex_distributor_ingester_append_failures_total counter
508508
cortex_distributor_ingester_append_failures_total{ingester="ingester-0",status="2xx",type="metadata"} 1
@@ -2459,7 +2459,7 @@ func TestDistributor_MetricsForLabelMatchers(t *testing.T) {
24592459
shuffleShardEnabled bool
24602460
shuffleShardSize int
24612461
matchers []*labels.Matcher
2462-
expectedResult []model.Metric
2462+
expectedResult []labels.Labels
24632463
expectedIngesters int
24642464
queryLimiter *limiter.QueryLimiter
24652465
expectedErr error
@@ -2468,7 +2468,7 @@ func TestDistributor_MetricsForLabelMatchers(t *testing.T) {
24682468
matchers: []*labels.Matcher{
24692469
mustNewMatcher(labels.MatchEqual, model.MetricNameLabel, "unknown"),
24702470
},
2471-
expectedResult: []model.Metric{},
2471+
expectedResult: []labels.Labels{},
24722472
expectedIngesters: numIngesters,
24732473
queryLimiter: limiter.NewQueryLimiter(0, 0, 0, 0),
24742474
expectedErr: nil,
@@ -2477,9 +2477,9 @@ func TestDistributor_MetricsForLabelMatchers(t *testing.T) {
24772477
matchers: []*labels.Matcher{
24782478
mustNewMatcher(labels.MatchEqual, model.MetricNameLabel, "test_1"),
24792479
},
2480-
expectedResult: []model.Metric{
2481-
util.LabelsToMetric(fixtures[0].lbls),
2482-
util.LabelsToMetric(fixtures[1].lbls),
2480+
expectedResult: []labels.Labels{
2481+
fixtures[0].lbls,
2482+
fixtures[1].lbls,
24832483
},
24842484
expectedIngesters: numIngesters,
24852485
queryLimiter: limiter.NewQueryLimiter(0, 0, 0, 0),
@@ -2490,8 +2490,8 @@ func TestDistributor_MetricsForLabelMatchers(t *testing.T) {
24902490
mustNewMatcher(labels.MatchEqual, "status", "200"),
24912491
mustNewMatcher(labels.MatchEqual, model.MetricNameLabel, "test_1"),
24922492
},
2493-
expectedResult: []model.Metric{
2494-
util.LabelsToMetric(fixtures[0].lbls),
2493+
expectedResult: []labels.Labels{
2494+
fixtures[0].lbls,
24952495
},
24962496
expectedIngesters: numIngesters,
24972497
queryLimiter: limiter.NewQueryLimiter(0, 0, 0, 0),
@@ -2501,9 +2501,9 @@ func TestDistributor_MetricsForLabelMatchers(t *testing.T) {
25012501
matchers: []*labels.Matcher{
25022502
mustNewMatcher(labels.MatchEqual, model.MetricNameLabel, "fast_fingerprint_collision"),
25032503
},
2504-
expectedResult: []model.Metric{
2505-
util.LabelsToMetric(fixtures[3].lbls),
2506-
util.LabelsToMetric(fixtures[4].lbls),
2504+
expectedResult: []labels.Labels{
2505+
fixtures[3].lbls,
2506+
fixtures[4].lbls,
25072507
},
25082508
expectedIngesters: numIngesters,
25092509
queryLimiter: limiter.NewQueryLimiter(0, 0, 0, 0),
@@ -2515,9 +2515,9 @@ func TestDistributor_MetricsForLabelMatchers(t *testing.T) {
25152515
matchers: []*labels.Matcher{
25162516
mustNewMatcher(labels.MatchEqual, model.MetricNameLabel, "test_1"),
25172517
},
2518-
expectedResult: []model.Metric{
2519-
util.LabelsToMetric(fixtures[0].lbls),
2520-
util.LabelsToMetric(fixtures[1].lbls),
2518+
expectedResult: []labels.Labels{
2519+
fixtures[0].lbls,
2520+
fixtures[1].lbls,
25212521
},
25222522
expectedIngesters: 3,
25232523
queryLimiter: limiter.NewQueryLimiter(0, 0, 0, 0),
@@ -2529,9 +2529,9 @@ func TestDistributor_MetricsForLabelMatchers(t *testing.T) {
25292529
matchers: []*labels.Matcher{
25302530
mustNewMatcher(labels.MatchEqual, model.MetricNameLabel, "test_1"),
25312531
},
2532-
expectedResult: []model.Metric{
2533-
util.LabelsToMetric(fixtures[0].lbls),
2534-
util.LabelsToMetric(fixtures[1].lbls),
2532+
expectedResult: []labels.Labels{
2533+
fixtures[0].lbls,
2534+
fixtures[1].lbls,
25352535
},
25362536
expectedIngesters: numIngesters,
25372537
queryLimiter: limiter.NewQueryLimiter(0, 0, 0, 0),
@@ -2563,8 +2563,8 @@ func TestDistributor_MetricsForLabelMatchers(t *testing.T) {
25632563
matchers: []*labels.Matcher{
25642564
mustNewMatcher(labels.MatchEqual, model.MetricNameLabel, "test_2"),
25652565
},
2566-
expectedResult: []model.Metric{
2567-
util.LabelsToMetric(fixtures[2].lbls),
2566+
expectedResult: []labels.Labels{
2567+
fixtures[2].lbls,
25682568
},
25692569
expectedIngesters: numIngesters,
25702570
queryLimiter: limiter.NewQueryLimiter(1, 0, 0, 0),

Diff for: pkg/querier/distributor_queryable.go

+8-8
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,8 @@ type Distributor interface {
3333
LabelValuesForLabelNameStream(ctx context.Context, from, to model.Time, label model.LabelName, hint *storage.LabelHints, partialDataEnabled bool, matchers ...*labels.Matcher) ([]string, error)
3434
LabelNames(context.Context, model.Time, model.Time, *storage.LabelHints, bool, ...*labels.Matcher) ([]string, error)
3535
LabelNamesStream(context.Context, model.Time, model.Time, *storage.LabelHints, bool, ...*labels.Matcher) ([]string, error)
36-
MetricsForLabelMatchers(ctx context.Context, from, through model.Time, hint *storage.SelectHints, partialDataEnabled bool, matchers ...*labels.Matcher) ([]model.Metric, error)
37-
MetricsForLabelMatchersStream(ctx context.Context, from, through model.Time, hint *storage.SelectHints, partialDataEnabled bool, matchers ...*labels.Matcher) ([]model.Metric, error)
36+
MetricsForLabelMatchers(ctx context.Context, from, through model.Time, hint *storage.SelectHints, partialDataEnabled bool, matchers ...*labels.Matcher) ([]labels.Labels, error)
37+
MetricsForLabelMatchersStream(ctx context.Context, from, through model.Time, hint *storage.SelectHints, partialDataEnabled bool, matchers ...*labels.Matcher) ([]labels.Labels, error)
3838
MetricsMetadata(ctx context.Context, req *client.MetricsMetadataRequest) ([]scrape.MetricMetadata, error)
3939
}
4040

@@ -122,7 +122,7 @@ func (q *distributorQuerier) Select(ctx context.Context, sortSeries bool, sp *st
122122
// See: https://github.com/prometheus/prometheus/pull/8050
123123
if sp != nil && sp.Func == "series" {
124124
var (
125-
ms []model.Metric
125+
ms []labels.Labels
126126
err error
127127
)
128128

@@ -136,14 +136,14 @@ func (q *distributorQuerier) Select(ctx context.Context, sortSeries bool, sp *st
136136
return storage.ErrSeriesSet(err)
137137
}
138138

139-
seriesSet := series.MetricsToSeriesSet(ctx, sortSeries, ms)
139+
seriesSet := series.LabelsSetToSeriesSet(sortSeries, ms)
140140

141141
if partialdata.IsPartialDataError(err) {
142142
warning := seriesSet.Warnings()
143143
return series.NewSeriesSetWithWarnings(seriesSet, warning.Add(err))
144144
}
145145

146-
return series.MetricsToSeriesSet(ctx, sortSeries, ms)
146+
return seriesSet
147147
}
148148

149149
return q.streamingSelect(ctx, sortSeries, partialDataEnabled, minT, maxT, matchers)
@@ -249,7 +249,7 @@ func (q *distributorQuerier) labelNamesWithMatchers(ctx context.Context, hints *
249249
defer log.Span.Finish()
250250

251251
var (
252-
ms []model.Metric
252+
ms []labels.Labels
253253
err error
254254
)
255255

@@ -265,8 +265,8 @@ func (q *distributorQuerier) labelNamesWithMatchers(ctx context.Context, hints *
265265
namesMap := make(map[string]struct{})
266266

267267
for _, m := range ms {
268-
for name := range m {
269-
namesMap[string(name)] = struct{}{}
268+
for _, l := range m {
269+
namesMap[l.Name] = struct{}{}
270270
}
271271
}
272272

Diff for: pkg/querier/distributor_queryable_test.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -224,10 +224,10 @@ func TestDistributorQuerier_LabelNames(t *testing.T) {
224224
t.Run("with matchers", func(t *testing.T) {
225225
t.Parallel()
226226

227-
metrics := []model.Metric{
228-
{"foo": "bar"},
229-
{"job": "baz"},
230-
{"job": "baz", "foo": "boom"},
227+
metrics := []labels.Labels{
228+
labels.FromStrings("foo", "bar"),
229+
labels.FromStrings("job", "baz"),
230+
labels.FromStrings("job", "baz", "foo", "boom"),
231231
}
232232
d := &MockDistributor{}
233233

Diff for: pkg/querier/series/series_set.go

+39
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package series
1818

1919
import (
2020
"context"
21+
"slices"
2122
"sort"
2223

2324
"github.com/prometheus/common/model"
@@ -30,6 +31,44 @@ import (
3031
"github.com/cortexproject/cortex/pkg/util"
3132
)
3233

34+
type labelsSetSeriesSet struct {
35+
cur int
36+
labelsSet []labels.Labels
37+
}
38+
39+
// LabelsSetToSeriesSet creates a storage.SeriesSet from a []labels.Labels.
40+
func LabelsSetToSeriesSet(sortSeries bool, labelsSet []labels.Labels) storage.SeriesSet {
41+
if sortSeries {
42+
slices.SortFunc(labelsSet, func(a, b labels.Labels) int { return labels.Compare(a, b) })
43+
}
44+
return &labelsSetSeriesSet{
45+
cur: -1,
46+
labelsSet: labelsSet,
47+
}
48+
}
49+
50+
// Next iterates through a series set and implements storage.SeriesSet.
51+
func (c *labelsSetSeriesSet) Next() bool {
52+
c.cur++
53+
return c.cur < len(c.labelsSet)
54+
}
55+
56+
// At returns the current series and implements storage.SeriesSet.
57+
func (c *labelsSetSeriesSet) At() storage.Series {
58+
lset := c.labelsSet[c.cur]
59+
return &ConcreteSeries{labels: lset}
60+
}
61+
62+
// Err implements storage.SeriesSet.
63+
func (c *labelsSetSeriesSet) Err() error {
64+
return nil
65+
}
66+
67+
// Warnings implements storage.SeriesSet.
68+
func (c *labelsSetSeriesSet) Warnings() annotations.Annotations {
69+
return nil
70+
}
71+
3372
// ConcreteSeriesSet implements storage.SeriesSet.
3473
type ConcreteSeriesSet struct {
3574
cur int

Diff for: pkg/querier/testutils.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -49,13 +49,13 @@ func (m *MockDistributor) LabelNamesStream(ctx context.Context, from model.Time,
4949
args := m.Called(ctx, from, to, hints, matchers)
5050
return args.Get(0).([]string), args.Error(1)
5151
}
52-
func (m *MockDistributor) MetricsForLabelMatchers(ctx context.Context, from, to model.Time, hints *storage.SelectHints, partialDataEnabled bool, matchers ...*labels.Matcher) ([]model.Metric, error) {
52+
func (m *MockDistributor) MetricsForLabelMatchers(ctx context.Context, from, to model.Time, hints *storage.SelectHints, partialDataEnabled bool, matchers ...*labels.Matcher) ([]labels.Labels, error) {
5353
args := m.Called(ctx, from, to, hints, matchers)
54-
return args.Get(0).([]model.Metric), args.Error(1)
54+
return args.Get(0).([]labels.Labels), args.Error(1)
5555
}
56-
func (m *MockDistributor) MetricsForLabelMatchersStream(ctx context.Context, from, to model.Time, hints *storage.SelectHints, partialDataEnabled bool, matchers ...*labels.Matcher) ([]model.Metric, error) {
56+
func (m *MockDistributor) MetricsForLabelMatchersStream(ctx context.Context, from, to model.Time, hints *storage.SelectHints, partialDataEnabled bool, matchers ...*labels.Matcher) ([]labels.Labels, error) {
5757
args := m.Called(ctx, from, to, hints, matchers)
58-
return args.Get(0).([]model.Metric), args.Error(1)
58+
return args.Get(0).([]labels.Labels), args.Error(1)
5959
}
6060

6161
func (m *MockDistributor) MetricsMetadata(ctx context.Context, request *client.MetricsMetadataRequest) ([]scrape.MetricMetadata, error) {

0 commit comments

Comments
 (0)