Skip to content

Commit

Permalink
Avoid exception use and memory leak in eval
Browse files Browse the repository at this point in the history
We automatically clear the cache now.
  • Loading branch information
kelunik committed Aug 20, 2023
1 parent 548d2c5 commit 4ef9222
Showing 1 changed file with 20 additions and 11 deletions.
31 changes: 20 additions & 11 deletions src/RedisClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

namespace Amp\Redis;

use Amp\Cache\AtomicCache;
use Amp\Cache\LocalCache;
use Amp\ForbidCloning;
use Amp\ForbidSerialization;
use Amp\Redis\Command\Option\RedisSetOptions;
Expand All @@ -13,19 +15,22 @@
use Amp\Redis\Command\RedisSortedSet;
use Amp\Redis\Connection\RedisLink;
use Amp\Redis\Protocol\QueryException;
use Amp\Redis\Protocol\RedisError;
use Amp\Sync\LocalKeyedMutex;
use Amp\Sync\LocalMutex;
use function Amp\Redis\Internal\toMap;

final class RedisClient
{
use ForbidCloning;
use ForbidSerialization;

/** @var string[] */
private array $evalCache = [];
private AtomicCache $evalCache;

public function __construct(
private readonly RedisLink $link
) {
$this->evalCache = $this->createCache();
}

public function getHyperLogLog(string $key): RedisHyperLogLog
Expand Down Expand Up @@ -748,7 +753,7 @@ public function hasScript(string $sha1): bool
*/
public function flushScripts(): void
{
$this->evalCache = []; // same as internal redis behavior
$this->evalCache = $this->createCache(); // same as internal redis behavior

$this->execute('script', 'flush');
}
Expand Down Expand Up @@ -785,20 +790,24 @@ public function echo(string $text): string
*/
public function eval(string $script, array $keys = [], array $args = []): mixed
{
try {
$sha1 = $this->evalCache[$script] ?? ($this->evalCache[$script] = \sha1($script));
return $this->execute('evalsha', $sha1, \count($keys), ...$keys, ...$args);
} catch (QueryException $e) {
if (\strtok($e->getMessage(), ' ') === 'NOSCRIPT') {
return $this->execute('eval', $script, \count($keys), ...$keys, ...$args);
}
$sha1 = $this->evalCache->computeIfAbsent($script, fn (string $value) => \sha1($value));

$response = $this->link->execute('evalsha', [$sha1, \count($keys), ...$keys, ...$args]);

throw $e;
if ($response instanceof RedisError && \strtok($response->getMessage(), ' ') === 'NOSCRIPT') {
return $this->execute('eval', $script, \count($keys), ...$keys, ...$args);
}

$response->unwrap();
}

public function select(int $database): void
{
$this->execute('select', $database);
}

private function createCache(): AtomicCache
{
return new AtomicCache(new LocalCache(1000, 60), new LocalKeyedMutex());
}
}

0 comments on commit 4ef9222

Please sign in to comment.