refactor(locker script): optimize of redis locker script
1.optimize locker script of un read lock
fix(locker_refresh): fix bug of locker refresh
1.fix bug of locker refresh when locker lock success after wait
test(lock_case): add new redis locker case
1.add new redis locker case
This commit is contained in:
parent
fda43c65d2
commit
d27a9bbafa
|
|
@ -79,10 +79,10 @@ elseif (mode == 'write') then
|
||||||
return -2;
|
return -2;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
-- 判断当前的确是读模式但是当前 token 并没有加读锁的情况,返回 1
|
-- 判断当前的确是读模式但是当前 token 并没有加读锁的情况,返回 0
|
||||||
local lockExists = redis.call('hexists', KEYS[1], lockKey);
|
local lockExists = redis.call('hexists', KEYS[1], lockKey);
|
||||||
if ((mode == 'read') and (lockExists == 0)) then
|
if ((mode == 'read') and (lockExists == 0)) then
|
||||||
return 1;
|
return 0;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
local counter = redis.call('hincrby', KEYS[1], lockKey, -1);
|
local counter = redis.call('hincrby', KEYS[1], lockKey, -1);
|
||||||
|
|
|
||||||
|
|
@ -167,7 +167,10 @@ func (rl *redissionLocker) cancelRefreshLockTime() {
|
||||||
|
|
||||||
func (rl *redissionLocker) closeSub(sub *redis.PubSub, noticeChan chan struct{}) {
|
func (rl *redissionLocker) closeSub(sub *redis.PubSub, noticeChan chan struct{}) {
|
||||||
if sub != nil {
|
if sub != nil {
|
||||||
sub.Close()
|
err := sub.Close()
|
||||||
|
if err != nil {
|
||||||
|
rl.logger.Error("close sub failed", zap.String("token", rl.token), zap.String("key", rl.key), zap.Error(err))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if noticeChan != nil {
|
if noticeChan != nil {
|
||||||
|
|
|
||||||
|
|
@ -74,6 +74,17 @@ func (rl *RedissionRWLocker) RLock(ctx context.Context, timeout ...time.Duration
|
||||||
if result.Code == constant.LockSuccess {
|
if result.Code == constant.LockSuccess {
|
||||||
rl.logger.Info(result.OutputResultMessage())
|
rl.logger.Info(result.OutputResultMessage())
|
||||||
rl.closeSub(sub, rl.subExitChan)
|
rl.closeSub(sub, rl.subExitChan)
|
||||||
|
|
||||||
|
if rl.needRefresh {
|
||||||
|
rl.refreshOnce.Do(func() {
|
||||||
|
if rl.refreshExitChan == nil {
|
||||||
|
rl.refreshExitChan = make(chan struct{})
|
||||||
|
}
|
||||||
|
|
||||||
|
// async refresh lock timeout unitl receive exit singal
|
||||||
|
go rl.refreshLockTimeout(ctx)
|
||||||
|
})
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
case <-acquireTimer.C:
|
case <-acquireTimer.C:
|
||||||
|
|
@ -206,6 +217,17 @@ func (rl *RedissionRWLocker) WLock(ctx context.Context, timeout ...time.Duration
|
||||||
if result.Code == constant.LockSuccess {
|
if result.Code == constant.LockSuccess {
|
||||||
rl.logger.Info(result.OutputResultMessage())
|
rl.logger.Info(result.OutputResultMessage())
|
||||||
rl.closeSub(sub, rl.subExitChan)
|
rl.closeSub(sub, rl.subExitChan)
|
||||||
|
|
||||||
|
if rl.needRefresh {
|
||||||
|
rl.refreshOnce.Do(func() {
|
||||||
|
if rl.refreshExitChan == nil {
|
||||||
|
rl.refreshExitChan = make(chan struct{})
|
||||||
|
}
|
||||||
|
|
||||||
|
// async refresh lock timeout unitl receive exit singal
|
||||||
|
go rl.refreshLockTimeout(ctx)
|
||||||
|
})
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
case <-acquireTimer.C:
|
case <-acquireTimer.C:
|
||||||
|
|
|
||||||
|
|
@ -526,7 +526,6 @@ func TestRWLock2CWithRLockAndWLockSucceed(t *testing.T) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO 设计两个客户端,C1先加写锁与C2后加读锁
|
|
||||||
func TestRWLock2CWithWLockAndRLock(t *testing.T) {
|
func TestRWLock2CWithWLockAndRLock(t *testing.T) {
|
||||||
ctx := context.TODO()
|
ctx := context.TODO()
|
||||||
|
|
||||||
|
|
@ -547,7 +546,7 @@ func TestRWLock2CWithWLockAndRLock(t *testing.T) {
|
||||||
rwLocker2.logger = log
|
rwLocker2.logger = log
|
||||||
|
|
||||||
duration := 10 * time.Second
|
duration := 10 * time.Second
|
||||||
// locker1加读锁
|
// locker1加写锁
|
||||||
err := rwLocker1.WLock(ctx, duration)
|
err := rwLocker1.WLock(ctx, duration)
|
||||||
assert.Equal(t, nil, err)
|
assert.Equal(t, nil, err)
|
||||||
|
|
||||||
|
|
@ -556,14 +555,25 @@ func TestRWLock2CWithWLockAndRLock(t *testing.T) {
|
||||||
assert.Equal(t, nil, err)
|
assert.Equal(t, nil, err)
|
||||||
assert.Equal(t, 1, num)
|
assert.Equal(t, 1, num)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
// locker1解写锁
|
||||||
|
time.Sleep(10 * time.Second)
|
||||||
|
err = rwLocker1.UnWLock(ctx)
|
||||||
|
assert.Equal(t, nil, err)
|
||||||
|
}()
|
||||||
|
|
||||||
// locker2加读锁
|
// locker2加读锁
|
||||||
duration = 2 * time.Second
|
duration = 30 * time.Second
|
||||||
err = rwLocker2.RLock(ctx, duration)
|
err = rwLocker2.RLock(ctx, duration)
|
||||||
// TODO 预测加读锁失败
|
|
||||||
assert.Equal(t, nil, err)
|
assert.Equal(t, nil, err)
|
||||||
|
|
||||||
// locker1解写锁
|
tokenKey2 := strings.Join([]string{rwLocker2.rwTokenTimeoutPrefix, rwLocker2.token}, ":")
|
||||||
err = rwLocker1.UnWLock(ctx)
|
num, err = rdb.HGet(ctx, rwLocker2.key, tokenKey2).Int()
|
||||||
|
assert.Equal(t, nil, err)
|
||||||
|
assert.Equal(t, 1, num)
|
||||||
|
|
||||||
|
// locker2解读锁
|
||||||
|
err = rwLocker2.UnRLock(ctx)
|
||||||
assert.Equal(t, nil, err)
|
assert.Equal(t, nil, err)
|
||||||
|
|
||||||
t.Log("rwLock 2 client lock test success")
|
t.Log("rwLock 2 client lock test success")
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue