From 65a9559d2a66acf578f90de652648d8baa0bd253 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=B3bert=20Kel=C4=8D=C3=A1k?= Date: Sat, 31 Aug 2024 02:38:40 +0200 Subject: [PATCH] Optimize Redis keys loading --- src/Dashboards/Redis/Compatibility/Predis.php | 41 +++++++++++++----- src/Dashboards/Redis/Compatibility/Redis.php | 43 ++++++++++++++++--- .../RedisCompatibilityInterface.php | 16 ++++++- src/Dashboards/Redis/RedisTrait.php | 15 +++---- tests/Clients/PredisTest.php | 2 +- 5 files changed, 89 insertions(+), 28 deletions(-) diff --git a/src/Dashboards/Redis/Compatibility/Predis.php b/src/Dashboards/Redis/Compatibility/Predis.php index 1c22e4f..ad82000 100644 --- a/src/Dashboards/Redis/Compatibility/Predis.php +++ b/src/Dashboards/Redis/Compatibility/Predis.php @@ -10,7 +10,6 @@ use Predis\Client; use Predis\Collection\Iterator\Keyspace; -use RobiNN\Pca\Dashboards\DashboardException; class Predis extends Client implements RedisCompatibilityInterface { use RedisJson; @@ -56,17 +55,14 @@ public function __construct(array $server) { ]); } - /** - * @throws DashboardException - */ - public function getType(string $key): string { - $type = (string) $this->type($key); + public function getType(string|int $type): string { + return $this->data_types[$type] ?? 'unknown'; + } - if (!isset($this->data_types[$type])) { - throw new DashboardException(sprintf('Unsupported data type: %s', $type)); - } + public function getKeyType(string $key): string { + $type = (string) $this->type($key); - return $this->data_types[$type]; + return $this->getType($type); } /** @@ -128,4 +124,29 @@ public function streamAdd(string $key, string $id, array $messages): string { public function rawCommand(string $command, mixed ...$arguments): mixed { return $this->executeRaw(func_get_args()); } + + /** + * @param array $keys + * + * @return array + */ + public function pipelineKeys(array $keys): array { + $results = $this->pipeline(function ($pipe) use ($keys) { + foreach ($keys as $key) { + $pipe->ttl($key); + $pipe->type($key); + } + }); + + $data = []; + + foreach ($keys as $i => $key) { + $data[$key] = [ + 'ttl' => $results[$i * 2], + 'type' => $this->getType((string) $results[$i * 2 + 1]), + ]; + } + + return $data; + } } diff --git a/src/Dashboards/Redis/Compatibility/Redis.php b/src/Dashboards/Redis/Compatibility/Redis.php index 6d5ba3c..8a8ec0f 100644 --- a/src/Dashboards/Redis/Compatibility/Redis.php +++ b/src/Dashboards/Redis/Compatibility/Redis.php @@ -67,10 +67,14 @@ public function connection(array $server): self { return $this; } + public function getType(string|int $type): string { + return $this->data_types[$type] ?? 'unknown'; + } + /** - * @throws RedisException|DashboardException + * @throws RedisException */ - public function getType(string $key): string { + public function getKeyType(string $key): string { $type = $this->type($key); if ($type === self::REDIS_NOT_FOUND) { @@ -78,11 +82,7 @@ public function getType(string $key): string { $type = $this->rawCommand('TYPE', $key); } - if (!isset($this->data_types[$type])) { - throw new DashboardException(sprintf('Unsupported data type: %s', $type)); - } - - return $this->data_types[$type]; + return $this->getType($type); } /** @@ -140,4 +140,33 @@ public function listRem(string $key, string $value, int $count): int { public function streamAdd(string $key, string $id, array $messages): string { return $this->xAdd($key, $id, $messages); } + + /** + * @param array $keys + * + * @return array + * + * @throws RedisException + */ + public function pipelineKeys(array $keys): array { + $pipeline = $this->multi(self::PIPELINE); + + foreach ($keys as $key) { + $pipeline->ttl($key); + $pipeline->type($key); + } + + $results = $pipeline->exec(); + + $data = []; + + foreach ($keys as $i => $key) { + $data[$key] = [ + 'ttl' => $results[$i * 2], + 'type' => $this->getType($results[$i * 2 + 1]), + ]; + } + + return $data; + } } diff --git a/src/Dashboards/Redis/Compatibility/RedisCompatibilityInterface.php b/src/Dashboards/Redis/Compatibility/RedisCompatibilityInterface.php index 3f94299..c30a21d 100644 --- a/src/Dashboards/Redis/Compatibility/RedisCompatibilityInterface.php +++ b/src/Dashboards/Redis/Compatibility/RedisCompatibilityInterface.php @@ -11,12 +11,17 @@ use RobiNN\Pca\Dashboards\DashboardException; interface RedisCompatibilityInterface { + /** + * Get a key type from an array. + */ + public function getType(string|int $type): string; + /** * Get a key type. * * @throws DashboardException */ - public function getType(string $key): string; + public function getKeyType(string $key): string; /** * Get server info. @@ -43,4 +48,13 @@ public function listRem(string $key, string $value, int $count): int; * @param array $messages */ public function streamAdd(string $key, string $id, array $messages): string; + + /** + * Pipeline keys for better performance. + * + * @param array $keys + * + * @return array + */ + public function pipelineKeys(array $keys): array; } diff --git a/src/Dashboards/Redis/RedisTrait.php b/src/Dashboards/Redis/RedisTrait.php index 9dbf1ee..f09456f 100644 --- a/src/Dashboards/Redis/RedisTrait.php +++ b/src/Dashboards/Redis/RedisTrait.php @@ -144,7 +144,7 @@ private function viewKey(): string { } try { - $type = $this->redis->getType($key); + $type = $this->redis->getKeyType($key); } catch (DashboardException $e) { return $e->getMessage(); } @@ -271,7 +271,7 @@ private function form(): string { // edit|subkeys if (isset($_GET['key']) && $this->redis->exists($key)) { try { - $type = $this->redis->getType($key); + $type = $this->redis->getKeyType($key); } catch (DashboardException $e) { Helpers::alert($this->template, $e->getMessage(), 'error'); $type = 'unknown'; @@ -317,14 +317,11 @@ private function getAllKeys(): array { $keys_array = $this->redis->keys($filter); } - foreach ($keys_array as $key) { - try { - $type = $this->redis->getType($key); - } catch (DashboardException) { - $type = 'unknown'; - } + $pipeline = $this->redis->pipelineKeys($keys_array); - $ttl = $this->redis->ttl($key); + foreach ($keys_array as $key) { + $ttl = $pipeline[$key]['ttl']; + $type = $pipeline[$key]['type']; $total = $this->getCountOfItemsInKey($type, $key); $keys[] = [ diff --git a/tests/Clients/PredisTest.php b/tests/Clients/PredisTest.php index 305bba1..d8e268b 100644 --- a/tests/Clients/PredisTest.php +++ b/tests/Clients/PredisTest.php @@ -44,7 +44,7 @@ public function testGetType(string $key): void { $this->predis->streamAdd('pu-pred-test-stream', '*', ['field1' => 'value1', 'field2' => 'value2']); $this->predis->streamAdd('pu-pred-test-stream', '*', ['field3' => 'value3']); - $this->assertSame($key, $this->predis->getType('pu-pred-test-'.$key)); + $this->assertSame($key, $this->predis->getKeyType('pu-pred-test-'.$key)); } #[DataProvider('keysProvider')]