Skip to content

Commit 099641f

Browse files
author
Vladimir Smirnov
committed
Fix *seriesLists functions (e.x. divideSeriesLists) to work properly with unsorted metrics
* Sort denominators and numerators * Add test config for mockbackend to replicate this scenario
1 parent fde6084 commit 099641f

File tree

4 files changed

+64
-7
lines changed

4 files changed

+64
-7
lines changed

CHANGES.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ CHANGELOG
2525
- [Fix] Honor SendGlobAsIs and AlwaysSendGlobAsIs (important for pre-0.12 configs)
2626
- [Fix] Fix panic in some cases when one of the metrics is missing
2727
- [Fix] Compatbility fixes to useAboveSeries (now it's behavior matches graphite-web's)
28+
- [Fix] Fix seriesList functions in case of unsorted responses (\*seriesList sorts denomniators and numerators first of all)
2829
- [Improvement] Redesign error handling and logging. Logging should be now less noisy and all error messages should contain better reasoning about error cause
2930
- [Improvement] Move more of the logging messages to Debug level - that should make logs less noisy and still preserve ability to see detailed errors on Debug level
3031
- [Improvement] Add a config parameter to disable tldCache (useful for clickhouse type backends)

cmd/mockbackend/main.go

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,19 @@ import (
55
"encoding/json"
66
"flag"
77
"fmt"
8-
"github.com/ansel1/merry"
9-
"github.com/go-graphite/carbonapi/intervalset"
10-
"go.uber.org/zap"
118
"io/ioutil"
129
"log"
1310
"math"
11+
"math/rand"
1412
"net/http"
1513
"strings"
1614
"sync"
1715
"time"
1816

17+
"github.com/ansel1/merry"
18+
"github.com/go-graphite/carbonapi/intervalset"
19+
"go.uber.org/zap"
20+
1921
"github.com/go-graphite/carbonapi/zipper/httpHeaders"
2022
protov2 "github.com/go-graphite/protocol/carbonapi_v2_pb"
2123
protov3 "github.com/go-graphite/protocol/carbonapi_v3_pb"
@@ -78,10 +80,11 @@ type MultiListenerConfig struct {
7880
}
7981

8082
type Config struct {
81-
Address string `yaml:"address"`
82-
Code int `yaml:"httpCode"`
83-
EmptyBody bool `yaml:"emptyBody"`
84-
Expressions map[string]Response `yaml:"expressions"`
83+
Address string `yaml:"address"`
84+
Code int `yaml:"httpCode"`
85+
ShuffleResults bool `yaml:"shuffleResults"`
86+
EmptyBody bool `yaml:"emptyBody"`
87+
Expressions map[string]Response `yaml:"expressions"`
8588
}
8689

8790
func copyResponse(src Response) Response {
@@ -243,6 +246,12 @@ func (cfg *listener) findHandler(wr http.ResponseWriter, req *http.Request) {
243246
})
244247
}
245248

249+
if cfg.Config.ShuffleResults {
250+
rand.Shuffle(len(multiGlobs.Metrics), func(i, j int) {
251+
multiGlobs.Metrics[i], multiGlobs.Metrics[j] = multiGlobs.Metrics[j], multiGlobs.Metrics[i]
252+
})
253+
}
254+
246255
logger.Info("will return", zap.Any("response", multiGlobs))
247256

248257
var b []byte
@@ -397,6 +406,15 @@ func (cfg *listener) renderHandler(wr http.ResponseWriter, req *http.Request) {
397406
}
398407
}
399408

409+
if cfg.Config.ShuffleResults {
410+
rand.Shuffle(len(multiv2.Metrics), func(i, j int) {
411+
multiv2.Metrics[i], multiv2.Metrics[j] = multiv2.Metrics[j], multiv2.Metrics[i]
412+
})
413+
rand.Shuffle(len(multiv3.Metrics), func(i, j int) {
414+
multiv3.Metrics[i], multiv3.Metrics[j] = multiv3.Metrics[j], multiv3.Metrics[i]
415+
})
416+
}
417+
400418
var d []byte
401419
var contentType string
402420
switch format {
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Example:
2+
# wget -q -O- "http://localhost:8081/render/?format=json&target=divideSeriesLists(seriesByTag('name=~exec_vgcache.cache_read_hits','subtype=dp1','vg_name=dp1_sdai'),seriesByTag('name=~exec_vgcache.cache_read.*','subtype=dp1','vg_name=dp1_sdai'))" | jq -r '.[] | .target'
3+
listeners:
4+
- shuffleResults: true
5+
expressions:
6+
"seriesByTag('name=~exec_vgcache.cache_read_hits','subtype=dp1','vg_name=dp1_sdai')":
7+
pathExpression: "seriesByTag('name=~exec_vgcache.cache_read_hits','subtype=dp1','vg_name=dp1_dai')"
8+
data:
9+
- metricName: "exec_vgcache.cache_read_hits;host=dp1-osd1;vg_name=dp1_sdai;avg=true"
10+
values: [2.0, 2.0, 2.0, 2.0]
11+
- metricName: "exec_vgcache.cache_read_hits;host=dp1-osd1;vg_name=dp1_sdai;sum=true"
12+
values: [4.0, 4.0, 4.0, 4.0]
13+
- metricName: "exec_vgcache.cache_read_hits;host=dp2-osd1;vg_name=dp2_sdai;avg=true"
14+
values: [2.0, 2.0, 2.0, 2.0]
15+
- metricName: "exec_vgcache.cache_read_hits;host=dp2-osd1;vg_name=dp2_sdai;sum=true"
16+
values: [4.0, 4.0, 4.0, 4.0]
17+
- metricName: "exec_vgcache.cache_read_hits;host=dp3-osd1;vg_name=dp3_sdai;avg=true"
18+
values: [2.0, 2.0, 2.0, 2.0]
19+
- metricName: "exec_vgcache.cache_read_hits;host=dp3-osd1;vg_name=dp3_sdai;sum=true"
20+
values: [4.0, 4.0, 4.0, 4.0]
21+
"seriesByTag('name=~exec_vgcache.cache_read.*','subtype=dp1','vg_name=dp1_sdai')":
22+
pathExpression: "seriesByTag('name=~exec_vgcache.cache_read.*','subtype=dp1','vg_name=dp1_sdai')"
23+
data:
24+
- metricName: "exec_vgcache.cache_read_hits;host=dp1-osd1;vg_name=dp1_sdai;avg=true"
25+
values: [2.0, 2.0, 2.0, 2.0]
26+
- metricName: "exec_vgcache.cache_read_hits;host=dp1-osd1;vg_name=dp1_sdai;sum=true"
27+
values: [4.0, 4.0, 4.0, 4.0]
28+
- metricName: "exec_vgcache.cache_read_hits;host=dp2-osd1;vg_name=dp2_sdai;avg=true"
29+
values: [2.0, 2.0, 2.0, 2.0]
30+
- metricName: "exec_vgcache.cache_read_hits;host=dp2-osd1;vg_name=dp2_sdai;sum=true"
31+
values: [4.0, 4.0, 4.0, 4.0]
32+
- metricName: "exec_vgcache.cache_read_hits;host=dp3-osd1;vg_name=dp3_sdai;avg=true"
33+
values: [2.0, 2.0, 2.0, 2.0]
34+
- metricName: "exec_vgcache.cache_read_hits;host=dp3-osd1;vg_name=dp3_sdai;sum=true"
35+
values: [4.0, 4.0, 4.0, 4.0]

expr/functions/seriesList/function.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package seriesList
33
import (
44
"fmt"
55
"math"
6+
"sort"
67
"strconv"
78

89
"github.com/go-graphite/carbonapi/expr/helper"
@@ -55,6 +56,7 @@ func (f *seriesList) Do(e parser.Expr, from, until int64, values map[parser.Metr
5556
return nil, nil
5657
}
5758
}
59+
sort.Slice(numerators, func(i, j int) bool { return numerators[i].Name < numerators[j].Name })
5860

5961
denominators, err := helper.GetSeriesArg(e.Args()[1], from, until, values)
6062
if err != nil {
@@ -71,6 +73,7 @@ func (f *seriesList) Do(e parser.Expr, from, until int64, values map[parser.Metr
7173
return nil, nil
7274
}
7375
}
76+
sort.Slice(numerators, func(i, j int) bool { return denominators[i].Name < denominators[j].Name })
7477

7578
sizeMatch := len(denominators) == len(numerators) || len(denominators) == 1
7679
useMatching, err := e.GetBoolNamedOrPosArgDefault("matching", 2, !useConstant && !sizeMatch)

0 commit comments

Comments
 (0)