/
dmutex_options.go
123 lines (107 loc) · 3.56 KB
/
dmutex_options.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
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
package dsync
import (
"fmt"
"git.golaxy.org/core"
"git.golaxy.org/core/util/generic"
"git.golaxy.org/core/util/option"
"git.golaxy.org/core/util/uid"
"math/rand"
"time"
)
type (
// A DelayFunc is used to decide the amount of time to wait between retries.
DelayFunc = generic.Func1[int, time.Duration]
// GenValueFunc is used to generate a random value.
GenValueFunc = generic.PairFunc0[string, error]
)
// DistMutexOptions represents the options for acquiring a distributed mutex.
type DistMutexOptions struct {
Expiry time.Duration
Tries int
DelayFunc DelayFunc
DriftFactor float64
TimeoutFactor float64
GenValueFunc GenValueFunc
Value string
}
var With _Option
type _Option struct{}
// Default sets the default options for acquiring a distributed mutex.
func (_Option) Default() option.Setting[DistMutexOptions] {
defaultRetryDelayFunc := func(tries int) time.Duration {
const (
minRetryDelayMilliSec = 10
maxRetryDelayMilliSec = 150
)
return time.Duration(rand.Intn(maxRetryDelayMilliSec-minRetryDelayMilliSec)+minRetryDelayMilliSec) * time.Millisecond
}
defaultGenValueFunc := func() (string, error) {
return string(uid.New()), nil
}
return func(options *DistMutexOptions) {
With.Expiry(3 * time.Second)(options)
With.Tries(15)(options)
With.RetryDelayFunc(defaultRetryDelayFunc)(options)
With.DriftFactor(0.01)(options)
With.TimeoutFactor(0.10)(options)
With.GenValueFunc(defaultGenValueFunc)(options)
With.Value("")(options)
}
}
// Expiry can be used to set the expiry of a mutex to the given value.
func (_Option) Expiry(expiry time.Duration) option.Setting[DistMutexOptions] {
return func(options *DistMutexOptions) {
options.Expiry = expiry
}
}
// Tries can be used to set the number of times lock acquire is attempted.
func (_Option) Tries(tries int) option.Setting[DistMutexOptions] {
return func(options *DistMutexOptions) {
options.Tries = tries
}
}
// RetryDelay can be used to set the amount of time to wait between retries.
func (_Option) RetryDelay(delay time.Duration) option.Setting[DistMutexOptions] {
return func(options *DistMutexOptions) {
options.DelayFunc = func(tries int) time.Duration {
return delay
}
}
}
// RetryDelayFunc can be used to override default delay behavior.
func (_Option) RetryDelayFunc(fn DelayFunc) option.Setting[DistMutexOptions] {
return func(options *DistMutexOptions) {
if fn == nil {
panic(fmt.Errorf("%w: option DelayFunc can't be assigned to nil", core.ErrArgs))
}
options.DelayFunc = fn
}
}
// DriftFactor can be used to set the clock drift factor.
func (_Option) DriftFactor(factor float64) option.Setting[DistMutexOptions] {
return func(options *DistMutexOptions) {
options.DriftFactor = factor
}
}
// TimeoutFactor can be used to set the timeout factor.
func (_Option) TimeoutFactor(factor float64) option.Setting[DistMutexOptions] {
return func(options *DistMutexOptions) {
options.TimeoutFactor = factor
}
}
// GenValueFunc can be used to set the custom value generator.
func (_Option) GenValueFunc(fn GenValueFunc) option.Setting[DistMutexOptions] {
return func(options *DistMutexOptions) {
if fn == nil {
panic(fmt.Errorf("%w: option GenValueFunc can't be assigned to nil", core.ErrArgs))
}
options.GenValueFunc = fn
}
}
// Value can be used to assign the random value without having to call lock.
// This allows the ownership of a lock to be "transferred" and allows the lock to be unlocked from elsewhere.
func (_Option) Value(v string) option.Setting[DistMutexOptions] {
return func(options *DistMutexOptions) {
options.Value = v
}
}