From 0d6666aac2376576670d53203e7d49dbd95b162f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Deruss=C3=A9?= Date: Tue, 20 Apr 2021 22:05:20 +0200 Subject: [PATCH] Inline lua scripts used by semaphore --- .../Component/Semaphore/Store/RedisStore.php | 77 ++++++++++++++++++- .../Store/Resources/redis_delete.lua | 7 -- .../Resources/redis_put_off_expiration.lua | 20 ----- .../Semaphore/Store/Resources/redis_save.lua | 41 ---------- 4 files changed, 74 insertions(+), 71 deletions(-) delete mode 100644 src/Symfony/Component/Semaphore/Store/Resources/redis_delete.lua delete mode 100644 src/Symfony/Component/Semaphore/Store/Resources/redis_put_off_expiration.lua delete mode 100644 src/Symfony/Component/Semaphore/Store/Resources/redis_save.lua diff --git a/src/Symfony/Component/Semaphore/Store/RedisStore.php b/src/Symfony/Component/Semaphore/Store/RedisStore.php index a29addf0d9..1cf36443fd 100644 --- a/src/Symfony/Component/Semaphore/Store/RedisStore.php +++ b/src/Symfony/Component/Semaphore/Store/RedisStore.php @@ -50,7 +50,49 @@ class RedisStore implements PersistingStoreInterface 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 = [ $this->getUniqueToken($key), @@ -74,7 +116,28 @@ class RedisStore implements PersistingStoreInterface 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)]); @@ -94,7 +157,15 @@ class RedisStore implements PersistingStoreInterface */ 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)]); } diff --git a/src/Symfony/Component/Semaphore/Store/Resources/redis_delete.lua b/src/Symfony/Component/Semaphore/Store/Resources/redis_delete.lua deleted file mode 100644 index 1405a7a6bb..0000000000 --- a/src/Symfony/Component/Semaphore/Store/Resources/redis_delete.lua +++ /dev/null @@ -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) diff --git a/src/Symfony/Component/Semaphore/Store/Resources/redis_put_off_expiration.lua b/src/Symfony/Component/Semaphore/Store/Resources/redis_put_off_expiration.lua deleted file mode 100644 index b260a2e451..0000000000 --- a/src/Symfony/Component/Semaphore/Store/Resources/redis_put_off_expiration.lua +++ /dev/null @@ -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 diff --git a/src/Symfony/Component/Semaphore/Store/Resources/redis_save.lua b/src/Symfony/Component/Semaphore/Store/Resources/redis_save.lua deleted file mode 100644 index c0cbac5f5a..0000000000 --- a/src/Symfony/Component/Semaphore/Store/Resources/redis_save.lua +++ /dev/null @@ -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