goconsistencehash/local/spinlock.go
2025-05-07 10:34:10 +08:00

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
}