-
Notifications
You must be signed in to change notification settings - Fork 0
/
lock.go
106 lines (93 loc) · 2.86 KB
/
lock.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
package cq
import (
"sync"
"time"
)
// LockValue reprecents the value an expiration of a lock for a key.
type LockValue[T interface{}] struct {
Value T
ExpiresAt time.Time
}
// IsExpired checks if the lock is expired.
func (lv LockValue[T]) IsExpired() bool {
exp := lv.ExpiresAt
if exp.IsZero() {
// No expire time for lock, assume forever.
exp = time.Now().Add(1 * time.Second)
}
return exp.Before(time.Now())
}
// Locker reprecents a lock manager.
type Locker[T interface{}] interface {
Exists(key string) bool
Get(key string) (LockValue[T], bool)
Aquire(key string, lock LockValue[T]) bool
Release(key string) bool
ForceRelease(key string)
}
// MemoryLocker is memory-based Locker implementation utilizing sync map.
type MemoryLocker[T any] struct {
locks sync.Map
}
// NewMemoryLocker creates a new MemoryLocker instance for a type.
// The type, T, reprecents the type of Value for a LockValue.
func NewMemoryLocker[T interface{}]() *MemoryLocker[T] {
return &MemoryLocker[T]{}
}
// NewUniqueMemoryLocker creates a new MemoryLocker instance for
// use with WithUnique... simply for quicker setup.
func NewUniqueMemoryLocker() *MemoryLocker[struct{}] {
return NewMemoryLocker[struct{}]()
}
// NewOverlapMemoryLocker creates a new MemoryLocker instance for
// use with WithoutOverlap... simply for quicker setup.
func NewOverlapMemoryLocker() *MemoryLocker[*sync.Mutex] {
return NewMemoryLocker[*sync.Mutex]()
}
// Get will load a lock from key.
// It will return a lock and a boolean reprecenting existance.
// Should a lock not exist for the key, an empty LockValue will be
// returned.
func (ml *MemoryLocker[T]) Get(key string) (LockValue[T], bool) {
lock, ok := ml.locks.Load(key)
if !ok {
return LockValue[T]{}, ok
}
lv := lock.(LockValue[T])
return lv, ok
}
// Exists will check if a LockValue exists for a key.
func (ml *MemoryLocker[T]) Exists(key string) (ok bool) {
_, ok = ml.Get(key)
return
}
// Aquire will attempt to aquire a lock for a given key.
// If a lock exists, and the expiration is in future, it will not
// allow for a new lock.
// If a lock exists, and the expiration is past, it will allow
// for a new lock.
// If a lock does not exist, it will allow for a new lock.
func (ml *MemoryLocker[T]) Aquire(key string, lock LockValue[T]) bool {
if lock, ok := ml.Get(key); ok {
if !lock.IsExpired() {
return false
}
}
ml.locks.Store(key, lock)
return true
}
// Release will attempt to remove the lock for a given key.
// If a lock exists for a given key, it will release (remove) it
// and return true.
// If a lock does not exist for a given key, it will return false.
func (ml *MemoryLocker[T]) Release(key string) bool {
if !ml.Exists(key) {
return false
}
ml.ForceRelease(key)
return true
}
// ForceRelease will release (remove) a lock for a given key.
func (ml *MemoryLocker[T]) ForceRelease(key string) {
ml.locks.Delete(key)
}