github.com/qgxpagamentos/mapmutex@v0.0.0-20200716162114-c133e97096b7/mutex.go (about) 1 package mapmutex 2 3 import ( 4 "math/rand" 5 "sync" 6 "time" 7 ) 8 9 // Mutex is the mutex with synchronized map 10 // it's for reducing unnecessary locks among different keys 11 type Mutex struct { 12 locks map[interface{}]interface{} 13 m *sync.Mutex 14 maxRetry int 15 maxDelay float64 // in nanosend 16 baseDelay float64 // in nanosecond 17 factor float64 18 jitter float64 19 } 20 21 // TryLock tries to aquire the lock. 22 func (m *Mutex) TryLock(key interface{}) (gotLock bool) { 23 for i := 0; i < m.maxRetry; i++ { 24 m.m.Lock() 25 if _, ok := m.locks[key]; ok { // if locked 26 m.m.Unlock() 27 time.Sleep(m.backoff(i)) 28 } else { // if unlock, lockit 29 m.locks[key] = struct{}{} 30 m.m.Unlock() 31 return true 32 } 33 } 34 35 return false 36 } 37 38 // Unlock unlocks for the key 39 // please call Unlock only after having aquired the lock 40 func (m *Mutex) Unlock(key interface{}) { 41 m.m.Lock() 42 delete(m.locks, key) 43 m.m.Unlock() 44 } 45 46 // borrowed from grpc 47 func (m *Mutex) backoff(retries int) time.Duration { 48 if retries == 0 { 49 return time.Duration(m.baseDelay) * time.Nanosecond 50 } 51 backoff, max := m.baseDelay, m.maxDelay 52 for backoff < max && retries > 0 { 53 backoff *= m.factor 54 retries-- 55 } 56 if backoff > max { 57 backoff = max 58 } 59 backoff *= 1 + m.jitter*(rand.Float64()*2-1) 60 if backoff < 0 { 61 return 0 62 } 63 return time.Duration(backoff) * time.Nanosecond 64 } 65 66 // NewMapMutex returns a mapmutex with default configs 67 func NewMapMutex() *Mutex { 68 return &Mutex{ 69 locks: make(map[interface{}]interface{}), 70 m: &sync.Mutex{}, 71 maxRetry: 200, 72 maxDelay: 100000000, // 0.1 second 73 baseDelay: 10, // 10 nanosecond 74 factor: 1.1, 75 jitter: 0.2, 76 } 77 } 78 79 // NewCustomizedMapMutex returns a customized mapmutex 80 func NewCustomizedMapMutex(mRetry int, mDelay, bDelay, factor, jitter float64) *Mutex { 81 return &Mutex{ 82 locks: make(map[interface{}]interface{}), 83 m: &sync.Mutex{}, 84 maxRetry: mRetry, 85 maxDelay: mDelay, 86 baseDelay: bDelay, 87 factor: factor, 88 jitter: jitter, 89 } 90 }