blob: dc8a0026c4842717b44578899b5673586ae918c8 [file] [log] [blame]
khenaidooab1f7bd2019-11-14 14:00:27 -05001// Copyright 2014 The Prometheus Authors
2// Licensed under the Apache License, Version 2.0 (the "License");
3// you may not use this file except in compliance with the License.
4// You may obtain a copy of the License at
5//
6// http://www.apache.org/licenses/LICENSE-2.0
7//
8// Unless required by applicable law or agreed to in writing, software
9// distributed under the License is distributed on an "AS IS" BASIS,
10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11// See the License for the specific language governing permissions and
12// limitations under the License.
13
14package model
15
16import (
17 "sort"
18)
19
20// SeparatorByte is a byte that cannot occur in valid UTF-8 sequences and is
21// used to separate label names, label values, and other strings from each other
22// when calculating their combined hash value (aka signature aka fingerprint).
23const SeparatorByte byte = 255
24
Abhay Kumara2ae5992025-11-10 14:02:24 +000025// cache the signature of an empty label set.
26var emptyLabelSignature = hashNew()
khenaidooab1f7bd2019-11-14 14:00:27 -050027
28// LabelsToSignature returns a quasi-unique signature (i.e., fingerprint) for a
29// given label set. (Collisions are possible but unlikely if the number of label
30// sets the function is applied to is small.)
31func LabelsToSignature(labels map[string]string) uint64 {
32 if len(labels) == 0 {
33 return emptyLabelSignature
34 }
35
36 labelNames := make([]string, 0, len(labels))
37 for labelName := range labels {
38 labelNames = append(labelNames, labelName)
39 }
40 sort.Strings(labelNames)
41
42 sum := hashNew()
43 for _, labelName := range labelNames {
44 sum = hashAdd(sum, labelName)
45 sum = hashAddByte(sum, SeparatorByte)
46 sum = hashAdd(sum, labels[labelName])
47 sum = hashAddByte(sum, SeparatorByte)
48 }
49 return sum
50}
51
52// labelSetToFingerprint works exactly as LabelsToSignature but takes a LabelSet as
53// parameter (rather than a label map) and returns a Fingerprint.
54func labelSetToFingerprint(ls LabelSet) Fingerprint {
55 if len(ls) == 0 {
56 return Fingerprint(emptyLabelSignature)
57 }
58
59 labelNames := make(LabelNames, 0, len(ls))
60 for labelName := range ls {
61 labelNames = append(labelNames, labelName)
62 }
63 sort.Sort(labelNames)
64
65 sum := hashNew()
66 for _, labelName := range labelNames {
67 sum = hashAdd(sum, string(labelName))
68 sum = hashAddByte(sum, SeparatorByte)
69 sum = hashAdd(sum, string(ls[labelName]))
70 sum = hashAddByte(sum, SeparatorByte)
71 }
72 return Fingerprint(sum)
73}
74
75// labelSetToFastFingerprint works similar to labelSetToFingerprint but uses a
76// faster and less allocation-heavy hash function, which is more susceptible to
77// create hash collisions. Therefore, collision detection should be applied.
78func labelSetToFastFingerprint(ls LabelSet) Fingerprint {
79 if len(ls) == 0 {
80 return Fingerprint(emptyLabelSignature)
81 }
82
83 var result uint64
84 for labelName, labelValue := range ls {
85 sum := hashNew()
86 sum = hashAdd(sum, string(labelName))
87 sum = hashAddByte(sum, SeparatorByte)
88 sum = hashAdd(sum, string(labelValue))
89 result ^= sum
90 }
91 return Fingerprint(result)
92}
93
94// SignatureForLabels works like LabelsToSignature but takes a Metric as
95// parameter (rather than a label map) and only includes the labels with the
96// specified LabelNames into the signature calculation. The labels passed in
97// will be sorted by this function.
98func SignatureForLabels(m Metric, labels ...LabelName) uint64 {
99 if len(labels) == 0 {
100 return emptyLabelSignature
101 }
102
103 sort.Sort(LabelNames(labels))
104
105 sum := hashNew()
106 for _, label := range labels {
107 sum = hashAdd(sum, string(label))
108 sum = hashAddByte(sum, SeparatorByte)
109 sum = hashAdd(sum, string(m[label]))
110 sum = hashAddByte(sum, SeparatorByte)
111 }
112 return sum
113}
114
115// SignatureWithoutLabels works like LabelsToSignature but takes a Metric as
116// parameter (rather than a label map) and excludes the labels with any of the
117// specified LabelNames from the signature calculation.
118func SignatureWithoutLabels(m Metric, labels map[LabelName]struct{}) uint64 {
119 if len(m) == 0 {
120 return emptyLabelSignature
121 }
122
123 labelNames := make(LabelNames, 0, len(m))
124 for labelName := range m {
125 if _, exclude := labels[labelName]; !exclude {
126 labelNames = append(labelNames, labelName)
127 }
128 }
129 if len(labelNames) == 0 {
130 return emptyLabelSignature
131 }
132 sort.Sort(labelNames)
133
134 sum := hashNew()
135 for _, labelName := range labelNames {
136 sum = hashAdd(sum, string(labelName))
137 sum = hashAddByte(sum, SeparatorByte)
138 sum = hashAdd(sum, string(m[labelName]))
139 sum = hashAddByte(sum, SeparatorByte)
140 }
141 return sum
142}