signature.go 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  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. "sort"
  16. )
  17. // SeparatorByte is a byte that cannot occur in valid UTF-8 sequences and is
  18. // used to separate label names, label values, and other strings from each other
  19. // when calculating their combined hash value (aka signature aka fingerprint).
  20. const SeparatorByte byte = 255
  21. // cache the signature of an empty label set.
  22. var emptyLabelSignature = hashNew()
  23. // LabelsToSignature returns a quasi-unique signature (i.e., fingerprint) for a
  24. // given label set. (Collisions are possible but unlikely if the number of label
  25. // sets the function is applied to is small.)
  26. func LabelsToSignature(labels map[string]string) uint64 {
  27. if len(labels) == 0 {
  28. return emptyLabelSignature
  29. }
  30. labelNames := make([]string, 0, len(labels))
  31. for labelName := range labels {
  32. labelNames = append(labelNames, labelName)
  33. }
  34. sort.Strings(labelNames)
  35. sum := hashNew()
  36. for _, labelName := range labelNames {
  37. sum = hashAdd(sum, labelName)
  38. sum = hashAddByte(sum, SeparatorByte)
  39. sum = hashAdd(sum, labels[labelName])
  40. sum = hashAddByte(sum, SeparatorByte)
  41. }
  42. return sum
  43. }
  44. // labelSetToFingerprint works exactly as LabelsToSignature but takes a LabelSet as
  45. // parameter (rather than a label map) and returns a Fingerprint.
  46. func labelSetToFingerprint(ls LabelSet) Fingerprint {
  47. if len(ls) == 0 {
  48. return Fingerprint(emptyLabelSignature)
  49. }
  50. labelNames := make(LabelNames, 0, len(ls))
  51. for labelName := range ls {
  52. labelNames = append(labelNames, labelName)
  53. }
  54. sort.Sort(labelNames)
  55. sum := hashNew()
  56. for _, labelName := range labelNames {
  57. sum = hashAdd(sum, string(labelName))
  58. sum = hashAddByte(sum, SeparatorByte)
  59. sum = hashAdd(sum, string(ls[labelName]))
  60. sum = hashAddByte(sum, SeparatorByte)
  61. }
  62. return Fingerprint(sum)
  63. }
  64. // labelSetToFastFingerprint works similar to labelSetToFingerprint but uses a
  65. // faster and less allocation-heavy hash function, which is more susceptible to
  66. // create hash collisions. Therefore, collision detection should be applied.
  67. func labelSetToFastFingerprint(ls LabelSet) Fingerprint {
  68. if len(ls) == 0 {
  69. return Fingerprint(emptyLabelSignature)
  70. }
  71. var result uint64
  72. for labelName, labelValue := range ls {
  73. sum := hashNew()
  74. sum = hashAdd(sum, string(labelName))
  75. sum = hashAddByte(sum, SeparatorByte)
  76. sum = hashAdd(sum, string(labelValue))
  77. result ^= sum
  78. }
  79. return Fingerprint(result)
  80. }
  81. // SignatureForLabels works like LabelsToSignature but takes a Metric as
  82. // parameter (rather than a label map) and only includes the labels with the
  83. // specified LabelNames into the signature calculation. The labels passed in
  84. // will be sorted by this function.
  85. func SignatureForLabels(m Metric, labels ...LabelName) uint64 {
  86. if len(labels) == 0 {
  87. return emptyLabelSignature
  88. }
  89. sort.Sort(LabelNames(labels))
  90. sum := hashNew()
  91. for _, label := range labels {
  92. sum = hashAdd(sum, string(label))
  93. sum = hashAddByte(sum, SeparatorByte)
  94. sum = hashAdd(sum, string(m[label]))
  95. sum = hashAddByte(sum, SeparatorByte)
  96. }
  97. return sum
  98. }
  99. // SignatureWithoutLabels works like LabelsToSignature but takes a Metric as
  100. // parameter (rather than a label map) and excludes the labels with any of the
  101. // specified LabelNames from the signature calculation.
  102. func SignatureWithoutLabels(m Metric, labels map[LabelName]struct{}) uint64 {
  103. if len(m) == 0 {
  104. return emptyLabelSignature
  105. }
  106. labelNames := make(LabelNames, 0, len(m))
  107. for labelName := range m {
  108. if _, exclude := labels[labelName]; !exclude {
  109. labelNames = append(labelNames, labelName)
  110. }
  111. }
  112. if len(labelNames) == 0 {
  113. return emptyLabelSignature
  114. }
  115. sort.Sort(labelNames)
  116. sum := hashNew()
  117. for _, labelName := range labelNames {
  118. sum = hashAdd(sum, string(labelName))
  119. sum = hashAddByte(sum, SeparatorByte)
  120. sum = hashAdd(sum, string(m[labelName]))
  121. sum = hashAddByte(sum, SeparatorByte)
  122. }
  123. return sum
  124. }