95 lines
1.5 KiB
Go
95 lines
1.5 KiB
Go
// Package redis is a redis implemenation of lock
|
|
package redis
|
|
|
|
import (
|
|
"errors"
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/go-redsync/redsync"
|
|
"github.com/micro/go-micro/sync/lock"
|
|
)
|
|
|
|
type redisLock struct {
|
|
sync.Mutex
|
|
|
|
locks map[string]*redsync.Mutex
|
|
opts lock.Options
|
|
c *redsync.Redsync
|
|
}
|
|
|
|
func (r *redisLock) Acquire(id string, opts ...lock.AcquireOption) error {
|
|
var options lock.AcquireOptions
|
|
for _, o := range opts {
|
|
o(&options)
|
|
}
|
|
|
|
var ropts []redsync.Option
|
|
|
|
if options.Wait > time.Duration(0) {
|
|
ropts = append(ropts, redsync.SetRetryDelay(options.Wait))
|
|
ropts = append(ropts, redsync.SetTries(1))
|
|
}
|
|
|
|
if options.TTL > time.Duration(0) {
|
|
ropts = append(ropts, redsync.SetExpiry(options.TTL))
|
|
}
|
|
|
|
m := r.c.NewMutex(r.opts.Prefix+id, ropts...)
|
|
err := m.Lock()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
r.Lock()
|
|
r.locks[id] = m
|
|
r.Unlock()
|
|
|
|
return nil
|
|
}
|
|
|
|
func (r *redisLock) Release(id string) error {
|
|
r.Lock()
|
|
defer r.Unlock()
|
|
m, ok := r.locks[id]
|
|
if !ok {
|
|
return errors.New("lock not found")
|
|
}
|
|
|
|
unlocked := m.Unlock()
|
|
delete(r.locks, id)
|
|
|
|
if !unlocked {
|
|
return errors.New("lock not unlocked")
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (r *redisLock) String() string {
|
|
return "redis"
|
|
}
|
|
|
|
func NewLock(opts ...lock.Option) lock.Lock {
|
|
var options lock.Options
|
|
for _, o := range opts {
|
|
o(&options)
|
|
}
|
|
|
|
nodes := options.Nodes
|
|
|
|
if len(nodes) == 0 {
|
|
nodes = []string{"127.0.0.1:6379"}
|
|
}
|
|
|
|
rpool := redsync.New([]redsync.Pool{&pool{
|
|
addrs: nodes,
|
|
}})
|
|
|
|
return &redisLock{
|
|
locks: make(map[string]*redsync.Mutex),
|
|
opts: options,
|
|
c: rpool,
|
|
}
|
|
}
|