From b94f65ddd37f7ff3b7c90accc4d95b55d9aaa5c7 Mon Sep 17 00:00:00 2001 From: pokom Date: Mon, 7 Nov 2022 15:11:57 -0500 Subject: [PATCH] perf(query): Align start/end times with step Range queries will now have their start and end times aligned with the step. This will help metric stores take better advantage of caches for queries. See (https://promlabs.com/blog/2020/06/18/the-anatomy-of-a-promql-query#range-queries) for details on range queries. - closes #1472 --- pkg/prom/query.go | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/pkg/prom/query.go b/pkg/prom/query.go index 8ed6f6eb1..2fe9113a3 100644 --- a/pkg/prom/query.go +++ b/pkg/prom/query.go @@ -258,9 +258,18 @@ func (ctx *Context) query(query string, t time.Time) (interface{}, v1.Warnings, return toReturn, warnings, nil } +// isRequestStepAligned will check if the start and end times are aligned with the step +func (ctx *Context) isRequestStepAligned(start, end time.Time, step time.Duration) bool { + return start.Unix()%step.Milliseconds() == 0 && end.Unix()%step.Milliseconds() == 0 +} + func (ctx *Context) QueryRange(query string, start, end time.Time, step time.Duration) QueryResultsChan { resCh := make(QueryResultsChan) + if !ctx.isRequestStepAligned(start, end, step) { + start, end = ctx.alignWindow(start, end, step) + } + go runQueryRange(query, start, end, step, ctx, resCh, "") return resCh @@ -357,6 +366,7 @@ func (ctx *Context) RawQueryRange(query string, start, end time.Time, step time. func (ctx *Context) queryRange(query string, start, end time.Time, step time.Duration) (interface{}, v1.Warnings, error) { body, err := ctx.RawQueryRange(query, start, end, step) + if err != nil { return nil, nil, err } @@ -382,6 +392,12 @@ func (ctx *Context) queryRange(query string, start, end time.Time, step time.Dur return toReturn, warnings, nil } +func (ctx *Context) alignWindow(start time.Time, end time.Time, step time.Duration) (time.Time, time.Time) { + alignedStart := (start.Unix() / step.Milliseconds()) * start.Unix() + alignedEnd := (end.Unix() / step.Milliseconds()) * end.Unix() + return time.UnixMilli(alignedStart), time.UnixMilli(alignedEnd) +} + // Extracts the warnings from the resulting json if they exist (part of the prometheus response api). func warningsFrom(result interface{}) v1.Warnings { var warnings v1.Warnings