Skip to content

Commit 819b1a7

Browse files
committed
querier: Dedup series is now replica label agnostic and simpler. Fixed panic seen when using larger number of replicas and small series.
Fixes #2645 Signed-off-by: Bartlomiej Plotka <bwplotka@gmail.com>
1 parent 6f2c3b1 commit 819b1a7

File tree

4 files changed

+90
-255
lines changed

4 files changed

+90
-255
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ We use *breaking* word for marking changes that are not backward compatible (rel
1616
- [#2637](https://github.com/thanos-io/thanos/pull/2637) Compact: detect retryable errors that are inside of a wrapped `tsdb.MultiError`
1717
- [#2648](https://github.com/thanos-io/thanos/pull/2648) Store: allow index cache and caching bucket to be configured at the same time.
1818
- [#2705](https://github.com/thanos-io/thanos/pull/2705) minio-go: Added support for `af-south-1` and `eu-south-1` regions.
19+
- [#2728](https://github.com/thanos-io/thanos/pull/2728) Query: Fixed panics when using larger number of replica labels with short series label sets.
1920

2021
### Changed
2122

pkg/query/iter.go

Lines changed: 7 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -342,18 +342,17 @@ func (it *chunkSeriesIterator) Err() error {
342342
}
343343

344344
type dedupSeriesSet struct {
345-
set storage.SeriesSet
346-
replicaLabels map[string]struct{}
347-
isCounter bool
345+
set storage.SeriesSet
346+
isCounter bool
348347

349348
replicas []storage.Series
350349
lset labels.Labels
351350
peek storage.Series
352351
ok bool
353352
}
354353

355-
func newDedupSeriesSet(set storage.SeriesSet, replicaLabels map[string]struct{}, isCounter bool) storage.SeriesSet {
356-
s := &dedupSeriesSet{set: set, replicaLabels: replicaLabels, isCounter: isCounter}
354+
func newDedupSeriesSet(set storage.SeriesSet, isCounter bool) storage.SeriesSet {
355+
s := &dedupSeriesSet{set: set, isCounter: isCounter}
357356
s.ok = s.set.Next()
358357
if s.ok {
359358
s.peek = s.set.At()
@@ -365,31 +364,11 @@ func (s *dedupSeriesSet) Next() bool {
365364
if !s.ok {
366365
return false
367366
}
368-
// Set the label set we are currently gathering to the peek element
369-
// without the replica label if it exists.
370-
s.lset = s.peekLset()
367+
s.lset = s.peek.Labels()
371368
s.replicas = append(s.replicas[:0], s.peek)
372369
return s.next()
373370
}
374371

375-
// peekLset returns the label set of the current peek element stripped from the
376-
// replica label if it exists.
377-
func (s *dedupSeriesSet) peekLset() labels.Labels {
378-
lset := s.peek.Labels()
379-
if len(s.replicaLabels) == 0 {
380-
return lset
381-
}
382-
// Check how many replica labels are present so that these are removed.
383-
var totalToRemove int
384-
for index := 0; index < len(s.replicaLabels); index++ {
385-
if _, ok := s.replicaLabels[lset[len(lset)-index-1].Name]; ok {
386-
totalToRemove++
387-
}
388-
}
389-
// Strip all present replica labels.
390-
return lset[:len(lset)-totalToRemove]
391-
}
392-
393372
func (s *dedupSeriesSet) next() bool {
394373
// Peek the next series to see whether it's a replica for the current series.
395374
s.ok = s.set.Next()
@@ -398,9 +377,9 @@ func (s *dedupSeriesSet) next() bool {
398377
return len(s.replicas) > 0
399378
}
400379
s.peek = s.set.At()
401-
nextLset := s.peekLset()
380+
nextLset := s.peek.Labels()
402381

403-
// If the label set modulo the replica label is equal to the current label set
382+
// If the label set is equal to the current label set
404383
// look for more replicas, otherwise a series is complete.
405384
if !labels.Equal(s.lset, nextLset) {
406385
return true

pkg/query/querier.go

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ func (q *querier) Select(_ bool, hints *storage.SelectHints, ms ...*labels.Match
216216

217217
// TODO(fabxc): this could potentially pushed further down into the store API
218218
// to make true streaming possible.
219-
sortDedupLabels(resp.seriesSet, q.replicaLabels)
219+
trimReplicaLabels(resp.seriesSet, q.replicaLabels)
220220

221221
set := &promSeriesSet{
222222
mint: q.mint,
@@ -226,28 +226,41 @@ func (q *querier) Select(_ bool, hints *storage.SelectHints, ms ...*labels.Match
226226
}
227227

228228
// The merged series set assembles all potentially-overlapping time ranges
229-
// of the same series into a single one. The series are ordered so that equal series
230-
// from different replicas are sequential. We can now deduplicate those.
231-
return newDedupSeriesSet(set, q.replicaLabels, len(aggrs) == 1 && aggrs[0] == storepb.Aggr_COUNTER), warns, nil
229+
// of the same series into a single one.
230+
return newDedupSeriesSet(set, len(aggrs) == 1 && aggrs[0] == storepb.Aggr_COUNTER), warns, nil
232231
}
233232

234-
// sortDedupLabels re-sorts the set so that the same series with different replica
235-
// labels are coming right after each other.
236-
func sortDedupLabels(set []storepb.Series, replicaLabels map[string]struct{}) {
237-
for _, s := range set {
233+
// trimReplicaLabels removed replica labels from all series and re-sorts the set so that the same series are coming right after each other.
234+
func trimReplicaLabels(set []storepb.Series, replicaLabels map[string]struct{}) {
235+
for si := range set {
236+
lset := set[si].Labels
238237
// Move the replica labels to the very end.
239-
sort.Slice(s.Labels, func(i, j int) bool {
240-
if _, ok := replicaLabels[s.Labels[i].Name]; ok {
238+
sort.Slice(lset, func(i, j int) bool {
239+
if _, ok := replicaLabels[lset[i].Name]; ok {
241240
return false
242241
}
243-
if _, ok := replicaLabels[s.Labels[j].Name]; ok {
242+
if _, ok := replicaLabels[lset[j].Name]; ok {
244243
return true
245244
}
246-
return s.Labels[i].Name < s.Labels[j].Name
245+
return lset[i].Name < lset[j].Name
247246
})
247+
248+
// Check how many replica labels are present so that these are removed.
249+
var totalToRemove int
250+
for i := 0; i < len(replicaLabels); i++ {
251+
if len(lset)-i == 0 {
252+
break
253+
}
254+
255+
if _, ok := replicaLabels[lset[len(lset)-i-1].Name]; ok {
256+
totalToRemove++
257+
}
258+
}
259+
// Strip all present replica labels.
260+
set[si].Labels = lset[:len(lset)-totalToRemove]
261+
248262
}
249-
// With the re-ordered label sets, re-sorting all series aligns the same series
250-
// from different replicas sequentially.
263+
// With the removed label sets, re-sorting all series aligns the same series sequentially.
251264
sort.Slice(set, func(i, j int) bool {
252265
return storepb.CompareLabels(set[i].Labels, set[j].Labels) < 0
253266
})

0 commit comments

Comments
 (0)