github.com/hellobchain/third_party@v0.0.0-20230331131523-deb0478a2e52/prometheus/common/model/signature.go (about) 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 14 package model 15 16 import ( 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). 23 const SeparatorByte byte = 255 24 25 var ( 26 // cache the signature of an empty label set. 27 emptyLabelSignature = hashNew() 28 ) 29 30 // LabelsToSignature returns a quasi-unique signature (i.e., fingerprint) for a 31 // given label set. (Collisions are possible but unlikely if the number of label 32 // sets the function is applied to is small.) 33 func LabelsToSignature(labels map[string]string) uint64 { 34 if len(labels) == 0 { 35 return emptyLabelSignature 36 } 37 38 labelNames := make([]string, 0, len(labels)) 39 for labelName := range labels { 40 labelNames = append(labelNames, labelName) 41 } 42 sort.Strings(labelNames) 43 44 sum := hashNew() 45 for _, labelName := range labelNames { 46 sum = hashAdd(sum, labelName) 47 sum = hashAddByte(sum, SeparatorByte) 48 sum = hashAdd(sum, labels[labelName]) 49 sum = hashAddByte(sum, SeparatorByte) 50 } 51 return sum 52 } 53 54 // labelSetToFingerprint works exactly as LabelsToSignature but takes a LabelSet as 55 // parameter (rather than a label map) and returns a Fingerprint. 56 func labelSetToFingerprint(ls LabelSet) Fingerprint { 57 if len(ls) == 0 { 58 return Fingerprint(emptyLabelSignature) 59 } 60 61 labelNames := make(LabelNames, 0, len(ls)) 62 for labelName := range ls { 63 labelNames = append(labelNames, labelName) 64 } 65 sort.Sort(labelNames) 66 67 sum := hashNew() 68 for _, labelName := range labelNames { 69 sum = hashAdd(sum, string(labelName)) 70 sum = hashAddByte(sum, SeparatorByte) 71 sum = hashAdd(sum, string(ls[labelName])) 72 sum = hashAddByte(sum, SeparatorByte) 73 } 74 return Fingerprint(sum) 75 } 76 77 // labelSetToFastFingerprint works similar to labelSetToFingerprint but uses a 78 // faster and less allocation-heavy hash function, which is more susceptible to 79 // create hash collisions. Therefore, collision detection should be applied. 80 func labelSetToFastFingerprint(ls LabelSet) Fingerprint { 81 if len(ls) == 0 { 82 return Fingerprint(emptyLabelSignature) 83 } 84 85 var result uint64 86 for labelName, labelValue := range ls { 87 sum := hashNew() 88 sum = hashAdd(sum, string(labelName)) 89 sum = hashAddByte(sum, SeparatorByte) 90 sum = hashAdd(sum, string(labelValue)) 91 result ^= sum 92 } 93 return Fingerprint(result) 94 } 95 96 // SignatureForLabels works like LabelsToSignature but takes a Metric as 97 // parameter (rather than a label map) and only includes the labels with the 98 // specified LabelNames into the signature calculation. The labels passed in 99 // will be sorted by this function. 100 func SignatureForLabels(m Metric, labels ...LabelName) uint64 { 101 if len(labels) == 0 { 102 return emptyLabelSignature 103 } 104 105 sort.Sort(LabelNames(labels)) 106 107 sum := hashNew() 108 for _, label := range labels { 109 sum = hashAdd(sum, string(label)) 110 sum = hashAddByte(sum, SeparatorByte) 111 sum = hashAdd(sum, string(m[label])) 112 sum = hashAddByte(sum, SeparatorByte) 113 } 114 return sum 115 } 116 117 // SignatureWithoutLabels works like LabelsToSignature but takes a Metric as 118 // parameter (rather than a label map) and excludes the labels with any of the 119 // specified LabelNames from the signature calculation. 120 func SignatureWithoutLabels(m Metric, labels map[LabelName]struct{}) uint64 { 121 if len(m) == 0 { 122 return emptyLabelSignature 123 } 124 125 labelNames := make(LabelNames, 0, len(m)) 126 for labelName := range m { 127 if _, exclude := labels[labelName]; !exclude { 128 labelNames = append(labelNames, labelName) 129 } 130 } 131 if len(labelNames) == 0 { 132 return emptyLabelSignature 133 } 134 sort.Sort(labelNames) 135 136 sum := hashNew() 137 for _, labelName := range labelNames { 138 sum = hashAdd(sum, string(labelName)) 139 sum = hashAddByte(sum, SeparatorByte) 140 sum = hashAdd(sum, string(m[labelName])) 141 sum = hashAddByte(sum, SeparatorByte) 142 } 143 return sum 144 }