代码拉取完成,页面将自动刷新
package redisson
import (
"errors"
"github.com/go-redis/redis"
"github.com/sirupsen/logrus"
"sync"
"time"
)
const (
// MaximumResponseTimeLimit 最大响应时间
MaximumResponseTimeLimit = 10 * time.Second
)
// redLockScript ...
var redLockScript = redis.NewScript(`
// 首先分布式锁的KEY不能存在,如果确实不存在,那么执行hset命令(hset REDLOCK_KEY uuid+threadId 1),并通过pexpire设置失效时间(也是锁的租约时间)
if (redis.call('exists', KEYS[1]) == 0) then
redis.call('hset', KEYS[1], ARGV[2], 1);
redis.call('pexpire', KEYS[1], ARGV[1]);
return nil;
end;
// 如果分布式锁的KEY已经存在,并且value也匹配,表示是当前线程持有的锁,那么重入次数加1,并且设置失效时间
if (redis.call('hexists', KEYS[1], ARGV[2]) == 1) then
redis.call('hincrby', KEYS[1], ARGV[2], 1);
redis.call('pexpire', KEYS[1], ARGV[1]);
return nil;
end;
// 获取分布式锁的KEY的失效时间毫秒数
return redis.call('pttl', KEYS[1]);
`)
// redLock ...
var redLock = &RedLock{
once: &sync.Once{},
}
// RedLock ...
type RedLock struct {
once *sync.Once
mutex *sync.Mutex
name string
rLocks []*RLock
}
// NewRedLock ...
func NewRedLock(name string, rLocks ...*RLock) *RedLock {
// 赋值有效锁
var newRLocks []*RLock
for _, rLock := range rLocks {
if rLock != nil {
newRLocks = append(newRLocks, rLock)
}
}
redLock.once.Do(func() {
redLock = &RedLock{
mutex: &sync.Mutex{},
name: name,
rLocks: newRLocks,
}
})
return redLock
}
// Lock ...
func (redLock *RedLock) Lock() error {
var errNilSli []error
redLock.mutex.Lock()
defer redLock.mutex.Unlock()
for _, rLock := range redLock.rLocks {
if rLock == nil {
continue
}
startTime := time.Now()
err := rLock.Lock(rLock.name)
// 响应时间小于指定时间
responseTime := time.Now().Sub(startTime)
if err == nil && responseTime < MaximumResponseTimeLimit {
errNilSli = append(errNilSli, err)
}
}
// 过半节点加锁成功
argsLen := len(redLock.rLocks)
argsExpect := argsLen/2 + 1
if len(errNilSli) >= argsExpect {
return nil
}
return errors.New("lock fail")
}
// TryLock ...
func (redLock *RedLock) TryLock() error {
var errSli []error
var tryCh = make(chan error, 2)
redLock.mutex.Lock()
defer redLock.mutex.Unlock()
rLockLen := len(redLock.rLocks)
for i := 0; i < rLockLen; i++ {
go func(rLock *RLock) {
tryCh <- rLock.TryLock(rLock.name)
}(redLock.rLocks[i])
}
// 堵塞等待
for i := 0; i < rLockLen; i++ {
ret := <-tryCh
if ret == nil {
errSli = append(errSli, nil)
}
}
// 过半节点加锁成功
argsLen := len(redLock.rLocks)
argsExpect := argsLen/2 + 1
if len(errSli) >= argsExpect {
return nil
}
return errors.New("lock fail")
}
// UnLock ...
func (redLock *RedLock) UnLock() error {
expiration := int64(LockExpiration) / 1000 / 1000
redLock.mutex.Lock()
defer redLock.mutex.Unlock()
ret, err := rUnlockScript.Run(rLock.rdb, []string{rLock.name, LockReleaseChannel}, LockReleaseFlag, expiration, rLock.uniqueId()).Result()
if err != nil {
logrus.Error(err)
return err
}
logrus.Infof("unlock name=%s field=%s code=%v msg=%s", rLock.name, rLock.uniqueId(), ret, rUnlockMsg[ret.(int64)])
return nil
}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。