2021-03-16 09:47:45 +00:00
// 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 (
2021-07-20 04:52:57 +00:00
"context"
"fmt"
"math"
2021-03-16 09:47:45 +00:00
"reflect"
"strconv"
2021-05-06 20:53:52 +00:00
"strings"
2024-10-29 09:40:46 +00:00
"sync"
2021-03-16 09:47:45 +00:00
"testing"
2021-10-22 08:19:38 +00:00
"github.com/prometheus/client_golang/prometheus"
2021-03-16 09:47:45 +00:00
"github.com/stretchr/testify/require"
2021-11-08 14:23:17 +00:00
"github.com/prometheus/prometheus/model/exemplar"
"github.com/prometheus/prometheus/model/labels"
2021-03-16 09:47:45 +00:00
"github.com/prometheus/prometheus/storage"
)
2021-07-20 04:52:57 +00:00
var eMetrics = NewExemplarMetrics ( prometheus . DefaultRegisterer )
2021-05-20 01:51:45 +00:00
// Tests the same exemplar cases as AddExemplar, but specifically the ValidateExemplar function so it can be relied on externally.
2021-05-06 20:53:52 +00:00
func TestValidateExemplar ( t * testing . T ) {
2021-07-20 04:52:57 +00:00
exs , err := NewCircularExemplarStorage ( 2 , eMetrics )
2021-03-16 09:47:45 +00:00
require . NoError ( t , err )
es := exs . ( * CircularExemplarStorage )
2022-03-09 22:17:29 +00:00
l := labels . FromStrings ( "service" , "asdf" )
2021-03-16 09:47:45 +00:00
e := exemplar . Exemplar {
2024-02-15 14:19:54 +00:00
Labels : labels . FromStrings ( "trace_id" , "qwerty" ) ,
2022-03-09 22:17:29 +00:00
Value : 0.1 ,
Ts : 1 ,
2021-03-16 09:47:45 +00:00
}
2021-05-06 20:53:52 +00:00
require . NoError ( t , es . ValidateExemplar ( l , e ) )
require . NoError ( t , es . AddExemplar ( l , e ) )
e2 := exemplar . Exemplar {
2024-02-15 14:19:54 +00:00
Labels : labels . FromStrings ( "trace_id" , "zxcvb" ) ,
2022-03-09 22:17:29 +00:00
Value : 0.1 ,
Ts : 2 ,
2021-05-06 20:53:52 +00:00
}
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 {
2022-03-09 22:17:29 +00:00
Labels : labels . FromStrings ( "a" , strings . Repeat ( "b" , exemplar . ExemplarMaxLabelSetLength ) ) ,
Value : 0.1 ,
Ts : 2 ,
2021-05-06 20:53:52 +00:00
}
require . Equal ( t , storage . ErrExemplarLabelLength , es . ValidateExemplar ( l , e4 ) )
}
func TestAddExemplar ( t * testing . T ) {
2021-07-20 04:52:57 +00:00
exs , err := NewCircularExemplarStorage ( 2 , eMetrics )
2021-03-16 09:47:45 +00:00
require . NoError ( t , err )
2021-05-06 20:53:52 +00:00
es := exs . ( * CircularExemplarStorage )
2022-03-09 22:17:29 +00:00
l := labels . FromStrings ( "service" , "asdf" )
2021-05-06 20:53:52 +00:00
e := exemplar . Exemplar {
2024-02-15 14:19:54 +00:00
Labels : labels . FromStrings ( "trace_id" , "qwerty" ) ,
2022-03-09 22:17:29 +00:00
Value : 0.1 ,
Ts : 1 ,
2021-05-06 20:53:52 +00:00
}
require . NoError ( t , es . AddExemplar ( l , e ) )
2023-12-07 11:35:01 +00:00
require . Equal ( t , 0 , es . index [ string ( l . Bytes ( nil ) ) ] . newest , "exemplar was not stored correctly" )
2021-03-16 09:47:45 +00:00
e2 := exemplar . Exemplar {
2024-02-15 14:19:54 +00:00
Labels : labels . FromStrings ( "trace_id" , "zxcvb" ) ,
2022-03-09 22:17:29 +00:00
Value : 0.1 ,
Ts : 2 ,
2021-03-16 09:47:45 +00:00
}
2021-05-06 20:53:52 +00:00
require . NoError ( t , es . AddExemplar ( l , e2 ) )
2023-12-07 11:35:01 +00:00
require . Equal ( t , 1 , es . index [ string ( l . Bytes ( nil ) ) ] . newest , "exemplar was not stored correctly, location of newest exemplar for series in index did not update" )
2022-01-06 10:28:58 +00:00
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 )
2021-03-16 09:47:45 +00:00
2021-05-06 20:53:52 +00:00
require . NoError ( t , es . AddExemplar ( l , e2 ) , "no error is expected attempting to add duplicate exemplar" )
2021-03-16 09:47:45 +00:00
e3 := e2
e3 . Ts = 3
2021-05-06 20:53:52 +00:00
require . NoError ( t , es . AddExemplar ( l , e3 ) , "no error is expected when attempting to add duplicate exemplar, even with different timestamp" )
2021-03-16 09:47:45 +00:00
e3 . Ts = 1
e3 . Value = 0.3
2021-05-06 20:53:52 +00:00
require . Equal ( t , storage . ErrOutOfOrderExemplar , es . AddExemplar ( l , e3 ) )
e4 := exemplar . Exemplar {
2022-03-09 22:17:29 +00:00
Labels : labels . FromStrings ( "a" , strings . Repeat ( "b" , exemplar . ExemplarMaxLabelSetLength ) ) ,
Value : 0.1 ,
Ts : 2 ,
2021-05-06 20:53:52 +00:00
}
require . Equal ( t , storage . ErrExemplarLabelLength , es . AddExemplar ( l , e4 ) )
2021-03-16 09:47:45 +00:00
}
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.
2021-07-20 04:52:57 +00:00
exs , err := NewCircularExemplarStorage ( 5 , eMetrics )
2021-03-16 09:47:45 +00:00
require . NoError ( t , err )
es := exs . ( * CircularExemplarStorage )
2022-03-09 22:17:29 +00:00
lName , lValue := "service" , "asdf"
l := labels . FromStrings ( lName , lValue )
2021-03-16 09:47:45 +00:00
var eList [ ] exemplar . Exemplar
for i := 0 ; i < len ( es . exemplars ) + 1 ; i ++ {
e := exemplar . Exemplar {
2024-02-15 14:19:54 +00:00
Labels : labels . FromStrings ( "trace_id" , "a" ) ,
2022-03-09 22:17:29 +00:00
Value : float64 ( i + 1 ) / 10 ,
Ts : int64 ( 101 + i ) ,
2021-03-16 09:47:45 +00:00
}
es . AddExemplar ( l , e )
eList = append ( eList , e )
}
require . True ( t , ( es . exemplars [ 0 ] . exemplar . Ts == 106 ) , "exemplar was not stored correctly" )
2022-03-09 22:17:29 +00:00
m , err := labels . NewMatcher ( labels . MatchEqual , lName , lValue )
2021-03-16 09:47:45 +00:00
require . NoError ( t , err , "error creating label matcher for exemplar query" )
ret , err := es . Select ( 100 , 110 , [ ] * labels . Matcher { m } )
require . NoError ( t , err )
2023-12-07 11:35:01 +00:00
require . Len ( t , ret , 1 , "select should have returned samples for a single series only" )
2021-03-16 09:47:45 +00:00
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 ) {
2021-07-20 04:52:57 +00:00
exs , err := NewCircularExemplarStorage ( 5 , eMetrics )
2021-03-16 09:47:45 +00:00
require . NoError ( t , err )
es := exs . ( * CircularExemplarStorage )
2022-03-09 22:17:29 +00:00
lName , lValue := "service" , "asdf"
l := labels . FromStrings ( lName , lValue )
2021-03-16 09:47:45 +00:00
e := exemplar . Exemplar {
2024-02-15 14:19:54 +00:00
Labels : labels . FromStrings ( "trace_id" , "querty" ) ,
2022-03-09 22:17:29 +00:00
Value : 0.1 ,
Ts : 12 ,
2021-03-16 09:47:45 +00:00
}
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" )
2022-03-09 22:17:29 +00:00
m , err := labels . NewMatcher ( labels . MatchEqual , lName , lValue )
2021-03-16 09:47:45 +00:00
require . NoError ( t , err , "error creating label matcher for exemplar query" )
ret , err := es . Select ( 0 , 100 , [ ] * labels . Matcher { m } )
require . NoError ( t , err )
2023-12-07 11:35:01 +00:00
require . Len ( t , ret , 1 , "select should have returned samples for a single series only" )
2021-03-16 09:47:45 +00:00
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 ) {
2021-07-20 04:52:57 +00:00
exs , err := NewCircularExemplarStorage ( 5 , eMetrics )
2021-03-16 09:47:45 +00:00
require . NoError ( t , err )
es := exs . ( * CircularExemplarStorage )
2022-03-09 22:17:29 +00:00
l1Name := "test_metric"
l1 := labels . FromStrings ( labels . MetricName , l1Name , "service" , "asdf" )
l2Name := "test_metric2"
l2 := labels . FromStrings ( labels . MetricName , l2Name , "service" , "qwer" )
2021-03-16 09:47:45 +00:00
for i := 0 ; i < len ( es . exemplars ) ; i ++ {
e1 := exemplar . Exemplar {
2024-02-15 14:19:54 +00:00
Labels : labels . FromStrings ( "trace_id" , "a" ) ,
2022-03-09 22:17:29 +00:00
Value : float64 ( i + 1 ) / 10 ,
Ts : int64 ( 101 + i ) ,
2021-03-16 09:47:45 +00:00
}
err = es . AddExemplar ( l1 , e1 )
require . NoError ( t , err )
e2 := exemplar . Exemplar {
2024-02-15 14:19:54 +00:00
Labels : labels . FromStrings ( "trace_id" , "b" ) ,
2022-03-09 22:17:29 +00:00
Value : float64 ( i + 1 ) / 10 ,
Ts : int64 ( 101 + i ) ,
2021-03-16 09:47:45 +00:00
}
err = es . AddExemplar ( l2 , e2 )
require . NoError ( t , err )
}
2022-03-09 22:17:29 +00:00
m , err := labels . NewMatcher ( labels . MatchEqual , labels . MetricName , l2Name )
2021-03-16 09:47:45 +00:00
require . NoError ( t , err , "error creating label matcher for exemplar query" )
ret , err := es . Select ( 100 , 200 , [ ] * labels . Matcher { m } )
require . NoError ( t , err )
2023-12-07 11:35:01 +00:00
require . Len ( t , ret , 1 , "select should have returned samples for a single series only" )
require . Len ( t , ret [ 0 ] . Exemplars , 3 , "didn't get expected 8 exemplars, got %d" , len ( ret [ 0 ] . Exemplars ) )
2021-03-16 09:47:45 +00:00
2022-03-09 22:17:29 +00:00
m , err = labels . NewMatcher ( labels . MatchEqual , labels . MetricName , l1Name )
2021-03-16 09:47:45 +00:00
require . NoError ( t , err , "error creating label matcher for exemplar query" )
ret , err = es . Select ( 100 , 200 , [ ] * labels . Matcher { m } )
require . NoError ( t , err )
2023-12-07 11:35:01 +00:00
require . Len ( t , ret , 1 , "select should have returned samples for a single series only" )
require . Len ( t , ret [ 0 ] . Exemplars , 2 , "didn't get expected 8 exemplars, got %d" , len ( ret [ 0 ] . Exemplars ) )
2021-03-16 09:47:45 +00:00
}
func TestSelectExemplar_TimeRange ( t * testing . T ) {
2021-07-20 04:52:57 +00:00
var lenEs int64 = 5
exs , err := NewCircularExemplarStorage ( lenEs , eMetrics )
2021-03-16 09:47:45 +00:00
require . NoError ( t , err )
es := exs . ( * CircularExemplarStorage )
2022-03-09 22:17:29 +00:00
lName , lValue := "service" , "asdf"
l := labels . FromStrings ( lName , lValue )
2021-03-16 09:47:45 +00:00
2021-07-20 04:52:57 +00:00
for i := 0 ; int64 ( i ) < lenEs ; i ++ {
2021-03-16 09:47:45 +00:00
err := es . AddExemplar ( l , exemplar . Exemplar {
2024-02-15 14:19:54 +00:00
Labels : labels . FromStrings ( "trace_id" , strconv . Itoa ( i ) ) ,
2022-03-09 22:17:29 +00:00
Value : 0.1 ,
Ts : int64 ( 101 + i ) ,
2021-03-16 09:47:45 +00:00
} )
require . NoError ( t , err )
2022-01-06 10:28:58 +00:00
require . Equal ( t , es . index [ string ( l . Bytes ( nil ) ) ] . newest , i , "exemplar was not stored correctly" )
2021-03-16 09:47:45 +00:00
}
2022-03-09 22:17:29 +00:00
m , err := labels . NewMatcher ( labels . MatchEqual , lName , lValue )
2021-03-16 09:47:45 +00:00
require . NoError ( t , err , "error creating label matcher for exemplar query" )
ret , err := es . Select ( 102 , 104 , [ ] * labels . Matcher { m } )
require . NoError ( t , err )
2023-12-07 11:35:01 +00:00
require . Len ( t , ret , 1 , "select should have returned samples for a single series only" )
require . Len ( t , ret [ 0 ] . Exemplars , 3 , "didn't get expected two exemplars %d, %+v" , len ( ret [ 0 ] . Exemplars ) , ret )
2021-03-16 09:47:45 +00:00
}
// 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 ) {
2021-07-20 04:52:57 +00:00
exs , err := NewCircularExemplarStorage ( 4 , eMetrics )
2021-03-16 09:47:45 +00:00
require . NoError ( t , err )
es := exs . ( * CircularExemplarStorage )
e := exemplar . Exemplar {
2024-02-15 14:19:54 +00:00
Labels : labels . FromStrings ( "trace_id" , "qwerty" ) ,
2022-03-09 22:17:29 +00:00
Value : 0.1 ,
Ts : 12 ,
2021-03-16 09:47:45 +00:00
}
2022-03-09 22:17:29 +00:00
lName0 , lValue0 := "service" , "asdf"
lName1 , lValue1 := "cluster" , "us-central1"
l := labels . FromStrings ( lName0 , lValue0 , lName1 , lValue1 )
2021-03-16 09:47:45 +00:00
// Lets just assume somehow the PromQL expression generated two separate lists of matchers,
// both of which can select this particular series.
m := [ ] [ ] * labels . Matcher {
{
2022-03-09 22:17:29 +00:00
labels . MustNewMatcher ( labels . MatchEqual , lName0 , lValue0 ) ,
2021-03-16 09:47:45 +00:00
} ,
{
2022-03-09 22:17:29 +00:00
labels . MustNewMatcher ( labels . MatchEqual , lName1 , lValue1 ) ,
2021-03-16 09:47:45 +00:00
} ,
}
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 )
2023-12-07 11:35:01 +00:00
require . Len ( t , ret , 1 , "select should have returned samples for a single series only" )
2021-03-16 09:47:45 +00:00
}
func TestIndexOverwrite ( t * testing . T ) {
2021-07-20 04:52:57 +00:00
exs , err := NewCircularExemplarStorage ( 2 , eMetrics )
2021-03-16 09:47:45 +00:00
require . NoError ( t , err )
es := exs . ( * CircularExemplarStorage )
2022-03-09 22:17:29 +00:00
l1 := labels . FromStrings ( "service" , "asdf" )
l2 := labels . FromStrings ( "service" , "qwer" )
2021-03-16 09:47:45 +00:00
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.
2022-01-06 10:28:58 +00:00
_ , ok := es . index [ string ( l1 . Bytes ( nil ) ) ]
2021-03-16 09:47:45 +00:00
require . False ( t , ok )
2022-01-06 10:28:58 +00:00
require . Equal ( t , & indexEntry { 1 , 0 , l2 } , es . index [ string ( l2 . Bytes ( nil ) ) ] )
2021-03-16 09:47:45 +00:00
err = es . AddExemplar ( l1 , exemplar . Exemplar { Value : 4 , Ts : 4 } )
require . NoError ( t , err )
2022-01-06 10:28:58 +00:00
i := es . index [ string ( l2 . Bytes ( nil ) ) ]
2021-05-05 17:51:16 +00:00
require . Equal ( t , & indexEntry { 0 , 0 , l2 } , i )
2021-03-16 09:47:45 +00:00
}
2021-07-20 04:52:57 +00:00
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 ,
} ,
{
2021-09-02 18:08:05 +00:00
name : "ShrinkToZero" ,
2021-07-20 04:52:57 +00:00
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 ,
} ,
2021-09-02 18:08:05 +00:00
{
name : "GrowFromZero" ,
startSize : 0 ,
newCount : 10 ,
expectedSeries : [ ] int { } ,
notExpectedSeries : [ ] int { } ,
expectedMigrated : 0 ,
} ,
2021-07-20 04:52:57 +00:00
}
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 ) ,
2021-10-22 08:06:44 +00:00
Ts : int64 ( i ) ,
} )
2021-07-20 04:52:57 +00:00
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 )
}
} )
}
}
2021-08-30 14:04:38 +00:00
func BenchmarkAddExemplar ( b * testing . B ) {
// We need to include these labels since we do length calculation
// before adding.
2024-02-15 14:19:54 +00:00
exLabels := labels . FromStrings ( "trace_id" , "89620921" )
2021-08-30 14:04:38 +00:00
2024-05-11 15:43:34 +00:00
for _ , capacity := range [ ] int { 1000 , 10000 , 100000 } {
for _ , n := range [ ] int { 10000 , 100000 , 1000000 } {
b . Run ( fmt . Sprintf ( "%d/%d" , n , capacity ) , func ( b * testing . B ) {
for j := 0 ; j < b . N ; j ++ {
b . StopTimer ( )
exs , err := NewCircularExemplarStorage ( int64 ( capacity ) , 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 )
}
2022-01-06 10:28:58 +00:00
}
}
2024-05-11 15:43:34 +00:00
} )
}
2021-07-20 04:52:57 +00:00
}
}
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 {
2022-01-06 10:28:58 +00:00
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 )
2021-07-20 04:52:57 +00:00
2024-05-11 16:00:32 +00:00
var l labels . Labels
2022-01-06 10:28:58 +00:00
for i := 0 ; i < int ( float64 ( tc . startSize ) * float64 ( 1.5 ) ) ; i ++ {
2024-05-11 16:00:32 +00:00
if i % 100 == 0 {
l = labels . FromStrings ( "service" , strconv . Itoa ( i ) )
}
2021-07-20 04:52:57 +00:00
2022-01-06 10:28:58 +00:00
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 )
}
2021-07-20 04:52:57 +00:00
} )
}
}
2024-10-29 09:40:46 +00:00
// TestCircularExemplarStorage_Concurrent_AddExemplar_Resize tries to provoke a data race between AddExemplar and Resize.
// Run with race detection enabled.
func TestCircularExemplarStorage_Concurrent_AddExemplar_Resize ( t * testing . T ) {
exs , err := NewCircularExemplarStorage ( 0 , eMetrics )
require . NoError ( t , err )
es := exs . ( * CircularExemplarStorage )
l := labels . FromStrings ( "service" , "asdf" )
e := exemplar . Exemplar {
Labels : labels . FromStrings ( "trace_id" , "qwerty" ) ,
Value : 0.1 ,
Ts : 1 ,
}
var wg sync . WaitGroup
wg . Add ( 1 )
t . Cleanup ( wg . Wait )
started := make ( chan struct { } )
go func ( ) {
defer wg . Done ( )
<- started
for i := 0 ; i < 100 ; i ++ {
require . NoError ( t , es . AddExemplar ( l , e ) )
}
} ( )
for i := 0 ; i < 100 ; i ++ {
es . Resize ( int64 ( i + 1 ) )
if i == 0 {
close ( started )
}
}
}