promql/engine.go
func (ng *Engine) execEvalStmt(ctx context.Context, query *query, s *EvalStmt) (Value, storage.Warnings, error) {
	prepareSpanTimer, ctxPrepare := query.stats.GetSpanTimer(ctx, stats.QueryPreparationTime, ng.metrics.queryPrepareTime)
	querier, warnings, err := ng.populateSeries(ctxPrepare, query.queryable, s)
	prepareSpanTimer.Finish()

	// XXX(fabxc): the querier returned by populateSeries might be instantiated
	// we must not return without closing irrespective of the error.
	// TODO: make this semantically saner.
	if querier != nil {
		defer querier.Close()
	}

	if err != nil {
		return nil, warnings, err
	}

	evalSpanTimer, ctxInnerEval := query.stats.GetSpanTimer(ctx, stats.InnerEvalTime, ng.metrics.queryInnerEval)
	// Instant evaluation. This is executed as a range evaluation with one step.
	if s.Start == s.End && s.Interval == 0 {
		start := timeMilliseconds(s.Start)
		evaluator := &evaluator{
			startTimestamp:      start,
			endTimestamp:        start,
			interval:            1,
			ctx:                 ctxInnerEval,
			maxSamples:          ng.maxSamplesPerQuery,
			defaultEvalInterval: GetDefaultEvaluationInterval(),
			logger:              ng.logger,
		}
		val, err := evaluator.Eval(s.Expr)
		if err != nil {
			return nil, warnings, err
		}

		evalSpanTimer.Finish()

		mat, ok := val.(Matrix)
		if !ok {
			panic(errors.Errorf("promql.Engine.exec: invalid expression type %q", val.Type()))
		}
		query.matrix = mat
		switch s.Expr.Type() {
		case ValueTypeVector:
			// Convert matrix with one value per series into vector.
			vector := make(Vector, len(mat))
			for i, s := range mat {
				// Point might have a different timestamp, force it to 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}}
			}
			return vector, warnings, nil
		case ValueTypeScalar:
			return Scalar{V: mat[0].Points[0].V, T: start}, warnings, nil
		case ValueTypeMatrix:
			return mat, warnings, nil
		default:
			panic(errors.Errorf("promql.Engine.exec: unexpected expression type %q", s.Expr.Type()))
		}

	}

	// Range evaluation.
	evaluator := &evaluator{
		startTimestamp:      timeMilliseconds(s.Start),
		endTimestamp:        timeMilliseconds(s.End),
		interval:            durationMilliseconds(s.Interval),
		ctx:                 ctxInnerEval,
		maxSamples:          ng.maxSamplesPerQuery,
		defaultEvalInterval: GetDefaultEvaluationInterval(),
		logger:              ng.logger,
	}
	val, err := evaluator.Eval(s.Expr)
	if err != nil {
		return nil, warnings, err
	}
	evalSpanTimer.Finish()

	mat, ok := val.(Matrix)
	if !ok {
		panic(errors.Errorf("promql.Engine.exec: invalid expression type %q", val.Type()))
	}
	query.matrix = mat

	if err := contextDone(ctx, "expression evaluation"); err != nil {
		return nil, warnings, err
	}

	// TODO(fabxc): order ensured by storage?
	// TODO(fabxc): where to ensure metric labels are a copy from the storage internals.
	sortSpanTimer, _ := query.stats.GetSpanTimer(ctx, stats.ResultSortTime, ng.metrics.queryResultSort)
	sort.Sort(mat)
	sortSpanTimer.Finish()

	return mat, warnings, nil
}
func (ng *Engine) execEvalStmt(ctx context.Context, query *query, s *EvalStmt) (Value, storage.Warnings, error) {
	prepareSpanTimer, ctxPrepare := query.stats.GetSpanTimer(ctx, stats.QueryPreparationTime, ng.metrics.queryPrepareTime)
	querier, warnings, err := ng.populateSeries(ctxPrepare, query.queryable, s)
	prepareSpanTimer.Finish()

	// XXX(fabxc): the querier returned by populateSeries might be instantiated
	// we must not return without closing irrespective of the error.
	// TODO: make this semantically saner.
	if querier != nil {
		defer querier.Close()
	}

	if err != nil {
		return nil, warnings, err
	}

	evalSpanTimer, ctxInnerEval := query.stats.GetSpanTimer(ctx, stats.InnerEvalTime, ng.metrics.queryInnerEval)
	// Instant evaluation. This is executed as a range evaluation with one step.
	if s.Start == s.End && s.Interval == 0 {
		start := timeMilliseconds(s.Start)
		evaluator := &evaluator{
			startTimestamp:      start,
			endTimestamp:        start,
			interval:            1,
			ctx:                 ctxInnerEval,
			maxSamples:          ng.maxSamplesPerQuery,
			defaultEvalInterval: GetDefaultEvaluationInterval(),
			logger:              ng.logger,
		}
		val, err := evaluator.Eval(s.Expr)
		if err != nil {
			return nil, warnings, err
		}

		evalSpanTimer.Finish()

		mat, ok := val.(Matrix)
		if !ok {
			panic(errors.Errorf("promql.Engine.exec: invalid expression type %q", val.Type()))
		}
		query.matrix = mat
		switch s.Expr.Type() {
		case ValueTypeVector:
			// Convert matrix with one value per series into vector.
			vector := make(Vector, len(mat))
			for i, s := range mat {
				// Point might have a different timestamp, force it to 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}}
			}
			return vector, warnings, nil
		case ValueTypeScalar:
			return Scalar{V: mat[0].Points[0].V, T: start}, warnings, nil
		case ValueTypeMatrix:
			return mat, warnings, nil
		default:
			panic(errors.Errorf("promql.Engine.exec: unexpected expression type %q", s.Expr.Type()))
		}

	}

	// Range evaluation.
	evaluator := &evaluator{
		startTimestamp:      timeMilliseconds(s.Start),
		endTimestamp:        timeMilliseconds(s.End),
		interval:            durationMilliseconds(s.Interval),
		ctx:                 ctxInnerEval,
		maxSamples:          ng.maxSamplesPerQuery,
		defaultEvalInterval: GetDefaultEvaluationInterval(),
		logger:              ng.logger,
	}
	val, err := evaluator.Eval(s.Expr)
	if err != nil {
		return nil, warnings, err
	}
	evalSpanTimer.Finish()

	mat, ok := val.(Matrix)
	if !ok {
		panic(errors.Errorf("promql.Engine.exec: invalid expression type %q", val.Type()))
	}
	query.matrix = mat

	if err := contextDone(ctx, "expression evaluation"); err != nil {
		return nil, warnings, err
	}

	// TODO(fabxc): order ensured by storage?
	// TODO(fabxc): where to ensure metric labels are a copy from the storage internals.
	sortSpanTimer, _ := query.stats.GetSpanTimer(ctx, stats.ResultSortTime, ng.metrics.queryResultSort)
	sort.Sort(mat)
	sortSpanTimer.Finish()

	return mat, warnings, nil
}
func ( ng * Engine ) execEvalStmt ( ctx context . Context , query * query , s * EvalStmt ) ( Value , storage . Warnings , error ) { prepareSpanTimer , ctxPrepare := query . stats . GetSpanTimer ( ctx , stats . QueryPreparationTime , ng . metrics . queryPrepareTime ) querier , warnings , err := ng . populateSeries ( ctxPrepare , query . queryable , s ) prepareSpanTimer . Finish ( ) // XXX(fabxc): the querier returned by populateSeries might be instantiated // we must not return without closing irrespective of the error. // TODO: make this semantically saner. if querier != nil { defer querier . Close ( ) } if err != nil { return nil , warnings , err } evalSpanTimer , ctxInnerEval := query . stats . GetSpanTimer ( ctx , stats . InnerEvalTime , ng . metrics . queryInnerEval ) // Instant evaluation. This is executed as a range evaluation with one step. if s . Start == s . End && s . Interval == 0 { start := timeMilliseconds ( s . Start ) evaluator := & evaluator { startTimestamp : start , endTimestamp : start , interval : 1 , ctx : ctxInnerEval , maxSamples : ng . maxSamplesPerQuery , defaultEvalInterval : GetDefaultEvaluationInterval ( ) , logger : ng . logger , } val , err := evaluator . Eval ( s . Expr ) if err != nil { return nil , warnings , err } evalSpanTimer . Finish ( ) mat , ok := val . ( Matrix ) if ! ok { panic ( errors . Errorf ( " " , val . Type ( ) ) ) } query . matrix = mat switch s . Expr . Type ( ) { case ValueTypeVector : // Convert matrix with one value per series into vector. vector := make ( Vector , len ( mat ) ) for i , s := range mat { // Point might have a different timestamp, force it to 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 } } } return vector , warnings , nil case ValueTypeScalar : return Scalar { V : mat [ 0 ] . Points [ 0 ] . V , T : start } , warnings , nil case ValueTypeMatrix : return mat , warnings , nil default : panic ( errors . Errorf ( " " , s . Expr . Type ( ) ) ) } } // Range evaluation. evaluator := & evaluator { startTimestamp : timeMilliseconds ( s . Start ) , endTimestamp : timeMilliseconds ( s . End ) , interval : durationMilliseconds ( s . Interval ) , ctx : ctxInnerEval , maxSamples : ng . maxSamplesPerQuery , defaultEvalInterval : GetDefaultEvaluationInterval ( ) , logger : ng . logger , } val , err := evaluator . Eval ( s . Expr ) if err != nil { return nil , warnings , err } evalSpanTimer . Finish ( ) mat , ok := val . ( Matrix ) if ! ok { panic ( errors . Errorf ( " " , val . Type ( ) ) ) } query . matrix = mat if err := contextDone ( ctx , " " ) ; err != nil { return nil , warnings , err } // TODO(fabxc): order ensured by storage? // TODO(fabxc): where to ensure metric labels are a copy from the storage internals. sortSpanTimer , _ := query . stats . GetSpanTimer ( ctx , stats . ResultSortTime , ng . metrics . queryResultSort ) sort . Sort ( mat ) sortSpanTimer . Finish ( ) return mat , warnings , nil }
// 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 .