Merge pull request #184 from realzeitmedia/allfnv

use local fnv hash everywhere
This commit is contained in:
Björn Rabenstein 2015-11-12 14:29:20 +01:00
commit 275368fd9e
3 changed files with 24 additions and 32 deletions

View File

@ -1,10 +1,8 @@
package prometheus package prometheus
import ( import (
"bytes"
"errors" "errors"
"fmt" "fmt"
"hash/fnv"
"regexp" "regexp"
"sort" "sort"
"strings" "strings"
@ -131,31 +129,24 @@ func NewDesc(fqName, help string, variableLabels []string, constLabels Labels) *
d.err = errors.New("duplicate label names") d.err = errors.New("duplicate label names")
return d return d
} }
h := fnv.New64a() vh := hashNew()
var b bytes.Buffer // To copy string contents into, avoiding []byte allocations.
for _, val := range labelValues { for _, val := range labelValues {
b.Reset() vh = hashAdd(vh, val)
b.WriteString(val) vh = hashAddByte(vh, separatorByte)
b.WriteByte(separatorByte)
h.Write(b.Bytes())
} }
d.id = h.Sum64() d.id = vh
// Sort labelNames so that order doesn't matter for the hash. // Sort labelNames so that order doesn't matter for the hash.
sort.Strings(labelNames) sort.Strings(labelNames)
// Now hash together (in this order) the help string and the sorted // Now hash together (in this order) the help string and the sorted
// label names. // label names.
h.Reset() lh := hashNew()
b.Reset() lh = hashAdd(lh, help)
b.WriteString(help) lh = hashAddByte(lh, separatorByte)
b.WriteByte(separatorByte)
h.Write(b.Bytes())
for _, labelName := range labelNames { for _, labelName := range labelNames {
b.Reset() lh = hashAdd(lh, labelName)
b.WriteString(labelName) lh = hashAddByte(lh, separatorByte)
b.WriteByte(separatorByte)
h.Write(b.Bytes())
} }
d.dimHash = h.Sum64() d.dimHash = lh
d.constLabelPairs = make([]*dto.LabelPair, 0, len(constLabels)) d.constLabelPairs = make([]*dto.LabelPair, 0, len(constLabels))
for n, v := range constLabels { for n, v := range constLabels {

View File

@ -20,3 +20,10 @@ func hashAdd(h uint64, s string) uint64 {
} }
return h return h
} }
// hashAddByte adds a byte to a fnv64a hash value, returning the updated hash.
func hashAddByte(h uint64, b byte) uint64 {
h ^= uint64(b)
h *= prime64
return h
}

View File

@ -24,7 +24,6 @@ import (
"compress/gzip" "compress/gzip"
"errors" "errors"
"fmt" "fmt"
"hash/fnv"
"io" "io"
"net/http" "net/http"
"net/url" "net/url"
@ -528,30 +527,25 @@ func (r *registry) checkConsistency(metricFamily *dto.MetricFamily, dtoMetric *d
} }
// Is the metric unique (i.e. no other metric with the same name and the same label values)? // Is the metric unique (i.e. no other metric with the same name and the same label values)?
h := fnv.New64a() h := hashNew()
var buf bytes.Buffer h = hashAdd(h, metricFamily.GetName())
buf.WriteString(metricFamily.GetName()) h = hashAddByte(h, separatorByte)
buf.WriteByte(separatorByte)
h.Write(buf.Bytes())
// Make sure label pairs are sorted. We depend on it for the consistency // Make sure label pairs are sorted. We depend on it for the consistency
// check. Label pairs must be sorted by contract. But the point of this // check. Label pairs must be sorted by contract. But the point of this
// method is to check for contract violations. So we better do the sort // method is to check for contract violations. So we better do the sort
// now. // now.
sort.Sort(LabelPairSorter(dtoMetric.Label)) sort.Sort(LabelPairSorter(dtoMetric.Label))
for _, lp := range dtoMetric.Label { for _, lp := range dtoMetric.Label {
buf.Reset() h = hashAdd(h, lp.GetValue())
buf.WriteString(lp.GetValue()) h = hashAddByte(h, separatorByte)
buf.WriteByte(separatorByte)
h.Write(buf.Bytes())
} }
metricHash := h.Sum64() if _, exists := metricHashes[h]; exists {
if _, exists := metricHashes[metricHash]; exists {
return fmt.Errorf( return fmt.Errorf(
"collected metric %s %s was collected before with the same name and label values", "collected metric %s %s was collected before with the same name and label values",
metricFamily.GetName(), dtoMetric, metricFamily.GetName(), dtoMetric,
) )
} }
metricHashes[metricHash] = struct{}{} metricHashes[h] = struct{}{}
if desc == nil { if desc == nil {
return nil // Nothing left to check if we have no desc. return nil // Nothing left to check if we have no desc.