mirror of
				https://github.com/prometheus/prometheus.git
				synced 2025-11-03 18:01:18 +01:00 
			
		
		
		
	Replacing code which assumes the internal structure of `Labels`. Signed-off-by: Bryan Boreham <bjboreham@gmail.com>
		
			
				
	
	
		
			497 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			497 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
// Copyright 2020 The Prometheus Authors
 | 
						|
// Licensed under the Apache License, Version 2.0 (the "License");
 | 
						|
// you may not use this file except in compliance with the License.
 | 
						|
// You may obtain a copy of the License at
 | 
						|
//
 | 
						|
// http://www.apache.org/licenses/LICENSE-2.0
 | 
						|
//
 | 
						|
// Unless required by applicable law or agreed to in writing, software
 | 
						|
// distributed under the License is distributed on an "AS IS" BASIS,
 | 
						|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
						|
// See the License for the specific language governing permissions and
 | 
						|
// limitations under the License.
 | 
						|
 | 
						|
package tsdb
 | 
						|
 | 
						|
import (
 | 
						|
	"context"
 | 
						|
	"fmt"
 | 
						|
	"math"
 | 
						|
	"reflect"
 | 
						|
	"strconv"
 | 
						|
	"strings"
 | 
						|
	"testing"
 | 
						|
 | 
						|
	"github.com/prometheus/client_golang/prometheus"
 | 
						|
	"github.com/stretchr/testify/require"
 | 
						|
 | 
						|
	"github.com/prometheus/prometheus/model/exemplar"
 | 
						|
	"github.com/prometheus/prometheus/model/labels"
 | 
						|
	"github.com/prometheus/prometheus/storage"
 | 
						|
)
 | 
						|
 | 
						|
var eMetrics = NewExemplarMetrics(prometheus.DefaultRegisterer)
 | 
						|
 | 
						|
// Tests the same exemplar cases as AddExemplar, but specifically the ValidateExemplar function so it can be relied on externally.
 | 
						|
func TestValidateExemplar(t *testing.T) {
 | 
						|
	exs, err := NewCircularExemplarStorage(2, eMetrics)
 | 
						|
	require.NoError(t, err)
 | 
						|
	es := exs.(*CircularExemplarStorage)
 | 
						|
 | 
						|
	l := labels.FromStrings("service", "asdf")
 | 
						|
	e := exemplar.Exemplar{
 | 
						|
		Labels: labels.FromStrings("traceID", "qwerty"),
 | 
						|
		Value:  0.1,
 | 
						|
		Ts:     1,
 | 
						|
	}
 | 
						|
 | 
						|
	require.NoError(t, es.ValidateExemplar(l, e))
 | 
						|
	require.NoError(t, es.AddExemplar(l, e))
 | 
						|
 | 
						|
	e2 := exemplar.Exemplar{
 | 
						|
		Labels: labels.FromStrings("traceID", "zxcvb"),
 | 
						|
		Value:  0.1,
 | 
						|
		Ts:     2,
 | 
						|
	}
 | 
						|
 | 
						|
	require.NoError(t, es.ValidateExemplar(l, e2))
 | 
						|
	require.NoError(t, es.AddExemplar(l, e2))
 | 
						|
 | 
						|
	require.Equal(t, es.ValidateExemplar(l, e2), storage.ErrDuplicateExemplar, "error is expected attempting to validate duplicate exemplar")
 | 
						|
 | 
						|
	e3 := e2
 | 
						|
	e3.Ts = 3
 | 
						|
	require.Equal(t, es.ValidateExemplar(l, e3), storage.ErrDuplicateExemplar, "error is expected when attempting to add duplicate exemplar, even with different timestamp")
 | 
						|
 | 
						|
	e3.Ts = 1
 | 
						|
	e3.Value = 0.3
 | 
						|
	require.Equal(t, es.ValidateExemplar(l, e3), storage.ErrOutOfOrderExemplar)
 | 
						|
 | 
						|
	e4 := exemplar.Exemplar{
 | 
						|
		Labels: labels.FromStrings("a", strings.Repeat("b", exemplar.ExemplarMaxLabelSetLength)),
 | 
						|
		Value:  0.1,
 | 
						|
		Ts:     2,
 | 
						|
	}
 | 
						|
	require.Equal(t, storage.ErrExemplarLabelLength, es.ValidateExemplar(l, e4))
 | 
						|
}
 | 
						|
 | 
						|
func TestAddExemplar(t *testing.T) {
 | 
						|
	exs, err := NewCircularExemplarStorage(2, eMetrics)
 | 
						|
	require.NoError(t, err)
 | 
						|
	es := exs.(*CircularExemplarStorage)
 | 
						|
 | 
						|
	l := labels.FromStrings("service", "asdf")
 | 
						|
	e := exemplar.Exemplar{
 | 
						|
		Labels: labels.FromStrings("traceID", "qwerty"),
 | 
						|
		Value:  0.1,
 | 
						|
		Ts:     1,
 | 
						|
	}
 | 
						|
 | 
						|
	require.NoError(t, es.AddExemplar(l, e))
 | 
						|
	require.Equal(t, es.index[string(l.Bytes(nil))].newest, 0, "exemplar was not stored correctly")
 | 
						|
 | 
						|
	e2 := exemplar.Exemplar{
 | 
						|
		Labels: labels.FromStrings("traceID", "zxcvb"),
 | 
						|
		Value:  0.1,
 | 
						|
		Ts:     2,
 | 
						|
	}
 | 
						|
 | 
						|
	require.NoError(t, es.AddExemplar(l, e2))
 | 
						|
	require.Equal(t, es.index[string(l.Bytes(nil))].newest, 1, "exemplar was not stored correctly, location of newest exemplar for series in index did not update")
 | 
						|
	require.True(t, es.exemplars[es.index[string(l.Bytes(nil))].newest].exemplar.Equals(e2), "exemplar was not stored correctly, expected %+v got: %+v", e2, es.exemplars[es.index[string(l.Bytes(nil))].newest].exemplar)
 | 
						|
 | 
						|
	require.NoError(t, es.AddExemplar(l, e2), "no error is expected attempting to add duplicate exemplar")
 | 
						|
 | 
						|
	e3 := e2
 | 
						|
	e3.Ts = 3
 | 
						|
	require.NoError(t, es.AddExemplar(l, e3), "no error is expected when attempting to add duplicate exemplar, even with different timestamp")
 | 
						|
 | 
						|
	e3.Ts = 1
 | 
						|
	e3.Value = 0.3
 | 
						|
	require.Equal(t, storage.ErrOutOfOrderExemplar, es.AddExemplar(l, e3))
 | 
						|
 | 
						|
	e4 := exemplar.Exemplar{
 | 
						|
		Labels: labels.FromStrings("a", strings.Repeat("b", exemplar.ExemplarMaxLabelSetLength)),
 | 
						|
		Value:  0.1,
 | 
						|
		Ts:     2,
 | 
						|
	}
 | 
						|
	require.Equal(t, storage.ErrExemplarLabelLength, es.AddExemplar(l, e4))
 | 
						|
}
 | 
						|
 | 
						|
func TestStorageOverflow(t *testing.T) {
 | 
						|
	// Test that circular buffer index and assignment
 | 
						|
	// works properly, adding more exemplars than can
 | 
						|
	// be stored and then querying for them.
 | 
						|
	exs, err := NewCircularExemplarStorage(5, eMetrics)
 | 
						|
	require.NoError(t, err)
 | 
						|
	es := exs.(*CircularExemplarStorage)
 | 
						|
 | 
						|
	lName, lValue := "service", "asdf"
 | 
						|
	l := labels.FromStrings(lName, lValue)
 | 
						|
 | 
						|
	var eList []exemplar.Exemplar
 | 
						|
	for i := 0; i < len(es.exemplars)+1; i++ {
 | 
						|
		e := exemplar.Exemplar{
 | 
						|
			Labels: labels.FromStrings("traceID", "a"),
 | 
						|
			Value:  float64(i+1) / 10,
 | 
						|
			Ts:     int64(101 + i),
 | 
						|
		}
 | 
						|
		es.AddExemplar(l, e)
 | 
						|
		eList = append(eList, e)
 | 
						|
	}
 | 
						|
	require.True(t, (es.exemplars[0].exemplar.Ts == 106), "exemplar was not stored correctly")
 | 
						|
 | 
						|
	m, err := labels.NewMatcher(labels.MatchEqual, lName, lValue)
 | 
						|
	require.NoError(t, err, "error creating label matcher for exemplar query")
 | 
						|
	ret, err := es.Select(100, 110, []*labels.Matcher{m})
 | 
						|
	require.NoError(t, err)
 | 
						|
	require.True(t, len(ret) == 1, "select should have returned samples for a single series only")
 | 
						|
 | 
						|
	require.True(t, reflect.DeepEqual(eList[1:], ret[0].Exemplars), "select did not return expected exemplars\n\texpected: %+v\n\tactual: %+v\n", eList[1:], ret[0].Exemplars)
 | 
						|
}
 | 
						|
 | 
						|
func TestSelectExemplar(t *testing.T) {
 | 
						|
	exs, err := NewCircularExemplarStorage(5, eMetrics)
 | 
						|
	require.NoError(t, err)
 | 
						|
	es := exs.(*CircularExemplarStorage)
 | 
						|
 | 
						|
	lName, lValue := "service", "asdf"
 | 
						|
	l := labels.FromStrings(lName, lValue)
 | 
						|
	e := exemplar.Exemplar{
 | 
						|
		Labels: labels.FromStrings("traceID", "querty"),
 | 
						|
		Value:  0.1,
 | 
						|
		Ts:     12,
 | 
						|
	}
 | 
						|
 | 
						|
	err = es.AddExemplar(l, e)
 | 
						|
	require.NoError(t, err, "adding exemplar failed")
 | 
						|
	require.True(t, reflect.DeepEqual(es.exemplars[0].exemplar, e), "exemplar was not stored correctly")
 | 
						|
 | 
						|
	m, err := labels.NewMatcher(labels.MatchEqual, lName, lValue)
 | 
						|
	require.NoError(t, err, "error creating label matcher for exemplar query")
 | 
						|
	ret, err := es.Select(0, 100, []*labels.Matcher{m})
 | 
						|
	require.NoError(t, err)
 | 
						|
	require.True(t, len(ret) == 1, "select should have returned samples for a single series only")
 | 
						|
 | 
						|
	expectedResult := []exemplar.Exemplar{e}
 | 
						|
	require.True(t, reflect.DeepEqual(expectedResult, ret[0].Exemplars), "select did not return expected exemplars\n\texpected: %+v\n\tactual: %+v\n", expectedResult, ret[0].Exemplars)
 | 
						|
}
 | 
						|
 | 
						|
func TestSelectExemplar_MultiSeries(t *testing.T) {
 | 
						|
	exs, err := NewCircularExemplarStorage(5, eMetrics)
 | 
						|
	require.NoError(t, err)
 | 
						|
	es := exs.(*CircularExemplarStorage)
 | 
						|
 | 
						|
	l1Name := "test_metric"
 | 
						|
	l1 := labels.FromStrings(labels.MetricName, l1Name, "service", "asdf")
 | 
						|
	l2Name := "test_metric2"
 | 
						|
	l2 := labels.FromStrings(labels.MetricName, l2Name, "service", "qwer")
 | 
						|
 | 
						|
	for i := 0; i < len(es.exemplars); i++ {
 | 
						|
		e1 := exemplar.Exemplar{
 | 
						|
			Labels: labels.FromStrings("traceID", "a"),
 | 
						|
			Value:  float64(i+1) / 10,
 | 
						|
			Ts:     int64(101 + i),
 | 
						|
		}
 | 
						|
		err = es.AddExemplar(l1, e1)
 | 
						|
		require.NoError(t, err)
 | 
						|
 | 
						|
		e2 := exemplar.Exemplar{
 | 
						|
			Labels: labels.FromStrings("traceID", "b"),
 | 
						|
			Value:  float64(i+1) / 10,
 | 
						|
			Ts:     int64(101 + i),
 | 
						|
		}
 | 
						|
		err = es.AddExemplar(l2, e2)
 | 
						|
		require.NoError(t, err)
 | 
						|
	}
 | 
						|
 | 
						|
	m, err := labels.NewMatcher(labels.MatchEqual, labels.MetricName, l2Name)
 | 
						|
	require.NoError(t, err, "error creating label matcher for exemplar query")
 | 
						|
	ret, err := es.Select(100, 200, []*labels.Matcher{m})
 | 
						|
	require.NoError(t, err)
 | 
						|
	require.True(t, len(ret) == 1, "select should have returned samples for a single series only")
 | 
						|
	require.True(t, len(ret[0].Exemplars) == 3, "didn't get expected 8 exemplars, got %d", len(ret[0].Exemplars))
 | 
						|
 | 
						|
	m, err = labels.NewMatcher(labels.MatchEqual, labels.MetricName, l1Name)
 | 
						|
	require.NoError(t, err, "error creating label matcher for exemplar query")
 | 
						|
	ret, err = es.Select(100, 200, []*labels.Matcher{m})
 | 
						|
	require.NoError(t, err)
 | 
						|
	require.True(t, len(ret) == 1, "select should have returned samples for a single series only")
 | 
						|
	require.True(t, len(ret[0].Exemplars) == 2, "didn't get expected 8 exemplars, got %d", len(ret[0].Exemplars))
 | 
						|
}
 | 
						|
 | 
						|
func TestSelectExemplar_TimeRange(t *testing.T) {
 | 
						|
	var lenEs int64 = 5
 | 
						|
	exs, err := NewCircularExemplarStorage(lenEs, eMetrics)
 | 
						|
	require.NoError(t, err)
 | 
						|
	es := exs.(*CircularExemplarStorage)
 | 
						|
 | 
						|
	lName, lValue := "service", "asdf"
 | 
						|
	l := labels.FromStrings(lName, lValue)
 | 
						|
 | 
						|
	for i := 0; int64(i) < lenEs; i++ {
 | 
						|
		err := es.AddExemplar(l, exemplar.Exemplar{
 | 
						|
			Labels: labels.FromStrings("traceID", strconv.Itoa(i)),
 | 
						|
			Value:  0.1,
 | 
						|
			Ts:     int64(101 + i),
 | 
						|
		})
 | 
						|
		require.NoError(t, err)
 | 
						|
		require.Equal(t, es.index[string(l.Bytes(nil))].newest, i, "exemplar was not stored correctly")
 | 
						|
	}
 | 
						|
 | 
						|
	m, err := labels.NewMatcher(labels.MatchEqual, lName, lValue)
 | 
						|
	require.NoError(t, err, "error creating label matcher for exemplar query")
 | 
						|
	ret, err := es.Select(102, 104, []*labels.Matcher{m})
 | 
						|
	require.NoError(t, err)
 | 
						|
	require.True(t, len(ret) == 1, "select should have returned samples for a single series only")
 | 
						|
	require.True(t, len(ret[0].Exemplars) == 3, "didn't get expected two exemplars %d, %+v", len(ret[0].Exemplars), ret)
 | 
						|
}
 | 
						|
 | 
						|
// Test to ensure that even though a series matches more than one matcher from the
 | 
						|
// query that it's exemplars are only included in the result a single time.
 | 
						|
func TestSelectExemplar_DuplicateSeries(t *testing.T) {
 | 
						|
	exs, err := NewCircularExemplarStorage(4, eMetrics)
 | 
						|
	require.NoError(t, err)
 | 
						|
	es := exs.(*CircularExemplarStorage)
 | 
						|
 | 
						|
	e := exemplar.Exemplar{
 | 
						|
		Labels: labels.FromStrings("traceID", "qwerty"),
 | 
						|
		Value:  0.1,
 | 
						|
		Ts:     12,
 | 
						|
	}
 | 
						|
 | 
						|
	lName0, lValue0 := "service", "asdf"
 | 
						|
	lName1, lValue1 := "cluster", "us-central1"
 | 
						|
	l := labels.FromStrings(lName0, lValue0, lName1, lValue1)
 | 
						|
 | 
						|
	// Lets just assume somehow the PromQL expression generated two separate lists of matchers,
 | 
						|
	// both of which can select this particular series.
 | 
						|
	m := [][]*labels.Matcher{
 | 
						|
		{
 | 
						|
			labels.MustNewMatcher(labels.MatchEqual, lName0, lValue0),
 | 
						|
		},
 | 
						|
		{
 | 
						|
			labels.MustNewMatcher(labels.MatchEqual, lName1, lValue1),
 | 
						|
		},
 | 
						|
	}
 | 
						|
 | 
						|
	err = es.AddExemplar(l, e)
 | 
						|
	require.NoError(t, err, "adding exemplar failed")
 | 
						|
	require.True(t, reflect.DeepEqual(es.exemplars[0].exemplar, e), "exemplar was not stored correctly")
 | 
						|
 | 
						|
	ret, err := es.Select(0, 100, m...)
 | 
						|
	require.NoError(t, err)
 | 
						|
	require.True(t, len(ret) == 1, "select should have returned samples for a single series only")
 | 
						|
}
 | 
						|
 | 
						|
func TestIndexOverwrite(t *testing.T) {
 | 
						|
	exs, err := NewCircularExemplarStorage(2, eMetrics)
 | 
						|
	require.NoError(t, err)
 | 
						|
	es := exs.(*CircularExemplarStorage)
 | 
						|
 | 
						|
	l1 := labels.FromStrings("service", "asdf")
 | 
						|
	l2 := labels.FromStrings("service", "qwer")
 | 
						|
 | 
						|
	err = es.AddExemplar(l1, exemplar.Exemplar{Value: 1, Ts: 1})
 | 
						|
	require.NoError(t, err)
 | 
						|
	err = es.AddExemplar(l2, exemplar.Exemplar{Value: 2, Ts: 2})
 | 
						|
	require.NoError(t, err)
 | 
						|
	err = es.AddExemplar(l2, exemplar.Exemplar{Value: 3, Ts: 3})
 | 
						|
	require.NoError(t, err)
 | 
						|
 | 
						|
	// Ensure index GC'ing is taking place, there should no longer be any
 | 
						|
	// index entry for series l1 since we just wrote two exemplars for series l2.
 | 
						|
	_, ok := es.index[string(l1.Bytes(nil))]
 | 
						|
	require.False(t, ok)
 | 
						|
	require.Equal(t, &indexEntry{1, 0, l2}, es.index[string(l2.Bytes(nil))])
 | 
						|
 | 
						|
	err = es.AddExemplar(l1, exemplar.Exemplar{Value: 4, Ts: 4})
 | 
						|
	require.NoError(t, err)
 | 
						|
 | 
						|
	i := es.index[string(l2.Bytes(nil))]
 | 
						|
	require.Equal(t, &indexEntry{0, 0, l2}, i)
 | 
						|
}
 | 
						|
 | 
						|
func TestResize(t *testing.T) {
 | 
						|
	testCases := []struct {
 | 
						|
		name              string
 | 
						|
		startSize         int64
 | 
						|
		newCount          int64
 | 
						|
		expectedSeries    []int
 | 
						|
		notExpectedSeries []int
 | 
						|
		expectedMigrated  int
 | 
						|
	}{
 | 
						|
		{
 | 
						|
			name:              "Grow",
 | 
						|
			startSize:         100,
 | 
						|
			newCount:          200,
 | 
						|
			expectedSeries:    []int{99, 98, 1, 0},
 | 
						|
			notExpectedSeries: []int{100},
 | 
						|
			expectedMigrated:  100,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name:              "Shrink",
 | 
						|
			startSize:         100,
 | 
						|
			newCount:          50,
 | 
						|
			expectedSeries:    []int{99, 98, 50},
 | 
						|
			notExpectedSeries: []int{49, 1, 0},
 | 
						|
			expectedMigrated:  50,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name:              "ShrinkToZero",
 | 
						|
			startSize:         100,
 | 
						|
			newCount:          0,
 | 
						|
			expectedSeries:    []int{},
 | 
						|
			notExpectedSeries: []int{},
 | 
						|
			expectedMigrated:  0,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name:              "Negative",
 | 
						|
			startSize:         100,
 | 
						|
			newCount:          -1,
 | 
						|
			expectedSeries:    []int{},
 | 
						|
			notExpectedSeries: []int{},
 | 
						|
			expectedMigrated:  0,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name:              "NegativeToNegative",
 | 
						|
			startSize:         -1,
 | 
						|
			newCount:          -2,
 | 
						|
			expectedSeries:    []int{},
 | 
						|
			notExpectedSeries: []int{},
 | 
						|
			expectedMigrated:  0,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name:              "GrowFromZero",
 | 
						|
			startSize:         0,
 | 
						|
			newCount:          10,
 | 
						|
			expectedSeries:    []int{},
 | 
						|
			notExpectedSeries: []int{},
 | 
						|
			expectedMigrated:  0,
 | 
						|
		},
 | 
						|
	}
 | 
						|
 | 
						|
	for _, tc := range testCases {
 | 
						|
		t.Run(tc.name, func(t *testing.T) {
 | 
						|
			exs, err := NewCircularExemplarStorage(tc.startSize, eMetrics)
 | 
						|
			require.NoError(t, err)
 | 
						|
			es := exs.(*CircularExemplarStorage)
 | 
						|
 | 
						|
			for i := 0; int64(i) < tc.startSize; i++ {
 | 
						|
				err = es.AddExemplar(labels.FromStrings("service", strconv.Itoa(i)), exemplar.Exemplar{
 | 
						|
					Value: float64(i),
 | 
						|
					Ts:    int64(i),
 | 
						|
				})
 | 
						|
				require.NoError(t, err)
 | 
						|
			}
 | 
						|
 | 
						|
			resized := es.Resize(tc.newCount)
 | 
						|
			require.Equal(t, tc.expectedMigrated, resized)
 | 
						|
 | 
						|
			q, err := es.Querier(context.TODO())
 | 
						|
			require.NoError(t, err)
 | 
						|
 | 
						|
			matchers := []*labels.Matcher{labels.MustNewMatcher(labels.MatchEqual, "service", "")}
 | 
						|
 | 
						|
			for _, expected := range tc.expectedSeries {
 | 
						|
				matchers[0].Value = strconv.Itoa(expected)
 | 
						|
				ex, err := q.Select(0, math.MaxInt64, matchers)
 | 
						|
				require.NoError(t, err)
 | 
						|
				require.NotEmpty(t, ex)
 | 
						|
			}
 | 
						|
 | 
						|
			for _, notExpected := range tc.notExpectedSeries {
 | 
						|
				matchers[0].Value = strconv.Itoa(notExpected)
 | 
						|
				ex, err := q.Select(0, math.MaxInt64, matchers)
 | 
						|
				require.NoError(t, err)
 | 
						|
				require.Empty(t, ex)
 | 
						|
			}
 | 
						|
		})
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func BenchmarkAddExemplar(b *testing.B) {
 | 
						|
	// We need to include these labels since we do length calculation
 | 
						|
	// before adding.
 | 
						|
	exLabels := labels.FromStrings("traceID", "89620921")
 | 
						|
 | 
						|
	for _, n := range []int{10000, 100000, 1000000} {
 | 
						|
		b.Run(fmt.Sprintf("%d", n), func(b *testing.B) {
 | 
						|
			for j := 0; j < b.N; j++ {
 | 
						|
				b.StopTimer()
 | 
						|
				exs, err := NewCircularExemplarStorage(int64(n), eMetrics)
 | 
						|
				require.NoError(b, err)
 | 
						|
				es := exs.(*CircularExemplarStorage)
 | 
						|
				var l labels.Labels
 | 
						|
				b.StartTimer()
 | 
						|
 | 
						|
				for i := 0; i < n; i++ {
 | 
						|
					if i%100 == 0 {
 | 
						|
						l = labels.FromStrings("service", strconv.Itoa(i))
 | 
						|
					}
 | 
						|
					err = es.AddExemplar(l, exemplar.Exemplar{Value: float64(i), Ts: int64(i), Labels: exLabels})
 | 
						|
					if err != nil {
 | 
						|
						require.NoError(b, err)
 | 
						|
					}
 | 
						|
				}
 | 
						|
			}
 | 
						|
		})
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func BenchmarkResizeExemplars(b *testing.B) {
 | 
						|
	testCases := []struct {
 | 
						|
		name         string
 | 
						|
		startSize    int64
 | 
						|
		endSize      int64
 | 
						|
		numExemplars int
 | 
						|
	}{
 | 
						|
		{
 | 
						|
			name:         "grow",
 | 
						|
			startSize:    100000,
 | 
						|
			endSize:      200000,
 | 
						|
			numExemplars: 150000,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name:         "shrink",
 | 
						|
			startSize:    100000,
 | 
						|
			endSize:      50000,
 | 
						|
			numExemplars: 100000,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name:         "grow",
 | 
						|
			startSize:    1000000,
 | 
						|
			endSize:      2000000,
 | 
						|
			numExemplars: 1500000,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name:         "shrink",
 | 
						|
			startSize:    1000000,
 | 
						|
			endSize:      500000,
 | 
						|
			numExemplars: 1000000,
 | 
						|
		},
 | 
						|
	}
 | 
						|
 | 
						|
	for _, tc := range testCases {
 | 
						|
		b.Run(fmt.Sprintf("%s-%d-to-%d", tc.name, tc.startSize, tc.endSize), func(b *testing.B) {
 | 
						|
			for j := 0; j < b.N; j++ {
 | 
						|
				b.StopTimer()
 | 
						|
				exs, err := NewCircularExemplarStorage(tc.startSize, eMetrics)
 | 
						|
				require.NoError(b, err)
 | 
						|
				es := exs.(*CircularExemplarStorage)
 | 
						|
 | 
						|
				for i := 0; i < int(float64(tc.startSize)*float64(1.5)); i++ {
 | 
						|
					l := labels.FromStrings("service", strconv.Itoa(i))
 | 
						|
 | 
						|
					err = es.AddExemplar(l, exemplar.Exemplar{Value: float64(i), Ts: int64(i)})
 | 
						|
					if err != nil {
 | 
						|
						require.NoError(b, err)
 | 
						|
					}
 | 
						|
				}
 | 
						|
				b.StartTimer()
 | 
						|
				es.Resize(tc.endSize)
 | 
						|
			}
 | 
						|
		})
 | 
						|
	}
 | 
						|
}
 |