2020-08-03 03:32:56 -07: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 storage
import (
2022-07-01 09:59:50 -07:00
"errors"
2020-08-03 03:32:56 -07:00
"fmt"
"math"
"sort"
"sync"
"testing"
2020-10-29 02:43:23 -07:00
"github.com/stretchr/testify/require"
2020-08-03 03:32:56 -07:00
2021-11-08 06:23:17 -08:00
"github.com/prometheus/prometheus/model/labels"
2020-08-03 03:32:56 -07:00
"github.com/prometheus/prometheus/tsdb/chunkenc"
"github.com/prometheus/prometheus/tsdb/tsdbutil"
)
func TestMergeQuerierWithChainMerger ( t * testing . T ) {
for _ , tc := range [ ] struct {
name string
primaryQuerierSeries [ ] Series
querierSeries [ ] [ ] Series
extraQueriers [ ] Querier
expected SeriesSet
} {
{
name : "one primary querier with no series" ,
primaryQuerierSeries : [ ] Series { } ,
expected : NewMockSeriesSet ( ) ,
} ,
{
name : "one secondary querier with no series" ,
querierSeries : [ ] [ ] Series { { } } ,
expected : NewMockSeriesSet ( ) ,
} ,
{
name : "many secondary queriers with no series" ,
querierSeries : [ ] [ ] Series { { } , { } , { } , { } , { } , { } , { } } ,
expected : NewMockSeriesSet ( ) ,
} ,
{
name : "mix of queriers with no series" ,
primaryQuerierSeries : [ ] Series { } ,
querierSeries : [ ] [ ] Series { { } , { } , { } , { } , { } , { } , { } } ,
expected : NewMockSeriesSet ( ) ,
} ,
// Test rest of cases on secondary queriers as the different between primary vs secondary is just error handling.
{
name : "one querier, two series" ,
querierSeries : [ ] [ ] Series { {
2022-12-08 04:31:08 -08:00
NewListSeries ( labels . FromStrings ( "bar" , "baz" ) , [ ] tsdbutil . Sample { fSample { 1 , 1 } , fSample { 2 , 2 } , fSample { 3 , 3 } } ) ,
NewListSeries ( labels . FromStrings ( "foo" , "bar" ) , [ ] tsdbutil . Sample { fSample { 0 , 0 } , fSample { 1 , 1 } , fSample { 2 , 2 } } ) ,
2020-08-03 03:32:56 -07:00
} } ,
expected : NewMockSeriesSet (
2022-12-08 04:31:08 -08:00
NewListSeries ( labels . FromStrings ( "bar" , "baz" ) , [ ] tsdbutil . Sample { fSample { 1 , 1 } , fSample { 2 , 2 } , fSample { 3 , 3 } } ) ,
NewListSeries ( labels . FromStrings ( "foo" , "bar" ) , [ ] tsdbutil . Sample { fSample { 0 , 0 } , fSample { 1 , 1 } , fSample { 2 , 2 } } ) ,
2020-08-03 03:32:56 -07:00
) ,
} ,
{
name : "two queriers, one different series each" ,
querierSeries : [ ] [ ] Series { {
2022-12-08 04:31:08 -08:00
NewListSeries ( labels . FromStrings ( "bar" , "baz" ) , [ ] tsdbutil . Sample { fSample { 1 , 1 } , fSample { 2 , 2 } , fSample { 3 , 3 } } ) ,
2020-08-03 03:32:56 -07:00
} , {
2022-12-08 04:31:08 -08:00
NewListSeries ( labels . FromStrings ( "foo" , "bar" ) , [ ] tsdbutil . Sample { fSample { 0 , 0 } , fSample { 1 , 1 } , fSample { 2 , 2 } } ) ,
2020-08-03 03:32:56 -07:00
} } ,
expected : NewMockSeriesSet (
2022-12-08 04:31:08 -08:00
NewListSeries ( labels . FromStrings ( "bar" , "baz" ) , [ ] tsdbutil . Sample { fSample { 1 , 1 } , fSample { 2 , 2 } , fSample { 3 , 3 } } ) ,
NewListSeries ( labels . FromStrings ( "foo" , "bar" ) , [ ] tsdbutil . Sample { fSample { 0 , 0 } , fSample { 1 , 1 } , fSample { 2 , 2 } } ) ,
2020-08-03 03:32:56 -07:00
) ,
} ,
{
name : "two time unsorted queriers, two series each" ,
querierSeries : [ ] [ ] Series { {
2022-12-08 04:31:08 -08:00
NewListSeries ( labels . FromStrings ( "bar" , "baz" ) , [ ] tsdbutil . Sample { fSample { 5 , 5 } , fSample { 6 , 6 } } ) ,
NewListSeries ( labels . FromStrings ( "foo" , "bar" ) , [ ] tsdbutil . Sample { fSample { 0 , 0 } , fSample { 1 , 1 } , fSample { 2 , 2 } } ) ,
2020-08-03 03:32:56 -07:00
} , {
2022-12-08 04:31:08 -08:00
NewListSeries ( labels . FromStrings ( "bar" , "baz" ) , [ ] tsdbutil . Sample { fSample { 1 , 1 } , fSample { 2 , 2 } , fSample { 3 , 3 } } ) ,
NewListSeries ( labels . FromStrings ( "foo" , "bar" ) , [ ] tsdbutil . Sample { fSample { 3 , 3 } , fSample { 4 , 4 } } ) ,
2020-08-03 03:32:56 -07:00
} } ,
expected : NewMockSeriesSet (
NewListSeries (
labels . FromStrings ( "bar" , "baz" ) ,
2022-12-08 04:31:08 -08:00
[ ] tsdbutil . Sample { fSample { 1 , 1 } , fSample { 2 , 2 } , fSample { 3 , 3 } , fSample { 5 , 5 } , fSample { 6 , 6 } } ,
2020-08-03 03:32:56 -07:00
) ,
NewListSeries (
labels . FromStrings ( "foo" , "bar" ) ,
2022-12-08 04:31:08 -08:00
[ ] tsdbutil . Sample { fSample { 0 , 0 } , fSample { 1 , 1 } , fSample { 2 , 2 } , fSample { 3 , 3 } , fSample { 4 , 4 } } ,
2020-08-03 03:32:56 -07:00
) ,
) ,
} ,
{
name : "five queriers, only two queriers have two time unsorted series each" ,
querierSeries : [ ] [ ] Series { { } , { } , {
2022-12-08 04:31:08 -08:00
NewListSeries ( labels . FromStrings ( "bar" , "baz" ) , [ ] tsdbutil . Sample { fSample { 5 , 5 } , fSample { 6 , 6 } } ) ,
NewListSeries ( labels . FromStrings ( "foo" , "bar" ) , [ ] tsdbutil . Sample { fSample { 0 , 0 } , fSample { 1 , 1 } , fSample { 2 , 2 } } ) ,
2020-08-03 03:32:56 -07:00
} , {
2022-12-08 04:31:08 -08:00
NewListSeries ( labels . FromStrings ( "bar" , "baz" ) , [ ] tsdbutil . Sample { fSample { 1 , 1 } , fSample { 2 , 2 } , fSample { 3 , 3 } } ) ,
NewListSeries ( labels . FromStrings ( "foo" , "bar" ) , [ ] tsdbutil . Sample { fSample { 3 , 3 } , fSample { 4 , 4 } } ) ,
2020-08-03 03:32:56 -07:00
} , { } } ,
expected : NewMockSeriesSet (
NewListSeries (
labels . FromStrings ( "bar" , "baz" ) ,
2022-12-08 04:31:08 -08:00
[ ] tsdbutil . Sample { fSample { 1 , 1 } , fSample { 2 , 2 } , fSample { 3 , 3 } , fSample { 5 , 5 } , fSample { 6 , 6 } } ,
2020-08-03 03:32:56 -07:00
) ,
NewListSeries (
labels . FromStrings ( "foo" , "bar" ) ,
2022-12-08 04:31:08 -08:00
[ ] tsdbutil . Sample { fSample { 0 , 0 } , fSample { 1 , 1 } , fSample { 2 , 2 } , fSample { 3 , 3 } , fSample { 4 , 4 } } ,
2020-08-03 03:32:56 -07:00
) ,
) ,
} ,
{
name : "two queriers, only two queriers have two time unsorted series each, with 3 noop and one nil querier together" ,
querierSeries : [ ] [ ] Series { { } , { } , {
2022-12-08 04:31:08 -08:00
NewListSeries ( labels . FromStrings ( "bar" , "baz" ) , [ ] tsdbutil . Sample { fSample { 5 , 5 } , fSample { 6 , 6 } } ) ,
NewListSeries ( labels . FromStrings ( "foo" , "bar" ) , [ ] tsdbutil . Sample { fSample { 0 , 0 } , fSample { 1 , 1 } , fSample { 2 , 2 } } ) ,
2020-08-03 03:32:56 -07:00
} , {
2022-12-08 04:31:08 -08:00
NewListSeries ( labels . FromStrings ( "bar" , "baz" ) , [ ] tsdbutil . Sample { fSample { 1 , 1 } , fSample { 2 , 2 } , fSample { 3 , 3 } } ) ,
NewListSeries ( labels . FromStrings ( "foo" , "bar" ) , [ ] tsdbutil . Sample { fSample { 3 , 3 } , fSample { 4 , 4 } } ) ,
2020-08-03 03:32:56 -07:00
} , { } } ,
extraQueriers : [ ] Querier { NoopQuerier ( ) , NoopQuerier ( ) , nil , NoopQuerier ( ) } ,
expected : NewMockSeriesSet (
NewListSeries (
labels . FromStrings ( "bar" , "baz" ) ,
2022-12-08 04:31:08 -08:00
[ ] tsdbutil . Sample { fSample { 1 , 1 } , fSample { 2 , 2 } , fSample { 3 , 3 } , fSample { 5 , 5 } , fSample { 6 , 6 } } ,
2020-08-03 03:32:56 -07:00
) ,
NewListSeries (
labels . FromStrings ( "foo" , "bar" ) ,
2022-12-08 04:31:08 -08:00
[ ] tsdbutil . Sample { fSample { 0 , 0 } , fSample { 1 , 1 } , fSample { 2 , 2 } , fSample { 3 , 3 } , fSample { 4 , 4 } } ,
2020-08-03 03:32:56 -07:00
) ,
) ,
} ,
{
name : "two queriers, with two series, one is overlapping" ,
querierSeries : [ ] [ ] Series { { } , { } , {
2022-12-08 04:31:08 -08:00
NewListSeries ( labels . FromStrings ( "bar" , "baz" ) , [ ] tsdbutil . Sample { fSample { 2 , 21 } , fSample { 3 , 31 } , fSample { 5 , 5 } , fSample { 6 , 6 } } ) ,
NewListSeries ( labels . FromStrings ( "foo" , "bar" ) , [ ] tsdbutil . Sample { fSample { 0 , 0 } , fSample { 1 , 1 } , fSample { 2 , 2 } } ) ,
2020-08-03 03:32:56 -07:00
} , {
2022-12-08 04:31:08 -08:00
NewListSeries ( labels . FromStrings ( "bar" , "baz" ) , [ ] tsdbutil . Sample { fSample { 1 , 1 } , fSample { 2 , 22 } , fSample { 3 , 32 } } ) ,
NewListSeries ( labels . FromStrings ( "foo" , "bar" ) , [ ] tsdbutil . Sample { fSample { 3 , 3 } , fSample { 4 , 4 } } ) ,
2020-08-03 03:32:56 -07:00
} , { } } ,
expected : NewMockSeriesSet (
NewListSeries (
labels . FromStrings ( "bar" , "baz" ) ,
2022-12-08 04:31:08 -08:00
[ ] tsdbutil . Sample { fSample { 1 , 1 } , fSample { 2 , 21 } , fSample { 3 , 31 } , fSample { 5 , 5 } , fSample { 6 , 6 } } ,
2020-08-03 03:32:56 -07:00
) ,
NewListSeries (
labels . FromStrings ( "foo" , "bar" ) ,
2022-12-08 04:31:08 -08:00
[ ] tsdbutil . Sample { fSample { 0 , 0 } , fSample { 1 , 1 } , fSample { 2 , 2 } , fSample { 3 , 3 } , fSample { 4 , 4 } } ,
2020-08-03 03:32:56 -07:00
) ,
) ,
} ,
{
name : "two queries, one with NaN samples series" ,
querierSeries : [ ] [ ] Series { {
2022-12-08 04:31:08 -08:00
NewListSeries ( labels . FromStrings ( "foo" , "bar" ) , [ ] tsdbutil . Sample { fSample { 0 , math . NaN ( ) } } ) ,
2020-08-03 03:32:56 -07:00
} , {
2022-12-08 04:31:08 -08:00
NewListSeries ( labels . FromStrings ( "foo" , "bar" ) , [ ] tsdbutil . Sample { fSample { 1 , 1 } } ) ,
2020-08-03 03:32:56 -07:00
} } ,
expected : NewMockSeriesSet (
2022-12-08 04:31:08 -08:00
NewListSeries ( labels . FromStrings ( "foo" , "bar" ) , [ ] tsdbutil . Sample { fSample { 0 , math . NaN ( ) } , fSample { 1 , 1 } } ) ,
2020-08-03 03:32:56 -07:00
) ,
} ,
} {
t . Run ( tc . name , func ( t * testing . T ) {
var p Querier
if tc . primaryQuerierSeries != nil {
p = & mockQuerier { toReturn : tc . primaryQuerierSeries }
}
var qs [ ] Querier
for _ , in := range tc . querierSeries {
qs = append ( qs , & mockQuerier { toReturn : in } )
}
qs = append ( qs , tc . extraQueriers ... )
mergedQuerier := NewMergeQuerier ( [ ] Querier { p } , qs , ChainedSeriesMerge ) . Select ( false , nil )
// Get all merged series upfront to make sure there are no incorrectly retained shared
// buffers causing bugs.
var mergedSeries [ ] Series
for mergedQuerier . Next ( ) {
mergedSeries = append ( mergedSeries , mergedQuerier . At ( ) )
}
2020-10-29 02:43:23 -07:00
require . NoError ( t , mergedQuerier . Err ( ) )
2020-08-03 03:32:56 -07:00
for _ , actualSeries := range mergedSeries {
2020-10-29 02:43:23 -07:00
require . True ( t , tc . expected . Next ( ) , "Expected Next() to be true" )
2020-08-03 03:32:56 -07:00
expectedSeries := tc . expected . At ( )
2020-10-29 02:43:23 -07:00
require . Equal ( t , expectedSeries . Labels ( ) , actualSeries . Labels ( ) )
2020-08-03 03:32:56 -07:00
2022-09-20 10:16:45 -07:00
expSmpl , expErr := ExpandSamples ( expectedSeries . Iterator ( nil ) , nil )
actSmpl , actErr := ExpandSamples ( actualSeries . Iterator ( nil ) , nil )
2020-10-29 02:43:23 -07:00
require . Equal ( t , expErr , actErr )
require . Equal ( t , expSmpl , actSmpl )
2020-08-03 03:32:56 -07:00
}
2020-10-29 02:43:23 -07:00
require . False ( t , tc . expected . Next ( ) , "Expected Next() to be false" )
2020-08-03 03:32:56 -07:00
} )
}
}
func TestMergeChunkQuerierWithNoVerticalChunkSeriesMerger ( t * testing . T ) {
for _ , tc := range [ ] struct {
name string
primaryChkQuerierSeries [ ] ChunkSeries
chkQuerierSeries [ ] [ ] ChunkSeries
extraQueriers [ ] ChunkQuerier
expected ChunkSeriesSet
} {
{
name : "one primary querier with no series" ,
primaryChkQuerierSeries : [ ] ChunkSeries { } ,
expected : NewMockChunkSeriesSet ( ) ,
} ,
{
name : "one secondary querier with no series" ,
chkQuerierSeries : [ ] [ ] ChunkSeries { { } } ,
expected : NewMockChunkSeriesSet ( ) ,
} ,
{
name : "many secondary queriers with no series" ,
chkQuerierSeries : [ ] [ ] ChunkSeries { { } , { } , { } , { } , { } , { } , { } } ,
expected : NewMockChunkSeriesSet ( ) ,
} ,
{
name : "mix of queriers with no series" ,
primaryChkQuerierSeries : [ ] ChunkSeries { } ,
chkQuerierSeries : [ ] [ ] ChunkSeries { { } , { } , { } , { } , { } , { } , { } } ,
expected : NewMockChunkSeriesSet ( ) ,
} ,
// Test rest of cases on secondary queriers as the different between primary vs secondary is just error handling.
{
name : "one querier, two series" ,
chkQuerierSeries : [ ] [ ] ChunkSeries { {
2022-12-08 04:31:08 -08:00
NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) , [ ] tsdbutil . Sample { fSample { 1 , 1 } , fSample { 2 , 2 } } , [ ] tsdbutil . Sample { fSample { 3 , 3 } } ) ,
NewListChunkSeriesFromSamples ( labels . FromStrings ( "foo" , "bar" ) , [ ] tsdbutil . Sample { fSample { 0 , 0 } , fSample { 1 , 1 } } , [ ] tsdbutil . Sample { fSample { 2 , 2 } } ) ,
2020-08-03 03:32:56 -07:00
} } ,
expected : NewMockChunkSeriesSet (
2022-12-08 04:31:08 -08:00
NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) , [ ] tsdbutil . Sample { fSample { 1 , 1 } , fSample { 2 , 2 } } , [ ] tsdbutil . Sample { fSample { 3 , 3 } } ) ,
NewListChunkSeriesFromSamples ( labels . FromStrings ( "foo" , "bar" ) , [ ] tsdbutil . Sample { fSample { 0 , 0 } , fSample { 1 , 1 } } , [ ] tsdbutil . Sample { fSample { 2 , 2 } } ) ,
2020-08-03 03:32:56 -07:00
) ,
} ,
{
name : "two secondaries, one different series each" ,
chkQuerierSeries : [ ] [ ] ChunkSeries { {
2022-12-08 04:31:08 -08:00
NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) , [ ] tsdbutil . Sample { fSample { 1 , 1 } , fSample { 2 , 2 } } , [ ] tsdbutil . Sample { fSample { 3 , 3 } } ) ,
2020-08-03 03:32:56 -07:00
} , {
2022-12-08 04:31:08 -08:00
NewListChunkSeriesFromSamples ( labels . FromStrings ( "foo" , "bar" ) , [ ] tsdbutil . Sample { fSample { 0 , 0 } , fSample { 1 , 1 } } , [ ] tsdbutil . Sample { fSample { 2 , 2 } } ) ,
2020-08-03 03:32:56 -07:00
} } ,
expected : NewMockChunkSeriesSet (
2022-12-08 04:31:08 -08:00
NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) , [ ] tsdbutil . Sample { fSample { 1 , 1 } , fSample { 2 , 2 } } , [ ] tsdbutil . Sample { fSample { 3 , 3 } } ) ,
NewListChunkSeriesFromSamples ( labels . FromStrings ( "foo" , "bar" ) , [ ] tsdbutil . Sample { fSample { 0 , 0 } , fSample { 1 , 1 } } , [ ] tsdbutil . Sample { fSample { 2 , 2 } } ) ,
2020-08-03 03:32:56 -07:00
) ,
} ,
{
name : "two secondaries, two not in time order series each" ,
chkQuerierSeries : [ ] [ ] ChunkSeries { {
2022-12-08 04:31:08 -08:00
NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) , [ ] tsdbutil . Sample { fSample { 5 , 5 } } , [ ] tsdbutil . Sample { fSample { 6 , 6 } } ) ,
NewListChunkSeriesFromSamples ( labels . FromStrings ( "foo" , "bar" ) , [ ] tsdbutil . Sample { fSample { 0 , 0 } , fSample { 1 , 1 } } , [ ] tsdbutil . Sample { fSample { 2 , 2 } } ) ,
2020-08-03 03:32:56 -07:00
} , {
2022-12-08 04:31:08 -08:00
NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) , [ ] tsdbutil . Sample { fSample { 1 , 1 } , fSample { 2 , 2 } } , [ ] tsdbutil . Sample { fSample { 3 , 3 } } ) ,
NewListChunkSeriesFromSamples ( labels . FromStrings ( "foo" , "bar" ) , [ ] tsdbutil . Sample { fSample { 3 , 3 } } , [ ] tsdbutil . Sample { fSample { 4 , 4 } } ) ,
2020-08-03 03:32:56 -07:00
} } ,
expected : NewMockChunkSeriesSet (
NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) ,
2022-12-08 04:31:08 -08:00
[ ] tsdbutil . Sample { fSample { 1 , 1 } , fSample { 2 , 2 } } ,
[ ] tsdbutil . Sample { fSample { 3 , 3 } } ,
[ ] tsdbutil . Sample { fSample { 5 , 5 } } ,
[ ] tsdbutil . Sample { fSample { 6 , 6 } } ,
2020-08-03 03:32:56 -07:00
) ,
NewListChunkSeriesFromSamples ( labels . FromStrings ( "foo" , "bar" ) ,
2022-12-08 04:31:08 -08:00
[ ] tsdbutil . Sample { fSample { 0 , 0 } , fSample { 1 , 1 } } ,
[ ] tsdbutil . Sample { fSample { 2 , 2 } } ,
[ ] tsdbutil . Sample { fSample { 3 , 3 } } ,
[ ] tsdbutil . Sample { fSample { 4 , 4 } } ,
2020-08-03 03:32:56 -07:00
) ,
) ,
} ,
{
name : "five secondaries, only two have two not in time order series each" ,
chkQuerierSeries : [ ] [ ] ChunkSeries { { } , { } , {
2022-12-08 04:31:08 -08:00
NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) , [ ] tsdbutil . Sample { fSample { 5 , 5 } } , [ ] tsdbutil . Sample { fSample { 6 , 6 } } ) ,
NewListChunkSeriesFromSamples ( labels . FromStrings ( "foo" , "bar" ) , [ ] tsdbutil . Sample { fSample { 0 , 0 } , fSample { 1 , 1 } } , [ ] tsdbutil . Sample { fSample { 2 , 2 } } ) ,
2020-08-03 03:32:56 -07:00
} , {
2022-12-08 04:31:08 -08:00
NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) , [ ] tsdbutil . Sample { fSample { 1 , 1 } , fSample { 2 , 2 } } , [ ] tsdbutil . Sample { fSample { 3 , 3 } } ) ,
NewListChunkSeriesFromSamples ( labels . FromStrings ( "foo" , "bar" ) , [ ] tsdbutil . Sample { fSample { 3 , 3 } } , [ ] tsdbutil . Sample { fSample { 4 , 4 } } ) ,
2020-08-03 03:32:56 -07:00
} , { } } ,
expected : NewMockChunkSeriesSet (
NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) ,
2022-12-08 04:31:08 -08:00
[ ] tsdbutil . Sample { fSample { 1 , 1 } , fSample { 2 , 2 } } ,
[ ] tsdbutil . Sample { fSample { 3 , 3 } } ,
[ ] tsdbutil . Sample { fSample { 5 , 5 } } ,
[ ] tsdbutil . Sample { fSample { 6 , 6 } } ,
2020-08-03 03:32:56 -07:00
) ,
NewListChunkSeriesFromSamples ( labels . FromStrings ( "foo" , "bar" ) ,
2022-12-08 04:31:08 -08:00
[ ] tsdbutil . Sample { fSample { 0 , 0 } , fSample { 1 , 1 } } ,
[ ] tsdbutil . Sample { fSample { 2 , 2 } } ,
[ ] tsdbutil . Sample { fSample { 3 , 3 } } ,
[ ] tsdbutil . Sample { fSample { 4 , 4 } } ,
2020-08-03 03:32:56 -07:00
) ,
) ,
} ,
{
name : "two secondaries, with two not in time order series each, with 3 noop queries and one nil together" ,
chkQuerierSeries : [ ] [ ] ChunkSeries { {
2022-12-08 04:31:08 -08:00
NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) , [ ] tsdbutil . Sample { fSample { 5 , 5 } } , [ ] tsdbutil . Sample { fSample { 6 , 6 } } ) ,
NewListChunkSeriesFromSamples ( labels . FromStrings ( "foo" , "bar" ) , [ ] tsdbutil . Sample { fSample { 0 , 0 } , fSample { 1 , 1 } } , [ ] tsdbutil . Sample { fSample { 2 , 2 } } ) ,
2020-08-03 03:32:56 -07:00
} , {
2022-12-08 04:31:08 -08:00
NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) , [ ] tsdbutil . Sample { fSample { 1 , 1 } , fSample { 2 , 2 } } , [ ] tsdbutil . Sample { fSample { 3 , 3 } } ) ,
NewListChunkSeriesFromSamples ( labels . FromStrings ( "foo" , "bar" ) , [ ] tsdbutil . Sample { fSample { 3 , 3 } } , [ ] tsdbutil . Sample { fSample { 4 , 4 } } ) ,
2020-08-03 03:32:56 -07:00
} } ,
extraQueriers : [ ] ChunkQuerier { NoopChunkedQuerier ( ) , NoopChunkedQuerier ( ) , nil , NoopChunkedQuerier ( ) } ,
expected : NewMockChunkSeriesSet (
NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) ,
2022-12-08 04:31:08 -08:00
[ ] tsdbutil . Sample { fSample { 1 , 1 } , fSample { 2 , 2 } } ,
[ ] tsdbutil . Sample { fSample { 3 , 3 } } ,
[ ] tsdbutil . Sample { fSample { 5 , 5 } } ,
[ ] tsdbutil . Sample { fSample { 6 , 6 } } ,
2020-08-03 03:32:56 -07:00
) ,
NewListChunkSeriesFromSamples ( labels . FromStrings ( "foo" , "bar" ) ,
2022-12-08 04:31:08 -08:00
[ ] tsdbutil . Sample { fSample { 0 , 0 } , fSample { 1 , 1 } } ,
[ ] tsdbutil . Sample { fSample { 2 , 2 } } ,
[ ] tsdbutil . Sample { fSample { 3 , 3 } } ,
[ ] tsdbutil . Sample { fSample { 4 , 4 } } ,
2020-08-03 03:32:56 -07:00
) ,
) ,
} ,
{
name : "two queries, one with NaN samples series" ,
chkQuerierSeries : [ ] [ ] ChunkSeries { {
2022-12-08 04:31:08 -08:00
NewListChunkSeriesFromSamples ( labels . FromStrings ( "foo" , "bar" ) , [ ] tsdbutil . Sample { fSample { 0 , math . NaN ( ) } } ) ,
2020-08-03 03:32:56 -07:00
} , {
2022-12-08 04:31:08 -08:00
NewListChunkSeriesFromSamples ( labels . FromStrings ( "foo" , "bar" ) , [ ] tsdbutil . Sample { fSample { 1 , 1 } } ) ,
2020-08-03 03:32:56 -07:00
} } ,
expected : NewMockChunkSeriesSet (
2022-12-08 04:31:08 -08:00
NewListChunkSeriesFromSamples ( labels . FromStrings ( "foo" , "bar" ) , [ ] tsdbutil . Sample { fSample { 0 , math . NaN ( ) } } , [ ] tsdbutil . Sample { fSample { 1 , 1 } } ) ,
2020-08-03 03:32:56 -07:00
) ,
} ,
} {
t . Run ( tc . name , func ( t * testing . T ) {
var p ChunkQuerier
if tc . primaryChkQuerierSeries != nil {
p = & mockChunkQurier { toReturn : tc . primaryChkQuerierSeries }
}
var qs [ ] ChunkQuerier
for _ , in := range tc . chkQuerierSeries {
qs = append ( qs , & mockChunkQurier { toReturn : in } )
}
qs = append ( qs , tc . extraQueriers ... )
merged := NewMergeChunkQuerier ( [ ] ChunkQuerier { p } , qs , NewCompactingChunkSeriesMerger ( nil ) ) . Select ( false , nil )
for merged . Next ( ) {
2020-10-29 02:43:23 -07:00
require . True ( t , tc . expected . Next ( ) , "Expected Next() to be true" )
2020-08-03 03:32:56 -07:00
actualSeries := merged . At ( )
expectedSeries := tc . expected . At ( )
2020-10-29 02:43:23 -07:00
require . Equal ( t , expectedSeries . Labels ( ) , actualSeries . Labels ( ) )
2020-08-03 03:32:56 -07:00
2022-09-20 10:16:45 -07:00
expChks , expErr := ExpandChunks ( expectedSeries . Iterator ( nil ) )
actChks , actErr := ExpandChunks ( actualSeries . Iterator ( nil ) )
2020-10-29 02:43:23 -07:00
require . Equal ( t , expErr , actErr )
require . Equal ( t , expChks , actChks )
2020-08-03 03:32:56 -07:00
}
2020-10-29 02:43:23 -07:00
require . NoError ( t , merged . Err ( ) )
require . False ( t , tc . expected . Next ( ) , "Expected Next() to be false" )
2020-08-03 03:32:56 -07:00
} )
}
}
func TestCompactingChunkSeriesMerger ( t * testing . T ) {
m := NewCompactingChunkSeriesMerger ( ChainedSeriesMerge )
2022-08-22 06:34:39 -07:00
// histogramSample returns a histogram that is unique to the ts.
2022-12-08 04:31:08 -08:00
histogramSample := func ( ts int64 ) hSample {
return hSample { t : ts , h : tsdbutil . GenerateTestHistogram ( int ( ts + 1 ) ) }
2023-02-10 03:39:33 -08:00
}
2022-12-08 04:31:08 -08:00
floatHistogramSample := func ( ts int64 ) fhSample {
return fhSample { t : ts , fh : tsdbutil . GenerateTestFloatHistogram ( int ( ts + 1 ) ) }
2022-08-22 06:34:39 -07:00
}
2020-08-03 03:32:56 -07:00
for _ , tc := range [ ] struct {
2023-07-04 22:29:00 -07:00
name string
input [ ] ChunkSeries
expected ChunkSeries
expectedChunksEstimate int
2020-08-03 03:32:56 -07:00
} {
{
name : "single empty series" ,
input : [ ] ChunkSeries {
NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) , nil ) ,
} ,
expected : NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) , nil ) ,
} ,
{
name : "single series" ,
input : [ ] ChunkSeries {
2022-12-08 04:31:08 -08:00
NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) , [ ] tsdbutil . Sample { fSample { 1 , 1 } , fSample { 2 , 2 } } , [ ] tsdbutil . Sample { fSample { 3 , 3 } } ) ,
2020-08-03 03:32:56 -07:00
} ,
2022-12-08 04:31:08 -08:00
expected : NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) , [ ] tsdbutil . Sample { fSample { 1 , 1 } , fSample { 2 , 2 } } , [ ] tsdbutil . Sample { fSample { 3 , 3 } } ) ,
2020-08-03 03:32:56 -07:00
} ,
{
name : "two empty series" ,
input : [ ] ChunkSeries {
NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) , nil ) ,
NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) , nil ) ,
} ,
expected : NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) , nil ) ,
} ,
{
name : "two non overlapping" ,
input : [ ] ChunkSeries {
2022-12-08 04:31:08 -08:00
NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) , [ ] tsdbutil . Sample { fSample { 1 , 1 } , fSample { 2 , 2 } } , [ ] tsdbutil . Sample { fSample { 3 , 3 } , fSample { 5 , 5 } } ) ,
NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) , [ ] tsdbutil . Sample { fSample { 7 , 7 } , fSample { 9 , 9 } } , [ ] tsdbutil . Sample { fSample { 10 , 10 } } ) ,
2020-08-03 03:32:56 -07:00
} ,
2022-12-08 04:31:08 -08:00
expected : NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) , [ ] tsdbutil . Sample { fSample { 1 , 1 } , fSample { 2 , 2 } } , [ ] tsdbutil . Sample { fSample { 3 , 3 } , fSample { 5 , 5 } } , [ ] tsdbutil . Sample { fSample { 7 , 7 } , fSample { 9 , 9 } } , [ ] tsdbutil . Sample { fSample { 10 , 10 } } ) ,
2020-08-03 03:32:56 -07:00
} ,
{
name : "two overlapping" ,
input : [ ] ChunkSeries {
2022-12-08 04:31:08 -08:00
NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) , [ ] tsdbutil . Sample { fSample { 1 , 1 } , fSample { 2 , 2 } } , [ ] tsdbutil . Sample { fSample { 3 , 3 } , fSample { 8 , 8 } } ) ,
NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) , [ ] tsdbutil . Sample { fSample { 7 , 7 } , fSample { 9 , 9 } } , [ ] tsdbutil . Sample { fSample { 10 , 10 } } ) ,
2020-08-03 03:32:56 -07:00
} ,
2022-12-08 04:31:08 -08:00
expected : NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) , [ ] tsdbutil . Sample { fSample { 1 , 1 } , fSample { 2 , 2 } } , [ ] tsdbutil . Sample { fSample { 3 , 3 } , fSample { 7 , 7 } , fSample { 8 , 8 } , fSample { 9 , 9 } } , [ ] tsdbutil . Sample { fSample { 10 , 10 } } ) ,
2020-08-03 03:32:56 -07:00
} ,
{
name : "two duplicated" ,
input : [ ] ChunkSeries {
2022-12-08 04:31:08 -08:00
NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) , [ ] tsdbutil . Sample { fSample { 1 , 1 } , fSample { 2 , 2 } , fSample { 3 , 3 } , fSample { 5 , 5 } } ) ,
NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) , [ ] tsdbutil . Sample { fSample { 2 , 2 } , fSample { 3 , 3 } , fSample { 5 , 5 } } ) ,
2020-08-03 03:32:56 -07:00
} ,
2022-12-08 04:31:08 -08:00
expected : NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) , [ ] tsdbutil . Sample { fSample { 1 , 1 } , fSample { 2 , 2 } , fSample { 3 , 3 } , fSample { 5 , 5 } } ) ,
2020-08-03 03:32:56 -07:00
} ,
{
name : "three overlapping" ,
input : [ ] ChunkSeries {
2022-12-08 04:31:08 -08:00
NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) , [ ] tsdbutil . Sample { fSample { 1 , 1 } , fSample { 2 , 2 } , fSample { 3 , 3 } , fSample { 5 , 5 } } ) ,
NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) , [ ] tsdbutil . Sample { fSample { 2 , 2 } , fSample { 3 , 3 } , fSample { 6 , 6 } } ) ,
NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) , [ ] tsdbutil . Sample { fSample { 0 , 0 } , fSample { 4 , 4 } } ) ,
2020-08-03 03:32:56 -07:00
} ,
2022-12-08 04:31:08 -08:00
expected : NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) , [ ] tsdbutil . Sample { fSample { 0 , 0 } , fSample { 1 , 1 } , fSample { 2 , 2 } , fSample { 3 , 3 } , fSample { 4 , 4 } , fSample { 5 , 5 } , fSample { 6 , 6 } } ) ,
2020-08-03 03:32:56 -07:00
} ,
{
name : "three in chained overlap" ,
input : [ ] ChunkSeries {
2022-12-08 04:31:08 -08:00
NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) , [ ] tsdbutil . Sample { fSample { 1 , 1 } , fSample { 2 , 2 } , fSample { 3 , 3 } , fSample { 5 , 5 } } ) ,
NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) , [ ] tsdbutil . Sample { fSample { 4 , 4 } , fSample { 6 , 66 } } ) ,
NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) , [ ] tsdbutil . Sample { fSample { 6 , 6 } , fSample { 10 , 10 } } ) ,
2020-08-03 03:32:56 -07:00
} ,
2022-12-08 04:31:08 -08:00
expected : NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) , [ ] tsdbutil . Sample { fSample { 1 , 1 } , fSample { 2 , 2 } , fSample { 3 , 3 } , fSample { 4 , 4 } , fSample { 5 , 5 } , fSample { 6 , 66 } , fSample { 10 , 10 } } ) ,
2020-08-03 03:32:56 -07:00
} ,
{
name : "three in chained overlap complex" ,
input : [ ] ChunkSeries {
2022-12-08 04:31:08 -08:00
NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) , [ ] tsdbutil . Sample { fSample { 0 , 0 } , fSample { 5 , 5 } } , [ ] tsdbutil . Sample { fSample { 10 , 10 } , fSample { 15 , 15 } } ) ,
NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) , [ ] tsdbutil . Sample { fSample { 2 , 2 } , fSample { 20 , 20 } } , [ ] tsdbutil . Sample { fSample { 25 , 25 } , fSample { 30 , 30 } } ) ,
NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) , [ ] tsdbutil . Sample { fSample { 18 , 18 } , fSample { 26 , 26 } } , [ ] tsdbutil . Sample { fSample { 31 , 31 } , fSample { 35 , 35 } } ) ,
2020-08-03 03:32:56 -07:00
} ,
expected : NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) ,
2022-12-08 04:31:08 -08:00
[ ] tsdbutil . Sample { fSample { 0 , 0 } , fSample { 2 , 2 } , fSample { 5 , 5 } , fSample { 10 , 10 } , fSample { 15 , 15 } , fSample { 18 , 18 } , fSample { 20 , 20 } , fSample { 25 , 25 } , fSample { 26 , 26 } , fSample { 30 , 30 } } ,
[ ] tsdbutil . Sample { fSample { 31 , 31 } , fSample { 35 , 35 } } ,
2020-08-03 03:32:56 -07:00
) ,
} ,
2021-05-18 09:37:16 -07:00
{
name : "110 overlapping" ,
input : [ ] ChunkSeries {
NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) , tsdbutil . GenerateSamples ( 0 , 110 ) ) , // [0 - 110)
NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) , tsdbutil . GenerateSamples ( 60 , 50 ) ) , // [60 - 110)
} ,
expected : NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) ,
tsdbutil . GenerateSamples ( 0 , 110 ) ,
) ,
2023-07-04 22:29:00 -07:00
expectedChunksEstimate : 2 , // Estimation doesn't consider duplicate series when estimating the number of chunks.
2021-05-18 09:37:16 -07:00
} ,
{
name : "150 overlapping samples, split chunk" ,
input : [ ] ChunkSeries {
NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) , tsdbutil . GenerateSamples ( 0 , 90 ) ) , // [0 - 90)
NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) , tsdbutil . GenerateSamples ( 60 , 90 ) ) , // [90 - 150)
} ,
expected : NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) ,
tsdbutil . GenerateSamples ( 0 , 120 ) ,
tsdbutil . GenerateSamples ( 120 , 30 ) ,
) ,
} ,
2022-08-22 06:34:39 -07:00
{
name : "histogram chunks overlapping" ,
input : [ ] ChunkSeries {
NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) , [ ] tsdbutil . Sample { histogramSample ( 0 ) , histogramSample ( 5 ) } , [ ] tsdbutil . Sample { histogramSample ( 10 ) , histogramSample ( 15 ) } ) ,
NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) , [ ] tsdbutil . Sample { histogramSample ( 2 ) , histogramSample ( 20 ) } , [ ] tsdbutil . Sample { histogramSample ( 25 ) , histogramSample ( 30 ) } ) ,
NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) , [ ] tsdbutil . Sample { histogramSample ( 18 ) , histogramSample ( 26 ) } , [ ] tsdbutil . Sample { histogramSample ( 31 ) , histogramSample ( 35 ) } ) ,
} ,
expected : NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) ,
[ ] tsdbutil . Sample { histogramSample ( 0 ) , histogramSample ( 2 ) , histogramSample ( 5 ) , histogramSample ( 10 ) , histogramSample ( 15 ) , histogramSample ( 18 ) , histogramSample ( 20 ) , histogramSample ( 25 ) , histogramSample ( 26 ) , histogramSample ( 30 ) } ,
[ ] tsdbutil . Sample { histogramSample ( 31 ) , histogramSample ( 35 ) } ,
) ,
} ,
{
name : "histogram chunks overlapping with float chunks" ,
input : [ ] ChunkSeries {
NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) , [ ] tsdbutil . Sample { histogramSample ( 0 ) , histogramSample ( 5 ) } , [ ] tsdbutil . Sample { histogramSample ( 10 ) , histogramSample ( 15 ) } ) ,
2022-12-08 04:31:08 -08:00
NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) , [ ] tsdbutil . Sample { fSample { 1 , 1 } , fSample { 12 , 12 } } , [ ] tsdbutil . Sample { fSample { 14 , 14 } } ) ,
2022-08-22 06:34:39 -07:00
} ,
expected : NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) ,
[ ] tsdbutil . Sample { histogramSample ( 0 ) } ,
2022-12-08 04:31:08 -08:00
[ ] tsdbutil . Sample { fSample { 1 , 1 } } ,
2022-08-22 06:34:39 -07:00
[ ] tsdbutil . Sample { histogramSample ( 5 ) , histogramSample ( 10 ) } ,
2022-12-08 04:31:08 -08:00
[ ] tsdbutil . Sample { fSample { 12 , 12 } , fSample { 14 , 14 } } ,
2022-08-22 06:34:39 -07:00
[ ] tsdbutil . Sample { histogramSample ( 15 ) } ,
) ,
2023-07-04 22:29:00 -07:00
expectedChunksEstimate : 4 , // Estimation assumes overlapping chunks don't swap back and forth between different encodings.
2022-08-22 06:34:39 -07:00
} ,
2023-02-10 03:39:33 -08:00
{
name : "float histogram chunks overlapping" ,
input : [ ] ChunkSeries {
NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) , [ ] tsdbutil . Sample { floatHistogramSample ( 0 ) , floatHistogramSample ( 5 ) } , [ ] tsdbutil . Sample { floatHistogramSample ( 10 ) , floatHistogramSample ( 15 ) } ) ,
NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) , [ ] tsdbutil . Sample { floatHistogramSample ( 2 ) , floatHistogramSample ( 20 ) } , [ ] tsdbutil . Sample { floatHistogramSample ( 25 ) , floatHistogramSample ( 30 ) } ) ,
NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) , [ ] tsdbutil . Sample { floatHistogramSample ( 18 ) , floatHistogramSample ( 26 ) } , [ ] tsdbutil . Sample { floatHistogramSample ( 31 ) , floatHistogramSample ( 35 ) } ) ,
} ,
expected : NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) ,
[ ] tsdbutil . Sample { floatHistogramSample ( 0 ) , floatHistogramSample ( 2 ) , floatHistogramSample ( 5 ) , floatHistogramSample ( 10 ) , floatHistogramSample ( 15 ) , floatHistogramSample ( 18 ) , floatHistogramSample ( 20 ) , floatHistogramSample ( 25 ) , floatHistogramSample ( 26 ) , floatHistogramSample ( 30 ) } ,
[ ] tsdbutil . Sample { floatHistogramSample ( 31 ) , floatHistogramSample ( 35 ) } ,
) ,
} ,
{
name : "float histogram chunks overlapping with float chunks" ,
input : [ ] ChunkSeries {
NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) , [ ] tsdbutil . Sample { floatHistogramSample ( 0 ) , floatHistogramSample ( 5 ) } , [ ] tsdbutil . Sample { floatHistogramSample ( 10 ) , floatHistogramSample ( 15 ) } ) ,
2022-12-08 04:31:08 -08:00
NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) , [ ] tsdbutil . Sample { fSample { 1 , 1 } , fSample { 12 , 12 } } , [ ] tsdbutil . Sample { fSample { 14 , 14 } } ) ,
2023-02-10 03:39:33 -08:00
} ,
expected : NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) ,
[ ] tsdbutil . Sample { floatHistogramSample ( 0 ) } ,
2022-12-08 04:31:08 -08:00
[ ] tsdbutil . Sample { fSample { 1 , 1 } } ,
2023-02-10 03:39:33 -08:00
[ ] tsdbutil . Sample { floatHistogramSample ( 5 ) , floatHistogramSample ( 10 ) } ,
2022-12-08 04:31:08 -08:00
[ ] tsdbutil . Sample { fSample { 12 , 12 } , fSample { 14 , 14 } } ,
2023-02-10 03:39:33 -08:00
[ ] tsdbutil . Sample { floatHistogramSample ( 15 ) } ,
) ,
2023-07-04 22:29:00 -07:00
expectedChunksEstimate : 4 , // Estimation assumes overlapping chunks don't swap back and forth between different encodings.
2023-02-10 03:39:33 -08:00
} ,
{
name : "float histogram chunks overlapping with histogram chunks" ,
input : [ ] ChunkSeries {
NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) , [ ] tsdbutil . Sample { floatHistogramSample ( 0 ) , floatHistogramSample ( 5 ) } , [ ] tsdbutil . Sample { floatHistogramSample ( 10 ) , floatHistogramSample ( 15 ) } ) ,
NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) , [ ] tsdbutil . Sample { histogramSample ( 1 ) , histogramSample ( 12 ) } , [ ] tsdbutil . Sample { histogramSample ( 14 ) } ) ,
} ,
expected : NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) ,
[ ] tsdbutil . Sample { floatHistogramSample ( 0 ) } ,
[ ] tsdbutil . Sample { histogramSample ( 1 ) } ,
[ ] tsdbutil . Sample { floatHistogramSample ( 5 ) , floatHistogramSample ( 10 ) } ,
[ ] tsdbutil . Sample { histogramSample ( 12 ) , histogramSample ( 14 ) } ,
[ ] tsdbutil . Sample { floatHistogramSample ( 15 ) } ,
) ,
2023-07-04 22:29:00 -07:00
expectedChunksEstimate : 4 , // Estimation assumes overlapping chunks don't swap back and forth between different encodings.
2023-02-10 03:39:33 -08:00
} ,
2020-08-03 03:32:56 -07:00
} {
t . Run ( tc . name , func ( t * testing . T ) {
merged := m ( tc . input ... )
2020-10-29 02:43:23 -07:00
require . Equal ( t , tc . expected . Labels ( ) , merged . Labels ( ) )
2022-09-20 10:16:45 -07:00
actChks , actErr := ExpandChunks ( merged . Iterator ( nil ) )
expChks , expErr := ExpandChunks ( tc . expected . Iterator ( nil ) )
2020-08-03 03:32:56 -07:00
2020-10-29 02:43:23 -07:00
require . Equal ( t , expErr , actErr )
require . Equal ( t , expChks , actChks )
2023-07-04 22:29:00 -07:00
if tc . expectedChunksEstimate == 0 {
tc . expectedChunksEstimate = len ( actChks )
}
require . Equalf ( t , tc . expectedChunksEstimate , merged . EstimatedChunkCount ( ) , "expected estimate of %v chunks, actual chunks are: %v" , tc . expectedChunksEstimate , actChks )
2020-08-03 03:32:56 -07:00
} )
}
}
2022-09-20 10:05:50 -07:00
func TestConcatenatingChunkSeriesMerger ( t * testing . T ) {
m := NewConcatenatingChunkSeriesMerger ( )
for _ , tc := range [ ] struct {
name string
input [ ] ChunkSeries
expected ChunkSeries
} {
{
name : "single empty series" ,
input : [ ] ChunkSeries {
NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) , nil ) ,
} ,
expected : NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) , nil ) ,
} ,
{
name : "single series" ,
input : [ ] ChunkSeries {
2022-12-08 04:31:08 -08:00
NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) , [ ] tsdbutil . Sample { fSample { 1 , 1 } , fSample { 2 , 2 } } , [ ] tsdbutil . Sample { fSample { 3 , 3 } } ) ,
2022-09-20 10:05:50 -07:00
} ,
2022-12-08 04:31:08 -08:00
expected : NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) , [ ] tsdbutil . Sample { fSample { 1 , 1 } , fSample { 2 , 2 } } , [ ] tsdbutil . Sample { fSample { 3 , 3 } } ) ,
2022-09-20 10:05:50 -07:00
} ,
{
name : "two empty series" ,
input : [ ] ChunkSeries {
NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) , nil ) ,
NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) , nil ) ,
} ,
expected : NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) , nil , nil ) ,
} ,
{
name : "two non overlapping" ,
input : [ ] ChunkSeries {
2022-12-08 04:31:08 -08:00
NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) , [ ] tsdbutil . Sample { fSample { 1 , 1 } , fSample { 2 , 2 } } , [ ] tsdbutil . Sample { fSample { 3 , 3 } , fSample { 5 , 5 } } ) ,
NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) , [ ] tsdbutil . Sample { fSample { 7 , 7 } , fSample { 9 , 9 } } , [ ] tsdbutil . Sample { fSample { 10 , 10 } } ) ,
2022-09-20 10:05:50 -07:00
} ,
2022-12-08 04:31:08 -08:00
expected : NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) , [ ] tsdbutil . Sample { fSample { 1 , 1 } , fSample { 2 , 2 } } , [ ] tsdbutil . Sample { fSample { 3 , 3 } , fSample { 5 , 5 } } , [ ] tsdbutil . Sample { fSample { 7 , 7 } , fSample { 9 , 9 } } , [ ] tsdbutil . Sample { fSample { 10 , 10 } } ) ,
2022-09-20 10:05:50 -07:00
} ,
{
name : "two overlapping" ,
input : [ ] ChunkSeries {
2022-12-08 04:31:08 -08:00
NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) , [ ] tsdbutil . Sample { fSample { 1 , 1 } , fSample { 2 , 2 } } , [ ] tsdbutil . Sample { fSample { 3 , 3 } , fSample { 8 , 8 } } ) ,
NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) , [ ] tsdbutil . Sample { fSample { 7 , 7 } , fSample { 9 , 9 } } , [ ] tsdbutil . Sample { fSample { 10 , 10 } } ) ,
2022-09-20 10:05:50 -07:00
} ,
expected : NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) ,
2022-12-08 04:31:08 -08:00
[ ] tsdbutil . Sample { fSample { 1 , 1 } , fSample { 2 , 2 } } , [ ] tsdbutil . Sample { fSample { 3 , 3 } , fSample { 8 , 8 } } ,
[ ] tsdbutil . Sample { fSample { 7 , 7 } , fSample { 9 , 9 } } , [ ] tsdbutil . Sample { fSample { 10 , 10 } } ,
2022-09-20 10:05:50 -07:00
) ,
} ,
{
name : "two duplicated" ,
input : [ ] ChunkSeries {
2022-12-08 04:31:08 -08:00
NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) , [ ] tsdbutil . Sample { fSample { 1 , 1 } , fSample { 2 , 2 } , fSample { 3 , 3 } , fSample { 5 , 5 } } ) ,
NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) , [ ] tsdbutil . Sample { fSample { 2 , 2 } , fSample { 3 , 3 } , fSample { 5 , 5 } } ) ,
2022-09-20 10:05:50 -07:00
} ,
expected : NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) ,
2022-12-08 04:31:08 -08:00
[ ] tsdbutil . Sample { fSample { 1 , 1 } , fSample { 2 , 2 } , fSample { 3 , 3 } , fSample { 5 , 5 } } ,
[ ] tsdbutil . Sample { fSample { 2 , 2 } , fSample { 3 , 3 } , fSample { 5 , 5 } } ,
2022-09-20 10:05:50 -07:00
) ,
} ,
{
name : "three overlapping" ,
input : [ ] ChunkSeries {
2022-12-08 04:31:08 -08:00
NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) , [ ] tsdbutil . Sample { fSample { 1 , 1 } , fSample { 2 , 2 } , fSample { 3 , 3 } , fSample { 5 , 5 } } ) ,
NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) , [ ] tsdbutil . Sample { fSample { 2 , 2 } , fSample { 3 , 3 } , fSample { 6 , 6 } } ) ,
NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) , [ ] tsdbutil . Sample { fSample { 0 , 0 } , fSample { 4 , 4 } } ) ,
2022-09-20 10:05:50 -07:00
} ,
expected : NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) ,
2022-12-08 04:31:08 -08:00
[ ] tsdbutil . Sample { fSample { 1 , 1 } , fSample { 2 , 2 } , fSample { 3 , 3 } , fSample { 5 , 5 } } ,
[ ] tsdbutil . Sample { fSample { 2 , 2 } , fSample { 3 , 3 } , fSample { 6 , 6 } } ,
[ ] tsdbutil . Sample { fSample { 0 , 0 } , fSample { 4 , 4 } } ,
2022-09-20 10:05:50 -07:00
) ,
} ,
{
name : "three in chained overlap" ,
input : [ ] ChunkSeries {
2022-12-08 04:31:08 -08:00
NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) , [ ] tsdbutil . Sample { fSample { 1 , 1 } , fSample { 2 , 2 } , fSample { 3 , 3 } , fSample { 5 , 5 } } ) ,
NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) , [ ] tsdbutil . Sample { fSample { 4 , 4 } , fSample { 6 , 66 } } ) ,
NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) , [ ] tsdbutil . Sample { fSample { 6 , 6 } , fSample { 10 , 10 } } ) ,
2022-09-20 10:05:50 -07:00
} ,
expected : NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) ,
2022-12-08 04:31:08 -08:00
[ ] tsdbutil . Sample { fSample { 1 , 1 } , fSample { 2 , 2 } , fSample { 3 , 3 } , fSample { 5 , 5 } } ,
[ ] tsdbutil . Sample { fSample { 4 , 4 } , fSample { 6 , 66 } } ,
[ ] tsdbutil . Sample { fSample { 6 , 6 } , fSample { 10 , 10 } } ,
2022-09-20 10:05:50 -07:00
) ,
} ,
{
name : "three in chained overlap complex" ,
input : [ ] ChunkSeries {
2022-12-08 04:31:08 -08:00
NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) , [ ] tsdbutil . Sample { fSample { 0 , 0 } , fSample { 5 , 5 } } , [ ] tsdbutil . Sample { fSample { 10 , 10 } , fSample { 15 , 15 } } ) ,
NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) , [ ] tsdbutil . Sample { fSample { 2 , 2 } , fSample { 20 , 20 } } , [ ] tsdbutil . Sample { fSample { 25 , 25 } , fSample { 30 , 30 } } ) ,
NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) , [ ] tsdbutil . Sample { fSample { 18 , 18 } , fSample { 26 , 26 } } , [ ] tsdbutil . Sample { fSample { 31 , 31 } , fSample { 35 , 35 } } ) ,
2022-09-20 10:05:50 -07:00
} ,
expected : NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) ,
2022-12-08 04:31:08 -08:00
[ ] tsdbutil . Sample { fSample { 0 , 0 } , fSample { 5 , 5 } } , [ ] tsdbutil . Sample { fSample { 10 , 10 } , fSample { 15 , 15 } } ,
[ ] tsdbutil . Sample { fSample { 2 , 2 } , fSample { 20 , 20 } } , [ ] tsdbutil . Sample { fSample { 25 , 25 } , fSample { 30 , 30 } } ,
[ ] tsdbutil . Sample { fSample { 18 , 18 } , fSample { 26 , 26 } } , [ ] tsdbutil . Sample { fSample { 31 , 31 } , fSample { 35 , 35 } } ,
2022-09-20 10:05:50 -07:00
) ,
} ,
{
name : "110 overlapping" ,
input : [ ] ChunkSeries {
NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) , tsdbutil . GenerateSamples ( 0 , 110 ) ) , // [0 - 110)
NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) , tsdbutil . GenerateSamples ( 60 , 50 ) ) , // [60 - 110)
} ,
expected : NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) ,
tsdbutil . GenerateSamples ( 0 , 110 ) ,
tsdbutil . GenerateSamples ( 60 , 50 ) ,
) ,
} ,
{
name : "150 overlapping samples, simply concatenated and no splits" ,
input : [ ] ChunkSeries {
NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) , tsdbutil . GenerateSamples ( 0 , 90 ) ) , // [0 - 90)
NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) , tsdbutil . GenerateSamples ( 60 , 90 ) ) , // [90 - 150)
} ,
expected : NewListChunkSeriesFromSamples ( labels . FromStrings ( "bar" , "baz" ) ,
tsdbutil . GenerateSamples ( 0 , 90 ) ,
tsdbutil . GenerateSamples ( 60 , 90 ) ,
) ,
} ,
} {
t . Run ( tc . name , func ( t * testing . T ) {
merged := m ( tc . input ... )
require . Equal ( t , tc . expected . Labels ( ) , merged . Labels ( ) )
2022-09-20 10:16:45 -07:00
actChks , actErr := ExpandChunks ( merged . Iterator ( nil ) )
expChks , expErr := ExpandChunks ( tc . expected . Iterator ( nil ) )
2022-09-20 10:05:50 -07:00
require . Equal ( t , expErr , actErr )
require . Equal ( t , expChks , actChks )
2023-07-04 22:29:00 -07:00
require . Equal ( t , len ( expChks ) , merged . EstimatedChunkCount ( ) )
2022-09-20 10:05:50 -07:00
} )
}
}
2020-08-03 03:32:56 -07:00
type mockQuerier struct {
LabelQuerier
toReturn [ ] Series
}
type seriesByLabel [ ] Series
func ( a seriesByLabel ) Len ( ) int { return len ( a ) }
func ( a seriesByLabel ) Swap ( i , j int ) { a [ i ] , a [ j ] = a [ j ] , a [ i ] }
func ( a seriesByLabel ) Less ( i , j int ) bool { return labels . Compare ( a [ i ] . Labels ( ) , a [ j ] . Labels ( ) ) < 0 }
func ( m * mockQuerier ) Select ( sortSeries bool , _ * SelectHints , _ ... * labels . Matcher ) SeriesSet {
cpy := make ( [ ] Series , len ( m . toReturn ) )
copy ( cpy , m . toReturn )
if sortSeries {
sort . Sort ( seriesByLabel ( cpy ) )
}
return NewMockSeriesSet ( cpy ... )
}
type mockChunkQurier struct {
LabelQuerier
toReturn [ ] ChunkSeries
}
type chunkSeriesByLabel [ ] ChunkSeries
func ( a chunkSeriesByLabel ) Len ( ) int { return len ( a ) }
func ( a chunkSeriesByLabel ) Swap ( i , j int ) { a [ i ] , a [ j ] = a [ j ] , a [ i ] }
func ( a chunkSeriesByLabel ) Less ( i , j int ) bool {
return labels . Compare ( a [ i ] . Labels ( ) , a [ j ] . Labels ( ) ) < 0
}
func ( m * mockChunkQurier ) Select ( sortSeries bool , _ * SelectHints , _ ... * labels . Matcher ) ChunkSeriesSet {
cpy := make ( [ ] ChunkSeries , len ( m . toReturn ) )
copy ( cpy , m . toReturn )
if sortSeries {
sort . Sort ( chunkSeriesByLabel ( cpy ) )
}
return NewMockChunkSeriesSet ( cpy ... )
}
type mockSeriesSet struct {
idx int
series [ ] Series
}
func NewMockSeriesSet ( series ... Series ) SeriesSet {
return & mockSeriesSet {
idx : - 1 ,
series : series ,
}
}
func ( m * mockSeriesSet ) Next ( ) bool {
m . idx ++
return m . idx < len ( m . series )
}
func ( m * mockSeriesSet ) At ( ) Series { return m . series [ m . idx ] }
func ( m * mockSeriesSet ) Err ( ) error { return nil }
func ( m * mockSeriesSet ) Warnings ( ) Warnings { return nil }
type mockChunkSeriesSet struct {
idx int
series [ ] ChunkSeries
}
func NewMockChunkSeriesSet ( series ... ChunkSeries ) ChunkSeriesSet {
return & mockChunkSeriesSet {
idx : - 1 ,
series : series ,
}
}
func ( m * mockChunkSeriesSet ) Next ( ) bool {
m . idx ++
return m . idx < len ( m . series )
}
func ( m * mockChunkSeriesSet ) At ( ) ChunkSeries { return m . series [ m . idx ] }
func ( m * mockChunkSeriesSet ) Err ( ) error { return nil }
func ( m * mockChunkSeriesSet ) Warnings ( ) Warnings { return nil }
func TestChainSampleIterator ( t * testing . T ) {
for _ , tc := range [ ] struct {
input [ ] chunkenc . Iterator
expected [ ] tsdbutil . Sample
} {
{
input : [ ] chunkenc . Iterator {
2022-12-08 04:31:08 -08:00
NewListSeriesIterator ( samples { fSample { 0 , 0 } , fSample { 1 , 1 } } ) ,
2020-08-03 03:32:56 -07:00
} ,
2022-12-08 04:31:08 -08:00
expected : [ ] tsdbutil . Sample { fSample { 0 , 0 } , fSample { 1 , 1 } } ,
2020-08-03 03:32:56 -07:00
} ,
{
input : [ ] chunkenc . Iterator {
2022-12-08 04:31:08 -08:00
NewListSeriesIterator ( samples { fSample { 0 , 0 } , fSample { 1 , 1 } } ) ,
NewListSeriesIterator ( samples { fSample { 2 , 2 } , fSample { 3 , 3 } } ) ,
2020-08-03 03:32:56 -07:00
} ,
2022-12-08 04:31:08 -08:00
expected : [ ] tsdbutil . Sample { fSample { 0 , 0 } , fSample { 1 , 1 } , fSample { 2 , 2 } , fSample { 3 , 3 } } ,
2020-08-03 03:32:56 -07:00
} ,
{
input : [ ] chunkenc . Iterator {
2022-12-08 04:31:08 -08:00
NewListSeriesIterator ( samples { fSample { 0 , 0 } , fSample { 3 , 3 } } ) ,
NewListSeriesIterator ( samples { fSample { 1 , 1 } , fSample { 4 , 4 } } ) ,
NewListSeriesIterator ( samples { fSample { 2 , 2 } , fSample { 5 , 5 } } ) ,
2020-08-03 03:32:56 -07:00
} ,
expected : [ ] tsdbutil . Sample {
2022-12-08 04:31:08 -08:00
fSample { 0 , 0 } , fSample { 1 , 1 } , fSample { 2 , 2 } , fSample { 3 , 3 } , fSample { 4 , 4 } , fSample { 5 , 5 } ,
2021-10-22 01:06:44 -07:00
} ,
2020-08-03 03:32:56 -07:00
} ,
// Overlap.
{
input : [ ] chunkenc . Iterator {
2022-12-08 04:31:08 -08:00
NewListSeriesIterator ( samples { fSample { 0 , 0 } , fSample { 1 , 1 } } ) ,
NewListSeriesIterator ( samples { fSample { 0 , 0 } , fSample { 2 , 2 } } ) ,
NewListSeriesIterator ( samples { fSample { 2 , 2 } , fSample { 3 , 3 } } ) ,
2020-08-03 03:32:56 -07:00
NewListSeriesIterator ( samples { } ) ,
NewListSeriesIterator ( samples { } ) ,
NewListSeriesIterator ( samples { } ) ,
} ,
2022-12-08 04:31:08 -08:00
expected : [ ] tsdbutil . Sample { fSample { 0 , 0 } , fSample { 1 , 1 } , fSample { 2 , 2 } , fSample { 3 , 3 } } ,
2020-08-03 03:32:56 -07:00
} ,
} {
2022-09-20 11:31:28 -07:00
merged := ChainSampleIteratorFromIterators ( nil , tc . input )
2020-08-03 03:32:56 -07:00
actual , err := ExpandSamples ( merged , nil )
2020-10-29 02:43:23 -07:00
require . NoError ( t , err )
require . Equal ( t , tc . expected , actual )
2020-08-03 03:32:56 -07:00
}
}
func TestChainSampleIteratorSeek ( t * testing . T ) {
for _ , tc := range [ ] struct {
input [ ] chunkenc . Iterator
seek int64
expected [ ] tsdbutil . Sample
} {
{
input : [ ] chunkenc . Iterator {
2022-12-08 04:31:08 -08:00
NewListSeriesIterator ( samples { fSample { 0 , 0 } , fSample { 1 , 1 } , fSample { 2 , 2 } } ) ,
2020-08-03 03:32:56 -07:00
} ,
seek : 1 ,
2022-12-08 04:31:08 -08:00
expected : [ ] tsdbutil . Sample { fSample { 1 , 1 } , fSample { 2 , 2 } } ,
2020-08-03 03:32:56 -07:00
} ,
{
input : [ ] chunkenc . Iterator {
2022-12-08 04:31:08 -08:00
NewListSeriesIterator ( samples { fSample { 0 , 0 } , fSample { 1 , 1 } } ) ,
NewListSeriesIterator ( samples { fSample { 2 , 2 } , fSample { 3 , 3 } } ) ,
2020-08-03 03:32:56 -07:00
} ,
seek : 2 ,
2022-12-08 04:31:08 -08:00
expected : [ ] tsdbutil . Sample { fSample { 2 , 2 } , fSample { 3 , 3 } } ,
2020-08-03 03:32:56 -07:00
} ,
{
input : [ ] chunkenc . Iterator {
2022-12-08 04:31:08 -08:00
NewListSeriesIterator ( samples { fSample { 0 , 0 } , fSample { 3 , 3 } } ) ,
NewListSeriesIterator ( samples { fSample { 1 , 1 } , fSample { 4 , 4 } } ) ,
NewListSeriesIterator ( samples { fSample { 2 , 2 } , fSample { 5 , 5 } } ) ,
2020-08-03 03:32:56 -07:00
} ,
seek : 2 ,
2022-12-08 04:31:08 -08:00
expected : [ ] tsdbutil . Sample { fSample { 2 , 2 } , fSample { 3 , 3 } , fSample { 4 , 4 } , fSample { 5 , 5 } } ,
2020-08-03 03:32:56 -07:00
} ,
2021-03-12 03:32:15 -08:00
{
input : [ ] chunkenc . Iterator {
2022-12-08 04:31:08 -08:00
NewListSeriesIterator ( samples { fSample { 0 , 0 } , fSample { 2 , 2 } , fSample { 3 , 3 } } ) ,
NewListSeriesIterator ( samples { fSample { 0 , 0 } , fSample { 1 , 1 } , fSample { 2 , 2 } } ) ,
2021-03-12 03:32:15 -08:00
} ,
seek : 0 ,
2022-12-08 04:31:08 -08:00
expected : [ ] tsdbutil . Sample { fSample { 0 , 0 } , fSample { 1 , 1 } , fSample { 2 , 2 } , fSample { 3 , 3 } } ,
2021-03-12 03:32:15 -08:00
} ,
2020-08-03 03:32:56 -07:00
} {
2022-09-20 11:31:28 -07:00
merged := ChainSampleIteratorFromIterators ( nil , tc . input )
2020-08-03 03:32:56 -07:00
actual := [ ] tsdbutil . Sample { }
2021-11-28 23:54:23 -08:00
if merged . Seek ( tc . seek ) == chunkenc . ValFloat {
2022-12-08 04:31:08 -08:00
t , f := merged . At ( )
actual = append ( actual , fSample { t , f } )
2020-08-03 03:32:56 -07:00
}
s , err := ExpandSamples ( merged , nil )
2020-10-29 02:43:23 -07:00
require . NoError ( t , err )
2020-08-03 03:32:56 -07:00
actual = append ( actual , s ... )
2020-10-29 02:43:23 -07:00
require . Equal ( t , tc . expected , actual )
2020-08-03 03:32:56 -07:00
}
}
2022-09-21 03:56:44 -07:00
func makeSeries ( numSeries , numSamples int ) [ ] Series {
2020-08-03 03:32:56 -07:00
series := [ ] Series { }
for j := 0 ; j < numSeries ; j ++ {
2022-03-09 14:21:50 -08:00
labels := labels . FromStrings ( "foo" , fmt . Sprintf ( "bar%d" , j ) )
2020-08-03 03:32:56 -07:00
samples := [ ] tsdbutil . Sample { }
for k := 0 ; k < numSamples ; k ++ {
2022-12-08 04:31:08 -08:00
samples = append ( samples , fSample { t : int64 ( k ) , f : float64 ( k ) } )
2020-08-03 03:32:56 -07:00
}
series = append ( series , NewListSeries ( labels , samples ) )
}
2022-09-21 03:56:44 -07:00
return series
2020-08-03 03:32:56 -07:00
}
2022-09-21 03:56:44 -07:00
func makeMergeSeriesSet ( serieses [ ] [ ] Series ) SeriesSet {
seriesSets := make ( [ ] genericSeriesSet , len ( serieses ) )
for i , s := range serieses {
seriesSets [ i ] = & genericSeriesSetAdapter { NewMockSeriesSet ( s ... ) }
2020-08-03 03:32:56 -07:00
}
return & seriesSetAdapter { newGenericMergeSeriesSet ( seriesSets , ( & seriesMergerAdapter { VerticalSeriesMergeFunc : ChainedSeriesMerge } ) . Merge ) }
}
2022-09-21 03:56:44 -07:00
func benchmarkDrain ( b * testing . B , makeSeriesSet func ( ) SeriesSet ) {
2020-08-03 03:32:56 -07:00
var err error
2022-09-21 03:56:44 -07:00
var t int64
var v float64
2022-09-20 10:16:45 -07:00
var iter chunkenc . Iterator
2020-08-03 03:32:56 -07:00
for n := 0 ; n < b . N ; n ++ {
2022-09-21 03:56:44 -07:00
seriesSet := makeSeriesSet ( )
2020-08-03 03:32:56 -07:00
for seriesSet . Next ( ) {
2022-09-20 10:16:45 -07:00
iter = seriesSet . At ( ) . Iterator ( iter )
2022-09-21 03:56:44 -07:00
for iter . Next ( ) == chunkenc . ValFloat {
t , v = iter . At ( )
}
err = iter . Err ( )
2020-08-03 03:32:56 -07:00
}
2022-09-21 03:56:44 -07:00
require . NoError ( b , err )
require . NotEqual ( b , t , v ) // To ensure the inner loop doesn't get optimised away.
2020-08-03 03:32:56 -07:00
}
}
func BenchmarkNoMergeSeriesSet_100_100 ( b * testing . B ) {
2022-09-21 03:56:44 -07:00
series := makeSeries ( 100 , 100 )
benchmarkDrain ( b , func ( ) SeriesSet { return NewMockSeriesSet ( series ... ) } )
2020-08-03 03:32:56 -07:00
}
func BenchmarkMergeSeriesSet ( b * testing . B ) {
for _ , bm := range [ ] struct {
numSeriesSets , numSeries , numSamples int
} {
{ 1 , 100 , 100 } ,
{ 10 , 100 , 100 } ,
{ 100 , 100 , 100 } ,
} {
2022-09-21 03:56:44 -07:00
serieses := [ ] [ ] Series { }
for i := 0 ; i < bm . numSeriesSets ; i ++ {
serieses = append ( serieses , makeSeries ( bm . numSeries , bm . numSamples ) )
}
2020-08-03 03:32:56 -07:00
b . Run ( fmt . Sprintf ( "%d_%d_%d" , bm . numSeriesSets , bm . numSeries , bm . numSamples ) , func ( b * testing . B ) {
2022-09-21 03:56:44 -07:00
benchmarkDrain ( b , func ( ) SeriesSet { return makeMergeSeriesSet ( serieses ) } )
2020-08-03 03:32:56 -07:00
} )
}
}
type mockGenericQuerier struct {
mtx sync . Mutex
closed bool
labelNamesCalls int
2021-02-09 09:38:35 -08:00
labelNamesRequested [ ] labelNameRequest
2020-08-03 03:32:56 -07:00
sortedSeriesRequested [ ] bool
resp [ ] string
warnings Warnings
err error
}
2021-02-09 09:38:35 -08:00
type labelNameRequest struct {
name string
matchers [ ] * labels . Matcher
}
2020-08-03 03:32:56 -07:00
func ( m * mockGenericQuerier ) Select ( b bool , _ * SelectHints , _ ... * labels . Matcher ) genericSeriesSet {
m . mtx . Lock ( )
m . sortedSeriesRequested = append ( m . sortedSeriesRequested , b )
m . mtx . Unlock ( )
return & mockGenericSeriesSet { resp : m . resp , warnings : m . warnings , err : m . err }
}
2021-02-09 09:38:35 -08:00
func ( m * mockGenericQuerier ) LabelValues ( name string , matchers ... * labels . Matcher ) ( [ ] string , Warnings , error ) {
2020-08-03 03:32:56 -07:00
m . mtx . Lock ( )
2021-02-09 09:38:35 -08:00
m . labelNamesRequested = append ( m . labelNamesRequested , labelNameRequest {
name : name ,
matchers : matchers ,
} )
2020-08-03 03:32:56 -07:00
m . mtx . Unlock ( )
return m . resp , m . warnings , m . err
}
2021-07-20 05:38:08 -07:00
func ( m * mockGenericQuerier ) LabelNames ( ... * labels . Matcher ) ( [ ] string , Warnings , error ) {
2020-08-03 03:32:56 -07:00
m . mtx . Lock ( )
m . labelNamesCalls ++
m . mtx . Unlock ( )
return m . resp , m . warnings , m . err
}
func ( m * mockGenericQuerier ) Close ( ) error {
m . closed = true
return nil
}
type mockGenericSeriesSet struct {
resp [ ] string
warnings Warnings
err error
curr int
}
func ( m * mockGenericSeriesSet ) Next ( ) bool {
if m . err != nil {
return false
}
if m . curr >= len ( m . resp ) {
return false
}
m . curr ++
return true
}
func ( m * mockGenericSeriesSet ) Err ( ) error { return m . err }
func ( m * mockGenericSeriesSet ) Warnings ( ) Warnings { return m . warnings }
func ( m * mockGenericSeriesSet ) At ( ) Labels {
return mockLabels ( m . resp [ m . curr - 1 ] )
}
type mockLabels string
func ( l mockLabels ) Labels ( ) labels . Labels {
return labels . FromStrings ( "test" , string ( l ) )
}
func unwrapMockGenericQuerier ( t * testing . T , qr genericQuerier ) * mockGenericQuerier {
m , ok := qr . ( * mockGenericQuerier )
if ! ok {
s , ok := qr . ( * secondaryQuerier )
2020-10-29 02:43:23 -07:00
require . True ( t , ok , "expected secondaryQuerier got something else" )
2020-08-03 03:32:56 -07:00
m , ok = s . genericQuerier . ( * mockGenericQuerier )
2020-10-29 02:43:23 -07:00
require . True ( t , ok , "expected mockGenericQuerier got something else" )
2020-08-03 03:32:56 -07:00
}
return m
}
func TestMergeGenericQuerierWithSecondaries_ErrorHandling ( t * testing . T ) {
var (
errStorage = errors . New ( "storage error" )
warnStorage = errors . New ( "storage warning" )
)
for _ , tcase := range [ ] struct {
name string
queriers [ ] genericQuerier
expectedSelectsSeries [ ] labels . Labels
expectedLabels [ ] string
2021-02-09 09:38:35 -08:00
expectedWarnings [ 4 ] Warnings
expectedErrs [ 4 ] error
2020-08-03 03:32:56 -07:00
} {
{ } ,
{
name : "one successful primary querier" ,
queriers : [ ] genericQuerier { & mockGenericQuerier { resp : [ ] string { "a" , "b" } , warnings : nil , err : nil } } ,
expectedSelectsSeries : [ ] labels . Labels {
labels . FromStrings ( "test" , "a" ) ,
labels . FromStrings ( "test" , "b" ) ,
} ,
expectedLabels : [ ] string { "a" , "b" } ,
} ,
{
name : "multiple successful primary queriers" ,
queriers : [ ] genericQuerier {
& mockGenericQuerier { resp : [ ] string { "a" , "b" } , warnings : nil , err : nil } ,
& mockGenericQuerier { resp : [ ] string { "b" , "c" } , warnings : nil , err : nil } ,
} ,
expectedSelectsSeries : [ ] labels . Labels {
labels . FromStrings ( "test" , "a" ) ,
labels . FromStrings ( "test" , "b" ) ,
labels . FromStrings ( "test" , "c" ) ,
} ,
expectedLabels : [ ] string { "a" , "b" , "c" } ,
} ,
{
name : "one failed primary querier" ,
queriers : [ ] genericQuerier { & mockGenericQuerier { warnings : nil , err : errStorage } } ,
2021-02-09 09:38:35 -08:00
expectedErrs : [ 4 ] error { errStorage , errStorage , errStorage , errStorage } ,
2020-08-03 03:32:56 -07:00
} ,
{
name : "one successful primary querier with successful secondaries" ,
queriers : [ ] genericQuerier {
& mockGenericQuerier { resp : [ ] string { "a" , "b" } , warnings : nil , err : nil } ,
& secondaryQuerier { genericQuerier : & mockGenericQuerier { resp : [ ] string { "b" } , warnings : nil , err : nil } } ,
& secondaryQuerier { genericQuerier : & mockGenericQuerier { resp : [ ] string { "c" } , warnings : nil , err : nil } } ,
} ,
expectedSelectsSeries : [ ] labels . Labels {
labels . FromStrings ( "test" , "a" ) ,
labels . FromStrings ( "test" , "b" ) ,
labels . FromStrings ( "test" , "c" ) ,
} ,
expectedLabels : [ ] string { "a" , "b" , "c" } ,
} ,
{
name : "one successful primary querier with empty response and successful secondaries" ,
queriers : [ ] genericQuerier {
& mockGenericQuerier { resp : [ ] string { } , warnings : nil , err : nil } ,
& secondaryQuerier { genericQuerier : & mockGenericQuerier { resp : [ ] string { "b" } , warnings : nil , err : nil } } ,
& secondaryQuerier { genericQuerier : & mockGenericQuerier { resp : [ ] string { "c" } , warnings : nil , err : nil } } ,
} ,
expectedSelectsSeries : [ ] labels . Labels {
labels . FromStrings ( "test" , "b" ) ,
labels . FromStrings ( "test" , "c" ) ,
} ,
expectedLabels : [ ] string { "b" , "c" } ,
} ,
{
name : "one failed primary querier with successful secondaries" ,
queriers : [ ] genericQuerier {
& mockGenericQuerier { warnings : nil , err : errStorage } ,
& secondaryQuerier { genericQuerier : & mockGenericQuerier { resp : [ ] string { "b" } , warnings : nil , err : nil } } ,
& secondaryQuerier { genericQuerier : & mockGenericQuerier { resp : [ ] string { "c" } , warnings : nil , err : nil } } ,
} ,
2021-02-09 09:38:35 -08:00
expectedErrs : [ 4 ] error { errStorage , errStorage , errStorage , errStorage } ,
2020-08-03 03:32:56 -07:00
} ,
{
name : "one successful primary querier with failed secondaries" ,
queriers : [ ] genericQuerier {
& mockGenericQuerier { resp : [ ] string { "a" } , warnings : nil , err : nil } ,
& secondaryQuerier { genericQuerier : & mockGenericQuerier { resp : [ ] string { "b" } , warnings : nil , err : errStorage } } ,
& secondaryQuerier { genericQuerier : & mockGenericQuerier { resp : [ ] string { "c" } , warnings : nil , err : errStorage } } ,
} ,
expectedSelectsSeries : [ ] labels . Labels {
labels . FromStrings ( "test" , "a" ) ,
} ,
expectedLabels : [ ] string { "a" } ,
2021-02-09 09:38:35 -08:00
expectedWarnings : [ 4 ] Warnings {
[ ] error { errStorage , errStorage } ,
2020-08-03 03:32:56 -07:00
[ ] error { errStorage , errStorage } ,
[ ] error { errStorage , errStorage } ,
[ ] error { errStorage , errStorage } ,
} ,
} ,
{
name : "successful queriers with warnings" ,
queriers : [ ] genericQuerier {
& mockGenericQuerier { resp : [ ] string { "a" } , warnings : [ ] error { warnStorage } , err : nil } ,
& secondaryQuerier { genericQuerier : & mockGenericQuerier { resp : [ ] string { "b" } , warnings : [ ] error { warnStorage } , err : nil } } ,
} ,
expectedSelectsSeries : [ ] labels . Labels {
labels . FromStrings ( "test" , "a" ) ,
labels . FromStrings ( "test" , "b" ) ,
} ,
expectedLabels : [ ] string { "a" , "b" } ,
2021-02-09 09:38:35 -08:00
expectedWarnings : [ 4 ] Warnings {
[ ] error { warnStorage , warnStorage } ,
2020-08-03 03:32:56 -07:00
[ ] error { warnStorage , warnStorage } ,
[ ] error { warnStorage , warnStorage } ,
[ ] error { warnStorage , warnStorage } ,
} ,
} ,
} {
t . Run ( tcase . name , func ( t * testing . T ) {
q := & mergeGenericQuerier {
queriers : tcase . queriers ,
mergeFn : func ( l ... Labels ) Labels { return l [ 0 ] } ,
}
t . Run ( "Select" , func ( t * testing . T ) {
res := q . Select ( false , nil )
var lbls [ ] labels . Labels
for res . Next ( ) {
lbls = append ( lbls , res . At ( ) . Labels ( ) )
}
2020-10-29 02:43:23 -07:00
require . Equal ( t , tcase . expectedWarnings [ 0 ] , res . Warnings ( ) )
require . Equal ( t , tcase . expectedErrs [ 0 ] , res . Err ( ) )
require . True ( t , errors . Is ( res . Err ( ) , tcase . expectedErrs [ 0 ] ) , "expected error doesn't match" )
require . Equal ( t , tcase . expectedSelectsSeries , lbls )
2020-08-03 03:32:56 -07:00
for _ , qr := range q . queriers {
m := unwrapMockGenericQuerier ( t , qr )
exp := [ ] bool { true }
if len ( q . queriers ) == 1 {
exp [ 0 ] = false
}
2020-10-29 02:43:23 -07:00
require . Equal ( t , exp , m . sortedSeriesRequested )
2020-08-03 03:32:56 -07:00
}
} )
t . Run ( "LabelNames" , func ( t * testing . T ) {
res , w , err := q . LabelNames ( )
2020-10-29 02:43:23 -07:00
require . Equal ( t , tcase . expectedWarnings [ 1 ] , w )
require . True ( t , errors . Is ( err , tcase . expectedErrs [ 1 ] ) , "expected error doesn't match" )
require . Equal ( t , tcase . expectedLabels , res )
2020-08-03 03:32:56 -07:00
if err != nil {
return
}
for _ , qr := range q . queriers {
m := unwrapMockGenericQuerier ( t , qr )
2020-10-29 02:43:23 -07:00
require . Equal ( t , 1 , m . labelNamesCalls )
2020-08-03 03:32:56 -07:00
}
} )
t . Run ( "LabelValues" , func ( t * testing . T ) {
res , w , err := q . LabelValues ( "test" )
2020-10-29 02:43:23 -07:00
require . Equal ( t , tcase . expectedWarnings [ 2 ] , w )
require . True ( t , errors . Is ( err , tcase . expectedErrs [ 2 ] ) , "expected error doesn't match" )
require . Equal ( t , tcase . expectedLabels , res )
2020-08-03 03:32:56 -07:00
if err != nil {
return
}
for _ , qr := range q . queriers {
m := unwrapMockGenericQuerier ( t , qr )
2021-02-09 09:38:35 -08:00
require . Equal ( t , [ ] labelNameRequest { { name : "test" } } , m . labelNamesRequested )
}
} )
t . Run ( "LabelValuesWithMatchers" , func ( t * testing . T ) {
matcher := labels . MustNewMatcher ( labels . MatchEqual , "otherLabel" , "someValue" )
res , w , err := q . LabelValues ( "test2" , matcher )
require . Equal ( t , tcase . expectedWarnings [ 3 ] , w )
require . True ( t , errors . Is ( err , tcase . expectedErrs [ 3 ] ) , "expected error doesn't match" )
require . Equal ( t , tcase . expectedLabels , res )
if err != nil {
return
}
for _ , qr := range q . queriers {
m := unwrapMockGenericQuerier ( t , qr )
require . Equal ( t , [ ] labelNameRequest {
{ name : "test" } ,
{ name : "test2" , matchers : [ ] * labels . Matcher { matcher } } ,
} , m . labelNamesRequested )
2020-08-03 03:32:56 -07:00
}
} )
} )
}
}