@@ -17,6 +17,7 @@ import (
17
17
"bytes"
18
18
"hash"
19
19
"hash/fnv"
20
+ "sort"
20
21
"sync"
21
22
)
22
23
@@ -46,30 +47,37 @@ func getHashAndBuf() *hashAndBuf {
46
47
}
47
48
48
49
func putHashAndBuf (hb * hashAndBuf ) {
50
+ hb .h .Reset ()
51
+ hb .b .Reset ()
49
52
hashAndBufPool .Put (hb )
50
53
}
51
54
52
- // LabelsToSignature returns a unique signature (i.e., fingerprint) for a given
53
- // label set.
55
+ // LabelsToSignature returns an quasi-unique signature (i.e., fingerprint) for a
56
+ // given label set. (Collisions are possible but unlikely if the number of label
57
+ // sets the function is applied to is small.)
54
58
func LabelsToSignature (labels map [string ]string ) uint64 {
55
59
if len (labels ) == 0 {
56
60
return emptyLabelSignature
57
61
}
58
62
59
- var result uint64
63
+ labelNames := make ([]string , 0 , len (labels ))
64
+ for labelName := range labels {
65
+ labelNames = append (labelNames , labelName )
66
+ }
67
+ sort .Strings (labelNames )
68
+
60
69
hb := getHashAndBuf ()
61
70
defer putHashAndBuf (hb )
62
71
63
- for labelName , labelValue := range labels {
72
+ for _ , labelName := range labelNames {
64
73
hb .b .WriteString (labelName )
65
74
hb .b .WriteByte (SeparatorByte )
66
- hb .b .WriteString (labelValue )
75
+ hb .b .WriteString (labels [labelName ])
76
+ hb .b .WriteByte (SeparatorByte )
67
77
hb .h .Write (hb .b .Bytes ())
68
- result ^= hb .h .Sum64 ()
69
- hb .h .Reset ()
70
78
hb .b .Reset ()
71
79
}
72
- return result
80
+ return hb . h . Sum64 ()
73
81
}
74
82
75
83
// metricToFingerprint works exactly as LabelsToSignature but takes a Metric as
@@ -79,6 +87,34 @@ func metricToFingerprint(m Metric) Fingerprint {
79
87
return Fingerprint (emptyLabelSignature )
80
88
}
81
89
90
+ labelNames := make (LabelNames , 0 , len (m ))
91
+ for labelName := range m {
92
+ labelNames = append (labelNames , labelName )
93
+ }
94
+ sort .Sort (labelNames )
95
+
96
+ hb := getHashAndBuf ()
97
+ defer putHashAndBuf (hb )
98
+
99
+ for _ , labelName := range labelNames {
100
+ hb .b .WriteString (string (labelName ))
101
+ hb .b .WriteByte (SeparatorByte )
102
+ hb .b .WriteString (string (m [labelName ]))
103
+ hb .b .WriteByte (SeparatorByte )
104
+ hb .h .Write (hb .b .Bytes ())
105
+ hb .b .Reset ()
106
+ }
107
+ return Fingerprint (hb .h .Sum64 ())
108
+ }
109
+
110
+ // metricToFastFingerprint works similar to metricToFingerprint but uses a
111
+ // faster and less allocation-heavy hash function, which is more susceptible to
112
+ // create hash collisions. Therefore, collision detection should be applied.
113
+ func metricToFastFingerprint (m Metric ) Fingerprint {
114
+ if len (m ) == 0 {
115
+ return Fingerprint (emptyLabelSignature )
116
+ }
117
+
82
118
var result uint64
83
119
hb := getHashAndBuf ()
84
120
defer putHashAndBuf (hb )
@@ -97,26 +133,27 @@ func metricToFingerprint(m Metric) Fingerprint {
97
133
98
134
// SignatureForLabels works like LabelsToSignature but takes a Metric as
99
135
// parameter (rather than a label map) and only includes the labels with the
100
- // specified LabelNames into the signature calculation.
136
+ // specified LabelNames into the signature calculation. The labels passed in
137
+ // will be sorted by this function.
101
138
func SignatureForLabels (m Metric , labels LabelNames ) uint64 {
102
139
if len (m ) == 0 || len (labels ) == 0 {
103
140
return emptyLabelSignature
104
141
}
105
142
106
- var result uint64
143
+ sort .Sort (labels )
144
+
107
145
hb := getHashAndBuf ()
108
146
defer putHashAndBuf (hb )
109
147
110
148
for _ , label := range labels {
111
149
hb .b .WriteString (string (label ))
112
150
hb .b .WriteByte (SeparatorByte )
113
151
hb .b .WriteString (string (m [label ]))
152
+ hb .b .WriteByte (SeparatorByte )
114
153
hb .h .Write (hb .b .Bytes ())
115
- result ^= hb .h .Sum64 ()
116
- hb .h .Reset ()
117
154
hb .b .Reset ()
118
155
}
119
- return result
156
+ return hb . h . Sum64 ()
120
157
}
121
158
122
159
// SignatureWithoutLabels works like LabelsToSignature but takes a Metric as
@@ -127,24 +164,27 @@ func SignatureWithoutLabels(m Metric, labels map[LabelName]struct{}) uint64 {
127
164
return emptyLabelSignature
128
165
}
129
166
130
- var result uint64
167
+ labelNames := make (LabelNames , 0 , len (m ))
168
+ for labelName := range m {
169
+ if _ , exclude := labels [labelName ]; ! exclude {
170
+ labelNames = append (labelNames , labelName )
171
+ }
172
+ }
173
+ if len (labelNames ) == 0 {
174
+ return emptyLabelSignature
175
+ }
176
+ sort .Sort (labelNames )
177
+
131
178
hb := getHashAndBuf ()
132
179
defer putHashAndBuf (hb )
133
180
134
- for labelName , labelValue := range m {
135
- if _ , exclude := labels [labelName ]; exclude {
136
- continue
137
- }
181
+ for _ , labelName := range labelNames {
138
182
hb .b .WriteString (string (labelName ))
139
183
hb .b .WriteByte (SeparatorByte )
140
- hb .b .WriteString (string (labelValue ))
184
+ hb .b .WriteString (string (m [labelName ]))
185
+ hb .b .WriteByte (SeparatorByte )
141
186
hb .h .Write (hb .b .Bytes ())
142
- result ^= hb .h .Sum64 ()
143
- hb .h .Reset ()
144
187
hb .b .Reset ()
145
188
}
146
- if result == 0 {
147
- return emptyLabelSignature
148
- }
149
- return result
189
+ return hb .h .Sum64 ()
150
190
}
0 commit comments