forked from thanos-io/promql-engine
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathutils.go
More file actions
201 lines (188 loc) · 6.43 KB
/
utils.go
File metadata and controls
201 lines (188 loc) · 6.43 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
// Copyright (c) The Thanos Community Authors.
// Licensed under the Apache License 2.0.
package binary
import (
"context"
"fmt"
"math"
"github.com/thanos-io/promql-engine/warnings"
"github.com/prometheus/prometheus/model/histogram"
"github.com/prometheus/prometheus/model/labels"
"github.com/prometheus/prometheus/promql/parser"
"github.com/prometheus/prometheus/promql/parser/posrange"
"github.com/prometheus/prometheus/util/annotations"
)
type binOpSide string
const (
lhBinOpSide binOpSide = "left"
rhBinOpSide binOpSide = "right"
)
type errManyToManyMatch struct {
matching *parser.VectorMatching
side binOpSide
original, duplicate labels.Labels
}
func newManyToManyMatchError(matching *parser.VectorMatching, original, duplicate labels.Labels, side binOpSide) *errManyToManyMatch {
return &errManyToManyMatch{
original: original,
duplicate: duplicate,
matching: matching,
side: side,
}
}
func (e *errManyToManyMatch) Error() string {
group := e.original.MatchLabels(e.matching.On, e.matching.MatchingLabels...)
// The choice of which series is reported as "original" vs "duplicate" is
// driven by upstream StepVector / map iteration order and is therefore
// non-deterministic across runs. Sort the rendered label-set strings so
// the error message is stable; downstream consumers (e.g. Cortex,
// see cortexproject/cortex#7546) compare these messages.
original, duplicate := e.original.String(), e.duplicate.String()
if duplicate < original {
original, duplicate = duplicate, original
}
msg := "found duplicate series for the match group %s on the %s hand-side of the operation: [%s, %s]" +
";many-to-many matching not allowed: matching labels must be unique on one side"
return fmt.Sprintf(msg, group, e.side, original, duplicate)
}
func shouldDropMetricName(op parser.ItemType, returnBool bool) bool {
switch op {
case parser.ADD, parser.SUB, parser.MUL, parser.DIV, parser.MOD, parser.POW, parser.ATAN2:
return true
default:
return op.IsComparisonOperator() && returnBool
}
}
// binOp evaluates a binary operation between two values.
// Returns: value, histogram, keep, warnings, error.
func binOp(op parser.ItemType, lhs, rhs float64, hlhs, hrhs *histogram.FloatHistogram) (float64, *histogram.FloatHistogram, bool, warnings.Warnings, error) {
switch {
case hlhs == nil && hrhs == nil:
{
switch op {
case parser.ADD:
return lhs + rhs, nil, true, 0, nil
case parser.SUB:
return lhs - rhs, nil, true, 0, nil
case parser.MUL:
return lhs * rhs, nil, true, 0, nil
case parser.DIV:
return lhs / rhs, nil, true, 0, nil
case parser.POW:
return math.Pow(lhs, rhs), nil, true, 0, nil
case parser.MOD:
return math.Mod(lhs, rhs), nil, true, 0, nil
case parser.EQLC:
return lhs, nil, lhs == rhs, 0, nil
case parser.NEQ:
return lhs, nil, lhs != rhs, 0, nil
case parser.GTR:
return lhs, nil, lhs > rhs, 0, nil
case parser.LSS:
return lhs, nil, lhs < rhs, 0, nil
case parser.GTE:
return lhs, nil, lhs >= rhs, 0, nil
case parser.LTE:
return lhs, nil, lhs <= rhs, 0, nil
case parser.ATAN2:
return math.Atan2(lhs, rhs), nil, true, 0, nil
}
}
case hlhs == nil && hrhs != nil:
{
switch op {
case parser.MUL:
return 0, hrhs.Copy().Mul(lhs).Compact(0), true, 0, nil
case parser.ADD, parser.SUB, parser.DIV, parser.POW, parser.MOD, parser.EQLC, parser.NEQ, parser.GTR, parser.LSS, parser.GTE, parser.LTE, parser.ATAN2:
return 0, nil, false, warnings.WarnIncompatibleTypesInBinOp, nil
}
}
case hlhs != nil && hrhs == nil:
{
switch op {
case parser.MUL:
return 0, hlhs.Copy().Mul(rhs).Compact(0), true, 0, nil
case parser.DIV:
return 0, hlhs.Copy().Div(rhs).Compact(0), true, 0, nil
case parser.ADD, parser.SUB, parser.POW, parser.MOD, parser.EQLC, parser.NEQ, parser.GTR, parser.LSS, parser.GTE, parser.LTE, parser.ATAN2:
return 0, nil, false, warnings.WarnIncompatibleTypesInBinOp, nil
}
}
case hlhs != nil && hrhs != nil:
{
switch op {
case parser.ADD:
res, counterResetCollision, nhcbBoundsReconciled, err := hlhs.Copy().Add(hrhs)
if err != nil {
return 0, nil, false, 0, err
}
var warn warnings.Warnings
if counterResetCollision {
warn |= warnings.WarnCounterResetCollision
}
if nhcbBoundsReconciled {
warn |= warnings.WarnNHCBBoundsReconciled
}
return 0, res.Compact(0), true, warn, nil
case parser.SUB:
res, counterResetCollision, nhcbBoundsReconciled, err := hlhs.Copy().Sub(hrhs)
if err != nil {
return 0, nil, false, 0, err
}
var warn warnings.Warnings
if counterResetCollision {
warn |= warnings.WarnCounterResetCollision
}
if nhcbBoundsReconciled {
warn |= warnings.WarnNHCBBoundsReconciled
}
return 0, res.Compact(0), true, warn, nil
case parser.EQLC:
// This operation expects that both histograms are compacted.
return 0, hlhs, hlhs.Equals(hrhs), 0, nil
case parser.NEQ:
// This operation expects that both histograms are compacted.
return 0, hlhs, !hlhs.Equals(hrhs), 0, nil
case parser.MUL, parser.DIV, parser.POW, parser.MOD, parser.GTR, parser.LSS, parser.GTE, parser.LTE, parser.ATAN2:
return 0, nil, false, warnings.WarnIncompatibleTypesInBinOp, nil
}
}
}
return 0, nil, false, 0, nil
}
// emitBinaryOpWarnings emits warnings for binary operation side effects.
func emitBinaryOpWarnings(ctx context.Context, warn warnings.Warnings, opType parser.ItemType) {
if warn == 0 {
return
}
if warn&warnings.WarnMixedExponentialCustomBuckets != 0 {
warnings.AddToContext(annotations.NewMixedExponentialCustomHistogramsWarning("", posrange.PositionRange{}), ctx)
}
if warn&warnings.WarnCounterResetCollision != 0 {
var op annotations.HistogramOperation
switch opType {
case parser.ADD:
op = annotations.HistogramAdd
case parser.SUB:
op = annotations.HistogramSub
default:
return
}
warnings.AddToContext(annotations.NewHistogramCounterResetCollisionWarning(posrange.PositionRange{}, op), ctx)
}
if warn&warnings.WarnNHCBBoundsReconciled != 0 {
var op annotations.HistogramOperation
switch opType {
case parser.ADD:
op = annotations.HistogramAdd
case parser.SUB:
op = annotations.HistogramSub
default:
return
}
warnings.AddToContext(annotations.NewMismatchedCustomBucketsHistogramsInfo(posrange.PositionRange{}, op), ctx)
}
if warn&warnings.WarnIncompatibleTypesInBinOp != 0 {
warnings.AddToContext(annotations.IncompatibleTypesInBinOpInfo, ctx)
}
}