diff --git a/src/Symfony/Component/Lock/CHANGELOG.md b/src/Symfony/Component/Lock/CHANGELOG.md index 385fffbcbaea..df19f0a54d7c 100644 --- a/src/Symfony/Component/Lock/CHANGELOG.md +++ b/src/Symfony/Component/Lock/CHANGELOG.md @@ -4,6 +4,7 @@ CHANGELOG 7.2 --- + * RedisStore uses `EVALSHA` over `EVAL` when evaluating LUA scripts * Add `NullStore` 7.0 diff --git a/src/Symfony/Component/Lock/Store/RedisStore.php b/src/Symfony/Component/Lock/Store/RedisStore.php index edbc89343f30..a7bf7fec29de 100644 --- a/src/Symfony/Component/Lock/Store/RedisStore.php +++ b/src/Symfony/Component/Lock/Store/RedisStore.php @@ -29,6 +29,8 @@ class RedisStore implements SharedLockStoreInterface { use ExpiringStoreTrait; + private const NO_SCRIPT_ERROR_MESSAGE = 'NOSCRIPT No matching script. Please use EVAL.'; + private bool $supportTime; /** @@ -226,11 +228,32 @@ public function exists(Key $key): bool private function evaluate(string $script, string $resource, array $args): mixed { + $scriptSha = sha1($script); + if ($this->redis instanceof \Redis || $this->redis instanceof Relay || $this->redis instanceof \RedisCluster) { $this->redis->clearLastError(); - $result = $this->redis->eval($script, array_merge([$resource], $args), 1); - if (null !== $err = $this->redis->getLastError()) { - throw new LockStorageException($err); + + $result = $this->redis->evalSha($scriptSha, array_merge([$resource], $args), 1); + if (self::NO_SCRIPT_ERROR_MESSAGE === $err = $this->redis->getLastError()) { + $this->redis->clearLastError(); + + if ($this->redis instanceof \RedisCluster) { + foreach ($this->redis->_masters() as $master) { + $this->redis->script($master, 'LOAD', $script); + } + } else { + $this->redis->script('LOAD', $script); + } + + if (null !== $err = $this->redis->getLastError()) { + throw new LockStorageException($err); + } + + $result = $this->redis->evalSha($scriptSha, array_merge([$resource], $args), 1); + + if (null !== $err = $this->redis->getLastError()) { + throw new LockStorageException($err); + } } return $result; @@ -239,9 +262,21 @@ private function evaluate(string $script, string $resource, array $args): mixed if ($this->redis instanceof \RedisArray) { $client = $this->redis->_instance($this->redis->_target($resource)); $client->clearLastError(); - $result = $client->eval($script, array_merge([$resource], $args), 1); - if (null !== $err = $client->getLastError()) { - throw new LockStorageException($err); + $result = $client->evalSha($scriptSha, array_merge([$resource], $args), 1); + if (self::NO_SCRIPT_ERROR_MESSAGE === $err = $client->getLastError()) { + $client->clearLastError(); + + $client->script('LOAD', $script); + + if (null !== $err = $client->getLastError()) { + throw new LockStorageException($err); + } + + $result = $client->evalSha($scriptSha, array_merge([$resource], $args), 1); + + if (null !== $err = $client->getLastError()) { + throw new LockStorageException($err); + } } return $result; @@ -250,7 +285,22 @@ private function evaluate(string $script, string $resource, array $args): mixed \assert($this->redis instanceof \Predis\ClientInterface); try { - return $this->redis->eval(...array_merge([$script, 1, $resource], $args)); + return $this->redis->evalSha($scriptSha, 1, $resource, ...$args); + } catch (ServerException $e) { + // Fallthrough only if we need to load the script + if (self::NO_SCRIPT_ERROR_MESSAGE !== $e->getMessage()) { + throw new LockStorageException($e->getMessage(), $e->getCode(), $e); + } + } + + try { + $this->redis->script('LOAD', $script); + } catch (ServerException $e) { + throw new LockStorageException($e->getMessage(), $e->getCode(), $e); + } + + try { + return $this->redis->evalSha($scriptSha, 1, $resource, ...$args); } catch (ServerException $e) { throw new LockStorageException($e->getMessage(), $e->getCode(), $e); } pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy