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 }