Hardcode rate() for sparse histograms

Signed-off-by: Ganesh Vernekar <ganeshvern@gmail.com>
This commit is contained in:
Ganesh Vernekar 2021-07-05 16:17:34 +05:30
parent 67871fd1f2
commit 4cb4fe44f2
No known key found for this signature in database
GPG Key ID: 0F8729A5EB59B965
1 changed files with 70 additions and 0 deletions

View File

@ -497,6 +497,27 @@ func (api *API) queryRange(r *http.Request) (result apiFuncResult) {
return apiFuncResult{nil, &apiError{errorBadData, errors.New("need exactly 1 selector")}, nil, nil} return apiFuncResult{nil, &apiError{errorBadData, errors.New("need exactly 1 selector")}, nil, nil}
} }
hasRate, rateDuration := false, time.Duration(0)
parser.Inspect(expr, func(node parser.Node, path []parser.Node) error {
switch n := node.(type) {
case *parser.Call:
if n.Func.Name == "rate" {
hasRate = true
rateDuration = n.Args[0].(*parser.MatrixSelector).Range
return errors.New("stop it here")
}
}
return nil
})
var numRateSamples int
if hasRate {
numRateSamples = int(end.Sub(start)/step + 1)
if start.Add(time.Duration(numRateSamples-1) * step).After(end) {
numRateSamples--
}
start = start.Add(-rateDuration) // Adjusting for the first point lookback.
}
q, err := api.Queryable.Querier(ctx, timestamp.FromTime(start), timestamp.FromTime(end)) q, err := api.Queryable.Querier(ctx, timestamp.FromTime(start), timestamp.FromTime(end))
if err != nil { if err != nil {
return apiFuncResult{nil, &apiError{errorExec, err}, nil, nil} return apiFuncResult{nil, &apiError{errorExec, err}, nil, nil}
@ -544,6 +565,55 @@ func (api *API) queryRange(r *http.Request) (result apiFuncResult) {
} }
} }
if hasRate {
newRes := make(promql.Matrix, len(res))
for i := range newRes {
newRes[i].Metric = res[i].Metric
points := make([]promql.Point, numRateSamples)
rawPoints := res[i].Points
startIdx, endIdx := 0, 0
for idx := range points {
pointTime := start.Add(time.Duration(idx) * step)
lookbackTime := pointTime.Add(-rateDuration)
points[idx].T = timestamp.FromTime(pointTime)
if len(rawPoints) == 0 {
continue
}
for startIdx < len(rawPoints) && timestamp.Time(rawPoints[startIdx].T).Before(lookbackTime) {
startIdx++
}
if startIdx >= len(rawPoints) {
startIdx = len(rawPoints) - 1
}
for endIdx < len(rawPoints) && timestamp.Time(rawPoints[endIdx].T).Before(pointTime) {
endIdx++
}
if endIdx >= len(rawPoints) {
endIdx = len(rawPoints) - 1
} else if timestamp.Time(rawPoints[endIdx].T).After(pointTime) && (len(rawPoints) == 1 || endIdx == 0) {
continue
} else {
endIdx--
}
valDiff := rawPoints[endIdx].V - rawPoints[startIdx].V
timeDiffSeconds := float64(timestamp.Time(rawPoints[endIdx].T).Sub(timestamp.Time(rawPoints[startIdx].T))) / float64(time.Second)
if timeDiffSeconds != 0 {
points[idx].V = valDiff / timeDiffSeconds
}
}
newRes[i].Points = points
}
res = newRes
}
sort.Sort(res) sort.Sort(res)
return apiFuncResult{&queryData{ return apiFuncResult{&queryData{