Browse Source

Apply the new signature/fingerprinting functions from client_golang.

This requires the new version of client_golang (vendoring will follow
in the next commit), which changes the fingerprinting for
clientmodel.Metric.
pull/573/head
beorn7 10 years ago
parent
commit
9e85ab0eef
  1. 24
      rules/ast/ast.go
  2. 10
      rules/ast/functions.go
  3. 52
      rules/ast/quantile.go

24
rules/ast/ast.go

@ -17,7 +17,6 @@ import (
"errors"
"flag"
"fmt"
"hash/fnv"
"math"
"time"
@ -383,23 +382,6 @@ func (node *ScalarFunctionCall) Eval(timestamp clientmodel.Timestamp) clientmode
return node.function.callFn(timestamp, node.args).(clientmodel.SampleValue)
}
// hashForLabels returns a hash value taken from the label/value pairs of the
// specified labels in the metric.
func hashForLabels(metric clientmodel.Metric, labels clientmodel.LabelNames) uint64 {
var result uint64
s := fnv.New64a()
for _, label := range labels {
s.Write([]byte(label))
s.Write([]byte{clientmodel.SeparatorByte})
s.Write([]byte(metric[label]))
result ^= s.Sum64()
s.Reset()
}
return result
}
// EvalVectorInstant evaluates a VectorNode with an instant query.
func EvalVectorInstant(node VectorNode, timestamp clientmodel.Timestamp, storage local.Storage, queryStats *stats.TimerGroup) (Vector, error) {
totalEvalTimer := queryStats.GetTimer(stats.TotalEvalTime).Start()
@ -503,7 +485,7 @@ func (node *VectorAggregation) Eval(timestamp clientmodel.Timestamp) Vector {
vector := node.vector.Eval(timestamp)
result := map[uint64]*groupedAggregation{}
for _, sample := range vector {
groupingKey := hashForLabels(sample.Metric.Metric, node.groupBy)
groupingKey := clientmodel.SignatureForLabels(sample.Metric.Metric, node.groupBy)
if groupedResult, ok := result[groupingKey]; ok {
if node.keepExtraLabels {
groupedResult.labels = labelIntersection(groupedResult.labels, sample.Metric)
@ -879,7 +861,7 @@ func (node *VectorArithExpr) evalVectors(timestamp clientmodel.Timestamp, lhs, r
metric := node.resultMetric(ls, rs)
// Check if the same label set has been added for a many-to-one matching before.
if node.matchCardinality == MatchManyToOne || node.matchCardinality == MatchOneToMany {
insHash := hashForLabels(metric.Metric, node.includeLabels)
insHash := clientmodel.SignatureForLabels(metric.Metric, node.includeLabels)
if ihs, exists := added[hash]; exists {
for _, ih := range ihs {
if ih == insHash {
@ -971,7 +953,7 @@ func (node *VectorArithExpr) hashForMetric(metric clientmodel.Metric) uint64 {
}
}
}
return hashForLabels(metric, labels)
return clientmodel.SignatureForLabels(metric, labels)
}
// Eval implements the MatrixNode interface and returns the value of

10
rules/ast/functions.go

@ -504,7 +504,7 @@ func histogramQuantileImpl(timestamp clientmodel.Timestamp, args []Node) interfa
q := args[0].(ScalarNode).Eval(timestamp)
inVec := args[1].(VectorNode).Eval(timestamp)
outVec := Vector{}
fpToMetricWithBuckets := map[clientmodel.Fingerprint]*metricWithBuckets{}
signatureToMetricWithBuckets := map[uint64]*metricWithBuckets{}
for _, el := range inVec {
upperBound, err := strconv.ParseFloat(
string(el.Metric.Metric[clientmodel.BucketLabel]), 64,
@ -514,18 +514,18 @@ func histogramQuantileImpl(timestamp clientmodel.Timestamp, args []Node) interfa
// TODO(beorn7): Issue a warning somehow.
continue
}
fp := bucketFingerprint(el.Metric.Metric)
mb, ok := fpToMetricWithBuckets[fp]
signature := clientmodel.SignatureWithoutLabels(el.Metric.Metric, excludedLabels)
mb, ok := signatureToMetricWithBuckets[signature]
if !ok {
el.Metric.Delete(clientmodel.BucketLabel)
el.Metric.Delete(clientmodel.MetricNameLabel)
mb = &metricWithBuckets{el.Metric, nil}
fpToMetricWithBuckets[fp] = mb
signatureToMetricWithBuckets[signature] = mb
}
mb.buckets = append(mb.buckets, bucket{upperBound, el.Value})
}
for _, mb := range fpToMetricWithBuckets {
for _, mb := range signatureToMetricWithBuckets {
outVec = append(outVec, &Sample{
Metric: mb.metric,
Value: clientmodel.SampleValue(quantile(q, mb.buckets)),

52
rules/ast/quantile.go

@ -14,8 +14,6 @@
package ast
import (
"encoding/binary"
"hash/fnv"
"math"
"sort"
@ -24,6 +22,13 @@ import (
// Helpers to calculate quantiles.
// excludedLabels are the labels to exclude from signature calculation for
// quantiles.
var excludedLabels = map[clientmodel.LabelName]struct{}{
clientmodel.MetricNameLabel: struct{}{},
clientmodel.BucketLabel: struct{}{},
}
type bucket struct {
upperBound float64
count clientmodel.SampleValue
@ -99,46 +104,3 @@ func quantile(q clientmodel.SampleValue, buckets buckets) float64 {
}
return bucketStart + (bucketEnd-bucketStart)*float64(rank/count)
}
// bucketFingerprint works like the Fingerprint method of Metric, but ignores
// the name and the bucket label.
func bucketFingerprint(m clientmodel.Metric) clientmodel.Fingerprint {
numLabels := 0
if len(m) > 2 {
numLabels = len(m) - 2
}
labelNames := make([]string, 0, numLabels)
maxLength := 0
for labelName, labelValue := range m {
if labelName == clientmodel.MetricNameLabel || labelName == clientmodel.BucketLabel {
continue
}
labelNames = append(labelNames, string(labelName))
if len(labelName) > maxLength {
maxLength = len(labelName)
}
if len(labelValue) > maxLength {
maxLength = len(labelValue)
}
}
sort.Strings(labelNames)
summer := fnv.New64a()
buf := make([]byte, maxLength)
for _, labelName := range labelNames {
labelValue := m[clientmodel.LabelName(labelName)]
copy(buf, labelName)
summer.Write(buf[:len(labelName)])
summer.Write([]byte{clientmodel.SeparatorByte})
copy(buf, labelValue)
summer.Write(buf[:len(labelValue)])
summer.Write([]byte{clientmodel.SeparatorByte})
}
return clientmodel.Fingerprint(binary.LittleEndian.Uint64(summer.Sum(nil)))
}

Loading…
Cancel
Save