[metricsql] for subqueries fixed behavior of functions that use query time range in their logic (like start, end, and running_*), from now on when using in subqueries they respect time range from query parameters (#5794)

This commit is contained in:
Alexander Marshalov 2024-02-22 04:19:32 +01:00
parent 7332431b90
commit 881dffd6a2
No known key found for this signature in database
3 changed files with 52 additions and 9 deletions

View file

@ -111,6 +111,11 @@ type EvalConfig struct {
End int64 End int64
Step int64 Step int64
// RealStart contains the original start of the interval when executed in subqueries (because Start can be changed for subqueries)
RealStart int64
// RealEnd contains the original end of the interval when executed in subqueries (because End can be changed for subqueries)
RealEnd int64
// MaxSeries is the maximum number of time series, which can be scanned by the query. // MaxSeries is the maximum number of time series, which can be scanned by the query.
// Zero means 'no limit' // Zero means 'no limit'
MaxSeries int MaxSeries int
@ -152,7 +157,17 @@ type EvalConfig struct {
func copyEvalConfig(src *EvalConfig) *EvalConfig { func copyEvalConfig(src *EvalConfig) *EvalConfig {
var ec EvalConfig var ec EvalConfig
ec.Start = src.Start ec.Start = src.Start
if ec.RealStart > 0 {
ec.RealStart = src.RealStart
} else {
ec.RealStart = src.Start
}
ec.End = src.End ec.End = src.End
if ec.RealEnd > 0 {
ec.RealEnd = src.RealEnd
} else {
ec.RealEnd = src.End
}
ec.Step = src.Step ec.Step = src.Step
ec.MaxSeries = src.MaxSeries ec.MaxSeries = src.MaxSeries
ec.MaxPointsPerSeries = src.MaxPointsPerSeries ec.MaxPointsPerSeries = src.MaxPointsPerSeries

View file

@ -1248,8 +1248,13 @@ func newTransformFuncRunning(rf func(a, b float64, idx int) float64) transformFu
prevValue := values[0] prevValue := values[0]
values = values[1:] values = values[1:]
for i, v := range values { for i, v := range values {
if !math.IsNaN(v) { if tfa.ec.RealEnd > 0 && ts.Timestamps[i] > tfa.ec.RealEnd {
prevValue = rf(prevValue, v, i+1) break
}
if ts.Timestamps[i] >= tfa.ec.RealStart {
if !math.IsNaN(v) {
prevValue = rf(prevValue, v, i+1)
}
} }
values[i] = prevValue values[i] = prevValue
} }
@ -1265,7 +1270,7 @@ func newTransformFuncRange(rf func(a, b float64, idx int) float64) transformFunc
if err != nil { if err != nil {
return nil, err return nil, err
} }
setLastValues(rvs) setLastValues(tfa, rvs)
return rvs, nil return rvs, nil
} }
} }
@ -1539,7 +1544,7 @@ func transformRangeQuantile(tfa *transformFuncArg) ([]*timeseries, error) {
} }
a.A = values a.A = values
putFloat64s(a) putFloat64s(a)
setLastValues(rvs) setLastValues(tfa, rvs)
return rvs, nil return rvs, nil
} }
@ -1554,9 +1559,14 @@ func transformRangeFirst(tfa *transformFuncArg) ([]*timeseries, error) {
if len(values) == 0 { if len(values) == 0 {
continue continue
} }
vFirstSet := false
vFirst := values[0] vFirst := values[0]
for i, v := range values { for i, v := range values {
if math.IsNaN(v) { if !vFirstSet && ts.Timestamps[i] >= tfa.ec.RealStart {
vFirst = v
vFirstSet = true
}
if !vFirstSet && math.IsNaN(v) {
continue continue
} }
values[i] = vFirst values[i] = vFirst
@ -1571,17 +1581,28 @@ func transformRangeLast(tfa *transformFuncArg) ([]*timeseries, error) {
return nil, err return nil, err
} }
rvs := args[0] rvs := args[0]
setLastValues(rvs) setLastValues(tfa, rvs)
return rvs, nil return rvs, nil
} }
func setLastValues(tss []*timeseries) { func setLastValues(tfa *transformFuncArg, tss []*timeseries) {
for _, ts := range tss { for _, ts := range tss {
values := skipTrailingNaNs(ts.Values) values := skipTrailingNaNs(ts.Values)
if len(values) == 0 { if len(values) == 0 {
continue continue
} }
vLast := values[len(values)-1] vLast := values[len(values)-1]
if tfa.ec.RealEnd > 0 {
for i := len(values) - 1; i >= 0; i-- {
if math.IsNaN(values[i]) {
continue
}
if ts.Timestamps[i] > tfa.ec.RealEnd {
continue
}
vLast = values[i]
}
}
for i, v := range values { for i, v := range values {
if math.IsNaN(v) { if math.IsNaN(v) {
continue continue
@ -2713,11 +2734,17 @@ func transformStep(tfa *transformFuncArg) float64 {
} }
func transformStart(tfa *transformFuncArg) float64 { func transformStart(tfa *transformFuncArg) float64 {
return float64(tfa.ec.Start) / 1e3 if tfa.ec.RealStart == 0 {
return float64(tfa.ec.Start) / 1e3
}
return float64(tfa.ec.RealStart) / 1e3
} }
func transformEnd(tfa *transformFuncArg) float64 { func transformEnd(tfa *transformFuncArg) float64 {
return float64(tfa.ec.End) / 1e3 if tfa.ec.RealEnd == 0 {
return float64(tfa.ec.End) / 1e3
}
return float64(tfa.ec.RealEnd) / 1e3
} }
// copyTimeseries returns a copy of tss. // copyTimeseries returns a copy of tss.

View file

@ -41,6 +41,7 @@ See also [LTS releases](https://docs.victoriametrics.com/LTS-releases.html).
* BUGFIX: fix the misleading error `0ms is out of allowed range [0 ...` when passing `step=0` to [/api/v1/query](https://docs.victoriametrics.com/keyconcepts/#instant-query) * BUGFIX: fix the misleading error `0ms is out of allowed range [0 ...` when passing `step=0` to [/api/v1/query](https://docs.victoriametrics.com/keyconcepts/#instant-query)
or [/api/v1/query_range](https://docs.victoriametrics.com/keyconcepts/#range-query). See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/5795). or [/api/v1/query_range](https://docs.victoriametrics.com/keyconcepts/#range-query). See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/5795).
* BUGFIX: [vmalert](https://docs.victoriametrics.com/#vmalert): consistently sort groups by name and filename on `/groups` page in UI. This should prevent non-deterministic sorting for groups with identical names. * BUGFIX: [vmalert](https://docs.victoriametrics.com/#vmalert): consistently sort groups by name and filename on `/groups` page in UI. This should prevent non-deterministic sorting for groups with identical names.
* BUGFIX: [MetricsQL](https://docs.victoriametrics.com/MetricsQL.html): For subqueries fix behavior of functions that use query time range in their logic (like `start`, `end`, and `running_*`), from now on when using in subqueries they respect time range from query parameters. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/5794) for details.
## [v1.98.0](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.98.0) ## [v1.98.0](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.98.0)