Commit f0e9196d authored by mknapphrt's avatar mknapphrt Committed by Brian Brazil

Return warnings on a remote read fail (#4832)

Signed-off-by: default avatarMark Knapp <mknapp@hudson-trading.com>
parent 77ee4108
...@@ -24,6 +24,10 @@ and one of the following HTTP response codes: ...@@ -24,6 +24,10 @@ and one of the following HTTP response codes:
Other non-`2xx` codes may be returned for errors occurring before the API Other non-`2xx` codes may be returned for errors occurring before the API
endpoint is reached. endpoint is reached.
An array of warnings may be returned if there are errors that do
not inhibit the request execution. All of the data that was successfully
collected will be returned in the data field.
The JSON response envelope format is as follows: The JSON response envelope format is as follows:
``` ```
...@@ -34,7 +38,11 @@ The JSON response envelope format is as follows: ...@@ -34,7 +38,11 @@ The JSON response envelope format is as follows:
// Only set if status is "error". The data field may still hold // Only set if status is "error". The data field may still hold
// additional data. // additional data.
"errorType": "<string>", "errorType": "<string>",
"error": "<string>" "error": "<string>",
// Only if there were warnings while executing the request.
// There will still be data in the data field.
"warnings": ["<string>"]
} }
``` ```
......
...@@ -111,8 +111,9 @@ type MatrixSelector struct { ...@@ -111,8 +111,9 @@ type MatrixSelector struct {
Offset time.Duration Offset time.Duration
LabelMatchers []*labels.Matcher LabelMatchers []*labels.Matcher
// The series are populated at query preparation time. // The unexpanded seriesSet populated at query preparation time.
series []storage.Series unexpandedSeriesSet storage.SeriesSet
series []storage.Series
} }
// NumberLiteral represents a number. // NumberLiteral represents a number.
...@@ -144,8 +145,9 @@ type VectorSelector struct { ...@@ -144,8 +145,9 @@ type VectorSelector struct {
Offset time.Duration Offset time.Duration
LabelMatchers []*labels.Matcher LabelMatchers []*labels.Matcher
// The series are populated at query preparation time. // The unexpanded seriesSet populated at query preparation time.
series []storage.Series unexpandedSeriesSet storage.SeriesSet
series []storage.Series
} }
func (e *AggregateExpr) Type() ValueType { return ValueTypeVector } func (e *AggregateExpr) Type() ValueType { return ValueTypeVector }
......
...@@ -154,8 +154,8 @@ func (q *query) Exec(ctx context.Context) *Result { ...@@ -154,8 +154,8 @@ func (q *query) Exec(ctx context.Context) *Result {
span.SetTag(queryTag, q.stmt.String()) span.SetTag(queryTag, q.stmt.String())
} }
res, err := q.ng.exec(ctx, q) res, err, warnings := q.ng.exec(ctx, q)
return &Result{Err: err, Value: res} return &Result{Err: err, Value: res, Warnings: warnings}
} }
// contextDone returns an error if the context was canceled or timed out. // contextDone returns an error if the context was canceled or timed out.
...@@ -332,7 +332,7 @@ func (ng *Engine) newTestQuery(f func(context.Context) error) Query { ...@@ -332,7 +332,7 @@ func (ng *Engine) newTestQuery(f func(context.Context) error) Query {
// //
// At this point per query only one EvalStmt is evaluated. Alert and record // At this point per query only one EvalStmt is evaluated. Alert and record
// statements are not handled by the Engine. // statements are not handled by the Engine.
func (ng *Engine) exec(ctx context.Context, q *query) (Value, error) { func (ng *Engine) exec(ctx context.Context, q *query) (Value, error, storage.Warnings) {
ng.metrics.currentQueries.Inc() ng.metrics.currentQueries.Inc()
defer ng.metrics.currentQueries.Dec() defer ng.metrics.currentQueries.Dec()
...@@ -345,7 +345,7 @@ func (ng *Engine) exec(ctx context.Context, q *query) (Value, error) { ...@@ -345,7 +345,7 @@ func (ng *Engine) exec(ctx context.Context, q *query) (Value, error) {
queueSpanTimer, _ := q.stats.GetSpanTimer(ctx, stats.ExecQueueTime, ng.metrics.queryQueueTime) queueSpanTimer, _ := q.stats.GetSpanTimer(ctx, stats.ExecQueueTime, ng.metrics.queryQueueTime)
if err := ng.gate.Start(ctx); err != nil { if err := ng.gate.Start(ctx); err != nil {
return nil, contextErr(err, "query queue") return nil, contextErr(err, "query queue"), nil
} }
defer ng.gate.Done() defer ng.gate.Done()
...@@ -361,14 +361,14 @@ func (ng *Engine) exec(ctx context.Context, q *query) (Value, error) { ...@@ -361,14 +361,14 @@ func (ng *Engine) exec(ctx context.Context, q *query) (Value, error) {
// The base context might already be canceled on the first iteration (e.g. during shutdown). // The base context might already be canceled on the first iteration (e.g. during shutdown).
if err := contextDone(ctx, env); err != nil { if err := contextDone(ctx, env); err != nil {
return nil, err return nil, err, nil
} }
switch s := q.Statement().(type) { switch s := q.Statement().(type) {
case *EvalStmt: case *EvalStmt:
return ng.execEvalStmt(ctx, q, s) return ng.execEvalStmt(ctx, q, s)
case testStmt: case testStmt:
return nil, s(ctx) return nil, s(ctx), nil
} }
panic(fmt.Errorf("promql.Engine.exec: unhandled statement of type %T", q.Statement())) panic(fmt.Errorf("promql.Engine.exec: unhandled statement of type %T", q.Statement()))
...@@ -383,9 +383,9 @@ func durationMilliseconds(d time.Duration) int64 { ...@@ -383,9 +383,9 @@ func durationMilliseconds(d time.Duration) int64 {
} }
// execEvalStmt evaluates the expression of an evaluation statement for the given time range. // execEvalStmt evaluates the expression of an evaluation statement for the given time range.
func (ng *Engine) execEvalStmt(ctx context.Context, query *query, s *EvalStmt) (Value, error) { func (ng *Engine) execEvalStmt(ctx context.Context, query *query, s *EvalStmt) (Value, error, storage.Warnings) {
prepareSpanTimer, ctxPrepare := query.stats.GetSpanTimer(ctx, stats.QueryPreparationTime, ng.metrics.queryPrepareTime) prepareSpanTimer, ctxPrepare := query.stats.GetSpanTimer(ctx, stats.QueryPreparationTime, ng.metrics.queryPrepareTime)
querier, err := ng.populateSeries(ctxPrepare, query.queryable, s) querier, err, warnings := ng.populateSeries(ctxPrepare, query.queryable, s)
prepareSpanTimer.Finish() prepareSpanTimer.Finish()
// XXX(fabxc): the querier returned by populateSeries might be instantiated // XXX(fabxc): the querier returned by populateSeries might be instantiated
...@@ -396,7 +396,7 @@ func (ng *Engine) execEvalStmt(ctx context.Context, query *query, s *EvalStmt) ( ...@@ -396,7 +396,7 @@ func (ng *Engine) execEvalStmt(ctx context.Context, query *query, s *EvalStmt) (
} }
if err != nil { if err != nil {
return nil, err return nil, err, warnings
} }
evalSpanTimer, _ := query.stats.GetSpanTimer(ctx, stats.InnerEvalTime, ng.metrics.queryInnerEval) evalSpanTimer, _ := query.stats.GetSpanTimer(ctx, stats.InnerEvalTime, ng.metrics.queryInnerEval)
...@@ -413,7 +413,7 @@ func (ng *Engine) execEvalStmt(ctx context.Context, query *query, s *EvalStmt) ( ...@@ -413,7 +413,7 @@ func (ng *Engine) execEvalStmt(ctx context.Context, query *query, s *EvalStmt) (
} }
val, err := evaluator.Eval(s.Expr) val, err := evaluator.Eval(s.Expr)
if err != nil { if err != nil {
return nil, err return nil, err, warnings
} }
evalSpanTimer.Finish() evalSpanTimer.Finish()
...@@ -432,11 +432,11 @@ func (ng *Engine) execEvalStmt(ctx context.Context, query *query, s *EvalStmt) ( ...@@ -432,11 +432,11 @@ func (ng *Engine) execEvalStmt(ctx context.Context, query *query, s *EvalStmt) (
// timestamp as that is when we ran the evaluation. // timestamp as that is when we ran the evaluation.
vector[i] = Sample{Metric: s.Metric, Point: Point{V: s.Points[0].V, T: start}} vector[i] = Sample{Metric: s.Metric, Point: Point{V: s.Points[0].V, T: start}}
} }
return vector, nil return vector, nil, warnings
case ValueTypeScalar: case ValueTypeScalar:
return Scalar{V: mat[0].Points[0].V, T: start}, nil return Scalar{V: mat[0].Points[0].V, T: start}, nil, warnings
case ValueTypeMatrix: case ValueTypeMatrix:
return mat, nil return mat, nil, warnings
default: default:
panic(fmt.Errorf("promql.Engine.exec: unexpected expression type %q", s.Expr.Type())) panic(fmt.Errorf("promql.Engine.exec: unexpected expression type %q", s.Expr.Type()))
} }
...@@ -454,7 +454,7 @@ func (ng *Engine) execEvalStmt(ctx context.Context, query *query, s *EvalStmt) ( ...@@ -454,7 +454,7 @@ func (ng *Engine) execEvalStmt(ctx context.Context, query *query, s *EvalStmt) (
} }
val, err := evaluator.Eval(s.Expr) val, err := evaluator.Eval(s.Expr)
if err != nil { if err != nil {
return nil, err return nil, err, warnings
} }
evalSpanTimer.Finish() evalSpanTimer.Finish()
...@@ -465,7 +465,7 @@ func (ng *Engine) execEvalStmt(ctx context.Context, query *query, s *EvalStmt) ( ...@@ -465,7 +465,7 @@ func (ng *Engine) execEvalStmt(ctx context.Context, query *query, s *EvalStmt) (
query.matrix = mat query.matrix = mat
if err := contextDone(ctx, "expression evaluation"); err != nil { if err := contextDone(ctx, "expression evaluation"); err != nil {
return nil, err return nil, err, warnings
} }
// TODO(fabxc): order ensured by storage? // TODO(fabxc): order ensured by storage?
...@@ -474,10 +474,10 @@ func (ng *Engine) execEvalStmt(ctx context.Context, query *query, s *EvalStmt) ( ...@@ -474,10 +474,10 @@ func (ng *Engine) execEvalStmt(ctx context.Context, query *query, s *EvalStmt) (
sort.Sort(mat) sort.Sort(mat)
sortSpanTimer.Finish() sortSpanTimer.Finish()
return mat, nil return mat, nil, warnings
} }
func (ng *Engine) populateSeries(ctx context.Context, q storage.Queryable, s *EvalStmt) (storage.Querier, error) { func (ng *Engine) populateSeries(ctx context.Context, q storage.Queryable, s *EvalStmt) (storage.Querier, error, storage.Warnings) {
var maxOffset time.Duration var maxOffset time.Duration
Inspect(s.Expr, func(node Node, _ []Node) error { Inspect(s.Expr, func(node Node, _ []Node) error {
switch n := node.(type) { switch n := node.(type) {
...@@ -503,11 +503,14 @@ func (ng *Engine) populateSeries(ctx context.Context, q storage.Queryable, s *Ev ...@@ -503,11 +503,14 @@ func (ng *Engine) populateSeries(ctx context.Context, q storage.Queryable, s *Ev
querier, err := q.Querier(ctx, timestamp.FromTime(mint), timestamp.FromTime(s.End)) querier, err := q.Querier(ctx, timestamp.FromTime(mint), timestamp.FromTime(s.End))
if err != nil { if err != nil {
return nil, err return nil, err, nil
} }
var warnings storage.Warnings
Inspect(s.Expr, func(node Node, path []Node) error { Inspect(s.Expr, func(node Node, path []Node) error {
var set storage.SeriesSet var set storage.SeriesSet
var wrn storage.Warnings
params := &storage.SelectParams{ params := &storage.SelectParams{
Start: timestamp.FromTime(s.Start), Start: timestamp.FromTime(s.Start),
End: timestamp.FromTime(s.End), End: timestamp.FromTime(s.End),
...@@ -524,17 +527,13 @@ func (ng *Engine) populateSeries(ctx context.Context, q storage.Queryable, s *Ev ...@@ -524,17 +527,13 @@ func (ng *Engine) populateSeries(ctx context.Context, q storage.Queryable, s *Ev
params.End = params.End - offsetMilliseconds params.End = params.End - offsetMilliseconds
} }
set, err = querier.Select(params, n.LabelMatchers...) set, err, wrn = querier.Select(params, n.LabelMatchers...)
warnings = append(warnings, wrn...)
if err != nil { if err != nil {
level.Error(ng.logger).Log("msg", "error selecting series set", "err", err) level.Error(ng.logger).Log("msg", "error selecting series set", "err", err)
return err return err
} }
n.series, err = expandSeriesSet(ctx, set) n.unexpandedSeriesSet = set
if err != nil {
// TODO(fabxc): use multi-error.
level.Error(ng.logger).Log("msg", "error expanding series set", "err", err)
return err
}
case *MatrixSelector: case *MatrixSelector:
params.Func = extractFuncFromPath(path) params.Func = extractFuncFromPath(path)
...@@ -547,20 +546,17 @@ func (ng *Engine) populateSeries(ctx context.Context, q storage.Queryable, s *Ev ...@@ -547,20 +546,17 @@ func (ng *Engine) populateSeries(ctx context.Context, q storage.Queryable, s *Ev
params.End = params.End - offsetMilliseconds params.End = params.End - offsetMilliseconds
} }
set, err = querier.Select(params, n.LabelMatchers...) set, err, wrn = querier.Select(params, n.LabelMatchers...)
warnings = append(warnings, wrn...)
if err != nil { if err != nil {
level.Error(ng.logger).Log("msg", "error selecting series set", "err", err) level.Error(ng.logger).Log("msg", "error selecting series set", "err", err)
return err return err
} }
n.series, err = expandSeriesSet(ctx, set) n.unexpandedSeriesSet = set
if err != nil {
level.Error(ng.logger).Log("msg", "error expanding series set", "err", err)
return err
}
} }
return nil return nil
}) })
return querier, err return querier, err, warnings
} }
// extractFuncFromPath walks up the path and searches for the first instance of // extractFuncFromPath walks up the path and searches for the first instance of
...@@ -582,6 +578,30 @@ func extractFuncFromPath(p []Node) string { ...@@ -582,6 +578,30 @@ func extractFuncFromPath(p []Node) string {
return extractFuncFromPath(p[:len(p)-1]) return extractFuncFromPath(p[:len(p)-1])
} }
func checkForSeriesSetExpansion(expr Expr, ctx context.Context) error {
switch e := expr.(type) {
case *MatrixSelector:
if e.series == nil {
series, err := expandSeriesSet(ctx, e.unexpandedSeriesSet)
if err != nil {
panic(err)
} else {
e.series = series
}
}
case *VectorSelector:
if e.series == nil {
series, err := expandSeriesSet(ctx, e.unexpandedSeriesSet)
if err != nil {
panic(err)
} else {
e.series = series
}
}
}
return nil
}
func expandSeriesSet(ctx context.Context, it storage.SeriesSet) (res []storage.Series, err error) { func expandSeriesSet(ctx context.Context, it storage.SeriesSet) (res []storage.Series, err error) {
for it.Next() { for it.Next() {
select { select {
...@@ -887,6 +907,9 @@ func (ev *evaluator) eval(expr Expr) Value { ...@@ -887,6 +907,9 @@ func (ev *evaluator) eval(expr Expr) Value {
} }
sel := e.Args[matrixArgIndex].(*MatrixSelector) sel := e.Args[matrixArgIndex].(*MatrixSelector)
if err := checkForSeriesSetExpansion(sel, ev.ctx); err != nil {
ev.error(err)
}
mat := make(Matrix, 0, len(sel.series)) // Output matrix. mat := make(Matrix, 0, len(sel.series)) // Output matrix.
offset := durationMilliseconds(sel.Offset) offset := durationMilliseconds(sel.Offset)
selRange := durationMilliseconds(sel.Range) selRange := durationMilliseconds(sel.Range)
...@@ -1018,6 +1041,9 @@ func (ev *evaluator) eval(expr Expr) Value { ...@@ -1018,6 +1041,9 @@ func (ev *evaluator) eval(expr Expr) Value {
}) })
case *VectorSelector: case *VectorSelector:
if err := checkForSeriesSetExpansion(e, ev.ctx); err != nil {
ev.error(err)
}
mat := make(Matrix, 0, len(e.series)) mat := make(Matrix, 0, len(e.series))
it := storage.NewBuffer(durationMilliseconds(LookbackDelta)) it := storage.NewBuffer(durationMilliseconds(LookbackDelta))
for i, s := range e.series { for i, s := range e.series {
...@@ -1058,6 +1084,10 @@ func (ev *evaluator) eval(expr Expr) Value { ...@@ -1058,6 +1084,10 @@ func (ev *evaluator) eval(expr Expr) Value {
// vectorSelector evaluates a *VectorSelector expression. // vectorSelector evaluates a *VectorSelector expression.
func (ev *evaluator) vectorSelector(node *VectorSelector, ts int64) Vector { func (ev *evaluator) vectorSelector(node *VectorSelector, ts int64) Vector {
if err := checkForSeriesSetExpansion(node, ev.ctx); err != nil {
ev.error(err)
}
var ( var (
vec = make(Vector, 0, len(node.series)) vec = make(Vector, 0, len(node.series))
) )
...@@ -1127,17 +1157,20 @@ func putPointSlice(p []Point) { ...@@ -1127,17 +1157,20 @@ func putPointSlice(p []Point) {
// matrixSelector evaluates a *MatrixSelector expression. // matrixSelector evaluates a *MatrixSelector expression.
func (ev *evaluator) matrixSelector(node *MatrixSelector) Matrix { func (ev *evaluator) matrixSelector(node *MatrixSelector) Matrix {
if err := checkForSeriesSetExpansion(node, ev.ctx); err != nil {
ev.error(err)
}
var ( var (
offset = durationMilliseconds(node.Offset) offset = durationMilliseconds(node.Offset)
maxt = ev.startTimestamp - offset maxt = ev.startTimestamp - offset
mint = maxt - durationMilliseconds(node.Range) mint = maxt - durationMilliseconds(node.Range)
matrix = make(Matrix, 0, len(node.series)) matrix = make(Matrix, 0, len(node.series))
err error
) )
it := storage.NewBuffer(durationMilliseconds(node.Range)) it := storage.NewBuffer(durationMilliseconds(node.Range))
for i, s := range node.series { for i, s := range node.series {
if err = contextDone(ev.ctx, "expression evaluation"); err != nil { if err := contextDone(ev.ctx, "expression evaluation"); err != nil {
ev.error(err) ev.error(err)
} }
it.Reset(s.Iterator()) it.Reset(s.Iterator())
......
...@@ -169,8 +169,8 @@ type errQuerier struct { ...@@ -169,8 +169,8 @@ type errQuerier struct {
err error err error
} }
func (q *errQuerier) Select(*storage.SelectParams, ...*labels.Matcher) (storage.SeriesSet, error) { func (q *errQuerier) Select(*storage.SelectParams, ...*labels.Matcher) (storage.SeriesSet, error, storage.Warnings) {
return errSeriesSet{err: q.err}, q.err return errSeriesSet{err: q.err}, q.err, nil
} }
func (*errQuerier) LabelValues(name string) ([]string, error) { return nil, nil } func (*errQuerier) LabelValues(name string) ([]string, error) { return nil, nil }
func (*errQuerier) LabelNames() ([]string, error) { return nil, nil } func (*errQuerier) LabelNames() ([]string, error) { return nil, nil }
...@@ -425,7 +425,8 @@ load 10s ...@@ -425,7 +425,8 @@ load 10s
MaxSamples: 1, MaxSamples: 1,
Result: Result{ Result: Result{
nil, nil,
Scalar{V: 1, T: 1000}}, Scalar{V: 1, T: 1000},
nil},
Start: time.Unix(1, 0), Start: time.Unix(1, 0),
}, },
{ {
...@@ -434,6 +435,7 @@ load 10s ...@@ -434,6 +435,7 @@ load 10s
Result: Result{ Result: Result{
ErrTooManySamples(env), ErrTooManySamples(env),
nil, nil,
nil,
}, },
Start: time.Unix(1, 0), Start: time.Unix(1, 0),
}, },
...@@ -443,6 +445,7 @@ load 10s ...@@ -443,6 +445,7 @@ load 10s
Result: Result{ Result: Result{
ErrTooManySamples(env), ErrTooManySamples(env),
nil, nil,
nil,
}, },
Start: time.Unix(1, 0), Start: time.Unix(1, 0),
}, },
...@@ -455,6 +458,7 @@ load 10s ...@@ -455,6 +458,7 @@ load 10s
Sample{Point: Point{V: 1, T: 1000}, Sample{Point: Point{V: 1, T: 1000},
Metric: labels.FromStrings("__name__", "metric")}, Metric: labels.FromStrings("__name__", "metric")},
}, },
nil,
}, },
Start: time.Unix(1, 0), Start: time.Unix(1, 0),
}, },
...@@ -467,6 +471,7 @@ load 10s ...@@ -467,6 +471,7 @@ load 10s
Points: []Point{{V: 1, T: 0}, {V: 2, T: 10000}}, Points: []Point{{V: 1, T: 0}, {V: 2, T: 10000}},
Metric: labels.FromStrings("__name__", "metric")}, Metric: labels.FromStrings("__name__", "metric")},
}, },
nil,
}, },
Start: time.Unix(10, 0), Start: time.Unix(10, 0),
}, },
...@@ -476,6 +481,7 @@ load 10s ...@@ -476,6 +481,7 @@ load 10s
Result: Result{ Result: Result{
ErrTooManySamples(env), ErrTooManySamples(env),
nil, nil,
nil,
}, },
Start: time.Unix(10, 0), Start: time.Unix(10, 0),
}, },
...@@ -489,6 +495,7 @@ load 10s ...@@ -489,6 +495,7 @@ load 10s
Points: []Point{{V: 1, T: 0}, {V: 1, T: 1000}, {V: 1, T: 2000}}, Points: []Point{{V: 1, T: 0}, {V: 1, T: 1000}, {V: 1, T: 2000}},
Metric: labels.FromStrings()}, Metric: labels.FromStrings()},
}, },
nil,
}, },
Start: time.Unix(0, 0), Start: time.Unix(0, 0),
End: time.Unix(2, 0), End: time.Unix(2, 0),
...@@ -500,6 +507,7 @@ load 10s ...@@ -500,6 +507,7 @@ load 10s
Result: Result{ Result: Result{
ErrTooManySamples(env), ErrTooManySamples(env),
nil, nil,
nil,
}, },
Start: time.Unix(0, 0), Start: time.Unix(0, 0),
End: time.Unix(2, 0), End: time.Unix(2, 0),
...@@ -514,6 +522,7 @@ load 10s ...@@ -514,6 +522,7 @@ load 10s
Points: []Point{{V: 1, T: 0}, {V: 1, T: 1000}, {V: 1, T: 2000}}, Points: []Point{{V: 1, T: 0}, {V: 1, T: 1000}, {V: 1, T: 2000}},
Metric: labels.FromStrings("__name__", "metric")}, Metric: labels.FromStrings("__name__", "metric")},
}, },
nil,
}, },
Start: time.Unix(0, 0), Start: time.Unix(0, 0),
End: time.Unix(2, 0), End: time.Unix(2, 0),
...@@ -525,6 +534,7 @@ load 10s ...@@ -525,6 +534,7 @@ load 10s
Result: Result{ Result: Result{
ErrTooManySamples(env), ErrTooManySamples(env),
nil, nil,
nil,
}, },
Start: time.Unix(0, 0), Start: time.Unix(0, 0),
End: time.Unix(2, 0), End: time.Unix(2, 0),
...@@ -539,6 +549,7 @@ load 10s ...@@ -539,6 +549,7 @@ load 10s
Points: []Point{{V: 1, T: 0}, {V: 1, T: 5000}, {V: 2, T: 10000}}, Points: []Point{{V: 1, T: 0}, {V: 1, T: 5000}, {V: 2, T: 10000}},
Metric: labels.FromStrings("__name__", "metric")}, Metric: labels.FromStrings("__name__", "metric")},
}, },
nil,
}, },
Start: time.Unix(0, 0), Start: time.Unix(0, 0),
End: time.Unix(10, 0), End: time.Unix(10, 0),
...@@ -550,6 +561,7 @@ load 10s ...@@ -550,6 +561,7 @@ load 10s
Result: Result{ Result: Result{
ErrTooManySamples(env), ErrTooManySamples(env),
nil, nil,
nil,
}, },
Start: time.Unix(0, 0), Start: time.Unix(0, 0),
End: time.Unix(10, 0), End: time.Unix(10, 0),
......
...@@ -20,6 +20,7 @@ import ( ...@@ -20,6 +20,7 @@ import (
"strings" "strings"
"github.com/prometheus/prometheus/pkg/labels" "github.com/prometheus/prometheus/pkg/labels"
"github.com/prometheus/prometheus/storage"
) )
// Value is a generic interface for values resulting from a query evaluation. // Value is a generic interface for values resulting from a query evaluation.
...@@ -201,8 +202,9 @@ func (m Matrix) ContainsSameLabelset() bool { ...@@ -201,8 +202,9 @@ func (m Matrix) ContainsSameLabelset() bool {
// Result holds the resulting value of an execution or an error // Result holds the resulting value of an execution or an error
// if any occurred. // if any occurred.
type Result struct { type Result struct {
Err error Err error
Value Value Value Value
Warnings storage.Warnings
} }
// Vector returns a Vector if the result value is one. An error is returned if // Vector returns a Vector if the result value is one. An error is returned if
......
...@@ -518,7 +518,7 @@ func (g *Group) RestoreForState(ts time.Time) { ...@@ -518,7 +518,7 @@ func (g *Group) RestoreForState(ts time.Time) {
matchers = append(matchers, mt) matchers = append(matchers, mt)
} }
sset, err := q.Select(nil, matchers...) sset, err, _ := q.Select(nil, matchers...)
if err != nil { if err != nil {
level.Error(g.logger).Log("msg", "Failed to restore 'for' state", level.Error(g.logger).Log("msg", "Failed to restore 'for' state",
labels.AlertName, alertRule.Name(), "stage", "Select", "err", err) labels.AlertName, alertRule.Name(), "stage", "Select", "err", err)
......
...@@ -538,7 +538,7 @@ func TestStaleness(t *testing.T) { ...@@ -538,7 +538,7 @@ func TestStaleness(t *testing.T) {
matcher, err := labels.NewMatcher(labels.MatchEqual, model.MetricNameLabel, "a_plus_one") matcher, err := labels.NewMatcher(labels.MatchEqual, model.MetricNameLabel, "a_plus_one")
testutil.Ok(t, err) testutil.Ok(t, err)
set, err := querier.Select(nil, matcher) set, err, _ := querier.Select(nil, matcher)
testutil.Ok(t, err) testutil.Ok(t, err)
samples, err := readSeriesSet(set) samples, err := readSeriesSet(set)
......
...@@ -68,23 +68,23 @@ func (f *fanout) Querier(ctx context.Context, mint, maxt int64) (Querier, error) ...@@ -68,23 +68,23 @@ func (f *fanout) Querier(ctx context.Context, mint, maxt int64) (Querier, error)
queriers := make([]Querier, 0, 1+len(f.secondaries)) queriers := make([]Querier, 0, 1+len(f.secondaries))
// Add primary querier // Add primary querier
querier, err := f.primary.Querier(ctx, mint, maxt) primaryQuerier, err := f.primary.Querier(ctx, mint, maxt)
if err != nil { if err != nil {
return nil, err return nil, err
} }
queriers = append(queriers, querier) queriers = append(queriers, primaryQuerier)
// Add secondary queriers // Add secondary queriers
for _, storage := range f.secondaries { for _, storage := range f.secondaries {
querier, err := storage.Querier(ctx, mint, maxt) querier, err := storage.Querier(ctx, mint, maxt)
if err != nil { if err != nil {
NewMergeQuerier(queriers).Close() NewMergeQuerier(primaryQuerier, queriers).Close()
return nil, err return nil, err
} }
queriers = append(queriers, querier) queriers = append(queriers, querier)
} }
return NewMergeQuerier(queriers), nil return NewMergeQuerier(primaryQuerier, queriers), nil
} }
func (f *fanout) Appender() (Appender, error) { func (f *fanout) Appender() (Appender, error) {
...@@ -190,14 +190,18 @@ func (f *fanoutAppender) Rollback() (err error) { ...@@ -190,14 +190,18 @@ func (f *fanoutAppender) Rollback() (err error) {
// mergeQuerier implements Querier. // mergeQuerier implements Querier.
type mergeQuerier struct { type mergeQuerier struct {
queriers []Querier primaryQuerier Querier
queriers []Querier
failedQueriers map[Querier]struct{}
setQuerierMap map[SeriesSet]Querier
} }
// NewMergeQuerier returns a new Querier that merges results of input queriers. // NewMergeQuerier returns a new Querier that merges results of input queriers.
// NB NewMergeQuerier will return NoopQuerier if no queriers are passed to it, // NB NewMergeQuerier will return NoopQuerier if no queriers are passed to it,
// and will filter NoopQueriers from its arguments, in order to reduce overhead // and will filter NoopQueriers from its arguments, in order to reduce overhead
// when only one querier is passed. // when only one querier is passed.
func NewMergeQuerier(queriers []Querier) Querier {