Make rules/ast golint clean.

Mostly, that means adding compliant doc strings to exported items.

Also, remove 'go vet' warnings where possible. (Some are unfortunately
not to avoid, arguably bugs in 'go vet'.)

Change-Id: I2827b6dd317492864c1383c3de1ea9eac5a219bb
This commit is contained in:
Bjoern Rabenstein 2014-02-13 18:48:56 +01:00
parent 5e8026779f
commit fd63500ed3
6 changed files with 225 additions and 82 deletions

View file

@ -32,8 +32,12 @@ import (
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Raw data value types. // Raw data value types.
// Vector is basically only an alias for clientmodel.Samples, but the
// contract is that in a Vector, all Samples have the same timestamp.
type Vector clientmodel.Samples type Vector clientmodel.Samples
// Matrix is a slice of SampleSets that implements sort.Interface and
// has a String method.
// BUG(julius): Pointerize this. // BUG(julius): Pointerize this.
type Matrix []metric.SampleSet type Matrix []metric.SampleSet
@ -46,9 +50,10 @@ type groupedAggregation struct {
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Enums. // Enums.
// Rule language expression types. // ExprType is an enum for the rule language expression types.
type ExprType int type ExprType int
// Possible language expression types.
const ( const (
SCALAR ExprType = iota SCALAR ExprType = iota
VECTOR VECTOR
@ -56,9 +61,10 @@ const (
STRING STRING
) )
// Binary operator types. // BinOpType is an enum for binary operator types.
type BinOpType int type BinOpType int
// Possible binary operator types.
const ( const (
ADD BinOpType = iota ADD BinOpType = iota
SUB SUB
@ -75,9 +81,10 @@ const (
OR OR
) )
// Aggregation types. // AggrType is an enum for aggregation types.
type AggrType int type AggrType int
// Possible aggregation types.
const ( const (
SUM AggrType = iota SUM AggrType = iota
AVG AVG
@ -89,9 +96,13 @@ const (
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Interfaces. // Interfaces.
// All node interfaces include the Node interface. // Nodes is a slice of any mix of node types as all node types
// implement the Node interface.
type Nodes []Node type Nodes []Node
// Node is the top-level interface for any kind of nodes. Each node
// type implements one of the ...Node interfaces, each of which embeds
// this Node interface.
type Node interface { type Node interface {
Type() ExprType Type() ExprType
Children() Nodes Children() Nodes
@ -99,26 +110,37 @@ type Node interface {
String() string String() string
} }
// All node types implement one of the following interfaces. The name of the // ScalarNode is a Node for scalar values.
// interface represents the type returned to the parent node.
type ScalarNode interface { type ScalarNode interface {
Node Node
// Eval evaluates and returns the value of the scalar represented by this node.
Eval(timestamp clientmodel.Timestamp, view *viewAdapter) clientmodel.SampleValue Eval(timestamp clientmodel.Timestamp, view *viewAdapter) clientmodel.SampleValue
} }
// VectorNode is a Node for vector values.
type VectorNode interface { type VectorNode interface {
Node Node
// Eval evaluates the node recursively and returns the result
// as a Vector (i.e. a slice of Samples all at the given
// Timestamp).
Eval(timestamp clientmodel.Timestamp, view *viewAdapter) Vector Eval(timestamp clientmodel.Timestamp, view *viewAdapter) Vector
} }
// MatrixNode is a Node for matrix values.
type MatrixNode interface { type MatrixNode interface {
Node Node
// Eval evaluates the node recursively and returns the result as a Matrix.
Eval(timestamp clientmodel.Timestamp, view *viewAdapter) Matrix Eval(timestamp clientmodel.Timestamp, view *viewAdapter) Matrix
// Eval evaluates the node recursively and returns the result
// as a Matrix that only contains the boundary values.
EvalBoundaries(timestamp clientmodel.Timestamp, view *viewAdapter) Matrix EvalBoundaries(timestamp clientmodel.Timestamp, view *viewAdapter) Matrix
} }
// StringNode is a Node for string values.
type StringNode interface { type StringNode interface {
Node Node
// Eval evaluates and returns the value of the string
// represented by this node.
Eval(timestamp clientmodel.Timestamp, view *viewAdapter) string Eval(timestamp clientmodel.Timestamp, view *viewAdapter) string
} }
@ -126,18 +148,20 @@ type StringNode interface {
// ScalarNode types. // ScalarNode types.
type ( type (
// A numeric literal. // ScalarLiteral represents a numeric literal.
ScalarLiteral struct { ScalarLiteral struct {
value clientmodel.SampleValue value clientmodel.SampleValue
} }
// A function of numeric return type. // ScalarFunctionCall represents a function with a numeric
// return type.
ScalarFunctionCall struct { ScalarFunctionCall struct {
function *Function function *Function
args Nodes args Nodes
} }
// An arithmetic expression of numeric type. // ScalarArithExpr represents an arithmetic expression of
// numeric type.
ScalarArithExpr struct { ScalarArithExpr struct {
opType BinOpType opType BinOpType
lhs ScalarNode lhs ScalarNode
@ -149,20 +173,21 @@ type (
// VectorNode types. // VectorNode types.
type ( type (
// Vector literal, i.e. metric name plus labelset. // A VectorLiteral represents a metric name plus labelset.
VectorLiteral struct { VectorLiteral struct {
labels clientmodel.LabelSet labels clientmodel.LabelSet
// Fingerprints are populated from labels at query analysis time. // Fingerprints are populated from labels at query analysis time.
fingerprints clientmodel.Fingerprints fingerprints clientmodel.Fingerprints
} }
// A function of vector return type. // VectorFunctionCall represents a function with vector return
// type.
VectorFunctionCall struct { VectorFunctionCall struct {
function *Function function *Function
args Nodes args Nodes
} }
// A vector aggregation with vector return type. // A VectorAggregation with vector return type.
VectorAggregation struct { VectorAggregation struct {
aggrType AggrType aggrType AggrType
groupBy clientmodel.LabelNames groupBy clientmodel.LabelNames
@ -170,7 +195,8 @@ type (
vector VectorNode vector VectorNode
} }
// An arithmetic expression of vector type. // VectorArithExpr represents an arithmetic expression of
// vector type.
VectorArithExpr struct { VectorArithExpr struct {
opType BinOpType opType BinOpType
lhs VectorNode lhs VectorNode
@ -182,10 +208,12 @@ type (
// MatrixNode types. // MatrixNode types.
type ( type (
// Matrix literal, i.e. metric name plus labelset and timerange. // A MatrixLiteral represents a metric name plus labelset and
// timerange.
MatrixLiteral struct { MatrixLiteral struct {
labels clientmodel.LabelSet labels clientmodel.LabelSet
// Fingerprints are populated from labels at query analysis time. // Fingerprints are populated from labels at query
// analysis time.
fingerprints clientmodel.Fingerprints fingerprints clientmodel.Fingerprints
interval time.Duration interval time.Duration
} }
@ -195,12 +223,13 @@ type (
// StringNode types. // StringNode types.
type ( type (
// String literal. // A StringLiteral is what you think it is.
StringLiteral struct { StringLiteral struct {
str string str string
} }
// A function of string return type. // StringFunctionCall represents a function with string return
// type.
StringFunctionCall struct { StringFunctionCall struct {
function *Function function *Function
args Nodes args Nodes
@ -210,40 +239,88 @@ type (
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Implementations. // Implementations.
// Node.Type() methods. // Type implements the Node interface.
func (node ScalarLiteral) Type() ExprType { return SCALAR } func (node ScalarLiteral) Type() ExprType { return SCALAR }
// Type implements the Node interface.
func (node ScalarFunctionCall) Type() ExprType { return SCALAR } func (node ScalarFunctionCall) Type() ExprType { return SCALAR }
func (node ScalarArithExpr) Type() ExprType { return SCALAR }
func (node VectorLiteral) Type() ExprType { return VECTOR } // Type implements the Node interface.
func (node ScalarArithExpr) Type() ExprType { return SCALAR }
// Type implements the Node interface.
func (node VectorLiteral) Type() ExprType { return VECTOR }
// Type implements the Node interface.
func (node VectorFunctionCall) Type() ExprType { return VECTOR } func (node VectorFunctionCall) Type() ExprType { return VECTOR }
func (node VectorAggregation) Type() ExprType { return VECTOR }
func (node VectorArithExpr) Type() ExprType { return VECTOR } // Type implements the Node interface.
func (node MatrixLiteral) Type() ExprType { return MATRIX } func (node VectorAggregation) Type() ExprType { return VECTOR }
func (node StringLiteral) Type() ExprType { return STRING }
// Type implements the Node interface.
func (node VectorArithExpr) Type() ExprType { return VECTOR }
// Type implements the Node interface.
func (node MatrixLiteral) Type() ExprType { return MATRIX }
// Type implements the Node interface.
func (node StringLiteral) Type() ExprType { return STRING }
// Type implements the Node interface.
func (node StringFunctionCall) Type() ExprType { return STRING } func (node StringFunctionCall) Type() ExprType { return STRING }
// Node.Children() methods. // Children implements the Node interface and returns an empty slice.
func (node ScalarLiteral) Children() Nodes { return Nodes{} } func (node ScalarLiteral) Children() Nodes { return Nodes{} }
// Children implements the Node interface and returns the args of the
// function call.
func (node ScalarFunctionCall) Children() Nodes { return node.args } func (node ScalarFunctionCall) Children() Nodes { return node.args }
func (node ScalarArithExpr) Children() Nodes { return Nodes{node.lhs, node.rhs} }
func (node VectorLiteral) Children() Nodes { return Nodes{} } // Children implements the Node interface and returns the LHS and the RHS
// of the expression.
func (node ScalarArithExpr) Children() Nodes { return Nodes{node.lhs, node.rhs} }
// Children implements the Node interface and returns an empty slice.
func (node VectorLiteral) Children() Nodes { return Nodes{} }
// Children implements the Node interface and returns the args of the
// function call.
func (node VectorFunctionCall) Children() Nodes { return node.args } func (node VectorFunctionCall) Children() Nodes { return node.args }
func (node VectorAggregation) Children() Nodes { return Nodes{node.vector} }
func (node VectorArithExpr) Children() Nodes { return Nodes{node.lhs, node.rhs} } // Children implements the Node interface and returns the vector to be
func (node MatrixLiteral) Children() Nodes { return Nodes{} } // aggregated.
func (node StringLiteral) Children() Nodes { return Nodes{} } func (node VectorAggregation) Children() Nodes { return Nodes{node.vector} }
// Children implements the Node interface and returns the LHS and the RHS
// of the expression.
func (node VectorArithExpr) Children() Nodes { return Nodes{node.lhs, node.rhs} }
// Children implements the Node interface and returns an empty slice.
func (node MatrixLiteral) Children() Nodes { return Nodes{} }
// Children implements the Node interface and returns an empty slice.
func (node StringLiteral) Children() Nodes { return Nodes{} }
// Children implements the Node interface and returns the args of the
// function call.
func (node StringFunctionCall) Children() Nodes { return node.args } func (node StringFunctionCall) Children() Nodes { return node.args }
// Eval implements the ScalarNode interface and returns the literal
// value.
func (node *ScalarLiteral) Eval(timestamp clientmodel.Timestamp, view *viewAdapter) clientmodel.SampleValue { func (node *ScalarLiteral) Eval(timestamp clientmodel.Timestamp, view *viewAdapter) clientmodel.SampleValue {
return node.value return node.value
} }
// Eval implements the ScalarNode interface and returns the result of
// the expression.
func (node *ScalarArithExpr) Eval(timestamp clientmodel.Timestamp, view *viewAdapter) clientmodel.SampleValue { func (node *ScalarArithExpr) Eval(timestamp clientmodel.Timestamp, view *viewAdapter) clientmodel.SampleValue {
lhs := node.lhs.Eval(timestamp, view) lhs := node.lhs.Eval(timestamp, view)
rhs := node.rhs.Eval(timestamp, view) rhs := node.rhs.Eval(timestamp, view)
return evalScalarBinop(node.opType, lhs, rhs) return evalScalarBinop(node.opType, lhs, rhs)
} }
// Eval implements the ScalarNode interface and returns the result of
// the function call.
func (node *ScalarFunctionCall) Eval(timestamp clientmodel.Timestamp, view *viewAdapter) clientmodel.SampleValue { func (node *ScalarFunctionCall) Eval(timestamp clientmodel.Timestamp, view *viewAdapter) clientmodel.SampleValue {
return node.function.callFn(timestamp, view, node.args).(clientmodel.SampleValue) return node.function.callFn(timestamp, view, node.args).(clientmodel.SampleValue)
} }
@ -278,6 +355,7 @@ func labelsToKey(labels clientmodel.Metric) uint64 {
return summer.Sum64() return summer.Sum64()
} }
// EvalVectorInstant evaluates a VectorNode with an instant query.
func EvalVectorInstant(node VectorNode, timestamp clientmodel.Timestamp, storage *metric.TieredStorage, queryStats *stats.TimerGroup) (vector Vector, err error) { func EvalVectorInstant(node VectorNode, timestamp clientmodel.Timestamp, storage *metric.TieredStorage, queryStats *stats.TimerGroup) (vector Vector, err error) {
viewAdapter, err := viewAdapterForInstantQuery(node, timestamp, storage, queryStats) viewAdapter, err := viewAdapterForInstantQuery(node, timestamp, storage, queryStats)
if err != nil { if err != nil {
@ -287,6 +365,7 @@ func EvalVectorInstant(node VectorNode, timestamp clientmodel.Timestamp, storage
return return
} }
// EvalVectorRange evaluates a VectorNode with a range query.
func EvalVectorRange(node VectorNode, start clientmodel.Timestamp, end clientmodel.Timestamp, interval time.Duration, storage *metric.TieredStorage, queryStats *stats.TimerGroup) (Matrix, error) { func EvalVectorRange(node VectorNode, start clientmodel.Timestamp, end clientmodel.Timestamp, interval time.Duration, storage *metric.TieredStorage, queryStats *stats.TimerGroup) (Matrix, error) {
// Explicitly initialize to an empty matrix since a nil Matrix encodes to // Explicitly initialize to an empty matrix since a nil Matrix encodes to
// null in JSON. // null in JSON.
@ -362,6 +441,8 @@ func (node *VectorAggregation) groupedAggregationsToVector(aggregations map[uint
return vector return vector
} }
// Eval implements the VectorNode interface and returns the aggregated
// Vector.
func (node *VectorAggregation) Eval(timestamp clientmodel.Timestamp, view *viewAdapter) Vector { func (node *VectorAggregation) Eval(timestamp clientmodel.Timestamp, view *viewAdapter) Vector {
vector := node.vector.Eval(timestamp, view) vector := node.vector.Eval(timestamp, view)
result := map[uint64]*groupedAggregation{} result := map[uint64]*groupedAggregation{}
@ -414,6 +495,8 @@ func (node *VectorAggregation) Eval(timestamp clientmodel.Timestamp, view *viewA
return node.groupedAggregationsToVector(result, timestamp) return node.groupedAggregationsToVector(result, timestamp)
} }
// Eval implements the VectorNode interface and returns the value of
// the literal.
func (node *VectorLiteral) Eval(timestamp clientmodel.Timestamp, view *viewAdapter) Vector { func (node *VectorLiteral) Eval(timestamp clientmodel.Timestamp, view *viewAdapter) Vector {
values, err := view.GetValueAtTime(node.fingerprints, timestamp) values, err := view.GetValueAtTime(node.fingerprints, timestamp)
if err != nil { if err != nil {
@ -423,6 +506,8 @@ func (node *VectorLiteral) Eval(timestamp clientmodel.Timestamp, view *viewAdapt
return values return values
} }
// Eval implements the VectorNode interface and returns the result of
// the function call.
func (node *VectorFunctionCall) Eval(timestamp clientmodel.Timestamp, view *viewAdapter) Vector { func (node *VectorFunctionCall) Eval(timestamp clientmodel.Timestamp, view *viewAdapter) Vector {
return node.function.callFn(timestamp, view, node.args).(Vector) return node.function.callFn(timestamp, view, node.args).(Vector)
} }
@ -440,51 +525,43 @@ func evalScalarBinop(opType BinOpType,
case DIV: case DIV:
if rhs != 0 { if rhs != 0 {
return lhs / rhs return lhs / rhs
} else {
return clientmodel.SampleValue(math.Inf(int(rhs)))
} }
return clientmodel.SampleValue(math.Inf(int(rhs)))
case MOD: case MOD:
if rhs != 0 { if rhs != 0 {
return clientmodel.SampleValue(int(lhs) % int(rhs)) return clientmodel.SampleValue(int(lhs) % int(rhs))
} else {
return clientmodel.SampleValue(math.Inf(int(rhs)))
} }
return clientmodel.SampleValue(math.Inf(int(rhs)))
case EQ: case EQ:
if lhs == rhs { if lhs == rhs {
return 1 return 1
} else {
return 0
} }
return 0
case NE: case NE:
if lhs != rhs { if lhs != rhs {
return 1 return 1
} else {
return 0
} }
return 0
case GT: case GT:
if lhs > rhs { if lhs > rhs {
return 1 return 1
} else {
return 0
} }
return 0
case LT: case LT:
if lhs < rhs { if lhs < rhs {
return 1 return 1
} else {
return 0
} }
return 0
case GE: case GE:
if lhs >= rhs { if lhs >= rhs {
return 1 return 1
} else {
return 0
} }
return 0
case LE: case LE:
if lhs <= rhs { if lhs <= rhs {
return 1 return 1
} else {
return 0
} }
return 0
} }
panic("Not all enum values enumerated in switch") panic("Not all enum values enumerated in switch")
} }
@ -502,51 +579,43 @@ func evalVectorBinop(opType BinOpType,
case DIV: case DIV:
if rhs != 0 { if rhs != 0 {
return lhs / rhs, true return lhs / rhs, true
} else {
return clientmodel.SampleValue(math.Inf(int(rhs))), true
} }
return clientmodel.SampleValue(math.Inf(int(rhs))), true
case MOD: case MOD:
if rhs != 0 { if rhs != 0 {
return clientmodel.SampleValue(int(lhs) % int(rhs)), true return clientmodel.SampleValue(int(lhs) % int(rhs)), true
} else {
return clientmodel.SampleValue(math.Inf(int(rhs))), true
} }
return clientmodel.SampleValue(math.Inf(int(rhs))), true
case EQ: case EQ:
if lhs == rhs { if lhs == rhs {
return lhs, true return lhs, true
} else {
return 0, false
} }
return 0, false
case NE: case NE:
if lhs != rhs { if lhs != rhs {
return lhs, true return lhs, true
} else {
return 0, false
} }
return 0, false
case GT: case GT:
if lhs > rhs { if lhs > rhs {
return lhs, true return lhs, true
} else {
return 0, false
} }
return 0, false
case LT: case LT:
if lhs < rhs { if lhs < rhs {
return lhs, true return lhs, true
} else {
return 0, false
} }
return 0, false
case GE: case GE:
if lhs >= rhs { if lhs >= rhs {
return lhs, true return lhs, true
} else {
return 0, false
} }
return 0, false
case LE: case LE:
if lhs <= rhs { if lhs <= rhs {
return lhs, true return lhs, true
} else {
return 0, false
} }
return 0, false
case AND: case AND:
return lhs, true return lhs, true
case OR: case OR:
@ -567,6 +636,8 @@ func labelsEqual(labels1, labels2 clientmodel.Metric) bool {
return true return true
} }
// Eval implements the VectorNode interface and returns the result of
// the expression.
func (node *VectorArithExpr) Eval(timestamp clientmodel.Timestamp, view *viewAdapter) Vector { func (node *VectorArithExpr) Eval(timestamp clientmodel.Timestamp, view *viewAdapter) Vector {
lhs := node.lhs.Eval(timestamp, view) lhs := node.lhs.Eval(timestamp, view)
result := Vector{} result := Vector{}
@ -598,6 +669,8 @@ func (node *VectorArithExpr) Eval(timestamp clientmodel.Timestamp, view *viewAda
panic("Invalid vector arithmetic expression operands") panic("Invalid vector arithmetic expression operands")
} }
// Eval implements the MatrixNode interface and returns the value of
// the literal.
func (node *MatrixLiteral) Eval(timestamp clientmodel.Timestamp, view *viewAdapter) Matrix { func (node *MatrixLiteral) Eval(timestamp clientmodel.Timestamp, view *viewAdapter) Matrix {
interval := &metric.Interval{ interval := &metric.Interval{
OldestInclusive: timestamp.Add(-node.interval), OldestInclusive: timestamp.Add(-node.interval),
@ -611,6 +684,8 @@ func (node *MatrixLiteral) Eval(timestamp clientmodel.Timestamp, view *viewAdapt
return values return values
} }
// EvalBoundaries implements the MatrixNode interface and returns the
// boundary values of the literal.
func (node *MatrixLiteral) EvalBoundaries(timestamp clientmodel.Timestamp, view *viewAdapter) Matrix { func (node *MatrixLiteral) EvalBoundaries(timestamp clientmodel.Timestamp, view *viewAdapter) Matrix {
interval := &metric.Interval{ interval := &metric.Interval{
OldestInclusive: timestamp.Add(-node.interval), OldestInclusive: timestamp.Add(-node.interval),
@ -624,22 +699,29 @@ func (node *MatrixLiteral) EvalBoundaries(timestamp clientmodel.Timestamp, view
return values return values
} }
// Len implements sort.Interface.
func (matrix Matrix) Len() int { func (matrix Matrix) Len() int {
return len(matrix) return len(matrix)
} }
// Less implements sort.Interface.
func (matrix Matrix) Less(i, j int) bool { func (matrix Matrix) Less(i, j int) bool {
return matrix[i].Metric.String() < matrix[j].Metric.String() return matrix[i].Metric.String() < matrix[j].Metric.String()
} }
// Swap implements sort.Interface.
func (matrix Matrix) Swap(i, j int) { func (matrix Matrix) Swap(i, j int) {
matrix[i], matrix[j] = matrix[j], matrix[i] matrix[i], matrix[j] = matrix[j], matrix[i]
} }
// Eval implements the StringNode interface and returns the value of
// the literal.
func (node *StringLiteral) Eval(timestamp clientmodel.Timestamp, view *viewAdapter) string { func (node *StringLiteral) Eval(timestamp clientmodel.Timestamp, view *viewAdapter) string {
return node.str return node.str
} }
// Eval implements the StringNode interface and returns the result of
// the function call.
func (node *StringFunctionCall) Eval(timestamp clientmodel.Timestamp, view *viewAdapter) string { func (node *StringFunctionCall) Eval(timestamp clientmodel.Timestamp, view *viewAdapter) string {
return node.function.callFn(timestamp, view, node.args).(string) return node.function.callFn(timestamp, view, node.args).(string)
} }
@ -647,18 +729,24 @@ func (node *StringFunctionCall) Eval(timestamp clientmodel.Timestamp, view *view
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Constructors. // Constructors.
// NewScalarLiteral returns a ScalarLiteral with the given value.
func NewScalarLiteral(value clientmodel.SampleValue) *ScalarLiteral { func NewScalarLiteral(value clientmodel.SampleValue) *ScalarLiteral {
return &ScalarLiteral{ return &ScalarLiteral{
value: value, value: value,
} }
} }
// NewVectorLiteral returns a (not yet evaluated) VectorLiteral with
// the given LabelSet.
func NewVectorLiteral(labels clientmodel.LabelSet) *VectorLiteral { func NewVectorLiteral(labels clientmodel.LabelSet) *VectorLiteral {
return &VectorLiteral{ return &VectorLiteral{
labels: labels, labels: labels,
} }
} }
// NewVectorAggregation returns a (not yet evaluated)
// VectorAggregation, aggregating the given VectorNode using the given
// AggrType, grouping by the given LabelNames.
func NewVectorAggregation(aggrType AggrType, vector VectorNode, groupBy clientmodel.LabelNames, keepExtraLabels bool) *VectorAggregation { func NewVectorAggregation(aggrType AggrType, vector VectorNode, groupBy clientmodel.LabelNames, keepExtraLabels bool) *VectorAggregation {
return &VectorAggregation{ return &VectorAggregation{
aggrType: aggrType, aggrType: aggrType,
@ -668,6 +756,9 @@ func NewVectorAggregation(aggrType AggrType, vector VectorNode, groupBy clientmo
} }
} }
// NewFunctionCall returns a (not yet evaluated) function call node
// (of type ScalarFunctionCall, VectorFunctionCall, or
// StringFunctionCall).
func NewFunctionCall(function *Function, args Nodes) (Node, error) { func NewFunctionCall(function *Function, args Nodes) (Node, error) {
if err := function.CheckArgTypes(args); err != nil { if err := function.CheckArgTypes(args); err != nil {
return nil, err return nil, err
@ -707,12 +798,14 @@ func nodesHaveTypes(nodes Nodes, exprTypes []ExprType) bool {
return true return true
} }
// NewArithExpr returns a (not yet evaluated) expression node (of type
// VectorArithExpr or ScalarArithExpr).
func NewArithExpr(opType BinOpType, lhs Node, rhs Node) (Node, error) { func NewArithExpr(opType BinOpType, lhs Node, rhs Node) (Node, error) {
if !nodesHaveTypes(Nodes{lhs, rhs}, []ExprType{SCALAR, VECTOR}) { if !nodesHaveTypes(Nodes{lhs, rhs}, []ExprType{SCALAR, VECTOR}) {
return nil, errors.New("Binary operands must be of vector or scalar type") return nil, errors.New("binary operands must be of vector or scalar type")
} }
if lhs.Type() == SCALAR && rhs.Type() == VECTOR { if lhs.Type() == SCALAR && rhs.Type() == VECTOR {
return nil, errors.New("Left side of vector binary operation must be of vector type") return nil, errors.New("left side of vector binary operation must be of vector type")
} }
if opType == AND || opType == OR { if opType == AND || opType == OR {
@ -736,6 +829,8 @@ func NewArithExpr(opType BinOpType, lhs Node, rhs Node) (Node, error) {
}, nil }, nil
} }
// NewMatrixLiteral returns a (not yet evaluated) MatrixLiteral with
// the given VectorLiteral and Duration.
func NewMatrixLiteral(vector *VectorLiteral, interval time.Duration) *MatrixLiteral { func NewMatrixLiteral(vector *VectorLiteral, interval time.Duration) *MatrixLiteral {
return &MatrixLiteral{ return &MatrixLiteral{
labels: vector.labels, labels: vector.labels,
@ -743,6 +838,8 @@ func NewMatrixLiteral(vector *VectorLiteral, interval time.Duration) *MatrixLite
} }
} }
// NewStringLiteral returns a StringLiteral with the given string as
// value.
func NewStringLiteral(str string) *StringLiteral { func NewStringLiteral(str string) *StringLiteral {
return &StringLiteral{ return &StringLiteral{
str: str, str: str,

View file

@ -14,7 +14,6 @@
package ast package ast
import ( import (
"errors"
"fmt" "fmt"
"math" "math"
"sort" "sort"
@ -25,6 +24,8 @@ import (
"github.com/prometheus/prometheus/utility" "github.com/prometheus/prometheus/utility"
) )
// Function represents a function of the expression language and is
// used by function nodes.
type Function struct { type Function struct {
name string name string
argTypes []ExprType argTypes []ExprType
@ -32,11 +33,14 @@ type Function struct {
callFn func(timestamp clientmodel.Timestamp, view *viewAdapter, args []Node) interface{} callFn func(timestamp clientmodel.Timestamp, view *viewAdapter, args []Node) interface{}
} }
// CheckArgTypes returns a non-nil error if the number or types of
// passed in arg nodes do not match the function's expectations.
func (function *Function) CheckArgTypes(args []Node) error { func (function *Function) CheckArgTypes(args []Node) error {
if len(function.argTypes) != len(args) { if len(function.argTypes) != len(args) {
return errors.New( return fmt.Errorf(
fmt.Sprintf("Wrong number of arguments to function %v(): %v expected, %v given", "wrong number of arguments to function %v(): %v expected, %v given",
function.name, len(function.argTypes), len(args))) function.name, len(function.argTypes), len(args),
)
} }
for idx, argType := range function.argTypes { for idx, argType := range function.argTypes {
invalidType := false invalidType := false
@ -59,9 +63,10 @@ func (function *Function) CheckArgTypes(args []Node) error {
} }
if invalidType { if invalidType {
return errors.New( return fmt.Errorf(
fmt.Sprintf("Wrong type for argument %v in function %v(), expected %v", "wrong type for argument %v in function %v(), expected %v",
idx, function.name, expectedType)) idx, function.name, expectedType,
)
} }
} }
return nil return nil
@ -175,7 +180,7 @@ func sortImpl(timestamp clientmodel.Timestamp, view *viewAdapter, args []Node) i
// === sortDesc(node *VectorNode) Vector === // === sortDesc(node *VectorNode) Vector ===
func sortDescImpl(timestamp clientmodel.Timestamp, view *viewAdapter, args []Node) interface{} { func sortDescImpl(timestamp clientmodel.Timestamp, view *viewAdapter, args []Node) interface{} {
descByValueSorter := utility.ReverseSorter{ descByValueSorter := utility.ReverseSorter{
vectorByValueSorter{ Interface: vectorByValueSorter{
vector: args[0].(VectorNode).Eval(timestamp, view), vector: args[0].(VectorNode).Eval(timestamp, view),
}, },
} }
@ -321,10 +326,12 @@ var functions = map[string]*Function{
}, },
} }
// GetFunction returns a predefined Function object for the given
// name.
func GetFunction(name string) (*Function, error) { func GetFunction(name string) (*Function, error) {
function, ok := functions[name] function, ok := functions[name]
if !ok { if !ok {
return nil, errors.New(fmt.Sprintf("Couldn't find function %v()", name)) return nil, fmt.Errorf("couldn't find function %v()", name)
} }
return function, nil return function, nil
} }

View file

@ -25,7 +25,8 @@ import (
var defaultStalenessDelta = flag.Int("defaultStalenessDelta", 300, "Default staleness delta allowance in seconds during expression evaluations.") var defaultStalenessDelta = flag.Int("defaultStalenessDelta", 300, "Default staleness delta allowance in seconds during expression evaluations.")
// Describes the lenience limits to apply to values from the materialized view. // StalenessPolicy describes the lenience limits to apply to values
// from the materialized view.
type StalenessPolicy struct { type StalenessPolicy struct {
// Describes the inclusive limit at which individual points if requested will // Describes the inclusive limit at which individual points if requested will
// be matched and subject to interpolation. // be matched and subject to interpolation.
@ -181,6 +182,8 @@ func (v *viewAdapter) GetRangeValues(fingerprints clientmodel.Fingerprints, inte
return sampleSets, nil return sampleSets, nil
} }
// NewViewAdapter returns an initialized view adapter with a default
// staleness policy (based on the --defaultStalenessDelta flag).
func NewViewAdapter(view metric.View, storage *metric.TieredStorage, queryStats *stats.TimerGroup) *viewAdapter { func NewViewAdapter(view metric.View, storage *metric.TieredStorage, queryStats *stats.TimerGroup) *viewAdapter {
stalenessPolicy := StalenessPolicy{ stalenessPolicy := StalenessPolicy{
DeltaAllowance: time.Duration(*defaultStalenessDelta) * time.Second, DeltaAllowance: time.Duration(*defaultStalenessDelta) * time.Second,

View file

@ -26,8 +26,10 @@ import (
"github.com/prometheus/prometheus/utility" "github.com/prometheus/prometheus/utility"
) )
// OutputFormat is an enum for the possible output formats.
type OutputFormat int type OutputFormat int
// Possible output formats.
const ( const (
TEXT OutputFormat = iota TEXT OutputFormat = iota
JSON JSON
@ -113,6 +115,7 @@ func (matrix Matrix) String() string {
return strings.Join(metricStrings, "\n") return strings.Join(metricStrings, "\n")
} }
// ErrorToJSON converts the given error into JSON.
func ErrorToJSON(err error) string { func ErrorToJSON(err error) string {
errorStruct := struct { errorStruct := struct {
Type string Type string
@ -129,6 +132,8 @@ func ErrorToJSON(err error) string {
return string(errorJSON) return string(errorJSON)
} }
// TypedValueToJSON converts the given data of type 'scalar',
// 'vector', or 'matrix' into its JSON representation.
func TypedValueToJSON(data interface{}, typeStr string) string { func TypedValueToJSON(data interface{}, typeStr string) string {
dataStruct := struct { dataStruct := struct {
Type string Type string
@ -144,6 +149,7 @@ func TypedValueToJSON(data interface{}, typeStr string) string {
return string(dataJSON) return string(dataJSON)
} }
// EvalToString evaluates the given node into a string of the given format.
func EvalToString(node Node, timestamp clientmodel.Timestamp, format OutputFormat, storage *metric.TieredStorage, queryStats *stats.TimerGroup) string { func EvalToString(node Node, timestamp clientmodel.Timestamp, format OutputFormat, storage *metric.TieredStorage, queryStats *stats.TimerGroup) string {
viewTimer := queryStats.GetTimer(stats.TotalViewBuildingTime).Start() viewTimer := queryStats.GetTimer(stats.TotalViewBuildingTime).Start()
viewAdapter, err := viewAdapterForInstantQuery(node, timestamp, storage, queryStats) viewAdapter, err := viewAdapterForInstantQuery(node, timestamp, storage, queryStats)
@ -194,6 +200,8 @@ func EvalToString(node Node, timestamp clientmodel.Timestamp, format OutputForma
panic("Switch didn't cover all node types") panic("Switch didn't cover all node types")
} }
// NodeTreeToDotGraph returns a DOT representation of the scalar
// literal.
func (node *ScalarLiteral) NodeTreeToDotGraph() string { func (node *ScalarLiteral) NodeTreeToDotGraph() string {
return fmt.Sprintf("%#p[label=\"%v\"];\n", node, node.value) return fmt.Sprintf("%#p[label=\"%v\"];\n", node, node.value)
} }
@ -209,12 +217,15 @@ func functionArgsToDotGraph(node Node, args []Node) string {
return graph return graph
} }
// NodeTreeToDotGraph returns a DOT representation of the function
// call.
func (node *ScalarFunctionCall) NodeTreeToDotGraph() string { func (node *ScalarFunctionCall) NodeTreeToDotGraph() string {
graph := fmt.Sprintf("%#p[label=\"%s\"];\n", node, node.function.name) graph := fmt.Sprintf("%#p[label=\"%s\"];\n", node, node.function.name)
graph += functionArgsToDotGraph(node, node.args) graph += functionArgsToDotGraph(node, node.args)
return graph return graph
} }
// NodeTreeToDotGraph returns a DOT representation of the expression.
func (node *ScalarArithExpr) NodeTreeToDotGraph() string { func (node *ScalarArithExpr) NodeTreeToDotGraph() string {
graph := fmt.Sprintf(` graph := fmt.Sprintf(`
%#p[label="%s"]; %#p[label="%s"];
@ -226,16 +237,21 @@ func (node *ScalarArithExpr) NodeTreeToDotGraph() string {
return graph return graph
} }
// NodeTreeToDotGraph returns a DOT representation of the vector literal.
func (node *VectorLiteral) NodeTreeToDotGraph() string { func (node *VectorLiteral) NodeTreeToDotGraph() string {
return fmt.Sprintf("%#p[label=\"%s\"];\n", node, node) return fmt.Sprintf("%#p[label=\"%s\"];\n", node, node)
} }
// NodeTreeToDotGraph returns a DOT representation of the function
// call.
func (node *VectorFunctionCall) NodeTreeToDotGraph() string { func (node *VectorFunctionCall) NodeTreeToDotGraph() string {
graph := fmt.Sprintf("%#p[label=\"%s\"];\n", node, node.function.name) graph := fmt.Sprintf("%#p[label=\"%s\"];\n", node, node.function.name)
graph += functionArgsToDotGraph(node, node.args) graph += functionArgsToDotGraph(node, node.args)
return graph return graph
} }
// NodeTreeToDotGraph returns a DOT representation of the vector
// aggregation.
func (node *VectorAggregation) NodeTreeToDotGraph() string { func (node *VectorAggregation) NodeTreeToDotGraph() string {
groupByStrings := make([]string, 0, len(node.groupBy)) groupByStrings := make([]string, 0, len(node.groupBy))
for _, label := range node.groupBy { for _, label := range node.groupBy {
@ -251,6 +267,7 @@ func (node *VectorAggregation) NodeTreeToDotGraph() string {
return graph return graph
} }
// NodeTreeToDotGraph returns a DOT representation of the expression.
func (node *VectorArithExpr) NodeTreeToDotGraph() string { func (node *VectorArithExpr) NodeTreeToDotGraph() string {
graph := fmt.Sprintf(` graph := fmt.Sprintf(`
%#p[label="%s"]; %#p[label="%s"];
@ -262,14 +279,20 @@ func (node *VectorArithExpr) NodeTreeToDotGraph() string {
return graph return graph
} }
// NodeTreeToDotGraph returns a DOT representation of the matrix
// literal.
func (node *MatrixLiteral) NodeTreeToDotGraph() string { func (node *MatrixLiteral) NodeTreeToDotGraph() string {
return fmt.Sprintf("%#p[label=\"%s\"];\n", node, node) return fmt.Sprintf("%#p[label=\"%s\"];\n", node, node)
} }
// NodeTreeToDotGraph returns a DOT representation of the string
// literal.
func (node *StringLiteral) NodeTreeToDotGraph() string { func (node *StringLiteral) NodeTreeToDotGraph() string {
return fmt.Sprintf("%#p[label=\"'%q'\"];\n", node, node.str) return fmt.Sprintf("%#p[label=\"'%q'\"];\n", node, node.str)
} }
// NodeTreeToDotGraph returns a DOT representation of the function
// call.
func (node *StringFunctionCall) NodeTreeToDotGraph() string { func (node *StringFunctionCall) NodeTreeToDotGraph() string {
graph := fmt.Sprintf("%#p[label=\"%s\"];\n", node, node.function.name) graph := fmt.Sprintf("%#p[label=\"%s\"];\n", node, node.function.name)
graph += functionArgsToDotGraph(node, node.args) graph += functionArgsToDotGraph(node, node.args)
@ -325,9 +348,8 @@ func (node *VectorAggregation) String() string {
aggrString := fmt.Sprintf("%s(%s)", node.aggrType, node.vector) aggrString := fmt.Sprintf("%s(%s)", node.aggrType, node.vector)
if len(node.groupBy) > 0 { if len(node.groupBy) > 0 {
return fmt.Sprintf("%s BY (%s)", aggrString, node.groupBy) return fmt.Sprintf("%s BY (%s)", aggrString, node.groupBy)
} else {
return aggrString
} }
return aggrString
} }
func (node *VectorArithExpr) String() string { func (node *VectorArithExpr) String() string {

View file

@ -24,9 +24,16 @@ import (
"github.com/prometheus/prometheus/storage/metric" "github.com/prometheus/prometheus/storage/metric"
) )
// FullRangeMap maps the fingerprint of a full range to the duration
// of the matrix literal it resulted from.
type FullRangeMap map[clientmodel.Fingerprint]time.Duration type FullRangeMap map[clientmodel.Fingerprint]time.Duration
// IntervalRangeMap is a set of fingerprints of interval ranges.
type IntervalRangeMap map[clientmodel.Fingerprint]bool type IntervalRangeMap map[clientmodel.Fingerprint]bool
// A QueryAnalyzer recursively traverses the AST to look for any nodes
// which will need data from the datastore. Instantiate with
// NewQueryAnalyzer.
type QueryAnalyzer struct { type QueryAnalyzer struct {
// Values collected by query analysis. // Values collected by query analysis.
// //
@ -37,13 +44,16 @@ type QueryAnalyzer struct {
// This is because full ranges can only result from matrix literals (like // This is because full ranges can only result from matrix literals (like
// "foo[5m]"), which have said time-spanning behavior during a ranged query. // "foo[5m]"), which have said time-spanning behavior during a ranged query.
FullRanges FullRangeMap FullRanges FullRangeMap
// Interval ranges always implicitly span the whole query interval. // Interval ranges always implicitly span the whole query range.
IntervalRanges IntervalRangeMap IntervalRanges IntervalRangeMap
// The underlying storage to which the query will be applied. Needed for // The underlying storage to which the query will be applied. Needed for
// extracting timeseries fingerprint information during query analysis. // extracting timeseries fingerprint information during query analysis.
storage *metric.TieredStorage storage *metric.TieredStorage
} }
// NewQueryAnalyzer returns a pointer to a newly instantiated
// QueryAnalyzer. The storage is needed to extract timeseries
// fingerprint information during query analysis.
func NewQueryAnalyzer(storage *metric.TieredStorage) *QueryAnalyzer { func NewQueryAnalyzer(storage *metric.TieredStorage) *QueryAnalyzer {
return &QueryAnalyzer{ return &QueryAnalyzer{
FullRanges: FullRangeMap{}, FullRanges: FullRangeMap{},
@ -52,6 +62,7 @@ func NewQueryAnalyzer(storage *metric.TieredStorage) *QueryAnalyzer {
} }
} }
// Visit implements the Visitor interface.
func (analyzer *QueryAnalyzer) Visit(node Node) { func (analyzer *QueryAnalyzer) Visit(node Node) {
switch n := node.(type) { switch n := node.(type) {
case *VectorLiteral: case *VectorLiteral:
@ -79,6 +90,8 @@ func (analyzer *QueryAnalyzer) Visit(node Node) {
} }
} }
// AnalyzeQueries walks the AST, starting at node, calling Visit on
// each node to collect fingerprints.
func (analyzer *QueryAnalyzer) AnalyzeQueries(node Node) { func (analyzer *QueryAnalyzer) AnalyzeQueries(node Node) {
Walk(analyzer, node) Walk(analyzer, node)
// Find and dedupe overlaps between full and stepped ranges. Full ranges // Find and dedupe overlaps between full and stepped ranges. Full ranges

View file

@ -13,12 +13,13 @@
package ast package ast
// Visitor is the interface for a Node visitor.
type Visitor interface { type Visitor interface {
Visit(node Node) Visit(node Node)
} }
// Walk() does a depth-first traversal of the AST, calling visitor.Visit() for // Walk does a depth-first traversal of the AST, starting at node,
// each encountered node in the tree. // calling visitor.Visit for each encountered Node in the tree.
func Walk(visitor Visitor, node Node) { func Walk(visitor Visitor, node Node) {
visitor.Visit(node) visitor.Visit(node)
for _, childNode := range node.Children() { for _, childNode := range node.Children() {