Repository: open-telemetry/opentelemetry-java
File: sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/state/DefaultSynchronousMetricStorage.java (Java)

Code before:
      newHandle = localAggregatorHolder.aggregator.createHandle();
    }
    handle = localAggregatorHolder.aggregatorHandles.putIfAbsent(attributes, newHandle);
    return handle != null ? handle : newHandle;
  }

  @Override
  public MetricData collect(
      Resource resource,
      InstrumentationScopeInfo instrumentationScopeInfo,
      long startEpochNanos,
      long epochNanos) {
    boolean reset = aggregationTemporality == DELTA;
    long start =
        aggregationTemporality == DELTA
            ? registeredReader.getLastCollectEpochNanos()
            : startEpochNanos;
    AggregatorHolder<T, U> holder = Objects.requireNonNull(this.aggregatorHolder.get());

    ConcurrentHashMap<Attributes, AggregatorHandle<T, U>> aggregatorHandles;
    if (reset) {
      AggregatorHolder<T, U> newHolder =
          (memoryMode == REUSABLE_DATA)
              ? new AggregatorHolder<>(holder.aggregator, previousCollectionAggregatorHandles)
              : new AggregatorHolder<>(holder.aggregator);
      // Otherwise, swapAggregator was called and the update should be ignored
      aggregatorHolder.compareAndSet(holder, newHolder);

      // Increment recordsInProgress by 1, which produces an odd number acting as a signal that
      // record operations should re-read the volatile this.aggregatorHolder.
      // Repeatedly grab recordsInProgress until it is <= 1, which signals all active record
      // operations are complete.
      int recordsInProgress = holder.activeRecordingThreads.addAndGet(1);
      while (recordsInProgress > 1) {
        recordsInProgress = holder.activeRecordingThreads.get();
      }
    }
    aggregatorHandles = holder.aggregatorHandles;

    List<T> points;
    if (memoryMode == REUSABLE_DATA) {
      reusableResultList.clear();
      points = reusableResultList;
    } else {
      points = new ArrayList<>(aggregatorHandles.size());
    }

    // In DELTA aggregation temporality each Attributes is reset to 0
    // every time we perform a collection (by definition of DELTA).
    // In IMMUTABLE_DATA MemoryMode, this is accomplished by removing all aggregator handles
    // (into which the values are recorded) effectively starting from 0

Review comment (bug):
```suggestion
      // If this fails, another thread called `setEnabled` and we can discard the current call
```

Code after:
    if (newHandle == null) {
      newHandle = aggregator.createHandle();
    }
    handle = aggregatorHandles.putIfAbsent(attributes, newHandle);
    return handle != null ? handle : newHandle;
  }

  @Override
  public MetricData collect(
      Resource resource,
      InstrumentationScopeInfo instrumentationScopeInfo,
      long startEpochNanos,
      long epochNanos) {
    boolean reset = aggregationTemporality == DELTA;
    long start =
        aggregationTemporality == DELTA
            ? registeredReader.getLastCollectEpochNanos()
            : startEpochNanos;

    ConcurrentHashMap<Attributes, AggregatorHandle<T, U>> aggregatorHandles;
    if (reset) {
      AggregatorHolder<T, U> holder = this.aggregatorHolder;
      this.aggregatorHolder =
          (memoryMode == REUSABLE_DATA)
              ? new AggregatorHolder<>(previousCollectionAggregatorHandles)
              : new AggregatorHolder<>();

      // Increment recordsInProgress by 1, which produces an odd number acting as a signal that
      // record operations should re-read the volatile this.aggregatorHolder.
      // Repeatedly grab recordsInProgress until it is <= 1, which signals all active record
      // operations are complete.
      int recordsInProgress = holder.activeRecordingThreads.addAndGet(1);
      while (recordsInProgress > 1) {
        recordsInProgress = holder.activeRecordingThreads.get();
      }
      aggregatorHandles = holder.aggregatorHandles;
    } else {
      aggregatorHandles = this.aggregatorHolder.aggregatorHandles;
    }

    List<T> points;
    if (memoryMode == REUSABLE_DATA) {
      reusableResultList.clear();
      points = reusableResultList;
    } else {
      points = new ArrayList<>(aggregatorHandles.size());
    }

    // In DELTA aggregation temporality each Attributes is reset to 0
    // every time we perform a collection (by definition of DELTA).
    // In IMMUTABLE_DATA MemoryMode, this is accomplished by removing all aggregator handles