diff --git a/sdk/metric/controller/basic/controller.go b/sdk/metric/controller/basic/controller.go index 7621f78e59c..5579751be46 100644 --- a/sdk/metric/controller/basic/controller.go +++ b/sdk/metric/controller/basic/controller.go @@ -57,7 +57,7 @@ var ErrControllerStarted = fmt.Errorf("controller already started") // be blocked by a pull request in the basic controller. type Controller struct { lock sync.Mutex - libraries map[instrumentation.Library]*registry.UniqueInstrumentMeterImpl + libraries sync.Map // a map[instrumentation.Library]*initMeterOnce checkpointerFactory export.CheckpointerFactory resource *resource.Resource @@ -76,6 +76,11 @@ type Controller struct { collectedTime time.Time } +type initMeterOnce struct { + unique *registry.UniqueInstrumentMeterImpl + initOnce sync.Once +} + var _ export.InstrumentationLibraryReader = &Controller{} var _ metric.MeterProvider = &Controller{} @@ -87,21 +92,20 @@ func (c *Controller) Meter(instrumentationName string, opts ...metric.MeterOptio SchemaURL: cfg.SchemaURL(), } - c.lock.Lock() - defer c.lock.Unlock() - m, ok := c.libraries[library] - if !ok { + newTmp := &initMeterOnce{} + m, _ := c.libraries.LoadOrStore(library, newTmp) + mo := m.(*initMeterOnce) + mo.initOnce.Do(func() { checkpointer := c.checkpointerFactory.NewCheckpointer() accumulator := sdk.NewAccumulator(checkpointer) - m = registry.NewUniqueInstrumentMeterImpl(&accumulatorCheckpointer{ + mo.unique = registry.NewUniqueInstrumentMeterImpl(&accumulatorCheckpointer{ Accumulator: accumulator, checkpointer: checkpointer, library: library, }) + }) - c.libraries[library] = m - } - return metric.WrapMeterImpl(m) + return metric.WrapMeterImpl(mo.unique) } type accumulatorCheckpointer struct { @@ -132,7 +136,6 @@ func New(checkpointerFactory export.CheckpointerFactory, opts ...Option) *Contro } } return &Controller{ - libraries: map[instrumentation.Library]*registry.UniqueInstrumentMeterImpl{}, checkpointerFactory: checkpointerFactory, exporter: c.Exporter, resource: c.Resource, @@ -249,12 +252,14 @@ func (c *Controller) accumulatorList() []*accumulatorCheckpointer { defer c.lock.Unlock() var r []*accumulatorCheckpointer - for _, entry := range c.libraries { - acc, ok := entry.MeterImpl().(*accumulatorCheckpointer) + c.libraries.Range(func(_, value interface{}) bool { + mo := value.(*initMeterOnce) + acc, ok := mo.unique.MeterImpl().(*accumulatorCheckpointer) if ok { r = append(r, acc) } - } + return true + }) return r }