Inline lua scripts used by semaphore

This commit is contained in:
Jérémy Derussé 2021-04-20 22:05:20 +02:00
parent 1ed5e0ca46
commit 0d6666aac2
No known key found for this signature in database
GPG Key ID: 2083FA5758C473D2
4 changed files with 74 additions and 71 deletions

View File

@ -50,7 +50,49 @@ class RedisStore implements PersistingStoreInterface
throw new InvalidArgumentException("The TTL should be greater than 0, '$ttlInSecond' given."); throw new InvalidArgumentException("The TTL should be greater than 0, '$ttlInSecond' given.");
} }
$script = file_get_contents(__DIR__.'/Resources/redis_save.lua'); $script = '
local key = KEYS[1]
local weightKey = key .. ":weight"
local timeKey = key .. ":time"
local identifier = ARGV[1]
local now = tonumber(ARGV[2])
local ttlInSecond = tonumber(ARGV[3])
local limit = tonumber(ARGV[4])
local weight = tonumber(ARGV[5])
-- Remove expired values
redis.call("ZREMRANGEBYSCORE", timeKey, "-inf", now)
redis.call("ZINTERSTORE", weightKey, 2, weightKey, timeKey, "WEIGHTS", 1, 0)
-- Semaphore already acquired?
if redis.call("ZSCORE", timeKey, identifier) then
return true
end
-- Try to get a semaphore
local semaphores = redis.call("ZRANGE", weightKey, 0, -1, "WITHSCORES")
local count = 0
for i = 1, #semaphores, 2 do
count = count + semaphores[i+1]
end
-- Could we get the semaphore ?
if count + weight > limit then
return false
end
-- Acquire the semaphore
redis.call("ZADD", timeKey, now + ttlInSecond, identifier)
redis.call("ZADD", weightKey, weight, identifier)
-- Extend the TTL
local maxExpiration = redis.call("ZREVRANGE", timeKey, 0, 0, "WITHSCORES")[2]
redis.call("EXPIREAT", weightKey, maxExpiration + 10)
redis.call("EXPIREAT", timeKey, maxExpiration + 10)
return true
';
$args = [ $args = [
$this->getUniqueToken($key), $this->getUniqueToken($key),
@ -74,7 +116,28 @@ class RedisStore implements PersistingStoreInterface
throw new InvalidArgumentException("The TTL should be greater than 0, '$ttlInSecond' given."); throw new InvalidArgumentException("The TTL should be greater than 0, '$ttlInSecond' given.");
} }
$script = file_get_contents(__DIR__.'/Resources/redis_put_off_expiration.lua'); $script = '
local key = KEYS[1]
local weightKey = key .. ":weight"
local timeKey = key .. ":time"
local added = redis.call("ZADD", timeKey, ARGV[1], ARGV[2])
if added == 1 then
redis.call("ZREM", timeKey, ARGV[2])
redis.call("ZREM", weightKey, ARGV[2])
end
-- Extend the TTL
local maxExpiration = redis.call("ZREVRANGE", timeKey, 0, 0, "WITHSCORES")[2]
if nil == maxExpiration then
return 1
end
redis.call("EXPIREAT", weightKey, maxExpiration + 10)
redis.call("EXPIREAT", timeKey, maxExpiration + 10)
return added
';
$ret = $this->evaluate($script, sprintf('{%s}', $key), [time() + $ttlInSecond, $this->getUniqueToken($key)]); $ret = $this->evaluate($script, sprintf('{%s}', $key), [time() + $ttlInSecond, $this->getUniqueToken($key)]);
@ -94,7 +157,15 @@ class RedisStore implements PersistingStoreInterface
*/ */
public function delete(Key $key) public function delete(Key $key)
{ {
$script = file_get_contents(__DIR__.'/Resources/redis_delete.lua'); $script = '
local key = KEYS[1]
local weightKey = key .. ":weight"
local timeKey = key .. ":time"
local identifier = ARGV[1]
redis.call("ZREM", timeKey, identifier)
return redis.call("ZREM", weightKey, identifier)
';
$this->evaluate($script, sprintf('{%s}', $key), [$this->getUniqueToken($key)]); $this->evaluate($script, sprintf('{%s}', $key), [$this->getUniqueToken($key)]);
} }

View File

@ -1,7 +0,0 @@
local key = KEYS[1]
local weightKey = key .. ":weight"
local timeKey = key .. ":time"
local identifier = ARGV[1]
redis.call("ZREM", timeKey, identifier)
return redis.call("ZREM", weightKey, identifier)

View File

@ -1,20 +0,0 @@
local key = KEYS[1]
local weightKey = key .. ":weight"
local timeKey = key .. ":time"
local added = redis.call("ZADD", timeKey, ARGV[1], ARGV[2])
if added == 1 then
redis.call("ZREM", timeKey, ARGV[2])
redis.call("ZREM", weightKey, ARGV[2])
end
-- Extend the TTL
local maxExpiration = redis.call("ZREVRANGE", timeKey, 0, 0, "WITHSCORES")[2]
if nil == maxExpiration then
return 1
end
redis.call("EXPIREAT", weightKey, maxExpiration + 10)
redis.call("EXPIREAT", timeKey, maxExpiration + 10)
return added

View File

@ -1,41 +0,0 @@
local key = KEYS[1]
local weightKey = key .. ":weight"
local timeKey = key .. ":time"
local identifier = ARGV[1]
local now = tonumber(ARGV[2])
local ttlInSecond = tonumber(ARGV[3])
local limit = tonumber(ARGV[4])
local weight = tonumber(ARGV[5])
-- Remove expired values
redis.call("ZREMRANGEBYSCORE", timeKey, "-inf", now)
redis.call("ZINTERSTORE", weightKey, 2, weightKey, timeKey, "WEIGHTS", 1, 0)
-- Semaphore already acquired?
if redis.call("ZSCORE", timeKey, identifier) then
return true
end
-- Try to get a semaphore
local semaphores = redis.call("ZRANGE", weightKey, 0, -1, "WITHSCORES")
local count = 0
for i = 1, #semaphores, 2 do
count = count + semaphores[i+1]
end
-- Could we get the semaphore ?
if count + weight > limit then
return false
end
-- Acquire the semaphore
redis.call("ZADD", timeKey, now + ttlInSecond, identifier)
redis.call("ZADD", weightKey, weight, identifier)
-- Extend the TTL
local maxExpiration = redis.call("ZREVRANGE", timeKey, 0, 0, "WITHSCORES")[2]
redis.call("EXPIREAT", weightKey, maxExpiration + 10)
redis.call("EXPIREAT", timeKey, maxExpiration + 10)
return true