signature.go 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. // 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. package model
  14. import (
  15. "bytes"
  16. "hash"
  17. "hash/fnv"
  18. "sort"
  19. "sync"
  20. )
  21. // SeparatorByte is a byte that cannot occur in valid UTF-8 sequences and is
  22. // used to separate label names, label values, and other strings from each other
  23. // when calculating their combined hash value (aka signature aka fingerprint).
  24. const SeparatorByte byte = 255
  25. var (
  26. // cache the signature of an empty label set.
  27. emptyLabelSignature = fnv.New64a().Sum64()
  28. hashAndBufPool sync.Pool
  29. )
  30. type hashAndBuf struct {
  31. h hash.Hash64
  32. b bytes.Buffer
  33. }
  34. func getHashAndBuf() *hashAndBuf {
  35. hb := hashAndBufPool.Get()
  36. if hb == nil {
  37. return &hashAndBuf{h: fnv.New64a()}
  38. }
  39. return hb.(*hashAndBuf)
  40. }
  41. func putHashAndBuf(hb *hashAndBuf) {
  42. hb.h.Reset()
  43. hb.b.Reset()
  44. hashAndBufPool.Put(hb)
  45. }
  46. // LabelsToSignature returns a quasi-unique signature (i.e., fingerprint) for a
  47. // given label set. (Collisions are possible but unlikely if the number of label
  48. // sets the function is applied to is small.)
  49. func LabelsToSignature(labels map[string]string) uint64 {
  50. if len(labels) == 0 {
  51. return emptyLabelSignature
  52. }
  53. labelNames := make([]string, 0, len(labels))
  54. for labelName := range labels {
  55. labelNames = append(labelNames, labelName)
  56. }
  57. sort.Strings(labelNames)
  58. hb := getHashAndBuf()
  59. defer putHashAndBuf(hb)
  60. for _, labelName := range labelNames {
  61. hb.b.WriteString(labelName)
  62. hb.b.WriteByte(SeparatorByte)
  63. hb.b.WriteString(labels[labelName])
  64. hb.b.WriteByte(SeparatorByte)
  65. hb.h.Write(hb.b.Bytes())
  66. hb.b.Reset()
  67. }
  68. return hb.h.Sum64()
  69. }
  70. // labelSetToFingerprint works exactly as LabelsToSignature but takes a LabelSet as
  71. // parameter (rather than a label map) and returns a Fingerprint.
  72. func labelSetToFingerprint(ls LabelSet) Fingerprint {
  73. if len(ls) == 0 {
  74. return Fingerprint(emptyLabelSignature)
  75. }
  76. labelNames := make(LabelNames, 0, len(ls))
  77. for labelName := range ls {
  78. labelNames = append(labelNames, labelName)
  79. }
  80. sort.Sort(labelNames)
  81. hb := getHashAndBuf()
  82. defer putHashAndBuf(hb)
  83. for _, labelName := range labelNames {
  84. hb.b.WriteString(string(labelName))
  85. hb.b.WriteByte(SeparatorByte)
  86. hb.b.WriteString(string(ls[labelName]))
  87. hb.b.WriteByte(SeparatorByte)
  88. hb.h.Write(hb.b.Bytes())
  89. hb.b.Reset()
  90. }
  91. return Fingerprint(hb.h.Sum64())
  92. }
  93. // labelSetToFastFingerprint works similar to labelSetToFingerprint but uses a
  94. // faster and less allocation-heavy hash function, which is more susceptible to
  95. // create hash collisions. Therefore, collision detection should be applied.
  96. func labelSetToFastFingerprint(ls LabelSet) Fingerprint {
  97. if len(ls) == 0 {
  98. return Fingerprint(emptyLabelSignature)
  99. }
  100. var result uint64
  101. hb := getHashAndBuf()
  102. defer putHashAndBuf(hb)
  103. for labelName, labelValue := range ls {
  104. hb.b.WriteString(string(labelName))
  105. hb.b.WriteByte(SeparatorByte)
  106. hb.b.WriteString(string(labelValue))
  107. hb.h.Write(hb.b.Bytes())
  108. result ^= hb.h.Sum64()
  109. hb.h.Reset()
  110. hb.b.Reset()
  111. }
  112. return Fingerprint(result)
  113. }
  114. // SignatureForLabels works like LabelsToSignature but takes a Metric as
  115. // parameter (rather than a label map) and only includes the labels with the
  116. // specified LabelNames into the signature calculation. The labels passed in
  117. // will be sorted by this function.
  118. func SignatureForLabels(m Metric, labels ...LabelName) uint64 {
  119. if len(m) == 0 || len(labels) == 0 {
  120. return emptyLabelSignature
  121. }
  122. sort.Sort(LabelNames(labels))
  123. hb := getHashAndBuf()
  124. defer putHashAndBuf(hb)
  125. for _, label := range labels {
  126. hb.b.WriteString(string(label))
  127. hb.b.WriteByte(SeparatorByte)
  128. hb.b.WriteString(string(m[label]))
  129. hb.b.WriteByte(SeparatorByte)
  130. hb.h.Write(hb.b.Bytes())
  131. hb.b.Reset()
  132. }
  133. return hb.h.Sum64()
  134. }
  135. // SignatureWithoutLabels works like LabelsToSignature but takes a Metric as
  136. // parameter (rather than a label map) and excludes the labels with any of the
  137. // specified LabelNames from the signature calculation.
  138. func SignatureWithoutLabels(m Metric, labels map[LabelName]struct{}) uint64 {
  139. if len(m) == 0 {
  140. return emptyLabelSignature
  141. }
  142. labelNames := make(LabelNames, 0, len(m))
  143. for labelName := range m {
  144. if _, exclude := labels[labelName]; !exclude {
  145. labelNames = append(labelNames, labelName)
  146. }
  147. }
  148. if len(labelNames) == 0 {
  149. return emptyLabelSignature
  150. }
  151. sort.Sort(labelNames)
  152. hb := getHashAndBuf()
  153. defer putHashAndBuf(hb)
  154. for _, labelName := range labelNames {
  155. hb.b.WriteString(string(labelName))
  156. hb.b.WriteByte(SeparatorByte)
  157. hb.b.WriteString(string(m[labelName]))
  158. hb.b.WriteByte(SeparatorByte)
  159. hb.h.Write(hb.b.Bytes())
  160. hb.b.Reset()
  161. }
  162. return hb.h.Sum64()
  163. }