Skip to content

Commit

Permalink
MQE: don't select more data than strictly necessary (#10209)
Browse files Browse the repository at this point in the history
  • Loading branch information
charleskorn authored Dec 12, 2024
1 parent 87d6570 commit a3ae00e
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 1 deletion.
2 changes: 1 addition & 1 deletion pkg/streamingpromql/operators/selectors/selector.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ func (s *Selector) SeriesMetadata(ctx context.Context) ([]types.SeriesMetadata,

// Apply lookback delta, range and offset after adjusting for timestamp from @ modifier.
rangeMilliseconds := s.Range.Milliseconds()
startTimestamp = startTimestamp - s.LookbackDelta.Milliseconds() - rangeMilliseconds - s.Offset - 1 // -1 to exclude samples on the lower boundary of the range.
startTimestamp = startTimestamp - s.LookbackDelta.Milliseconds() - rangeMilliseconds - s.Offset + 1 // +1 to exclude samples on the lower boundary of the range (queriers work with closed intervals, we use left-open).
endTimestamp = endTimestamp - s.Offset

hints := &storage.SelectHints{
Expand Down
84 changes: 84 additions & 0 deletions pkg/streamingpromql/operators/selectors/selector_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,17 @@
package selectors

import (
"context"
"fmt"
"strconv"
"testing"
"time"

"github.com/prometheus/prometheus/model/labels"
"github.com/prometheus/prometheus/model/timestamp"
"github.com/prometheus/prometheus/storage"
"github.com/prometheus/prometheus/tsdb/chunkenc"
"github.com/prometheus/prometheus/util/annotations"
"github.com/stretchr/testify/require"

"github.com/grafana/mimir/pkg/streamingpromql/types"
Expand Down Expand Up @@ -97,3 +101,83 @@ func (m mockSeries) Labels() labels.Labels {
func (m mockSeries) Iterator(chunkenc.Iterator) chunkenc.Iterator {
panic("mockSeries: Iterator() not supported")
}

func TestSelector_QueryRanges(t *testing.T) {
start := time.Date(2024, 12, 11, 3, 12, 45, 0, time.UTC)
end := start.Add(time.Hour)
timeRange := types.NewRangeQueryTimeRange(start, end, time.Minute)

t.Run("instant vector selector", func(t *testing.T) {
queryable := &mockQueryable{}
lookbackDelta := 5 * time.Minute
s := &Selector{
Queryable: queryable,
TimeRange: timeRange,
LookbackDelta: lookbackDelta,
}

_, err := s.SeriesMetadata(context.Background())
require.NoError(t, err)

expectedMinT := timestamp.FromTime(start.Add(-lookbackDelta).Add(time.Millisecond)) // Add a millisecond to exclude the beginning of the range.
expectedMaxT := timestamp.FromTime(end)
require.Equal(t, expectedMinT, queryable.mint)
require.Equal(t, expectedMaxT, queryable.maxt)
require.Equal(t, expectedMinT, queryable.hints.Start)
require.Equal(t, expectedMaxT, queryable.hints.End)
})

t.Run("range vector selector", func(t *testing.T) {
queryable := &mockQueryable{}
selectorRange := 15 * time.Minute
s := &Selector{
Queryable: queryable,
TimeRange: timeRange,
Range: selectorRange,
}

_, err := s.SeriesMetadata(context.Background())
require.NoError(t, err)

expectedMinT := timestamp.FromTime(start.Add(-selectorRange).Add(time.Millisecond)) // Add a millisecond to exclude the beginning of the range.
expectedMaxT := timestamp.FromTime(end)
require.Equal(t, expectedMinT, queryable.mint)
require.Equal(t, expectedMaxT, queryable.maxt)
require.Equal(t, expectedMinT, queryable.hints.Start)
require.Equal(t, expectedMaxT, queryable.hints.End)
})
}

type mockQueryable struct {
mint, maxt int64
hints *storage.SelectHints
}

func (m *mockQueryable) Querier(mint, maxt int64) (storage.Querier, error) {
m.mint = mint
m.maxt = maxt

return &mockQuerier{m}, nil
}

type mockQuerier struct {
q *mockQueryable
}

func (m *mockQuerier) Select(_ context.Context, _ bool, hints *storage.SelectHints, _ ...*labels.Matcher) storage.SeriesSet {
m.q.hints = hints

return storage.EmptySeriesSet()
}

func (m *mockQuerier) LabelValues(context.Context, string, *storage.LabelHints, ...*labels.Matcher) ([]string, annotations.Annotations, error) {
panic("not supported")
}

func (m *mockQuerier) LabelNames(context.Context, *storage.LabelHints, ...*labels.Matcher) ([]string, annotations.Annotations, error) {
panic("not supported")
}

func (m *mockQuerier) Close() error {
panic("not supported")
}

0 comments on commit a3ae00e

Please sign in to comment.