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