modelRT/distributedlock/luascript/rlock_script.go

108 lines
3.7 KiB
Go
Raw Normal View History

// Package luascript defines the lua script used for redis distributed lock
package luascript
// RlockScript is the lua script for the lock read lock command
/*
KEYS[1]锁的键名key,通常是锁的唯一标识
KEYS[2]锁的超时键名前缀rwTimeoutPrefix,用于存储每个读锁的超时键
ARGV[1]锁的过期时间lockLeaseTime,单位为毫秒
ARGV[2]当前客户端的唯一标识token,用于区分不同的客户端
*/
var RlockScript = `local mode = redis.call('hget', KEYS[1], 'mode');
local lockKey = KEYS[2] .. ARGV[2];
if (mode == false) then
redis.call('hset', KEYS[1], 'mode', 'read');
redis.call('hset', KEYS[1], lockKey, '1');
redis.call('hexpire', KEYS[1], ARGV[1] 'fields' '1' lockKey);
redis.call('expire', KEYS[1], ARGV[1]);
return 1;
end;
if (mode == 'write') then
return -1;
end;
if (mode == 'read') then
if (redis.call('exists', KEYS[1], ARGV[2]) == 1) then
redis.call('hincrby', KEYS[1], lockKey, '1');
local remainTime = redis.call('httl', KEYS[1], 'fields', '1', lockKey);
redis.call('hexpire', key, math.max(remainTime, ARGV[1]));
else
redis.call('hset', KEYS[1], lockKey, '1');
redis.call('hexpire', KEYS[1], lockKey, ARGV[1]);
end;
local cursor = 0;
local maxRemainTime = tonumber(ARGV[1]);
local pattern = KEYS[2] .. ':*';
repeat
local hscanResult = redis.call('hscan', KEYS[1], cursor, 'match', pattern, 'count', '100');
cursor = tonumber(hscanResult[1]);
local fields = hscanResult[2];
for i = 1, #fields,2 do
local field = fields[i];
local remainTime = redis.call('httl', KEYS[1], 'fields', '1', field);
maxRemainTime = math.max(tonumber(remainTime[1]), maxRemainTime);
end;
until cursor == 0;
local remainTime = redis.call('ttl', KEYS[1]);
redis.call('expire', KEYS[1], math.max(tonumber(remainTime),maxRemainTime));
return 1;
end;
`
// TODO 优化读锁解锁语句
// UnRlockScript is the lua script for the unlock read lock command
/*
KEYS[1]:锁的键名key,通常是锁的唯一标识
KEYS[2]:锁的释放通知频道chankey,用于通知其他客户端锁已释放
KEYS[3]:锁的超时键名前缀rwTimeoutTokenPrefix,用于存储每个读锁的超时键
KEYS[4]:锁的超时键名前缀prefixKey,用于存储每个读锁的超时键
ARGV[1]:解锁消息unlockMessage,用于通知其他客户端锁已释放
ARGV[2]:当前客户端的唯一标识token,用于区分不同的客户端
*/
var UnRlockScript = `local mode = redis.call('hget', KEYS[1], 'mode');
if (mode == false) then
redis.call('publish', KEYS[2], ARGV[1]);
return 1;
end;
local lockExists = redis.call('hexists', KEYS[1], ARGV[2]);
if (lockExists == 0) then
return nil;
end;
local counter = redis.call('hincrby', KEYS[1], ARGV[2], -1);
if (counter == 0) then
redis.call('hdel', KEYS[1], ARGV[2]);
end;
redis.call('del', KEYS[3] .. ':' .. (counter+1));
if (redis.call('hlen', KEYS[1]) > 1) then
local maxRemainTime = -3;
local keys = redis.call('hkeys', KEYS[1]);
for n, key in ipairs(keys) do
counter = tonumber(redis.call('hget', KEYS[1], key));
if type(counter) == 'number' then
for i=counter, 1, -1 do
local remainTime = redis.call('ttl', KEYS[4] .. ':' .. key .. ':rwlock_timeout:' .. i);
maxRemainTime = math.max(remainTime, maxRemainTime);
end;
end;
end;
if maxRemainTime > 0 then
redis.call('pexpire', KEYS[1], maxRemainTime);
return 0;
end;
if mode == 'write' then
return 0;
end;
end;
redis.call('del', KEYS[1]);
redis.call('publish', KEYS[2], ARGV[1]);
return 1;
`