| 
									
										
										
										
											2020-08-03 18:32:56 +08: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 ( | 
					
						
							| 
									
										
										
										
											2023-09-12 18:37:38 +08:00
										 |  |  | 	"context" | 
					
						
							| 
									
										
										
										
											2022-07-02 00:59:50 +08:00
										 |  |  | 	"errors" | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 	"fmt" | 
					
						
							|  |  |  | 	"math" | 
					
						
							|  |  |  | 	"sort" | 
					
						
							|  |  |  | 	"sync" | 
					
						
							|  |  |  | 	"testing" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-29 17:43:23 +08:00
										 |  |  | 	"github.com/stretchr/testify/require" | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-19 23:06:46 +08:00
										 |  |  | 	"github.com/prometheus/prometheus/model/histogram" | 
					
						
							| 
									
										
										
										
											2021-11-08 22:23:17 +08:00
										 |  |  | 	"github.com/prometheus/prometheus/model/labels" | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 	"github.com/prometheus/prometheus/tsdb/chunkenc" | 
					
						
							| 
									
										
										
										
											2023-08-24 21:21:17 +08:00
										 |  |  | 	"github.com/prometheus/prometheus/tsdb/chunks" | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 	"github.com/prometheus/prometheus/tsdb/tsdbutil" | 
					
						
							| 
									
										
										
										
											2023-09-15 00:57:31 +08:00
										 |  |  | 	"github.com/prometheus/prometheus/util/annotations" | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 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{{ | 
					
						
							| 
									
										
										
										
											2023-08-24 21:21:17 +08:00
										 |  |  | 				NewListSeries(labels.FromStrings("bar", "baz"), []chunks.Sample{fSample{1, 1}, fSample{2, 2}, fSample{3, 3}}), | 
					
						
							|  |  |  | 				NewListSeries(labels.FromStrings("foo", "bar"), []chunks.Sample{fSample{0, 0}, fSample{1, 1}, fSample{2, 2}}), | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 			}}, | 
					
						
							|  |  |  | 			expected: NewMockSeriesSet( | 
					
						
							| 
									
										
										
										
											2023-08-24 21:21:17 +08:00
										 |  |  | 				NewListSeries(labels.FromStrings("bar", "baz"), []chunks.Sample{fSample{1, 1}, fSample{2, 2}, fSample{3, 3}}), | 
					
						
							|  |  |  | 				NewListSeries(labels.FromStrings("foo", "bar"), []chunks.Sample{fSample{0, 0}, fSample{1, 1}, fSample{2, 2}}), | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 			), | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name: "two queriers, one different series each", | 
					
						
							|  |  |  | 			querierSeries: [][]Series{{ | 
					
						
							| 
									
										
										
										
											2023-08-24 21:21:17 +08:00
										 |  |  | 				NewListSeries(labels.FromStrings("bar", "baz"), []chunks.Sample{fSample{1, 1}, fSample{2, 2}, fSample{3, 3}}), | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 			}, { | 
					
						
							| 
									
										
										
										
											2023-08-24 21:21:17 +08:00
										 |  |  | 				NewListSeries(labels.FromStrings("foo", "bar"), []chunks.Sample{fSample{0, 0}, fSample{1, 1}, fSample{2, 2}}), | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 			}}, | 
					
						
							|  |  |  | 			expected: NewMockSeriesSet( | 
					
						
							| 
									
										
										
										
											2023-08-24 21:21:17 +08:00
										 |  |  | 				NewListSeries(labels.FromStrings("bar", "baz"), []chunks.Sample{fSample{1, 1}, fSample{2, 2}, fSample{3, 3}}), | 
					
						
							|  |  |  | 				NewListSeries(labels.FromStrings("foo", "bar"), []chunks.Sample{fSample{0, 0}, fSample{1, 1}, fSample{2, 2}}), | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 			), | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name: "two time unsorted queriers, two series each", | 
					
						
							|  |  |  | 			querierSeries: [][]Series{{ | 
					
						
							| 
									
										
										
										
											2023-08-24 21:21:17 +08:00
										 |  |  | 				NewListSeries(labels.FromStrings("bar", "baz"), []chunks.Sample{fSample{5, 5}, fSample{6, 6}}), | 
					
						
							|  |  |  | 				NewListSeries(labels.FromStrings("foo", "bar"), []chunks.Sample{fSample{0, 0}, fSample{1, 1}, fSample{2, 2}}), | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 			}, { | 
					
						
							| 
									
										
										
										
											2023-08-24 21:21:17 +08:00
										 |  |  | 				NewListSeries(labels.FromStrings("bar", "baz"), []chunks.Sample{fSample{1, 1}, fSample{2, 2}, fSample{3, 3}}), | 
					
						
							|  |  |  | 				NewListSeries(labels.FromStrings("foo", "bar"), []chunks.Sample{fSample{3, 3}, fSample{4, 4}}), | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 			}}, | 
					
						
							|  |  |  | 			expected: NewMockSeriesSet( | 
					
						
							|  |  |  | 				NewListSeries( | 
					
						
							|  |  |  | 					labels.FromStrings("bar", "baz"), | 
					
						
							| 
									
										
										
										
											2023-08-24 21:21:17 +08:00
										 |  |  | 					[]chunks.Sample{fSample{1, 1}, fSample{2, 2}, fSample{3, 3}, fSample{5, 5}, fSample{6, 6}}, | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 				), | 
					
						
							|  |  |  | 				NewListSeries( | 
					
						
							|  |  |  | 					labels.FromStrings("foo", "bar"), | 
					
						
							| 
									
										
										
										
											2023-08-24 21:21:17 +08:00
										 |  |  | 					[]chunks.Sample{fSample{0, 0}, fSample{1, 1}, fSample{2, 2}, fSample{3, 3}, fSample{4, 4}}, | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 				), | 
					
						
							|  |  |  | 			), | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name: "five queriers, only two queriers have two time unsorted series each", | 
					
						
							|  |  |  | 			querierSeries: [][]Series{{}, {}, { | 
					
						
							| 
									
										
										
										
											2023-08-24 21:21:17 +08:00
										 |  |  | 				NewListSeries(labels.FromStrings("bar", "baz"), []chunks.Sample{fSample{5, 5}, fSample{6, 6}}), | 
					
						
							|  |  |  | 				NewListSeries(labels.FromStrings("foo", "bar"), []chunks.Sample{fSample{0, 0}, fSample{1, 1}, fSample{2, 2}}), | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 			}, { | 
					
						
							| 
									
										
										
										
											2023-08-24 21:21:17 +08:00
										 |  |  | 				NewListSeries(labels.FromStrings("bar", "baz"), []chunks.Sample{fSample{1, 1}, fSample{2, 2}, fSample{3, 3}}), | 
					
						
							|  |  |  | 				NewListSeries(labels.FromStrings("foo", "bar"), []chunks.Sample{fSample{3, 3}, fSample{4, 4}}), | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 			}, {}}, | 
					
						
							|  |  |  | 			expected: NewMockSeriesSet( | 
					
						
							|  |  |  | 				NewListSeries( | 
					
						
							|  |  |  | 					labels.FromStrings("bar", "baz"), | 
					
						
							| 
									
										
										
										
											2023-08-24 21:21:17 +08:00
										 |  |  | 					[]chunks.Sample{fSample{1, 1}, fSample{2, 2}, fSample{3, 3}, fSample{5, 5}, fSample{6, 6}}, | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 				), | 
					
						
							|  |  |  | 				NewListSeries( | 
					
						
							|  |  |  | 					labels.FromStrings("foo", "bar"), | 
					
						
							| 
									
										
										
										
											2023-08-24 21:21:17 +08:00
										 |  |  | 					[]chunks.Sample{fSample{0, 0}, fSample{1, 1}, fSample{2, 2}, fSample{3, 3}, fSample{4, 4}}, | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 				), | 
					
						
							|  |  |  | 			), | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name: "two queriers, only two queriers have two time unsorted series each, with 3 noop and one nil querier together", | 
					
						
							|  |  |  | 			querierSeries: [][]Series{{}, {}, { | 
					
						
							| 
									
										
										
										
											2023-08-24 21:21:17 +08:00
										 |  |  | 				NewListSeries(labels.FromStrings("bar", "baz"), []chunks.Sample{fSample{5, 5}, fSample{6, 6}}), | 
					
						
							|  |  |  | 				NewListSeries(labels.FromStrings("foo", "bar"), []chunks.Sample{fSample{0, 0}, fSample{1, 1}, fSample{2, 2}}), | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 			}, { | 
					
						
							| 
									
										
										
										
											2023-08-24 21:21:17 +08:00
										 |  |  | 				NewListSeries(labels.FromStrings("bar", "baz"), []chunks.Sample{fSample{1, 1}, fSample{2, 2}, fSample{3, 3}}), | 
					
						
							|  |  |  | 				NewListSeries(labels.FromStrings("foo", "bar"), []chunks.Sample{fSample{3, 3}, fSample{4, 4}}), | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 			}, {}}, | 
					
						
							|  |  |  | 			extraQueriers: []Querier{NoopQuerier(), NoopQuerier(), nil, NoopQuerier()}, | 
					
						
							|  |  |  | 			expected: NewMockSeriesSet( | 
					
						
							|  |  |  | 				NewListSeries( | 
					
						
							|  |  |  | 					labels.FromStrings("bar", "baz"), | 
					
						
							| 
									
										
										
										
											2023-08-24 21:21:17 +08:00
										 |  |  | 					[]chunks.Sample{fSample{1, 1}, fSample{2, 2}, fSample{3, 3}, fSample{5, 5}, fSample{6, 6}}, | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 				), | 
					
						
							|  |  |  | 				NewListSeries( | 
					
						
							|  |  |  | 					labels.FromStrings("foo", "bar"), | 
					
						
							| 
									
										
										
										
											2023-08-24 21:21:17 +08:00
										 |  |  | 					[]chunks.Sample{fSample{0, 0}, fSample{1, 1}, fSample{2, 2}, fSample{3, 3}, fSample{4, 4}}, | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 				), | 
					
						
							|  |  |  | 			), | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name: "two queriers, with two series, one is overlapping", | 
					
						
							|  |  |  | 			querierSeries: [][]Series{{}, {}, { | 
					
						
							| 
									
										
										
										
											2023-08-24 21:21:17 +08:00
										 |  |  | 				NewListSeries(labels.FromStrings("bar", "baz"), []chunks.Sample{fSample{2, 21}, fSample{3, 31}, fSample{5, 5}, fSample{6, 6}}), | 
					
						
							|  |  |  | 				NewListSeries(labels.FromStrings("foo", "bar"), []chunks.Sample{fSample{0, 0}, fSample{1, 1}, fSample{2, 2}}), | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 			}, { | 
					
						
							| 
									
										
										
										
											2023-08-24 21:21:17 +08:00
										 |  |  | 				NewListSeries(labels.FromStrings("bar", "baz"), []chunks.Sample{fSample{1, 1}, fSample{2, 22}, fSample{3, 32}}), | 
					
						
							|  |  |  | 				NewListSeries(labels.FromStrings("foo", "bar"), []chunks.Sample{fSample{3, 3}, fSample{4, 4}}), | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 			}, {}}, | 
					
						
							|  |  |  | 			expected: NewMockSeriesSet( | 
					
						
							|  |  |  | 				NewListSeries( | 
					
						
							|  |  |  | 					labels.FromStrings("bar", "baz"), | 
					
						
							| 
									
										
										
										
											2023-08-24 21:21:17 +08:00
										 |  |  | 					[]chunks.Sample{fSample{1, 1}, fSample{2, 21}, fSample{3, 31}, fSample{5, 5}, fSample{6, 6}}, | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 				), | 
					
						
							|  |  |  | 				NewListSeries( | 
					
						
							|  |  |  | 					labels.FromStrings("foo", "bar"), | 
					
						
							| 
									
										
										
										
											2023-08-24 21:21:17 +08:00
										 |  |  | 					[]chunks.Sample{fSample{0, 0}, fSample{1, 1}, fSample{2, 2}, fSample{3, 3}, fSample{4, 4}}, | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 				), | 
					
						
							|  |  |  | 			), | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name: "two queries, one with NaN samples series", | 
					
						
							|  |  |  | 			querierSeries: [][]Series{{ | 
					
						
							| 
									
										
										
										
											2023-08-24 21:21:17 +08:00
										 |  |  | 				NewListSeries(labels.FromStrings("foo", "bar"), []chunks.Sample{fSample{0, math.NaN()}}), | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 			}, { | 
					
						
							| 
									
										
										
										
											2023-08-24 21:21:17 +08:00
										 |  |  | 				NewListSeries(labels.FromStrings("foo", "bar"), []chunks.Sample{fSample{1, 1}}), | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 			}}, | 
					
						
							|  |  |  | 			expected: NewMockSeriesSet( | 
					
						
							| 
									
										
										
										
											2023-08-24 21:21:17 +08:00
										 |  |  | 				NewListSeries(labels.FromStrings("foo", "bar"), []chunks.Sample{fSample{0, math.NaN()}, fSample{1, 1}}), | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 			), | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	} { | 
					
						
							|  |  |  | 		t.Run(tc.name, func(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2024-01-20 05:25:30 +08:00
										 |  |  | 			var p []Querier | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 			if tc.primaryQuerierSeries != nil { | 
					
						
							| 
									
										
										
										
											2024-01-20 05:25:30 +08:00
										 |  |  | 				p = append(p, &mockQuerier{toReturn: tc.primaryQuerierSeries}) | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 			} | 
					
						
							|  |  |  | 			var qs []Querier | 
					
						
							|  |  |  | 			for _, in := range tc.querierSeries { | 
					
						
							|  |  |  | 				qs = append(qs, &mockQuerier{toReturn: in}) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			qs = append(qs, tc.extraQueriers...) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-20 05:25:30 +08:00
										 |  |  | 			mergedQuerier := NewMergeQuerier(p, qs, ChainedSeriesMerge).Select(context.Background(), false, nil) | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			// 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 17:43:23 +08:00
										 |  |  | 			require.NoError(t, mergedQuerier.Err()) | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			for _, actualSeries := range mergedSeries { | 
					
						
							| 
									
										
										
										
											2020-10-29 17:43:23 +08:00
										 |  |  | 				require.True(t, tc.expected.Next(), "Expected Next() to be true") | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 				expectedSeries := tc.expected.At() | 
					
						
							| 
									
										
										
										
											2020-10-29 17:43:23 +08:00
										 |  |  | 				require.Equal(t, expectedSeries.Labels(), actualSeries.Labels()) | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-21 01:16:45 +08:00
										 |  |  | 				expSmpl, expErr := ExpandSamples(expectedSeries.Iterator(nil), nil) | 
					
						
							|  |  |  | 				actSmpl, actErr := ExpandSamples(actualSeries.Iterator(nil), nil) | 
					
						
							| 
									
										
										
										
											2020-10-29 17:43:23 +08:00
										 |  |  | 				require.Equal(t, expErr, actErr) | 
					
						
							|  |  |  | 				require.Equal(t, expSmpl, actSmpl) | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2020-10-29 17:43:23 +08:00
										 |  |  | 			require.False(t, tc.expected.Next(), "Expected Next() to be false") | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08: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{{ | 
					
						
							| 
									
										
										
										
											2023-08-24 21:21:17 +08:00
										 |  |  | 				NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), []chunks.Sample{fSample{1, 1}, fSample{2, 2}}, []chunks.Sample{fSample{3, 3}}), | 
					
						
							|  |  |  | 				NewListChunkSeriesFromSamples(labels.FromStrings("foo", "bar"), []chunks.Sample{fSample{0, 0}, fSample{1, 1}}, []chunks.Sample{fSample{2, 2}}), | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 			}}, | 
					
						
							|  |  |  | 			expected: NewMockChunkSeriesSet( | 
					
						
							| 
									
										
										
										
											2023-08-24 21:21:17 +08:00
										 |  |  | 				NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), []chunks.Sample{fSample{1, 1}, fSample{2, 2}}, []chunks.Sample{fSample{3, 3}}), | 
					
						
							|  |  |  | 				NewListChunkSeriesFromSamples(labels.FromStrings("foo", "bar"), []chunks.Sample{fSample{0, 0}, fSample{1, 1}}, []chunks.Sample{fSample{2, 2}}), | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 			), | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name: "two secondaries, one different series each", | 
					
						
							|  |  |  | 			chkQuerierSeries: [][]ChunkSeries{{ | 
					
						
							| 
									
										
										
										
											2023-08-24 21:21:17 +08:00
										 |  |  | 				NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), []chunks.Sample{fSample{1, 1}, fSample{2, 2}}, []chunks.Sample{fSample{3, 3}}), | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 			}, { | 
					
						
							| 
									
										
										
										
											2023-08-24 21:21:17 +08:00
										 |  |  | 				NewListChunkSeriesFromSamples(labels.FromStrings("foo", "bar"), []chunks.Sample{fSample{0, 0}, fSample{1, 1}}, []chunks.Sample{fSample{2, 2}}), | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 			}}, | 
					
						
							|  |  |  | 			expected: NewMockChunkSeriesSet( | 
					
						
							| 
									
										
										
										
											2023-08-24 21:21:17 +08:00
										 |  |  | 				NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), []chunks.Sample{fSample{1, 1}, fSample{2, 2}}, []chunks.Sample{fSample{3, 3}}), | 
					
						
							|  |  |  | 				NewListChunkSeriesFromSamples(labels.FromStrings("foo", "bar"), []chunks.Sample{fSample{0, 0}, fSample{1, 1}}, []chunks.Sample{fSample{2, 2}}), | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 			), | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name: "two secondaries, two not in time order series each", | 
					
						
							|  |  |  | 			chkQuerierSeries: [][]ChunkSeries{{ | 
					
						
							| 
									
										
										
										
											2023-08-24 21:21:17 +08:00
										 |  |  | 				NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), []chunks.Sample{fSample{5, 5}}, []chunks.Sample{fSample{6, 6}}), | 
					
						
							|  |  |  | 				NewListChunkSeriesFromSamples(labels.FromStrings("foo", "bar"), []chunks.Sample{fSample{0, 0}, fSample{1, 1}}, []chunks.Sample{fSample{2, 2}}), | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 			}, { | 
					
						
							| 
									
										
										
										
											2023-08-24 21:21:17 +08:00
										 |  |  | 				NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), []chunks.Sample{fSample{1, 1}, fSample{2, 2}}, []chunks.Sample{fSample{3, 3}}), | 
					
						
							|  |  |  | 				NewListChunkSeriesFromSamples(labels.FromStrings("foo", "bar"), []chunks.Sample{fSample{3, 3}}, []chunks.Sample{fSample{4, 4}}), | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 			}}, | 
					
						
							|  |  |  | 			expected: NewMockChunkSeriesSet( | 
					
						
							|  |  |  | 				NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), | 
					
						
							| 
									
										
										
										
											2023-08-24 21:21:17 +08:00
										 |  |  | 					[]chunks.Sample{fSample{1, 1}, fSample{2, 2}}, | 
					
						
							|  |  |  | 					[]chunks.Sample{fSample{3, 3}}, | 
					
						
							|  |  |  | 					[]chunks.Sample{fSample{5, 5}}, | 
					
						
							|  |  |  | 					[]chunks.Sample{fSample{6, 6}}, | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 				), | 
					
						
							|  |  |  | 				NewListChunkSeriesFromSamples(labels.FromStrings("foo", "bar"), | 
					
						
							| 
									
										
										
										
											2023-08-24 21:21:17 +08:00
										 |  |  | 					[]chunks.Sample{fSample{0, 0}, fSample{1, 1}}, | 
					
						
							|  |  |  | 					[]chunks.Sample{fSample{2, 2}}, | 
					
						
							|  |  |  | 					[]chunks.Sample{fSample{3, 3}}, | 
					
						
							|  |  |  | 					[]chunks.Sample{fSample{4, 4}}, | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 				), | 
					
						
							|  |  |  | 			), | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name: "five secondaries, only two have two not in time order series each", | 
					
						
							|  |  |  | 			chkQuerierSeries: [][]ChunkSeries{{}, {}, { | 
					
						
							| 
									
										
										
										
											2023-08-24 21:21:17 +08:00
										 |  |  | 				NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), []chunks.Sample{fSample{5, 5}}, []chunks.Sample{fSample{6, 6}}), | 
					
						
							|  |  |  | 				NewListChunkSeriesFromSamples(labels.FromStrings("foo", "bar"), []chunks.Sample{fSample{0, 0}, fSample{1, 1}}, []chunks.Sample{fSample{2, 2}}), | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 			}, { | 
					
						
							| 
									
										
										
										
											2023-08-24 21:21:17 +08:00
										 |  |  | 				NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), []chunks.Sample{fSample{1, 1}, fSample{2, 2}}, []chunks.Sample{fSample{3, 3}}), | 
					
						
							|  |  |  | 				NewListChunkSeriesFromSamples(labels.FromStrings("foo", "bar"), []chunks.Sample{fSample{3, 3}}, []chunks.Sample{fSample{4, 4}}), | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 			}, {}}, | 
					
						
							|  |  |  | 			expected: NewMockChunkSeriesSet( | 
					
						
							|  |  |  | 				NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), | 
					
						
							| 
									
										
										
										
											2023-08-24 21:21:17 +08:00
										 |  |  | 					[]chunks.Sample{fSample{1, 1}, fSample{2, 2}}, | 
					
						
							|  |  |  | 					[]chunks.Sample{fSample{3, 3}}, | 
					
						
							|  |  |  | 					[]chunks.Sample{fSample{5, 5}}, | 
					
						
							|  |  |  | 					[]chunks.Sample{fSample{6, 6}}, | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 				), | 
					
						
							|  |  |  | 				NewListChunkSeriesFromSamples(labels.FromStrings("foo", "bar"), | 
					
						
							| 
									
										
										
										
											2023-08-24 21:21:17 +08:00
										 |  |  | 					[]chunks.Sample{fSample{0, 0}, fSample{1, 1}}, | 
					
						
							|  |  |  | 					[]chunks.Sample{fSample{2, 2}}, | 
					
						
							|  |  |  | 					[]chunks.Sample{fSample{3, 3}}, | 
					
						
							|  |  |  | 					[]chunks.Sample{fSample{4, 4}}, | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 				), | 
					
						
							|  |  |  | 			), | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name: "two secondaries, with two not in time order series each, with 3 noop queries and one nil together", | 
					
						
							|  |  |  | 			chkQuerierSeries: [][]ChunkSeries{{ | 
					
						
							| 
									
										
										
										
											2023-08-24 21:21:17 +08:00
										 |  |  | 				NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), []chunks.Sample{fSample{5, 5}}, []chunks.Sample{fSample{6, 6}}), | 
					
						
							|  |  |  | 				NewListChunkSeriesFromSamples(labels.FromStrings("foo", "bar"), []chunks.Sample{fSample{0, 0}, fSample{1, 1}}, []chunks.Sample{fSample{2, 2}}), | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 			}, { | 
					
						
							| 
									
										
										
										
											2023-08-24 21:21:17 +08:00
										 |  |  | 				NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), []chunks.Sample{fSample{1, 1}, fSample{2, 2}}, []chunks.Sample{fSample{3, 3}}), | 
					
						
							|  |  |  | 				NewListChunkSeriesFromSamples(labels.FromStrings("foo", "bar"), []chunks.Sample{fSample{3, 3}}, []chunks.Sample{fSample{4, 4}}), | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 			}}, | 
					
						
							|  |  |  | 			extraQueriers: []ChunkQuerier{NoopChunkedQuerier(), NoopChunkedQuerier(), nil, NoopChunkedQuerier()}, | 
					
						
							|  |  |  | 			expected: NewMockChunkSeriesSet( | 
					
						
							|  |  |  | 				NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), | 
					
						
							| 
									
										
										
										
											2023-08-24 21:21:17 +08:00
										 |  |  | 					[]chunks.Sample{fSample{1, 1}, fSample{2, 2}}, | 
					
						
							|  |  |  | 					[]chunks.Sample{fSample{3, 3}}, | 
					
						
							|  |  |  | 					[]chunks.Sample{fSample{5, 5}}, | 
					
						
							|  |  |  | 					[]chunks.Sample{fSample{6, 6}}, | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 				), | 
					
						
							|  |  |  | 				NewListChunkSeriesFromSamples(labels.FromStrings("foo", "bar"), | 
					
						
							| 
									
										
										
										
											2023-08-24 21:21:17 +08:00
										 |  |  | 					[]chunks.Sample{fSample{0, 0}, fSample{1, 1}}, | 
					
						
							|  |  |  | 					[]chunks.Sample{fSample{2, 2}}, | 
					
						
							|  |  |  | 					[]chunks.Sample{fSample{3, 3}}, | 
					
						
							|  |  |  | 					[]chunks.Sample{fSample{4, 4}}, | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 				), | 
					
						
							|  |  |  | 			), | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name: "two queries, one with NaN samples series", | 
					
						
							|  |  |  | 			chkQuerierSeries: [][]ChunkSeries{{ | 
					
						
							| 
									
										
										
										
											2023-08-24 21:21:17 +08:00
										 |  |  | 				NewListChunkSeriesFromSamples(labels.FromStrings("foo", "bar"), []chunks.Sample{fSample{0, math.NaN()}}), | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 			}, { | 
					
						
							| 
									
										
										
										
											2023-08-24 21:21:17 +08:00
										 |  |  | 				NewListChunkSeriesFromSamples(labels.FromStrings("foo", "bar"), []chunks.Sample{fSample{1, 1}}), | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 			}}, | 
					
						
							|  |  |  | 			expected: NewMockChunkSeriesSet( | 
					
						
							| 
									
										
										
										
											2023-08-24 21:21:17 +08:00
										 |  |  | 				NewListChunkSeriesFromSamples(labels.FromStrings("foo", "bar"), []chunks.Sample{fSample{0, math.NaN()}}, []chunks.Sample{fSample{1, 1}}), | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 			), | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	} { | 
					
						
							|  |  |  | 		t.Run(tc.name, func(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2024-01-20 05:25:30 +08:00
										 |  |  | 			var p []ChunkQuerier | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 			if tc.primaryChkQuerierSeries != nil { | 
					
						
							| 
									
										
										
										
											2024-06-24 18:17:33 +08:00
										 |  |  | 				p = append(p, &mockChunkQuerier{toReturn: tc.primaryChkQuerierSeries}) | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			var qs []ChunkQuerier | 
					
						
							|  |  |  | 			for _, in := range tc.chkQuerierSeries { | 
					
						
							| 
									
										
										
										
											2024-03-22 14:44:38 +08:00
										 |  |  | 				qs = append(qs, &mockChunkQuerier{toReturn: in}) | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 			} | 
					
						
							|  |  |  | 			qs = append(qs, tc.extraQueriers...) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-20 05:25:30 +08:00
										 |  |  | 			merged := NewMergeChunkQuerier(p, qs, NewCompactingChunkSeriesMerger(nil)).Select(context.Background(), false, nil) | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 			for merged.Next() { | 
					
						
							| 
									
										
										
										
											2020-10-29 17:43:23 +08:00
										 |  |  | 				require.True(t, tc.expected.Next(), "Expected Next() to be true") | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 				actualSeries := merged.At() | 
					
						
							|  |  |  | 				expectedSeries := tc.expected.At() | 
					
						
							| 
									
										
										
										
											2020-10-29 17:43:23 +08:00
										 |  |  | 				require.Equal(t, expectedSeries.Labels(), actualSeries.Labels()) | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-21 01:16:45 +08:00
										 |  |  | 				expChks, expErr := ExpandChunks(expectedSeries.Iterator(nil)) | 
					
						
							|  |  |  | 				actChks, actErr := ExpandChunks(actualSeries.Iterator(nil)) | 
					
						
							| 
									
										
										
										
											2020-10-29 17:43:23 +08:00
										 |  |  | 				require.Equal(t, expErr, actErr) | 
					
						
							|  |  |  | 				require.Equal(t, expChks, actChks) | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2020-10-29 17:43:23 +08:00
										 |  |  | 			require.NoError(t, merged.Err()) | 
					
						
							|  |  |  | 			require.False(t, tc.expected.Next(), "Expected Next() to be false") | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 		}) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-19 23:06:46 +08:00
										 |  |  | func histogramSample(ts int64, hint histogram.CounterResetHint) hSample { | 
					
						
							| 
									
										
										
										
											2024-12-16 06:53:36 +08:00
										 |  |  | 	h := tsdbutil.GenerateTestHistogram(ts + 1) | 
					
						
							| 
									
										
										
										
											2023-09-19 23:06:46 +08:00
										 |  |  | 	h.CounterResetHint = hint | 
					
						
							|  |  |  | 	return hSample{t: ts, h: h} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func floatHistogramSample(ts int64, hint histogram.CounterResetHint) fhSample { | 
					
						
							| 
									
										
										
										
											2024-12-16 06:53:36 +08:00
										 |  |  | 	fh := tsdbutil.GenerateTestFloatHistogram(ts + 1) | 
					
						
							| 
									
										
										
										
											2023-09-19 23:06:46 +08:00
										 |  |  | 	fh.CounterResetHint = hint | 
					
						
							|  |  |  | 	return fhSample{t: ts, fh: fh} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Shorthands for counter reset hints.
 | 
					
						
							|  |  |  | const ( | 
					
						
							|  |  |  | 	uk = histogram.UnknownCounterReset | 
					
						
							|  |  |  | 	cr = histogram.CounterReset | 
					
						
							|  |  |  | 	nr = histogram.NotCounterReset | 
					
						
							|  |  |  | 	ga = histogram.GaugeType | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | func TestCompactingChunkSeriesMerger(t *testing.T) { | 
					
						
							|  |  |  | 	m := NewCompactingChunkSeriesMerger(ChainedSeriesMerge) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-22 21:34:39 +08:00
										 |  |  | 	// histogramSample returns a histogram that is unique to the ts.
 | 
					
						
							| 
									
										
										
										
											2022-12-08 20:31:08 +08:00
										 |  |  | 	histogramSample := func(ts int64) hSample { | 
					
						
							| 
									
										
										
										
											2023-09-19 23:06:46 +08:00
										 |  |  | 		return histogramSample(ts, uk) | 
					
						
							| 
									
										
										
										
											2023-02-10 19:39:33 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-08 20:31:08 +08:00
										 |  |  | 	floatHistogramSample := func(ts int64) fhSample { | 
					
						
							| 
									
										
										
										
											2023-09-19 23:06:46 +08:00
										 |  |  | 		return floatHistogramSample(ts, uk) | 
					
						
							| 
									
										
										
										
											2022-08-22 21:34:39 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 	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{ | 
					
						
							| 
									
										
										
										
											2023-08-24 21:21:17 +08:00
										 |  |  | 				NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), []chunks.Sample{fSample{1, 1}, fSample{2, 2}}, []chunks.Sample{fSample{3, 3}}), | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 			}, | 
					
						
							| 
									
										
										
										
											2023-08-24 21:21:17 +08:00
										 |  |  | 			expected: NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), []chunks.Sample{fSample{1, 1}, fSample{2, 2}}, []chunks.Sample{fSample{3, 3}}), | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08: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{ | 
					
						
							| 
									
										
										
										
											2023-08-24 21:21:17 +08:00
										 |  |  | 				NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), []chunks.Sample{fSample{1, 1}, fSample{2, 2}}, []chunks.Sample{fSample{3, 3}, fSample{5, 5}}), | 
					
						
							|  |  |  | 				NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), []chunks.Sample{fSample{7, 7}, fSample{9, 9}}, []chunks.Sample{fSample{10, 10}}), | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 			}, | 
					
						
							| 
									
										
										
										
											2023-08-24 21:21:17 +08:00
										 |  |  | 			expected: NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), []chunks.Sample{fSample{1, 1}, fSample{2, 2}}, []chunks.Sample{fSample{3, 3}, fSample{5, 5}}, []chunks.Sample{fSample{7, 7}, fSample{9, 9}}, []chunks.Sample{fSample{10, 10}}), | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name: "two overlapping", | 
					
						
							|  |  |  | 			input: []ChunkSeries{ | 
					
						
							| 
									
										
										
										
											2023-08-24 21:21:17 +08:00
										 |  |  | 				NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), []chunks.Sample{fSample{1, 1}, fSample{2, 2}}, []chunks.Sample{fSample{3, 3}, fSample{8, 8}}), | 
					
						
							|  |  |  | 				NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), []chunks.Sample{fSample{7, 7}, fSample{9, 9}}, []chunks.Sample{fSample{10, 10}}), | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 			}, | 
					
						
							| 
									
										
										
										
											2023-08-24 21:21:17 +08:00
										 |  |  | 			expected: NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), []chunks.Sample{fSample{1, 1}, fSample{2, 2}}, []chunks.Sample{fSample{3, 3}, fSample{7, 7}, fSample{8, 8}, fSample{9, 9}}, []chunks.Sample{fSample{10, 10}}), | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name: "two duplicated", | 
					
						
							|  |  |  | 			input: []ChunkSeries{ | 
					
						
							| 
									
										
										
										
											2023-08-24 21:21:17 +08:00
										 |  |  | 				NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), []chunks.Sample{fSample{1, 1}, fSample{2, 2}, fSample{3, 3}, fSample{5, 5}}), | 
					
						
							|  |  |  | 				NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), []chunks.Sample{fSample{2, 2}, fSample{3, 3}, fSample{5, 5}}), | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 			}, | 
					
						
							| 
									
										
										
										
											2023-08-24 21:21:17 +08:00
										 |  |  | 			expected: NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), []chunks.Sample{fSample{1, 1}, fSample{2, 2}, fSample{3, 3}, fSample{5, 5}}), | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name: "three overlapping", | 
					
						
							|  |  |  | 			input: []ChunkSeries{ | 
					
						
							| 
									
										
										
										
											2023-08-24 21:21:17 +08:00
										 |  |  | 				NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), []chunks.Sample{fSample{1, 1}, fSample{2, 2}, fSample{3, 3}, fSample{5, 5}}), | 
					
						
							|  |  |  | 				NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), []chunks.Sample{fSample{2, 2}, fSample{3, 3}, fSample{6, 6}}), | 
					
						
							|  |  |  | 				NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), []chunks.Sample{fSample{0, 0}, fSample{4, 4}}), | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 			}, | 
					
						
							| 
									
										
										
										
											2023-08-24 21:21:17 +08:00
										 |  |  | 			expected: NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), []chunks.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 18:32:56 +08:00
										 |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name: "three in chained overlap", | 
					
						
							|  |  |  | 			input: []ChunkSeries{ | 
					
						
							| 
									
										
										
										
											2023-08-24 21:21:17 +08:00
										 |  |  | 				NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), []chunks.Sample{fSample{1, 1}, fSample{2, 2}, fSample{3, 3}, fSample{5, 5}}), | 
					
						
							|  |  |  | 				NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), []chunks.Sample{fSample{4, 4}, fSample{6, 66}}), | 
					
						
							|  |  |  | 				NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), []chunks.Sample{fSample{6, 6}, fSample{10, 10}}), | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 			}, | 
					
						
							| 
									
										
										
										
											2023-08-24 21:21:17 +08:00
										 |  |  | 			expected: NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), []chunks.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 18:32:56 +08:00
										 |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name: "three in chained overlap complex", | 
					
						
							|  |  |  | 			input: []ChunkSeries{ | 
					
						
							| 
									
										
										
										
											2023-08-24 21:21:17 +08:00
										 |  |  | 				NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), []chunks.Sample{fSample{0, 0}, fSample{5, 5}}, []chunks.Sample{fSample{10, 10}, fSample{15, 15}}), | 
					
						
							|  |  |  | 				NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), []chunks.Sample{fSample{2, 2}, fSample{20, 20}}, []chunks.Sample{fSample{25, 25}, fSample{30, 30}}), | 
					
						
							|  |  |  | 				NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), []chunks.Sample{fSample{18, 18}, fSample{26, 26}}, []chunks.Sample{fSample{31, 31}, fSample{35, 35}}), | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 			}, | 
					
						
							|  |  |  | 			expected: NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), | 
					
						
							| 
									
										
										
										
											2023-08-24 21:21:17 +08:00
										 |  |  | 				[]chunks.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}}, | 
					
						
							|  |  |  | 				[]chunks.Sample{fSample{31, 31}, fSample{35, 35}}, | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 			), | 
					
						
							|  |  |  | 		}, | 
					
						
							| 
									
										
										
										
											2021-05-19 00:37:16 +08:00
										 |  |  | 		{ | 
					
						
							|  |  |  | 			name: "110 overlapping", | 
					
						
							|  |  |  | 			input: []ChunkSeries{ | 
					
						
							| 
									
										
										
										
											2023-08-24 21:21:17 +08:00
										 |  |  | 				NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), chunks.GenerateSamples(0, 110)), // [0 - 110)
 | 
					
						
							|  |  |  | 				NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), chunks.GenerateSamples(60, 50)), // [60 - 110)
 | 
					
						
							| 
									
										
										
										
											2021-05-19 00:37:16 +08:00
										 |  |  | 			}, | 
					
						
							|  |  |  | 			expected: NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), | 
					
						
							| 
									
										
										
										
											2023-08-24 21:21:17 +08:00
										 |  |  | 				chunks.GenerateSamples(0, 110), | 
					
						
							| 
									
										
										
										
											2021-05-19 00:37:16 +08:00
										 |  |  | 			), | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name: "150 overlapping samples, split chunk", | 
					
						
							|  |  |  | 			input: []ChunkSeries{ | 
					
						
							| 
									
										
										
										
											2023-08-24 21:21:17 +08:00
										 |  |  | 				NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), chunks.GenerateSamples(0, 90)),  // [0 - 90)
 | 
					
						
							|  |  |  | 				NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), chunks.GenerateSamples(60, 90)), // [90 - 150)
 | 
					
						
							| 
									
										
										
										
											2021-05-19 00:37:16 +08:00
										 |  |  | 			}, | 
					
						
							|  |  |  | 			expected: NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), | 
					
						
							| 
									
										
										
										
											2023-08-24 21:21:17 +08:00
										 |  |  | 				chunks.GenerateSamples(0, 120), | 
					
						
							|  |  |  | 				chunks.GenerateSamples(120, 30), | 
					
						
							| 
									
										
										
										
											2021-05-19 00:37:16 +08:00
										 |  |  | 			), | 
					
						
							|  |  |  | 		}, | 
					
						
							| 
									
										
										
										
											2022-08-22 21:34:39 +08:00
										 |  |  | 		{ | 
					
						
							|  |  |  | 			name: "histogram chunks overlapping", | 
					
						
							|  |  |  | 			input: []ChunkSeries{ | 
					
						
							| 
									
										
										
										
											2023-08-24 21:21:17 +08:00
										 |  |  | 				NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), []chunks.Sample{histogramSample(0), histogramSample(5)}, []chunks.Sample{histogramSample(10), histogramSample(15)}), | 
					
						
							|  |  |  | 				NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), []chunks.Sample{histogramSample(2), histogramSample(20)}, []chunks.Sample{histogramSample(25), histogramSample(30)}), | 
					
						
							|  |  |  | 				NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), []chunks.Sample{histogramSample(18), histogramSample(26)}, []chunks.Sample{histogramSample(31), histogramSample(35)}), | 
					
						
							| 
									
										
										
										
											2022-08-22 21:34:39 +08:00
										 |  |  | 			}, | 
					
						
							|  |  |  | 			expected: NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), | 
					
						
							| 
									
										
										
										
											2023-08-24 21:21:17 +08:00
										 |  |  | 				[]chunks.Sample{histogramSample(0), histogramSample(2), histogramSample(5), histogramSample(10), histogramSample(15), histogramSample(18), histogramSample(20), histogramSample(25), histogramSample(26), histogramSample(30)}, | 
					
						
							|  |  |  | 				[]chunks.Sample{histogramSample(31), histogramSample(35)}, | 
					
						
							| 
									
										
										
										
											2022-08-22 21:34:39 +08:00
										 |  |  | 			), | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name: "histogram chunks overlapping with float chunks", | 
					
						
							|  |  |  | 			input: []ChunkSeries{ | 
					
						
							| 
									
										
										
										
											2023-08-24 21:21:17 +08:00
										 |  |  | 				NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), []chunks.Sample{histogramSample(0), histogramSample(5)}, []chunks.Sample{histogramSample(10), histogramSample(15)}), | 
					
						
							|  |  |  | 				NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), []chunks.Sample{fSample{1, 1}, fSample{12, 12}}, []chunks.Sample{fSample{14, 14}}), | 
					
						
							| 
									
										
										
										
											2022-08-22 21:34:39 +08:00
										 |  |  | 			}, | 
					
						
							|  |  |  | 			expected: NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), | 
					
						
							| 
									
										
										
										
											2023-08-24 21:21:17 +08:00
										 |  |  | 				[]chunks.Sample{histogramSample(0)}, | 
					
						
							|  |  |  | 				[]chunks.Sample{fSample{1, 1}}, | 
					
						
							|  |  |  | 				[]chunks.Sample{histogramSample(5), histogramSample(10)}, | 
					
						
							|  |  |  | 				[]chunks.Sample{fSample{12, 12}, fSample{14, 14}}, | 
					
						
							|  |  |  | 				[]chunks.Sample{histogramSample(15)}, | 
					
						
							| 
									
										
										
										
											2022-08-22 21:34:39 +08:00
										 |  |  | 			), | 
					
						
							|  |  |  | 		}, | 
					
						
							| 
									
										
										
										
											2023-02-10 19:39:33 +08:00
										 |  |  | 		{ | 
					
						
							|  |  |  | 			name: "float histogram chunks overlapping", | 
					
						
							|  |  |  | 			input: []ChunkSeries{ | 
					
						
							| 
									
										
										
										
											2023-08-24 21:21:17 +08:00
										 |  |  | 				NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), []chunks.Sample{floatHistogramSample(0), floatHistogramSample(5)}, []chunks.Sample{floatHistogramSample(10), floatHistogramSample(15)}), | 
					
						
							|  |  |  | 				NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), []chunks.Sample{floatHistogramSample(2), floatHistogramSample(20)}, []chunks.Sample{floatHistogramSample(25), floatHistogramSample(30)}), | 
					
						
							|  |  |  | 				NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), []chunks.Sample{floatHistogramSample(18), floatHistogramSample(26)}, []chunks.Sample{floatHistogramSample(31), floatHistogramSample(35)}), | 
					
						
							| 
									
										
										
										
											2023-02-10 19:39:33 +08:00
										 |  |  | 			}, | 
					
						
							|  |  |  | 			expected: NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), | 
					
						
							| 
									
										
										
										
											2023-08-24 21:21:17 +08:00
										 |  |  | 				[]chunks.Sample{floatHistogramSample(0), floatHistogramSample(2), floatHistogramSample(5), floatHistogramSample(10), floatHistogramSample(15), floatHistogramSample(18), floatHistogramSample(20), floatHistogramSample(25), floatHistogramSample(26), floatHistogramSample(30)}, | 
					
						
							|  |  |  | 				[]chunks.Sample{floatHistogramSample(31), floatHistogramSample(35)}, | 
					
						
							| 
									
										
										
										
											2023-02-10 19:39:33 +08:00
										 |  |  | 			), | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name: "float histogram chunks overlapping with float chunks", | 
					
						
							|  |  |  | 			input: []ChunkSeries{ | 
					
						
							| 
									
										
										
										
											2023-08-24 21:21:17 +08:00
										 |  |  | 				NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), []chunks.Sample{floatHistogramSample(0), floatHistogramSample(5)}, []chunks.Sample{floatHistogramSample(10), floatHistogramSample(15)}), | 
					
						
							|  |  |  | 				NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), []chunks.Sample{fSample{1, 1}, fSample{12, 12}}, []chunks.Sample{fSample{14, 14}}), | 
					
						
							| 
									
										
										
										
											2023-02-10 19:39:33 +08:00
										 |  |  | 			}, | 
					
						
							|  |  |  | 			expected: NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), | 
					
						
							| 
									
										
										
										
											2023-08-24 21:21:17 +08:00
										 |  |  | 				[]chunks.Sample{floatHistogramSample(0)}, | 
					
						
							|  |  |  | 				[]chunks.Sample{fSample{1, 1}}, | 
					
						
							|  |  |  | 				[]chunks.Sample{floatHistogramSample(5), floatHistogramSample(10)}, | 
					
						
							|  |  |  | 				[]chunks.Sample{fSample{12, 12}, fSample{14, 14}}, | 
					
						
							|  |  |  | 				[]chunks.Sample{floatHistogramSample(15)}, | 
					
						
							| 
									
										
										
										
											2023-02-10 19:39:33 +08:00
										 |  |  | 			), | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name: "float histogram chunks overlapping with histogram chunks", | 
					
						
							|  |  |  | 			input: []ChunkSeries{ | 
					
						
							| 
									
										
										
										
											2023-08-24 21:21:17 +08:00
										 |  |  | 				NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), []chunks.Sample{floatHistogramSample(0), floatHistogramSample(5)}, []chunks.Sample{floatHistogramSample(10), floatHistogramSample(15)}), | 
					
						
							|  |  |  | 				NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), []chunks.Sample{histogramSample(1), histogramSample(12)}, []chunks.Sample{histogramSample(14)}), | 
					
						
							| 
									
										
										
										
											2023-02-10 19:39:33 +08:00
										 |  |  | 			}, | 
					
						
							|  |  |  | 			expected: NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), | 
					
						
							| 
									
										
										
										
											2023-08-24 21:21:17 +08:00
										 |  |  | 				[]chunks.Sample{floatHistogramSample(0)}, | 
					
						
							|  |  |  | 				[]chunks.Sample{histogramSample(1)}, | 
					
						
							|  |  |  | 				[]chunks.Sample{floatHistogramSample(5), floatHistogramSample(10)}, | 
					
						
							|  |  |  | 				[]chunks.Sample{histogramSample(12), histogramSample(14)}, | 
					
						
							|  |  |  | 				[]chunks.Sample{floatHistogramSample(15)}, | 
					
						
							| 
									
										
										
										
											2023-02-10 19:39:33 +08:00
										 |  |  | 			), | 
					
						
							|  |  |  | 		}, | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 	} { | 
					
						
							|  |  |  | 		t.Run(tc.name, func(t *testing.T) { | 
					
						
							|  |  |  | 			merged := m(tc.input...) | 
					
						
							| 
									
										
										
										
											2020-10-29 17:43:23 +08:00
										 |  |  | 			require.Equal(t, tc.expected.Labels(), merged.Labels()) | 
					
						
							| 
									
										
										
										
											2022-09-21 01:16:45 +08:00
										 |  |  | 			actChks, actErr := ExpandChunks(merged.Iterator(nil)) | 
					
						
							|  |  |  | 			expChks, expErr := ExpandChunks(tc.expected.Iterator(nil)) | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-29 17:43:23 +08:00
										 |  |  | 			require.Equal(t, expErr, actErr) | 
					
						
							|  |  |  | 			require.Equal(t, expChks, actChks) | 
					
						
							| 
									
										
										
										
											2023-09-19 23:06:46 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			actSamples := chunks.ChunkMetasToSamples(actChks) | 
					
						
							|  |  |  | 			expSamples := chunks.ChunkMetasToSamples(expChks) | 
					
						
							|  |  |  | 			require.Equal(t, expSamples, actSamples) | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 		}) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-19 23:06:46 +08:00
										 |  |  | func TestCompactingChunkSeriesMergerHistogramCounterResetHint(t *testing.T) { | 
					
						
							|  |  |  | 	m := NewCompactingChunkSeriesMerger(ChainedSeriesMerge) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for sampleType, sampleFunc := range map[string]func(int64, histogram.CounterResetHint) chunks.Sample{ | 
					
						
							|  |  |  | 		"histogram":       func(ts int64, hint histogram.CounterResetHint) chunks.Sample { return histogramSample(ts, hint) }, | 
					
						
							|  |  |  | 		"float histogram": func(ts int64, hint histogram.CounterResetHint) chunks.Sample { return floatHistogramSample(ts, hint) }, | 
					
						
							|  |  |  | 	} { | 
					
						
							|  |  |  | 		for name, tc := range map[string]struct { | 
					
						
							|  |  |  | 			input    []ChunkSeries | 
					
						
							|  |  |  | 			expected ChunkSeries | 
					
						
							|  |  |  | 		}{ | 
					
						
							|  |  |  | 			"histogram counter reset hint kept in single series": { | 
					
						
							|  |  |  | 				input: []ChunkSeries{ | 
					
						
							|  |  |  | 					NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), | 
					
						
							|  |  |  | 						[]chunks.Sample{sampleFunc(0, cr), sampleFunc(5, uk)}, | 
					
						
							|  |  |  | 						[]chunks.Sample{sampleFunc(10, cr), sampleFunc(15, uk)}, | 
					
						
							|  |  |  | 					), | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 				expected: NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), | 
					
						
							|  |  |  | 					[]chunks.Sample{sampleFunc(0, cr), sampleFunc(5, uk)}, | 
					
						
							|  |  |  | 					[]chunks.Sample{sampleFunc(10, cr), sampleFunc(15, uk)}, | 
					
						
							|  |  |  | 				), | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			"histogram not counter reset hint kept in single series": { | 
					
						
							|  |  |  | 				input: []ChunkSeries{ | 
					
						
							|  |  |  | 					NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), | 
					
						
							|  |  |  | 						[]chunks.Sample{sampleFunc(0, nr), sampleFunc(5, uk)}, | 
					
						
							|  |  |  | 						[]chunks.Sample{sampleFunc(10, nr), sampleFunc(15, uk)}, | 
					
						
							|  |  |  | 					), | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 				expected: NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), | 
					
						
							|  |  |  | 					[]chunks.Sample{sampleFunc(0, nr), sampleFunc(5, uk)}, | 
					
						
							|  |  |  | 					[]chunks.Sample{sampleFunc(10, nr), sampleFunc(15, uk)}, | 
					
						
							|  |  |  | 				), | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			"histogram counter reset hint kept in multiple equal series": { | 
					
						
							|  |  |  | 				input: []ChunkSeries{ | 
					
						
							|  |  |  | 					NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), | 
					
						
							|  |  |  | 						[]chunks.Sample{sampleFunc(0, cr), sampleFunc(5, uk)}, | 
					
						
							|  |  |  | 						[]chunks.Sample{sampleFunc(10, cr), sampleFunc(15, uk)}, | 
					
						
							|  |  |  | 					), | 
					
						
							|  |  |  | 					NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), | 
					
						
							|  |  |  | 						[]chunks.Sample{sampleFunc(0, cr), sampleFunc(5, uk)}, | 
					
						
							|  |  |  | 						[]chunks.Sample{sampleFunc(10, cr), sampleFunc(15, uk)}, | 
					
						
							|  |  |  | 					), | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 				expected: NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), | 
					
						
							|  |  |  | 					[]chunks.Sample{sampleFunc(0, cr), sampleFunc(5, uk)}, | 
					
						
							|  |  |  | 					[]chunks.Sample{sampleFunc(10, cr), sampleFunc(15, uk)}, | 
					
						
							|  |  |  | 				), | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			"histogram not counter reset hint kept in multiple equal series": { | 
					
						
							|  |  |  | 				input: []ChunkSeries{ | 
					
						
							|  |  |  | 					NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), | 
					
						
							|  |  |  | 						[]chunks.Sample{sampleFunc(0, nr), sampleFunc(5, uk)}, | 
					
						
							|  |  |  | 						[]chunks.Sample{sampleFunc(10, nr), sampleFunc(15, uk)}, | 
					
						
							|  |  |  | 					), | 
					
						
							|  |  |  | 					NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), | 
					
						
							|  |  |  | 						[]chunks.Sample{sampleFunc(0, nr), sampleFunc(5, uk)}, | 
					
						
							|  |  |  | 						[]chunks.Sample{sampleFunc(10, nr), sampleFunc(15, uk)}, | 
					
						
							|  |  |  | 					), | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 				expected: NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), | 
					
						
							|  |  |  | 					[]chunks.Sample{sampleFunc(0, nr), sampleFunc(5, uk)}, | 
					
						
							|  |  |  | 					[]chunks.Sample{sampleFunc(10, nr), sampleFunc(15, uk)}, | 
					
						
							|  |  |  | 				), | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			"histogram counter reset hint dropped from differing series": { | 
					
						
							|  |  |  | 				input: []ChunkSeries{ | 
					
						
							|  |  |  | 					NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), | 
					
						
							|  |  |  | 						[]chunks.Sample{sampleFunc(0, cr), sampleFunc(5, uk)}, | 
					
						
							|  |  |  | 						[]chunks.Sample{sampleFunc(10, cr), sampleFunc(15, uk)}, | 
					
						
							|  |  |  | 					), | 
					
						
							|  |  |  | 					NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), | 
					
						
							|  |  |  | 						[]chunks.Sample{sampleFunc(0, cr), sampleFunc(5, uk)}, | 
					
						
							|  |  |  | 						[]chunks.Sample{sampleFunc(10, cr), sampleFunc(12, uk), sampleFunc(15, uk)}, | 
					
						
							|  |  |  | 					), | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 				expected: NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), | 
					
						
							|  |  |  | 					[]chunks.Sample{sampleFunc(0, cr), sampleFunc(5, uk)}, | 
					
						
							|  |  |  | 					[]chunks.Sample{sampleFunc(10, uk), sampleFunc(12, uk), sampleFunc(15, uk)}, | 
					
						
							|  |  |  | 				), | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			"histogram counter not reset hint dropped from differing series": { | 
					
						
							|  |  |  | 				input: []ChunkSeries{ | 
					
						
							|  |  |  | 					NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), | 
					
						
							|  |  |  | 						[]chunks.Sample{sampleFunc(0, nr), sampleFunc(5, uk)}, | 
					
						
							|  |  |  | 						[]chunks.Sample{sampleFunc(10, nr), sampleFunc(15, uk)}, | 
					
						
							|  |  |  | 					), | 
					
						
							|  |  |  | 					NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), | 
					
						
							|  |  |  | 						[]chunks.Sample{sampleFunc(0, nr), sampleFunc(5, uk)}, | 
					
						
							|  |  |  | 						[]chunks.Sample{sampleFunc(10, nr), sampleFunc(12, uk), sampleFunc(15, uk)}, | 
					
						
							|  |  |  | 					), | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 				expected: NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), | 
					
						
							|  |  |  | 					[]chunks.Sample{sampleFunc(0, nr), sampleFunc(5, uk)}, | 
					
						
							|  |  |  | 					[]chunks.Sample{sampleFunc(10, uk), sampleFunc(12, uk), sampleFunc(15, uk)}, | 
					
						
							|  |  |  | 				), | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 		} { | 
					
						
							|  |  |  | 			t.Run(sampleType+"/"+name, func(t *testing.T) { | 
					
						
							|  |  |  | 				merged := m(tc.input...) | 
					
						
							|  |  |  | 				require.Equal(t, tc.expected.Labels(), merged.Labels()) | 
					
						
							|  |  |  | 				actChks, actErr := ExpandChunks(merged.Iterator(nil)) | 
					
						
							|  |  |  | 				expChks, expErr := ExpandChunks(tc.expected.Iterator(nil)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				require.Equal(t, expErr, actErr) | 
					
						
							|  |  |  | 				require.Equal(t, expChks, actChks) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				actSamples := chunks.ChunkMetasToSamples(actChks) | 
					
						
							|  |  |  | 				expSamples := chunks.ChunkMetasToSamples(expChks) | 
					
						
							|  |  |  | 				require.Equal(t, expSamples, actSamples) | 
					
						
							|  |  |  | 			}) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-21 01:05:50 +08: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{ | 
					
						
							| 
									
										
										
										
											2023-08-24 21:21:17 +08:00
										 |  |  | 				NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), []chunks.Sample{fSample{1, 1}, fSample{2, 2}}, []chunks.Sample{fSample{3, 3}}), | 
					
						
							| 
									
										
										
										
											2022-09-21 01:05:50 +08:00
										 |  |  | 			}, | 
					
						
							| 
									
										
										
										
											2023-08-24 21:21:17 +08:00
										 |  |  | 			expected: NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), []chunks.Sample{fSample{1, 1}, fSample{2, 2}}, []chunks.Sample{fSample{3, 3}}), | 
					
						
							| 
									
										
										
										
											2022-09-21 01:05:50 +08: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{ | 
					
						
							| 
									
										
										
										
											2023-08-24 21:21:17 +08:00
										 |  |  | 				NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), []chunks.Sample{fSample{1, 1}, fSample{2, 2}}, []chunks.Sample{fSample{3, 3}, fSample{5, 5}}), | 
					
						
							|  |  |  | 				NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), []chunks.Sample{fSample{7, 7}, fSample{9, 9}}, []chunks.Sample{fSample{10, 10}}), | 
					
						
							| 
									
										
										
										
											2022-09-21 01:05:50 +08:00
										 |  |  | 			}, | 
					
						
							| 
									
										
										
										
											2023-08-24 21:21:17 +08:00
										 |  |  | 			expected: NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), []chunks.Sample{fSample{1, 1}, fSample{2, 2}}, []chunks.Sample{fSample{3, 3}, fSample{5, 5}}, []chunks.Sample{fSample{7, 7}, fSample{9, 9}}, []chunks.Sample{fSample{10, 10}}), | 
					
						
							| 
									
										
										
										
											2022-09-21 01:05:50 +08:00
										 |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name: "two overlapping", | 
					
						
							|  |  |  | 			input: []ChunkSeries{ | 
					
						
							| 
									
										
										
										
											2023-08-24 21:21:17 +08:00
										 |  |  | 				NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), []chunks.Sample{fSample{1, 1}, fSample{2, 2}}, []chunks.Sample{fSample{3, 3}, fSample{8, 8}}), | 
					
						
							|  |  |  | 				NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), []chunks.Sample{fSample{7, 7}, fSample{9, 9}}, []chunks.Sample{fSample{10, 10}}), | 
					
						
							| 
									
										
										
										
											2022-09-21 01:05:50 +08:00
										 |  |  | 			}, | 
					
						
							|  |  |  | 			expected: NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), | 
					
						
							| 
									
										
										
										
											2023-08-24 21:21:17 +08:00
										 |  |  | 				[]chunks.Sample{fSample{1, 1}, fSample{2, 2}}, []chunks.Sample{fSample{3, 3}, fSample{8, 8}}, | 
					
						
							|  |  |  | 				[]chunks.Sample{fSample{7, 7}, fSample{9, 9}}, []chunks.Sample{fSample{10, 10}}, | 
					
						
							| 
									
										
										
										
											2022-09-21 01:05:50 +08:00
										 |  |  | 			), | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name: "two duplicated", | 
					
						
							|  |  |  | 			input: []ChunkSeries{ | 
					
						
							| 
									
										
										
										
											2023-08-24 21:21:17 +08:00
										 |  |  | 				NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), []chunks.Sample{fSample{1, 1}, fSample{2, 2}, fSample{3, 3}, fSample{5, 5}}), | 
					
						
							|  |  |  | 				NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), []chunks.Sample{fSample{2, 2}, fSample{3, 3}, fSample{5, 5}}), | 
					
						
							| 
									
										
										
										
											2022-09-21 01:05:50 +08:00
										 |  |  | 			}, | 
					
						
							|  |  |  | 			expected: NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), | 
					
						
							| 
									
										
										
										
											2023-08-24 21:21:17 +08:00
										 |  |  | 				[]chunks.Sample{fSample{1, 1}, fSample{2, 2}, fSample{3, 3}, fSample{5, 5}}, | 
					
						
							|  |  |  | 				[]chunks.Sample{fSample{2, 2}, fSample{3, 3}, fSample{5, 5}}, | 
					
						
							| 
									
										
										
										
											2022-09-21 01:05:50 +08:00
										 |  |  | 			), | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name: "three overlapping", | 
					
						
							|  |  |  | 			input: []ChunkSeries{ | 
					
						
							| 
									
										
										
										
											2023-08-24 21:21:17 +08:00
										 |  |  | 				NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), []chunks.Sample{fSample{1, 1}, fSample{2, 2}, fSample{3, 3}, fSample{5, 5}}), | 
					
						
							|  |  |  | 				NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), []chunks.Sample{fSample{2, 2}, fSample{3, 3}, fSample{6, 6}}), | 
					
						
							|  |  |  | 				NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), []chunks.Sample{fSample{0, 0}, fSample{4, 4}}), | 
					
						
							| 
									
										
										
										
											2022-09-21 01:05:50 +08:00
										 |  |  | 			}, | 
					
						
							|  |  |  | 			expected: NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), | 
					
						
							| 
									
										
										
										
											2023-08-24 21:21:17 +08:00
										 |  |  | 				[]chunks.Sample{fSample{1, 1}, fSample{2, 2}, fSample{3, 3}, fSample{5, 5}}, | 
					
						
							|  |  |  | 				[]chunks.Sample{fSample{2, 2}, fSample{3, 3}, fSample{6, 6}}, | 
					
						
							|  |  |  | 				[]chunks.Sample{fSample{0, 0}, fSample{4, 4}}, | 
					
						
							| 
									
										
										
										
											2022-09-21 01:05:50 +08:00
										 |  |  | 			), | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name: "three in chained overlap", | 
					
						
							|  |  |  | 			input: []ChunkSeries{ | 
					
						
							| 
									
										
										
										
											2023-08-24 21:21:17 +08:00
										 |  |  | 				NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), []chunks.Sample{fSample{1, 1}, fSample{2, 2}, fSample{3, 3}, fSample{5, 5}}), | 
					
						
							|  |  |  | 				NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), []chunks.Sample{fSample{4, 4}, fSample{6, 66}}), | 
					
						
							|  |  |  | 				NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), []chunks.Sample{fSample{6, 6}, fSample{10, 10}}), | 
					
						
							| 
									
										
										
										
											2022-09-21 01:05:50 +08:00
										 |  |  | 			}, | 
					
						
							|  |  |  | 			expected: NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), | 
					
						
							| 
									
										
										
										
											2023-08-24 21:21:17 +08:00
										 |  |  | 				[]chunks.Sample{fSample{1, 1}, fSample{2, 2}, fSample{3, 3}, fSample{5, 5}}, | 
					
						
							|  |  |  | 				[]chunks.Sample{fSample{4, 4}, fSample{6, 66}}, | 
					
						
							|  |  |  | 				[]chunks.Sample{fSample{6, 6}, fSample{10, 10}}, | 
					
						
							| 
									
										
										
										
											2022-09-21 01:05:50 +08:00
										 |  |  | 			), | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name: "three in chained overlap complex", | 
					
						
							|  |  |  | 			input: []ChunkSeries{ | 
					
						
							| 
									
										
										
										
											2023-08-24 21:21:17 +08:00
										 |  |  | 				NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), []chunks.Sample{fSample{0, 0}, fSample{5, 5}}, []chunks.Sample{fSample{10, 10}, fSample{15, 15}}), | 
					
						
							|  |  |  | 				NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), []chunks.Sample{fSample{2, 2}, fSample{20, 20}}, []chunks.Sample{fSample{25, 25}, fSample{30, 30}}), | 
					
						
							|  |  |  | 				NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), []chunks.Sample{fSample{18, 18}, fSample{26, 26}}, []chunks.Sample{fSample{31, 31}, fSample{35, 35}}), | 
					
						
							| 
									
										
										
										
											2022-09-21 01:05:50 +08:00
										 |  |  | 			}, | 
					
						
							|  |  |  | 			expected: NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), | 
					
						
							| 
									
										
										
										
											2023-08-24 21:21:17 +08:00
										 |  |  | 				[]chunks.Sample{fSample{0, 0}, fSample{5, 5}}, []chunks.Sample{fSample{10, 10}, fSample{15, 15}}, | 
					
						
							|  |  |  | 				[]chunks.Sample{fSample{2, 2}, fSample{20, 20}}, []chunks.Sample{fSample{25, 25}, fSample{30, 30}}, | 
					
						
							|  |  |  | 				[]chunks.Sample{fSample{18, 18}, fSample{26, 26}}, []chunks.Sample{fSample{31, 31}, fSample{35, 35}}, | 
					
						
							| 
									
										
										
										
											2022-09-21 01:05:50 +08:00
										 |  |  | 			), | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name: "110 overlapping", | 
					
						
							|  |  |  | 			input: []ChunkSeries{ | 
					
						
							| 
									
										
										
										
											2023-08-24 21:21:17 +08:00
										 |  |  | 				NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), chunks.GenerateSamples(0, 110)), // [0 - 110)
 | 
					
						
							|  |  |  | 				NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), chunks.GenerateSamples(60, 50)), // [60 - 110)
 | 
					
						
							| 
									
										
										
										
											2022-09-21 01:05:50 +08:00
										 |  |  | 			}, | 
					
						
							|  |  |  | 			expected: NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), | 
					
						
							| 
									
										
										
										
											2023-08-24 21:21:17 +08:00
										 |  |  | 				chunks.GenerateSamples(0, 110), | 
					
						
							|  |  |  | 				chunks.GenerateSamples(60, 50), | 
					
						
							| 
									
										
										
										
											2022-09-21 01:05:50 +08:00
										 |  |  | 			), | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name: "150 overlapping samples, simply concatenated and no splits", | 
					
						
							|  |  |  | 			input: []ChunkSeries{ | 
					
						
							| 
									
										
										
										
											2023-08-24 21:21:17 +08:00
										 |  |  | 				NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), chunks.GenerateSamples(0, 90)),  // [0 - 90)
 | 
					
						
							|  |  |  | 				NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), chunks.GenerateSamples(60, 90)), // [90 - 150)
 | 
					
						
							| 
									
										
										
										
											2022-09-21 01:05:50 +08:00
										 |  |  | 			}, | 
					
						
							|  |  |  | 			expected: NewListChunkSeriesFromSamples(labels.FromStrings("bar", "baz"), | 
					
						
							| 
									
										
										
										
											2023-08-24 21:21:17 +08:00
										 |  |  | 				chunks.GenerateSamples(0, 90), | 
					
						
							|  |  |  | 				chunks.GenerateSamples(60, 90), | 
					
						
							| 
									
										
										
										
											2022-09-21 01:05:50 +08:00
										 |  |  | 			), | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	} { | 
					
						
							|  |  |  | 		t.Run(tc.name, func(t *testing.T) { | 
					
						
							|  |  |  | 			merged := m(tc.input...) | 
					
						
							|  |  |  | 			require.Equal(t, tc.expected.Labels(), merged.Labels()) | 
					
						
							| 
									
										
										
										
											2022-09-21 01:16:45 +08:00
										 |  |  | 			actChks, actErr := ExpandChunks(merged.Iterator(nil)) | 
					
						
							|  |  |  | 			expChks, expErr := ExpandChunks(tc.expected.Iterator(nil)) | 
					
						
							| 
									
										
										
										
											2022-09-21 01:05:50 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			require.Equal(t, expErr, actErr) | 
					
						
							|  |  |  | 			require.Equal(t, expChks, actChks) | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-02 12:29:09 +08:00
										 |  |  | func TestConcatenatingChunkIterator(t *testing.T) { | 
					
						
							|  |  |  | 	chunk1, err := chunks.ChunkFromSamples([]chunks.Sample{fSample{t: 1, f: 10}}) | 
					
						
							|  |  |  | 	require.NoError(t, err) | 
					
						
							|  |  |  | 	chunk2, err := chunks.ChunkFromSamples([]chunks.Sample{fSample{t: 2, f: 20}}) | 
					
						
							|  |  |  | 	require.NoError(t, err) | 
					
						
							|  |  |  | 	chunk3, err := chunks.ChunkFromSamples([]chunks.Sample{fSample{t: 3, f: 30}}) | 
					
						
							|  |  |  | 	require.NoError(t, err) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	testError := errors.New("something went wrong") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	testCases := map[string]struct { | 
					
						
							|  |  |  | 		iterators      []chunks.Iterator | 
					
						
							|  |  |  | 		expectedChunks []chunks.Meta | 
					
						
							|  |  |  | 		expectedError  error | 
					
						
							|  |  |  | 	}{ | 
					
						
							|  |  |  | 		"many successful iterators": { | 
					
						
							|  |  |  | 			iterators: []chunks.Iterator{ | 
					
						
							|  |  |  | 				NewListChunkSeriesIterator(chunk1, chunk2), | 
					
						
							|  |  |  | 				NewListChunkSeriesIterator(chunk3), | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			expectedChunks: []chunks.Meta{chunk1, chunk2, chunk3}, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		"single failing iterator": { | 
					
						
							|  |  |  | 			iterators: []chunks.Iterator{ | 
					
						
							|  |  |  | 				errChunksIterator{err: testError}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			expectedError: testError, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		"some failing and some successful iterators": { | 
					
						
							|  |  |  | 			iterators: []chunks.Iterator{ | 
					
						
							|  |  |  | 				NewListChunkSeriesIterator(chunk1, chunk2), | 
					
						
							|  |  |  | 				errChunksIterator{err: testError}, | 
					
						
							|  |  |  | 				NewListChunkSeriesIterator(chunk3), | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			expectedChunks: []chunks.Meta{chunk1, chunk2}, // Should stop before advancing to last iterator.
 | 
					
						
							|  |  |  | 			expectedError:  testError, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for name, testCase := range testCases { | 
					
						
							|  |  |  | 		t.Run(name, func(t *testing.T) { | 
					
						
							|  |  |  | 			it := concatenatingChunkIterator{iterators: testCase.iterators} | 
					
						
							|  |  |  | 			var chks []chunks.Meta | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			for it.Next() { | 
					
						
							|  |  |  | 				chks = append(chks, it.At()) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			require.Equal(t, testCase.expectedChunks, chks) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if testCase.expectedError == nil { | 
					
						
							|  |  |  | 				require.NoError(t, it.Err()) | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				require.EqualError(t, it.Err(), testCase.expectedError.Error()) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | type mockQuerier struct { | 
					
						
							| 
									
										
										
										
											2024-07-22 21:33:59 +08:00
										 |  |  | 	mtx sync.Mutex | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	toReturn []Series // Response for Select.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	closed                bool | 
					
						
							|  |  |  | 	labelNamesCalls       int | 
					
						
							|  |  |  | 	labelNamesRequested   []labelNameRequest | 
					
						
							|  |  |  | 	sortedSeriesRequested []bool | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-22 21:33:59 +08:00
										 |  |  | 	resp     []string // Response for LabelNames and LabelValues; turned into Select response if toReturn is not supplied.
 | 
					
						
							|  |  |  | 	warnings annotations.Annotations | 
					
						
							|  |  |  | 	err      error | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type labelNameRequest struct { | 
					
						
							|  |  |  | 	name     string | 
					
						
							|  |  |  | 	matchers []*labels.Matcher | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 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 } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-12 18:37:38 +08:00
										 |  |  | func (m *mockQuerier) Select(_ context.Context, sortSeries bool, _ *SelectHints, _ ...*labels.Matcher) SeriesSet { | 
					
						
							| 
									
										
										
										
											2024-07-22 21:33:59 +08:00
										 |  |  | 	m.mtx.Lock() | 
					
						
							|  |  |  | 	defer m.mtx.Unlock() | 
					
						
							|  |  |  | 	m.sortedSeriesRequested = append(m.sortedSeriesRequested, sortSeries) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var ret []Series | 
					
						
							|  |  |  | 	if len(m.toReturn) > 0 { | 
					
						
							|  |  |  | 		ret = make([]Series, len(m.toReturn)) | 
					
						
							|  |  |  | 		copy(ret, m.toReturn) | 
					
						
							|  |  |  | 	} else if len(m.resp) > 0 { | 
					
						
							|  |  |  | 		ret = make([]Series, 0, len(m.resp)) | 
					
						
							|  |  |  | 		for _, l := range m.resp { | 
					
						
							| 
									
										
										
										
											2024-07-22 23:34:42 +08:00
										 |  |  | 			ret = append(ret, NewListSeries(labels.FromStrings("test", l), nil)) | 
					
						
							| 
									
										
										
										
											2024-07-22 21:33:59 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 	if sortSeries { | 
					
						
							| 
									
										
										
										
											2024-07-22 21:33:59 +08:00
										 |  |  | 		sort.Sort(seriesByLabel(ret)) | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-22 21:33:59 +08:00
										 |  |  | 	return &mockSeriesSet{idx: -1, series: ret, warnings: m.warnings, err: m.err} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-02-10 15:06:58 +08:00
										 |  |  | func (m *mockQuerier) LabelValues(_ context.Context, name string, _ *LabelHints, matchers ...*labels.Matcher) ([]string, annotations.Annotations, error) { | 
					
						
							| 
									
										
										
										
											2024-07-22 21:33:59 +08:00
										 |  |  | 	m.mtx.Lock() | 
					
						
							|  |  |  | 	m.labelNamesRequested = append(m.labelNamesRequested, labelNameRequest{ | 
					
						
							|  |  |  | 		name:     name, | 
					
						
							|  |  |  | 		matchers: matchers, | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 	m.mtx.Unlock() | 
					
						
							|  |  |  | 	return m.resp, m.warnings, m.err | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (m *mockQuerier) LabelNames(context.Context, *LabelHints, ...*labels.Matcher) ([]string, annotations.Annotations, error) { | 
					
						
							|  |  |  | 	m.mtx.Lock() | 
					
						
							|  |  |  | 	m.labelNamesCalls++ | 
					
						
							|  |  |  | 	m.mtx.Unlock() | 
					
						
							|  |  |  | 	return m.resp, m.warnings, m.err | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (m *mockQuerier) Close() error { | 
					
						
							|  |  |  | 	m.closed = true | 
					
						
							|  |  |  | 	return nil | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-22 14:44:38 +08:00
										 |  |  | type mockChunkQuerier struct { | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 	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 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-22 14:44:38 +08:00
										 |  |  | func (m *mockChunkQuerier) Select(_ context.Context, sortSeries bool, _ *SelectHints, _ ...*labels.Matcher) ChunkSeriesSet { | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 	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 | 
					
						
							| 
									
										
										
										
											2024-07-22 21:33:59 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	warnings annotations.Annotations | 
					
						
							|  |  |  | 	err      error | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func NewMockSeriesSet(series ...Series) SeriesSet { | 
					
						
							|  |  |  | 	return &mockSeriesSet{ | 
					
						
							|  |  |  | 		idx:    -1, | 
					
						
							|  |  |  | 		series: series, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (m *mockSeriesSet) Next() bool { | 
					
						
							| 
									
										
										
										
											2024-07-22 21:33:59 +08:00
										 |  |  | 	if m.err != nil { | 
					
						
							|  |  |  | 		return false | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 	m.idx++ | 
					
						
							|  |  |  | 	return m.idx < len(m.series) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (m *mockSeriesSet) At() Series { return m.series[m.idx] } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-22 21:33:59 +08:00
										 |  |  | func (m *mockSeriesSet) Err() error { return m.err } | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-22 21:33:59 +08:00
										 |  |  | func (m *mockSeriesSet) Warnings() annotations.Annotations { return m.warnings } | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 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] } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-04 14:20:57 +08:00
										 |  |  | func (*mockChunkSeriesSet) Err() error { return nil } | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-04 14:20:57 +08:00
										 |  |  | func (*mockChunkSeriesSet) Warnings() annotations.Annotations { return nil } | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | func TestChainSampleIterator(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2023-09-19 23:06:46 +08:00
										 |  |  | 	for sampleType, sampleFunc := range map[string]func(int64) chunks.Sample{ | 
					
						
							|  |  |  | 		"float":           func(ts int64) chunks.Sample { return fSample{ts, float64(ts)} }, | 
					
						
							|  |  |  | 		"histogram":       func(ts int64) chunks.Sample { return histogramSample(ts, uk) }, | 
					
						
							|  |  |  | 		"float histogram": func(ts int64) chunks.Sample { return floatHistogramSample(ts, uk) }, | 
					
						
							|  |  |  | 	} { | 
					
						
							|  |  |  | 		for name, tc := range map[string]struct { | 
					
						
							|  |  |  | 			input    []chunkenc.Iterator | 
					
						
							|  |  |  | 			expected []chunks.Sample | 
					
						
							|  |  |  | 		}{ | 
					
						
							|  |  |  | 			"single iterator": { | 
					
						
							|  |  |  | 				input: []chunkenc.Iterator{ | 
					
						
							|  |  |  | 					NewListSeriesIterator(samples{sampleFunc(0), sampleFunc(1)}), | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 				expected: []chunks.Sample{sampleFunc(0), sampleFunc(1)}, | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 			}, | 
					
						
							| 
									
										
										
										
											2023-09-19 23:06:46 +08:00
										 |  |  | 			"non overlapping iterators": { | 
					
						
							|  |  |  | 				input: []chunkenc.Iterator{ | 
					
						
							|  |  |  | 					NewListSeriesIterator(samples{sampleFunc(0), sampleFunc(1)}), | 
					
						
							|  |  |  | 					NewListSeriesIterator(samples{sampleFunc(2), sampleFunc(3)}), | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 				expected: []chunks.Sample{sampleFunc(0), sampleFunc(1), sampleFunc(2), sampleFunc(3)}, | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 			}, | 
					
						
							| 
									
										
										
										
											2023-09-19 23:06:46 +08:00
										 |  |  | 			"overlapping but distinct iterators": { | 
					
						
							|  |  |  | 				input: []chunkenc.Iterator{ | 
					
						
							|  |  |  | 					NewListSeriesIterator(samples{sampleFunc(0), sampleFunc(3)}), | 
					
						
							|  |  |  | 					NewListSeriesIterator(samples{sampleFunc(1), sampleFunc(4)}), | 
					
						
							|  |  |  | 					NewListSeriesIterator(samples{sampleFunc(2), sampleFunc(5)}), | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 				expected: []chunks.Sample{ | 
					
						
							|  |  |  | 					sampleFunc(0), sampleFunc(1), sampleFunc(2), sampleFunc(3), sampleFunc(4), sampleFunc(5), | 
					
						
							|  |  |  | 				}, | 
					
						
							| 
									
										
										
										
											2021-10-22 16:06:44 +08:00
										 |  |  | 			}, | 
					
						
							| 
									
										
										
										
											2023-09-19 23:06:46 +08:00
										 |  |  | 			"overlapping iterators": { | 
					
						
							|  |  |  | 				input: []chunkenc.Iterator{ | 
					
						
							|  |  |  | 					NewListSeriesIterator(samples{sampleFunc(0), sampleFunc(1)}), | 
					
						
							|  |  |  | 					NewListSeriesIterator(samples{sampleFunc(0), sampleFunc(2)}), | 
					
						
							|  |  |  | 					NewListSeriesIterator(samples{sampleFunc(2), sampleFunc(3)}), | 
					
						
							|  |  |  | 					NewListSeriesIterator(samples{}), | 
					
						
							|  |  |  | 					NewListSeriesIterator(samples{}), | 
					
						
							|  |  |  | 					NewListSeriesIterator(samples{}), | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 				expected: []chunks.Sample{sampleFunc(0), sampleFunc(1), sampleFunc(2), sampleFunc(3)}, | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 			}, | 
					
						
							| 
									
										
										
										
											2023-09-19 23:06:46 +08:00
										 |  |  | 		} { | 
					
						
							|  |  |  | 			t.Run(sampleType+"/"+name, func(t *testing.T) { | 
					
						
							|  |  |  | 				merged := ChainSampleIteratorFromIterators(nil, tc.input) | 
					
						
							|  |  |  | 				actual, err := ExpandSamples(merged, nil) | 
					
						
							|  |  |  | 				require.NoError(t, err) | 
					
						
							|  |  |  | 				require.Equal(t, tc.expected, actual) | 
					
						
							|  |  |  | 			}) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func TestChainSampleIteratorHistogramCounterResetHint(t *testing.T) { | 
					
						
							|  |  |  | 	for sampleType, sampleFunc := range map[string]func(int64, histogram.CounterResetHint) chunks.Sample{ | 
					
						
							|  |  |  | 		"histogram":       func(ts int64, hint histogram.CounterResetHint) chunks.Sample { return histogramSample(ts, hint) }, | 
					
						
							|  |  |  | 		"float histogram": func(ts int64, hint histogram.CounterResetHint) chunks.Sample { return floatHistogramSample(ts, hint) }, | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 	} { | 
					
						
							| 
									
										
										
										
											2023-09-19 23:06:46 +08:00
										 |  |  | 		for name, tc := range map[string]struct { | 
					
						
							|  |  |  | 			input    []chunkenc.Iterator | 
					
						
							|  |  |  | 			expected []chunks.Sample | 
					
						
							|  |  |  | 		}{ | 
					
						
							|  |  |  | 			"single iterator": { | 
					
						
							|  |  |  | 				input: []chunkenc.Iterator{ | 
					
						
							|  |  |  | 					NewListSeriesIterator(samples{sampleFunc(0, cr), sampleFunc(1, cr), sampleFunc(2, uk)}), | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 				expected: []chunks.Sample{sampleFunc(0, uk), sampleFunc(1, cr), sampleFunc(2, uk)}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			"single iterator gauge": { | 
					
						
							|  |  |  | 				input: []chunkenc.Iterator{ | 
					
						
							|  |  |  | 					NewListSeriesIterator(samples{sampleFunc(0, ga), sampleFunc(1, ga), sampleFunc(2, ga)}), | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 				expected: []chunks.Sample{sampleFunc(0, ga), sampleFunc(1, ga), sampleFunc(2, ga)}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			"overlapping iterators gauge": { | 
					
						
							|  |  |  | 				input: []chunkenc.Iterator{ | 
					
						
							|  |  |  | 					NewListSeriesIterator(samples{sampleFunc(0, ga), sampleFunc(1, ga), sampleFunc(2, ga), sampleFunc(4, ga)}), | 
					
						
							|  |  |  | 					NewListSeriesIterator(samples{sampleFunc(0, ga), sampleFunc(1, ga), sampleFunc(3, ga), sampleFunc(5, ga)}), | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 				expected: []chunks.Sample{sampleFunc(0, ga), sampleFunc(1, ga), sampleFunc(2, ga), sampleFunc(3, ga), sampleFunc(4, ga), sampleFunc(5, ga)}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			"non overlapping iterators": { | 
					
						
							|  |  |  | 				input: []chunkenc.Iterator{ | 
					
						
							|  |  |  | 					NewListSeriesIterator(samples{sampleFunc(0, cr), sampleFunc(1, uk)}), | 
					
						
							|  |  |  | 					NewListSeriesIterator(samples{sampleFunc(2, cr), sampleFunc(3, cr)}), | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 				expected: []chunks.Sample{sampleFunc(0, uk), sampleFunc(1, uk), sampleFunc(2, uk), sampleFunc(3, cr)}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			"overlapping but distinct iterators": { | 
					
						
							|  |  |  | 				input: []chunkenc.Iterator{ | 
					
						
							|  |  |  | 					NewListSeriesIterator(samples{sampleFunc(0, cr), sampleFunc(3, uk), sampleFunc(5, cr)}), | 
					
						
							|  |  |  | 					NewListSeriesIterator(samples{sampleFunc(1, uk), sampleFunc(2, cr), sampleFunc(4, cr)}), | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 				expected: []chunks.Sample{ | 
					
						
							|  |  |  | 					sampleFunc(0, uk), sampleFunc(1, uk), sampleFunc(2, cr), sampleFunc(3, uk), sampleFunc(4, uk), sampleFunc(5, uk), | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			"overlapping iterators": { | 
					
						
							|  |  |  | 				input: []chunkenc.Iterator{ | 
					
						
							|  |  |  | 					NewListSeriesIterator(samples{sampleFunc(0, cr), sampleFunc(1, cr), sampleFunc(2, cr)}), | 
					
						
							|  |  |  | 					NewListSeriesIterator(samples{sampleFunc(0, cr), sampleFunc(1, cr), sampleFunc(2, cr)}), | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 				expected: []chunks.Sample{sampleFunc(0, uk), sampleFunc(1, uk), sampleFunc(2, uk)}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 		} { | 
					
						
							|  |  |  | 			t.Run(sampleType+"/"+name, func(t *testing.T) { | 
					
						
							|  |  |  | 				merged := ChainSampleIteratorFromIterators(nil, tc.input) | 
					
						
							|  |  |  | 				actual, err := ExpandSamples(merged, nil) | 
					
						
							|  |  |  | 				require.NoError(t, err) | 
					
						
							|  |  |  | 				require.Equal(t, tc.expected, actual) | 
					
						
							|  |  |  | 			}) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func TestChainSampleIteratorSeek(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2023-09-19 23:06:46 +08:00
										 |  |  | 	for sampleType, sampleFunc := range map[string]func(int64) chunks.Sample{ | 
					
						
							|  |  |  | 		"float":           func(ts int64) chunks.Sample { return fSample{ts, float64(ts)} }, | 
					
						
							|  |  |  | 		"histogram":       func(ts int64) chunks.Sample { return histogramSample(ts, uk) }, | 
					
						
							|  |  |  | 		"float histogram": func(ts int64) chunks.Sample { return floatHistogramSample(ts, uk) }, | 
					
						
							|  |  |  | 	} { | 
					
						
							|  |  |  | 		for name, tc := range map[string]struct { | 
					
						
							|  |  |  | 			input    []chunkenc.Iterator | 
					
						
							|  |  |  | 			seek     int64 | 
					
						
							|  |  |  | 			expected []chunks.Sample | 
					
						
							|  |  |  | 		}{ | 
					
						
							|  |  |  | 			"single iterator": { | 
					
						
							|  |  |  | 				input: []chunkenc.Iterator{ | 
					
						
							|  |  |  | 					NewListSeriesIterator(samples{sampleFunc(0), sampleFunc(1), sampleFunc(2)}), | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 				seek:     1, | 
					
						
							|  |  |  | 				expected: []chunks.Sample{sampleFunc(1), sampleFunc(2)}, | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 			}, | 
					
						
							| 
									
										
										
										
											2023-09-19 23:06:46 +08:00
										 |  |  | 			"non overlapping iterators": { | 
					
						
							|  |  |  | 				input: []chunkenc.Iterator{ | 
					
						
							|  |  |  | 					NewListSeriesIterator(samples{sampleFunc(0), sampleFunc(1)}), | 
					
						
							|  |  |  | 					NewListSeriesIterator(samples{sampleFunc(2), sampleFunc(3)}), | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 				seek:     2, | 
					
						
							|  |  |  | 				expected: []chunks.Sample{sampleFunc(2), sampleFunc(3)}, | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 			}, | 
					
						
							| 
									
										
										
										
											2023-09-19 23:06:46 +08:00
										 |  |  | 			"overlapping but distinct iterators": { | 
					
						
							|  |  |  | 				input: []chunkenc.Iterator{ | 
					
						
							|  |  |  | 					NewListSeriesIterator(samples{sampleFunc(0), sampleFunc(3)}), | 
					
						
							|  |  |  | 					NewListSeriesIterator(samples{sampleFunc(1), sampleFunc(4)}), | 
					
						
							|  |  |  | 					NewListSeriesIterator(samples{sampleFunc(2), sampleFunc(5)}), | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 				seek:     2, | 
					
						
							|  |  |  | 				expected: []chunks.Sample{sampleFunc(2), sampleFunc(3), sampleFunc(4), sampleFunc(5)}, | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 			}, | 
					
						
							| 
									
										
										
										
											2023-09-19 23:06:46 +08:00
										 |  |  | 			"overlapping iterators": { | 
					
						
							|  |  |  | 				input: []chunkenc.Iterator{ | 
					
						
							|  |  |  | 					NewListSeriesIterator(samples{sampleFunc(0), sampleFunc(2), sampleFunc(3)}), | 
					
						
							|  |  |  | 					NewListSeriesIterator(samples{sampleFunc(0), sampleFunc(1), sampleFunc(2)}), | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 				seek:     0, | 
					
						
							|  |  |  | 				expected: []chunks.Sample{sampleFunc(0), sampleFunc(1), sampleFunc(2), sampleFunc(3)}, | 
					
						
							| 
									
										
										
										
											2021-03-12 19:32:15 +08:00
										 |  |  | 			}, | 
					
						
							| 
									
										
										
										
											2023-09-19 23:06:46 +08:00
										 |  |  | 		} { | 
					
						
							|  |  |  | 			t.Run(sampleType+"/"+name, func(t *testing.T) { | 
					
						
							|  |  |  | 				merged := ChainSampleIteratorFromIterators(nil, tc.input) | 
					
						
							|  |  |  | 				actual := []chunks.Sample{} | 
					
						
							|  |  |  | 				switch merged.Seek(tc.seek) { | 
					
						
							|  |  |  | 				case chunkenc.ValFloat: | 
					
						
							|  |  |  | 					t, f := merged.At() | 
					
						
							|  |  |  | 					actual = append(actual, fSample{t, f}) | 
					
						
							|  |  |  | 				case chunkenc.ValHistogram: | 
					
						
							| 
									
										
										
										
											2024-01-24 00:02:14 +08:00
										 |  |  | 					t, h := merged.AtHistogram(nil) | 
					
						
							| 
									
										
										
										
											2023-09-19 23:06:46 +08:00
										 |  |  | 					actual = append(actual, hSample{t, h}) | 
					
						
							|  |  |  | 				case chunkenc.ValFloatHistogram: | 
					
						
							| 
									
										
										
										
											2024-01-24 00:02:14 +08:00
										 |  |  | 					t, fh := merged.AtFloatHistogram(nil) | 
					
						
							| 
									
										
										
										
											2023-09-19 23:06:46 +08:00
										 |  |  | 					actual = append(actual, fhSample{t, fh}) | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				s, err := ExpandSamples(merged, nil) | 
					
						
							|  |  |  | 				require.NoError(t, err) | 
					
						
							|  |  |  | 				actual = append(actual, s...) | 
					
						
							|  |  |  | 				require.Equal(t, tc.expected, actual) | 
					
						
							|  |  |  | 			}) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-01 06:35:17 +08:00
										 |  |  | func TestChainSampleIteratorSeekFailingIterator(t *testing.T) { | 
					
						
							|  |  |  | 	merged := ChainSampleIteratorFromIterators(nil, []chunkenc.Iterator{ | 
					
						
							|  |  |  | 		NewListSeriesIterator(samples{fSample{0, 0.1}, fSample{1, 1.1}, fSample{2, 2.1}}), | 
					
						
							|  |  |  | 		errIterator{errors.New("something went wrong")}, | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	require.Equal(t, chunkenc.ValNone, merged.Seek(0)) | 
					
						
							|  |  |  | 	require.EqualError(t, merged.Err(), "something went wrong") | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func TestChainSampleIteratorNextImmediatelyFailingIterator(t *testing.T) { | 
					
						
							|  |  |  | 	merged := ChainSampleIteratorFromIterators(nil, []chunkenc.Iterator{ | 
					
						
							|  |  |  | 		NewListSeriesIterator(samples{fSample{0, 0.1}, fSample{1, 1.1}, fSample{2, 2.1}}), | 
					
						
							|  |  |  | 		errIterator{errors.New("something went wrong")}, | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	require.Equal(t, chunkenc.ValNone, merged.Next()) | 
					
						
							|  |  |  | 	require.EqualError(t, merged.Err(), "something went wrong") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Next() does some special handling for the first iterator, so make sure it handles the first iterator returning an error too.
 | 
					
						
							|  |  |  | 	merged = ChainSampleIteratorFromIterators(nil, []chunkenc.Iterator{ | 
					
						
							|  |  |  | 		errIterator{errors.New("something went wrong")}, | 
					
						
							|  |  |  | 		NewListSeriesIterator(samples{fSample{0, 0.1}, fSample{1, 1.1}, fSample{2, 2.1}}), | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	require.Equal(t, chunkenc.ValNone, merged.Next()) | 
					
						
							|  |  |  | 	require.EqualError(t, merged.Err(), "something went wrong") | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-19 23:06:46 +08:00
										 |  |  | func TestChainSampleIteratorSeekHistogramCounterResetHint(t *testing.T) { | 
					
						
							|  |  |  | 	for sampleType, sampleFunc := range map[string]func(int64, histogram.CounterResetHint) chunks.Sample{ | 
					
						
							|  |  |  | 		"histogram":       func(ts int64, hint histogram.CounterResetHint) chunks.Sample { return histogramSample(ts, hint) }, | 
					
						
							|  |  |  | 		"float histogram": func(ts int64, hint histogram.CounterResetHint) chunks.Sample { return floatHistogramSample(ts, hint) }, | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 	} { | 
					
						
							| 
									
										
										
										
											2023-09-19 23:06:46 +08:00
										 |  |  | 		for name, tc := range map[string]struct { | 
					
						
							|  |  |  | 			input    []chunkenc.Iterator | 
					
						
							|  |  |  | 			seek     int64 | 
					
						
							|  |  |  | 			expected []chunks.Sample | 
					
						
							|  |  |  | 		}{ | 
					
						
							|  |  |  | 			"single iterator": { | 
					
						
							|  |  |  | 				input: []chunkenc.Iterator{ | 
					
						
							|  |  |  | 					NewListSeriesIterator(samples{sampleFunc(0, cr), sampleFunc(1, cr), sampleFunc(2, uk)}), | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 				seek:     1, | 
					
						
							|  |  |  | 				expected: []chunks.Sample{sampleFunc(1, uk), sampleFunc(2, uk)}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			"non overlapping iterators": { | 
					
						
							|  |  |  | 				input: []chunkenc.Iterator{ | 
					
						
							|  |  |  | 					NewListSeriesIterator(samples{sampleFunc(0, cr), sampleFunc(1, uk)}), | 
					
						
							|  |  |  | 					NewListSeriesIterator(samples{sampleFunc(2, cr), sampleFunc(3, cr)}), | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 				seek:     2, | 
					
						
							|  |  |  | 				expected: []chunks.Sample{sampleFunc(2, uk), sampleFunc(3, cr)}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			"non overlapping iterators seek to internal reset": { | 
					
						
							|  |  |  | 				input: []chunkenc.Iterator{ | 
					
						
							|  |  |  | 					NewListSeriesIterator(samples{sampleFunc(0, cr), sampleFunc(1, uk)}), | 
					
						
							|  |  |  | 					NewListSeriesIterator(samples{sampleFunc(2, cr), sampleFunc(3, cr)}), | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 				seek:     3, | 
					
						
							|  |  |  | 				expected: []chunks.Sample{sampleFunc(3, uk)}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 		} { | 
					
						
							|  |  |  | 			t.Run(sampleType+"/"+name, func(t *testing.T) { | 
					
						
							|  |  |  | 				merged := ChainSampleIteratorFromIterators(nil, tc.input) | 
					
						
							|  |  |  | 				actual := []chunks.Sample{} | 
					
						
							|  |  |  | 				switch merged.Seek(tc.seek) { | 
					
						
							|  |  |  | 				case chunkenc.ValFloat: | 
					
						
							|  |  |  | 					t, f := merged.At() | 
					
						
							|  |  |  | 					actual = append(actual, fSample{t, f}) | 
					
						
							|  |  |  | 				case chunkenc.ValHistogram: | 
					
						
							| 
									
										
										
										
											2024-01-24 00:02:14 +08:00
										 |  |  | 					t, h := merged.AtHistogram(nil) | 
					
						
							| 
									
										
										
										
											2023-09-19 23:06:46 +08:00
										 |  |  | 					actual = append(actual, hSample{t, h}) | 
					
						
							|  |  |  | 				case chunkenc.ValFloatHistogram: | 
					
						
							| 
									
										
										
										
											2024-01-24 00:02:14 +08:00
										 |  |  | 					t, fh := merged.AtFloatHistogram(nil) | 
					
						
							| 
									
										
										
										
											2023-09-19 23:06:46 +08:00
										 |  |  | 					actual = append(actual, fhSample{t, fh}) | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				s, err := ExpandSamples(merged, nil) | 
					
						
							|  |  |  | 				require.NoError(t, err) | 
					
						
							|  |  |  | 				actual = append(actual, s...) | 
					
						
							|  |  |  | 				require.Equal(t, tc.expected, actual) | 
					
						
							|  |  |  | 			}) | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-21 18:56:44 +08:00
										 |  |  | func makeSeries(numSeries, numSamples int) []Series { | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 	series := []Series{} | 
					
						
							| 
									
										
										
										
											2025-08-27 20:38:54 +08:00
										 |  |  | 	for j := range numSeries { | 
					
						
							| 
									
										
										
										
											2022-03-10 06:21:50 +08:00
										 |  |  | 		labels := labels.FromStrings("foo", fmt.Sprintf("bar%d", j)) | 
					
						
							| 
									
										
										
										
											2023-08-24 21:21:17 +08:00
										 |  |  | 		samples := []chunks.Sample{} | 
					
						
							| 
									
										
										
										
											2025-08-27 20:38:54 +08:00
										 |  |  | 		for k := range numSamples { | 
					
						
							| 
									
										
										
										
											2022-12-08 20:31:08 +08:00
										 |  |  | 			samples = append(samples, fSample{t: int64(k), f: float64(k)}) | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		series = append(series, NewListSeries(labels, samples)) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-09-21 18:56:44 +08:00
										 |  |  | 	return series | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-21 18:56:44 +08:00
										 |  |  | func makeMergeSeriesSet(serieses [][]Series) SeriesSet { | 
					
						
							|  |  |  | 	seriesSets := make([]genericSeriesSet, len(serieses)) | 
					
						
							|  |  |  | 	for i, s := range serieses { | 
					
						
							|  |  |  | 		seriesSets[i] = &genericSeriesSetAdapter{NewMockSeriesSet(s...)} | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2024-11-08 00:52:55 +08:00
										 |  |  | 	return &seriesSetAdapter{newGenericMergeSeriesSet(seriesSets, 0, (&seriesMergerAdapter{VerticalSeriesMergeFunc: ChainedSeriesMerge}).Merge)} | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-21 18:56:44 +08:00
										 |  |  | func benchmarkDrain(b *testing.B, makeSeriesSet func() SeriesSet) { | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 	var err error | 
					
						
							| 
									
										
										
										
											2022-09-21 18:56:44 +08:00
										 |  |  | 	var t int64 | 
					
						
							|  |  |  | 	var v float64 | 
					
						
							| 
									
										
										
										
											2022-09-21 01:16:45 +08:00
										 |  |  | 	var iter chunkenc.Iterator | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 	for n := 0; n < b.N; n++ { | 
					
						
							| 
									
										
										
										
											2022-09-21 18:56:44 +08:00
										 |  |  | 		seriesSet := makeSeriesSet() | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 		for seriesSet.Next() { | 
					
						
							| 
									
										
										
										
											2022-09-21 01:16:45 +08:00
										 |  |  | 			iter = seriesSet.At().Iterator(iter) | 
					
						
							| 
									
										
										
										
											2022-09-21 18:56:44 +08:00
										 |  |  | 			for iter.Next() == chunkenc.ValFloat { | 
					
						
							|  |  |  | 				t, v = iter.At() | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			err = iter.Err() | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2022-09-21 18:56:44 +08:00
										 |  |  | 		require.NoError(b, err) | 
					
						
							|  |  |  | 		require.NotEqual(b, t, v) // To ensure the inner loop doesn't get optimised away.
 | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func BenchmarkNoMergeSeriesSet_100_100(b *testing.B) { | 
					
						
							| 
									
										
										
										
											2022-09-21 18:56:44 +08:00
										 |  |  | 	series := makeSeries(100, 100) | 
					
						
							|  |  |  | 	benchmarkDrain(b, func() SeriesSet { return NewMockSeriesSet(series...) }) | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08: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 18:56:44 +08:00
										 |  |  | 		serieses := [][]Series{} | 
					
						
							|  |  |  | 		for i := 0; i < bm.numSeriesSets; i++ { | 
					
						
							|  |  |  | 			serieses = append(serieses, makeSeries(bm.numSeries, bm.numSamples)) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 		b.Run(fmt.Sprintf("%d_%d_%d", bm.numSeriesSets, bm.numSeries, bm.numSamples), func(b *testing.B) { | 
					
						
							| 
									
										
										
										
											2022-09-21 18:56:44 +08:00
										 |  |  | 			benchmarkDrain(b, func() SeriesSet { return makeMergeSeriesSet(serieses) }) | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 		}) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-08 00:52:55 +08:00
										 |  |  | func BenchmarkMergeLabelValuesWithLimit(b *testing.B) { | 
					
						
							|  |  |  | 	var queriers []genericQuerier | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-27 20:38:54 +08:00
										 |  |  | 	for i := range 5 { | 
					
						
							| 
									
										
										
										
											2024-11-08 00:52:55 +08:00
										 |  |  | 		var lbls []string | 
					
						
							| 
									
										
										
										
											2025-08-27 20:38:54 +08:00
										 |  |  | 		for j := range 100000 { | 
					
						
							| 
									
										
										
										
											2024-11-08 00:52:55 +08:00
										 |  |  | 			lbls = append(lbls, fmt.Sprintf("querier_%d_label_%d", i, j)) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		q := &mockQuerier{resp: lbls} | 
					
						
							|  |  |  | 		queriers = append(queriers, newGenericQuerierFrom(q)) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	mergeQuerier := &mergeGenericQuerier{ | 
					
						
							|  |  |  | 		queriers: queriers, // Assume querying 5 blocks.
 | 
					
						
							|  |  |  | 		mergeFn: func(l ...Labels) Labels { | 
					
						
							|  |  |  | 			return l[0] | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-04 14:20:57 +08:00
										 |  |  | 	b.Run("benchmark", func(*testing.B) { | 
					
						
							| 
									
										
										
										
											2024-11-08 00:52:55 +08:00
										 |  |  | 		ctx := context.Background() | 
					
						
							|  |  |  | 		hints := &LabelHints{ | 
					
						
							|  |  |  | 			Limit: 1000, | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		mergeQuerier.LabelValues(ctx, "name", hints) | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-22 21:33:59 +08:00
										 |  |  | func visitMockQueriers(t *testing.T, qr Querier, f func(t *testing.T, q *mockQuerier)) int { | 
					
						
							|  |  |  | 	count := 0 | 
					
						
							|  |  |  | 	switch x := qr.(type) { | 
					
						
							|  |  |  | 	case *mockQuerier: | 
					
						
							|  |  |  | 		count++ | 
					
						
							|  |  |  | 		f(t, x) | 
					
						
							|  |  |  | 	case *querierAdapter: | 
					
						
							|  |  |  | 		count += visitMockQueriersInGenericQuerier(t, x.genericQuerier, f) | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2024-07-22 21:33:59 +08:00
										 |  |  | 	return count | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-22 21:33:59 +08:00
										 |  |  | func visitMockQueriersInGenericQuerier(t *testing.T, g genericQuerier, f func(t *testing.T, q *mockQuerier)) int { | 
					
						
							|  |  |  | 	count := 0 | 
					
						
							|  |  |  | 	switch x := g.(type) { | 
					
						
							|  |  |  | 	case *mergeGenericQuerier: | 
					
						
							|  |  |  | 		for _, q := range x.queriers { | 
					
						
							|  |  |  | 			count += visitMockQueriersInGenericQuerier(t, q, f) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	case *genericQuerierAdapter: | 
					
						
							|  |  |  | 		// Visitor for chunkQuerier not implemented.
 | 
					
						
							|  |  |  | 		count += visitMockQueriers(t, x.q, f) | 
					
						
							|  |  |  | 	case *secondaryQuerier: | 
					
						
							|  |  |  | 		count += visitMockQueriersInGenericQuerier(t, x.genericQuerier, f) | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2024-07-22 21:33:59 +08:00
										 |  |  | 	return count | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-22 21:33:59 +08:00
										 |  |  | func TestMergeQuerierWithSecondaries_ErrorHandling(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 	var ( | 
					
						
							|  |  |  | 		errStorage  = errors.New("storage error") | 
					
						
							|  |  |  | 		warnStorage = errors.New("storage warning") | 
					
						
							| 
									
										
										
										
											2023-09-14 16:39:51 +08:00
										 |  |  | 		ctx         = context.Background() | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 	) | 
					
						
							|  |  |  | 	for _, tcase := range []struct { | 
					
						
							| 
									
										
										
										
											2024-07-22 21:33:59 +08:00
										 |  |  | 		name        string | 
					
						
							|  |  |  | 		primaries   []Querier | 
					
						
							|  |  |  | 		secondaries []Querier | 
					
						
							| 
									
										
										
										
											2024-11-08 00:52:55 +08:00
										 |  |  | 		limit       int | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		expectedSelectsSeries []labels.Labels | 
					
						
							|  |  |  | 		expectedLabels        []string | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-15 00:57:31 +08:00
										 |  |  | 		expectedWarnings annotations.Annotations | 
					
						
							| 
									
										
										
										
											2021-02-10 01:38:35 +08:00
										 |  |  | 		expectedErrs     [4]error | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 	}{ | 
					
						
							|  |  |  | 		{ | 
					
						
							| 
									
										
										
										
											2024-07-22 21:33:59 +08:00
										 |  |  | 			name:      "one successful primary querier", | 
					
						
							|  |  |  | 			primaries: []Querier{&mockQuerier{resp: []string{"a", "b"}, warnings: nil, err: nil}}, | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 			expectedSelectsSeries: []labels.Labels{ | 
					
						
							|  |  |  | 				labels.FromStrings("test", "a"), | 
					
						
							|  |  |  | 				labels.FromStrings("test", "b"), | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			expectedLabels: []string{"a", "b"}, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name: "multiple successful primary queriers", | 
					
						
							| 
									
										
										
										
											2024-07-22 21:33:59 +08:00
										 |  |  | 			primaries: []Querier{ | 
					
						
							|  |  |  | 				&mockQuerier{resp: []string{"a", "b"}, warnings: nil, err: nil}, | 
					
						
							|  |  |  | 				&mockQuerier{resp: []string{"b", "c"}, warnings: nil, err: nil}, | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 			}, | 
					
						
							|  |  |  | 			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", | 
					
						
							| 
									
										
										
										
											2024-07-22 21:33:59 +08:00
										 |  |  | 			primaries:    []Querier{&mockQuerier{warnings: nil, err: errStorage}}, | 
					
						
							| 
									
										
										
										
											2021-02-10 01:38:35 +08:00
										 |  |  | 			expectedErrs: [4]error{errStorage, errStorage, errStorage, errStorage}, | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name: "one successful primary querier with successful secondaries", | 
					
						
							| 
									
										
										
										
											2024-07-22 21:33:59 +08:00
										 |  |  | 			primaries: []Querier{ | 
					
						
							|  |  |  | 				&mockQuerier{resp: []string{"a", "b"}, warnings: nil, err: nil}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			secondaries: []Querier{ | 
					
						
							|  |  |  | 				&mockQuerier{resp: []string{"b"}, warnings: nil, err: nil}, | 
					
						
							|  |  |  | 				&mockQuerier{resp: []string{"c"}, warnings: nil, err: nil}, | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 			}, | 
					
						
							|  |  |  | 			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", | 
					
						
							| 
									
										
										
										
											2024-07-22 21:33:59 +08:00
										 |  |  | 			primaries: []Querier{ | 
					
						
							|  |  |  | 				&mockQuerier{resp: []string{}, warnings: nil, err: nil}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			secondaries: []Querier{ | 
					
						
							|  |  |  | 				&mockQuerier{resp: []string{"b"}, warnings: nil, err: nil}, | 
					
						
							|  |  |  | 				&mockQuerier{resp: []string{"c"}, warnings: nil, err: nil}, | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 			}, | 
					
						
							|  |  |  | 			expectedSelectsSeries: []labels.Labels{ | 
					
						
							|  |  |  | 				labels.FromStrings("test", "b"), | 
					
						
							|  |  |  | 				labels.FromStrings("test", "c"), | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			expectedLabels: []string{"b", "c"}, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name: "one failed primary querier with successful secondaries", | 
					
						
							| 
									
										
										
										
											2024-07-22 21:33:59 +08:00
										 |  |  | 			primaries: []Querier{ | 
					
						
							|  |  |  | 				&mockQuerier{warnings: nil, err: errStorage}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			secondaries: []Querier{ | 
					
						
							|  |  |  | 				&mockQuerier{resp: []string{"b"}, warnings: nil, err: nil}, | 
					
						
							|  |  |  | 				&mockQuerier{resp: []string{"c"}, warnings: nil, err: nil}, | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 			}, | 
					
						
							| 
									
										
										
										
											2021-02-10 01:38:35 +08:00
										 |  |  | 			expectedErrs: [4]error{errStorage, errStorage, errStorage, errStorage}, | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 		}, | 
					
						
							| 
									
										
										
										
											2024-07-22 22:02:52 +08:00
										 |  |  | 		{ | 
					
						
							|  |  |  | 			name:      "nil primary querier with failed secondary", | 
					
						
							|  |  |  | 			primaries: nil, | 
					
						
							|  |  |  | 			secondaries: []Querier{ | 
					
						
							|  |  |  | 				&mockQuerier{resp: []string{"b"}, warnings: nil, err: errStorage}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			expectedLabels:   []string{}, | 
					
						
							|  |  |  | 			expectedWarnings: annotations.New().Add(errStorage), | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name:      "nil primary querier with two failed secondaries", | 
					
						
							|  |  |  | 			primaries: nil, | 
					
						
							|  |  |  | 			secondaries: []Querier{ | 
					
						
							|  |  |  | 				&mockQuerier{resp: []string{"b"}, warnings: nil, err: errStorage}, | 
					
						
							|  |  |  | 				&mockQuerier{resp: []string{"c"}, warnings: nil, err: errStorage}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			expectedLabels:   []string{}, | 
					
						
							|  |  |  | 			expectedWarnings: annotations.New().Add(errStorage), | 
					
						
							|  |  |  | 		}, | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 		{ | 
					
						
							|  |  |  | 			name: "one successful primary querier with failed secondaries", | 
					
						
							| 
									
										
										
										
											2024-07-22 21:33:59 +08:00
										 |  |  | 			primaries: []Querier{ | 
					
						
							|  |  |  | 				&mockQuerier{resp: []string{"a"}, warnings: nil, err: nil}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			secondaries: []Querier{ | 
					
						
							|  |  |  | 				&mockQuerier{resp: []string{"b"}, warnings: nil, err: errStorage}, | 
					
						
							|  |  |  | 				&mockQuerier{resp: []string{"c"}, warnings: nil, err: errStorage}, | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 			}, | 
					
						
							|  |  |  | 			expectedSelectsSeries: []labels.Labels{ | 
					
						
							|  |  |  | 				labels.FromStrings("test", "a"), | 
					
						
							|  |  |  | 			}, | 
					
						
							| 
									
										
										
										
											2023-09-15 00:57:31 +08:00
										 |  |  | 			expectedLabels:   []string{"a"}, | 
					
						
							|  |  |  | 			expectedWarnings: annotations.New().Add(errStorage), | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name: "successful queriers with warnings", | 
					
						
							| 
									
										
										
										
											2024-07-22 21:33:59 +08:00
										 |  |  | 			primaries: []Querier{ | 
					
						
							|  |  |  | 				&mockQuerier{resp: []string{"a"}, warnings: annotations.New().Add(warnStorage), err: nil}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			secondaries: []Querier{ | 
					
						
							|  |  |  | 				&mockQuerier{resp: []string{"b"}, warnings: annotations.New().Add(warnStorage), err: nil}, | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 			}, | 
					
						
							|  |  |  | 			expectedSelectsSeries: []labels.Labels{ | 
					
						
							|  |  |  | 				labels.FromStrings("test", "a"), | 
					
						
							|  |  |  | 				labels.FromStrings("test", "b"), | 
					
						
							|  |  |  | 			}, | 
					
						
							| 
									
										
										
										
											2023-09-15 00:57:31 +08:00
										 |  |  | 			expectedLabels:   []string{"a", "b"}, | 
					
						
							|  |  |  | 			expectedWarnings: annotations.New().Add(warnStorage), | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 		}, | 
					
						
							| 
									
										
										
										
											2024-11-08 00:52:55 +08:00
										 |  |  | 		{ | 
					
						
							|  |  |  | 			name: "successful queriers with limit", | 
					
						
							|  |  |  | 			primaries: []Querier{ | 
					
						
							|  |  |  | 				&mockQuerier{resp: []string{"a", "d"}, warnings: annotations.New().Add(warnStorage), err: nil}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			secondaries: []Querier{ | 
					
						
							|  |  |  | 				&mockQuerier{resp: []string{"b", "c"}, warnings: annotations.New().Add(warnStorage), err: nil}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			limit: 2, | 
					
						
							|  |  |  | 			expectedSelectsSeries: []labels.Labels{ | 
					
						
							|  |  |  | 				labels.FromStrings("test", "a"), | 
					
						
							|  |  |  | 				labels.FromStrings("test", "b"), | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			expectedLabels:   []string{"a", "b"}, | 
					
						
							|  |  |  | 			expectedWarnings: annotations.New().Add(warnStorage), | 
					
						
							|  |  |  | 		}, | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 	} { | 
					
						
							| 
									
										
										
										
											2024-11-08 00:52:55 +08:00
										 |  |  | 		var labelHints *LabelHints | 
					
						
							|  |  |  | 		var selectHints *SelectHints | 
					
						
							|  |  |  | 		if tcase.limit > 0 { | 
					
						
							|  |  |  | 			labelHints = &LabelHints{ | 
					
						
							|  |  |  | 				Limit: tcase.limit, | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			selectHints = &SelectHints{ | 
					
						
							|  |  |  | 				Limit: tcase.limit, | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 		t.Run(tcase.name, func(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2024-07-22 21:33:59 +08:00
										 |  |  | 			q := NewMergeQuerier(tcase.primaries, tcase.secondaries, func(s ...Series) Series { return s[0] }) | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			t.Run("Select", func(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2024-11-08 00:52:55 +08:00
										 |  |  | 				res := q.Select(context.Background(), false, selectHints) | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 				var lbls []labels.Labels | 
					
						
							|  |  |  | 				for res.Next() { | 
					
						
							|  |  |  | 					lbls = append(lbls, res.At().Labels()) | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2023-09-15 00:57:31 +08:00
										 |  |  | 				require.Subset(t, tcase.expectedWarnings, res.Warnings()) | 
					
						
							| 
									
										
										
										
											2020-10-29 17:43:23 +08:00
										 |  |  | 				require.Equal(t, tcase.expectedErrs[0], res.Err()) | 
					
						
							| 
									
										
										
										
											2023-12-07 19:35:01 +08:00
										 |  |  | 				require.ErrorIs(t, res.Err(), tcase.expectedErrs[0], "expected error doesn't match") | 
					
						
							| 
									
										
										
										
											2020-10-29 17:43:23 +08:00
										 |  |  | 				require.Equal(t, tcase.expectedSelectsSeries, lbls) | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-22 21:33:59 +08:00
										 |  |  | 				n := visitMockQueriers(t, q, func(t *testing.T, m *mockQuerier) { | 
					
						
							|  |  |  | 					// Single queries should be unsorted; merged queries sorted.
 | 
					
						
							|  |  |  | 					exp := len(tcase.primaries)+len(tcase.secondaries) > 1 | 
					
						
							|  |  |  | 					require.Equal(t, []bool{exp}, m.sortedSeriesRequested) | 
					
						
							|  |  |  | 				}) | 
					
						
							|  |  |  | 				// Check we visited all queriers.
 | 
					
						
							|  |  |  | 				require.Equal(t, len(tcase.primaries)+len(tcase.secondaries), n) | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 			}) | 
					
						
							|  |  |  | 			t.Run("LabelNames", func(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2024-11-08 00:52:55 +08:00
										 |  |  | 				res, w, err := q.LabelNames(ctx, labelHints) | 
					
						
							| 
									
										
										
										
											2023-09-15 00:57:31 +08:00
										 |  |  | 				require.Subset(t, tcase.expectedWarnings, w) | 
					
						
							| 
									
										
										
										
											2023-12-07 19:35:01 +08:00
										 |  |  | 				require.ErrorIs(t, err, tcase.expectedErrs[1], "expected error doesn't match") | 
					
						
							| 
									
										
										
										
											2024-07-22 22:01:00 +08:00
										 |  |  | 				requireEqualSlice(t, tcase.expectedLabels, res) | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 				if err != nil { | 
					
						
							|  |  |  | 					return | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2024-07-22 21:33:59 +08:00
										 |  |  | 				visitMockQueriers(t, q, func(t *testing.T, m *mockQuerier) { | 
					
						
							| 
									
										
										
										
											2020-10-29 17:43:23 +08:00
										 |  |  | 					require.Equal(t, 1, m.labelNamesCalls) | 
					
						
							| 
									
										
										
										
											2024-07-22 21:33:59 +08:00
										 |  |  | 				}) | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 			}) | 
					
						
							|  |  |  | 			t.Run("LabelValues", func(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2024-11-08 00:52:55 +08:00
										 |  |  | 				res, w, err := q.LabelValues(ctx, "test", labelHints) | 
					
						
							| 
									
										
										
										
											2023-09-15 00:57:31 +08:00
										 |  |  | 				require.Subset(t, tcase.expectedWarnings, w) | 
					
						
							| 
									
										
										
										
											2023-12-07 19:35:01 +08:00
										 |  |  | 				require.ErrorIs(t, err, tcase.expectedErrs[2], "expected error doesn't match") | 
					
						
							| 
									
										
										
										
											2024-07-22 22:01:00 +08:00
										 |  |  | 				requireEqualSlice(t, tcase.expectedLabels, res) | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 				if err != nil { | 
					
						
							|  |  |  | 					return | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2024-07-22 21:33:59 +08:00
										 |  |  | 				visitMockQueriers(t, q, func(t *testing.T, m *mockQuerier) { | 
					
						
							| 
									
										
										
										
											2021-02-10 01:38:35 +08:00
										 |  |  | 					require.Equal(t, []labelNameRequest{{name: "test"}}, m.labelNamesRequested) | 
					
						
							| 
									
										
										
										
											2024-07-22 21:33:59 +08:00
										 |  |  | 				}) | 
					
						
							| 
									
										
										
										
											2021-02-10 01:38:35 +08:00
										 |  |  | 			}) | 
					
						
							|  |  |  | 			t.Run("LabelValuesWithMatchers", func(t *testing.T) { | 
					
						
							|  |  |  | 				matcher := labels.MustNewMatcher(labels.MatchEqual, "otherLabel", "someValue") | 
					
						
							| 
									
										
										
										
											2024-11-08 00:52:55 +08:00
										 |  |  | 				res, w, err := q.LabelValues(ctx, "test2", labelHints, matcher) | 
					
						
							| 
									
										
										
										
											2023-09-15 00:57:31 +08:00
										 |  |  | 				require.Subset(t, tcase.expectedWarnings, w) | 
					
						
							| 
									
										
										
										
											2023-12-07 19:35:01 +08:00
										 |  |  | 				require.ErrorIs(t, err, tcase.expectedErrs[3], "expected error doesn't match") | 
					
						
							| 
									
										
										
										
											2024-07-22 22:01:00 +08:00
										 |  |  | 				requireEqualSlice(t, tcase.expectedLabels, res) | 
					
						
							| 
									
										
										
										
											2021-02-10 01:38:35 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 				if err != nil { | 
					
						
							|  |  |  | 					return | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2024-07-22 21:33:59 +08:00
										 |  |  | 				visitMockQueriers(t, q, func(t *testing.T, m *mockQuerier) { | 
					
						
							| 
									
										
										
										
											2021-02-10 01:38:35 +08:00
										 |  |  | 					require.Equal(t, []labelNameRequest{ | 
					
						
							|  |  |  | 						{name: "test"}, | 
					
						
							|  |  |  | 						{name: "test2", matchers: []*labels.Matcher{matcher}}, | 
					
						
							|  |  |  | 					}, m.labelNamesRequested) | 
					
						
							| 
									
										
										
										
											2024-07-22 21:33:59 +08:00
										 |  |  | 				}) | 
					
						
							| 
									
										
										
										
											2020-08-03 18:32:56 +08:00
										 |  |  | 			}) | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2023-11-01 06:35:17 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-22 22:01:00 +08:00
										 |  |  | // Check slice but ignore difference between nil and empty.
 | 
					
						
							| 
									
										
										
										
											2025-08-27 20:38:54 +08:00
										 |  |  | func requireEqualSlice[T any](t require.TestingT, a, b []T, msgAndArgs ...any) { | 
					
						
							| 
									
										
										
										
											2024-07-22 22:01:00 +08:00
										 |  |  | 	if len(a) == 0 { | 
					
						
							|  |  |  | 		require.Empty(t, b, msgAndArgs...) | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		require.Equal(t, a, b, msgAndArgs...) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-01 06:35:17 +08:00
										 |  |  | type errIterator struct { | 
					
						
							|  |  |  | 	err error | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-04 14:20:57 +08:00
										 |  |  | func (errIterator) Next() chunkenc.ValueType { | 
					
						
							| 
									
										
										
										
											2023-11-01 06:35:17 +08:00
										 |  |  | 	return chunkenc.ValNone | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-04 14:20:57 +08:00
										 |  |  | func (errIterator) Seek(int64) chunkenc.ValueType { | 
					
						
							| 
									
										
										
										
											2023-11-01 06:35:17 +08:00
										 |  |  | 	return chunkenc.ValNone | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-04 14:20:57 +08:00
										 |  |  | func (errIterator) At() (int64, float64) { | 
					
						
							| 
									
										
										
										
											2023-11-01 06:35:17 +08:00
										 |  |  | 	return 0, 0 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-04 14:20:57 +08:00
										 |  |  | func (errIterator) AtHistogram(*histogram.Histogram) (int64, *histogram.Histogram) { | 
					
						
							| 
									
										
										
										
											2023-11-01 06:35:17 +08:00
										 |  |  | 	return 0, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-04 14:20:57 +08:00
										 |  |  | func (errIterator) AtFloatHistogram(*histogram.FloatHistogram) (int64, *histogram.FloatHistogram) { | 
					
						
							| 
									
										
										
										
											2023-11-01 06:35:17 +08:00
										 |  |  | 	return 0, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-04 14:20:57 +08:00
										 |  |  | func (errIterator) AtT() int64 { | 
					
						
							| 
									
										
										
										
											2023-11-01 06:35:17 +08:00
										 |  |  | 	return 0 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (e errIterator) Err() error { | 
					
						
							|  |  |  | 	return e.err | 
					
						
							|  |  |  | } |