github.com/Rookout/GoSDK@v0.1.48/pkg/utils/concurrent_map.go (about)

     1  package utils
     2  
     3  import (
     4  	"fmt"
     5  	"sync"
     6  )
     7  
     8  type ValueCreator func() (interface{}, error)
     9  
    10  type ConcurrentMap struct {
    11  	internalMap sync.Map
    12  }
    13  
    14  type onceWithValue struct {
    15  	once  sync.Once
    16  	value interface{}
    17  	err   error
    18  }
    19  
    20  func (m *ConcurrentMap) GetOrCreate(key interface{}, valueCreator ValueCreator) (actual interface{}, err error) {
    21  	
    22  	res, _ := m.internalMap.LoadOrStore(key, &onceWithValue{})
    23  	onceWithValue := res.(*onceWithValue)
    24  
    25  	onceWithValue.once.Do(func() {
    26  		defer func() {
    27  			if r := recover(); r != nil {
    28  				onceWithValue.err = fmt.Errorf("recovered from panic in value creator: %#v", r)
    29  				m.internalMap.Delete(key)
    30  			}
    31  		}()
    32  		value, err := valueCreator()
    33  		if err != nil {
    34  			onceWithValue.err = err
    35  			m.internalMap.Delete(key)
    36  			return
    37  		}
    38  
    39  		onceWithValue.value = value
    40  	})
    41  
    42  	return onceWithValue.value, onceWithValue.err
    43  }