prometheus/model/fingerprinting.go

208 lines
5.2 KiB
Go
Raw Normal View History

2013-02-08 17:03:26 +00:00
// Copyright 2013 Prometheus Team
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package model
import (
"code.google.com/p/goprotobuf/proto"
"encoding/binary"
"fmt"
dto "github.com/prometheus/prometheus/model/generated"
"hash/fnv"
"sort"
"strconv"
"strings"
)
const (
// rowKeyDelimiter is used to separate formatted versions of a metric's row
// key.
rowKeyDelimiter = "-"
)
// Builds a Fingerprint from a row key.
2013-05-17 10:58:15 +00:00
func NewFingerprintFromRowKey(rowKey string) *Fingerprint {
2013-02-08 17:03:26 +00:00
components := strings.Split(rowKey, rowKeyDelimiter)
hash, err := strconv.ParseUint(components[0], 10, 64)
if err != nil {
panic(err)
}
labelMatterLength, err := strconv.ParseUint(components[2], 10, 0)
if err != nil {
panic(err)
}
2013-05-17 10:58:15 +00:00
return &Fingerprint{
2013-02-08 17:03:26 +00:00
hash: hash,
firstCharacterOfFirstLabelName: components[1],
labelMatterLength: uint(labelMatterLength),
lastCharacterOfLastLabelValue: components[3],
}
}
// Builds a Fingerprint from a datastore entry.
2013-05-17 10:58:15 +00:00
func NewFingerprintFromDTO(f *dto.Fingerprint) *Fingerprint {
2013-02-08 17:03:26 +00:00
return NewFingerprintFromRowKey(*f.Signature)
}
// Decomposes a Metric into a Fingerprint.
2013-05-17 10:58:15 +00:00
func NewFingerprintFromMetric(metric Metric) *Fingerprint {
2013-02-08 17:03:26 +00:00
labelLength := len(metric)
labelNames := make([]string, 0, labelLength)
for labelName := range metric {
labelNames = append(labelNames, string(labelName))
}
sort.Strings(labelNames)
summer := fnv.New64a()
firstCharacterOfFirstLabelName := ""
lastCharacterOfLastLabelValue := ""
labelMatterLength := 0
for i, labelName := range labelNames {
labelValue := metric[LabelName(labelName)]
labelNameLength := len(labelName)
labelValueLength := len(labelValue)
labelMatterLength += labelNameLength + labelValueLength
2013-03-07 01:16:39 +00:00
if i == 0 {
2013-02-08 17:03:26 +00:00
firstCharacterOfFirstLabelName = labelName[0:1]
2013-03-07 01:16:39 +00:00
}
if i == labelLength-1 {
lastCharacterOfLastLabelValue = string(labelValue[labelValueLength-1 : labelValueLength])
2013-02-08 17:03:26 +00:00
}
summer.Write([]byte(labelName))
summer.Write([]byte(reservedDelimiter))
summer.Write([]byte(labelValue))
}
2013-05-17 10:58:15 +00:00
return &Fingerprint{
2013-02-08 17:03:26 +00:00
firstCharacterOfFirstLabelName: firstCharacterOfFirstLabelName,
hash: binary.LittleEndian.Uint64(summer.Sum(nil)),
labelMatterLength: uint(labelMatterLength % 10),
lastCharacterOfLastLabelValue: lastCharacterOfLastLabelValue,
2013-02-08 17:03:26 +00:00
}
}
// A simplified representation of an entity.
2013-05-17 10:58:15 +00:00
type Fingerprint struct {
2013-02-08 17:03:26 +00:00
// A hashed representation of the underyling entity. For our purposes, FNV-1A
// 64-bit is used.
hash uint64
firstCharacterOfFirstLabelName string
labelMatterLength uint
lastCharacterOfLastLabelValue string
}
2013-05-17 10:58:15 +00:00
func (f *Fingerprint) String() string {
2013-03-26 11:33:48 +00:00
return f.ToRowKey()
}
2013-05-17 10:58:15 +00:00
// Transforms the Fingerprint into a database row key.
func (f *Fingerprint) ToRowKey() string {
2013-02-08 17:03:26 +00:00
return strings.Join([]string{fmt.Sprintf("%020d", f.hash), f.firstCharacterOfFirstLabelName, fmt.Sprint(f.labelMatterLength), f.lastCharacterOfLastLabelValue}, rowKeyDelimiter)
}
2013-05-17 10:58:15 +00:00
func (f *Fingerprint) ToDTO() *dto.Fingerprint {
2013-02-08 17:03:26 +00:00
return &dto.Fingerprint{
Signature: proto.String(f.ToRowKey()),
}
}
2013-05-17 10:58:15 +00:00
func (f *Fingerprint) Hash() uint64 {
2013-02-08 17:03:26 +00:00
return f.hash
}
2013-05-17 10:58:15 +00:00
func (f *Fingerprint) FirstCharacterOfFirstLabelName() string {
2013-02-08 17:03:26 +00:00
return f.firstCharacterOfFirstLabelName
}
2013-05-17 10:58:15 +00:00
func (f *Fingerprint) LabelMatterLength() uint {
2013-02-08 17:03:26 +00:00
return f.labelMatterLength
}
2013-05-17 10:58:15 +00:00
func (f *Fingerprint) LastCharacterOfLastLabelValue() string {
2013-02-08 17:03:26 +00:00
return f.lastCharacterOfLastLabelValue
}
2013-05-17 10:58:15 +00:00
func (f *Fingerprint) Less(o *Fingerprint) bool {
if f.hash < o.hash {
2013-05-16 15:16:39 +00:00
return true
}
2013-05-17 10:58:15 +00:00
if f.hash > o.hash {
2013-05-16 15:16:39 +00:00
return false
}
2013-05-17 10:58:15 +00:00
if f.firstCharacterOfFirstLabelName < o.firstCharacterOfFirstLabelName {
2013-05-16 15:16:39 +00:00
return true
}
2013-05-17 10:58:15 +00:00
if f.firstCharacterOfFirstLabelName > o.firstCharacterOfFirstLabelName {
2013-05-16 15:16:39 +00:00
return false
}
2013-05-17 10:58:15 +00:00
if f.labelMatterLength < o.labelMatterLength {
2013-05-16 15:16:39 +00:00
return true
}
2013-05-17 10:58:15 +00:00
if f.labelMatterLength > o.labelMatterLength {
2013-05-16 15:16:39 +00:00
return false
}
2013-05-17 10:58:15 +00:00
if f.lastCharacterOfLastLabelValue < o.lastCharacterOfLastLabelValue {
2013-05-16 15:16:39 +00:00
return true
}
2013-05-17 10:58:15 +00:00
if f.lastCharacterOfLastLabelValue > o.lastCharacterOfLastLabelValue {
2013-05-16 15:16:39 +00:00
return false
}
return false
2013-02-08 17:03:26 +00:00
}
2013-05-17 10:58:15 +00:00
func (f *Fingerprint) Equal(o *Fingerprint) (equal bool) {
2013-02-08 17:03:26 +00:00
equal = f.Hash() == o.Hash()
if !equal {
return
}
equal = f.FirstCharacterOfFirstLabelName() == o.FirstCharacterOfFirstLabelName()
if !equal {
return
}
equal = f.LabelMatterLength() == o.LabelMatterLength()
if !equal {
return
}
equal = f.LastCharacterOfLastLabelValue() == o.LastCharacterOfLastLabelValue()
return
}
// Represents a collection of Fingerprint subject to a given natural sorting
// scheme.
2013-05-17 10:58:15 +00:00
type Fingerprints []*Fingerprint
2013-02-08 17:03:26 +00:00
func (f Fingerprints) Len() int {
return len(f)
}
func (f Fingerprints) Less(i, j int) bool {
2013-02-08 17:03:26 +00:00
return f[i].Less(f[j])
}
func (f Fingerprints) Swap(i, j int) {
f[i], f[j] = f[j], f[i]
}