Skip to content

Commit

Permalink
[sdk-metrics] Fix a race condition when a metric is deactivated and r…
Browse files Browse the repository at this point in the history
…e-activated in the same collection cycle (#5908)

Co-authored-by: Piotr Kiełkowicz <[email protected]>
  • Loading branch information
CodeBlanch and Kielek authored Oct 21, 2024
1 parent 0eebf97 commit 25a9366
Showing 1 changed file with 8 additions and 4 deletions.
12 changes: 8 additions & 4 deletions src/OpenTelemetry/Metrics/Reader/MetricReaderExt.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ namespace OpenTelemetry.Metrics;
public abstract partial class MetricReader
{
private readonly HashSet<string> metricStreamNames = new(StringComparer.OrdinalIgnoreCase);
private readonly ConcurrentDictionary<MetricStreamIdentity, Metric> instrumentIdentityToMetric = new();
private readonly ConcurrentDictionary<MetricStreamIdentity, Metric?> instrumentIdentityToMetric = new();
private readonly Lock instrumentCreationLock = new();
private int metricLimit;
private int cardinalityLimit;
Expand Down Expand Up @@ -201,7 +201,7 @@ internal void ApplyParentProviderSettings(

private bool TryGetExistingMetric(in MetricStreamIdentity metricStreamIdentity, [NotNullWhen(true)] out Metric? existingMetric)
=> this.instrumentIdentityToMetric.TryGetValue(metricStreamIdentity, out existingMetric)
&& existingMetric.Active;
&& existingMetric != null && existingMetric.Active;

private void CreateOrUpdateMetricStreamRegistration(in MetricStreamIdentity metricStreamIdentity)
{
Expand Down Expand Up @@ -268,8 +268,12 @@ private void RemoveMetric(ref Metric? metric)

OpenTelemetrySdkEventSource.Log.MetricInstrumentRemoved(metric!.Name, metric.MeterName);

var result = this.instrumentIdentityToMetric.TryRemove(metric.InstrumentIdentity, out var _);
Debug.Assert(result, "result was false");
// Note: This is using TryUpdate and NOT TryRemove because there is a
// race condition. If a metric is deactivated and then reactivated in
// the same collection cycle
// instrumentIdentityToMetric[metric.InstrumentIdentity] may already
// point to the new activated metric and not the old deactivated one.
this.instrumentIdentityToMetric.TryUpdate(metric.InstrumentIdentity, null, metric);

// Note: metric is a reference to the array storage so
// this clears the metric out of the array.
Expand Down

0 comments on commit 25a9366

Please sign in to comment.