blob: 2555e5599110c72b43f02c1c5df5b1f69c60b614 [file] [log] [blame]
Girish Gowdra3d633032019-12-10 16:37:05 +05301package mapmutex
2
3import (
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
11type 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.
22func (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
40func (m *Mutex) Unlock(key interface{}) {
41 m.m.Lock()
42 delete(m.locks, key)
43 m.m.Unlock()
44}
45
46// borrowed from grpc
47func (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
67func 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
80func 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}