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  }