diff --git a/src/Prometheus.Client/LabelsHelper.cs b/src/Prometheus.Client/LabelsHelper.cs index 5ccd684a..75379930 100644 --- a/src/Prometheus.Client/LabelsHelper.cs +++ b/src/Prometheus.Client/LabelsHelper.cs @@ -61,19 +61,19 @@ int GetTupleSize(Type tupleType) #endif } - public static int GetHashCode(TTuple values) + public static int GetHashCode(TTuple values, int seed = 0) #if NET6_0_OR_GREATER where TTuple : struct, ITuple, IEquatable #else where TTuple : struct, IEquatable #endif { - return TupleHelper.GetTupleHashCode(values); + return TupleHelper.GetTupleHashCode(values, seed); } - public static int GetHashCode(IReadOnlyList values) + public static int GetHashCode(IReadOnlyList values, int seed = 0) { - var result = 0; + var result = seed; // ReSharper disable once ForCanBeConvertedToForeach // do not use for-each here, it allocates which is easy to avoid by for loop @@ -260,9 +260,9 @@ public static string[] ToArray(TTuple values) }); } - public static int GetTupleHashCode(TTuple values) + public static int GetTupleHashCode(TTuple values, int seed) { - return _hashCodeReducer(values, 0, (item, _, aggregated) => + return _hashCodeReducer(values, seed, (item, _, aggregated) => { if (item == null) throw new ArgumentException("Label value cannot be empty"); diff --git a/src/Prometheus.Client/MetricFamily.cs b/src/Prometheus.Client/MetricFamily.cs index a742a1d3..20bbae08 100644 --- a/src/Prometheus.Client/MetricFamily.cs +++ b/src/Prometheus.Client/MetricFamily.cs @@ -24,7 +24,7 @@ public sealed class MetricFamily : I private readonly IReadOnlyList _metricNames; private readonly Func, TImplementation> _instanceFactory; private readonly Lazy _unlabelled; - private readonly ConcurrentDictionary _labelledMetrics; + private readonly ConcurrentDictionary _labelledMetrics; public MetricFamily(TConfig configuration, MetricType metricType, Func, TImplementation> instanceFactory) { @@ -35,7 +35,7 @@ public MetricFamily(TConfig configuration, MetricType metricType, Func(() => _instanceFactory(_configuration, default)); LabelNames = LabelsHelper.FromArray(configuration.LabelNames); if (configuration.LabelNames.Count > 0) - _labelledMetrics = new ConcurrentDictionary(); + _labelledMetrics = new ConcurrentDictionary(); } public string Name => _configuration.Name; @@ -64,7 +64,7 @@ TMetric IMetricFamily.WithLabels(params string[] labels) if (labels.Length != _configuration.LabelNames.Count) throw new ArgumentException("Wrong number of labels"); - var key = LabelsHelper.GetHashCode(labels); + var key = new MetricKey(labels); if (_labelledMetrics.TryGetValue(key, out var metric)) { @@ -83,7 +83,7 @@ TMetric IMetricFamily.RemoveLabelled(params string[] labels) if (labels.Length != _configuration.LabelNames.Count) throw new ArgumentException("Wrong number of labels"); - var key = LabelsHelper.GetHashCode(labels); + var key = new MetricKey(labels); _labelledMetrics.TryRemove(key, out var removed); return removed; @@ -94,7 +94,7 @@ public TMetric WithLabels(TLabels labels) if (_labelledMetrics == null) throw new InvalidOperationException("Metric family does not have any labels"); - var key = LabelsHelper.GetHashCode(labels); + var key = new MetricKey(labels); if (_labelledMetrics.TryGetValue(key, out var metric)) { @@ -110,7 +110,7 @@ public TMetric RemoveLabelled(TLabels labels) if (_labelledMetrics == null) throw new InvalidOperationException("Metric family does not have any labels"); - var key = LabelsHelper.GetHashCode(labels); + var key = new MetricKey(labels); _labelledMetrics.TryRemove(key, out var removed); return removed; @@ -148,4 +148,32 @@ private IEnumerable, TMetric>> EnumerateLabel foreach (var labelled in _labelledMetrics) yield return new KeyValuePair, TMetric>(labelled.Value.LabelValues, labelled.Value); } + + private readonly struct MetricKey : IEquatable + { + private readonly int _hash1; + private readonly int _hash2; + + public MetricKey(TLabels labels) + { + _hash1 = LabelsHelper.GetHashCode(labels, 0); + _hash2 = LabelsHelper.GetHashCode(labels, 42); + } + + public MetricKey(params string[] labels) + { + _hash1 = LabelsHelper.GetHashCode(labels, 0); + _hash2 = LabelsHelper.GetHashCode(labels, 42); + } + + public override int GetHashCode() + { + return _hash1; + } + + public bool Equals(MetricKey other) + { + return _hash1 == other._hash1 && _hash2 == other._hash2; + } + } }