73 lines
1.2 KiB
Go
73 lines
1.2 KiB
Go
package local
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"git.zhangshuocauc.cn/redhat/goconsistencehash/local/os"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
type SpinLock struct {
|
|
mu sync.Mutex
|
|
token string
|
|
locked bool
|
|
expire time.Time
|
|
}
|
|
|
|
func NewSpinLock() *SpinLock {
|
|
return &SpinLock{}
|
|
}
|
|
|
|
func (s *SpinLock) tryLock(expire int) bool {
|
|
s.mu.Lock()
|
|
defer s.mu.Unlock()
|
|
|
|
now := time.Now()
|
|
if !s.locked || now.After(s.expire) {
|
|
s.locked = true
|
|
s.token = os.GetCurrentProcessAndGoroutineIDStr()
|
|
s.expire = now.Add(time.Duration(expire) * time.Second)
|
|
return true
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
func (s *SpinLock) Lock(ctx context.Context, expire int) error {
|
|
ticker := time.NewTicker(100 * time.Millisecond)
|
|
defer ticker.Stop()
|
|
|
|
for range ticker.C {
|
|
select {
|
|
case <-ctx.Done():
|
|
return ctx.Err()
|
|
default:
|
|
}
|
|
|
|
if s.tryLock(expire) {
|
|
return nil
|
|
}
|
|
}
|
|
|
|
return errors.New("try lock error")
|
|
}
|
|
|
|
func (s *SpinLock) UnLock(ctx context.Context) error {
|
|
s.mu.Lock()
|
|
defer s.mu.Unlock()
|
|
|
|
if s.token != os.GetCurrentProcessAndGoroutineIDStr() {
|
|
return errors.New("not my lock")
|
|
}
|
|
|
|
if !s.locked || time.Now().After(s.expire) {
|
|
return errors.New("try unlock an unlocked lock")
|
|
}
|
|
|
|
s.locked = false
|
|
s.token = ""
|
|
|
|
return nil
|
|
}
|