1 Star 2 Fork 3

周小猪/go-redisson

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
redlock.go 3.21 KB
一键复制 编辑 原始数据 按行查看 历史
zhouyangzhi 提交于 2021-11-13 15:15 +08:00 . redLock
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
}
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
Go
1
https://gitee.com/zhouxiaozhu/go-redisson.git
git@gitee.com:zhouxiaozhu/go-redisson.git
zhouxiaozhu
go-redisson
go-redisson
master

搜索帮助