Depointerize Matrix/Vector types as well as time.Time arguments.

This commit is contained in:
Julius Volz 2013-03-28 17:05:06 +01:00
parent b912f75d11
commit ec413459fa
8 changed files with 65 additions and 65 deletions

View file

@ -95,7 +95,7 @@ func main() {
case ruleResult := <-ruleResults: case ruleResult := <-ruleResults:
for _, sample := range ruleResult.Samples { for _, sample := range ruleResult.Samples {
ts.AppendSample(*sample) ts.AppendSample(sample)
} }
} }
} }

View file

@ -27,8 +27,8 @@ import (
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Raw data value types. // Raw data value types.
type Vector []*model.Sample type Vector model.Samples
type Matrix []*model.SampleSet type Matrix []model.SampleSet
type groupedAggregation struct { type groupedAggregation struct {
labels model.Metric labels model.Metric
@ -97,23 +97,23 @@ type Node interface {
// interface represents the type returned to the parent node. // interface represents the type returned to the parent node.
type ScalarNode interface { type ScalarNode interface {
Node Node
Eval(timestamp *time.Time, view *viewAdapter) model.SampleValue Eval(timestamp time.Time, view *viewAdapter) model.SampleValue
} }
type VectorNode interface { type VectorNode interface {
Node Node
Eval(timestamp *time.Time, view *viewAdapter) Vector Eval(timestamp time.Time, view *viewAdapter) Vector
} }
type MatrixNode interface { type MatrixNode interface {
Node Node
Eval(timestamp *time.Time, view *viewAdapter) Matrix Eval(timestamp time.Time, view *viewAdapter) Matrix
EvalBoundaries(timestamp *time.Time, view *viewAdapter) Matrix EvalBoundaries(timestamp time.Time, view *viewAdapter) Matrix
} }
type StringNode interface { type StringNode interface {
Node Node
Eval(timestamp *time.Time, view *viewAdapter) string Eval(timestamp time.Time, view *viewAdapter) string
} }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@ -227,17 +227,17 @@ func (node MatrixLiteral) Children() []Node { return []Node{} }
func (node StringLiteral) Children() []Node { return []Node{} } func (node StringLiteral) Children() []Node { return []Node{} }
func (node StringFunctionCall) Children() []Node { return node.args } func (node StringFunctionCall) Children() []Node { return node.args }
func (node *ScalarLiteral) Eval(timestamp *time.Time, view *viewAdapter) model.SampleValue { func (node *ScalarLiteral) Eval(timestamp time.Time, view *viewAdapter) model.SampleValue {
return node.value return node.value
} }
func (node *ScalarArithExpr) Eval(timestamp *time.Time, view *viewAdapter) model.SampleValue { func (node *ScalarArithExpr) Eval(timestamp time.Time, view *viewAdapter) model.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)
} }
func (node *ScalarFunctionCall) Eval(timestamp *time.Time, view *viewAdapter) model.SampleValue { func (node *ScalarFunctionCall) Eval(timestamp time.Time, view *viewAdapter) model.SampleValue {
return node.function.callFn(timestamp, view, node.args).(model.SampleValue) return node.function.callFn(timestamp, view, node.args).(model.SampleValue)
} }
@ -263,7 +263,7 @@ func EvalVectorInstant(node VectorNode, timestamp time.Time) (vector Vector) {
if err != nil { if err != nil {
return return
} }
return node.Eval(&timestamp, viewAdapter) return node.Eval(timestamp, viewAdapter)
} }
func EvalVectorRange(node VectorNode, start time.Time, end time.Time, interval time.Duration) (matrix Matrix, err error) { func EvalVectorRange(node VectorNode, start time.Time, end time.Time, interval time.Duration) (matrix Matrix, err error) {
@ -278,7 +278,7 @@ func EvalVectorRange(node VectorNode, start time.Time, end time.Time, interval t
// TODO implement watchdog timer for long-running queries. // TODO implement watchdog timer for long-running queries.
sampleSets := map[string]*model.SampleSet{} sampleSets := map[string]*model.SampleSet{}
for t := start; t.Before(end); t = t.Add(interval) { for t := start; t.Before(end); t = t.Add(interval) {
vector := node.Eval(&t, viewAdapter) vector := node.Eval(t, viewAdapter)
for _, sample := range vector { for _, sample := range vector {
samplePair := model.SamplePair{ samplePair := model.SamplePair{
Value: sample.Value, Value: sample.Value,
@ -297,7 +297,7 @@ func EvalVectorRange(node VectorNode, start time.Time, end time.Time, interval t
} }
for _, sampleSet := range sampleSets { for _, sampleSet := range sampleSets {
matrix = append(matrix, sampleSet) matrix = append(matrix, *sampleSet)
} }
return return
} }
@ -312,23 +312,23 @@ func labelIntersection(metric1, metric2 model.Metric) model.Metric {
return intersection return intersection
} }
func (node *VectorAggregation) groupedAggregationsToVector(aggregations map[string]*groupedAggregation, timestamp *time.Time) Vector { func (node *VectorAggregation) groupedAggregationsToVector(aggregations map[string]*groupedAggregation, timestamp time.Time) Vector {
vector := Vector{} vector := Vector{}
for _, aggregation := range aggregations { for _, aggregation := range aggregations {
if node.aggrType == AVG { if node.aggrType == AVG {
aggregation.value = aggregation.value / model.SampleValue(aggregation.groupCount) aggregation.value = aggregation.value / model.SampleValue(aggregation.groupCount)
} }
sample := &model.Sample{ sample := model.Sample{
Metric: aggregation.labels, Metric: aggregation.labels,
Value: aggregation.value, Value: aggregation.value,
Timestamp: *timestamp, Timestamp: timestamp,
} }
vector = append(vector, sample) vector = append(vector, sample)
} }
return vector return vector
} }
func (node *VectorAggregation) Eval(timestamp *time.Time, view *viewAdapter) Vector { func (node *VectorAggregation) Eval(timestamp time.Time, view *viewAdapter) Vector {
vector := node.vector.Eval(timestamp, view) vector := node.vector.Eval(timestamp, view)
result := map[string]*groupedAggregation{} result := map[string]*groupedAggregation{}
for _, sample := range vector { for _, sample := range vector {
@ -361,7 +361,7 @@ func (node *VectorAggregation) Eval(timestamp *time.Time, view *viewAdapter) Vec
return node.groupedAggregationsToVector(result, timestamp) return node.groupedAggregationsToVector(result, timestamp)
} }
func (node *VectorLiteral) Eval(timestamp *time.Time, view *viewAdapter) Vector { func (node *VectorLiteral) Eval(timestamp time.Time, view *viewAdapter) Vector {
values, err := view.GetValueAtTime(node.fingerprints, timestamp) values, err := view.GetValueAtTime(node.fingerprints, timestamp)
if err != nil { if err != nil {
log.Printf("Unable to get vector values") log.Printf("Unable to get vector values")
@ -370,7 +370,7 @@ func (node *VectorLiteral) Eval(timestamp *time.Time, view *viewAdapter) Vector
return values return values
} }
func (node *VectorFunctionCall) Eval(timestamp *time.Time, view *viewAdapter) Vector { func (node *VectorFunctionCall) Eval(timestamp time.Time, view *viewAdapter) Vector {
return node.function.callFn(timestamp, view, node.args).(Vector) return node.function.callFn(timestamp, view, node.args).(Vector)
} }
@ -514,7 +514,7 @@ func labelsEqual(labels1, labels2 model.Metric) bool {
return true return true
} }
func (node *VectorArithExpr) Eval(timestamp *time.Time, view *viewAdapter) Vector { func (node *VectorArithExpr) Eval(timestamp time.Time, view *viewAdapter) Vector {
lhs := node.lhs.Eval(timestamp, view) lhs := node.lhs.Eval(timestamp, view)
result := Vector{} result := Vector{}
if node.rhs.Type() == SCALAR { if node.rhs.Type() == SCALAR {
@ -545,10 +545,10 @@ func (node *VectorArithExpr) Eval(timestamp *time.Time, view *viewAdapter) Vecto
panic("Invalid vector arithmetic expression operands") panic("Invalid vector arithmetic expression operands")
} }
func (node *MatrixLiteral) Eval(timestamp *time.Time, view *viewAdapter) Matrix { func (node *MatrixLiteral) Eval(timestamp time.Time, view *viewAdapter) Matrix {
interval := &model.Interval{ interval := &model.Interval{
OldestInclusive: timestamp.Add(-node.interval), OldestInclusive: timestamp.Add(-node.interval),
NewestInclusive: *timestamp, NewestInclusive: timestamp,
} }
values, err := view.GetRangeValues(node.fingerprints, interval) values, err := view.GetRangeValues(node.fingerprints, interval)
if err != nil { if err != nil {
@ -558,10 +558,10 @@ func (node *MatrixLiteral) Eval(timestamp *time.Time, view *viewAdapter) Matrix
return values return values
} }
func (node *MatrixLiteral) EvalBoundaries(timestamp *time.Time, view *viewAdapter) Matrix { func (node *MatrixLiteral) EvalBoundaries(timestamp time.Time, view *viewAdapter) Matrix {
interval := &model.Interval{ interval := &model.Interval{
OldestInclusive: timestamp.Add(-node.interval), OldestInclusive: timestamp.Add(-node.interval),
NewestInclusive: *timestamp, NewestInclusive: timestamp,
} }
values, err := view.GetBoundaryValues(node.fingerprints, interval) values, err := view.GetBoundaryValues(node.fingerprints, interval)
if err != nil { if err != nil {
@ -583,11 +583,11 @@ func (matrix Matrix) Swap(i, j int) {
matrix[i], matrix[j] = matrix[j], matrix[i] matrix[i], matrix[j] = matrix[j], matrix[i]
} }
func (node *StringLiteral) Eval(timestamp *time.Time, view *viewAdapter) string { func (node *StringLiteral) Eval(timestamp time.Time, view *viewAdapter) string {
return node.str return node.str
} }
func (node *StringFunctionCall) Eval(timestamp *time.Time, view *viewAdapter) string { func (node *StringFunctionCall) Eval(timestamp time.Time, view *viewAdapter) string {
return node.function.callFn(timestamp, view, node.args).(string) return node.function.callFn(timestamp, view, node.args).(string)
} }

View file

@ -24,7 +24,7 @@ type Function struct {
name string name string
argTypes []ExprType argTypes []ExprType
returnType ExprType returnType ExprType
callFn func(timestamp *time.Time, view *viewAdapter, args []Node) interface{} callFn func(timestamp time.Time, view *viewAdapter, args []Node) interface{}
} }
func (function *Function) CheckArgTypes(args []Node) error { func (function *Function) CheckArgTypes(args []Node) error {
@ -63,17 +63,17 @@ func (function *Function) CheckArgTypes(args []Node) error {
} }
// === time() === // === time() ===
func timeImpl(timestamp *time.Time, view *viewAdapter, args []Node) interface{} { func timeImpl(timestamp time.Time, view *viewAdapter, args []Node) interface{} {
return model.SampleValue(time.Now().Unix()) return model.SampleValue(time.Now().Unix())
} }
// === count(vector VectorNode) === // === count(vector VectorNode) ===
func countImpl(timestamp *time.Time, view *viewAdapter, args []Node) interface{} { func countImpl(timestamp time.Time, view *viewAdapter, args []Node) interface{} {
return model.SampleValue(len(args[0].(VectorNode).Eval(timestamp, view))) return model.SampleValue(len(args[0].(VectorNode).Eval(timestamp, view)))
} }
// === delta(matrix MatrixNode, isCounter ScalarNode) === // === delta(matrix MatrixNode, isCounter ScalarNode) ===
func deltaImpl(timestamp *time.Time, view *viewAdapter, args []Node) interface{} { func deltaImpl(timestamp time.Time, view *viewAdapter, args []Node) interface{} {
matrixNode := args[0].(MatrixNode) matrixNode := args[0].(MatrixNode)
isCounter := int(args[1].(ScalarNode).Eval(timestamp, view)) isCounter := int(args[1].(ScalarNode).Eval(timestamp, view))
resultVector := Vector{} resultVector := Vector{}
@ -98,10 +98,10 @@ func deltaImpl(timestamp *time.Time, view *viewAdapter, args []Node) interface{}
lastValue = currentValue lastValue = currentValue
} }
resultValue := lastValue - samples.Values[0].Value + counterCorrection resultValue := lastValue - samples.Values[0].Value + counterCorrection
resultSample := &model.Sample{ resultSample := model.Sample{
Metric: samples.Metric, Metric: samples.Metric,
Value: resultValue, Value: resultValue,
Timestamp: *timestamp, Timestamp: timestamp,
} }
resultVector = append(resultVector, resultSample) resultVector = append(resultVector, resultSample)
} }
@ -109,7 +109,7 @@ func deltaImpl(timestamp *time.Time, view *viewAdapter, args []Node) interface{}
} }
// === rate(node *MatrixNode) === // === rate(node *MatrixNode) ===
func rateImpl(timestamp *time.Time, view *viewAdapter, args []Node) interface{} { func rateImpl(timestamp time.Time, view *viewAdapter, args []Node) interface{} {
args = append(args, &ScalarLiteral{value: 1}) args = append(args, &ScalarLiteral{value: 1})
vector := deltaImpl(timestamp, view, args).(Vector) vector := deltaImpl(timestamp, view, args).(Vector)
@ -124,36 +124,36 @@ func rateImpl(timestamp *time.Time, view *viewAdapter, args []Node) interface{}
} }
// === sampleVectorImpl() === // === sampleVectorImpl() ===
func sampleVectorImpl(timestamp *time.Time, view *viewAdapter, args []Node) interface{} { func sampleVectorImpl(timestamp time.Time, view *viewAdapter, args []Node) interface{} {
return Vector{ return Vector{
&model.Sample{ model.Sample{
Metric: model.Metric{ Metric: model.Metric{
model.MetricNameLabel: "http_requests", model.MetricNameLabel: "http_requests",
"job": "api-server", "job": "api-server",
"instance": "0", "instance": "0",
}, },
Value: 10, Value: 10,
Timestamp: *timestamp, Timestamp: timestamp,
}, },
&model.Sample{ model.Sample{
Metric: model.Metric{ Metric: model.Metric{
model.MetricNameLabel: "http_requests", model.MetricNameLabel: "http_requests",
"job": "api-server", "job": "api-server",
"instance": "1", "instance": "1",
}, },
Value: 20, Value: 20,
Timestamp: *timestamp, Timestamp: timestamp,
}, },
&model.Sample{ model.Sample{
Metric: model.Metric{ Metric: model.Metric{
model.MetricNameLabel: "http_requests", model.MetricNameLabel: "http_requests",
"job": "api-server", "job": "api-server",
"instance": "2", "instance": "2",
}, },
Value: 30, Value: 30,
Timestamp: *timestamp, Timestamp: timestamp,
}, },
&model.Sample{ model.Sample{
Metric: model.Metric{ Metric: model.Metric{
model.MetricNameLabel: "http_requests", model.MetricNameLabel: "http_requests",
"job": "api-server", "job": "api-server",
@ -161,9 +161,9 @@ func sampleVectorImpl(timestamp *time.Time, view *viewAdapter, args []Node) inte
"group": "canary", "group": "canary",
}, },
Value: 40, Value: 40,
Timestamp: *timestamp, Timestamp: timestamp,
}, },
&model.Sample{ model.Sample{
Metric: model.Metric{ Metric: model.Metric{
model.MetricNameLabel: "http_requests", model.MetricNameLabel: "http_requests",
"job": "api-server", "job": "api-server",
@ -171,9 +171,9 @@ func sampleVectorImpl(timestamp *time.Time, view *viewAdapter, args []Node) inte
"group": "canary", "group": "canary",
}, },
Value: 40, Value: 40,
Timestamp: *timestamp, Timestamp: timestamp,
}, },
&model.Sample{ model.Sample{
Metric: model.Metric{ Metric: model.Metric{
model.MetricNameLabel: "http_requests", model.MetricNameLabel: "http_requests",
"job": "api-server", "job": "api-server",
@ -181,9 +181,9 @@ func sampleVectorImpl(timestamp *time.Time, view *viewAdapter, args []Node) inte
"group": "mytest", "group": "mytest",
}, },
Value: 40, Value: 40,
Timestamp: *timestamp, Timestamp: timestamp,
}, },
&model.Sample{ model.Sample{
Metric: model.Metric{ Metric: model.Metric{
model.MetricNameLabel: "http_requests", model.MetricNameLabel: "http_requests",
"job": "api-server", "job": "api-server",
@ -191,7 +191,7 @@ func sampleVectorImpl(timestamp *time.Time, view *viewAdapter, args []Node) inte
"group": "mytest", "group": "mytest",
}, },
Value: 40, Value: 40,
Timestamp: *timestamp, Timestamp: timestamp,
}, },
} }
} }

View file

@ -50,11 +50,11 @@ func interpolateSamples(first, second *model.SamplePair, timestamp time.Time) *m
// surrounding a given target time. If samples are found both before and after // surrounding a given target time. If samples are found both before and after
// the target time, the sample value is interpolated between these. Otherwise, // the target time, the sample value is interpolated between these. Otherwise,
// the single closest sample is returned verbatim. // the single closest sample is returned verbatim.
func (v *viewAdapter) chooseClosestSample(samples []model.SamplePair, timestamp *time.Time) (sample *model.SamplePair) { func (v *viewAdapter) chooseClosestSample(samples []model.SamplePair, timestamp time.Time) (sample *model.SamplePair) {
var closestBefore *model.SamplePair var closestBefore *model.SamplePair
var closestAfter *model.SamplePair var closestAfter *model.SamplePair
for _, candidate := range samples { for _, candidate := range samples {
delta := candidate.Timestamp.Sub(*timestamp) delta := candidate.Timestamp.Sub(timestamp)
// Samples before target time. // Samples before target time.
if delta < 0 { if delta < 0 {
// Ignore samples outside of staleness policy window. // Ignore samples outside of staleness policy window.
@ -86,7 +86,7 @@ func (v *viewAdapter) chooseClosestSample(samples []model.SamplePair, timestamp
switch { switch {
case closestBefore != nil && closestAfter != nil: case closestBefore != nil && closestAfter != nil:
sample = interpolateSamples(closestBefore, closestAfter, *timestamp) sample = interpolateSamples(closestBefore, closestAfter, timestamp)
case closestBefore != nil: case closestBefore != nil:
sample = closestBefore sample = closestBefore
default: default:
@ -96,26 +96,26 @@ func (v *viewAdapter) chooseClosestSample(samples []model.SamplePair, timestamp
return return
} }
func (v *viewAdapter) GetValueAtTime(fingerprints model.Fingerprints, timestamp *time.Time) (samples []*model.Sample, err error) { func (v *viewAdapter) GetValueAtTime(fingerprints model.Fingerprints, timestamp time.Time) (samples Vector, err error) {
for _, fingerprint := range fingerprints { for _, fingerprint := range fingerprints {
sampleCandidates := v.view.GetValueAtTime(fingerprint, *timestamp) sampleCandidates := v.view.GetValueAtTime(fingerprint, timestamp)
samplePair := v.chooseClosestSample(sampleCandidates, timestamp) samplePair := v.chooseClosestSample(sampleCandidates, timestamp)
m, err := queryStorage.GetMetricForFingerprint(fingerprint) m, err := queryStorage.GetMetricForFingerprint(fingerprint)
if err != nil { if err != nil {
continue continue
} }
if samplePair != nil { if samplePair != nil {
samples = append(samples, &model.Sample{ samples = append(samples, model.Sample{
Metric: *m, Metric: *m,
Value: samplePair.Value, Value: samplePair.Value,
Timestamp: *timestamp, Timestamp: timestamp,
}) })
} }
} }
return return
} }
func (v *viewAdapter) GetBoundaryValues(fingerprints model.Fingerprints, interval *model.Interval) (sampleSets []*model.SampleSet, err error) { func (v *viewAdapter) GetBoundaryValues(fingerprints model.Fingerprints, interval *model.Interval) (sampleSets []model.SampleSet, err error) {
for _, fingerprint := range fingerprints { for _, fingerprint := range fingerprints {
// TODO: change to GetBoundaryValues() once it has the right return type. // TODO: change to GetBoundaryValues() once it has the right return type.
samplePairs := v.view.GetRangeValues(fingerprint, *interval) samplePairs := v.view.GetRangeValues(fingerprint, *interval)
@ -129,7 +129,7 @@ func (v *viewAdapter) GetBoundaryValues(fingerprints model.Fingerprints, interva
continue continue
} }
sampleSet := &model.SampleSet{ sampleSet := model.SampleSet{
Metric: *m, Metric: *m,
Values: samplePairs, Values: samplePairs,
} }
@ -138,7 +138,7 @@ func (v *viewAdapter) GetBoundaryValues(fingerprints model.Fingerprints, interva
return sampleSets, nil return sampleSets, nil
} }
func (v *viewAdapter) GetRangeValues(fingerprints model.Fingerprints, interval *model.Interval) (sampleSets []*model.SampleSet, err error) { func (v *viewAdapter) GetRangeValues(fingerprints model.Fingerprints, interval *model.Interval) (sampleSets []model.SampleSet, err error) {
for _, fingerprint := range fingerprints { for _, fingerprint := range fingerprints {
samplePairs := v.view.GetRangeValues(fingerprint, *interval) samplePairs := v.view.GetRangeValues(fingerprint, *interval)
if samplePairs == nil { if samplePairs == nil {
@ -151,7 +151,7 @@ func (v *viewAdapter) GetRangeValues(fingerprints model.Fingerprints, interval *
continue continue
} }
sampleSet := &model.SampleSet{ sampleSet := model.SampleSet{
Metric: *m, Metric: *m,
Values: samplePairs, Values: samplePairs,
} }

View file

@ -152,8 +152,8 @@ func TypedValueToJSON(data interface{}, typeStr string) string {
return string(dataJSON) return string(dataJSON)
} }
func EvalToString(node Node, timestamp *time.Time, format OutputFormat) string { func EvalToString(node Node, timestamp time.Time, format OutputFormat) string {
viewAdapter, err := viewAdapterForInstantQuery(node, *timestamp) viewAdapter, err := viewAdapterForInstantQuery(node, timestamp)
if err != nil { if err != nil {
panic(err) panic(err)
} }

View file

@ -241,7 +241,7 @@ func TestExpressions(t *testing.T) {
t.Errorf("Test should fail, but didn't") t.Errorf("Test should fail, but didn't")
} }
failed := false failed := false
resultStr := ast.EvalToString(testExpr, &testEvalTime, ast.TEXT) resultStr := ast.EvalToString(testExpr, testEvalTime, ast.TEXT)
resultLines := strings.Split(resultStr, "\n") resultLines := strings.Split(resultStr, "\n")
if len(exprTest.output) != len(resultLines) { if len(exprTest.output) != len(resultLines) {

View file

@ -42,7 +42,7 @@ func getTestVectorFromTestMatrix(matrix ast.Matrix) ast.Vector {
vector := ast.Vector{} vector := ast.Vector{}
for _, sampleSet := range matrix { for _, sampleSet := range matrix {
lastSample := sampleSet.Values[len(sampleSet.Values)-1] lastSample := sampleSet.Values[len(sampleSet.Values)-1]
vector = append(vector, &model.Sample{ vector = append(vector, model.Sample{
Metric: sampleSet.Metric, Metric: sampleSet.Metric,
Value: lastSample.Value, Value: lastSample.Value,
Timestamp: lastSample.Timestamp, Timestamp: lastSample.Timestamp,

View file

@ -44,7 +44,7 @@ func (serv MetricsService) Query(expr string, formatJson string) (result string)
rb.SetContentType(gorest.Text_Plain) rb.SetContentType(gorest.Text_Plain)
} }
return ast.EvalToString(exprNode, &timestamp, format) return ast.EvalToString(exprNode, timestamp, format)
} }
func (serv MetricsService) QueryRange(expr string, end int64, duration int64, step int64) string { func (serv MetricsService) QueryRange(expr string, end int64, duration int64, step int64) string {